From 84e62b155629c51e58158bcae7284a05f6e14536 Mon Sep 17 00:00:00 2001 From: Didrik Stevensson Date: Thu, 25 Jun 2020 12:15:40 +0200 Subject: [PATCH 1/5] resource/aws_eks_node_group: added support for node_group_name_prefix --- aws/resource_aws_eks_node_group.go | 28 +++++++++-- aws/resource_aws_eks_node_group_test.go | 51 +++++++++++++++++++++ website/docs/r/eks_node_group.html.markdown | 3 +- 3 files changed, 76 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_eks_node_group.go b/aws/resource_aws_eks_node_group.go index 09d3a3258cb..99ceb1ffcb1 100644 --- a/aws/resource_aws_eks_node_group.go +++ b/aws/resource_aws_eks_node_group.go @@ -115,10 +115,19 @@ func resourceAwsEksNodeGroup() *schema.Resource { }, }, "node_group_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.NoZeroValues, + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + ConflictsWith: []string{"node_group_name_prefix"}, + ValidateFunc: validation.NoZeroValues, + }, + "node_group_name_prefix": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"node_group_name"}, + ValidateFunc: validation.NoZeroValues, }, "node_role_arn": { Type: schema.TypeString, @@ -227,7 +236,16 @@ func resourceAwsEksNodeGroupCreate(d *schema.ResourceData, meta interface{}) err defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) clusterName := d.Get("cluster_name").(string) - nodeGroupName := d.Get("node_group_name").(string) + + var nodeGroupName string + + if v, ok := d.GetOk("node_group_name"); ok { + nodeGroupName = v.(string) + } else if v, ok := d.GetOk("node_group_name_prefix"); ok { + nodeGroupName = resource.PrefixedUniqueId(v.(string)) + } else { + nodeGroupName = resource.PrefixedUniqueId("tf-") + } input := &eks.CreateNodegroupInput{ ClientRequestToken: aws.String(resource.UniqueId()), diff --git a/aws/resource_aws_eks_node_group_test.go b/aws/resource_aws_eks_node_group_test.go index 8d92adcb211..46854251dc8 100644 --- a/aws/resource_aws_eks_node_group_test.go +++ b/aws/resource_aws_eks_node_group_test.go @@ -135,6 +135,34 @@ func TestAccAWSEksNodeGroup_basic(t *testing.T) { }) } +func TestAccAWSEksNodeGroup_NamePrefix(t *testing.T) { + var nodeGroup eks.Nodegroup + rName := acctest.RandomWithPrefix("tf-acc-test") + rNamePrefix := "tf-acc-test" + resourceName := "aws_eks_node_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEksNodeGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEksNodeGroupConfigNodeGroupNamePrefix(rName, rNamePrefix), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksNodeGroupExists(resourceName, &nodeGroup), + resource.TestCheckResourceAttr(resourceName, "node_group_name_prefix", rNamePrefix), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"node_group_name_prefix"}, + }, + }, + }) +} + func TestAccAWSEksNodeGroup_disappears(t *testing.T) { var nodeGroup eks.Nodegroup rName := acctest.RandomWithPrefix("tf-acc-test") @@ -1116,6 +1144,29 @@ resource "aws_eks_node_group" "test" { `, rName) } +func testAccAWSEksNodeGroupConfigNodeGroupNamePrefix(rName, rNamePrefix string) string { + return testAccAWSEksNodeGroupConfigBase(rName) + fmt.Sprintf(` +resource "aws_eks_node_group" "test" { + cluster_name = aws_eks_cluster.test.name + node_group_name_prefix = %[1]q + node_role_arn = aws_iam_role.node.arn + subnet_ids = aws_subnet.test[*].id + + scaling_config { + desired_size = 1 + max_size = 1 + min_size = 1 + } + + depends_on = [ + "aws_iam_role_policy_attachment.node-AmazonEKSWorkerNodePolicy", + "aws_iam_role_policy_attachment.node-AmazonEKS_CNI_Policy", + "aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly", + ] +} +`, rNamePrefix) +} + func testAccAWSEksNodeGroupConfigAmiType(rName, amiType string) string { return testAccAWSEksNodeGroupConfigBase(rName) + fmt.Sprintf(` resource "aws_eks_node_group" "test" { diff --git a/website/docs/r/eks_node_group.html.markdown b/website/docs/r/eks_node_group.html.markdown index 2c17aed57fd..23896cdf517 100644 --- a/website/docs/r/eks_node_group.html.markdown +++ b/website/docs/r/eks_node_group.html.markdown @@ -116,7 +116,6 @@ resource "aws_subnet" "example" { The following arguments are required: * `cluster_name` – (Required) Name of the EKS Cluster. Must be between 1-100 characters in length. Must begin with an alphanumeric character, and must only contain alphanumeric characters, dashes and underscores (`^[0-9A-Za-z][A-Za-z0-9\-_]+$`). -* `node_group_name` – (Required) Name of the EKS Node Group. * `node_role_arn` – (Required) Amazon Resource Name (ARN) of the IAM Role that provides permissions for the EKS Node Group. * `scaling_config` - (Required) Configuration block with scaling settings. Detailed below. * `subnet_ids` – (Required) Identifiers of EC2 Subnets to associate with the EKS Node Group. These subnets must have the following resource tag: `kubernetes.io/cluster/CLUSTER_NAME` (where `CLUSTER_NAME` is replaced with the name of the EKS Cluster). @@ -130,6 +129,8 @@ The following arguments are optional: * `instance_types` - (Optional) List of instance types associated with the EKS Node Group. Defaults to `["t3.medium"]`. Terraform will only perform drift detection if a configuration value is provided. * `labels` - (Optional) Key-value map of Kubernetes labels. Only labels that are applied with the EKS API are managed by this argument. Other Kubernetes labels applied to the EKS Node Group will not be managed. * `launch_template` - (Optional) Configuration block with Launch Template settings. Detailed below. +* `node_group_name` – (Optional) Name of the EKS Node Group. If omitted, Terraform will assign a random, unique name. +* `node_group_name_prefix` – (Optional) Creates a unique name beginning with the specified prefix. Conflicts with `node_group_name`. * `release_version` – (Optional) AMI version of the EKS Node Group. Defaults to latest version for Kubernetes version. * `remote_access` - (Optional) Configuration block with remote access settings. Detailed below. * `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](https://www.terraform.io/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. From 4da5bf13c3bcbf4b056a766c9786c97220fd4ec5 Mon Sep 17 00:00:00 2001 From: troyready Date: Wed, 30 Sep 2020 12:27:39 -0700 Subject: [PATCH 2/5] aws_eks_node_group: allow name to be optional not all node group properties can be updated via the API, making many changes require a replacement of the resource. To make this seamless with create_before_destroy, Terraform should allow for the name to be automatically computed. From ea98a467447fa2b38e17e1e2ff68ddd14899b1f5 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 12 May 2021 13:56:27 -0400 Subject: [PATCH 3/5] r/aws_eks_node_group: 'node_group_name_prefix' is Computed. --- aws/resource_aws_eks_node_group.go | 34 ++--- aws/resource_aws_eks_node_group_test.go | 152 ++++++++++++++------ website/docs/r/eks_node_group.html.markdown | 4 +- 3 files changed, 121 insertions(+), 69 deletions(-) diff --git a/aws/resource_aws_eks_node_group.go b/aws/resource_aws_eks_node_group.go index 99ceb1ffcb1..8c24ff73092 100644 --- a/aws/resource_aws_eks_node_group.go +++ b/aws/resource_aws_eks_node_group.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" ) func resourceAwsEksNodeGroup() *schema.Resource { @@ -35,15 +36,11 @@ func resourceAwsEksNodeGroup() *schema.Resource { Schema: map[string]*schema.Schema{ "ami_type": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - eks.AMITypesAl2X8664, - eks.AMITypesAl2X8664Gpu, - eks.AMITypesAl2Arm64, - }, false), + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(eks.AMITypes_Values(), false), }, "arn": { Type: schema.TypeString, @@ -117,17 +114,16 @@ func resourceAwsEksNodeGroup() *schema.Resource { "node_group_name": { Type: schema.TypeString, Optional: true, - ForceNew: true, Computed: true, + ForceNew: true, ConflictsWith: []string{"node_group_name_prefix"}, - ValidateFunc: validation.NoZeroValues, }, "node_group_name_prefix": { Type: schema.TypeString, Optional: true, + Computed: true, ForceNew: true, ConflictsWith: []string{"node_group_name"}, - ValidateFunc: validation.NoZeroValues, }, "node_role_arn": { Type: schema.TypeString, @@ -235,18 +231,9 @@ func resourceAwsEksNodeGroupCreate(d *schema.ResourceData, meta interface{}) err conn := meta.(*AWSClient).eksconn defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) - clusterName := d.Get("cluster_name").(string) - - var nodeGroupName string - - if v, ok := d.GetOk("node_group_name"); ok { - nodeGroupName = v.(string) - } else if v, ok := d.GetOk("node_group_name_prefix"); ok { - nodeGroupName = resource.PrefixedUniqueId(v.(string)) - } else { - nodeGroupName = resource.PrefixedUniqueId("tf-") - } + clusterName := d.Get("cluster_name").(string) + nodeGroupName := naming.Generate(d.Get("node_group_name").(string), d.Get("node_group_name_prefix").(string)) input := &eks.CreateNodegroupInput{ ClientRequestToken: aws.String(resource.UniqueId()), ClusterName: aws.String(clusterName), @@ -376,6 +363,7 @@ func resourceAwsEksNodeGroupRead(d *schema.ResourceData, meta interface{}) error } d.Set("node_group_name", nodeGroup.NodegroupName) + d.Set("name_prefix", naming.NamePrefixFromName(aws.StringValue(nodeGroup.NodegroupName))) d.Set("node_role_arn", nodeGroup.NodeRole) d.Set("release_version", nodeGroup.ReleaseVersion) diff --git a/aws/resource_aws_eks_node_group_test.go b/aws/resource_aws_eks_node_group_test.go index 46854251dc8..5b1e44cc97f 100644 --- a/aws/resource_aws_eks_node_group_test.go +++ b/aws/resource_aws_eks_node_group_test.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" ) func init() { @@ -111,6 +112,7 @@ func TestAccAWSEksNodeGroup_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "instance_types.#", "1"), resource.TestCheckResourceAttr(resourceName, "labels.%", "0"), resource.TestCheckResourceAttr(resourceName, "node_group_name", rName), + resource.TestCheckResourceAttr(resourceName, "node_group_name_prefix", ""), resource.TestCheckResourceAttrPair(resourceName, "node_role_arn", iamRoleResourceName, "arn"), resource.TestMatchResourceAttr(resourceName, "release_version", regexp.MustCompile(`^\d+\.\d+\.\d+-\d{8}$`)), resource.TestCheckResourceAttr(resourceName, "remote_access.#", "0"), @@ -135,29 +137,57 @@ func TestAccAWSEksNodeGroup_basic(t *testing.T) { }) } +func TestAccAWSEksNodeGroup_Name_Generated(t *testing.T) { + var nodeGroup eks.Nodegroup + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_eks_node_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ErrorCheck: testAccErrorCheck(t, eks.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEksNodeGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEksNodeGroupConfigNodeGroupNameGenerated(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEksNodeGroupExists(resourceName, &nodeGroup), + naming.TestCheckResourceAttrNameGenerated(resourceName, "node_group_name"), + resource.TestCheckResourceAttr(resourceName, "node_group_name_prefix", "terraform-"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAWSEksNodeGroup_NamePrefix(t *testing.T) { var nodeGroup eks.Nodegroup rName := acctest.RandomWithPrefix("tf-acc-test") - rNamePrefix := "tf-acc-test" resourceName := "aws_eks_node_group.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSEks(t) }, + ErrorCheck: testAccErrorCheck(t, eks.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSEksNodeGroupDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEksNodeGroupConfigNodeGroupNamePrefix(rName, rNamePrefix), + Config: testAccAWSEksNodeGroupConfigNodeGroupNamePrefix(rName, "tf-acc-test-prefix-"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEksNodeGroupExists(resourceName, &nodeGroup), - resource.TestCheckResourceAttr(resourceName, "node_group_name_prefix", rNamePrefix), + naming.TestCheckResourceAttrNameFromPrefix(resourceName, "node_group_name", "tf-acc-test-prefix-"), + resource.TestCheckResourceAttr(resourceName, "node_group_name_prefix", "tf-acc-test-prefix-"), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"node_group_name_prefix"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -1022,13 +1052,17 @@ resource "aws_vpc" "test" { enable_dns_support = true tags = { - Name = "tf-acc-test-eks-node-group" + Name = %[1]q "kubernetes.io/cluster/%[1]s" = "shared" } } resource "aws_internet_gateway" "test" { vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } } resource "aws_route_table" "test" { @@ -1038,6 +1072,10 @@ resource "aws_route_table" "test" { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.test.id } + + tags = { + Name = %[1]q + } } resource "aws_main_route_table_association" "test" { @@ -1062,6 +1100,10 @@ resource "aws_security_group" "test" { protocol = -1 to_port = 0 } + + tags = { + Name = %[1]q + } } resource "aws_subnet" "test" { @@ -1073,7 +1115,7 @@ resource "aws_subnet" "test" { vpc_id = aws_vpc.test.id tags = { - Name = "tf-acc-test-eks-node-group" + Name = %[1]q "kubernetes.io/cluster/%[1]s" = "shared" } } @@ -1122,7 +1164,7 @@ resource "aws_eks_cluster" "test" { } func testAccAWSEksNodeGroupConfigNodeGroupName(rName string) string { - return testAccAWSEksNodeGroupConfigBase(rName) + fmt.Sprintf(` + return composeConfig(testAccAWSEksNodeGroupConfigBase(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q @@ -1141,16 +1183,38 @@ resource "aws_eks_node_group" "test" { aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly, ] } -`, rName) +`, rName)) +} + +func testAccAWSEksNodeGroupConfigNodeGroupNameGenerated(rName string) string { + return composeConfig(testAccAWSEksNodeGroupConfigBase(rName), ` +resource "aws_eks_node_group" "test" { + cluster_name = aws_eks_cluster.test.name + node_role_arn = aws_iam_role.node.arn + subnet_ids = aws_subnet.test[*].id + + scaling_config { + desired_size = 1 + max_size = 1 + min_size = 1 + } + + depends_on = [ + aws_iam_role_policy_attachment.node-AmazonEKSWorkerNodePolicy, + aws_iam_role_policy_attachment.node-AmazonEKS_CNI_Policy, + aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly, + ] +} +`) } -func testAccAWSEksNodeGroupConfigNodeGroupNamePrefix(rName, rNamePrefix string) string { - return testAccAWSEksNodeGroupConfigBase(rName) + fmt.Sprintf(` +func testAccAWSEksNodeGroupConfigNodeGroupNamePrefix(rName, namePrefix string) string { + return composeConfig(testAccAWSEksNodeGroupConfigBase(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { - cluster_name = aws_eks_cluster.test.name - node_group_name_prefix = %[1]q - node_role_arn = aws_iam_role.node.arn - subnet_ids = aws_subnet.test[*].id + cluster_name = aws_eks_cluster.test.name + node_group_name_prefix = %[1]q + node_role_arn = aws_iam_role.node.arn + subnet_ids = aws_subnet.test[*].id scaling_config { desired_size = 1 @@ -1164,11 +1228,11 @@ resource "aws_eks_node_group" "test" { "aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly", ] } -`, rNamePrefix) +`, namePrefix)) } func testAccAWSEksNodeGroupConfigAmiType(rName, amiType string) string { - return testAccAWSEksNodeGroupConfigBase(rName) + fmt.Sprintf(` + return composeConfig(testAccAWSEksNodeGroupConfigBase(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { ami_type = %[2]q cluster_name = aws_eks_cluster.test.name @@ -1188,11 +1252,11 @@ resource "aws_eks_node_group" "test" { aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly, ] } -`, rName, amiType) +`, rName, amiType)) } func testAccAWSEksNodeGroupConfigCapacityType(rName, capacityType string) string { - return testAccAWSEksNodeGroupConfigBase(rName) + fmt.Sprintf(` + return composeConfig(testAccAWSEksNodeGroupConfigBase(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { capacity_type = %[2]q cluster_name = aws_eks_cluster.test.name @@ -1212,11 +1276,11 @@ resource "aws_eks_node_group" "test" { aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly, ] } -`, rName, capacityType) +`, rName, capacityType)) } func testAccAWSEksNodeGroupConfigDiskSize(rName string, diskSize int) string { - return testAccAWSEksNodeGroupConfigBase(rName) + fmt.Sprintf(` + return composeConfig(testAccAWSEksNodeGroupConfigBase(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name disk_size = %[2]d @@ -1236,11 +1300,11 @@ resource "aws_eks_node_group" "test" { aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly, ] } -`, rName, diskSize) +`, rName, diskSize)) } func testAccAWSEksNodeGroupConfigForceUpdateVersion(rName, version string) string { - return testAccAWSEksNodeGroupConfigBaseVersion(rName, version) + fmt.Sprintf(` + return composeConfig(testAccAWSEksNodeGroupConfigBaseVersion(rName, version), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name force_update_version = true @@ -1261,7 +1325,7 @@ resource "aws_eks_node_group" "test" { aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly, ] } -`, rName) +`, rName)) } func testAccAWSEksNodeGroupConfigInstanceTypesMultiple(rName string) string { @@ -1333,7 +1397,7 @@ resource "aws_eks_node_group" "test" { } func testAccAWSEksNodeGroupConfigLabels1(rName, labelKey1, labelValue1 string) string { - return testAccAWSEksNodeGroupConfigBase(rName) + fmt.Sprintf(` + return composeConfig(testAccAWSEksNodeGroupConfigBase(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q @@ -1356,11 +1420,11 @@ resource "aws_eks_node_group" "test" { aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly, ] } -`, rName, labelKey1, labelValue1) +`, rName, labelKey1, labelValue1)) } func testAccAWSEksNodeGroupConfigLabels2(rName, labelKey1, labelValue1, labelKey2, labelValue2 string) string { - return testAccAWSEksNodeGroupConfigBase(rName) + fmt.Sprintf(` + return composeConfig(testAccAWSEksNodeGroupConfigBase(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q @@ -1384,7 +1448,7 @@ resource "aws_eks_node_group" "test" { aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly, ] } -`, rName, labelKey1, labelValue1, labelKey2, labelValue2) +`, rName, labelKey1, labelValue1, labelKey2, labelValue2)) } func testAccAWSEksNodeGroupConfigLaunchTemplateId1(rName string) string { @@ -1664,7 +1728,7 @@ resource "aws_eks_node_group" "test" { } func testAccAWSEksNodeGroupConfigReleaseVersion(rName string, version string) string { - return testAccAWSEksNodeGroupConfigBaseVersion(rName, version) + fmt.Sprintf(` + return composeConfig(testAccAWSEksNodeGroupConfigBaseVersion(rName, version), fmt.Sprintf(` data "aws_ssm_parameter" "test" { name = "/aws/service/eks/optimized-ami/${aws_eks_cluster.test.version}/amazon-linux-2/recommended/release_version" } @@ -1689,11 +1753,11 @@ resource "aws_eks_node_group" "test" { aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly, ] } -`, rName) +`, rName)) } func testAccAWSEksNodeGroupConfigRemoteAccessEc2SshKey(rName string) string { - return testAccAWSEksNodeGroupConfigBase(rName) + fmt.Sprintf(` + return composeConfig(testAccAWSEksNodeGroupConfigBase(rName), fmt.Sprintf(` resource "aws_key_pair" "test" { key_name = %[1]q public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD3F6tyPEFEzV0LX3X8BsXdMsQz1x2cEikKDEY0aIj41qgxMCP/iteneqXSIFZBp5vizPvaoIR3Um9xK7PGoW8giupGn+EPuxIA4cDM4vzOqOkiMPhz5XK0whEjkVzTo4+S0puvDZuwIsdiW9mxhJc7tgBNL0cYlWSYVkz4G/fslNfRPW5mYAM49f4fhtxPb5ok4Q2Lg9dPKVHO/Bgeu5woMc7RY0p1ej6D4CKFE6lymSDJpW0YHX/wqE9+cfEauh7xZcG0q9t2ta6F6fmX0agvpFyZo8aFbXeUBr7osSCJNgvavWbM/06niWrOvYX2xwWdhXmXSrbX8ZbabVohBK41 example@example.com" @@ -1721,11 +1785,11 @@ resource "aws_eks_node_group" "test" { aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly, ] } -`, rName) +`, rName)) } func testAccAWSEksNodeGroupConfigRemoteAccessSourceSecurityGroupIds1(rName string) string { - return testAccAWSEksNodeGroupConfigBase(rName) + fmt.Sprintf(` + return composeConfig(testAccAWSEksNodeGroupConfigBase(rName), fmt.Sprintf(` resource "aws_key_pair" "test" { key_name = %[1]q public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD3F6tyPEFEzV0LX3X8BsXdMsQz1x2cEikKDEY0aIj41qgxMCP/iteneqXSIFZBp5vizPvaoIR3Um9xK7PGoW8giupGn+EPuxIA4cDM4vzOqOkiMPhz5XK0whEjkVzTo4+S0puvDZuwIsdiW9mxhJc7tgBNL0cYlWSYVkz4G/fslNfRPW5mYAM49f4fhtxPb5ok4Q2Lg9dPKVHO/Bgeu5woMc7RY0p1ej6D4CKFE6lymSDJpW0YHX/wqE9+cfEauh7xZcG0q9t2ta6F6fmX0agvpFyZo8aFbXeUBr7osSCJNgvavWbM/06niWrOvYX2xwWdhXmXSrbX8ZbabVohBK41 example@example.com" @@ -1754,11 +1818,11 @@ resource "aws_eks_node_group" "test" { aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly, ] } -`, rName) +`, rName)) } func testAccAWSEksNodeGroupConfigScalingConfigSizes(rName string, desiredSize, maxSize, minSize int) string { - return testAccAWSEksNodeGroupConfigBase(rName) + fmt.Sprintf(` + return composeConfig(testAccAWSEksNodeGroupConfigBase(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q @@ -1777,11 +1841,11 @@ resource "aws_eks_node_group" "test" { aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly, ] } -`, rName, desiredSize, maxSize, minSize) +`, rName, desiredSize, maxSize, minSize)) } func testAccAWSEksNodeGroupConfigTags1(rName, tagKey1, tagValue1 string) string { - return testAccAWSEksNodeGroupConfigBase(rName) + fmt.Sprintf(` + return composeConfig(testAccAWSEksNodeGroupConfigBase(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q @@ -1804,11 +1868,11 @@ resource "aws_eks_node_group" "test" { aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly, ] } -`, rName, tagKey1, tagValue1) +`, rName, tagKey1, tagValue1)) } func testAccAWSEksNodeGroupConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return testAccAWSEksNodeGroupConfigBase(rName) + fmt.Sprintf(` + return composeConfig(testAccAWSEksNodeGroupConfigBase(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q @@ -1832,11 +1896,11 @@ resource "aws_eks_node_group" "test" { aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly, ] } -`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +`, rName, tagKey1, tagValue1, tagKey2, tagValue2)) } func testAccAWSEksNodeGroupConfigVersion(rName, version string) string { - return testAccAWSEksNodeGroupConfigBaseVersion(rName, version) + fmt.Sprintf(` + return composeConfig(testAccAWSEksNodeGroupConfigBaseVersion(rName, version), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q @@ -1856,5 +1920,5 @@ resource "aws_eks_node_group" "test" { aws_iam_role_policy_attachment.node-AmazonEC2ContainerRegistryReadOnly, ] } -`, rName) +`, rName)) } diff --git a/website/docs/r/eks_node_group.html.markdown b/website/docs/r/eks_node_group.html.markdown index 23896cdf517..e021880b5c8 100644 --- a/website/docs/r/eks_node_group.html.markdown +++ b/website/docs/r/eks_node_group.html.markdown @@ -122,14 +122,14 @@ The following arguments are required: The following arguments are optional: -* `ami_type` - (Optional) Type of Amazon Machine Image (AMI) associated with the EKS Node Group. Defaults to `AL2_x86_64`. Valid values: `AL2_x86_64`, `AL2_x86_64_GPU`, `AL2_ARM_64`. Terraform will only perform drift detection if a configuration value is provided. +* `ami_type` - (Optional) Type of Amazon Machine Image (AMI) associated with the EKS Node Group. Defaults to `AL2_x86_64`. Valid values: `AL2_x86_64`, `AL2_x86_64_GPU`, `AL2_ARM_64`, `CUSTOM`. Terraform will only perform drift detection if a configuration value is provided. * `capacity_type` - (Optional) Type of capacity associated with the EKS Node Group. Valid values: `ON_DEMAND`, `SPOT`. Terraform will only perform drift detection if a configuration value is provided. * `disk_size` - (Optional) Disk size in GiB for worker nodes. Defaults to `20`. Terraform will only perform drift detection if a configuration value is provided. * `force_update_version` - (Optional) Force version update if existing pods are unable to be drained due to a pod disruption budget issue. * `instance_types` - (Optional) List of instance types associated with the EKS Node Group. Defaults to `["t3.medium"]`. Terraform will only perform drift detection if a configuration value is provided. * `labels` - (Optional) Key-value map of Kubernetes labels. Only labels that are applied with the EKS API are managed by this argument. Other Kubernetes labels applied to the EKS Node Group will not be managed. * `launch_template` - (Optional) Configuration block with Launch Template settings. Detailed below. -* `node_group_name` – (Optional) Name of the EKS Node Group. If omitted, Terraform will assign a random, unique name. +* `node_group_name` – (Optional) Name of the EKS Node Group. If omitted, Terraform will assign a random, unique name. Conflicts with `node_group_name_prefix`. * `node_group_name_prefix` – (Optional) Creates a unique name beginning with the specified prefix. Conflicts with `node_group_name`. * `release_version` – (Optional) AMI version of the EKS Node Group. Defaults to latest version for Kubernetes version. * `remote_access` - (Optional) Configuration block with remote access settings. Detailed below. From 8bfa9c85389bf13dd9368a438f06ac31f7ea5c31 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 12 May 2021 13:57:50 -0400 Subject: [PATCH 4/5] Add CHANGELOG entry. --- .changelog/13938.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/13938.txt diff --git a/.changelog/13938.txt b/.changelog/13938.txt new file mode 100644 index 00000000000..410820390f1 --- /dev/null +++ b/.changelog/13938.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_eks_node_group: Add `node_group_name_prefix` argument +``` \ No newline at end of file From dbb40cc76d8e78a13e60c5f084fcacde34ea29a2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 12 May 2021 15:05:36 -0400 Subject: [PATCH 5/5] Fix typo. --- aws/internal/service/eks/id.go | 25 +++++++++ aws/resource_aws_eks_node_group.go | 72 ++++++++++--------------- aws/resource_aws_eks_node_group_test.go | 7 +-- 3 files changed, 58 insertions(+), 46 deletions(-) create mode 100644 aws/internal/service/eks/id.go diff --git a/aws/internal/service/eks/id.go b/aws/internal/service/eks/id.go new file mode 100644 index 00000000000..67651b3c435 --- /dev/null +++ b/aws/internal/service/eks/id.go @@ -0,0 +1,25 @@ +package eks + +import ( + "fmt" + "strings" +) + +const nodeGroupResourceIDSeparator = ":" + +func NodeGroupCreateResourceID(clusterName, nodeGroupName string) string { + parts := []string{clusterName, nodeGroupName} + id := strings.Join(parts, nodeGroupResourceIDSeparator) + + return id +} + +func NodeGroupParseResourceID(id string) (string, string, error) { + parts := strings.Split(id, nodeGroupResourceIDSeparator) + + if len(parts) == 2 && parts[0] != "" && parts[1] != "" { + return parts[0], parts[1], nil + } + + return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected cluster-name%[2]snode-group-name", id, nodeGroupResourceIDSeparator) +} diff --git a/aws/resource_aws_eks_node_group.go b/aws/resource_aws_eks_node_group.go index 8c24ff73092..7f4f9b7c62f 100644 --- a/aws/resource_aws_eks_node_group.go +++ b/aws/resource_aws_eks_node_group.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" + tfeks "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks" ) func resourceAwsEksNodeGroup() *schema.Resource { @@ -288,13 +289,11 @@ func resourceAwsEksNodeGroupCreate(d *schema.ResourceData, meta interface{}) err _, err := conn.CreateNodegroup(input) - id := resourceAwsEksNodeGroupCreateId(clusterName, nodeGroupName) - if err != nil { - return fmt.Errorf("error creating EKS Node Group (%s): %s", id, err) + return fmt.Errorf("error creating EKS Node Group (%s/%s): %w", clusterName, nodeGroupName, err) } - d.SetId(id) + d.SetId(tfeks.NodeGroupCreateResourceID(clusterName, nodeGroupName)) stateConf := resource.StateChangeConf{ Pending: []string{eks.NodegroupStatusCreating}, @@ -304,7 +303,7 @@ func resourceAwsEksNodeGroupCreate(d *schema.ResourceData, meta interface{}) err } if _, err := stateConf.WaitForState(); err != nil { - return fmt.Errorf("error waiting for EKS Node Group (%s) creation: %s", d.Id(), err) + return fmt.Errorf("error waiting for EKS Node Group (%s) creation: %w", d.Id(), err) } return resourceAwsEksNodeGroupRead(d, meta) @@ -315,7 +314,8 @@ func resourceAwsEksNodeGroupRead(d *schema.ResourceData, meta interface{}) error defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig - clusterName, nodeGroupName, err := resourceAwsEksNodeGroupParseId(d.Id()) + clusterName, nodeGroupName, err := tfeks.NodeGroupParseResourceID(d.Id()) + if err != nil { return err } @@ -334,7 +334,7 @@ func resourceAwsEksNodeGroupRead(d *schema.ResourceData, meta interface{}) error } if err != nil { - return fmt.Errorf("error reading EKS Node Group (%s): %s", d.Id(), err) + return fmt.Errorf("error reading EKS Node Group (%s): %w", d.Id(), err) } nodeGroup := output.Nodegroup @@ -351,38 +351,38 @@ func resourceAwsEksNodeGroupRead(d *schema.ResourceData, meta interface{}) error d.Set("disk_size", nodeGroup.DiskSize) if err := d.Set("instance_types", aws.StringValueSlice(nodeGroup.InstanceTypes)); err != nil { - return fmt.Errorf("error setting instance_types: %s", err) + return fmt.Errorf("error setting instance_types: %w", err) } if err := d.Set("labels", aws.StringValueMap(nodeGroup.Labels)); err != nil { - return fmt.Errorf("error setting labels: %s", err) + return fmt.Errorf("error setting labels: %w", err) } if err := d.Set("launch_template", flattenEksLaunchTemplateSpecification(nodeGroup.LaunchTemplate)); err != nil { - return fmt.Errorf("error setting launch_template: %s", err) + return fmt.Errorf("error setting launch_template: %w", err) } d.Set("node_group_name", nodeGroup.NodegroupName) - d.Set("name_prefix", naming.NamePrefixFromName(aws.StringValue(nodeGroup.NodegroupName))) + d.Set("node_group_name_prefix", naming.NamePrefixFromName(aws.StringValue(nodeGroup.NodegroupName))) d.Set("node_role_arn", nodeGroup.NodeRole) d.Set("release_version", nodeGroup.ReleaseVersion) if err := d.Set("remote_access", flattenEksRemoteAccessConfig(nodeGroup.RemoteAccess)); err != nil { - return fmt.Errorf("error setting remote_access: %s", err) + return fmt.Errorf("error setting remote_access: %w", err) } if err := d.Set("resources", flattenEksNodeGroupResources(nodeGroup.Resources)); err != nil { - return fmt.Errorf("error setting resources: %s", err) + return fmt.Errorf("error setting resources: %w", err) } if err := d.Set("scaling_config", flattenEksNodeGroupScalingConfig(nodeGroup.ScalingConfig)); err != nil { - return fmt.Errorf("error setting scaling_config: %s", err) + return fmt.Errorf("error setting scaling_config: %w", err) } d.Set("status", nodeGroup.Status) if err := d.Set("subnet_ids", aws.StringValueSlice(nodeGroup.Subnets)); err != nil { - return fmt.Errorf("error setting subnets: %s", err) + return fmt.Errorf("error setting subnets: %w", err) } tags := keyvaluetags.EksKeyValueTags(nodeGroup.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) @@ -404,7 +404,8 @@ func resourceAwsEksNodeGroupRead(d *schema.ResourceData, meta interface{}) error func resourceAwsEksNodeGroupUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).eksconn - clusterName, nodeGroupName, err := resourceAwsEksNodeGroupParseId(d.Id()) + clusterName, nodeGroupName, err := tfeks.NodeGroupParseResourceID(d.Id()) + if err != nil { return err } @@ -426,7 +427,7 @@ func resourceAwsEksNodeGroupUpdate(d *schema.ResourceData, meta interface{}) err output, err := conn.UpdateNodegroupConfig(input) if err != nil { - return fmt.Errorf("error updating EKS Node Group (%s) config: %s", d.Id(), err) + return fmt.Errorf("error updating EKS Node Group (%s) config: %w", d.Id(), err) } if output == nil || output.Update == nil || output.Update.Id == nil { @@ -437,7 +438,7 @@ func resourceAwsEksNodeGroupUpdate(d *schema.ResourceData, meta interface{}) err err = waitForEksNodeGroupUpdate(conn, clusterName, nodeGroupName, updateID, d.Timeout(schema.TimeoutUpdate)) if err != nil { - return fmt.Errorf("error waiting for EKS Node Group (%s) config update (%s): %s", d.Id(), updateID, err) + return fmt.Errorf("error waiting for EKS Node Group (%s) config update (%s): %w", d.Id(), updateID, err) } } @@ -480,7 +481,7 @@ func resourceAwsEksNodeGroupUpdate(d *schema.ResourceData, meta interface{}) err output, err := conn.UpdateNodegroupVersion(input) if err != nil { - return fmt.Errorf("error updating EKS Node Group (%s) version: %s", d.Id(), err) + return fmt.Errorf("error updating EKS Node Group (%s) version: %w", d.Id(), err) } if output == nil || output.Update == nil || output.Update.Id == nil { @@ -491,14 +492,14 @@ func resourceAwsEksNodeGroupUpdate(d *schema.ResourceData, meta interface{}) err err = waitForEksNodeGroupUpdate(conn, clusterName, nodeGroupName, updateID, d.Timeout(schema.TimeoutUpdate)) if err != nil { - return fmt.Errorf("error waiting for EKS Node Group (%s) version update (%s): %s", d.Id(), updateID, err) + return fmt.Errorf("error waiting for EKS Node Group (%s) version update (%s): %w", d.Id(), updateID, err) } } if d.HasChange("tags_all") { o, n := d.GetChange("tags_all") if err := keyvaluetags.EksUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { - return fmt.Errorf("error updating tags: %s", err) + return fmt.Errorf("error updating tags: %w", err) } } @@ -508,7 +509,8 @@ func resourceAwsEksNodeGroupUpdate(d *schema.ResourceData, meta interface{}) err func resourceAwsEksNodeGroupDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).eksconn - clusterName, nodeGroupName, err := resourceAwsEksNodeGroupParseId(d.Id()) + clusterName, nodeGroupName, err := tfeks.NodeGroupParseResourceID(d.Id()) + if err != nil { return err } @@ -525,11 +527,11 @@ func resourceAwsEksNodeGroupDelete(d *schema.ResourceData, meta interface{}) err } if err != nil { - return fmt.Errorf("error deleting EKS Node Group (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting EKS Node Group (%s): %w", d.Id(), err) } if err := waitForEksNodeGroupDeletion(conn, clusterName, nodeGroupName, d.Timeout(schema.TimeoutDelete)); err != nil { - return fmt.Errorf("error waiting for EKS Node Group (%s) deletion: %s", d.Id(), err) + return fmt.Errorf("error waiting for EKS Node Group (%s) deletion: %w", d.Id(), err) } return nil @@ -724,7 +726,7 @@ func refreshEksNodeGroupStatus(conn *eks.EKS, clusterName string, nodeGroupName nodeGroup := output.Nodegroup if nodeGroup == nil { - return nodeGroup, "", fmt.Errorf("EKS Node Group (%s) missing", resourceAwsEksNodeGroupCreateId(clusterName, nodeGroupName)) + return nodeGroup, "", fmt.Errorf("EKS Node Group (%s) missing", tfeks.NodeGroupCreateResourceID(clusterName, nodeGroupName)) } status := aws.StringValue(nodeGroup.Status) @@ -733,7 +735,7 @@ func refreshEksNodeGroupStatus(conn *eks.EKS, clusterName string, nodeGroupName // unexpected state 'CREATE_FAILED', wanted target 'ACTIVE'. last error: %!s() if status == eks.NodegroupStatusCreateFailed || status == eks.NodegroupStatusDeleteFailed { if nodeGroup.Health == nil || len(nodeGroup.Health.Issues) == 0 || nodeGroup.Health.Issues[0] == nil { - return nodeGroup, status, fmt.Errorf("unable to find additional information about %s status, check EKS Node Group (%s) health", status, resourceAwsEksNodeGroupCreateId(clusterName, nodeGroupName)) + return nodeGroup, status, fmt.Errorf("unable to find additional information about %s status, check EKS Node Group (%s) health", status, tfeks.NodeGroupCreateResourceID(clusterName, nodeGroupName)) } issue := nodeGroup.Health.Issues[0] @@ -760,7 +762,7 @@ func refreshEksNodeGroupUpdateStatus(conn *eks.EKS, clusterName string, nodeGrou } if output == nil || output.Update == nil { - return nil, "", fmt.Errorf("EKS Node Group (%s) update (%s) missing", resourceAwsEksNodeGroupCreateId(clusterName, nodeGroupName), updateID) + return nil, "", fmt.Errorf("EKS Node Group (%s) update (%s) missing", tfeks.NodeGroupCreateResourceID(clusterName, nodeGroupName), updateID) } return output.Update, aws.StringValue(output.Update.Status), nil @@ -818,19 +820,3 @@ func waitForEksNodeGroupUpdate(conn *eks.EKS, clusterName, nodeGroupName string, return fmt.Errorf("EKS Node Group (%s) update (%s) status (%s) not successful: Errors:\n%s", clusterName, updateID, aws.StringValue(update.Status), strings.Join(detailedErrors, "\n")) } - -func resourceAwsEksNodeGroupParseId(id string) (string, string, error) { - // inverse of resourceAwsEksNodeGroupCreateId() - parts := strings.Split(id, ":") - - if len(parts) != 2 { - return "", "", fmt.Errorf("unexpected format of ID (%s), expected cluster-name:node-group-name", id) - } - - return parts[0], parts[1], nil -} - -func resourceAwsEksNodeGroupCreateId(clusterName, nodeGroupName string) string { - // inverse of resourceAwsEksNodeGroupParseId() - return fmt.Sprintf("%s:%s", clusterName, nodeGroupName) -} diff --git a/aws/resource_aws_eks_node_group_test.go b/aws/resource_aws_eks_node_group_test.go index 5b1e44cc97f..b381cba9598 100644 --- a/aws/resource_aws_eks_node_group_test.go +++ b/aws/resource_aws_eks_node_group_test.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" + tfeks "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks" ) func init() { @@ -54,7 +55,7 @@ func testSweepEksNodeGroups(region string) error { d.Set("cluster_name", clusterName) d.Set("node_group_name", nodeGroupName) - d.SetId(resourceAwsEksNodeGroupCreateId(clusterName, nodeGroupName)) + d.SetId(tfeks.NodeGroupCreateResourceID(clusterName, nodeGroupName)) sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } @@ -869,7 +870,7 @@ func testAccCheckAWSEksNodeGroupExists(resourceName string, nodeGroup *eks.Nodeg return fmt.Errorf("No EKS Node Group ID is set") } - clusterName, nodeGroupName, err := resourceAwsEksNodeGroupParseId(rs.Primary.ID) + clusterName, nodeGroupName, err := tfeks.NodeGroupParseResourceID(rs.Primary.ID) if err != nil { return err } @@ -913,7 +914,7 @@ func testAccCheckAWSEksNodeGroupDestroy(s *terraform.State) error { continue } - clusterName, nodeGroupName, err := resourceAwsEksNodeGroupParseId(rs.Primary.ID) + clusterName, nodeGroupName, err := tfeks.NodeGroupParseResourceID(rs.Primary.ID) if err != nil { return err }