diff --git a/docs/resources/lke_node_pool.md b/docs/resources/lke_node_pool.md index d16cb5cf0..137283d41 100644 --- a/docs/resources/lke_node_pool.md +++ b/docs/resources/lke_node_pool.md @@ -93,6 +93,10 @@ The following arguments are supported: * `labels` - (Optional) A map attribute containing key-value pairs to be added as labels to nodes in the node pool. Labels help classify your nodes and to easily select subsets of objects. To learn more, review [Add Labels and Taints to your LKE Node Pools](https://www.linode.com/docs/products/compute/kubernetes/guides/deploy-and-manage-cluster-with-the-linode-api/#add-labels-and-taints-to-your-lke-node-pools). +* `k8s_version` - (Optional) The k8s version of the nodes in this node pool. For LKE enterprise only and may not currently available to all users even under v4beta. + +* `update_strategy` - (Optional) The strategy for updating the node pool k8s version. For LKE enterprise only and may not currently available to all users even under v4beta. + * [`autoscaler`](#autoscaler) - (Optional) If defined, an autoscaler will be enabled with the given configuration. * [`taint`](#taint) - (Optional) Kubernetes taints to add to node pool nodes. Taints help control how pods are scheduled onto nodes, specifically allowing them to repel certain pods. To learn more, review [Add Labels and Taints to your LKE Node Pools](https://www.linode.com/docs/products/compute/kubernetes/guides/deploy-and-manage-cluster-with-the-linode-api/#add-labels-and-taints-to-your-lke-node-pools). diff --git a/go.mod b/go.mod index 40939481e..b3064f0c9 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/hashicorp/terraform-plugin-mux v0.18.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1 github.com/hashicorp/terraform-plugin-testing v1.12.0 - github.com/linode/linodego v1.48.1 + github.com/linode/linodego v1.49.0 github.com/linode/linodego/k8s v1.25.2 github.com/stretchr/testify v1.10.0 golang.org/x/crypto v0.37.0 @@ -102,7 +102,7 @@ require ( github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/zclconf/go-cty v1.16.2 // indirect golang.org/x/mod v0.22.0 // indirect - golang.org/x/oauth2 v0.27.0 // indirect + golang.org/x/oauth2 v0.28.0 // indirect golang.org/x/sys v0.32.0 // indirect golang.org/x/term v0.31.0 // indirect golang.org/x/text v0.24.0 // indirect diff --git a/go.sum b/go.sum index 5fe29e266..9077dcd7a 100644 --- a/go.sum +++ b/go.sum @@ -194,8 +194,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/linode/linodego v1.48.1 h1:Ojw1S+K5jJr1dggO8/H6r4FINxXnJbOU5GkbpaTfmhU= -github.com/linode/linodego v1.48.1/go.mod h1:fc3t60If8X+yZTFAebhCnNDFrhwQhq9HDU92WnBousQ= +github.com/linode/linodego v1.49.0 h1:MNd3qwvQzbXB5mCpvdCqlUIu1RPA9oC+50LyB9kK+GQ= +github.com/linode/linodego v1.49.0/go.mod h1:B+HAM3//4w1wOS0BwdaQBKwBxlfe6kYJ7bSC6jJ/xtc= github.com/linode/linodego/k8s v1.25.2 h1:PY6S0sAD3xANVvM9WY38bz9GqMTjIbytC8IJJ9Cv23o= github.com/linode/linodego/k8s v1.25.2/go.mod h1:DC1XCSRZRGsmaa/ggpDPSDUmOM6aK1bhSIP6+f9Cwhc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= @@ -299,8 +299,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= -golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= +golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/linode/lkenodepool/framework_models.go b/linode/lkenodepool/framework_models.go index 9d74088cf..766a53932 100644 --- a/linode/lkenodepool/framework_models.go +++ b/linode/lkenodepool/framework_models.go @@ -24,6 +24,8 @@ type NodePoolModel struct { Autoscaler []NodePoolAutoscalerModel `tfsdk:"autoscaler"` Taints []NodePoolTaintModel `tfsdk:"taint"` Labels types.Map `tfsdk:"labels"` + K8sVersion types.String `tfsdk:"k8s_version"` + UpdateStrategy types.String `tfsdk:"update_strategy"` } type NodePoolAutoscalerModel struct { @@ -122,9 +124,22 @@ func (pool *NodePoolModel) FlattenLKENodePool( diags.Append(errs...) } pool.Nodes = helper.KeepOrUpdateValue(pool.Nodes, *nodePoolLinodes, preserveKnown) + + pool.K8sVersion = helper.KeepOrUpdateStringPointer(pool.K8sVersion, p.K8sVersion, preserveKnown) + + if p.UpdateStrategy != nil { + pool.UpdateStrategy = helper.KeepOrUpdateString(pool.UpdateStrategy, string(*p.UpdateStrategy), preserveKnown) + } else { + pool.UpdateStrategy = helper.KeepOrUpdateString(pool.UpdateStrategy, "", preserveKnown) + } } -func (pool *NodePoolModel) SetNodePoolCreateOptions(ctx context.Context, p *linodego.LKENodePoolCreateOptions, diags *diag.Diagnostics) { +func (pool *NodePoolModel) SetNodePoolCreateOptions( + ctx context.Context, + p *linodego.LKENodePoolCreateOptions, + diags *diag.Diagnostics, + tier string, +) { p.Count = helper.FrameworkSafeInt64ToInt( pool.Count.ValueInt64(), diags, @@ -143,33 +158,82 @@ func (pool *NodePoolModel) SetNodePoolCreateOptions(ctx context.Context, p *lino p.Taints = pool.getLKENodePoolTaints() pool.Labels.ElementsAs(ctx, &p.Labels, false) + + if tier == "enterprise" { + p.K8sVersion = pool.K8sVersion.ValueStringPointer() + p.UpdateStrategy = linodego.Pointer(linodego.LKENodePoolUpdateStrategy(pool.UpdateStrategy.ValueString())) + } } -func (pool *NodePoolModel) SetNodePoolUpdateOptions(ctx context.Context, p *linodego.LKENodePoolUpdateOptions, diags *diag.Diagnostics) { - p.Count = helper.FrameworkSafeInt64ToInt( - pool.Count.ValueInt64(), - diags, - ) +func (pool *NodePoolModel) SetNodePoolUpdateOptions( + ctx context.Context, + p *linodego.LKENodePoolUpdateOptions, + diags *diag.Diagnostics, + state *NodePoolModel, + tier string, +) bool { + var shouldUpdate bool + + if !state.Count.Equal(pool.Count) { + p.Count = helper.FrameworkSafeInt64ToInt( + pool.Count.ValueInt64(), + diags, + ) + if diags.HasError() { + return false + } + + shouldUpdate = true + } + + if !state.Tags.Equal(pool.Tags) { + if !pool.Tags.IsNull() { + diags.Append(pool.Tags.ElementsAs(ctx, &p.Tags, false)...) + if diags.HasError() { + return false + } + } + + shouldUpdate = true + } + + autoscaler, asNeedsUpdate := pool.shouldUpdateLKENodePoolAutoscaler(p.Count, state, diags) if diags.HasError() { - return + return false } - if !pool.Tags.IsNull() { - diags.Append(pool.Tags.ElementsAs(ctx, &p.Tags, false)...) - if diags.HasError() { - return + if asNeedsUpdate { + p.Autoscaler = autoscaler + if p.Autoscaler.Enabled && p.Count == 0 { + p.Count = p.Autoscaler.Min } } - p.Autoscaler = pool.getLKENodePoolAutoscaler(p.Count, diags) - if p.Autoscaler.Enabled && p.Count == 0 { - p.Count = p.Autoscaler.Min + shouldUpdate = shouldUpdate || asNeedsUpdate + + if !(len(state.Taints) == 0 && len(pool.Taints) == 0) { + taints := pool.getLKENodePoolTaints() + p.Taints = &taints + shouldUpdate = true } - taints := pool.getLKENodePoolTaints() - p.Taints = &taints + if !state.Labels.Equal(pool.Labels) { + pool.Labels.ElementsAs(ctx, &p.Labels, false) + } - pool.Labels.ElementsAs(ctx, &p.Labels, false) + if tier == "enterprise" { + if !state.K8sVersion.Equal(pool.K8sVersion) { + p.K8sVersion = pool.K8sVersion.ValueStringPointer() + shouldUpdate = true + } + + if !state.UpdateStrategy.Equal(pool.UpdateStrategy) { + p.UpdateStrategy = linodego.Pointer(linodego.LKENodePoolUpdateStrategy(pool.UpdateStrategy.ValueString())) + shouldUpdate = true + } + } + + return shouldUpdate } func (pool *NodePoolModel) ExtractClusterAndNodePoolIDs(diags *diag.Diagnostics) (int, int) { @@ -195,6 +259,35 @@ func (pool *NodePoolModel) getLKENodePoolAutoscaler(count int, diags *diag.Diagn return &autoscaler } +func (pool *NodePoolModel) shouldUpdateLKENodePoolAutoscaler( + count int, + state *NodePoolModel, + diags *diag.Diagnostics, +) (*linodego.LKENodePoolAutoscaler, bool) { + var autoscaler linodego.LKENodePoolAutoscaler + var shouldUpdate bool + + if len(pool.Autoscaler) > 0 { + if len(state.Autoscaler) == 0 || + (len(state.Autoscaler) > 0 && (!state.Autoscaler[0].Min.Equal(pool.Autoscaler[0].Min) || + !state.Autoscaler[0].Max.Equal(pool.Autoscaler[0].Max))) { + autoscaler.Enabled = true + autoscaler.Min = helper.FrameworkSafeInt64ToInt(pool.Autoscaler[0].Min.ValueInt64(), diags) + autoscaler.Max = helper.FrameworkSafeInt64ToInt(pool.Autoscaler[0].Max.ValueInt64(), diags) + + shouldUpdate = true + } + } else if len(state.Autoscaler) > 0 { + autoscaler.Enabled = false + autoscaler.Min = count + autoscaler.Max = count + + shouldUpdate = true + } + + return &autoscaler, shouldUpdate +} + func (taint NodePoolTaintModel) getLKENodePoolTaint() linodego.LKENodePoolTaint { return linodego.LKENodePoolTaint{ Effect: linodego.LKENodePoolTaintEffect(taint.Effect.ValueString()), @@ -212,3 +305,21 @@ func (pool *NodePoolModel) getLKENodePoolTaints() []linodego.LKENodePoolTaint { return taints } + +func (data *NodePoolModel) CopyFrom(other NodePoolModel, preserveKnown bool) { + data.ID = helper.KeepOrUpdateValue(data.ID, other.ID, preserveKnown) + data.ClusterID = helper.KeepOrUpdateValue(data.ClusterID, other.ClusterID, preserveKnown) + data.Count = helper.KeepOrUpdateValue(data.Count, other.Count, preserveKnown) + data.Type = helper.KeepOrUpdateValue(data.Type, other.Type, preserveKnown) + data.DiskEncryption = helper.KeepOrUpdateValue(data.DiskEncryption, other.DiskEncryption, preserveKnown) + data.Tags = helper.KeepOrUpdateValue(data.Tags, other.Tags, preserveKnown) + data.Nodes = helper.KeepOrUpdateValue(data.Nodes, other.Nodes, preserveKnown) + data.Labels = helper.KeepOrUpdateValue(data.Labels, other.Labels, preserveKnown) + data.K8sVersion = helper.KeepOrUpdateValue(data.K8sVersion, other.K8sVersion, preserveKnown) + data.UpdateStrategy = helper.KeepOrUpdateValue(data.UpdateStrategy, other.UpdateStrategy, preserveKnown) + + if !preserveKnown { + data.Autoscaler = other.Autoscaler + data.Taints = other.Taints + } +} diff --git a/linode/lkenodepool/framework_models_unit_test.go b/linode/lkenodepool/framework_models_unit_test.go index caa06175f..cadf7761a 100644 --- a/linode/lkenodepool/framework_models_unit_test.go +++ b/linode/lkenodepool/framework_models_unit_test.go @@ -66,7 +66,7 @@ func TestSetNodePoolCreateOptions(t *testing.T) { var createOpts linodego.LKENodePoolCreateOptions var diags diag.Diagnostics - nodePoolModel.SetNodePoolCreateOptions(context.Background(), &createOpts, &diags) + nodePoolModel.SetNodePoolCreateOptions(context.Background(), &createOpts, &diags, "enterprise") assert.False(t, diags.HasError()) assert.Equal(t, 3, createOpts.Count) @@ -77,17 +77,22 @@ func TestSetNodePoolCreateOptions(t *testing.T) { assert.True(t, createOpts.Autoscaler.Enabled) assert.Equal(t, 1, createOpts.Autoscaler.Min) assert.Equal(t, 5, createOpts.Autoscaler.Max) + + assert.Equal(t, "k8s_version", *createOpts.K8sVersion) + assert.Equal(t, "on_recycle", string(*createOpts.UpdateStrategy)) } func TestSetNodePoolUpdateOptions(t *testing.T) { nodePoolModel := createNodePoolModel() + state := NodePoolModel{ID: types.StringValue("123")} var updateOpts linodego.LKENodePoolUpdateOptions var diags diag.Diagnostics - nodePoolModel.SetNodePoolUpdateOptions(context.Background(), &updateOpts, &diags) + shouldUpdate := nodePoolModel.SetNodePoolUpdateOptions(context.Background(), &updateOpts, &diags, &state, "enterprise") assert.False(t, diags.HasError()) + assert.True(t, shouldUpdate) assert.Equal(t, 3, updateOpts.Count) assert.Contains(t, *updateOpts.Tags, "production") assert.Contains(t, *updateOpts.Tags, "web-server") @@ -95,6 +100,9 @@ func TestSetNodePoolUpdateOptions(t *testing.T) { assert.True(t, updateOpts.Autoscaler.Enabled) assert.Equal(t, 1, updateOpts.Autoscaler.Min) assert.Equal(t, 5, updateOpts.Autoscaler.Max) + + assert.Equal(t, "k8s_version", *updateOpts.K8sVersion) + assert.Equal(t, "on_recycle", string(*updateOpts.UpdateStrategy)) } func createNodePoolModel() *NodePoolModel { @@ -117,6 +125,8 @@ func createNodePoolModel() *NodePoolModel { Max: types.Int64Value(5), }, }, + K8sVersion: types.StringValue("k8s_version"), + UpdateStrategy: types.StringValue("on_recycle"), } nodePoolModel.Labels = types.MapValueMust(types.StringType, map[string]attr.Value{}) diff --git a/linode/lkenodepool/framework_resource.go b/linode/lkenodepool/framework_resource.go index 2fb8c890c..ad53882bf 100644 --- a/linode/lkenodepool/framework_resource.go +++ b/linode/lkenodepool/framework_resource.go @@ -98,18 +98,23 @@ func (r *Resource) Create( return } - var createOpts linodego.LKENodePoolCreateOptions - - plan.SetNodePoolCreateOptions(ctx, &createOpts, &resp.Diagnostics) - if resp.Diagnostics.HasError() { - return - } - clusterID := helper.FrameworkSafeInt64ToInt( plan.ClusterID.ValueInt64(), &resp.Diagnostics, ) + if resp.Diagnostics.HasError() { + return + } + + cluster, err := client.GetLKECluster(ctx, clusterID) + if err != nil { + resp.Diagnostics.AddError("error getting cluster", err.Error()) + return + } + + var createOpts linodego.LKENodePoolCreateOptions + plan.SetNodePoolCreateOptions(ctx, &createOpts, &resp.Diagnostics, cluster.Tier) if resp.Diagnostics.HasError() { return } @@ -172,41 +177,50 @@ func (r *Resource) Update( return } - var updateOpts linodego.LKENodePoolUpdateOptions - - plan.SetNodePoolUpdateOptions(ctx, &updateOpts, &resp.Diagnostics) - if resp.Diagnostics.HasError() { - return - } - clusterID, poolID := state.ExtractClusterAndNodePoolIDs(&resp.Diagnostics) if resp.Diagnostics.HasError() { return } - tflog.Debug(ctx, "client.UpdateLKENodePool(...)", map[string]any{ - "cluster_id": clusterID, - "options": updateOpts, - }) - pool, err := client.UpdateLKENodePool(ctx, clusterID, poolID, updateOpts) + cluster, err := client.GetLKECluster(ctx, clusterID) if err != nil { - resp.Diagnostics.AddError("Error updating a Linode Node Pool", err.Error()) + resp.Diagnostics.AddError("error getting cluster", err.Error()) return } - tflog.Debug(ctx, "waiting for node pool to enter ready status") - readyPool, err := WaitForNodePoolReady(ctx, - *client, - int(r.Meta.Config.EventPollMilliseconds.ValueInt64()), - clusterID, - pool.ID, - ) - if err != nil { - resp.Diagnostics.AddError("Linode Node Pool is not ready after update", err.Error()) + var updateOpts linodego.LKENodePoolUpdateOptions + + shouldUpdate := plan.SetNodePoolUpdateOptions(ctx, &updateOpts, &resp.Diagnostics, &state, cluster.Tier) + if resp.Diagnostics.HasError() { return } - plan.FlattenLKENodePool(ctx, readyPool, true, &resp.Diagnostics) + if shouldUpdate { + tflog.Debug(ctx, "client.UpdateLKENodePool(...)", map[string]any{ + "cluster_id": clusterID, + "options": updateOpts, + }) + pool, err := client.UpdateLKENodePool(ctx, clusterID, poolID, updateOpts) + if err != nil { + resp.Diagnostics.AddError("Error updating a Linode Node Pool", err.Error()) + return + } + + tflog.Debug(ctx, "waiting for node pool to enter ready status") + readyPool, err := WaitForNodePoolReady(ctx, + *client, + int(r.Meta.Config.EventPollMilliseconds.ValueInt64()), + clusterID, + pool.ID, + ) + if err != nil { + resp.Diagnostics.AddError("Linode Node Pool is not ready after update", err.Error()) + return + } + plan.FlattenLKENodePool(ctx, readyPool, true, &resp.Diagnostics) + } + + plan.CopyFrom(state, true) // Workaround for Crossplane issue where ID is not // properly populated in plan diff --git a/linode/lkenodepool/framework_resource_schema.go b/linode/lkenodepool/framework_resource_schema.go index 11e78797f..1a6f4474e 100644 --- a/linode/lkenodepool/framework_resource_schema.go +++ b/linode/lkenodepool/framework_resource_schema.go @@ -1,6 +1,8 @@ package lkenodepool import ( + "context" + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" @@ -81,6 +83,43 @@ var resourceSchema = schema.Schema{ Computed: true, Default: helper.EmptyMapDefault(types.StringType), }, + "k8s_version": schema.StringAttribute{ + Description: "The k8s version of the nodes in this node pool. " + + "For LKE enterprise only and may not currently available to all users.", + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + stringplanmodifier.RequiresReplaceIf( + func( + ctx context.Context, + sr planmodifier.StringRequest, + rrifr *stringplanmodifier.RequiresReplaceIfFuncResponse, + ) { + var strategy string + sr.Plan.GetAttribute(ctx, path.Root("update_strategy"), &strategy) + rrifr.RequiresReplace = strategy == "rolling_update" + }, + "Triggers replacement when `k8s_version` is changed and `update_strategy` is rolling_update", + "Changing `k8s_version` with a Rolling Update strategy forces a new resource.", + ), + }, + }, + "update_strategy": schema.StringAttribute{ + Description: "The strategy for updating the node pool k8s version. " + + "For LKE enterprise only and may not currently available to all users.", + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + Validators: []validator.String{ + stringvalidator.OneOf( + string(linodego.LKENodePoolOnRecycle), + string(linodego.LKENodePoolRollingUpdate), + ), + }, + }, }, Blocks: map[string]schema.Block{ "autoscaler": schema.ListNestedBlock{ @@ -91,10 +130,12 @@ var resourceSchema = schema.Schema{ NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "min": schema.Int64Attribute{ - Required: true, + Optional: true, + Description: "The minimum number of nodes to automatically scale to.", }, "max": schema.Int64Attribute{ - Required: true, + Optional: true, + Description: "The maximum number of nodes to automatically scale to.", }, }, }, diff --git a/linode/lkenodepool/framework_resource_test.go b/linode/lkenodepool/framework_resource_test.go index e95a223ed..f32142bb2 100644 --- a/linode/lkenodepool/framework_resource_test.go +++ b/linode/lkenodepool/framework_resource_test.go @@ -411,6 +411,75 @@ func TestAccResourceNodePool_taints_labels(t *testing.T) { }) } +func TestAccResourceNodePoolEnterprise_basic(t *testing.T) { + t.Parallel() + + resName := "linode_lke_node_pool.foobar" + clusterLabel := acctest.RandomWithPrefix("tf_test_") + poolTag := acctest.RandomWithPrefix("tf_test_") + + client, err := acceptance.GetTestClient() + if err != nil { + log.Fatalf("failed to get client: %s", err) + } + + versions, err := client.ListLKETierVersions(context.Background(), "enterprise", nil) + if err != nil { + log.Fatal(err) + } + + if len(versions) < 1 { + t.Skip("No enterprise k8s versions found for test. Skipping now...") + } + + enterpriseK8sVersion := versions[0].ID + + region, err := acceptance.GetRandomRegionWithCaps([]string{"Kubernetes Enterprise"}, "core") + if err != nil { + log.Fatal(err) + } + + templateData := createTemplateData() + templateData.ClusterLabel = clusterLabel + templateData.PoolTag = poolTag + templateData.K8sVersion = enterpriseK8sVersion + templateData.Region = region + templateData.UpdateStrategy = "on_recycle" + createConfig := createEnterpriseResourceConfig(t, &templateData) + templateData.UpdateStrategy = "rolling_update" + updateConfig := createEnterpriseResourceConfig(t, &templateData) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + ProtoV5ProviderFactories: acceptance.ProtoV5ProviderFactories, + CheckDestroy: checkNodePoolDestroy, + Steps: []resource.TestStep{ + { + Config: createConfig, + Check: resource.ComposeTestCheckFunc( + checkNodePoolExists, + resource.TestCheckResourceAttr(resName, "k8s_version", enterpriseK8sVersion), + resource.TestCheckResourceAttr(resName, "update_strategy", "on_recycle"), + ), + }, + { + ResourceName: resName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: resourceImportStateID, + }, + { + Config: updateConfig, + Check: resource.ComposeTestCheckFunc( + checkNodePoolExists, + resource.TestCheckResourceAttr(resName, "k8s_version", enterpriseK8sVersion), + resource.TestCheckResourceAttr(resName, "update_strategy", "rolling_update"), + ), + }, + }, + }) +} + func checkNodePoolExists(s *terraform.State) error { client := acceptance.TestAccProvider.Meta().(*helper.ProviderMeta).Client clusterID, poolID, err := extractIDs(s) @@ -455,6 +524,10 @@ func createResourceConfig(t testing.TB, data *tmpl.TemplateData) string { return acceptanceTmpl.ProviderNoPoll(t) + tmpl.Generate(t, data) } +func createEnterpriseResourceConfig(t testing.TB, data *tmpl.TemplateData) string { + return acceptanceTmpl.ProviderNoPoll(t) + tmpl.EnterpriseBasic(t, data) +} + func createTemplateData() tmpl.TemplateData { var data tmpl.TemplateData data.ClusterID = clusterID diff --git a/linode/lkenodepool/tmpl/lke_e_nodepool.gotf b/linode/lkenodepool/tmpl/lke_e_nodepool.gotf new file mode 100644 index 000000000..1fd0eba45 --- /dev/null +++ b/linode/lkenodepool/tmpl/lke_e_nodepool.gotf @@ -0,0 +1,33 @@ +{{ define "lke_e_nodepool" }} + +{{ if not .ClusterID }} +resource "linode_lke_cluster" "nodepool_test_cluster" { + label = "{{.ClusterLabel}}" + region = "{{ .Region }}" + k8s_version = "{{.K8sVersion}}" + tags = ["nodepool_test_cluster"] + external_pool_tags = ["external"] + tier = "enterprise" + + pool { + type = "g6-standard-1" + count = 1 + } +} +{{ end }} + +resource "linode_lke_node_pool" "foobar" { +{{ if .ClusterID }} + cluster_id = "{{.ClusterID}}" +{{ else }} + cluster_id = linode_lke_cluster.nodepool_test_cluster.id +{{ end }} + + node_count = 2 + type = "{{ .PoolNodeType }}" + k8s_version = "{{.K8sVersion}}" + update_strategy = "{{.UpdateStrategy}}" + tags = ["external", "{{.PoolTag}}"] +} + +{{ end }} \ No newline at end of file diff --git a/linode/lkenodepool/tmpl/template.go b/linode/lkenodepool/tmpl/template.go index 6251d36a7..e88aa063b 100644 --- a/linode/lkenodepool/tmpl/template.go +++ b/linode/lkenodepool/tmpl/template.go @@ -25,8 +25,13 @@ type TemplateData struct { AutoscalerMax int Taints []TaintData Labels map[string]string + UpdateStrategy string } func Generate(t testing.TB, data *TemplateData) string { return acceptance.ExecuteTemplate(t, "nodepool_template", *data) } + +func EnterpriseBasic(t testing.TB, data *TemplateData) string { + return acceptance.ExecuteTemplate(t, "lke_e_nodepool", *data) +}