Skip to content

Commit a9c50fc

Browse files
authored
Fix inconsistent result after creating SKE cluster with empty node po… (#461)
* Fix inconsistent result after creating SKE cluster with empty node pool taints * Improve code readability * Suggestions from review
1 parent a15bd14 commit a9c50fc

2 files changed

Lines changed: 217 additions & 2 deletions

File tree

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,7 +1323,11 @@ func mapNodePools(ctx context.Context, cl *ske.Cluster, m *Model) error {
13231323
nodePool["cri"] = types.StringPointerValue(nodePoolResp.Cri.Name)
13241324
}
13251325

1326-
err := mapTaints(nodePoolResp.Taints, nodePool)
1326+
taintsInModel := false
1327+
if i < len(modelNodePools) && !modelNodePools[i].Taints.IsNull() && !modelNodePools[i].Taints.IsUnknown() {
1328+
taintsInModel = true
1329+
}
1330+
err := mapTaints(nodePoolResp.Taints, nodePool, taintsInModel)
13271331
if err != nil {
13281332
return fmt.Errorf("mapping index %d, field taints: %w", i, err)
13291333
}
@@ -1362,8 +1366,16 @@ func mapNodePools(ctx context.Context, cl *ske.Cluster, m *Model) error {
13621366
return nil
13631367
}
13641368

1365-
func mapTaints(t *[]ske.Taint, nodePool map[string]attr.Value) error {
1369+
func mapTaints(t *[]ske.Taint, nodePool map[string]attr.Value, existInModel bool) error {
13661370
if t == nil || len(*t) == 0 {
1371+
if existInModel {
1372+
taintsTF, diags := types.ListValue(types.ObjectType{AttrTypes: taintTypes}, []attr.Value{})
1373+
if diags.HasError() {
1374+
return fmt.Errorf("create empty taints list: %w", core.DiagsToError(diags))
1375+
}
1376+
nodePool["taints"] = taintsTF
1377+
return nil
1378+
}
13671379
nodePool["taints"] = types.ListNull(types.ObjectType{AttrTypes: taintTypes})
13681380
return nil
13691381
}

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

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ func TestMapFields(t *testing.T) {
3131
tests := []struct {
3232
description string
3333
stateExtensions types.Object
34+
stateNodePools types.List
3435
input *ske.Cluster
3536
expected Model
3637
isValid bool
3738
}{
3839
{
3940
"default_values",
4041
types.ObjectNull(extensionsTypes),
42+
types.ListNull(types.ObjectType{AttrTypes: nodePoolTypes}),
4143
&ske.Cluster{
4244
Name: utils.Ptr("name"),
4345
},
@@ -59,6 +61,7 @@ func TestMapFields(t *testing.T) {
5961
{
6062
"simple_values",
6163
types.ObjectNull(extensionsTypes),
64+
types.ListNull(types.ObjectType{AttrTypes: nodePoolTypes}),
6265
&ske.Cluster{
6366
Extensions: &ske.Extension{
6467
Acl: &ske.ACL{
@@ -233,6 +236,7 @@ func TestMapFields(t *testing.T) {
233236
{
234237
"empty_network",
235238
types.ObjectNull(extensionsTypes),
239+
types.ListNull(types.ObjectType{AttrTypes: nodePoolTypes}),
236240
&ske.Cluster{
237241
Name: utils.Ptr("name"),
238242
Network: &ske.Network{},
@@ -255,6 +259,7 @@ func TestMapFields(t *testing.T) {
255259
{
256260
"extensions_mixed_values",
257261
types.ObjectNull(extensionsTypes),
262+
types.ListNull(types.ObjectType{AttrTypes: nodePoolTypes}),
258263
&ske.Cluster{
259264
Extensions: &ske.Extension{
260265
Acl: &ske.ACL{
@@ -303,6 +308,7 @@ func TestMapFields(t *testing.T) {
303308
"argus_instance_id": types.StringNull(),
304309
}),
305310
}),
311+
types.ListNull(types.ObjectType{AttrTypes: nodePoolTypes}),
306312
&ske.Cluster{
307313
Extensions: &ske.Extension{},
308314
Name: utils.Ptr("name"),
@@ -344,6 +350,7 @@ func TestMapFields(t *testing.T) {
344350
"argus_instance_id": types.StringValue("id"),
345351
}),
346352
}),
353+
types.ListNull(types.ObjectType{AttrTypes: nodePoolTypes}),
347354
&ske.Cluster{
348355
Extensions: &ske.Extension{
349356
Acl: &ske.ACL{
@@ -381,6 +388,7 @@ func TestMapFields(t *testing.T) {
381388
{
382389
"extensions_not_set",
383390
types.ObjectNull(extensionsTypes),
391+
types.ListNull(types.ObjectType{AttrTypes: nodePoolTypes}),
384392
&ske.Cluster{
385393
Extensions: &ske.Extension{},
386394
Name: utils.Ptr("name"),
@@ -399,16 +407,210 @@ func TestMapFields(t *testing.T) {
399407
},
400408
true,
401409
},
410+
{
411+
"nil_taints_when_empty_list_on_state",
412+
types.ObjectNull(extensionsTypes),
413+
types.ListValueMust(
414+
types.ObjectType{AttrTypes: nodePoolTypes},
415+
[]attr.Value{
416+
types.ObjectValueMust(
417+
nodePoolTypes,
418+
map[string]attr.Value{
419+
"name": types.StringValue("node"),
420+
"machine_type": types.StringValue("B"),
421+
"os_name": types.StringValue("os"),
422+
"os_version": types.StringNull(),
423+
"os_version_min": types.StringNull(),
424+
"os_version_used": types.StringValue("os-ver"),
425+
"minimum": types.Int64Value(1),
426+
"maximum": types.Int64Value(5),
427+
"max_surge": types.Int64Value(3),
428+
"max_unavailable": types.Int64Null(),
429+
"volume_type": types.StringValue("type"),
430+
"volume_size": types.Int64Value(3),
431+
"labels": types.MapValueMust(
432+
types.StringType,
433+
map[string]attr.Value{
434+
"k": types.StringValue("v"),
435+
},
436+
),
437+
"taints": types.ListValueMust(types.ObjectType{AttrTypes: taintTypes}, []attr.Value{}),
438+
"cri": types.StringValue("cri"),
439+
"availability_zones": types.ListValueMust(
440+
types.StringType,
441+
[]attr.Value{
442+
types.StringValue("z1"),
443+
types.StringValue("z2"),
444+
},
445+
),
446+
},
447+
),
448+
},
449+
),
450+
&ske.Cluster{
451+
Extensions: &ske.Extension{
452+
Acl: &ske.ACL{
453+
AllowedCidrs: &[]string{"cidr1"},
454+
Enabled: utils.Ptr(true),
455+
},
456+
Argus: &ske.Argus{
457+
ArgusInstanceId: utils.Ptr("aid"),
458+
Enabled: utils.Ptr(true),
459+
},
460+
},
461+
Hibernation: &ske.Hibernation{
462+
Schedules: &[]ske.HibernationSchedule{
463+
{
464+
End: utils.Ptr("2"),
465+
Start: utils.Ptr("1"),
466+
Timezone: utils.Ptr("CET"),
467+
},
468+
},
469+
},
470+
Kubernetes: &ske.Kubernetes{
471+
AllowPrivilegedContainers: utils.Ptr(true),
472+
Version: utils.Ptr("1.2.3"),
473+
},
474+
Maintenance: &ske.Maintenance{
475+
AutoUpdate: &ske.MaintenanceAutoUpdate{
476+
KubernetesVersion: utils.Ptr(true),
477+
MachineImageVersion: utils.Ptr(true),
478+
},
479+
TimeWindow: &ske.TimeWindow{
480+
Start: utils.Ptr("0000-01-02T03:04:05+06:00"),
481+
End: utils.Ptr("0010-11-12T13:14:15Z"),
482+
},
483+
},
484+
Network: &ske.Network{
485+
Id: utils.Ptr("nid"),
486+
},
487+
Name: utils.Ptr("name"),
488+
Nodepools: &[]ske.Nodepool{
489+
{
490+
AvailabilityZones: &[]string{"z1", "z2"},
491+
Cri: &ske.CRI{
492+
Name: utils.Ptr("cri"),
493+
},
494+
Labels: &map[string]string{"k": "v"},
495+
Machine: &ske.Machine{
496+
Image: &ske.Image{
497+
Name: utils.Ptr("os"),
498+
Version: utils.Ptr("os-ver"),
499+
},
500+
Type: utils.Ptr("B"),
501+
},
502+
MaxSurge: utils.Ptr(int64(3)),
503+
MaxUnavailable: nil,
504+
Maximum: utils.Ptr(int64(5)),
505+
Minimum: utils.Ptr(int64(1)),
506+
Name: utils.Ptr("node"),
507+
Taints: nil,
508+
Volume: &ske.Volume{
509+
Size: utils.Ptr(int64(3)),
510+
Type: utils.Ptr("type"),
511+
},
512+
},
513+
},
514+
Status: &ske.ClusterStatus{
515+
Aggregated: &cs,
516+
Error: nil,
517+
Hibernated: nil,
518+
},
519+
},
520+
Model{
521+
Id: types.StringValue("pid,name"),
522+
ProjectId: types.StringValue("pid"),
523+
Name: types.StringValue("name"),
524+
KubernetesVersion: types.StringNull(),
525+
KubernetesVersionUsed: types.StringValue("1.2.3"),
526+
AllowPrivilegedContainers: types.BoolValue(true),
527+
NodePools: types.ListValueMust(
528+
types.ObjectType{AttrTypes: nodePoolTypes},
529+
[]attr.Value{
530+
types.ObjectValueMust(
531+
nodePoolTypes,
532+
map[string]attr.Value{
533+
"name": types.StringValue("node"),
534+
"machine_type": types.StringValue("B"),
535+
"os_name": types.StringValue("os"),
536+
"os_version": types.StringNull(),
537+
"os_version_min": types.StringNull(),
538+
"os_version_used": types.StringValue("os-ver"),
539+
"minimum": types.Int64Value(1),
540+
"maximum": types.Int64Value(5),
541+
"max_surge": types.Int64Value(3),
542+
"max_unavailable": types.Int64Null(),
543+
"volume_type": types.StringValue("type"),
544+
"volume_size": types.Int64Value(3),
545+
"labels": types.MapValueMust(
546+
types.StringType,
547+
map[string]attr.Value{
548+
"k": types.StringValue("v"),
549+
},
550+
),
551+
"taints": types.ListValueMust(types.ObjectType{AttrTypes: taintTypes}, []attr.Value{}),
552+
"cri": types.StringValue("cri"),
553+
"availability_zones": types.ListValueMust(
554+
types.StringType,
555+
[]attr.Value{
556+
types.StringValue("z1"),
557+
types.StringValue("z2"),
558+
},
559+
),
560+
},
561+
),
562+
},
563+
),
564+
Maintenance: types.ObjectValueMust(maintenanceTypes, map[string]attr.Value{
565+
"enable_kubernetes_version_updates": types.BoolValue(true),
566+
"enable_machine_image_version_updates": types.BoolValue(true),
567+
"start": types.StringValue("03:04:05+06:00"),
568+
"end": types.StringValue("13:14:15Z"),
569+
}),
570+
Network: types.ObjectValueMust(networkTypes, map[string]attr.Value{
571+
"id": types.StringValue("nid"),
572+
}),
573+
Hibernations: types.ListValueMust(
574+
types.ObjectType{AttrTypes: hibernationTypes},
575+
[]attr.Value{
576+
types.ObjectValueMust(
577+
hibernationTypes,
578+
map[string]attr.Value{
579+
"start": types.StringValue("1"),
580+
"end": types.StringValue("2"),
581+
"timezone": types.StringValue("CET"),
582+
},
583+
),
584+
},
585+
),
586+
Extensions: types.ObjectValueMust(extensionsTypes, map[string]attr.Value{
587+
"acl": types.ObjectValueMust(aclTypes, map[string]attr.Value{
588+
"enabled": types.BoolValue(true),
589+
"allowed_cidrs": types.ListValueMust(types.StringType, []attr.Value{
590+
types.StringValue("cidr1"),
591+
}),
592+
}),
593+
"argus": types.ObjectValueMust(argusTypes, map[string]attr.Value{
594+
"enabled": types.BoolValue(true),
595+
"argus_instance_id": types.StringValue("aid"),
596+
}),
597+
}),
598+
KubeConfig: types.StringNull(),
599+
},
600+
true,
601+
},
402602
{
403603
"nil_response",
404604
types.ObjectNull(extensionsTypes),
605+
types.ListNull(types.ObjectType{AttrTypes: nodePoolTypes}),
405606
nil,
406607
Model{},
407608
false,
408609
},
409610
{
410611
"no_resource_id",
411612
types.ObjectNull(extensionsTypes),
613+
types.ListNull(types.ObjectType{AttrTypes: nodePoolTypes}),
412614
&ske.Cluster{},
413615
Model{},
414616
false,
@@ -419,6 +621,7 @@ func TestMapFields(t *testing.T) {
419621
state := &Model{
420622
ProjectId: tt.expected.ProjectId,
421623
Extensions: tt.stateExtensions,
624+
NodePools: tt.stateNodePools,
422625
}
423626
err := mapFields(context.Background(), tt.input, state)
424627
if !tt.isValid && err == nil {

0 commit comments

Comments
 (0)