From fbb6ff3750d96c4dc25151507d791a6ffee6fe98 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Fri, 6 Sep 2024 10:33:54 -0500 Subject: [PATCH 01/17] r/aws_eks_cluster: Add support for EKS Auto Mode --- internal/service/eks/cluster.go | 268 +++++++++++++++++- internal/service/eks/cluster_data_source.go | 61 ++++ .../service/eks/cluster_data_source_test.go | 6 + internal/service/eks/cluster_test.go | 207 ++++++++++++++ website/docs/d/eks_cluster.html.markdown | 9 + website/docs/r/eks_cluster.html.markdown | 161 +++++++++++ 6 files changed, 709 insertions(+), 3 deletions(-) diff --git a/internal/service/eks/cluster.go b/internal/service/eks/cluster.go index 9bc5383fda2..b616be2dc3f 100644 --- a/internal/service/eks/cluster.go +++ b/internal/service/eks/cluster.go @@ -113,6 +113,34 @@ func resourceCluster() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "compute_config": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "node_pools": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "node_role_arn": { + Type: schema.TypeString, + Optional: true, + // ForceNew: true, + // ValidateFunc: validation.NoZeroValues, + }, + }, + }, + }, names.AttrCreatedAt: { Type: schema.TypeString, Computed: true, @@ -188,6 +216,20 @@ func resourceCluster() *schema.Resource { ConflictsWith: []string{"outpost_config"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "elastic_load_balancing": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + }, + }, + }, "ip_family": { Type: schema.TypeString, Optional: true, @@ -326,6 +368,29 @@ func resourceCluster() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "storage_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "block_storage": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + }, + }, + }, + }, + }, + }, names.AttrTags: tftags.TagsSchema(), names.AttrTagsAll: tftags.TagsSchemaComputed(), "upgrade_policy": { @@ -430,6 +495,10 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta int Tags: getTagsIn(ctx), } + if v, ok := d.GetOk("compute_config"); ok { + input.ComputeConfig = expandComputeConfigRequest(v.([]interface{})) + } + if v, ok := d.GetOk("access_config"); ok { input.AccessConfig = expandCreateAccessConfigRequest(v.([]interface{})) } @@ -446,6 +515,10 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta int input.RemoteNetworkConfig = expandRemoteNetworkConfigRequest(v.([]interface{})) } + if v, ok := d.GetOk("storage_config"); ok { + input.StorageConfig = expandStorageConfigRequest(v.([]interface{})) + } + if v, ok := d.GetOk("upgrade_policy"); ok { input.UpgradePolicy = expandUpgradePolicy(v.([]interface{})) } @@ -458,6 +531,15 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta int input.ZonalShiftConfig = expandZonalShiftConfig(v.([]interface{})) } + // // ToDo - this doesn't seem to work as intended + // if aws.ToBool(input.ComputeConfig.Enabled) { + // input.KubernetesNetworkConfig.ElasticLoadBalancing.Enabled = aws.Bool(true) + // input.StorageConfig.BlockStorage.Enabled = aws.Bool(true) + // } else { + // input.KubernetesNetworkConfig.ElasticLoadBalancing.Enabled = aws.Bool(false) + // input.StorageConfig.BlockStorage.Enabled = aws.Bool(false) + // } + outputRaw, err := tfresource.RetryWhen(ctx, propagationTimeout, func() (interface{}, error) { return conn.CreateCluster(ctx, input) @@ -540,6 +622,9 @@ func resourceClusterRead(ctx context.Context, d *schema.ResourceData, meta inter if cluster.OutpostConfig != nil { d.Set("cluster_id", cluster.Id) } + if err := d.Set("compute_config", flattenComputeConfigResponse(cluster.ComputeConfig)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting compute_config: %s", err) + } d.Set(names.AttrCreatedAt, cluster.CreatedAt.Format(time.RFC3339)) if err := d.Set("enabled_cluster_log_types", flattenLogging(cluster.Logging)); err != nil { return sdkdiag.AppendErrorf(diags, "setting enabled_cluster_log_types: %s", err) @@ -564,6 +649,9 @@ func resourceClusterRead(ctx context.Context, d *schema.ResourceData, meta inter } d.Set(names.AttrRoleARN, cluster.RoleArn) d.Set(names.AttrStatus, cluster.Status) + if err := d.Set("storage_config", flattenStorageConfigResponse(cluster.StorageConfig)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting storage_config: %s", err) + } if err := d.Set("upgrade_policy", flattenUpgradePolicy(cluster.UpgradePolicy)); err != nil { return sdkdiag.AppendErrorf(diags, "setting upgrade_policy: %s", err) } @@ -628,6 +716,41 @@ func resourceClusterUpdate(ctx context.Context, d *schema.ResourceData, meta int } } + if d.HasChanges("compute_config", "kubernetes_network_config", "storage_config") { + computeConfig := expandComputeConfigRequest(d.Get("compute_config").([]interface{})) + kubernetesNetworkConfig := expandKubernetesNetworkConfigRequest(d.Get("kubernetes_network_config").([]interface{})) + storageConfig := expandStorageConfigRequest(d.Get("storage_config").([]interface{})) + + // InvalidParameterException: For EKS Auto Mode, please ensure that all required configs, + // including computeConfig, kubernetesNetworkConfig, and blockStorage are all either fully enabled or fully disabled. + if computeConfig != nil && aws.ToBool(computeConfig.Enabled) { + kubernetesNetworkConfig.ElasticLoadBalancing.Enabled = aws.Bool(true) + storageConfig.BlockStorage.Enabled = aws.Bool(true) + } else { + kubernetesNetworkConfig.ElasticLoadBalancing.Enabled = aws.Bool(false) + storageConfig.BlockStorage.Enabled = aws.Bool(false) + } + + input := &eks.UpdateClusterConfigInput{ + Name: aws.String(d.Id()), + ComputeConfig: computeConfig, + KubernetesNetworkConfig: kubernetesNetworkConfig, + StorageConfig: storageConfig, + } + + output, err := conn.UpdateClusterConfig(ctx, input) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "updating EKS Cluster (%s) compute 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) compute config update (%s): %s", d.Id(), updateID, err) + } + } + if d.HasChange("encryption_config") { o, n := d.GetChange("encryption_config") @@ -1009,6 +1132,33 @@ func expandUpdateAccessConfigRequest(tfList []interface{}) *types.UpdateAccessCo return apiObject } +func expandComputeConfigRequest(tfList []interface{}) *types.ComputeConfigRequest { + if len(tfList) == 0 { + return nil + } + + tfMap, ok := tfList[0].(map[string]interface{}) + if !ok { + return nil + } + + apiObject := &types.ComputeConfigRequest{} + + if v, ok := tfMap["enabled"].(bool); ok { + apiObject.Enabled = aws.Bool(v) + } + + if v, ok := tfMap["node_pools"].(*schema.Set); ok && v.Len() > 0 { + apiObject.NodePools = flex.ExpandStringValueSet(v) + } + + if v, ok := tfMap["node_role_arn"].(string); ok && v != "" { + apiObject.NodeRoleArn = aws.String(v) + } + + return apiObject +} + func expandEncryptionConfig(tfList []interface{}) []types.EncryptionConfig { if len(tfList) == 0 { return nil @@ -1055,6 +1205,44 @@ func expandProvider(tfList []interface{}) *types.Provider { return apiObject } +func expandStorageConfigRequest(tfList []interface{}) *types.StorageConfigRequest { + if len(tfList) == 0 { + return nil + } + + tfMap, ok := tfList[0].(map[string]interface{}) + if !ok { + return nil + } + + apiObject := &types.StorageConfigRequest{} + + if v, ok := tfMap["block_storage"].([]interface{}); ok { + apiObject.BlockStorage = expandBlockStorage(v) + } + + return apiObject +} + +func expandBlockStorage(tfList []interface{}) *types.BlockStorage { + if len(tfList) == 0 { + return nil + } + + tfMap, ok := tfList[0].(map[string]interface{}) + if !ok { + return nil + } + + apiObject := &types.BlockStorage{} + + if v, ok := tfMap["enabled"].(bool); ok { + apiObject.Enabled = aws.Bool(v) + } + + return apiObject +} + func expandOutpostConfigRequest(tfList []interface{}) *types.OutpostConfigRequest { if len(tfList) == 0 { return nil @@ -1137,6 +1325,10 @@ func expandKubernetesNetworkConfigRequest(tfList []interface{}) *types.Kubernete apiObject := &types.KubernetesNetworkConfigRequest{} + if v, ok := tfMap["elastic_load_balancing"].([]interface{}); ok { + apiObject.ElasticLoadBalancing = expandKubernetesNetworkConfigElasticLoadBalancing(v) + } + if v, ok := tfMap["ip_family"].(string); ok && v != "" { apiObject.IpFamily = types.IpFamily(v) } @@ -1148,6 +1340,25 @@ func expandKubernetesNetworkConfigRequest(tfList []interface{}) *types.Kubernete return apiObject } +func expandKubernetesNetworkConfigElasticLoadBalancing(tfList []interface{}) *types.ElasticLoadBalancing { + if len(tfList) == 0 { + return nil + } + + tfMap, ok := tfList[0].(map[string]interface{}) + if !ok { + return nil + } + + apiObject := &types.ElasticLoadBalancing{} + + if v, ok := tfMap["enabled"].(bool); ok { + apiObject.Enabled = aws.Bool(v) + } + + return apiObject +} + func expandRemoteNetworkConfigRequest(tfList []interface{}) *types.RemoteNetworkConfigRequest { if len(tfList) == 0 { return nil @@ -1283,6 +1494,20 @@ func flattenCertificate(certificate *types.Certificate) []map[string]interface{} return []map[string]interface{}{m} } +func flattenComputeConfigResponse(apiObject *types.ComputeConfigResponse) []map[string]interface{} { + if apiObject == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{ + "enabled": aws.ToBool(apiObject.Enabled), + "node_pools": flex.FlattenStringValueList(apiObject.NodePools), + "node_role_arn": aws.ToString(apiObject.NodeRoleArn), + } + + return []map[string]interface{}{m} +} + func flattenIdentity(identity *types.Identity) []map[string]interface{} { if identity == nil { return []map[string]interface{}{} @@ -1398,9 +1623,22 @@ func flattenKubernetesNetworkConfigResponse(apiObject *types.KubernetesNetworkCo } tfMap := map[string]interface{}{ - "service_ipv4_cidr": aws.ToString(apiObject.ServiceIpv4Cidr), - "service_ipv6_cidr": aws.ToString(apiObject.ServiceIpv6Cidr), - "ip_family": apiObject.IpFamily, + "elastic_load_balancing": flattenKubernetesNetworkConfigElasticLoadBalancing(apiObject.ElasticLoadBalancing), + "service_ipv4_cidr": aws.ToString(apiObject.ServiceIpv4Cidr), + "service_ipv6_cidr": aws.ToString(apiObject.ServiceIpv6Cidr), + "ip_family": apiObject.IpFamily, + } + + return []interface{}{tfMap} +} + +func flattenKubernetesNetworkConfigElasticLoadBalancing(apiObjects *types.ElasticLoadBalancing) []interface{} { + if apiObjects == nil { + return nil + } + + tfMap := map[string]interface{}{ + "enabled": aws.ToBool(apiObjects.Enabled), } return []interface{}{tfMap} @@ -1481,6 +1719,30 @@ func flattenControlPlanePlacementResponse(apiObject *types.ControlPlanePlacement return []interface{}{tfMap} } +func flattenStorageConfigResponse(apiObject *types.StorageConfigResponse) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{ + "block_storage": flattenBlockStorage(apiObject.BlockStorage), + } + + return []interface{}{tfMap} +} + +func flattenBlockStorage(apiObject *types.BlockStorage) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{ + "enabled": aws.ToBool(apiObject.Enabled), + } + + return []interface{}{tfMap} +} + func flattenUpgradePolicy(apiObject *types.UpgradePolicyResponse) []interface{} { if apiObject == nil { return nil diff --git a/internal/service/eks/cluster_data_source.go b/internal/service/eks/cluster_data_source.go index 79998c11451..736e86e54df 100644 --- a/internal/service/eks/cluster_data_source.go +++ b/internal/service/eks/cluster_data_source.go @@ -57,6 +57,29 @@ func dataSourceCluster() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "compute_config": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "node_pools": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "node_role_arn": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, names.AttrCreatedAt: { Type: schema.TypeString, Computed: true, @@ -95,6 +118,18 @@ func dataSourceCluster() *schema.Resource { Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "elastic_load_balancing": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Computed: true, + }, + }, + }, + }, "ip_family": { Type: schema.TypeString, Computed: true, @@ -192,6 +227,26 @@ func dataSourceCluster() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "storage_config": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "block_storage": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Computed: true, + }, + }, + }, + }, + }, + }, + }, names.AttrTags: tftags.TagsSchemaComputed(), "upgrade_policy": { Type: schema.TypeList, @@ -289,6 +344,9 @@ func dataSourceClusterRead(ctx context.Context, d *schema.ResourceData, meta int if cluster.OutpostConfig != nil { d.Set("cluster_id", cluster.Id) } + if err := d.Set("compute_config", flattenComputeConfigResponse(cluster.ComputeConfig)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting compute_config: %s", err) + } d.Set(names.AttrCreatedAt, cluster.CreatedAt.Format(time.RFC3339)) if err := d.Set("enabled_cluster_log_types", flattenLogging(cluster.Logging)); err != nil { return sdkdiag.AppendErrorf(diags, "setting enabled_cluster_log_types: %s", err) @@ -310,6 +368,9 @@ func dataSourceClusterRead(ctx context.Context, d *schema.ResourceData, meta int } d.Set(names.AttrRoleARN, cluster.RoleArn) d.Set(names.AttrStatus, cluster.Status) + if err := d.Set("storage_config", flattenStorageConfigResponse(cluster.StorageConfig)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting storage_config: %s", err) + } if err := d.Set("upgrade_policy", flattenUpgradePolicy(cluster.UpgradePolicy)); err != nil { return sdkdiag.AppendErrorf(diags, "setting upgrade_policy: %s", err) } diff --git a/internal/service/eks/cluster_data_source_test.go b/internal/service/eks/cluster_data_source_test.go index ca8f1a68674..66aec92b5dd 100644 --- a/internal/service/eks/cluster_data_source_test.go +++ b/internal/service/eks/cluster_data_source_test.go @@ -33,6 +33,7 @@ func TestAccEKSClusterDataSource_basic(t *testing.T) { resource.TestCheckResourceAttr(dataSourceResourceName, "certificate_authority.#", "1"), resource.TestCheckResourceAttrPair(resourceName, "certificate_authority.0.data", dataSourceResourceName, "certificate_authority.0.data"), resource.TestCheckNoResourceAttr(dataSourceResourceName, "cluster_id"), + resource.TestCheckResourceAttr(resourceName, "compute_config.#", "0"), resource.TestCheckResourceAttrPair(resourceName, names.AttrCreatedAt, dataSourceResourceName, names.AttrCreatedAt), resource.TestCheckResourceAttr(dataSourceResourceName, "enabled_cluster_log_types.#", "2"), resource.TestCheckTypeSetElemAttr(dataSourceResourceName, "enabled_cluster_log_types.*", "api"), @@ -42,6 +43,7 @@ func TestAccEKSClusterDataSource_basic(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "identity.0.oidc.#", dataSourceResourceName, "identity.0.oidc.#"), resource.TestCheckResourceAttrPair(resourceName, "identity.0.oidc.0.issuer", dataSourceResourceName, "identity.0.oidc.0.issuer"), resource.TestCheckResourceAttrPair(resourceName, "kubernetes_network_config.#", dataSourceResourceName, "kubernetes_network_config.#"), + resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.#", "1"), resource.TestCheckResourceAttrPair(resourceName, "kubernetes_network_config.0.ip_family", dataSourceResourceName, "kubernetes_network_config.0.ip_family"), resource.TestCheckResourceAttrPair(resourceName, "kubernetes_network_config.0.service_ipv4_cidr", dataSourceResourceName, "kubernetes_network_config.0.service_ipv4_cidr"), resource.TestCheckResourceAttrPair(resourceName, "kubernetes_network_config.0.service_ipv6_cidr", dataSourceResourceName, "kubernetes_network_config.0.service_ipv6_cidr"), @@ -50,6 +52,7 @@ func TestAccEKSClusterDataSource_basic(t *testing.T) { resource.TestCheckResourceAttr(dataSourceResourceName, "remote_network_config.#", "0"), resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, dataSourceResourceName, names.AttrRoleARN), resource.TestCheckResourceAttrPair(resourceName, names.AttrStatus, dataSourceResourceName, names.AttrStatus), + resource.TestCheckResourceAttr(resourceName, "storage_config.#", "0"), resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsPercent, dataSourceResourceName, acctest.CtTagsPercent), resource.TestCheckResourceAttr(resourceName, "upgrade_policy.#", "1"), resource.TestCheckResourceAttr(resourceName, "upgrade_policy.0.support_type", "EXTENDED"), @@ -87,11 +90,13 @@ func TestAccEKSClusterDataSource_outpost(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, names.AttrARN, dataSourceResourceName, names.AttrARN), resource.TestCheckResourceAttr(dataSourceResourceName, "certificate_authority.#", "1"), resource.TestCheckResourceAttrPair(resourceName, "certificate_authority.0.data", dataSourceResourceName, "certificate_authority.0.data"), + resource.TestCheckResourceAttr(resourceName, "compute_config.#", "0"), resource.TestCheckResourceAttrPair(resourceName, names.AttrCreatedAt, dataSourceResourceName, names.AttrCreatedAt), resource.TestCheckResourceAttr(dataSourceResourceName, "enabled_cluster_log_types.#", "0"), resource.TestCheckResourceAttrPair(resourceName, names.AttrEndpoint, dataSourceResourceName, names.AttrEndpoint), resource.TestCheckResourceAttr(dataSourceResourceName, "identity.#", "0"), resource.TestCheckResourceAttrPair(resourceName, "kubernetes_network_config.#", dataSourceResourceName, "kubernetes_network_config.#"), + resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.#", "1"), resource.TestCheckResourceAttrPair(resourceName, "kubernetes_network_config.0.ip_family", dataSourceResourceName, "kubernetes_network_config.0.ip_family"), resource.TestCheckResourceAttrPair(resourceName, "kubernetes_network_config.0.service_ipv4_cidr", dataSourceResourceName, "kubernetes_network_config.0.service_ipv4_cidr"), resource.TestCheckResourceAttrPair(resourceName, "kubernetes_network_config.0.service_ipv6_cidr", dataSourceResourceName, "kubernetes_network_config.0.service_ipv6_cidr"), @@ -99,6 +104,7 @@ func TestAccEKSClusterDataSource_outpost(t *testing.T) { resource.TestCheckResourceAttr(dataSourceResourceName, "remote_network_config.#", "0"), resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, dataSourceResourceName, names.AttrRoleARN), resource.TestCheckResourceAttrPair(resourceName, names.AttrStatus, dataSourceResourceName, names.AttrStatus), + resource.TestCheckResourceAttr(resourceName, "storage_config.#", "0"), resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsPercent, dataSourceResourceName, acctest.CtTagsPercent), resource.TestCheckResourceAttr(resourceName, "upgrade_policy.#", "1"), resource.TestCheckResourceAttr(resourceName, "upgrade_policy.0.support_type", "EXTENDED"), diff --git a/internal/service/eks/cluster_test.go b/internal/service/eks/cluster_test.go index 8ae6237b7fe..8fbc64e1a5d 100644 --- a/internal/service/eks/cluster_test.go +++ b/internal/service/eks/cluster_test.go @@ -283,6 +283,57 @@ func TestAccEKSCluster_BootstrapSelfManagedAddons_migrate(t *testing.T) { }) } +func TestAccEKSCluster_ComputeConfig(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); testAccPreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EKSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccClusterConfig_computeConfig(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &cluster1), + resource.TestCheckResourceAttr(resourceName, "compute_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "compute_config.0.enabled", acctest.CtTrue), + resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.#", "1"), + resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.0.enabled", acctest.CtTrue), + resource.TestCheckResourceAttr(resourceName, "storage_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_config.0.block_storage.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_config.0.block_storage.0.enabled", acctest.CtTrue), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"bootstrap_self_managed_addons"}, + }, + { + Config: testAccClusterConfig_computeConfig(rName, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &cluster2), + testAccCheckClusterNotRecreated(&cluster1, &cluster2), + resource.TestCheckResourceAttr(resourceName, "compute_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "compute_config.0.enabled", acctest.CtFalse), + resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.#", "1"), + resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.0.enabled", acctest.CtFalse), + resource.TestCheckResourceAttr(resourceName, "storage_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_config.0.block_storage.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_config.0.block_storage.0.enabled", acctest.CtFalse), + ), + }, + }, + }) +} + func TestAccEKSCluster_Encryption_create(t *testing.T) { ctx := acctest.Context(t) var cluster types.Cluster @@ -1261,6 +1312,162 @@ resource "aws_eks_cluster" "test" { `, rName, bootstrapSelfManagedAddons)) } +func testAccClusterConfig_computeConfigBase(rName string) string { + return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_iam_role" "cluster" { + name = %[1]q + + assume_role_policy = < **NOTE:** When using EKS Auto Mode `compute_config.enabled`, `kubernetes_network_config.elastic_load_balancing.enabled`, and `storage_config.block_storage.enabled` must *ALL be set to `true`. Likewise for disabling EKS Auto Mode, all three arguments must be set to `false`. + +```terraform +resource "aws_eks_cluster" "example" { + name = "example" + + access_config { + authentication_mode = "API" + } + + role_arn = aws_iam_role.cluster.arn + version = "1.31" + + compute_config { + enabled = true + node_pools = ["general-purpose"] + node_role_arn = aws_iam_role.node.arn + } + + kubernetes_network_config { + elastic_load_balancing { + enabled = true + } + } + + storage_config { + block_storage { + enabled = true + } + } + + vpc_config { + endpoint_private_access = true + endpoint_public_access = true + + subnet_ids = [ + aws_subnet.az1.id, + aws_subnet.az2.id, + aws_subnet.az3.id, + ] + } + + # Ensure that IAM Role permissions are created before and deleted + # after EKS Cluster handling. Otherwise, EKS will not be able to + # properly delete EKS managed EC2 infrastructure such as Security Groups. + depends_on = [ + aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy, + aws_iam_role_policy_attachment.cluster_AmazonEKSComputePolicy, + aws_iam_role_policy_attachment.cluster_AmazonEKSBlockStoragePolicy, + aws_iam_role_policy_attachment.cluster_AmazonEKSLoadBalancingPolicy, + aws_iam_role_policy_attachment.cluster_AmazonEKSNetworkingPolicy, + ] +} + +resource "aws_iam_role" "node" { + name = "eks-auto-node-example" + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = ["sts:AssumeRole"] + Effect = "Allow" + Principal = { + Service = "ec2.amazonaws.com" + } + }, + ] + }) +} + +resource "aws_iam_role_policy_attachment" "node_AmazonEKSWorkerNodeMinimalPolicy" { + policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodeMinimalPolicy" + role = aws_iam_role.node.name +} + +resource "aws_iam_role_policy_attachment" "node_AmazonEC2ContainerRegistryPullOnly" { + policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPullOnly" + role = aws_iam_role.node.name +} + +resource "aws_iam_role" "cluster" { + name = "eks-cluster-example" + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = [ + "sts:AssumeRole", + "sts:TagSession" + ] + Effect = "Allow" + Principal = { + Service = "eks.amazonaws.com" + } + }, + ] + }) +} + +resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSClusterPolicy" { + policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy" + role = aws_iam_role.cluster.name +} + +resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSComputePolicy" { + policy_arn = "arn:aws:iam::aws:policy/AmazonEKSComputePolicy" + role = aws_iam_role.cluster.name +} + +resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSBlockStoragePolicy" { + policy_arn = "arn:aws:iam::aws:policy/AmazonEKSBlockStoragePolicy" + role = aws_iam_role.cluster.name +} + +resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSLoadBalancingPolicy" { + policy_arn = "arn:aws:iam::aws:policy/AmazonEKSLoadBalancingPolicy" + role = aws_iam_role.cluster.name +} + +resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSNetworkingPolicy" { + policy_arn = "arn:aws:iam::aws:policy/AmazonEKSNetworkingPolicy" + role = aws_iam_role.cluster.name +} +``` + ### EKS Cluster with EKS Hybrid Nodes ```terraform @@ -217,11 +344,16 @@ 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`. +* `compute_config` - (Optional) Configuration block with compute configuration for EKS Auto Mode. Detailed below. * `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. 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. +<<<<<<< HEAD * `remote_network_config` - (Optional) Configuration block with remote network configuration for EKS Hybrid Nodes. Detailed below. +======= +* `storage_config` - (Optional) Configuration block with storage configuration for EKS Auto Mode. Detailed below. +>>>>>>> e8e205cf10 (r/aws_eks_cluster: Add support for EKS Auto Mode) * `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. @@ -234,6 +366,14 @@ The `access_config` configuration block supports the following arguments: * `authentication_mode` - (Optional) The authentication mode for the cluster. Valid values are `CONFIG_MAP`, `API` or `API_AND_CONFIG_MAP` * `bootstrap_cluster_creator_admin_permissions` - (Optional) Whether or not to bootstrap the access config values to the cluster. Default is `false`. +### compute_config + +The `compute_config` configuration block supports the following arguments: + +* `enabled` - (Optional) Request to enable or disable the compute capability on your EKS Auto Mode cluster. If the compute capability is enabled, EKS Auto Mode will create and delete EC2 Managed Instances in your Amazon Web Services account. +* `node_pools` - (Optional) Configuration for node pools that defines the compute resources for your EKS Auto Mode cluster. Valid options are `general-purpose` and `system`. +* `node_role_arn` - (Optional) The ARN of the IAM Role EKS will assign to EC2 Managed Instances in your EKS Auto Mode cluster. This value cannot be changed after the compute capability of EKS Auto Mode is enabled.. + ### encryption_config The `encryption_config` configuration block supports the following arguments: @@ -247,6 +387,7 @@ The `provider` configuration block supports the following arguments: * `key_arn` - (Required) ARN of the Key Management Service (KMS) customer master key (CMK). The CMK must be symmetric, created in the same region as the cluster, and if the CMK was created in a different account, the user must have access to the CMK. For more information, see [Allowing Users in Other Accounts to Use a CMK in the AWS Key Management Service Developer Guide](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-modifying-external-accounts.html). +<<<<<<< HEAD ### remote_network_config The `remote_network_config` configuration block supports the following arguments: @@ -265,6 +406,19 @@ The `remote_node_networks` configuration block supports the following arguments: The `remote_pod_networks` configuration block supports the following arguments: * `cidrs` - (Required) List of network CIDRs that can contain pods that run Kubernetes webhooks on hybrid nodes. +======= +### storage_config + +The `storage_config` configuration block supports the following arguments: + +* `block_storage` - (Optional) Configuration block with block storage configuration for EKS Auto Mode. Detailed below. + +#### block_storage + +The `block_storage` configuration block supports the following arguments: + +* `enabled` - (Optional) Indicates if the block storage capability is enabled on your EKS Auto Mode cluster. If the block storage capability is enabled, EKS Auto Mode will create and delete EBS volumes in your Amazon Web Services account. +>>>>>>> e8e205cf10 (r/aws_eks_cluster: Add support for EKS Auto Mode) ### vpc_config Arguments @@ -278,6 +432,7 @@ The `remote_pod_networks` configuration block supports the following arguments: The `kubernetes_network_config` configuration block supports the following arguments: +* `elastic_load_balancing` - (Optional) Configuration block with elastic load balancing configuration for the cluster. Detailed below. * `service_ipv4_cidr` - (Optional) The CIDR block to assign Kubernetes pod and service IP addresses from. If you don't specify a block, Kubernetes assigns addresses from either the 10.100.0.0/16 or 172.20.0.0/16 CIDR blocks. We recommend that you specify a block that does not overlap with resources in other networks that are peered or connected to your VPC. You can only specify a custom CIDR block when you create a cluster, changing this value will force a new cluster to be created. The block must meet the following requirements: * Within one of the following private IP address blocks: 10.0.0.0/8, 172.16.0.0/12, or 192.168.0.0/16. @@ -287,6 +442,12 @@ The `kubernetes_network_config` configuration block supports the following argum * Between /24 and /12. * `ip_family` - (Optional) The IP family used to assign Kubernetes pod and service addresses. Valid values are `ipv4` (default) and `ipv6`. You can only specify an IP family when you create a cluster, changing this value will force a new cluster to be created. +#### elastic_load_balancing + +The `elastic_load_balancing` configuration block supports the following arguments: + +* `enabled` - (Optional) Indicates if the load balancing capability is enabled on your EKS Auto Mode cluster. If the load balancing capability is enabled, EKS Auto Mode will create and delete load balancers in your Amazon Web Services account. + ### outpost_config The `outpost_config` configuration block supports the following arguments: From 6f2aa7d8b060a64e619b3286083071d10768fd8a Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Fri, 29 Nov 2024 09:46:34 -0600 Subject: [PATCH 02/17] fix: Add type validation to `node_pools` --- internal/service/eks/cluster.go | 3 ++- internal/service/eks/consts.go | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/internal/service/eks/cluster.go b/internal/service/eks/cluster.go index b616be2dc3f..41b42b59f2d 100644 --- a/internal/service/eks/cluster.go +++ b/internal/service/eks/cluster.go @@ -129,7 +129,8 @@ func resourceCluster() *schema.Resource { Type: schema.TypeSet, Optional: true, Elem: &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(nodePoolType_Values(), false), }, }, "node_role_arn": { diff --git a/internal/service/eks/consts.go b/internal/service/eks/consts.go index 0d2130f27ad..4721f680e0d 100644 --- a/internal/service/eks/consts.go +++ b/internal/service/eks/consts.go @@ -42,3 +42,15 @@ func accessEntryType_Values() []string { accessEntryTypeStandard, } } + +const ( + nodePoolGeneralPurpose = "general-purpose" + nodePoolSystem = "system" +) + +func nodePoolType_Values() []string { + return []string{ + nodePoolGeneralPurpose, + nodePoolSystem, + } +} From 14704fd12799309e0184d478d44dd7497fa1cfba Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Fri, 29 Nov 2024 09:47:28 -0600 Subject: [PATCH 03/17] fix: Swap out hybrid node type for auto mode type --- internal/service/eks/consts.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/eks/consts.go b/internal/service/eks/consts.go index 4721f680e0d..87a67c59e7c 100644 --- a/internal/service/eks/consts.go +++ b/internal/service/eks/consts.go @@ -26,19 +26,19 @@ const ( ) const ( + accessEntryTypeEC2 = "EC2" accessEntryTypeEC2Linux = "EC2_LINUX" accessEntryTypeEC2Windows = "EC2_WINDOWS" accessEntryTypeFargateLinux = "FARGATE_LINUX" - accessEntryTypeHybridLinux = "HYBRID_LINUX" accessEntryTypeStandard = "STANDARD" ) func accessEntryType_Values() []string { return []string{ + accessEntryTypeEC2, accessEntryTypeEC2Linux, accessEntryTypeEC2Windows, accessEntryTypeFargateLinux, - accessEntryTypeHybridLinux, accessEntryTypeStandard, } } From 896a9fb2aad83e34b44032f397c4671aa7eef7d0 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Fri, 29 Nov 2024 09:51:48 -0600 Subject: [PATCH 04/17] fix: Remove VPC controller policy that is not required for examples From 7cf44e218bb15ddfc6a0482183e3d6bef1c2ae7d Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Sun, 1 Dec 2024 08:03:20 -0600 Subject: [PATCH 05/17] Update internal/service/eks/cluster_test.go Co-authored-by: Graham Davison --- internal/service/eks/cluster_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/service/eks/cluster_test.go b/internal/service/eks/cluster_test.go index 8fbc64e1a5d..dd9fe8ae2f4 100644 --- a/internal/service/eks/cluster_test.go +++ b/internal/service/eks/cluster_test.go @@ -301,6 +301,9 @@ func TestAccEKSCluster_ComputeConfig(t *testing.T) { testAccCheckClusterExists(ctx, resourceName, &cluster1), resource.TestCheckResourceAttr(resourceName, "compute_config.#", "1"), resource.TestCheckResourceAttr(resourceName, "compute_config.0.enabled", acctest.CtTrue), + resource.TestCheckResourceAttr(resourceName, "compute_config.0.node_pools.#", "1"), + resource.TestCheckResourceAttr(resourceName, "compute_config.0.node_pools.0", "general-purpose"), + resource.TestCheckResourceAttrPair(resourceName, "compute_config.0.node_role_arn", "aws_iam_role.node", "arn"), resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.#", "1"), resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.#", "1"), resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.0.enabled", acctest.CtTrue), From e1ca0636e26b6a6a67ce053a23d8604fc29e5069 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Sun, 1 Dec 2024 08:03:29 -0600 Subject: [PATCH 06/17] Update internal/service/eks/cluster_test.go Co-authored-by: Graham Davison --- internal/service/eks/cluster_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/service/eks/cluster_test.go b/internal/service/eks/cluster_test.go index dd9fe8ae2f4..a432bc98d20 100644 --- a/internal/service/eks/cluster_test.go +++ b/internal/service/eks/cluster_test.go @@ -325,6 +325,9 @@ func TestAccEKSCluster_ComputeConfig(t *testing.T) { testAccCheckClusterNotRecreated(&cluster1, &cluster2), resource.TestCheckResourceAttr(resourceName, "compute_config.#", "1"), resource.TestCheckResourceAttr(resourceName, "compute_config.0.enabled", acctest.CtFalse), + resource.TestCheckResourceAttr(resourceName, "compute_config.0.node_pools.#", "1"), + resource.TestCheckResourceAttr(resourceName, "compute_config.0.node_pools.0", "general-purpose"), + resource.TestCheckResourceAttrPair(resourceName, "compute_config.0.node_role_arn", "aws_iam_role.node", "arn"), resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.#", "1"), resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.#", "1"), resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.0.enabled", acctest.CtFalse), From ae5c350e1c015955516c631cfaf17390829fdaea Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Sun, 1 Dec 2024 08:04:02 -0600 Subject: [PATCH 07/17] Update internal/service/eks/cluster.go Co-authored-by: Graham Davison --- internal/service/eks/cluster.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/service/eks/cluster.go b/internal/service/eks/cluster.go index 41b42b59f2d..d9882ac9d11 100644 --- a/internal/service/eks/cluster.go +++ b/internal/service/eks/cluster.go @@ -123,7 +123,6 @@ func resourceCluster() *schema.Resource { "enabled": { Type: schema.TypeBool, Optional: true, - Default: false, }, "node_pools": { Type: schema.TypeSet, From 7c3dfdfa067ce1c18ec2953b38b720d93f058186 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Sun, 1 Dec 2024 08:04:09 -0600 Subject: [PATCH 08/17] Update internal/service/eks/cluster.go Co-authored-by: Graham Davison --- internal/service/eks/cluster.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/service/eks/cluster.go b/internal/service/eks/cluster.go index d9882ac9d11..46353adf0be 100644 --- a/internal/service/eks/cluster.go +++ b/internal/service/eks/cluster.go @@ -225,7 +225,6 @@ func resourceCluster() *schema.Resource { "enabled": { Type: schema.TypeBool, Optional: true, - Default: false, }, }, }, From b6a4205cff16eaafd67386862cb5f6ab0215fd63 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Sun, 1 Dec 2024 08:04:17 -0600 Subject: [PATCH 09/17] Update internal/service/eks/cluster.go Co-authored-by: Graham Davison --- internal/service/eks/cluster.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/service/eks/cluster.go b/internal/service/eks/cluster.go index 46353adf0be..6002fa0bb9f 100644 --- a/internal/service/eks/cluster.go +++ b/internal/service/eks/cluster.go @@ -382,7 +382,6 @@ func resourceCluster() *schema.Resource { "enabled": { Type: schema.TypeBool, Optional: true, - Default: false, }, }, }, From 9dc95c3d88ca54a5c04c80e877cc436cb5ba0dc6 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Sun, 1 Dec 2024 08:07:23 -0600 Subject: [PATCH 10/17] chore: Add node role ARN force new and validation --- internal/service/eks/cluster.go | 8 ++++---- internal/service/eks/cluster_test.go | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/internal/service/eks/cluster.go b/internal/service/eks/cluster.go index 6002fa0bb9f..a4aca5beb24 100644 --- a/internal/service/eks/cluster.go +++ b/internal/service/eks/cluster.go @@ -133,10 +133,10 @@ func resourceCluster() *schema.Resource { }, }, "node_role_arn": { - Type: schema.TypeString, - Optional: true, - // ForceNew: true, - // ValidateFunc: validation.NoZeroValues, + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: verify.ValidARN, }, }, }, diff --git a/internal/service/eks/cluster_test.go b/internal/service/eks/cluster_test.go index a432bc98d20..bd0940ecbeb 100644 --- a/internal/service/eks/cluster_test.go +++ b/internal/service/eks/cluster_test.go @@ -52,6 +52,7 @@ func TestAccEKSCluster_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "certificate_authority.#", "1"), resource.TestCheckResourceAttrSet(resourceName, "certificate_authority.0.data"), resource.TestCheckNoResourceAttr(resourceName, "cluster_id"), + resource.TestCheckResourceAttr(resourceName, "compute_config.#", "0"), acctest.CheckResourceAttrRFC3339(resourceName, names.AttrCreatedAt), resource.TestCheckResourceAttr(resourceName, "enabled_cluster_log_types.#", "0"), resource.TestCheckResourceAttr(resourceName, "encryption_config.#", "0"), @@ -60,6 +61,8 @@ func TestAccEKSCluster_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "identity.0.oidc.#", "1"), resource.TestMatchResourceAttr(resourceName, "identity.0.oidc.0.issuer", regexache.MustCompile(`^https://`)), resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.#", "1"), + resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.0.enabled", "false"), resource.TestCheckResourceAttrSet(resourceName, "kubernetes_network_config.0.service_ipv4_cidr"), resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.ip_family", "ipv4"), resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), @@ -67,6 +70,7 @@ func TestAccEKSCluster_basic(t *testing.T) { resource.TestMatchResourceAttr(resourceName, "platform_version", regexache.MustCompile(`^eks\.\d+$`)), resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.cluster", names.AttrARN), resource.TestCheckResourceAttr(resourceName, names.AttrStatus, string(types.ClusterStatusActive)), + resource.TestCheckResourceAttr(resourceName, "storage_config.#", "0"), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "0"), resource.TestMatchResourceAttr(resourceName, names.AttrVersion, regexache.MustCompile(`^\d+\.\d+$`)), resource.TestCheckResourceAttr(resourceName, "upgrade_policy.#", "1"), From 2f768017865383672fd2ebb3a3770665c6475fa7 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Sun, 1 Dec 2024 08:33:32 -0600 Subject: [PATCH 11/17] feat: Add customizeDiff for auto mode enable/disable --- internal/service/eks/cluster.go | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/internal/service/eks/cluster.go b/internal/service/eks/cluster.go index a4aca5beb24..d8a17b64c3a 100644 --- a/internal/service/eks/cluster.go +++ b/internal/service/eks/cluster.go @@ -5,6 +5,7 @@ package eks import ( "context" + "errors" "fmt" "log" "time" @@ -53,6 +54,7 @@ func resourceCluster() *schema.Resource { CustomizeDiff: customdiff.Sequence( verify.SetTagsDiff, + validateAutoModeCustsomizeDiff, customdiff.ForceNewIfChange("encryption_config", func(_ context.Context, old, new, meta interface{}) bool { // You cannot disable envelope encryption after enabling it. This action is irreversible. return len(old.([]interface{})) == 1 && len(new.([]interface{})) == 0 @@ -529,15 +531,6 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta int input.ZonalShiftConfig = expandZonalShiftConfig(v.([]interface{})) } - // // ToDo - this doesn't seem to work as intended - // if aws.ToBool(input.ComputeConfig.Enabled) { - // input.KubernetesNetworkConfig.ElasticLoadBalancing.Enabled = aws.Bool(true) - // input.StorageConfig.BlockStorage.Enabled = aws.Bool(true) - // } else { - // input.KubernetesNetworkConfig.ElasticLoadBalancing.Enabled = aws.Bool(false) - // input.StorageConfig.BlockStorage.Enabled = aws.Bool(false) - // } - outputRaw, err := tfresource.RetryWhen(ctx, propagationTimeout, func() (interface{}, error) { return conn.CreateCluster(ctx, input) @@ -1764,3 +1757,19 @@ func flattenZonalShiftConfig(apiObject *types.ZonalShiftConfigResponse) []interf return []interface{}{tfMap} } + +// EKS Auto Mode is comprised of `compute_config`, `kubernetes_networking.elastic_load_balancing`, and `storage_config` attributes. +// All three `enabled` fields need to be set to either `true` or `false` +func validateAutoModeCustsomizeDiff(_ context.Context, d *schema.ResourceDiff, _ any) error { + if d.HasChanges("compute_config", "kubernetes_network_config", "storage_config") { + computeConfig := expandComputeConfigRequest(d.Get("compute_config").([]interface{})) + kubernetesNetworkConfig := expandKubernetesNetworkConfigRequest(d.Get("kubernetes_network_config").([]interface{})) + storageConfig := expandStorageConfigRequest(d.Get("storage_config").([]interface{})) + + if computeConfig.Enabled != kubernetesNetworkConfig.ElasticLoadBalancing.Enabled || computeConfig.Enabled != storageConfig.BlockStorage.Enabled { + return errors.New("compute_config.enabled, kubernetes_networking_config.elastic_load_balancing.enabled, and storage_config.block_storage.enabled must all be set to either true or false") + } + } + + return nil +} From 7ede0a57c3ec4ca8b45eada2f4cc20eba5f4f613 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Sun, 1 Dec 2024 10:01:32 -0600 Subject: [PATCH 12/17] chore: Clean up --- internal/service/eks/cluster.go | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/internal/service/eks/cluster.go b/internal/service/eks/cluster.go index d8a17b64c3a..3ffe563d522 100644 --- a/internal/service/eks/cluster.go +++ b/internal/service/eks/cluster.go @@ -118,7 +118,6 @@ func resourceCluster() *schema.Resource { "compute_config": { Type: schema.TypeList, Optional: true, - Computed: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -712,16 +711,6 @@ func resourceClusterUpdate(ctx context.Context, d *schema.ResourceData, meta int kubernetesNetworkConfig := expandKubernetesNetworkConfigRequest(d.Get("kubernetes_network_config").([]interface{})) storageConfig := expandStorageConfigRequest(d.Get("storage_config").([]interface{})) - // InvalidParameterException: For EKS Auto Mode, please ensure that all required configs, - // including computeConfig, kubernetesNetworkConfig, and blockStorage are all either fully enabled or fully disabled. - if computeConfig != nil && aws.ToBool(computeConfig.Enabled) { - kubernetesNetworkConfig.ElasticLoadBalancing.Enabled = aws.Bool(true) - storageConfig.BlockStorage.Enabled = aws.Bool(true) - } else { - kubernetesNetworkConfig.ElasticLoadBalancing.Enabled = aws.Bool(false) - storageConfig.BlockStorage.Enabled = aws.Bool(false) - } - input := &eks.UpdateClusterConfigInput{ Name: aws.String(d.Id()), ComputeConfig: computeConfig, @@ -1758,15 +1747,15 @@ func flattenZonalShiftConfig(apiObject *types.ZonalShiftConfigResponse) []interf return []interface{}{tfMap} } -// EKS Auto Mode is comprised of `compute_config`, `kubernetes_networking.elastic_load_balancing`, and `storage_config` attributes. -// All three `enabled` fields need to be set to either `true` or `false` +// InvalidParameterException: For EKS Auto Mode, please ensure that all required configs, +// including computeConfig, kubernetesNetworkConfig, and blockStorage are all either fully enabled or fully disabled. func validateAutoModeCustsomizeDiff(_ context.Context, d *schema.ResourceDiff, _ any) error { if d.HasChanges("compute_config", "kubernetes_network_config", "storage_config") { computeConfig := expandComputeConfigRequest(d.Get("compute_config").([]interface{})) kubernetesNetworkConfig := expandKubernetesNetworkConfigRequest(d.Get("kubernetes_network_config").([]interface{})) storageConfig := expandStorageConfigRequest(d.Get("storage_config").([]interface{})) - if computeConfig.Enabled != kubernetesNetworkConfig.ElasticLoadBalancing.Enabled || computeConfig.Enabled != storageConfig.BlockStorage.Enabled { + if aws.ToBool(computeConfig.Enabled) != aws.ToBool(kubernetesNetworkConfig.ElasticLoadBalancing.Enabled) || aws.ToBool(computeConfig.Enabled) != aws.ToBool(storageConfig.BlockStorage.Enabled) { return errors.New("compute_config.enabled, kubernetes_networking_config.elastic_load_balancing.enabled, and storage_config.block_storage.enabled must all be set to either true or false") } } From 0bc93387868b437bef2e5904d09e828f2d1a29a0 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Sun, 1 Dec 2024 15:08:55 -0600 Subject: [PATCH 13/17] chore: Add changelog entry, remove local SDK path re-write --- .changelog/40370.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/40370.txt diff --git a/.changelog/40370.txt b/.changelog/40370.txt new file mode 100644 index 00000000000..643c98d44b6 --- /dev/null +++ b/.changelog/40370.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_eks_cluster: Add `compute_config`, `storage_config`, and `kubernetes_network_config.elastic_load_balancing` arguments for EKS Auto Mode +``` From dcb0db14102101761964e382925af10b34ae2000 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Mon, 2 Dec 2024 10:14:40 -0600 Subject: [PATCH 14/17] fix: Correct semgrep checks --- internal/service/eks/cluster.go | 22 ++++++++++----------- internal/service/eks/cluster_data_source.go | 6 +++--- internal/service/eks/cluster_test.go | 6 +++--- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/internal/service/eks/cluster.go b/internal/service/eks/cluster.go index 3ffe563d522..70120762d77 100644 --- a/internal/service/eks/cluster.go +++ b/internal/service/eks/cluster.go @@ -121,7 +121,7 @@ func resourceCluster() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "enabled": { + names.AttrEnabled: { Type: schema.TypeBool, Optional: true, }, @@ -223,7 +223,7 @@ func resourceCluster() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "enabled": { + names.AttrEnabled: { Type: schema.TypeBool, Optional: true, }, @@ -380,7 +380,7 @@ func resourceCluster() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "enabled": { + names.AttrEnabled: { Type: schema.TypeBool, Optional: true, }, @@ -1124,7 +1124,7 @@ func expandComputeConfigRequest(tfList []interface{}) *types.ComputeConfigReques apiObject := &types.ComputeConfigRequest{} - if v, ok := tfMap["enabled"].(bool); ok { + if v, ok := tfMap[names.AttrEnabled].(bool); ok { apiObject.Enabled = aws.Bool(v) } @@ -1216,7 +1216,7 @@ func expandBlockStorage(tfList []interface{}) *types.BlockStorage { apiObject := &types.BlockStorage{} - if v, ok := tfMap["enabled"].(bool); ok { + if v, ok := tfMap[names.AttrEnabled].(bool); ok { apiObject.Enabled = aws.Bool(v) } @@ -1332,7 +1332,7 @@ func expandKubernetesNetworkConfigElasticLoadBalancing(tfList []interface{}) *ty apiObject := &types.ElasticLoadBalancing{} - if v, ok := tfMap["enabled"].(bool); ok { + if v, ok := tfMap[names.AttrEnabled].(bool); ok { apiObject.Enabled = aws.Bool(v) } @@ -1480,9 +1480,9 @@ func flattenComputeConfigResponse(apiObject *types.ComputeConfigResponse) []map[ } m := map[string]interface{}{ - "enabled": aws.ToBool(apiObject.Enabled), - "node_pools": flex.FlattenStringValueList(apiObject.NodePools), - "node_role_arn": aws.ToString(apiObject.NodeRoleArn), + names.AttrEnabled: aws.ToBool(apiObject.Enabled), + "node_pools": flex.FlattenStringValueList(apiObject.NodePools), + "node_role_arn": aws.ToString(apiObject.NodeRoleArn), } return []map[string]interface{}{m} @@ -1618,7 +1618,7 @@ func flattenKubernetesNetworkConfigElasticLoadBalancing(apiObjects *types.Elasti } tfMap := map[string]interface{}{ - "enabled": aws.ToBool(apiObjects.Enabled), + names.AttrEnabled: aws.ToBool(apiObjects.Enabled), } return []interface{}{tfMap} @@ -1717,7 +1717,7 @@ func flattenBlockStorage(apiObject *types.BlockStorage) []interface{} { } tfMap := map[string]interface{}{ - "enabled": aws.ToBool(apiObject.Enabled), + names.AttrEnabled: aws.ToBool(apiObject.Enabled), } return []interface{}{tfMap} diff --git a/internal/service/eks/cluster_data_source.go b/internal/service/eks/cluster_data_source.go index 736e86e54df..10c84e7f1cd 100644 --- a/internal/service/eks/cluster_data_source.go +++ b/internal/service/eks/cluster_data_source.go @@ -62,7 +62,7 @@ func dataSourceCluster() *schema.Resource { Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "enabled": { + names.AttrEnabled: { Type: schema.TypeBool, Computed: true, }, @@ -123,7 +123,7 @@ func dataSourceCluster() *schema.Resource { Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "enabled": { + names.AttrEnabled: { Type: schema.TypeBool, Computed: true, }, @@ -237,7 +237,7 @@ func dataSourceCluster() *schema.Resource { Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "enabled": { + names.AttrEnabled: { Type: schema.TypeBool, Computed: true, }, diff --git a/internal/service/eks/cluster_test.go b/internal/service/eks/cluster_test.go index bd0940ecbeb..2c3cef477fa 100644 --- a/internal/service/eks/cluster_test.go +++ b/internal/service/eks/cluster_test.go @@ -62,7 +62,7 @@ func TestAccEKSCluster_basic(t *testing.T) { resource.TestMatchResourceAttr(resourceName, "identity.0.oidc.0.issuer", regexache.MustCompile(`^https://`)), resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.#", "1"), resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.#", "1"), - resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.0.enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.0.enabled", acctest.CtFalse), resource.TestCheckResourceAttrSet(resourceName, "kubernetes_network_config.0.service_ipv4_cidr"), resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.ip_family", "ipv4"), resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), @@ -307,7 +307,7 @@ func TestAccEKSCluster_ComputeConfig(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "compute_config.0.enabled", acctest.CtTrue), resource.TestCheckResourceAttr(resourceName, "compute_config.0.node_pools.#", "1"), resource.TestCheckResourceAttr(resourceName, "compute_config.0.node_pools.0", "general-purpose"), - resource.TestCheckResourceAttrPair(resourceName, "compute_config.0.node_role_arn", "aws_iam_role.node", "arn"), + resource.TestCheckResourceAttrPair(resourceName, "compute_config.0.node_role_arn", "aws_iam_role.node", names.AttrARN), resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.#", "1"), resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.#", "1"), resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.0.enabled", acctest.CtTrue), @@ -331,7 +331,7 @@ func TestAccEKSCluster_ComputeConfig(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "compute_config.0.enabled", acctest.CtFalse), resource.TestCheckResourceAttr(resourceName, "compute_config.0.node_pools.#", "1"), resource.TestCheckResourceAttr(resourceName, "compute_config.0.node_pools.0", "general-purpose"), - resource.TestCheckResourceAttrPair(resourceName, "compute_config.0.node_role_arn", "aws_iam_role.node", "arn"), + resource.TestCheckResourceAttrPair(resourceName, "compute_config.0.node_role_arn", "aws_iam_role.node", names.AttrARN), resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.#", "1"), resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.#", "1"), resource.TestCheckResourceAttr(resourceName, "kubernetes_network_config.0.elastic_load_balancing.0.enabled", acctest.CtFalse), From 6fbe79fc3c063166084668f0f1a8e2106ec44484 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Mon, 2 Dec 2024 13:54:45 -0600 Subject: [PATCH 15/17] fix: Avoid casting nil to boolean when not set in customizeDiff --- internal/service/eks/cluster.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/service/eks/cluster.go b/internal/service/eks/cluster.go index 70120762d77..33131ca877b 100644 --- a/internal/service/eks/cluster.go +++ b/internal/service/eks/cluster.go @@ -1755,7 +1755,11 @@ func validateAutoModeCustsomizeDiff(_ context.Context, d *schema.ResourceDiff, _ kubernetesNetworkConfig := expandKubernetesNetworkConfigRequest(d.Get("kubernetes_network_config").([]interface{})) storageConfig := expandStorageConfigRequest(d.Get("storage_config").([]interface{})) - if aws.ToBool(computeConfig.Enabled) != aws.ToBool(kubernetesNetworkConfig.ElasticLoadBalancing.Enabled) || aws.ToBool(computeConfig.Enabled) != aws.ToBool(storageConfig.BlockStorage.Enabled) { + computeConfigEnabled := computeConfig != nil && computeConfig.Enabled != nil && aws.ToBool(computeConfig.Enabled) + kubernetesNetworkConfigEnabled := kubernetesNetworkConfig != nil && kubernetesNetworkConfig.ElasticLoadBalancing != nil && kubernetesNetworkConfig.ElasticLoadBalancing.Enabled != nil && aws.ToBool(kubernetesNetworkConfig.ElasticLoadBalancing.Enabled) + storageConfigEnabled := storageConfig != nil && storageConfig.BlockStorage != nil && storageConfig.BlockStorage.Enabled != nil && aws.ToBool(storageConfig.BlockStorage.Enabled) + + if computeConfigEnabled != kubernetesNetworkConfigEnabled || computeConfigEnabled != storageConfigEnabled { return errors.New("compute_config.enabled, kubernetes_networking_config.elastic_load_balancing.enabled, and storage_config.block_storage.enabled must all be set to either true or false") } } From f04e575bb9a1724c8d939e49e76c44d616ba3ca3 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Mon, 2 Dec 2024 15:13:11 -0600 Subject: [PATCH 16/17] fix: Correct merge/rebase changes --- internal/service/eks/consts.go | 2 ++ website/docs/r/eks_cluster.html.markdown | 17 ----------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/internal/service/eks/consts.go b/internal/service/eks/consts.go index 87a67c59e7c..4138157330f 100644 --- a/internal/service/eks/consts.go +++ b/internal/service/eks/consts.go @@ -30,6 +30,7 @@ const ( accessEntryTypeEC2Linux = "EC2_LINUX" accessEntryTypeEC2Windows = "EC2_WINDOWS" accessEntryTypeFargateLinux = "FARGATE_LINUX" + accessEntryTypeHybridLinux = "HYBRID_LINUX" accessEntryTypeStandard = "STANDARD" ) @@ -39,6 +40,7 @@ func accessEntryType_Values() []string { accessEntryTypeEC2Linux, accessEntryTypeEC2Windows, accessEntryTypeFargateLinux, + accessEntryTypeHybridLinux, accessEntryTypeStandard, } } diff --git a/website/docs/r/eks_cluster.html.markdown b/website/docs/r/eks_cluster.html.markdown index 082205a0f12..0cac4a6b05b 100644 --- a/website/docs/r/eks_cluster.html.markdown +++ b/website/docs/r/eks_cluster.html.markdown @@ -349,11 +349,8 @@ The following arguments are optional: * `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. -<<<<<<< HEAD * `remote_network_config` - (Optional) Configuration block with remote network configuration for EKS Hybrid Nodes. Detailed below. -======= * `storage_config` - (Optional) Configuration block with storage configuration for EKS Auto Mode. Detailed below. ->>>>>>> e8e205cf10 (r/aws_eks_cluster: Add support for EKS Auto Mode) * `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. @@ -387,7 +384,6 @@ The `provider` configuration block supports the following arguments: * `key_arn` - (Required) ARN of the Key Management Service (KMS) customer master key (CMK). The CMK must be symmetric, created in the same region as the cluster, and if the CMK was created in a different account, the user must have access to the CMK. For more information, see [Allowing Users in Other Accounts to Use a CMK in the AWS Key Management Service Developer Guide](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-modifying-external-accounts.html). -<<<<<<< HEAD ### remote_network_config The `remote_network_config` configuration block supports the following arguments: @@ -406,19 +402,6 @@ The `remote_node_networks` configuration block supports the following arguments: The `remote_pod_networks` configuration block supports the following arguments: * `cidrs` - (Required) List of network CIDRs that can contain pods that run Kubernetes webhooks on hybrid nodes. -======= -### storage_config - -The `storage_config` configuration block supports the following arguments: - -* `block_storage` - (Optional) Configuration block with block storage configuration for EKS Auto Mode. Detailed below. - -#### block_storage - -The `block_storage` configuration block supports the following arguments: - -* `enabled` - (Optional) Indicates if the block storage capability is enabled on your EKS Auto Mode cluster. If the block storage capability is enabled, EKS Auto Mode will create and delete EBS volumes in your Amazon Web Services account. ->>>>>>> e8e205cf10 (r/aws_eks_cluster: Add support for EKS Auto Mode) ### vpc_config Arguments From c1364530146332134a5c627554a0cad8382658ca Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Mon, 2 Dec 2024 15:00:03 -0800 Subject: [PATCH 17/17] Fixes diff on refresh --- internal/service/eks/cluster.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/service/eks/cluster.go b/internal/service/eks/cluster.go index 33131ca877b..43bb45fcab8 100644 --- a/internal/service/eks/cluster.go +++ b/internal/service/eks/cluster.go @@ -220,6 +220,7 @@ func resourceCluster() *schema.Resource { "elastic_load_balancing": { Type: schema.TypeList, Optional: true, + Computed: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{