diff --git a/.changelog/40698.txt b/.changelog/40698.txt new file mode 100644 index 00000000000..8f1405f17e5 --- /dev/null +++ b/.changelog/40698.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_eks_node_group: Add `node_repair_config` configuration block +``` \ No newline at end of file diff --git a/internal/service/eks/node_group.go b/internal/service/eks/node_group.go index acf4093b7cc..46a86f9d933 100644 --- a/internal/service/eks/node_group.go +++ b/internal/service/eks/node_group.go @@ -146,6 +146,21 @@ func resourceNodeGroup() *schema.Resource { ConflictsWith: []string{"node_group_name"}, ValidateFunc: validation.StringLenBetween(0, 63-id.UniqueIDSuffixLength), }, + "node_repair_config": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrEnabled: { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + }, + }, + }, "node_role_arn": { Type: schema.TypeString, Required: true, @@ -341,6 +356,10 @@ func resourceNodeGroupCreate(ctx context.Context, d *schema.ResourceData, meta i input.LaunchTemplate = expandLaunchTemplateSpecification(v) } + if v, ok := d.GetOk("node_repair_config"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.NodeRepairConfig = expandNodeRepairConfig(v.([]interface{})[0].(map[string]interface{})) + } + if v, ok := d.GetOk("release_version"); ok { input.ReleaseVersion = aws.String(v.(string)) } @@ -414,16 +433,23 @@ func resourceNodeGroupRead(ctx context.Context, d *schema.ResourceData, meta int } d.Set("node_group_name", nodeGroup.NodegroupName) d.Set("node_group_name_prefix", create.NamePrefixFromName(aws.ToString(nodeGroup.NodegroupName))) + if nodeGroup.NodeRepairConfig != nil { + if err := d.Set("node_repair_config", []interface{}{flattenNodeRepairConfig(nodeGroup.NodeRepairConfig)}); err != nil { + return sdkdiag.AppendErrorf(diags, "setting node_repair_config: %s", err) + } + } else { + d.Set("node_repair_config", nil) + } d.Set("node_role_arn", nodeGroup.NodeRole) d.Set("release_version", nodeGroup.ReleaseVersion) if err := d.Set("remote_access", flattenRemoteAccessConfig(nodeGroup.RemoteAccess)); err != nil { return sdkdiag.AppendErrorf(diags, "setting remote_access: %s", err) } - if err := d.Set(names.AttrResources, flattenNodeGroupResources(nodeGroup.Resources)); err != nil { + if err := d.Set(names.AttrResources, flattenNodegroupResources(nodeGroup.Resources)); err != nil { return sdkdiag.AppendErrorf(diags, "setting resources: %s", err) } if nodeGroup.ScalingConfig != nil { - if err := d.Set("scaling_config", []interface{}{flattenNodeGroupScalingConfig(nodeGroup.ScalingConfig)}); err != nil { + if err := d.Set("scaling_config", []interface{}{flattenNodegroupScalingConfig(nodeGroup.ScalingConfig)}); err != nil { return sdkdiag.AppendErrorf(diags, "setting scaling_config: %s", err) } } else { @@ -435,7 +461,7 @@ func resourceNodeGroupRead(ctx context.Context, d *schema.ResourceData, meta int return sdkdiag.AppendErrorf(diags, "setting taint: %s", err) } if nodeGroup.UpdateConfig != nil { - if err := d.Set("update_config", []interface{}{flattenNodeGroupUpdateConfig(nodeGroup.UpdateConfig)}); err != nil { + if err := d.Set("update_config", []interface{}{flattenNodegroupUpdateConfig(nodeGroup.UpdateConfig)}); err != nil { return sdkdiag.AppendErrorf(diags, "setting update_config: %s", err) } } else { @@ -508,7 +534,7 @@ func resourceNodeGroupUpdate(ctx context.Context, d *schema.ResourceData, meta i } } - if d.HasChanges("labels", "scaling_config", "taint", "update_config") { + if d.HasChanges("labels", "node_repair_config", "scaling_config", "taint", "update_config") { oldLabelsRaw, newLabelsRaw := d.GetChange("labels") oldTaintsRaw, newTaintsRaw := d.GetChange("taint") @@ -520,6 +546,12 @@ func resourceNodeGroupUpdate(ctx context.Context, d *schema.ResourceData, meta i Taints: expandUpdateTaintsPayload(oldTaintsRaw.(*schema.Set).List(), newTaintsRaw.(*schema.Set).List()), } + if d.HasChange("node_repair_config") { + if v, ok := d.GetOk("node_repair_config"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.NodeRepairConfig = expandNodeRepairConfig(v.([]interface{})[0].(map[string]interface{})) + } + } + if d.HasChange("scaling_config") { if v, ok := d.GetOk("scaling_config"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { input.ScalingConfig = expandNodegroupScalingConfig(v.([]interface{})[0].(map[string]interface{})) @@ -745,28 +777,28 @@ func issuesError(apiObjects []types.Issue) error { return errors.Join(errs...) } -func expandLaunchTemplateSpecification(l []interface{}) *types.LaunchTemplateSpecification { - if len(l) == 0 || l[0] == nil { +func expandLaunchTemplateSpecification(tfList []interface{}) *types.LaunchTemplateSpecification { + if len(tfList) == 0 || tfList[0] == nil { return nil } - m := l[0].(map[string]interface{}) + tfMap := tfList[0].(map[string]interface{}) - config := &types.LaunchTemplateSpecification{} + apiObject := &types.LaunchTemplateSpecification{} - if v, ok := m[names.AttrID].(string); ok && v != "" { - config.Id = aws.String(v) + if v, ok := tfMap[names.AttrID].(string); ok && v != "" { + apiObject.Id = aws.String(v) } - if v, ok := m[names.AttrName].(string); ok && v != "" { - config.Name = aws.String(v) + if v, ok := tfMap[names.AttrName].(string); ok && v != "" { + apiObject.Name = aws.String(v) } - if v, ok := m[names.AttrVersion].(string); ok && v != "" { - config.Version = aws.String(v) + if v, ok := tfMap[names.AttrVersion].(string); ok && v != "" { + apiObject.Version = aws.String(v) } - return config + return apiObject } func expandNodegroupScalingConfig(tfMap map[string]interface{}) *types.NodegroupScalingConfig { @@ -791,38 +823,37 @@ func expandNodegroupScalingConfig(tfMap map[string]interface{}) *types.Nodegroup return apiObject } -func expandTaints(l []interface{}) []types.Taint { - if len(l) == 0 { +func expandTaints(tfList []interface{}) []types.Taint { + if len(tfList) == 0 { return nil } - var taints []types.Taint - - for _, raw := range l { - t, ok := raw.(map[string]interface{}) + var apiObjects []types.Taint + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) if !ok { continue } - taint := types.Taint{} + apiObject := types.Taint{} - if k, ok := t[names.AttrKey].(string); ok { - taint.Key = aws.String(k) + if v, ok := tfMap["effect"].(string); ok { + apiObject.Effect = types.TaintEffect(v) } - if v, ok := t[names.AttrValue].(string); ok { - taint.Value = aws.String(v) + if v, ok := tfMap[names.AttrKey].(string); ok { + apiObject.Key = aws.String(v) } - if e, ok := t["effect"].(string); ok { - taint.Effect = types.TaintEffect(e) + if v, ok := tfMap[names.AttrValue].(string); ok { + apiObject.Value = aws.String(v) } - taints = append(taints, taint) + apiObjects = append(apiObjects, apiObject) } - return taints + return apiObjects } func expandUpdateTaintsPayload(oldTaintsRaw, newTaintsRaw []interface{}) *types.UpdateTaintsPayload { @@ -877,24 +908,24 @@ func expandUpdateTaintsPayload(oldTaintsRaw, newTaintsRaw []interface{}) *types. return updateTaintsPayload } -func expandRemoteAccessConfig(l []interface{}) *types.RemoteAccessConfig { - if len(l) == 0 || l[0] == nil { +func expandRemoteAccessConfig(tfList []interface{}) *types.RemoteAccessConfig { + if len(tfList) == 0 || tfList[0] == nil { return nil } - m := l[0].(map[string]interface{}) + tfMap := tfList[0].(map[string]interface{}) - config := &types.RemoteAccessConfig{} + apiObject := &types.RemoteAccessConfig{} - if v, ok := m["ec2_ssh_key"].(string); ok && v != "" { - config.Ec2SshKey = aws.String(v) + if v, ok := tfMap["ec2_ssh_key"].(string); ok && v != "" { + apiObject.Ec2SshKey = aws.String(v) } - if v, ok := m["source_security_group_ids"].(*schema.Set); ok && v.Len() > 0 { - config.SourceSecurityGroups = flex.ExpandStringValueSet(v) + if v, ok := tfMap["source_security_group_ids"].(*schema.Set); ok && v.Len() > 0 { + apiObject.SourceSecurityGroups = flex.ExpandStringValueSet(v) } - return config + return apiObject } func expandNodegroupUpdateConfig(tfMap map[string]interface{}) *types.NodegroupUpdateConfig { @@ -915,6 +946,20 @@ func expandNodegroupUpdateConfig(tfMap map[string]interface{}) *types.NodegroupU return apiObject } +func expandNodeRepairConfig(tfMap map[string]interface{}) *types.NodeRepairConfig { + if tfMap == nil { + return nil + } + + apiObject := &types.NodeRepairConfig{} + + if v, ok := tfMap[names.AttrEnabled].(bool); ok { + apiObject.Enabled = aws.Bool(v) + } + + return apiObject +} + func expandUpdateLabelsPayload(ctx context.Context, oldLabelsMap, newLabelsMap interface{}) *types.UpdateLabelsPayload { // EKS Labels operate similarly to keyvaluetags oldLabels := tftags.New(ctx, oldLabelsMap) @@ -940,60 +985,60 @@ func expandUpdateLabelsPayload(ctx context.Context, oldLabelsMap, newLabelsMap i return updateLabelsPayload } -func flattenAutoScalingGroups(autoScalingGroups []types.AutoScalingGroup) []map[string]interface{} { - if len(autoScalingGroups) == 0 { - return []map[string]interface{}{} +func flattenAutoScalingGroups(apiObjects []types.AutoScalingGroup) []interface{} { + if len(apiObjects) == 0 { + return []interface{}{} } - l := make([]map[string]interface{}, 0, len(autoScalingGroups)) + tfList := make([]interface{}, 0, len(apiObjects)) - for _, autoScalingGroup := range autoScalingGroups { - m := map[string]interface{}{ - names.AttrName: aws.ToString(autoScalingGroup.Name), + for _, apiObject := range apiObjects { + tfMap := map[string]interface{}{ + names.AttrName: aws.ToString(apiObject.Name), } - l = append(l, m) + tfList = append(tfList, tfMap) } - return l + return tfList } -func flattenLaunchTemplateSpecification(config *types.LaunchTemplateSpecification) []map[string]interface{} { - if config == nil { +func flattenLaunchTemplateSpecification(apiObject *types.LaunchTemplateSpecification) []interface{} { + if apiObject == nil { return nil } - m := map[string]interface{}{} + tfMap := map[string]interface{}{} - if v := config.Id; v != nil { - m[names.AttrID] = aws.ToString(v) + if v := apiObject.Id; v != nil { + tfMap[names.AttrID] = aws.ToString(v) } - if v := config.Name; v != nil { - m[names.AttrName] = aws.ToString(v) + if v := apiObject.Name; v != nil { + tfMap[names.AttrName] = aws.ToString(v) } - if v := config.Version; v != nil { - m[names.AttrVersion] = aws.ToString(v) + if v := apiObject.Version; v != nil { + tfMap[names.AttrVersion] = aws.ToString(v) } - return []map[string]interface{}{m} + return []interface{}{tfMap} } -func flattenNodeGroupResources(resources *types.NodegroupResources) []map[string]interface{} { - if resources == nil { - return []map[string]interface{}{} +func flattenNodegroupResources(apiObject *types.NodegroupResources) []interface{} { + if apiObject == nil { + return []interface{}{} } - m := map[string]interface{}{ - "autoscaling_groups": flattenAutoScalingGroups(resources.AutoScalingGroups), - "remote_access_security_group_id": aws.ToString(resources.RemoteAccessSecurityGroup), + tfMap := map[string]interface{}{ + "autoscaling_groups": flattenAutoScalingGroups(apiObject.AutoScalingGroups), + "remote_access_security_group_id": aws.ToString(apiObject.RemoteAccessSecurityGroup), } - return []map[string]interface{}{m} + return []interface{}{tfMap} } -func flattenNodeGroupScalingConfig(apiObject *types.NodegroupScalingConfig) map[string]interface{} { +func flattenNodegroupScalingConfig(apiObject *types.NodegroupScalingConfig) map[string]interface{} { if apiObject == nil { return nil } @@ -1015,7 +1060,21 @@ func flattenNodeGroupScalingConfig(apiObject *types.NodegroupScalingConfig) map[ return tfMap } -func flattenNodeGroupUpdateConfig(apiObject *types.NodegroupUpdateConfig) map[string]interface{} { +func flattenNodeRepairConfig(apiObject *types.NodeRepairConfig) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := make(map[string]interface{}) + + if v := apiObject.Enabled; v != nil { + tfMap[names.AttrEnabled] = aws.ToBool(v) + } + + return tfMap +} + +func flattenNodegroupUpdateConfig(apiObject *types.NodegroupUpdateConfig) map[string]interface{} { if apiObject == nil { return nil } @@ -1033,33 +1092,35 @@ func flattenNodeGroupUpdateConfig(apiObject *types.NodegroupUpdateConfig) map[st return tfMap } -func flattenRemoteAccessConfig(config *types.RemoteAccessConfig) []map[string]interface{} { - if config == nil { - return []map[string]interface{}{} +func flattenRemoteAccessConfig(apiObject *types.RemoteAccessConfig) []interface{} { + if apiObject == nil { + return []interface{}{} } - m := map[string]interface{}{ - "ec2_ssh_key": aws.ToString(config.Ec2SshKey), - "source_security_group_ids": config.SourceSecurityGroups, + tfMap := map[string]interface{}{ + "ec2_ssh_key": aws.ToString(apiObject.Ec2SshKey), + "source_security_group_ids": apiObject.SourceSecurityGroups, } - return []map[string]interface{}{m} + return []interface{}{tfMap} } -func flattenTaints(taints []types.Taint) []interface{} { - if len(taints) == 0 { +func flattenTaints(apiObjects []types.Taint) []interface{} { + if len(apiObjects) == 0 { return nil } - var results []interface{} + var tfList []interface{} - for _, taint := range taints { - t := make(map[string]interface{}) - t[names.AttrKey] = aws.ToString(taint.Key) - t[names.AttrValue] = aws.ToString(taint.Value) - t["effect"] = taint.Effect + for _, apiObject := range apiObjects { + tfMap := make(map[string]interface{}) + + tfMap["effect"] = apiObject.Effect + tfMap[names.AttrKey] = aws.ToString(apiObject.Key) + tfMap[names.AttrValue] = aws.ToString(apiObject.Value) - results = append(results, t) + tfList = append(tfList, tfMap) } - return results + + return tfList } diff --git a/internal/service/eks/node_group_data_source.go b/internal/service/eks/node_group_data_source.go index dd98bd86695..d240a572a63 100644 --- a/internal/service/eks/node_group_data_source.go +++ b/internal/service/eks/node_group_data_source.go @@ -216,11 +216,11 @@ func dataSourceNodeGroupRead(ctx context.Context, d *schema.ResourceData, meta i if err := d.Set("remote_access", flattenRemoteAccessConfig(nodeGroup.RemoteAccess)); err != nil { return sdkdiag.AppendErrorf(diags, "setting remote_access: %s", err) } - if err := d.Set(names.AttrResources, flattenNodeGroupResources(nodeGroup.Resources)); err != nil { + if err := d.Set(names.AttrResources, flattenNodegroupResources(nodeGroup.Resources)); err != nil { return sdkdiag.AppendErrorf(diags, "setting resources: %s", err) } if nodeGroup.ScalingConfig != nil { - if err := d.Set("scaling_config", []interface{}{flattenNodeGroupScalingConfig(nodeGroup.ScalingConfig)}); err != nil { + if err := d.Set("scaling_config", []interface{}{flattenNodegroupScalingConfig(nodeGroup.ScalingConfig)}); err != nil { return sdkdiag.AppendErrorf(diags, "setting scaling_config: %s", err) } } else { diff --git a/internal/service/eks/node_group_data_source_test.go b/internal/service/eks/node_group_data_source_test.go index 994617458df..b969c134817 100644 --- a/internal/service/eks/node_group_data_source_test.go +++ b/internal/service/eks/node_group_data_source_test.go @@ -25,7 +25,7 @@ func TestAccEKSNodeGroupDataSource_basic(t *testing.T) { ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, Steps: []resource.TestStep{ { - Config: testAccNodeGroupConfig_dataSourceName(rName), + Config: testAccNodeGroupConfig_name(rName), Check: resource.ComposeTestCheckFunc(), }, { @@ -57,7 +57,7 @@ func TestAccEKSNodeGroupDataSource_basic(t *testing.T) { } func testAccNodeGroupDataSourceConfig_basic(rName string) string { - return acctest.ConfigCompose(testAccNodeGroupConfig_dataSourceName(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_name(rName), fmt.Sprintf(` data "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q diff --git a/internal/service/eks/node_group_test.go b/internal/service/eks/node_group_test.go index cda03d5e304..74cb82e2580 100644 --- a/internal/service/eks/node_group_test.go +++ b/internal/service/eks/node_group_test.go @@ -40,10 +40,10 @@ func TestAccEKSNodeGroup_basic(t *testing.T) { CheckDestroy: testAccCheckNodeGroupDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccNodeGroupConfig_dataSourceName(rName), - Check: resource.ComposeTestCheckFunc( + Config: testAccNodeGroupConfig_name(rName), + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckNodeGroupExists(ctx, resourceName, &nodeGroup), - resource.TestCheckResourceAttr(resourceName, "ami_type", string(types.AMITypesAl2X8664)), + resource.TestCheckResourceAttr(resourceName, "ami_type", string(types.AMITypesAl2023X8664Standard)), acctest.MatchResourceAttrRegionalARN(ctx, resourceName, names.AttrARN, "eks", regexache.MustCompile(fmt.Sprintf("nodegroup/%[1]s/%[1]s/.+", rName))), resource.TestCheckResourceAttrPair(resourceName, names.AttrClusterName, eksClusterResourceName, names.AttrName), resource.TestCheckResourceAttr(resourceName, "capacity_type", string(types.CapacityTypesOnDemand)), @@ -149,7 +149,7 @@ func TestAccEKSNodeGroup_disappears(t *testing.T) { CheckDestroy: testAccCheckNodeGroupDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccNodeGroupConfig_dataSourceName(rName), + Config: testAccNodeGroupConfig_name(rName), Check: resource.ComposeTestCheckFunc( testAccCheckNodeGroupExists(ctx, resourceName, &nodeGroup), acctest.CheckResourceDisappears(ctx, acctest.Provider, tfeks.ResourceNodeGroup(), resourceName), @@ -162,7 +162,7 @@ func TestAccEKSNodeGroup_disappears(t *testing.T) { func TestAccEKSNodeGroup_amiType(t *testing.T) { ctx := acctest.Context(t) - var nodeGroup1, nodeGroup2 types.Nodegroup + var nodeGroup1 types.Nodegroup rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_eks_node_group.test" @@ -184,13 +184,6 @@ func TestAccEKSNodeGroup_amiType(t *testing.T) { ImportState: true, ImportStateVerify: true, }, - { - Config: testAccNodeGroupConfig_amiType(rName, string(types.AMITypesAl2Arm64)), - Check: resource.ComposeTestCheckFunc( - testAccCheckNodeGroupExists(ctx, resourceName, &nodeGroup2), - resource.TestCheckResourceAttr(resourceName, "ami_type", string(types.AMITypesAl2Arm64)), - ), - }, }, }) } @@ -513,6 +506,35 @@ func TestAccEKSNodeGroup_LaunchTemplate_version(t *testing.T) { }) } +func TestAccEKSNodeGroup_nodeRepairConfig(t *testing.T) { + ctx := acctest.Context(t) + var nodeGroup1 types.Nodegroup + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_eks_node_group.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: testAccCheckNodeGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccNodeGroupConfig_nodeRepairConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckNodeGroupExists(ctx, resourceName, &nodeGroup1), + resource.TestCheckResourceAttr(resourceName, "node_repair_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "node_repair_config.0.enabled", acctest.CtTrue), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccEKSNodeGroup_releaseVersion(t *testing.T) { ctx := acctest.Context(t) var nodeGroup1, nodeGroup2 types.Nodegroup @@ -1066,17 +1088,8 @@ func testAccCheckNodeGroupRecreated(i, j *types.Nodegroup) resource.TestCheckFun } } -func testAccNodeGroupBaseIAMAndVPCConfig(rName string) string { - return fmt.Sprintf(` -data "aws_availability_zones" "available" { - state = "available" - - filter { - name = "opt-in-status" - values = ["opt-in-not-required"] - } -} - +func testAccNodeGroupConfig_iamAndVPCBase(rName string) string { + return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` data "aws_partition" "current" {} resource "aws_iam_role" "cluster" { @@ -1205,12 +1218,12 @@ resource "aws_subnet" "test" { "kubernetes.io/cluster/%[1]s" = "shared" } } -`, rName) +`, rName)) } -func testAccNodeGroupBaseConfig(rName string) string { +func testAccNodeGroupConfig_base(rName string) string { return acctest.ConfigCompose( - testAccNodeGroupBaseIAMAndVPCConfig(rName), + testAccNodeGroupConfig_iamAndVPCBase(rName), fmt.Sprintf(` resource "aws_eks_cluster" "test" { name = %[1]q @@ -1228,9 +1241,9 @@ resource "aws_eks_cluster" "test" { `, rName)) } -func testAccNodeGroupBaseVersionConfig(rName string, version string) string { +func testAccNodeGroupConfig_versionBase(rName string, version string) string { return acctest.ConfigCompose( - testAccNodeGroupBaseIAMAndVPCConfig(rName), + testAccNodeGroupConfig_iamAndVPCBase(rName), fmt.Sprintf(` resource "aws_eks_cluster" "test" { name = %[1]q @@ -1249,8 +1262,8 @@ resource "aws_eks_cluster" "test" { `, rName, version)) } -func testAccNodeGroupConfig_dataSourceName(rName string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), fmt.Sprintf(` +func testAccNodeGroupConfig_name(rName string) string { + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q @@ -1273,7 +1286,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_nameGenerated(rName string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), ` + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), ` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_role_arn = aws_iam_role.node.arn @@ -1295,7 +1308,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_namePrefix(rName, namePrefix string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name_prefix = %[1]q @@ -1318,7 +1331,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_amiType(rName, amiType string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { ami_type = %[2]q cluster_name = aws_eks_cluster.test.name @@ -1342,7 +1355,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_capacityType(rName, capacityType string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { capacity_type = %[2]q cluster_name = aws_eks_cluster.test.name @@ -1366,7 +1379,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_diskSize(rName string, diskSize int) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name disk_size = %[2]d @@ -1390,7 +1403,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_forceUpdateVersion(rName, version string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseVersionConfig(rName, version), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_versionBase(rName, version), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name force_update_version = true @@ -1416,7 +1429,7 @@ resource "aws_eks_node_group" "test" { func testAccNodeGroupConfig_instanceTypesMultiple(rName, instanceTypes string) string { return acctest.ConfigCompose( - testAccNodeGroupBaseConfig(rName), + testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name @@ -1444,7 +1457,7 @@ resource "aws_eks_node_group" "test" { func testAccNodeGroupConfig_instanceTypesSingle(rName string) string { return acctest.ConfigCompose( - testAccNodeGroupBaseConfig(rName), + testAccNodeGroupConfig_base(rName), fmt.Sprintf(` data "aws_ec2_instance_type_offering" "available" { filter { @@ -1478,7 +1491,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_labels1(rName, labelKey1, labelValue1 string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q @@ -1505,7 +1518,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_labels2(rName, labelKey1, labelValue1, labelKey2, labelValue2 string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q @@ -1534,7 +1547,7 @@ resource "aws_eks_node_group" "test" { func testAccNodeGroupConfig_launchTemplateId1(rName string) string { return acctest.ConfigCompose( - testAccNodeGroupBaseConfig(rName), + testAccNodeGroupConfig_base(rName), fmt.Sprintf(` data "aws_ssm_parameter" "test" { name = "/aws/service/eks/optimized-ami/${aws_eks_cluster.test.version}/amazon-linux-2/recommended/image_id" @@ -1582,7 +1595,7 @@ resource "aws_eks_node_group" "test" { func testAccNodeGroupConfig_launchTemplateId2(rName string) string { return acctest.ConfigCompose( - testAccNodeGroupBaseConfig(rName), + testAccNodeGroupConfig_base(rName), fmt.Sprintf(` data "aws_ssm_parameter" "test" { name = "/aws/service/eks/optimized-ami/${aws_eks_cluster.test.version}/amazon-linux-2/recommended/image_id" @@ -1630,7 +1643,7 @@ resource "aws_eks_node_group" "test" { func testAccNodeGroupConfig_launchTemplateName1(rName string) string { return acctest.ConfigCompose( - testAccNodeGroupBaseConfig(rName), + testAccNodeGroupConfig_base(rName), fmt.Sprintf(` data "aws_ssm_parameter" "test" { name = "/aws/service/eks/optimized-ami/${aws_eks_cluster.test.version}/amazon-linux-2/recommended/image_id" @@ -1678,7 +1691,7 @@ resource "aws_eks_node_group" "test" { func testAccNodeGroupConfig_launchTemplateName2(rName string) string { return acctest.ConfigCompose( - testAccNodeGroupBaseConfig(rName), + testAccNodeGroupConfig_base(rName), fmt.Sprintf(` data "aws_ssm_parameter" "test" { name = "/aws/service/eks/optimized-ami/${aws_eks_cluster.test.version}/amazon-linux-2/recommended/image_id" @@ -1726,7 +1739,7 @@ resource "aws_eks_node_group" "test" { func testAccNodeGroupConfig_launchTemplateVersion1(rName string) string { return acctest.ConfigCompose( - testAccNodeGroupBaseConfig(rName), + testAccNodeGroupConfig_base(rName), fmt.Sprintf(` data "aws_ssm_parameter" "test" { name = "/aws/service/eks/optimized-ami/${aws_eks_cluster.test.version}/amazon-linux-2/recommended/image_id" @@ -1768,7 +1781,7 @@ resource "aws_eks_node_group" "test" { func testAccNodeGroupConfig_launchTemplateVersion2(rName string) string { return acctest.ConfigCompose( - testAccNodeGroupBaseConfig(rName), + testAccNodeGroupConfig_base(rName), fmt.Sprintf(` data "aws_ssm_parameter" "test" { name = "/aws/service/eks/optimized-ami/${aws_eks_cluster.test.version}/amazon-linux-2/recommended/image_id" @@ -1809,7 +1822,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_releaseVersion(rName string, version string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseVersionConfig(rName, version), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_versionBase(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" } @@ -1838,7 +1851,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_remoteAccessEC2SSHKey(rName, publicKey string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_key_pair" "test" { key_name = %[1]q public_key = %[2]q @@ -1870,7 +1883,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_remoteAccessSourceSecurityIds1(rName, publicKey string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_key_pair" "test" { key_name = %[1]q public_key = %[2]q @@ -1903,7 +1916,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_scalingSizes(rName string, desiredSize, maxSize, minSize int) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q @@ -1926,7 +1939,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_tags1(rName, tagKey1, tagValue1 string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q @@ -1953,7 +1966,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q @@ -1981,7 +1994,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_taints1(rName, taintKey1, taintValue1, taintEffect1 string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q @@ -2010,7 +2023,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_taints2(rName, taintKey1, taintValue1, taintEffect1, taintKey2, taintValue2, taintEffect2 string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q @@ -2044,8 +2057,35 @@ resource "aws_eks_node_group" "test" { `, rName, taintKey1, taintValue1, taintEffect1, taintKey2, taintValue2, taintEffect2)) } +func testAccNodeGroupConfig_nodeRepairConfig(rName string) string { + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` +resource "aws_eks_node_group" "test" { + cluster_name = aws_eks_cluster.test.name + node_group_name = %[1]q + node_role_arn = aws_iam_role.node.arn + subnet_ids = aws_subnet.test[*].id + + scaling_config { + desired_size = 1 + max_size = 3 + min_size = 1 + } + + node_repair_config { + enabled = true + } + + 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, + ] +} +`, rName)) +} + func testAccNodeGroupConfig_update1(rName string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q @@ -2072,7 +2112,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_update2(rName string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q @@ -2099,7 +2139,7 @@ resource "aws_eks_node_group" "test" { } func testAccNodeGroupConfig_version(rName, version string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseVersionConfig(rName, version), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_versionBase(rName, version), fmt.Sprintf(` resource "aws_eks_node_group" "test" { cluster_name = aws_eks_cluster.test.name node_group_name = %[1]q diff --git a/internal/service/eks/node_groups_data_source_test.go b/internal/service/eks/node_groups_data_source_test.go index 11a11466b00..c42d3d82da1 100644 --- a/internal/service/eks/node_groups_data_source_test.go +++ b/internal/service/eks/node_groups_data_source_test.go @@ -50,7 +50,7 @@ data "aws_eks_node_groups" "test" { } func testAccNodeGroupsDataSourceConfig_namesBasic(rName string) string { - return acctest.ConfigCompose(testAccNodeGroupBaseConfig(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccNodeGroupConfig_base(rName), fmt.Sprintf(` resource "aws_eks_node_group" "test_a" { cluster_name = aws_eks_cluster.test.name node_group_name = "%[1]s-test-a" diff --git a/website/docs/r/eks_node_group.html.markdown b/website/docs/r/eks_node_group.html.markdown index bcbbd5b62c9..49c8f712cc3 100644 --- a/website/docs/r/eks_node_group.html.markdown +++ b/website/docs/r/eks_node_group.html.markdown @@ -150,6 +150,7 @@ The following arguments are optional: * `launch_template` - (Optional) Configuration block with Launch Template settings. See [`launch_template`](#launch_template-configuration-block) below for details. Conflicts with `remote_access`. * `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`. The node group name can't be longer than 63 characters. It must start with a letter or digit, but can also include hyphens and underscores for the remaining characters. * `node_group_name_prefix` – (Optional) Creates a unique name beginning with the specified prefix. Conflicts with `node_group_name`. +* `node_repair_config` - (Optional) The node auto repair configuration for the node group. See [`node_repair_config`](#node_repair_config-configuration-block) below for details. * `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. See [`remote_access`](#remote_access-configuration-block) below for details. Conflicts with `launch_template`. * `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. @@ -165,6 +166,10 @@ The following arguments are optional: * `name` - (Optional) Name of the EC2 Launch Template. Conflicts with `id`. * `version` - (Required) EC2 Launch Template version number. While the API accepts values like `$Default` and `$Latest`, the API will convert the value to the associated version number (e.g., `1`) on read and Terraform will show a difference on next plan. Using the `default_version` or `latest_version` attribute of the `aws_launch_template` resource or data source is recommended for this argument. +### node_repair_config Configuration Block + +* `enabled` - (Required) Specifies whether to enable node auto repair for the node group. Node auto repair is disabled by default. + ### remote_access Configuration Block * `ec2_ssh_key` - (Optional) EC2 Key Pair name that provides access for remote communication with the worker nodes in the EKS Node Group. If you specify this configuration, but do not specify `source_security_group_ids` when you create an EKS Node Group, either port 3389 for Windows, or port 22 for all other operating systems is opened on the worker nodes to the Internet (0.0.0.0/0). For Windows nodes, this will allow you to use RDP, for all others this allows you to SSH into the worker nodes.