From 514fe6e7f1168422792a9bb97c649e8386728397 Mon Sep 17 00:00:00 2001 From: Manuel Vaas Date: Fri, 7 Aug 2026 18:25:51 +0200 Subject: [PATCH 1/4] fix(ske): nil pointer when gateway api is not set relates to #1671 --- stackit/internal/services/ske/cluster/resource.go | 2 +- .../internal/services/ske/cluster/resource_test.go | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/stackit/internal/services/ske/cluster/resource.go b/stackit/internal/services/ske/cluster/resource.go index c2d2051ec..063a058f5 100644 --- a/stackit/internal/services/ske/cluster/resource.go +++ b/stackit/internal/services/ske/cluster/resource.go @@ -2161,7 +2161,7 @@ func mapExtensions(ctx context.Context, cl *ske.Cluster, m *Model) error { dnsExtension := types.ObjectNull(dnsTypes) if cl.Extensions.Dns != nil { enabled := types.BoolValue(cl.Extensions.Dns.Enabled) - gatewayApi := types.BoolValue(*cl.Extensions.Dns.GatewayApi) + gatewayApi := types.BoolPointerValue(cl.Extensions.Dns.GatewayApi) zonesList, diags := types.ListValueFrom(ctx, types.StringType, cl.Extensions.Dns.Zones) if diags.HasError() { diff --git a/stackit/internal/services/ske/cluster/resource_test.go b/stackit/internal/services/ske/cluster/resource_test.go index ec6ad006e..5e330305f 100644 --- a/stackit/internal/services/ske/cluster/resource_test.go +++ b/stackit/internal/services/ske/cluster/resource_test.go @@ -342,9 +342,8 @@ func TestMapFields(t *testing.T) { Enabled: true, }, Dns: &ske.DNS{ - Zones: nil, - Enabled: true, - GatewayApi: new(true), + Zones: nil, + Enabled: true, }, ApplicationLoadBalancer: &ske.ApplicationLoadBalancer{ Enabled: true, @@ -382,7 +381,7 @@ func TestMapFields(t *testing.T) { "dns": types.ObjectValueMust(dnsTypes, map[string]attr.Value{ "enabled": types.BoolValue(true), "zones": types.ListNull(types.StringType), - "gateway_api": types.BoolValue(true), + "gateway_api": types.BoolNull(), }), "application_load_balancer": types.ObjectValueMust(applicationLoadBalancerTypes, map[string]attr.Value{ "enabled": types.BoolValue(true), @@ -409,7 +408,7 @@ func TestMapFields(t *testing.T) { "dns": types.ObjectValueMust(dnsTypes, map[string]attr.Value{ "enabled": types.BoolValue(false), "zones": types.ListNull(types.StringType), - "gateway_api": types.BoolValue(false), + "gateway_api": types.BoolNull(), }), "application_load_balancer": types.ObjectValueMust(applicationLoadBalancerTypes, map[string]attr.Value{ "enabled": types.BoolValue(false), @@ -450,7 +449,7 @@ func TestMapFields(t *testing.T) { "dns": types.ObjectValueMust(dnsTypes, map[string]attr.Value{ "enabled": types.BoolValue(false), "zones": types.ListNull(types.StringType), - "gateway_api": types.BoolValue(false), + "gateway_api": types.BoolNull(), }), "application_load_balancer": types.ObjectValueMust(applicationLoadBalancerTypes, map[string]attr.Value{ "enabled": types.BoolValue(false), From 46951d3141ac4aa1d642bebecaff0be3219d0fd3 Mon Sep 17 00:00:00 2001 From: Manuel Vaas Date: Wed, 12 Aug 2026 14:18:58 +0200 Subject: [PATCH 2/4] fix ske --- stackit/internal/services/ske/cluster/resource.go | 14 ++++++++------ .../internal/services/ske/cluster/resource_test.go | 5 ++++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/stackit/internal/services/ske/cluster/resource.go b/stackit/internal/services/ske/cluster/resource.go index 063a058f5..887e1b1ee 100644 --- a/stackit/internal/services/ske/cluster/resource.go +++ b/stackit/internal/services/ske/cluster/resource.go @@ -754,6 +754,7 @@ func (r *clusterResource) Schema(_ context.Context, _ resource.SchemaRequest, re "extensions": schema.SingleNestedAttribute{ Description: "A single extensions block as defined below.", Optional: true, + Computed: true, PlanModifiers: []planmodifier.Object{ objectplanmodifier.UseStateForUnknown(), }, @@ -830,13 +831,13 @@ func (r *clusterResource) Schema(_ context.Context, _ resource.SchemaRequest, re "gateway_api": schema.BoolAttribute{ Description: "Enables Gateway API support for ExternalDNS. The CRDs must be installed by the user. Once installed, ExternalDNS will be configured at the next cluster reconcile.", Optional: true, - Computed: true, }, }, }, "application_load_balancer": schema.SingleNestedAttribute{ Description: "Application Load Balancer extension.", Optional: true, + Computed: true, Attributes: map[string]schema.Attribute{ "enabled": schema.BoolAttribute{ Description: "Enables the application load balancer extension. Note: This feature is in private preview. Enabling application load balancer extension is only possible for enabled accounts. Otherwise the request will be rejected.", @@ -2029,7 +2030,7 @@ func checkDisabledExtensions(ctx context.Context, ex *extensions) (aclDisabled, } applicationLoadBalancer := applicationLoadBalancer{} - if ex.ApplicationLoadBalancer.IsNull() { + if utils.IsUndefined(ex.ApplicationLoadBalancer) { applicationLoadBalancer.Enabled = types.BoolValue(false) } else { diags = ex.ApplicationLoadBalancer.As(ctx, &applicationLoadBalancer, basetypes.ObjectAsOptions{}) @@ -2049,11 +2050,13 @@ func mapExtensions(ctx context.Context, cl *ske.Cluster, m *Model) error { var diags diag.Diagnostics ex := extensions{} - if !m.Extensions.IsNull() { + if !utils.IsUndefined(m.Extensions) { diags := m.Extensions.As(ctx, &ex, basetypes.ObjectAsOptions{}) if diags.HasError() { return fmt.Errorf("converting extensions object: %v", diags.Errors()) } + } else { + m.Extensions = types.ObjectNull(extensionsTypes) } // If the user provides the extensions block with the enabled flags as false @@ -2069,9 +2072,8 @@ func mapExtensions(ctx context.Context, cl *ske.Cluster, m *Model) error { if err != nil { return fmt.Errorf("checking if extensions are disabled: %w", err) } - disabledExtensions := aclDisabled && observabilityDisabled && dnsDisabled && applicationLoadBalancerDisabled - if skeUtils.IsEmptyExtension(cl.Extensions) && (disabledExtensions || m.Extensions.IsNull()) { + if skeUtils.IsEmptyExtension(cl.Extensions) && utils.IsUndefined(m.Extensions) { if m.Extensions.Attributes() == nil { m.Extensions = types.ObjectNull(extensionsTypes) } @@ -2154,7 +2156,7 @@ func mapExtensions(ctx context.Context, cl *ske.Cluster, m *Model) error { if diags.HasError() { return fmt.Errorf("creating applicationLoadBalancer: %w", core.DiagsToError(diags)) } - } else if applicationLoadBalancerDisabled && !ex.ApplicationLoadBalancer.IsNull() { + } else if applicationLoadBalancerDisabled && !utils.IsUndefined(ex.ApplicationLoadBalancer) { applicationLoadBalancerExtension = ex.ApplicationLoadBalancer } diff --git a/stackit/internal/services/ske/cluster/resource_test.go b/stackit/internal/services/ske/cluster/resource_test.go index 5e330305f..97d55ac33 100644 --- a/stackit/internal/services/ske/cluster/resource_test.go +++ b/stackit/internal/services/ske/cluster/resource_test.go @@ -496,6 +496,9 @@ func TestMapFields(t *testing.T) { Enabled: true, GatewayApi: new(true), }, + ApplicationLoadBalancer: &ske.ApplicationLoadBalancer{ + Enabled: true, + }, }, Name: new("name"), Access: &ske.Access{ @@ -534,7 +537,7 @@ func TestMapFields(t *testing.T) { "gateway_api": types.BoolValue(true), }), "application_load_balancer": types.ObjectValueMust(applicationLoadBalancerTypes, map[string]attr.Value{ - "enabled": types.BoolValue(false), + "enabled": types.BoolValue(true), }), }), KubernetesVersionUsed: types.StringValue(""), From 6e29224be93a5d815ee8d9c39ca8e437a4756102 Mon Sep 17 00:00:00 2001 From: Manuel Vaas Date: Thu, 13 Aug 2026 09:54:54 +0200 Subject: [PATCH 3/4] fix toPayload function --- stackit/internal/services/ske/cluster/resource.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stackit/internal/services/ske/cluster/resource.go b/stackit/internal/services/ske/cluster/resource.go index 887e1b1ee..771372514 100644 --- a/stackit/internal/services/ske/cluster/resource.go +++ b/stackit/internal/services/ske/cluster/resource.go @@ -1499,7 +1499,7 @@ func toExtensionsPayload(ctx context.Context, m *Model) (*ske.Extension, error) return nil, fmt.Errorf("converting extensions.dns object: %v", diags.Errors()) } dnsEnabled := dns.Enabled.ValueBool() - gatewayApi := dns.GatewayApi.ValueBool() + gatewayApi := conversion.BoolValueToPointer(dns.GatewayApi) zones := []string{} diags = dns.Zones.ElementsAs(ctx, &zones, true) @@ -1509,7 +1509,7 @@ func toExtensionsPayload(ctx context.Context, m *Model) (*ske.Extension, error) skeDNS = &ske.DNS{ Enabled: dnsEnabled, Zones: zones, - GatewayApi: &gatewayApi, + GatewayApi: gatewayApi, } } From c7d85a66cdd13af8df4959debe46154c33c1e54c Mon Sep 17 00:00:00 2001 From: Manuel Vaas Date: Thu, 13 Aug 2026 17:19:31 +0200 Subject: [PATCH 4/4] remove plan modifier --- stackit/internal/services/ske/cluster/resource.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/stackit/internal/services/ske/cluster/resource.go b/stackit/internal/services/ske/cluster/resource.go index 771372514..929362a8d 100644 --- a/stackit/internal/services/ske/cluster/resource.go +++ b/stackit/internal/services/ske/cluster/resource.go @@ -755,9 +755,6 @@ func (r *clusterResource) Schema(_ context.Context, _ resource.SchemaRequest, re Description: "A single extensions block as defined below.", Optional: true, Computed: true, - PlanModifiers: []planmodifier.Object{ - objectplanmodifier.UseStateForUnknown(), - }, Attributes: map[string]schema.Attribute{ "argus": schema.SingleNestedAttribute{ Description: "A single argus block as defined below. This field is deprecated and will be removed 06 January 2026.", @@ -2055,8 +2052,6 @@ func mapExtensions(ctx context.Context, cl *ske.Cluster, m *Model) error { if diags.HasError() { return fmt.Errorf("converting extensions object: %v", diags.Errors()) } - } else { - m.Extensions = types.ObjectNull(extensionsTypes) } // If the user provides the extensions block with the enabled flags as false @@ -2073,13 +2068,6 @@ func mapExtensions(ctx context.Context, cl *ske.Cluster, m *Model) error { return fmt.Errorf("checking if extensions are disabled: %w", err) } - if skeUtils.IsEmptyExtension(cl.Extensions) && utils.IsUndefined(m.Extensions) { - if m.Extensions.Attributes() == nil { - m.Extensions = types.ObjectNull(extensionsTypes) - } - return nil - } - aclExtension := types.ObjectNull(aclTypes) if cl.Extensions.Acl != nil { enabled := types.BoolValue(cl.Extensions.Acl.Enabled)