Skip to content

Commit d1b10d2

Browse files
SKE Cluster: fix extensions and hibernations mapping (#135)
* Fix bug in extensions.argus conversion * Fix mapExtensions * Fix extensions mapping, add test case * Check disabled argus or acl independently * Add last fixes * Replace NewListValueFrom with NewListValue * Remove unused argument
1 parent cbbf3a0 commit d1b10d2

File tree

2 files changed

+254
-21
lines changed

2 files changed

+254
-21
lines changed

stackit/internal/services/ske/cluster/resource.go

Lines changed: 95 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ type extensions struct {
154154

155155
// Types corresponding to extensions
156156
var extensionsTypes = map[string]attr.Type{
157-
"argus": basetypes.ObjectType{AttrTypes: argusExtensionTypes},
157+
"argus": basetypes.ObjectType{AttrTypes: argusTypes},
158158
"acl": basetypes.ObjectType{AttrTypes: aclTypes},
159159
}
160160

@@ -169,13 +169,13 @@ var aclTypes = map[string]attr.Type{
169169
"allowed_cidrs": basetypes.ListType{ElemType: types.StringType},
170170
}
171171

172-
type argusExtension struct {
172+
type argus struct {
173173
Enabled types.Bool `tfsdk:"enabled"`
174174
ArgusInstanceId types.String `tfsdk:"argus_instance_id"`
175175
}
176176

177177
// Types corresponding to argusExtension
178-
var argusExtensionTypes = map[string]attr.Type{
178+
var argusTypes = map[string]attr.Type{
179179
"enabled": basetypes.BoolType{},
180180
"argus_instance_id": basetypes.StringType{},
181181
}
@@ -490,7 +490,7 @@ func (r *clusterResource) Schema(_ context.Context, _ resource.SchemaRequest, re
490490
},
491491
"allowed_cidrs": schema.ListAttribute{
492492
Description: "Specify a list of CIDRs to whitelist.",
493-
Required: true,
493+
Optional: true,
494494
ElementType: types.StringType,
495495
},
496496
},
@@ -818,24 +818,24 @@ func toExtensionsPayload(ctx context.Context, m *Cluster) (*ske.Extension, error
818818
}
819819
}
820820

821-
var skeArgusExtension *ske.Argus
821+
var skeArgus *ske.Argus
822822
if !(ex.Argus.IsNull() || ex.Argus.IsUnknown()) {
823-
argus := argusExtension{}
823+
argus := argus{}
824824
diags = ex.Argus.As(ctx, &argus, basetypes.ObjectAsOptions{})
825825
if diags.HasError() {
826826
return nil, fmt.Errorf("converting extensions.argus object: %v", diags.Errors())
827827
}
828828
argusEnabled := conversion.BoolValueToPointer(argus.Enabled)
829829
argusInstanceId := conversion.StringValueToPointer(argus.ArgusInstanceId)
830-
skeArgusExtension = &ske.Argus{
830+
skeArgus = &ske.Argus{
831831
Enabled: argusEnabled,
832832
ArgusInstanceId: argusInstanceId,
833833
}
834834
}
835835

836836
return &ske.Extension{
837837
Acl: skeAcl,
838-
Argus: skeArgusExtension,
838+
Argus: skeArgus,
839839
}, nil
840840
}
841841

@@ -1040,11 +1040,28 @@ func mapTaints(t *[]ske.Taint, nodePool map[string]attr.Value) error {
10401040
}
10411041

10421042
func mapHibernations(cl *ske.ClusterResponse, m *Cluster) error {
1043-
if cl.Hibernation == nil || cl.Hibernation.Schedules == nil {
1043+
if cl.Hibernation == nil {
1044+
if !m.Hibernations.IsNull() {
1045+
emptyHibernations, diags := basetypes.NewListValue(basetypes.ObjectType{AttrTypes: hibernationTypes}, []attr.Value{})
1046+
if diags.HasError() {
1047+
return fmt.Errorf("hibernations is an empty list, converting to terraform empty list: %w", core.DiagsToError(diags))
1048+
}
1049+
m.Hibernations = emptyHibernations
1050+
return nil
1051+
}
10441052
m.Hibernations = basetypes.NewListNull(basetypes.ObjectType{AttrTypes: hibernationTypes})
10451053
return nil
10461054
}
10471055

1056+
if cl.Hibernation.Schedules == nil {
1057+
emptyHibernations, diags := basetypes.NewListValue(basetypes.ObjectType{AttrTypes: hibernationTypes}, []attr.Value{})
1058+
if diags.HasError() {
1059+
return fmt.Errorf("hibernations is an empty list, converting to terraform empty list: %w", core.DiagsToError(diags))
1060+
}
1061+
m.Hibernations = emptyHibernations
1062+
return nil
1063+
}
1064+
10481065
hibernations := []attr.Value{}
10491066
for i, hibernationResp := range *cl.Hibernation.Schedules {
10501067
hibernation := map[string]attr.Value{
@@ -1149,14 +1166,73 @@ func getMaintenanceTimes(ctx context.Context, cl *ske.ClusterResponse, m *Cluste
11491166
return startTime, endTime, nil
11501167
}
11511168

1169+
func checkDisabledExtensions(ctx context.Context, ex extensions) (aclDisabled, argusDisabled bool, err error) {
1170+
var diags diag.Diagnostics
1171+
acl := acl{}
1172+
if ex.ACL.IsNull() {
1173+
acl.Enabled = types.BoolValue(false)
1174+
} else {
1175+
diags = ex.ACL.As(ctx, &acl, basetypes.ObjectAsOptions{})
1176+
if diags.HasError() {
1177+
return false, false, fmt.Errorf("converting extensions.acl object: %v", diags.Errors())
1178+
}
1179+
}
1180+
1181+
argus := argus{}
1182+
if ex.Argus.IsNull() {
1183+
argus.Enabled = types.BoolValue(false)
1184+
} else {
1185+
diags = ex.Argus.As(ctx, &argus, basetypes.ObjectAsOptions{})
1186+
if diags.HasError() {
1187+
return false, false, fmt.Errorf("converting extensions.argus object: %v", diags.Errors())
1188+
}
1189+
}
1190+
1191+
return !acl.Enabled.ValueBool(), !argus.Enabled.ValueBool(), nil
1192+
}
1193+
11521194
func mapExtensions(ctx context.Context, cl *ske.ClusterResponse, m *Cluster) error {
1153-
if cl.Extensions == nil || (cl.Extensions.Argus == nil && cl.Extensions.Acl == nil) {
1195+
if cl.Extensions == nil {
11541196
m.Extensions = types.ObjectNull(extensionsTypes)
11551197
return nil
11561198
}
11571199

11581200
var diags diag.Diagnostics
1159-
acl := types.ObjectNull(aclTypes)
1201+
ex := extensions{}
1202+
if !m.Extensions.IsNull() {
1203+
diags := m.Extensions.As(ctx, &ex, basetypes.ObjectAsOptions{})
1204+
if diags.HasError() {
1205+
return fmt.Errorf("converting extensions object: %v", diags.Errors())
1206+
}
1207+
}
1208+
1209+
// If the user provides the extensions block with the enabled flags as false
1210+
// the SKE API will return an empty extensions block, which throws an inconsistent
1211+
// result after apply error. To prevent this error, if both flags are false,
1212+
// we set the fields provided by the user in the terraform model
1213+
1214+
// If the extensions field is not provided, the SKE API returns an empty object.
1215+
// If we parse that object into the terraform model, it will produce an inconsistent result after apply
1216+
// error
1217+
1218+
aclDisabled, argusDisabled, err := checkDisabledExtensions(ctx, ex)
1219+
if err != nil {
1220+
return fmt.Errorf("checking if extensions are disabled: %w", err)
1221+
}
1222+
disabledExtensions := false
1223+
if aclDisabled && argusDisabled {
1224+
disabledExtensions = true
1225+
}
1226+
1227+
emptyExtensions := &ske.Extension{}
1228+
if *cl.Extensions == *emptyExtensions && (disabledExtensions || m.Extensions.IsNull()) {
1229+
if m.Extensions.Attributes() == nil {
1230+
m.Extensions = types.ObjectNull(extensionsTypes)
1231+
}
1232+
return nil
1233+
}
1234+
1235+
aclExtension := types.ObjectNull(aclTypes)
11601236
if cl.Extensions.Acl != nil {
11611237
enabled := types.BoolNull()
11621238
if cl.Extensions.Acl.Enabled != nil {
@@ -1173,13 +1249,15 @@ func mapExtensions(ctx context.Context, cl *ske.ClusterResponse, m *Cluster) err
11731249
"allowed_cidrs": cidrsList,
11741250
}
11751251

1176-
acl, diags = types.ObjectValue(aclTypes, aclValues)
1252+
aclExtension, diags = types.ObjectValue(aclTypes, aclValues)
11771253
if diags.HasError() {
11781254
return fmt.Errorf("creating acl: %w", core.DiagsToError(diags))
11791255
}
1256+
} else if aclDisabled && !ex.ACL.IsNull() {
1257+
aclExtension = ex.ACL
11801258
}
11811259

1182-
argusExtension := types.ObjectNull(argusExtensionTypes)
1260+
argusExtension := types.ObjectNull(argusTypes)
11831261
if cl.Extensions.Argus != nil {
11841262
enabled := types.BoolNull()
11851263
if cl.Extensions.Argus.Enabled != nil {
@@ -1196,14 +1274,16 @@ func mapExtensions(ctx context.Context, cl *ske.ClusterResponse, m *Cluster) err
11961274
"argus_instance_id": argusInstanceId,
11971275
}
11981276

1199-
argusExtension, diags = types.ObjectValue(argusExtensionTypes, argusExtensionValues)
1277+
argusExtension, diags = types.ObjectValue(argusTypes, argusExtensionValues)
12001278
if diags.HasError() {
12011279
return fmt.Errorf("creating argus extension: %w", core.DiagsToError(diags))
12021280
}
1281+
} else if argusDisabled && !ex.Argus.IsNull() {
1282+
argusExtension = ex.Argus
12031283
}
12041284

12051285
extensionsValues := map[string]attr.Value{
1206-
"acl": acl,
1286+
"acl": aclExtension,
12071287
"argus": argusExtension,
12081288
}
12091289

0 commit comments

Comments
 (0)