Skip to content

Commit ee55753

Browse files
authored
Merge branch 'master' into co-4344-bump-max-drain-timeout
2 parents f1edd4a + d4da95d commit ee55753

17 files changed

+658
-24
lines changed

castai/resource_edge_location.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ func (r *edgeLocationResource) Create(ctx context.Context, req resource.CreateRe
383383

384384
createReq := omni.EdgeLocationsAPICreateEdgeLocationJSONRequestBody{
385385
Name: plan.Name.ValueString(),
386-
Region: plan.Region.ValueString(),
386+
Region: plan.Region.ValueStringPointer(),
387387
Zones: lo.ToPtr(r.toZones(plan.Zones)),
388388
}
389389

@@ -463,7 +463,9 @@ func (r *edgeLocationResource) Read(ctx context.Context, req resource.ReadReques
463463

464464
edgeLocation := apiResp.JSON200
465465

466-
state.Region = types.StringValue(edgeLocation.Region)
466+
if edgeLocation.Region != nil {
467+
state.Region = types.StringValue(*edgeLocation.Region)
468+
}
467469
state.Name = types.StringValue(edgeLocation.Name)
468470
state.Description = types.StringNull()
469471
if edgeLocation.Description != nil {

castai/resource_enterprise_role_binding.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ func buildBatchCreateRoleBindingRequest(data *schema.ResourceData, enterpriseID
417417
return nil, fmt.Errorf("reading role binding data: %w", err)
418418
}
419419

420-
definition := buildRoleBindingDefinition(roleBinding)
420+
definition := buildRoleBindingDefinition(roleBinding, enterpriseID)
421421

422422
request := organization_management.BatchCreateEnterpriseRoleBindingsRequest{
423423
EnterpriseId: enterpriseID,
@@ -442,7 +442,7 @@ func buildBatchUpdateRoleBindingRequest(data *schema.ResourceData, enterpriseID,
442442
return nil, fmt.Errorf("reading role binding data: %w", err)
443443
}
444444

445-
definition := buildRoleBindingDefinition(roleBinding)
445+
definition := buildRoleBindingDefinition(roleBinding, enterpriseID)
446446

447447
request := organization_management.BatchUpdateEnterpriseRoleBindingsRequest{
448448
EnterpriseId: enterpriseID,
@@ -460,14 +460,20 @@ func buildBatchUpdateRoleBindingRequest(data *schema.ResourceData, enterpriseID,
460460
return &request, nil
461461
}
462462

463-
func buildRoleBindingDefinition(roleBinding EnterpriseRoleBinding) organization_management.RoleBindingDefinition {
463+
func buildRoleBindingDefinition(roleBinding EnterpriseRoleBinding, enterpriseID string) organization_management.RoleBindingDefinition {
464464
subjects := convertEnterpriseRoleBindingSubjectsToSDK(roleBinding.Subjects)
465465
scopes := convertEnterpriseRoleBindingScopesToSDK(roleBinding.Scopes)
466466

467467
definition := organization_management.RoleBindingDefinition{
468468
RoleId: lo.ToPtr(roleBinding.RoleID),
469469
}
470470

471+
// When the role binding targets a child organization, set ChildOrganizationId so the
472+
// API validates role_id against the child org's roles instead of the enterprise's roles.
473+
if roleBinding.OrganizationID != enterpriseID {
474+
definition.ChildOrganizationId = lo.ToPtr(roleBinding.OrganizationID)
475+
}
476+
471477
if len(subjects) > 0 {
472478
definition.Subjects = &subjects
473479
}

castai/resource_enterprise_role_binding_test.go

Lines changed: 123 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ func TestResourceEnterpriseRoleBindingCreateContext(t *testing.T) {
129129
Name: "engineering-viewer",
130130
Description: lo.ToPtr("Engineering viewer role binding"),
131131
Definition: organization_management.RoleBindingDefinition{
132-
RoleId: lo.ToPtr(roleID),
132+
RoleId: lo.ToPtr(roleID),
133+
ChildOrganizationId: lo.ToPtr(organizationID1),
133134
Subjects: &[]organization_management.Subject{
134135
{
135136
User: &organization_management.UserSubject{
@@ -511,6 +512,121 @@ func TestResourceEnterpriseRoleBindingCreateContext(t *testing.T) {
511512
r.True(result.HasError())
512513
r.Contains(result[0].Summary, "at least one scope (organization or cluster) must be defined")
513514
})
515+
516+
t.Run("when organization_id differs from enterprise_id then ChildOrganizationId is set in definition", func(t *testing.T) {
517+
t.Parallel()
518+
r := require.New(t)
519+
mockClient := mockOrganizationManagement.NewMockClientWithResponsesInterface(gomock.NewController(t))
520+
521+
ctx := context.Background()
522+
provider := &ProviderConfig{
523+
organizationManagementClient: mockClient,
524+
}
525+
526+
enterpriseID := uuid.NewString()
527+
childOrgID := uuid.NewString() // different from enterpriseID
528+
roleBindingID := uuid.NewString()
529+
roleID := uuid.NewString()
530+
userID := uuid.NewString()
531+
532+
expectedCreateRequest := organization_management.BatchCreateEnterpriseRoleBindingsRequest{
533+
EnterpriseId: enterpriseID,
534+
Requests: []organization_management.BatchCreateEnterpriseRoleBindingsRequestCreateRoleBindingRequest{
535+
{
536+
OrganizationId: childOrgID,
537+
RoleBinding: organization_management.BatchCreateEnterpriseRoleBindingsRequestRoleBinding{
538+
Name: "child-org-binding",
539+
Description: lo.ToPtr(""),
540+
Definition: organization_management.RoleBindingDefinition{
541+
RoleId: lo.ToPtr(roleID),
542+
ChildOrganizationId: lo.ToPtr(childOrgID),
543+
Subjects: &[]organization_management.Subject{
544+
{
545+
User: &organization_management.UserSubject{Id: userID},
546+
},
547+
},
548+
Scopes: &[]organization_management.Scope{
549+
{
550+
Organization: &organization_management.OrganizationScope{Id: childOrgID},
551+
},
552+
},
553+
},
554+
},
555+
},
556+
},
557+
}
558+
559+
mockClient.EXPECT().
560+
EnterpriseAPIBatchCreateEnterpriseRoleBindingsWithResponse(gomock.Any(), enterpriseID, expectedCreateRequest).
561+
Return(&organization_management.EnterpriseAPIBatchCreateEnterpriseRoleBindingsResponse{
562+
Body: nil,
563+
HTTPResponse: &http.Response{StatusCode: http.StatusOK},
564+
JSON200: &organization_management.BatchCreateEnterpriseRoleBindingsResponse{
565+
RoleBindings: &[]organization_management.RoleBinding{
566+
{
567+
Id: lo.ToPtr(roleBindingID),
568+
Name: lo.ToPtr("child-org-binding"),
569+
OrganizationId: lo.ToPtr(childOrgID),
570+
Definition: &organization_management.RoleBindingDefinition{
571+
RoleId: lo.ToPtr(roleID),
572+
ChildOrganizationId: lo.ToPtr(childOrgID),
573+
Subjects: &[]organization_management.Subject{
574+
{User: &organization_management.UserSubject{Id: userID}},
575+
},
576+
Scopes: &[]organization_management.Scope{
577+
{Organization: &organization_management.OrganizationScope{Id: childOrgID}},
578+
},
579+
},
580+
},
581+
},
582+
},
583+
}, nil)
584+
585+
stateValue := cty.ObjectVal(map[string]cty.Value{
586+
FieldEnterpriseRoleBindingEnterpriseID: cty.StringVal(enterpriseID),
587+
FieldEnterpriseRoleBindingOrganizationID: cty.StringVal(childOrgID),
588+
FieldEnterpriseRoleBindingName: cty.StringVal("child-org-binding"),
589+
FieldEnterpriseRoleBindingDescription: cty.StringVal(""),
590+
FieldEnterpriseRoleBindingRoleID: cty.StringVal(roleID),
591+
FieldEnterpriseRoleBindingSubjects: cty.ListVal([]cty.Value{
592+
cty.ObjectVal(map[string]cty.Value{
593+
FieldEnterpriseRoleBindingSubjectUser: cty.ListVal([]cty.Value{
594+
cty.ObjectVal(map[string]cty.Value{
595+
FieldEnterpriseRoleBindingSubjectID: cty.StringVal(userID),
596+
}),
597+
}),
598+
FieldEnterpriseRoleBindingSubjectServiceAccount: cty.ListValEmpty(cty.Object(map[string]cty.Type{
599+
FieldEnterpriseRoleBindingSubjectID: cty.String,
600+
})),
601+
FieldEnterpriseRoleBindingSubjectGroup: cty.ListValEmpty(cty.Object(map[string]cty.Type{
602+
FieldEnterpriseRoleBindingSubjectID: cty.String,
603+
})),
604+
}),
605+
}),
606+
FieldEnterpriseRoleBindingScopes: cty.ListVal([]cty.Value{
607+
cty.ObjectVal(map[string]cty.Value{
608+
FieldEnterpriseRoleBindingScopeOrganization: cty.ListVal([]cty.Value{
609+
cty.ObjectVal(map[string]cty.Value{
610+
FieldEnterpriseRoleBindingScopeID: cty.StringVal(childOrgID),
611+
}),
612+
}),
613+
FieldEnterpriseRoleBindingScopeCluster: cty.ListValEmpty(cty.Object(map[string]cty.Type{
614+
FieldEnterpriseRoleBindingScopeID: cty.String,
615+
})),
616+
}),
617+
}),
618+
})
619+
state := terraform.NewInstanceStateShimmedFromValue(stateValue, 0)
620+
621+
resource := resourceEnterpriseRoleBinding()
622+
data := resource.Data(state)
623+
624+
result := resource.CreateContext(ctx, data, provider)
625+
626+
r.Nil(result)
627+
r.False(result.HasError())
628+
r.Equal(roleBindingID, data.Id())
629+
})
514630
}
515631

516632
func TestResourceEnterpriseRoleBindingReadContext(t *testing.T) {
@@ -982,7 +1098,8 @@ func TestResourceEnterpriseRoleBindingUpdateContext(t *testing.T) {
9821098
OrganizationId: organizationID,
9831099
Description: lo.ToPtr("Updated description"),
9841100
Definition: organization_management.RoleBindingDefinition{
985-
RoleId: lo.ToPtr(newRoleID),
1101+
RoleId: lo.ToPtr(newRoleID),
1102+
ChildOrganizationId: lo.ToPtr(organizationID),
9861103
Subjects: &[]organization_management.Subject{
9871104
{
9881105
User: &organization_management.UserSubject{
@@ -1238,7 +1355,8 @@ func TestResourceEnterpriseRoleBindingUpdateContext(t *testing.T) {
12381355
OrganizationId: organizationID,
12391356
Description: lo.ToPtr("Test description"),
12401357
Definition: organization_management.RoleBindingDefinition{
1241-
RoleId: lo.ToPtr(roleID),
1358+
RoleId: lo.ToPtr(roleID),
1359+
ChildOrganizationId: lo.ToPtr(organizationID),
12421360
Subjects: &[]organization_management.Subject{
12431361
{
12441362
User: &organization_management.UserSubject{
@@ -1419,7 +1537,8 @@ func TestResourceEnterpriseRoleBindingUpdateContext(t *testing.T) {
14191537
OrganizationId: organizationID,
14201538
Description: lo.ToPtr("Test description"),
14211539
Definition: organization_management.RoleBindingDefinition{
1422-
RoleId: lo.ToPtr(roleID),
1540+
RoleId: lo.ToPtr(roleID),
1541+
ChildOrganizationId: lo.ToPtr(organizationID),
14231542
Subjects: &[]organization_management.Subject{
14241543
{
14251544
User: &organization_management.UserSubject{

castai/resource_node_configuration.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ const (
4848
FieldNodeConfigurationAKSApplicationSecurityGroups = "application_security_groups"
4949
FieldNodeConfigurationAKSPublicIP = "public_ip"
5050
FieldNodeConfigurationAKSPodSubnetID = "pod_subnet_id"
51+
FieldNodeConfigurationAKSEncryptionAtHost = "enable_encryption_at_host"
5152
)
5253

5354
const (
@@ -491,6 +492,11 @@ func resourceNodeConfiguration() *schema.Resource {
491492
Optional: true,
492493
Description: "ID of pod subnet to be used for provisioned nodes.",
493494
},
495+
FieldNodeConfigurationAKSEncryptionAtHost: {
496+
Type: schema.TypeBool,
497+
Optional: true,
498+
Description: "Whether to enable encryption at host for provisioned nodes. See https://learn.microsoft.com/en-us/azure/virtual-machines/disk-encryption#encryption-at-host---end-to-end-encryption-for-your-vm-data",
499+
},
494500
},
495501
},
496502
},
@@ -1190,6 +1196,10 @@ func toAKSSConfig(obj map[string]interface{}) *sdk.NodeconfigV1AKSConfig {
11901196
out.PodSubnetId = toPtr(v)
11911197
}
11921198

1199+
if v, ok := obj[FieldNodeConfigurationAKSEncryptionAtHost].(bool); ok {
1200+
out.EnableEncryptionAtHost = toPtr(v)
1201+
}
1202+
11931203
return out
11941204
}
11951205

@@ -1386,6 +1396,10 @@ func flattenAKSConfig(config *sdk.NodeconfigV1AKSConfig) []map[string]interface{
13861396
m[FieldNodeConfigurationAKSPodSubnetID] = *v
13871397
}
13881398

1399+
if v := config.EnableEncryptionAtHost; v != nil {
1400+
m[FieldNodeConfigurationAKSEncryptionAtHost] = *v
1401+
}
1402+
13891403
return []map[string]interface{}{m}
13901404
}
13911405

castai/resource_node_configuration_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,3 +376,55 @@ func Test_NodeConfiguration_UpdateContext(t *testing.T) {
376376
})
377377
}
378378
}
379+
380+
func TestToAKSSConfig_EnableEncryptionAtHost(t *testing.T) {
381+
tests := []struct {
382+
name string
383+
input any
384+
expected any
385+
}{
386+
{name: "true", input: true, expected: true},
387+
{name: "false", input: false, expected: false},
388+
{name: "nil", input: nil, expected: nil},
389+
}
390+
for _, tt := range tests {
391+
t.Run(tt.name, func(t *testing.T) {
392+
out := toAKSSConfig(map[string]any{
393+
FieldNodeConfigurationAKSEncryptionAtHost: tt.input,
394+
})
395+
396+
if tt.expected == nil {
397+
require.Nil(t, out.EnableEncryptionAtHost)
398+
} else {
399+
require.Equal(t, tt.expected, *out.EnableEncryptionAtHost)
400+
}
401+
})
402+
}
403+
404+
t.Run("empty", func(t *testing.T) {
405+
out := toAKSSConfig(map[string]any{})
406+
407+
require.Nil(t, out.EnableEncryptionAtHost)
408+
})
409+
}
410+
411+
func TestFlattenAKSConfig_EnableEncryptionAtHost(t *testing.T) {
412+
tests := []struct {
413+
name string
414+
input *bool
415+
expected any
416+
}{
417+
{name: "true", input: toPtr(true), expected: true},
418+
{name: "false", input: toPtr(false), expected: false},
419+
{name: "nil", input: nil, expected: nil},
420+
}
421+
for _, tt := range tests {
422+
t.Run(tt.name, func(t *testing.T) {
423+
result := flattenAKSConfig(&sdk.NodeconfigV1AKSConfig{
424+
EnableEncryptionAtHost: tt.input,
425+
})
426+
require.Len(t, result, 1)
427+
require.Equal(t, tt.expected, result[0][FieldNodeConfigurationAKSEncryptionAtHost])
428+
})
429+
}
430+
}

0 commit comments

Comments
 (0)