diff --git a/.changelog/39852.txt b/.changelog/39852.txt new file mode 100644 index 00000000000..8cfa94fc4c3 --- /dev/null +++ b/.changelog/39852.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_eks_cluster: Add `zonal_shift_config` argument +``` diff --git a/internal/service/eks/cluster.go b/internal/service/eks/cluster.go index 36cbda1200a..b0c38464ece 100644 --- a/internal/service/eks/cluster.go +++ b/internal/service/eks/cluster.go @@ -341,6 +341,19 @@ func resourceCluster() *schema.Resource { }, }, }, + "zonal_shift_config": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrEnabled: { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, }, } } @@ -381,6 +394,10 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta int input.Version = aws.String(v.(string)) } + if v, ok := d.GetOk("zonal_shift_config"); ok { + input.ZonalShiftConfig = expandZonalShiftConfig(v.([]interface{})) + } + outputRaw, err := tfresource.RetryWhen(ctx, propagationTimeout, func() (interface{}, error) { return conn.CreateCluster(ctx, input) @@ -491,6 +508,9 @@ func resourceClusterRead(ctx context.Context, d *schema.ResourceData, meta inter if err := d.Set(names.AttrVPCConfig, flattenVPCConfigResponse(cluster.ResourcesVpcConfig)); err != nil { return sdkdiag.AppendErrorf(diags, "setting vpc_config: %s", err) } + if err := d.Set("zonal_shift_config", flattenZonalShiftConfig(cluster.ZonalShiftConfig)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting zonal_shift_config: %s", err) + } setTagsOut(ctx, cluster.Tags) @@ -642,6 +662,25 @@ func resourceClusterUpdate(ctx context.Context, d *schema.ResourceData, meta int } } + if d.HasChange("zonal_shift_config") { + input := &eks.UpdateClusterConfigInput{ + Name: aws.String(d.Id()), + ZonalShiftConfig: expandZonalShiftConfig(d.Get("zonal_shift_config").([]interface{})), + } + + output, err := conn.UpdateClusterConfig(ctx, input) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "updating EKS Cluster (%s) zonal shift config: %s", d.Id(), err) + } + + updateID := aws.ToString(output.Update.Id) + + if _, err := waitClusterUpdateSuccessful(ctx, conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for EKS Cluster (%s) zonal shift config update (%s): %s", d.Id(), updateID, err) + } + } + return append(diags, resourceClusterRead(ctx, d, meta)...) } @@ -1083,6 +1122,25 @@ func expandUpgradePolicy(tfList []interface{}) *types.UpgradePolicyRequest { return upgradePolicyRequest } +func expandZonalShiftConfig(tfList []interface{}) *types.ZonalShiftConfigRequest { + if len(tfList) == 0 { + return nil + } + + tfMap, ok := tfList[0].(map[string]interface{}) + if !ok { + return nil + } + + ZonalShiftConfigRequest := &types.ZonalShiftConfigRequest{} + + if v, ok := tfMap[names.AttrEnabled].(bool); ok { + ZonalShiftConfigRequest.Enabled = aws.Bool(v) + } + + return ZonalShiftConfigRequest +} + func flattenCertificate(certificate *types.Certificate) []map[string]interface{} { if certificate == nil { return []map[string]interface{}{} @@ -1255,3 +1313,15 @@ func flattenUpgradePolicy(apiObject *types.UpgradePolicyResponse) []interface{} return []interface{}{tfMap} } + +func flattenZonalShiftConfig(apiObject *types.ZonalShiftConfigResponse) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{ + names.AttrEnabled: apiObject.Enabled, + } + + return []interface{}{tfMap} +} diff --git a/internal/service/eks/cluster_data_source.go b/internal/service/eks/cluster_data_source.go index b5429795c27..f20ed3139b1 100644 --- a/internal/service/eks/cluster_data_source.go +++ b/internal/service/eks/cluster_data_source.go @@ -214,6 +214,18 @@ func dataSourceCluster() *schema.Resource { }, }, }, + "zonal_shift_config": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrEnabled: { + Type: schema.TypeBool, + Computed: true, + }, + }, + }, + }, }, } } @@ -268,6 +280,9 @@ func dataSourceClusterRead(ctx context.Context, d *schema.ResourceData, meta int if err := d.Set(names.AttrVPCConfig, flattenVPCConfigResponse(cluster.ResourcesVpcConfig)); err != nil { return sdkdiag.AppendErrorf(diags, "setting vpc_config: %s", err) } + if err := d.Set("zonal_shift_config", flattenZonalShiftConfig(cluster.ZonalShiftConfig)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting zonal_shift_config: %s", err) + } if err := d.Set(names.AttrTags, KeyValueTags(ctx, cluster.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { return sdkdiag.AppendErrorf(diags, "setting tags: %s", err) diff --git a/internal/service/eks/cluster_data_source_test.go b/internal/service/eks/cluster_data_source_test.go index 256c1b18c5a..dee9734b446 100644 --- a/internal/service/eks/cluster_data_source_test.go +++ b/internal/service/eks/cluster_data_source_test.go @@ -61,6 +61,7 @@ func TestAccEKSClusterDataSource_basic(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "vpc_config.0.subnet_ids.#", dataSourceResourceName, "vpc_config.0.subnet_ids.#"), resource.TestCheckResourceAttrPair(resourceName, "vpc_config.0.public_access_cidrs.#", dataSourceResourceName, "vpc_config.0.public_access_cidrs.#"), resource.TestCheckResourceAttrPair(resourceName, "vpc_config.0.vpc_id", dataSourceResourceName, "vpc_config.0.vpc_id"), + resource.TestCheckResourceAttr(resourceName, "zonal_shift_config.#", "0"), ), }, }, diff --git a/internal/service/eks/cluster_test.go b/internal/service/eks/cluster_test.go index 45b24148772..753da1a8e69 100644 --- a/internal/service/eks/cluster_test.go +++ b/internal/service/eks/cluster_test.go @@ -77,6 +77,7 @@ func TestAccEKSCluster_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "vpc_config.0.security_group_ids.#", "0"), resource.TestCheckResourceAttr(resourceName, "vpc_config.0.subnet_ids.#", "2"), resource.TestMatchResourceAttr(resourceName, "vpc_config.0.vpc_id", regexache.MustCompile(`^vpc-.+`)), + resource.TestCheckResourceAttr(resourceName, "zonal_shift_config.#", "0"), ), }, { @@ -960,6 +961,44 @@ func TestAccEKSCluster_upgradePolicy(t *testing.T) { }) } +func TestAccEKSCluster_zonalShiftConfig(t *testing.T) { + ctx := acctest.Context(t) + var cluster1, cluster2 types.Cluster + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_eks_cluster.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EKSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccClusterConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &cluster1), + resource.TestCheckResourceAttr(resourceName, "zonal_shift_config.#", "0"), + ), + }, + { + Config: testAccClusterConfig_zonalShiftConfig(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &cluster2), + testAccCheckClusterNotRecreated(&cluster1, &cluster2), + resource.TestCheckResourceAttr(resourceName, "zonal_shift_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "zonal_shift_config.0.enabled", acctest.CtTrue), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"bootstrap_self_managed_addons"}, + }, + }, + }) +} + func testAccCheckClusterExists(ctx context.Context, n string, v *types.Cluster) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -1539,3 +1578,22 @@ resource "aws_eks_cluster" "test" { } `, rName, supportType)) } + +func testAccClusterConfig_zonalShiftConfig(rName string, enabled bool) string { + return acctest.ConfigCompose(testAccClusterConfig_base(rName), fmt.Sprintf(` +resource "aws_eks_cluster" "test" { + name = %[1]q + role_arn = aws_iam_role.test.arn + + vpc_config { + subnet_ids = aws_subnet.test[*].id + } + + zonal_shift_config { + enabled = %[2]t + } + + depends_on = [aws_iam_role_policy_attachment.test-AmazonEKSClusterPolicy] +} +`, rName, enabled)) +} diff --git a/website/docs/d/eks_cluster.html.markdown b/website/docs/d/eks_cluster.html.markdown index 1f491226bf0..578a845020c 100644 --- a/website/docs/d/eks_cluster.html.markdown +++ b/website/docs/d/eks_cluster.html.markdown @@ -77,3 +77,5 @@ This data source exports the following attributes in addition to the arguments a * `security_group_ids` – List of security group IDs * `subnet_ids` – List of subnet IDs * `vpc_id` – The VPC associated with your cluster. +* `zonal_shift_config` - Contains Zonal Shift Configuration. + * `enabled` - Whether zonal shift is enabled. diff --git a/website/docs/r/eks_cluster.html.markdown b/website/docs/r/eks_cluster.html.markdown index 5633ae8287e..03cdf1724cf 100644 --- a/website/docs/r/eks_cluster.html.markdown +++ b/website/docs/r/eks_cluster.html.markdown @@ -217,12 +217,13 @@ The following arguments are optional: * `access_config` - (Optional) Configuration block for the access config associated with your cluster, see [Amazon EKS Access Entries](https://docs.aws.amazon.com/eks/latest/userguide/access-entries.html). * `bootstrap_self_managed_addons` - (Optional) Install default unmanaged add-ons, such as `aws-cni`, `kube-proxy`, and CoreDNS during cluster creation. If `false`, you must manually install desired add-ons. Changing this value will force a new cluster to be created. Defaults to `true`. * `enabled_cluster_log_types` - (Optional) List of the desired control plane logging to enable. For more information, see [Amazon EKS Control Plane Logging](https://docs.aws.amazon.com/eks/latest/userguide/control-plane-logs.html). -* `encryption_config` - (Optional) Configuration block with encryption configuration for the cluster. Only available on Kubernetes 1.13 and above clusters created after March 6, 2020. Detailed below. +* `encryption_config` - (Optional) Configuration block with encryption configuration for the cluster. Detailed below. * `kubernetes_network_config` - (Optional) Configuration block with kubernetes network configuration for the cluster. Detailed below. If removed, Terraform will only perform drift detection if a configuration value is provided. * `outpost_config` - (Optional) Configuration block representing the configuration of your local Amazon EKS cluster on an AWS Outpost. This block isn't available for creating Amazon EKS clusters on the AWS cloud. * `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. * `upgrade_policy` - (Optional) Configuration block for the support policy to use for the cluster. See [upgrade_policy](#upgrade_policy) for details. * `version` – (Optional) Desired Kubernetes master version. If you do not specify a value, the latest available version at resource creation is used and no upgrades will occur except those automatically triggered by EKS. The value must be configured and increased to upgrade the version when desired. Downgrades are not supported by EKS. +* `zonal_shift_config` - (Optional) Configuration block with zonal shift configuration for the cluster. Detailed below. ### access_config @@ -292,6 +293,12 @@ The `upgrade_policy` configuration block supports the following arguments: * `support_type` - (Optional) Support type to use for the cluster. If the cluster is set to `EXTENDED`, it will enter extended support at the end of standard support. If the cluster is set to `STANDARD`, it will be automatically upgraded at the end of standard support. Valid values are `EXTENDED`, `STANDARD` +### zonal_shift_config + +The `zonal_shift_config` configuration block supports the following arguments: + +* `enabled` - (Optional) Whether zonal shift is enabled for the cluster. + ## Attribute Reference This resource exports the following attributes in addition to the arguments above: