Skip to content

Commit 557e9d6

Browse files
committed
fix(ske): diff in plan triggers always replace because of network.id
1 parent acd75e4 commit 557e9d6

4 files changed

Lines changed: 291 additions & 33 deletions

File tree

docs/resources/ske_cluster.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,15 +193,12 @@ Optional:
193193
<a id="nestedatt--maintenance"></a>
194194
### Nested Schema for `maintenance`
195195

196-
Required:
197-
198-
- `end` (String) Time for maintenance window end. E.g. `01:23:45Z`, `05:00:00+02:00`.
199-
- `start` (String) Time for maintenance window start. E.g. `01:23:45Z`, `05:00:00+02:00`.
200-
201196
Optional:
202197

203198
- `enable_kubernetes_version_updates` (Boolean) Flag to enable/disable auto-updates of the Kubernetes version. Defaults to `true`. SKE automatically updates the cluster Kubernetes version if you have set `maintenance.enable_kubernetes_version_updates` to true or if there is a mandatory update, as described in [General information for Kubernetes & OS updates](https://docs.stackit.cloud/products/runtime/kubernetes-engine/basics/version-updates/).
204199
- `enable_machine_image_version_updates` (Boolean) Flag to enable/disable auto-updates of the OS image version. Defaults to `true`. SKE automatically updates the cluster Kubernetes version if you have set `maintenance.enable_kubernetes_version_updates` to true or if there is a mandatory update, as described in [General information for Kubernetes & OS updates](https://docs.stackit.cloud/products/runtime/kubernetes-engine/basics/version-updates/).
200+
- `end` (String) Time for maintenance window end. E.g. `01:23:45Z`, `05:00:00+02:00`.
201+
- `start` (String) Time for maintenance window start. E.g. `01:23:45Z`, `05:00:00+02:00`.
205202

206203

207204
<a id="nestedatt--network"></a>

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

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@ import (
1414
stringplanmodifierUtils "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils/planmodifiers/stringplanmodifier"
1515

1616
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
17+
"github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator"
1718
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
1819
"github.com/hashicorp/terraform-plugin-framework/attr"
1920
"github.com/hashicorp/terraform-plugin-framework/diag"
21+
"github.com/hashicorp/terraform-plugin-framework/path"
2022
"github.com/hashicorp/terraform-plugin-framework/resource"
2123
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
2224
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
25+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
2326
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int32default"
2427
"github.com/hashicorp/terraform-plugin-framework/resource/schema/listdefault"
2528
"github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier"
@@ -524,37 +527,59 @@ func (r *clusterResource) Schema(_ context.Context, _ resource.SchemaRequest, re
524527
PlanModifiers: []planmodifier.Object{
525528
objectplanmodifier.UseStateForUnknown(),
526529
},
530+
Validators: []validator.Object{
531+
objectvalidator.AlsoRequires(
532+
path.MatchRelative().AtName("start"),
533+
path.MatchRelative().AtName("end"),
534+
),
535+
},
527536
Attributes: map[string]schema.Attribute{
528537
"enable_kubernetes_version_updates": schema.BoolAttribute{
529538
Description: "Flag to enable/disable auto-updates of the Kubernetes version. Defaults to `true`. " + SKEUpdateDoc,
530539
Optional: true,
531540
Computed: true,
532541
Default: booldefault.StaticBool(true),
542+
PlanModifiers: []planmodifier.Bool{
543+
boolplanmodifier.UseStateForUnknown(),
544+
},
533545
},
534546
"enable_machine_image_version_updates": schema.BoolAttribute{
535547
Description: "Flag to enable/disable auto-updates of the OS image version. Defaults to `true`. " + SKEUpdateDoc,
536548
Optional: true,
537549
Computed: true,
538550
Default: booldefault.StaticBool(true),
551+
PlanModifiers: []planmodifier.Bool{
552+
boolplanmodifier.UseStateForUnknown(),
553+
},
539554
},
540555
"start": schema.StringAttribute{
541556
Description: "Time for maintenance window start. E.g. `01:23:45Z`, `05:00:00+02:00`.",
542-
Required: true,
557+
Optional: true,
558+
Computed: true,
543559
Validators: []validator.String{
544560
stringvalidator.RegexMatches(
545561
regexp.MustCompile(`^(((\d{2}:\d{2}:\d{2}(?:\.\d+)?))(Z|[\+-]\d{2}:\d{2})?)$`),
546562
"must be a full-time as defined by RFC3339, Section 5.6. E.g. `01:23:45Z`, `05:00:00+02:00`",
547563
),
564+
stringvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("end")),
565+
},
566+
PlanModifiers: []planmodifier.String{
567+
stringplanmodifier.UseStateForUnknown(),
548568
},
549569
},
550570
"end": schema.StringAttribute{
551571
Description: "Time for maintenance window end. E.g. `01:23:45Z`, `05:00:00+02:00`.",
552-
Required: true,
572+
Optional: true,
573+
Computed: true,
553574
Validators: []validator.String{
554575
stringvalidator.RegexMatches(
555576
regexp.MustCompile(`^(((\d{2}:\d{2}:\d{2}(?:\.\d+)?))(Z|[\+-]\d{2}:\d{2})?)$`),
556577
"must be a full-time as defined by RFC3339, Section 5.6. E.g. `01:23:45Z`, `05:00:00+02:00`",
557578
),
579+
stringvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("start")),
580+
},
581+
PlanModifiers: []planmodifier.String{
582+
stringplanmodifier.UseStateForUnknown(),
558583
},
559584
},
560585
},
@@ -563,6 +588,9 @@ func (r *clusterResource) Schema(_ context.Context, _ resource.SchemaRequest, re
563588
Description: "Network block as defined below.",
564589
Optional: true,
565590
Computed: true,
591+
PlanModifiers: []planmodifier.Object{
592+
objectplanmodifier.UseStateForUnknown(),
593+
},
566594
Attributes: map[string]schema.Attribute{
567595
"id": schema.StringAttribute{
568596
Description: "ID of the STACKIT Network Area (SNA) network into which the cluster will be deployed.",
@@ -572,20 +600,25 @@ func (r *clusterResource) Schema(_ context.Context, _ resource.SchemaRequest, re
572600
validate.UUID(),
573601
},
574602
PlanModifiers: []planmodifier.String{
575-
stringplanmodifier.RequiresReplace(),
603+
stringplanmodifier.RequiresReplaceIfConfigured(),
604+
stringplanmodifier.UseStateForUnknown(),
576605
},
577606
},
578607
"control_plane": schema.SingleNestedAttribute{
579608
Description: "Control plane for the cluster.",
580609
Optional: true,
581610
Computed: true,
611+
PlanModifiers: []planmodifier.Object{
612+
objectplanmodifier.UseStateForUnknown(),
613+
},
582614
Attributes: map[string]schema.Attribute{
583615
"access_scope": schema.StringAttribute{
584616
Description: "Access scope of the control plane. It defines if the Kubernetes control plane is public or only available inside a STACKIT Network Area." + utils.FormatPossibleValues(sdkUtils.EnumSliceToStringSlice(ske.AllowedAccessScopeEnumValues)...) + " The field is immutable!",
585617
Optional: true,
586618
Computed: true,
587619
PlanModifiers: []planmodifier.String{
588620
stringplanmodifier.RequiresReplace(),
621+
stringplanmodifier.UseStateForUnknown(),
589622
},
590623
},
591624
},

stackit/internal/services/ske/ske_acc_test.go

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,17 @@ import (
55
_ "embed"
66
"fmt"
77
"maps"
8-
"strings"
98
"testing"
109

1110
"github.com/hashicorp/terraform-plugin-testing/config"
1211
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
1312
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
13+
"github.com/hashicorp/terraform-plugin-testing/plancheck"
1414
"github.com/hashicorp/terraform-plugin-testing/terraform"
1515
"github.com/stackitcloud/stackit-sdk-go/core/utils"
1616
"github.com/stackitcloud/stackit-sdk-go/services/ske"
1717
"github.com/stackitcloud/stackit-sdk-go/services/ske/wait"
1818

19-
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
2019
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/testutil"
2120
)
2221

@@ -217,23 +216,42 @@ func TestAccSKEMin(t *testing.T) {
217216
{
218217
Config: resourceMin,
219218
ConfigVariables: configVarsMinUpdated(),
219+
ConfigPlanChecks: resource.ConfigPlanChecks{
220+
PreApply: []plancheck.PlanCheck{
221+
plancheck.ExpectResourceAction("stackit_ske_cluster.cluster", plancheck.ResourceActionUpdate),
222+
},
223+
},
220224
Check: resource.ComposeAggregateTestCheckFunc(
221225
// cluster data
222-
resource.TestCheckResourceAttr("data.stackit_ske_cluster.cluster", "node_pools.#", "1"),
223-
resource.TestCheckResourceAttr("data.stackit_ske_cluster.cluster", "node_pools.0.availability_zones.#", "1"),
224-
resource.TestCheckResourceAttr("data.stackit_ske_cluster.cluster", "node_pools.0.availability_zones.0", testutil.ConvertConfigVariable(testConfigVarsMin["nodepool_availability_zone1"])),
225-
resource.TestCheckResourceAttr("data.stackit_ske_cluster.cluster", "node_pools.0.machine_type", testutil.ConvertConfigVariable(testConfigVarsMin["nodepool_machine_type"])),
226-
resource.TestCheckResourceAttr("data.stackit_ske_cluster.cluster", "node_pools.0.maximum", testutil.ConvertConfigVariable(testConfigVarsMin["nodepool_maximum"])),
227-
resource.TestCheckResourceAttr("data.stackit_ske_cluster.cluster", "node_pools.0.minimum", testutil.ConvertConfigVariable(testConfigVarsMin["nodepool_minimum"])),
228-
resource.TestCheckResourceAttr("data.stackit_ske_cluster.cluster", "node_pools.0.name", testutil.ConvertConfigVariable(testConfigVarsMin["nodepool_name"])),
226+
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "project_id", testutil.ConvertConfigVariable(configVarsMinUpdated()["project_id"])),
227+
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "name", testutil.ConvertConfigVariable(configVarsMinUpdated()["name"])),
229228

230-
resource.TestCheckResourceAttrSet("data.stackit_ske_cluster.cluster", "kubernetes_version_used"),
231-
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "maintenance.enable_kubernetes_version_updates", testutil.ConvertConfigVariable(testConfigVarsMax["maintenance_enable_kubernetes_version_updates"])),
232-
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "maintenance.enable_machine_image_version_updates", testutil.ConvertConfigVariable(testConfigVarsMax["maintenance_enable_machine_image_version_updates"])),
233-
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "maintenance.start", testutil.ConvertConfigVariable(testConfigVarsMax["maintenance_start"])),
234-
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "maintenance.end", testutil.ConvertConfigVariable(testConfigVarsMax["maintenance_end"])),
235-
resource.TestCheckResourceAttrSet("data.stackit_ske_cluster.cluster", "kubernetes_version_used"),
236-
resource.TestCheckResourceAttrSet("stackit_ske_cluster.cluster", "region"),
229+
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "node_pools.#", "1"),
230+
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "node_pools.0.availability_zones.#", "1"),
231+
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "node_pools.0.availability_zones.0", testutil.ConvertConfigVariable(configVarsMinUpdated()["nodepool_availability_zone1"])),
232+
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "node_pools.0.machine_type", testutil.ConvertConfigVariable(configVarsMinUpdated()["nodepool_machine_type"])),
233+
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "node_pools.0.maximum", testutil.ConvertConfigVariable(configVarsMinUpdated()["nodepool_maximum"])),
234+
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "node_pools.0.minimum", testutil.ConvertConfigVariable(configVarsMinUpdated()["nodepool_minimum"])),
235+
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "node_pools.0.name", testutil.ConvertConfigVariable(configVarsMinUpdated()["nodepool_name"])),
236+
resource.TestCheckResourceAttrSet("stackit_ske_cluster.cluster", "node_pools.0.os_version_used"),
237+
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "kubernetes_version_min", testutil.ConvertConfigVariable(configVarsMinUpdated()["kubernetes_version_min"])),
238+
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "maintenance.enable_kubernetes_version_updates", testutil.ConvertConfigVariable(configVarsMinUpdated()["maintenance_enable_kubernetes_version_updates"])),
239+
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "maintenance.enable_machine_image_version_updates", testutil.ConvertConfigVariable(configVarsMinUpdated()["maintenance_enable_machine_image_version_updates"])),
240+
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "maintenance.start", testutil.ConvertConfigVariable(configVarsMinUpdated()["maintenance_start"])),
241+
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "maintenance.end", testutil.ConvertConfigVariable(configVarsMinUpdated()["maintenance_end"])),
242+
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "region", testutil.ConvertConfigVariable(configVarsMinUpdated()["region"])),
243+
resource.TestCheckResourceAttrSet("stackit_ske_cluster.cluster", "kubernetes_version_used"),
244+
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "network.control_plane.access_scope", testutil.ConvertConfigVariable(configVarsMinUpdated()["network_control_plane_access_scope"])),
245+
246+
// Kubeconfig
247+
resource.TestCheckResourceAttrPair(
248+
"stackit_ske_kubeconfig.kubeconfig", "project_id",
249+
"stackit_ske_cluster.cluster", "project_id",
250+
),
251+
resource.TestCheckResourceAttrPair(
252+
"stackit_ske_kubeconfig.kubeconfig", "cluster_name",
253+
"stackit_ske_cluster.cluster", "name",
254+
),
237255
),
238256
},
239257
// Deletion is done by the framework implicitly
@@ -412,6 +430,11 @@ func TestAccSKEMax(t *testing.T) {
412430
{
413431
Config: resourceMax,
414432
ConfigVariables: configVarsMaxUpdated(),
433+
ConfigPlanChecks: resource.ConfigPlanChecks{
434+
PreApply: []plancheck.PlanCheck{
435+
plancheck.ExpectResourceAction("stackit_ske_cluster.cluster", plancheck.ResourceActionUpdate),
436+
},
437+
},
415438
Check: resource.ComposeAggregateTestCheckFunc(
416439
// cluster data
417440
resource.TestCheckResourceAttr("stackit_ske_cluster.cluster", "project_id", testutil.ConvertConfigVariable(configVarsMaxUpdated()["project_id"])),
@@ -513,8 +536,7 @@ func testAccCheckSKEDestroy(s *terraform.State) error {
513536
if rs.Type != "stackit_ske_cluster" {
514537
continue
515538
}
516-
// cluster terraform ID: = "[project_id],[region],[cluster_name]"
517-
clusterName := strings.Split(rs.Primary.ID, core.Separator)[2]
539+
clusterName := rs.Primary.Attributes["name"]
518540
clustersToDestroy = append(clustersToDestroy, clusterName)
519541
}
520542

0 commit comments

Comments
 (0)