Skip to content

Commit 54fa46f

Browse files
committed
refactor: enhance member and role binding validation in enterprise group update
1 parent 50e2548 commit 54fa46f

1 file changed

Lines changed: 166 additions & 163 deletions

File tree

castai/resource_enterprise_group.go

Lines changed: 166 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -868,227 +868,230 @@ func resourceEnterpriseGroupUpdate(ctx context.Context, data *schema.ResourceDat
868868

869869
tflog.Debug(ctx, "Updating enterprise group", map[string]any{"group_id": groupID})
870870

871-
if data.HasChanges(
871+
if !data.HasChanges(
872872
FieldEnterpriseGroupName,
873873
FieldEnterpriseGroupDescription,
874874
FieldEnterpriseGroupMembers,
875875
FieldEnterpriseGroupRoleBindings,
876876
) {
877-
var members []organization_management.BatchUpdateEnterpriseGroupsRequestMember
878-
if membersData, ok := data.Get(FieldEnterpriseGroupMembers).([]any); ok {
879-
for _, memberWrapper := range membersData {
880-
if memberWrapper == nil {
877+
tflog.Debug(ctx, "No changes detected, skipping update", map[string]any{"group_id": groupID})
878+
return nil
879+
}
880+
881+
var members []organization_management.BatchUpdateEnterpriseGroupsRequestMember
882+
if membersData, ok := data.Get(FieldEnterpriseGroupMembers).([]any); ok {
883+
for _, memberWrapper := range membersData {
884+
if memberWrapper == nil {
885+
continue
886+
}
887+
888+
memberWrapperMap, ok := memberWrapper.(map[string]any)
889+
if !ok {
890+
return diag.FromErr(fmt.Errorf("invalid member configuration: expected object, got %T", memberWrapper))
891+
}
892+
893+
membersDataNested, ok := memberWrapperMap[FieldEnterpriseGroupsMember].([]any)
894+
if !ok || len(membersDataNested) == 0 {
895+
continue
896+
}
897+
898+
for _, memberData := range membersDataNested {
899+
if memberData == nil {
881900
continue
882901
}
883902

884-
memberWrapperMap, ok := memberWrapper.(map[string]any)
903+
member, ok := memberData.(map[string]any)
885904
if !ok {
886-
return diag.FromErr(fmt.Errorf("invalid member configuration: expected object, got %T", memberWrapper))
905+
return diag.FromErr(fmt.Errorf("invalid member data: expected object, got %T", memberData))
887906
}
888907

889-
membersDataNested, ok := memberWrapperMap[FieldEnterpriseGroupsMember].([]any)
890-
if !ok || len(membersDataNested) == 0 {
891-
continue
908+
memberKind, ok := member[FieldEnterpriseGroupMemberKind].(string)
909+
if !ok {
910+
return diag.FromErr(fmt.Errorf("member missing required 'kind' field"))
892911
}
893912

894-
for _, memberData := range membersDataNested {
895-
if memberData == nil {
896-
continue
897-
}
913+
memberID, ok := member[FieldEnterpriseGroupMemberID].(string)
914+
if !ok {
915+
return diag.FromErr(fmt.Errorf("member missing required 'id' field"))
916+
}
898917

899-
member, ok := memberData.(map[string]any)
900-
if !ok {
901-
return diag.FromErr(fmt.Errorf("invalid member data: expected object, got %T", memberData))
902-
}
918+
var kind organization_management.BatchUpdateEnterpriseGroupsRequestMemberKind
919+
switch memberKind {
920+
case EnterpriseGroupMemberKindUser:
921+
kind = organization_management.BatchUpdateEnterpriseGroupsRequestMemberKindUSER
922+
case EnterpriseGroupMemberKindServiceAccount:
923+
kind = organization_management.BatchUpdateEnterpriseGroupsRequestMemberKindSERVICEACCOUNT
924+
default:
925+
kind = organization_management.BatchUpdateEnterpriseGroupsRequestMemberKindSUBJECTKINDUNSPECIFIED
926+
}
903927

904-
memberKind, ok := member[FieldEnterpriseGroupMemberKind].(string)
905-
if !ok {
906-
return diag.FromErr(fmt.Errorf("member missing required 'kind' field"))
907-
}
928+
members = append(members, organization_management.BatchUpdateEnterpriseGroupsRequestMember{
929+
Kind: kind,
930+
Id: memberID,
931+
})
932+
}
933+
}
934+
}
908935

909-
memberID, ok := member[FieldEnterpriseGroupMemberID].(string)
910-
if !ok {
911-
return diag.FromErr(fmt.Errorf("member missing required 'id' field"))
912-
}
936+
var roleBindings []organization_management.BatchUpdateEnterpriseGroupsRequestRoleBinding
937+
if bindingsData, ok := data.Get(FieldEnterpriseGroupRoleBindings).([]any); ok {
938+
for _, bindingWrapper := range bindingsData {
939+
if bindingWrapper == nil {
940+
continue
941+
}
913942

914-
var kind organization_management.BatchUpdateEnterpriseGroupsRequestMemberKind
915-
switch memberKind {
916-
case EnterpriseGroupMemberKindUser:
917-
kind = organization_management.BatchUpdateEnterpriseGroupsRequestMemberKindUSER
918-
case EnterpriseGroupMemberKindServiceAccount:
919-
kind = organization_management.BatchUpdateEnterpriseGroupsRequestMemberKindSERVICEACCOUNT
920-
default:
921-
kind = organization_management.BatchUpdateEnterpriseGroupsRequestMemberKindSUBJECTKINDUNSPECIFIED
922-
}
943+
bindingWrapperMap, ok := bindingWrapper.(map[string]any)
944+
if !ok {
945+
return diag.FromErr(fmt.Errorf("invalid role binding configuration: expected object, got %T", bindingWrapper))
946+
}
923947

924-
members = append(members, organization_management.BatchUpdateEnterpriseGroupsRequestMember{
925-
Kind: kind,
926-
Id: memberID,
927-
})
928-
}
948+
bindingsDataNested, ok := bindingWrapperMap[FieldEnterpriseGroupRoleBinding].([]any)
949+
if !ok || len(bindingsDataNested) == 0 {
950+
continue
929951
}
930-
}
931952

932-
var roleBindings []organization_management.BatchUpdateEnterpriseGroupsRequestRoleBinding
933-
if bindingsData, ok := data.Get(FieldEnterpriseGroupRoleBindings).([]any); ok {
934-
for _, bindingWrapper := range bindingsData {
935-
if bindingWrapper == nil {
953+
for _, bindingData := range bindingsDataNested {
954+
if bindingData == nil {
936955
continue
937956
}
938957

939-
bindingWrapperMap, ok := bindingWrapper.(map[string]any)
958+
binding, ok := bindingData.(map[string]any)
940959
if !ok {
941-
return diag.FromErr(fmt.Errorf("invalid role binding configuration: expected object, got %T", bindingWrapper))
960+
return diag.FromErr(fmt.Errorf("invalid role binding data: expected object, got %T", bindingData))
942961
}
943962

944-
bindingsDataNested, ok := bindingWrapperMap[FieldEnterpriseGroupRoleBinding].([]any)
945-
if !ok || len(bindingsDataNested) == 0 {
946-
continue
963+
rbName, ok := binding[FieldEnterpriseGroupRoleBindingName].(string)
964+
if !ok {
965+
return diag.FromErr(fmt.Errorf("role binding missing required 'name' field"))
947966
}
948967

949-
for _, bindingData := range bindingsDataNested {
950-
if bindingData == nil {
951-
continue
952-
}
968+
rbRoleID, ok := binding[FieldEnterpriseGroupRoleBindingRoleID].(string)
969+
if !ok {
970+
return diag.FromErr(fmt.Errorf("role binding missing required 'role_id' field"))
971+
}
953972

954-
binding, ok := bindingData.(map[string]any)
955-
if !ok {
956-
return diag.FromErr(fmt.Errorf("invalid role binding data: expected object, got %T", bindingData))
957-
}
973+
var rbScopes []organization_management.Scope
974+
if scopesData, ok := binding[FieldEnterpriseGroupRoleBindingScopes].([]any); ok {
975+
for _, scopeWrapper := range scopesData {
976+
if scopeWrapper == nil {
977+
continue
978+
}
958979

959-
rbName, ok := binding[FieldEnterpriseGroupRoleBindingName].(string)
960-
if !ok {
961-
return diag.FromErr(fmt.Errorf("role binding missing required 'name' field"))
962-
}
980+
scopeWrapperMap, ok := scopeWrapper.(map[string]any)
981+
if !ok {
982+
return diag.FromErr(fmt.Errorf("invalid scope configuration: expected object, got %T", scopeWrapper))
983+
}
963984

964-
rbRoleID, ok := binding[FieldEnterpriseGroupRoleBindingRoleID].(string)
965-
if !ok {
966-
return diag.FromErr(fmt.Errorf("role binding missing required 'role_id' field"))
967-
}
985+
scopesDataNested, ok := scopeWrapperMap[FieldEnterpriseGroupScope].([]any)
986+
if !ok || len(scopesDataNested) == 0 {
987+
continue
988+
}
968989

969-
var rbScopes []organization_management.Scope
970-
if scopesData, ok := binding[FieldEnterpriseGroupRoleBindingScopes].([]any); ok {
971-
for _, scopeWrapper := range scopesData {
972-
if scopeWrapper == nil {
990+
for _, scopeData := range scopesDataNested {
991+
if scopeData == nil {
973992
continue
974993
}
975994

976-
scopeWrapperMap, ok := scopeWrapper.(map[string]any)
995+
scope, ok := scopeData.(map[string]any)
977996
if !ok {
978-
return diag.FromErr(fmt.Errorf("invalid scope configuration: expected object, got %T", scopeWrapper))
997+
return diag.FromErr(fmt.Errorf("invalid scope data: expected object, got %T", scopeData))
979998
}
980999

981-
scopesDataNested, ok := scopeWrapperMap[FieldEnterpriseGroupScope].([]any)
982-
if !ok || len(scopesDataNested) == 0 {
983-
continue
984-
}
985-
986-
for _, scopeData := range scopesDataNested {
987-
if scopeData == nil {
988-
continue
989-
}
990-
991-
scope, ok := scopeData.(map[string]any)
992-
if !ok {
993-
return diag.FromErr(fmt.Errorf("invalid scope data: expected object, got %T", scopeData))
994-
}
995-
996-
orgID, _ := scope[FieldEnterpriseGroupScopeOrganization].(string)
997-
clusterID, _ := scope[FieldEnterpriseGroupScopeCluster].(string)
1000+
orgID, _ := scope[FieldEnterpriseGroupScopeOrganization].(string)
1001+
clusterID, _ := scope[FieldEnterpriseGroupScopeCluster].(string)
9981002

999-
if orgID != "" && clusterID != "" {
1000-
return diag.FromErr(fmt.Errorf("scope cannot have both 'organization' and 'cluster' set simultaneously"))
1001-
}
1003+
if orgID != "" && clusterID != "" {
1004+
return diag.FromErr(fmt.Errorf("scope cannot have both 'organization' and 'cluster' set simultaneously"))
1005+
}
10021006

1003-
if orgID != "" {
1004-
rbScopes = append(rbScopes, organization_management.Scope{
1005-
Organization: &organization_management.OrganizationScope{
1006-
Id: orgID,
1007-
},
1008-
})
1009-
} else if clusterID != "" {
1010-
rbScopes = append(rbScopes, organization_management.Scope{
1011-
Cluster: &organization_management.ClusterScope{
1012-
Id: clusterID,
1013-
},
1014-
})
1015-
}
1007+
if orgID != "" {
1008+
rbScopes = append(rbScopes, organization_management.Scope{
1009+
Organization: &organization_management.OrganizationScope{
1010+
Id: orgID,
1011+
},
1012+
})
1013+
} else if clusterID != "" {
1014+
rbScopes = append(rbScopes, organization_management.Scope{
1015+
Cluster: &organization_management.ClusterScope{
1016+
Id: clusterID,
1017+
},
1018+
})
10161019
}
10171020
}
10181021
}
1022+
}
10191023

1020-
rbID := ""
1021-
if id, ok := binding[FieldEnterpriseGroupRoleBindingID].(string); ok && id != "" {
1022-
rbID = id
1023-
}
1024-
1025-
roleBindings = append(roleBindings, organization_management.BatchUpdateEnterpriseGroupsRequestRoleBinding{
1026-
Id: rbID,
1027-
Name: rbName,
1028-
RoleId: rbRoleID,
1029-
Scopes: rbScopes,
1030-
})
1024+
rbID := ""
1025+
if id, ok := binding[FieldEnterpriseGroupRoleBindingID].(string); ok && id != "" {
1026+
rbID = id
10311027
}
1028+
1029+
roleBindings = append(roleBindings, organization_management.BatchUpdateEnterpriseGroupsRequestRoleBinding{
1030+
Id: rbID,
1031+
Name: rbName,
1032+
RoleId: rbRoleID,
1033+
Scopes: rbScopes,
1034+
})
10321035
}
10331036
}
1037+
}
10341038

1035-
groupName, ok := data.Get(FieldEnterpriseGroupName).(string)
1036-
if !ok {
1037-
return diag.FromErr(fmt.Errorf("group name is required for group %s", groupID))
1038-
}
1039+
groupName, ok := data.Get(FieldEnterpriseGroupName).(string)
1040+
if !ok {
1041+
return diag.FromErr(fmt.Errorf("group name is required for group %s", groupID))
1042+
}
10391043

1040-
orgID, ok := data.Get(FieldEnterpriseGroupOrganizationID).(string)
1041-
if !ok {
1042-
return diag.FromErr(fmt.Errorf("organization ID is required for group %s", groupID))
1043-
}
1044+
orgID, ok := data.Get(FieldEnterpriseGroupOrganizationID).(string)
1045+
if !ok {
1046+
return diag.FromErr(fmt.Errorf("organization ID is required for group %s", groupID))
1047+
}
10441048

1045-
description, ok := data.GetOk(FieldEnterpriseGroupDescription)
1046-
if !ok {
1047-
description = ""
1048-
}
1049-
descriptionStr := description.(string)
1050-
1051-
updateRequest := organization_management.BatchUpdateEnterpriseGroupsRequest{
1052-
EnterpriseId: enterpriseID,
1053-
Requests: []organization_management.BatchUpdateEnterpriseGroupsRequestUpdateGroupRequest{
1054-
{
1055-
Id: groupID,
1056-
Name: groupName,
1057-
OrganizationId: orgID,
1058-
Description: descriptionStr,
1059-
Members: members,
1060-
RoleBindings: roleBindings,
1061-
},
1062-
},
1063-
}
1049+
description, ok := data.GetOk(FieldEnterpriseGroupDescription)
1050+
if !ok {
1051+
description = ""
1052+
}
1053+
descriptionStr := description.(string)
10641054

1065-
resp, err := client.EnterpriseAPIBatchUpdateEnterpriseGroupsWithResponse(
1066-
ctx,
1067-
enterpriseID,
1068-
updateRequest,
1069-
)
1070-
if err = sdk.CheckOKResponse(resp, err); err != nil {
1071-
return diag.FromErr(fmt.Errorf("batch update enterprise groups failed: %w", err))
1072-
}
1055+
updateRequest := organization_management.BatchUpdateEnterpriseGroupsRequest{
1056+
EnterpriseId: enterpriseID,
1057+
Requests: []organization_management.BatchUpdateEnterpriseGroupsRequestUpdateGroupRequest{
1058+
{
1059+
Id: groupID,
1060+
Name: groupName,
1061+
OrganizationId: orgID,
1062+
Description: descriptionStr,
1063+
Members: members,
1064+
RoleBindings: roleBindings,
1065+
},
1066+
},
1067+
}
10731068

1074-
if resp.JSON200 == nil || resp.JSON200.Groups == nil {
1075-
return diag.FromErr(fmt.Errorf("unexpected empty response from batch update"))
1076-
}
1069+
resp, err := client.EnterpriseAPIBatchUpdateEnterpriseGroupsWithResponse(
1070+
ctx,
1071+
enterpriseID,
1072+
updateRequest,
1073+
)
1074+
if err = sdk.CheckOKResponse(resp, err); err != nil {
1075+
return diag.FromErr(fmt.Errorf("batch update enterprise groups failed: %w", err))
1076+
}
10771077

1078-
g := (*resp.JSON200.Groups)[0]
1078+
if resp.JSON200 == nil || resp.JSON200.Groups == nil {
1079+
return diag.FromErr(fmt.Errorf("unexpected empty response from batch update"))
1080+
}
10791081

1080-
group, err := convertBatchUpdateEnterpriseGroupsResponseGroup(g)
1081-
if err != nil {
1082-
return diag.FromErr(fmt.Errorf("converting updated group data: %w", err))
1083-
}
1082+
g := (*resp.JSON200.Groups)[0]
10841083

1085-
if err = setEnterpriseGroupsData(data, group); err != nil {
1086-
return diag.FromErr(fmt.Errorf("failed to set updated group data: %w", err))
1087-
}
1084+
group, err := convertBatchUpdateEnterpriseGroupsResponseGroup(g)
1085+
if err != nil {
1086+
return diag.FromErr(fmt.Errorf("converting updated group data: %w", err))
1087+
}
10881088

1089-
tflog.Debug(ctx, "Enterprise group updated successfully", map[string]any{"group_id": groupID})
1089+
if err = setEnterpriseGroupsData(data, group); err != nil {
1090+
return diag.FromErr(fmt.Errorf("failed to set updated group data: %w", err))
10901091
}
10911092

1093+
tflog.Debug(ctx, "Enterprise group updated successfully", map[string]any{"group_id": groupID})
1094+
10921095
return nil
10931096
}
10941097

0 commit comments

Comments
 (0)