diff --git a/.changelog/29555.txt b/.changelog/29555.txt new file mode 100644 index 000000000000..6675db4b3009 --- /dev/null +++ b/.changelog/29555.txt @@ -0,0 +1,2 @@ +```release-note:note +resource/aws_eks_addon: The `resolve_conflicts` argument has been deprecated. Use the `resolve_conflicts_on_create` and/or `resolve_conflicts_on_update` arguments instead diff --git a/internal/provider/tags_interceptor.go b/internal/provider/tags_interceptor.go index 83de6c05cc3c..896d77e23f02 100644 --- a/internal/provider/tags_interceptor.go +++ b/internal/provider/tags_interceptor.go @@ -4,14 +4,13 @@ import ( "context" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" - "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/types" - "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -26,6 +25,19 @@ func tagsUpdateFunc(ctx context.Context, d schemaResourceData, sp conns.ServiceP return ctx, diags } + var identifier string + if identifierAttribute := spt.IdentifierAttribute; identifierAttribute == "id" { + identifier = d.Id() + } else { + identifier = d.Get(identifierAttribute).(string) + } + + // Some old resources may not have the required attribute set after Read: + // https://github.com/hashicorp/terraform-provider-aws/issues/31180 + if identifier == "" { + return ctx, diags + } + configTags := make(map[string]string) if config := d.GetRawConfig(); !config.IsNull() && config.IsKnown() { c := config.GetAttr(names.AttrTags) @@ -54,12 +66,6 @@ func tagsUpdateFunc(ctx context.Context, d schemaResourceData, sp conns.ServiceP toAdd := configAll.Difference(tagsAll) toRemove := tagsAll.Difference(configAll) - var identifier string - if identifierAttribute := spt.IdentifierAttribute; identifierAttribute == "id" { - identifier = d.Id() - } else { - identifier = d.Get(identifierAttribute).(string) - } // If the service package has a generic resource update tags methods, call it. var err error @@ -73,13 +79,8 @@ func tagsUpdateFunc(ctx context.Context, d schemaResourceData, sp conns.ServiceP err = v.UpdateTags(ctx, meta, identifier, spt.ResourceType, toRemove, toAdd) } - if verify.ErrorISOUnsupported(meta.(*conns.AWSClient).Partition, err) { - // ISO partitions may not support tagging, giving error - tflog.Warn(ctx, "failed updating tags for resource", map[string]interface{}{ - spt.IdentifierAttribute: identifier, - "error": err.Error(), - }) - + // ISO partitions may not support tagging, giving error. + if errs.IsUnsupportedOperationInPartitionError(meta.(*conns.AWSClient).Partition, err) { return ctx, diags } @@ -107,35 +108,36 @@ func tagsReadFunc(ctx context.Context, d schemaResourceData, sp conns.ServicePac identifier = d.Get(identifierAttribute).(string) } - var err error - if v, ok := sp.(interface { - ListTags(context.Context, any, string) error - }); ok { - err = v.ListTags(ctx, meta, identifier) // Sets tags in Context - } else if v, ok := sp.(interface { - ListTags(context.Context, any, string, string) error - }); ok && spt.ResourceType != "" { - err = v.ListTags(ctx, meta, identifier, spt.ResourceType) // Sets tags in Context - } + // Some old resources may not have the required attribute set after Read: + // https://github.com/hashicorp/terraform-provider-aws/issues/31180 + if identifier != "" { + var err error - if verify.ErrorISOUnsupported(meta.(*conns.AWSClient).Partition, err) { - // ISO partitions may not support tagging, giving error - tflog.Warn(ctx, "failed listing tags for resource", map[string]interface{}{ - spt.IdentifierAttribute: d.Id(), - "error": err.Error(), - }) - return ctx, diags - } + if v, ok := sp.(interface { + ListTags(context.Context, any, string) error + }); ok { + err = v.ListTags(ctx, meta, identifier) // Sets tags in Context + } else if v, ok := sp.(interface { + ListTags(context.Context, any, string, string) error + }); ok && spt.ResourceType != "" { + err = v.ListTags(ctx, meta, identifier, spt.ResourceType) // Sets tags in Context + } - if inContext.ServicePackageName == names.DynamoDB && err != nil { - // When a DynamoDB Table is `ARCHIVED`, ListTags returns `ResourceNotFoundException`. - if tfresource.NotFound(err) || tfawserr.ErrMessageContains(err, "UnknownOperationException", "Tagging is not currently supported in DynamoDB Local.") { - err = nil + // ISO partitions may not support tagging, giving error. + if errs.IsUnsupportedOperationInPartitionError(meta.(*conns.AWSClient).Partition, err) { + return ctx, diags } - } - if err != nil { - return ctx, sdkdiag.AppendErrorf(diags, "listing tags for %s %s (%s): %s", serviceName, resourceName, identifier, err) + if inContext.ServicePackageName == names.DynamoDB && err != nil { + // When a DynamoDB Table is `ARCHIVED`, ListTags returns `ResourceNotFoundException`. + if tfresource.NotFound(err) || tfawserr.ErrMessageContains(err, "UnknownOperationException", "Tagging is not currently supported in DynamoDB Local.") { + err = nil + } + } + + if err != nil { + return ctx, sdkdiag.AppendErrorf(diags, "listing tags for %s %s (%s): %s", serviceName, resourceName, identifier, err) + } } // Remove any provider configured ignore_tags and system tags from those returned from the service API. diff --git a/internal/service/ec2/vpc_subnet_test.go b/internal/service/ec2/vpc_subnet_test.go index 596d0e2100d0..f44723645b3a 100644 --- a/internal/service/ec2/vpc_subnet_test.go +++ b/internal/service/ec2/vpc_subnet_test.go @@ -375,28 +375,6 @@ func TestAccVPCSubnet_DefaultTagsProviderAndResource_overlappingTag(t *testing.T }) } -func TestAccVPCSubnet_DefaultTagsProviderAndResource_duplicateTag(t *testing.T) { - ctx := acctest.Context(t) - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: acctest.ConfigCompose( - acctest.ConfigDefaultTags_Tags1("overlapkey", "overlapvalue"), - testAccVPCSubnetConfig_tags1(rName, "overlapkey", "overlapvalue"), - ), - PlanOnly: true, - ExpectError: regexp.MustCompile(`"tags" are identical to those in the "default_tags" configuration block`), - }, - }, - }) -} - func TestAccVPCSubnet_defaultAndIgnoreTags(t *testing.T) { ctx := acctest.Context(t) var subnet ec2.Subnet diff --git a/internal/service/eks/addon.go b/internal/service/eks/addon.go index 98d3a0aa77d3..6679ec4c59c3 100644 --- a/internal/service/eks/addon.go +++ b/internal/service/eks/addon.go @@ -2,7 +2,6 @@ package eks import ( "context" - "fmt" "log" "regexp" "time" @@ -11,11 +10,11 @@ import ( "github.com/aws/aws-sdk-go/service/eks" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + sdkid "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" @@ -90,6 +89,22 @@ func ResourceAddon() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.StringInSlice(eks.ResolveConflicts_Values(), false), + Deprecated: `The "resolve_conflicts" attribute can't be set to "PRESERVE" on initial resource creation. Use "resolve_conflicts_on_create" and/or "resolve_conflicts_on_update" instead`, + }, + "resolve_conflicts_on_create": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + eks.ResolveConflictsNone, + eks.ResolveConflictsOverwrite, + }, false), + ConflictsWith: []string{"resolve_conflicts"}, + }, + "resolve_conflicts_on_update": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(eks.ResolveConflicts_Values(), false), + ConflictsWith: []string{"resolve_conflicts"}, }, "service_account_role_arn": { Type: schema.TypeString, @@ -103,14 +118,15 @@ func ResourceAddon() *schema.Resource { } func resourceAddonCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics conn := meta.(*conns.AWSClient).EKSConn() addonName := d.Get("addon_name").(string) clusterName := d.Get("cluster_name").(string) - addonId := AddonCreateResourceID(clusterName, addonName) + id := AddonCreateResourceID(clusterName, addonName) input := &eks.CreateAddonInput{ AddonName: aws.String(addonName), - ClientRequestToken: aws.String(id.UniqueId()), + ClientRequestToken: aws.String(sdkid.UniqueId()), ClusterName: aws.String(clusterName), Tags: GetTagsIn(ctx), } @@ -119,49 +135,44 @@ func resourceAddonCreate(ctx context.Context, d *schema.ResourceData, meta inter input.AddonVersion = aws.String(v.(string)) } + if v, ok := d.GetOk("configuration_values"); ok { + input.ConfigurationValues = aws.String(v.(string)) + } + if v, ok := d.GetOk("resolve_conflicts"); ok { input.ResolveConflicts = aws.String(v.(string)) + } else if v, ok := d.GetOk("resolve_conflicts_on_create"); ok { + input.ResolveConflicts = aws.String(v.(string)) } if v, ok := d.GetOk("service_account_role_arn"); ok { input.ServiceAccountRoleArn = aws.String(v.(string)) } - if v, ok := d.GetOk("configuration_values"); ok { - input.ConfigurationValues = aws.String(v.(string)) - } - - err := retry.RetryContext(ctx, propagationTimeout, func() *retry.RetryError { - _, err := conn.CreateAddonWithContext(ctx, input) - - if tfawserr.ErrMessageContains(err, eks.ErrCodeInvalidParameterException, "CREATE_FAILED") { - return retry.RetryableError(err) - } - - if tfawserr.ErrMessageContains(err, eks.ErrCodeInvalidParameterException, "does not exist") { - return retry.RetryableError(err) - } - - if err != nil { - return retry.NonRetryableError(err) - } + _, err := tfresource.RetryWhen(ctx, propagationTimeout, + func() (interface{}, error) { + return conn.CreateAddonWithContext(ctx, input) + }, + func(err error) (bool, error) { + if tfawserr.ErrMessageContains(err, eks.ErrCodeInvalidParameterException, "CREATE_FAILED") { + return true, err + } - return nil - }) + if tfawserr.ErrMessageContains(err, eks.ErrCodeInvalidParameterException, "does not exist") { + return true, err + } - if tfresource.TimedOut(err) { - _, err = conn.CreateAddonWithContext(ctx, input) - } + return false, err + }, + ) if err != nil { - return diag.FromErr(fmt.Errorf("creating EKS Add-On (%s): %w", addonId, err)) + return sdkdiag.AppendErrorf(diags, "creating EKS Add-On (%s): %s", id, err) } - d.SetId(addonId) - - _, err = waitAddonCreated(ctx, conn, clusterName, addonName, d.Timeout(schema.TimeoutCreate)) + d.SetId(id) - if err != nil { + if _, err := waitAddonCreated(ctx, conn, clusterName, addonName, d.Timeout(schema.TimeoutCreate)); err != nil { // Creating addon w/o setting resolve_conflicts to "OVERWRITE" // might result in a failed creation, if unmanaged version of addon is already deployed // and there are configuration conflicts: @@ -171,20 +182,21 @@ func resourceAddonCreate(ctx context.Context, d *schema.ResourceData, meta inter // Re-creating like this will resolve the error, but it will also purge any // configurations that were applied by the user (that were conflicting). This might we an unwanted // side effect and should be left for the user to decide how to handle it. - return diag.FromErr(fmt.Errorf("unexpected EKS Add-On (%s) state returned during creation: %w\n[WARNING] Running terraform apply again will remove the kubernetes add-on and attempt to create it again effectively purging previous add-on configuration", - d.Id(), err)) + diags = sdkdiag.AppendErrorf(diags, "waiting for EKS Add-On (%s) create: %s", d.Id(), err) + return sdkdiag.AppendWarningf(diags, "Running terraform apply again will remove the kubernetes add-on and attempt to create it again effectively purging previous add-on configuration") } - return resourceAddonRead(ctx, d, meta) + return append(diags, resourceAddonRead(ctx, d, meta)...) } func resourceAddonRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics conn := meta.(*conns.AWSClient).EKSConn() clusterName, addonName, err := AddonParseResourceID(d.Id()) if err != nil { - return diag.FromErr(err) + return sdkdiag.AppendFromErr(diags, err) } addon, err := FindAddonByClusterNameAndAddonName(ctx, conn, clusterName, addonName) @@ -196,7 +208,7 @@ func resourceAddonRead(ctx context.Context, d *schema.ResourceData, meta interfa } if err != nil { - return diag.FromErr(fmt.Errorf("error reading EKS Add-On (%s): %w", d.Id(), err)) + return sdkdiag.AppendErrorf(diags, "reading EKS Add-On (%s): %s", d.Id(), err) } d.Set("addon_name", addon.AddonName) @@ -210,22 +222,23 @@ func resourceAddonRead(ctx context.Context, d *schema.ResourceData, meta interfa SetTagsOut(ctx, addon.Tags) - return nil + return diags } func resourceAddonUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics conn := meta.(*conns.AWSClient).EKSConn() clusterName, addonName, err := AddonParseResourceID(d.Id()) if err != nil { - return diag.FromErr(err) + return sdkdiag.AppendFromErr(diags, err) } if d.HasChanges("addon_version", "service_account_role_arn", "configuration_values") { input := &eks.UpdateAddonInput{ AddonName: aws.String(addonName), - ClientRequestToken: aws.String(id.UniqueId()), + ClientRequestToken: aws.String(sdkid.UniqueId()), ClusterName: aws.String(clusterName), } @@ -237,7 +250,15 @@ func resourceAddonUpdate(ctx context.Context, d *schema.ResourceData, meta inter input.ConfigurationValues = aws.String(d.Get("configuration_values").(string)) } + var conflictResolutionAttr, conflictResolution string + if v, ok := d.GetOk("resolve_conflicts"); ok { + conflictResolutionAttr = "resolve_conflicts" + conflictResolution = v.(string) + input.ResolveConflicts = aws.String(v.(string)) + } else if v, ok := d.GetOk("resolve_conflicts_on_update"); ok { + conflictResolutionAttr = "resolve_conflicts_on_update" + conflictResolution = v.(string) input.ResolveConflicts = aws.String(v.(string)) } @@ -250,36 +271,33 @@ func resourceAddonUpdate(ctx context.Context, d *schema.ResourceData, meta inter output, err := conn.UpdateAddonWithContext(ctx, input) if err != nil { - return diag.FromErr(fmt.Errorf("error updating EKS Add-On (%s): %w", d.Id(), err)) + return sdkdiag.AppendErrorf(diags, "updating EKS Add-On (%s): %s", d.Id(), err) } updateID := aws.StringValue(output.Update.Id) - - _, err = waitAddonUpdateSuccessful(ctx, conn, clusterName, addonName, updateID, d.Timeout(schema.TimeoutUpdate)) - - if err != nil { - if d.Get("resolve_conflicts") != eks.ResolveConflictsOverwrite { + if _, err := waitAddonUpdateSuccessful(ctx, conn, clusterName, addonName, updateID, d.Timeout(schema.TimeoutUpdate)); err != nil { + if conflictResolution != eks.ResolveConflictsOverwrite { // Changing addon version w/o setting resolve_conflicts to "OVERWRITE" // might result in a failed update if there are conflicts: // ConfigurationConflict Apply failed with 1 conflict: conflict with "kubectl"... - return diag.FromErr(fmt.Errorf("error waiting for EKS Add-On (%s) update (%s): %w, consider setting attribute %q to %q", - d.Id(), updateID, err, "resolve_conflicts", eks.ResolveConflictsOverwrite)) + return sdkdiag.AppendErrorf(diags, "waiting for EKS Add-On (%s) update (%s): %s. Consider setting attribute %q to %q", d.Id(), updateID, err, conflictResolutionAttr, eks.ResolveConflictsOverwrite) } - return diag.FromErr(fmt.Errorf("error waiting for EKS Add-On (%s) update (%s): %w", d.Id(), updateID, err)) + return sdkdiag.AppendErrorf(diags, "waiting for EKS Add-On (%s) update (%s): %s", d.Id(), updateID, err) } } - return resourceAddonRead(ctx, d, meta) + return append(diags, resourceAddonRead(ctx, d, meta)...) } func resourceAddonDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics conn := meta.(*conns.AWSClient).EKSConn() clusterName, addonName, err := AddonParseResourceID(d.Id()) if err != nil { - return diag.FromErr(err) + return sdkdiag.AppendFromErr(diags, err) } input := &eks.DeleteAddonInput{ @@ -295,14 +313,12 @@ func resourceAddonDelete(ctx context.Context, d *schema.ResourceData, meta inter _, err = conn.DeleteAddonWithContext(ctx, input) if err != nil { - return diag.FromErr(fmt.Errorf("error deleting EKS Add-On (%s): %w", d.Id(), err)) + return sdkdiag.AppendErrorf(diags, "deleting EKS Add-On (%s): %s", d.Id(), err) } - _, err = waitAddonDeleted(ctx, conn, clusterName, addonName, d.Timeout(schema.TimeoutDelete)) - - if err != nil { - return diag.FromErr(fmt.Errorf("error waiting for EKS Add-On (%s) to delete: %w", d.Id(), err)) + if _, err := waitAddonDeleted(ctx, conn, clusterName, addonName, d.Timeout(schema.TimeoutDelete)); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for EKS Add-On (%s) delete: %s", d.Id(), err) } - return nil + return diags } diff --git a/internal/service/eks/addon_test.go b/internal/service/eks/addon_test.go index b7e307a5b53e..5edc28eb573f 100644 --- a/internal/service/eks/addon_test.go +++ b/internal/service/eks/addon_test.go @@ -110,8 +110,8 @@ func TestAccEKSAddon_addonVersion(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_eks_addon.test" addonName := "vpc-cni" - addonVersion1 := "v1.8.0-eksbuild.1" - addonVersion2 := "v1.9.0-eksbuild.1" + addonVersion1 := "v1.12.5-eksbuild.2" + addonVersion2 := "v1.12.6-eksbuild.1" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(ctx, t); testAccPreCheckAddon(ctx, t) }, @@ -130,7 +130,7 @@ func TestAccEKSAddon_addonVersion(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"resolve_conflicts"}, + ImportStateVerifyIgnore: []string{"resolve_conflicts_on_create", "resolve_conflicts_on_update"}, }, { Config: testAccAddonConfig_version(rName, addonName, addonVersion2), @@ -173,7 +173,7 @@ func TestAccEKSAddon_preserve(t *testing.T) { }) } -func TestAccEKSAddon_resolveConflicts(t *testing.T) { +func TestAccEKSAddon_deprecated(t *testing.T) { ctx := acctest.Context(t) var addon1, addon2, addon3 eks.Addon rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -187,7 +187,7 @@ func TestAccEKSAddon_resolveConflicts(t *testing.T) { CheckDestroy: testAccCheckAddonDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccAddonConfig_resolveConflicts(rName, addonName, eks.ResolveConflictsNone), + Config: testAccAddonConfig_deprecated(rName, addonName, eks.ResolveConflictsNone), Check: resource.ComposeTestCheckFunc( testAccCheckAddonExists(ctx, resourceName, &addon1), resource.TestCheckResourceAttr(resourceName, "resolve_conflicts", eks.ResolveConflictsNone), @@ -200,14 +200,14 @@ func TestAccEKSAddon_resolveConflicts(t *testing.T) { ImportStateVerifyIgnore: []string{"resolve_conflicts"}, }, { - Config: testAccAddonConfig_resolveConflicts(rName, addonName, eks.ResolveConflictsOverwrite), + Config: testAccAddonConfig_deprecated(rName, addonName, eks.ResolveConflictsOverwrite), Check: resource.ComposeTestCheckFunc( testAccCheckAddonExists(ctx, resourceName, &addon2), resource.TestCheckResourceAttr(resourceName, "resolve_conflicts", eks.ResolveConflictsOverwrite), ), }, { - Config: testAccAddonConfig_resolveConflicts(rName, addonName, eks.ResolveConflictsPreserve), + Config: testAccAddonConfig_deprecated(rName, addonName, eks.ResolveConflictsPreserve), Check: resource.ComposeTestCheckFunc( testAccCheckAddonExists(ctx, resourceName, &addon3), resource.TestCheckResourceAttr(resourceName, "resolve_conflicts", eks.ResolveConflictsPreserve), @@ -217,6 +217,53 @@ func TestAccEKSAddon_resolveConflicts(t *testing.T) { }) } +func TestAccEKSAddon_resolveConflicts(t *testing.T) { + ctx := acctest.Context(t) + var addon1, addon2, addon3 eks.Addon + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_eks_addon.test" + addonName := "vpc-cni" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(ctx, t); testAccPreCheckAddon(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, eks.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAddonDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAddonConfig_resolveConflicts(rName, addonName, eks.ResolveConflictsNone, eks.ResolveConflictsNone), + Check: resource.ComposeTestCheckFunc( + testAccCheckAddonExists(ctx, resourceName, &addon1), + resource.TestCheckResourceAttr(resourceName, "resolve_conflicts_on_create", eks.ResolveConflictsNone), + resource.TestCheckResourceAttr(resourceName, "resolve_conflicts_on_update", eks.ResolveConflictsNone), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"resolve_conflicts_on_create", "resolve_conflicts_on_update"}, + }, + { + Config: testAccAddonConfig_resolveConflicts(rName, addonName, eks.ResolveConflictsOverwrite, eks.ResolveConflictsOverwrite), + Check: resource.ComposeTestCheckFunc( + testAccCheckAddonExists(ctx, resourceName, &addon2), + resource.TestCheckResourceAttr(resourceName, "resolve_conflicts_on_create", eks.ResolveConflictsOverwrite), + resource.TestCheckResourceAttr(resourceName, "resolve_conflicts_on_update", eks.ResolveConflictsOverwrite), + ), + }, + { + Config: testAccAddonConfig_resolveConflicts(rName, addonName, eks.ResolveConflictsOverwrite, eks.ResolveConflictsPreserve), + Check: resource.ComposeTestCheckFunc( + testAccCheckAddonExists(ctx, resourceName, &addon3), + resource.TestCheckResourceAttr(resourceName, "resolve_conflicts_on_create", eks.ResolveConflictsOverwrite), + resource.TestCheckResourceAttr(resourceName, "resolve_conflicts_on_update", eks.ResolveConflictsPreserve), + ), + }, + }, + }) +} + func TestAccEKSAddon_serviceAccountRoleARN(t *testing.T) { ctx := acctest.Context(t) var addon eks.Addon @@ -257,7 +304,7 @@ func TestAccEKSAddon_configurationValues(t *testing.T) { emptyConfigurationValues := "{}" invalidConfigurationValues := "{\"env\": {\"INVALID_FIELD\":\"2\"}}" addonName := "vpc-cni" - addonVersion := "v1.10.4-eksbuild.1" + addonVersion := "v1.12.6-eksbuild.1" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(ctx, t); testAccPreCheckAddon(ctx, t) }, @@ -347,382 +394,6 @@ func TestAccEKSAddon_tags(t *testing.T) { }) } -func TestAccEKSAddon_DefaultTags_providerOnly(t *testing.T) { - ctx := acctest.Context(t) - var addon eks.Addon - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_eks_addon.test" - addonName := "vpc-cni" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, eks.EndpointsID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckAddonDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: acctest.ConfigCompose( - acctest.ConfigDefaultTags_Tags1("providerkey1", "providervalue1"), - testAccAddonConfig_basic(rName, addonName), - ), - Check: resource.ComposeTestCheckFunc( - testAccCheckAddonExists(ctx, resourceName, &addon), - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), - resource.TestCheckResourceAttr(resourceName, "tags_all.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.providerkey1", "providervalue1"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: acctest.ConfigCompose( - acctest.ConfigDefaultTags_Tags2("providerkey1", "providervalue1", "providerkey2", "providervalue2"), - testAccAddonConfig_basic(rName, addonName), - ), - Check: resource.ComposeTestCheckFunc( - testAccCheckAddonExists(ctx, resourceName, &addon), - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), - resource.TestCheckResourceAttr(resourceName, "tags_all.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags_all.providerkey1", "providervalue1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.providerkey2", "providervalue2"), - ), - }, - { - Config: acctest.ConfigCompose( - acctest.ConfigDefaultTags_Tags1("providerkey1", "value1"), - testAccAddonConfig_basic(rName, addonName), - ), - Check: resource.ComposeTestCheckFunc( - testAccCheckAddonExists(ctx, resourceName, &addon), - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), - resource.TestCheckResourceAttr(resourceName, "tags_all.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.providerkey1", "value1"), - ), - }, - }, - }) -} - -func TestAccEKSAddon_DefaultTags_updateToProviderOnly(t *testing.T) { - ctx := acctest.Context(t) - var addon eks.Addon - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_eks_addon.test" - addonName := "vpc-cni" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, eks.EndpointsID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckAddonDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccAddonConfig_tags1(rName, addonName, "key1", "value1"), - Check: resource.ComposeTestCheckFunc( - testAccCheckAddonExists(ctx, resourceName, &addon), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.key1", "value1"), - ), - }, - { - Config: acctest.ConfigCompose( - acctest.ConfigDefaultTags_Tags1("key1", "value1"), - testAccAddonConfig_basic(rName, addonName), - ), - Check: resource.ComposeTestCheckFunc( - testAccCheckAddonExists(ctx, resourceName, &addon), - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), - resource.TestCheckResourceAttr(resourceName, "tags_all.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.key1", "value1"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccEKSAddon_DefaultTags_updateToResourceOnly(t *testing.T) { - ctx := acctest.Context(t) - var addon eks.Addon - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_eks_addon.test" - addonName := "vpc-cni" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, eks.EndpointsID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckAddonDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: acctest.ConfigCompose( - acctest.ConfigDefaultTags_Tags1("key1", "value1"), - testAccAddonConfig_basic(rName, addonName), - ), - Check: resource.ComposeTestCheckFunc( - testAccCheckAddonExists(ctx, resourceName, &addon), - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), - resource.TestCheckResourceAttr(resourceName, "tags_all.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.key1", "value1"), - ), - }, - { - Config: testAccAddonConfig_tags1(rName, addonName, "key1", "value1"), - Check: resource.ComposeTestCheckFunc( - testAccCheckAddonExists(ctx, resourceName, &addon), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.key1", "value1"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func TestAccEKSAddon_DefaultTagsProviderAndResource_nonOverlappingTag(t *testing.T) { - ctx := acctest.Context(t) - var addon eks.Addon - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_eks_addon.test" - addonName := "vpc-cni" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, eks.EndpointsID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckAddonDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: acctest.ConfigCompose( - acctest.ConfigDefaultTags_Tags1("providerkey1", "providervalue1"), - testAccAddonConfig_tags1(rName, addonName, "resourcekey1", "resourcevalue1"), - ), - Check: resource.ComposeTestCheckFunc( - testAccCheckAddonExists(ctx, resourceName, &addon), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.resourcekey1", "resourcevalue1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.providerkey1", "providervalue1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.resourcekey1", "resourcevalue1"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: acctest.ConfigCompose( - acctest.ConfigDefaultTags_Tags1("providerkey1", "providervalue1"), - testAccAddonConfig_tags2(rName, addonName, "resourcekey1", "resourcevalue1", "resourcekey2", "resourcevalue2"), - ), - Check: resource.ComposeTestCheckFunc( - testAccCheckAddonExists(ctx, resourceName, &addon), - resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags_all.%", "3"), - resource.TestCheckResourceAttr(resourceName, "tags.resourcekey1", "resourcevalue1"), - resource.TestCheckResourceAttr(resourceName, "tags.resourcekey2", "resourcevalue2"), - resource.TestCheckResourceAttr(resourceName, "tags_all.providerkey1", "providervalue1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.resourcekey1", "resourcevalue1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.resourcekey2", "resourcevalue2"), - ), - }, - { - Config: acctest.ConfigCompose( - acctest.ConfigDefaultTags_Tags1("providerkey2", "providervalue2"), - testAccAddonConfig_tags1(rName, addonName, "resourcekey3", "resourcevalue3"), - ), - Check: resource.ComposeTestCheckFunc( - testAccCheckAddonExists(ctx, resourceName, &addon), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.resourcekey3", "resourcevalue3"), - resource.TestCheckResourceAttr(resourceName, "tags_all.providerkey2", "providervalue2"), - resource.TestCheckResourceAttr(resourceName, "tags_all.resourcekey3", "resourcevalue3"), - ), - }, - }, - }) -} - -func TestAccEKSAddon_DefaultTagsProviderAndResource_overlappingTag(t *testing.T) { - ctx := acctest.Context(t) - var addon eks.Addon - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_eks_addon.test" - addonName := "vpc-cni" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, eks.EndpointsID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckAddonDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: acctest.ConfigCompose( - acctest.ConfigDefaultTags_Tags1("overlapkey1", "providervalue1"), - testAccAddonConfig_tags1(rName, addonName, "overlapkey1", "resourcevalue1"), - ), - Check: resource.ComposeTestCheckFunc( - testAccCheckAddonExists(ctx, resourceName, &addon), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.overlapkey1", "resourcevalue1"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: acctest.ConfigCompose( - acctest.ConfigDefaultTags_Tags2("overlapkey1", "providervalue1", "overlapkey2", "providervalue2"), - testAccAddonConfig_tags2(rName, addonName, "overlapkey1", "resourcevalue1", "overlapkey2", "resourcevalue2"), - ), - Check: resource.ComposeTestCheckFunc( - testAccCheckAddonExists(ctx, resourceName, &addon), - resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags_all.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.overlapkey1", "resourcevalue1"), - resource.TestCheckResourceAttr(resourceName, "tags.overlapkey2", "resourcevalue2"), - resource.TestCheckResourceAttr(resourceName, "tags_all.overlapkey1", "resourcevalue1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.overlapkey2", "resourcevalue2"), - ), - }, - { - Config: acctest.ConfigCompose( - acctest.ConfigDefaultTags_Tags1("overlapkey1", "providervalue1"), - testAccAddonConfig_tags1(rName, addonName, "overlapkey1", "resourcevalue2"), - ), - Check: resource.ComposeTestCheckFunc( - testAccCheckAddonExists(ctx, resourceName, &addon), - resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags_all.%", "1"), - resource.TestCheckResourceAttr(resourceName, "tags.overlapkey1", "resourcevalue2"), - resource.TestCheckResourceAttr(resourceName, "tags_all.overlapkey1", "resourcevalue2"), - ), - }, - }, - }) -} - -func TestAccEKSAddon_DefaultTagsProviderAndResource_duplicateTag(t *testing.T) { - ctx := acctest.Context(t) - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - addonName := "vpc-cni" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, eks.EndpointsID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: nil, - Steps: []resource.TestStep{ - { - Config: acctest.ConfigCompose( - acctest.ConfigDefaultTags_Tags1("overlapkey", "overlapvalue"), - testAccAddonConfig_tags1(rName, addonName, "overlapkey", "overlapvalue"), - ), - PlanOnly: true, - ExpectError: regexp.MustCompile(`"tags" are identical to those in the "default_tags" configuration block`), - }, - }, - }) -} - -func TestAccEKSAddon_defaultAndIgnoreTags(t *testing.T) { - ctx := acctest.Context(t) - var addon eks.Addon - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_eks_addon.test" - addonName := "vpc-cni" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, eks.EndpointsID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckAddonDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccAddonConfig_tags1(rName, addonName, "key1", "value1"), - Check: resource.ComposeTestCheckFunc( - testAccCheckAddonExists(ctx, resourceName, &addon), - testAccCheckAddonUpdateTags(ctx, &addon, nil, map[string]string{"defaultkey1": "defaultvalue1"}), - ), - ExpectNonEmptyPlan: true, - }, - { - Config: acctest.ConfigCompose( - acctest.ConfigDefaultAndIgnoreTagsKeyPrefixes1("defaultkey1", "defaultvalue1", "defaultkey"), - testAccAddonConfig_tags1(rName, addonName, "key1", "value1"), - ), - PlanOnly: true, - }, - { - Config: acctest.ConfigCompose( - acctest.ConfigDefaultAndIgnoreTagsKeys1("defaultkey1", "defaultvalue1"), - testAccAddonConfig_tags1(rName, addonName, "key1", "value1"), - ), - PlanOnly: true, - }, - }, - }) -} - -func TestAccEKSAddon_ignoreTags(t *testing.T) { - ctx := acctest.Context(t) - var addon eks.Addon - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_eks_addon.test" - addonName := "vpc-cni" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, eks.EndpointsID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckAddonDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccAddonConfig_tags1(rName, addonName, "key1", "value1"), - Check: resource.ComposeTestCheckFunc( - testAccCheckAddonExists(ctx, resourceName, &addon), - testAccCheckAddonUpdateTags(ctx, &addon, nil, map[string]string{"ignorekey1": "ignorevalue1"}), - ), - ExpectNonEmptyPlan: true, - }, - { - Config: acctest.ConfigCompose( - acctest.ConfigIgnoreTagsKeyPrefixes1("ignorekey"), - testAccAddonConfig_tags1(rName, addonName, "key1", "value1"), - ), - PlanOnly: true, - }, - { - Config: acctest.ConfigCompose( - acctest.ConfigIgnoreTagsKeys("ignorekey1"), - testAccAddonConfig_tags1(rName, addonName, "key1", "value1"), - ), - PlanOnly: true, - }, - }, - }) -} - func testAccCheckAddonExists(ctx context.Context, n string, v *eks.Addon) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -885,10 +556,11 @@ resource "aws_eks_addon" "test" { func testAccAddonConfig_version(rName, addonName, addonVersion string) string { return acctest.ConfigCompose(testAccAddonConfig_base(rName), fmt.Sprintf(` resource "aws_eks_addon" "test" { - cluster_name = aws_eks_cluster.test.name - addon_name = %[2]q - addon_version = %[3]q - resolve_conflicts = "OVERWRITE" + cluster_name = aws_eks_cluster.test.name + addon_name = %[2]q + addon_version = %[3]q + resolve_conflicts_on_create = "OVERWRITE" + resolve_conflicts_on_update = "OVERWRITE" } `, rName, addonName, addonVersion)) } @@ -903,7 +575,7 @@ resource "aws_eks_addon" "test" { `, rName, addonName)) } -func testAccAddonConfig_resolveConflicts(rName, addonName, resolveConflicts string) string { +func testAccAddonConfig_deprecated(rName, addonName, resolveConflicts string) string { return acctest.ConfigCompose(testAccAddonConfig_base(rName), fmt.Sprintf(` resource "aws_eks_addon" "test" { cluster_name = aws_eks_cluster.test.name @@ -913,6 +585,17 @@ resource "aws_eks_addon" "test" { `, rName, addonName, resolveConflicts)) } +func testAccAddonConfig_resolveConflicts(rName, addonName, resolveConflictsOnCreate, resolveConflictsOnUpdate string) string { + return acctest.ConfigCompose(testAccAddonConfig_base(rName), fmt.Sprintf(` +resource "aws_eks_addon" "test" { + cluster_name = aws_eks_cluster.test.name + addon_name = %[2]q + resolve_conflicts_on_create = %[3]q + resolve_conflicts_on_update = %[4]q +} +`, rName, addonName, resolveConflictsOnCreate, resolveConflictsOnUpdate)) +} + func testAccAddonConfig_serviceAccountRoleARN(rName, addonName string) string { return acctest.ConfigCompose(testAccAddonConfig_base(rName), fmt.Sprintf(` resource "aws_iam_role" "test-service-role" { diff --git a/website/docs/r/eks_addon.html.markdown b/website/docs/r/eks_addon.html.markdown index ade95a0efa49..dd7d66e995ef 100644 --- a/website/docs/r/eks_addon.html.markdown +++ b/website/docs/r/eks_addon.html.markdown @@ -24,18 +24,16 @@ resource "aws_eks_addon" "example" { } ``` -## Example Update add-on usage with resolve_conflicts and PRESERVE +## Example Update add-on usage with resolve_conflicts_on_update and PRESERVE -`resolve_conflicts` with `PRESERVE` can be used to retain the config changes applied to the add-on with kubectl while upgrading to a newer version of the add-on. - -~> **Note:** `resolve_conflicts` with `PRESERVE` can only be used for upgrading the add-ons but not during the creation of add-on. +`resolve_conflicts_on_update` with `PRESERVE` can be used to retain the config changes applied to the add-on with kubectl while upgrading to a newer version of the add-on. ```terraform resource "aws_eks_addon" "example" { - cluster_name = aws_eks_cluster.example.name - addon_name = "coredns" - addon_version = "v1.8.7-eksbuild.3" #e.g., previous version v1.8.7-eksbuild.2 and the new version is v1.8.7-eksbuild.3 - resolve_conflicts = "PRESERVE" + cluster_name = aws_eks_cluster.example.name + addon_name = "coredns" + addon_version = "v1.8.7-eksbuild.3" #e.g., previous version v1.8.7-eksbuild.2 and the new version is v1.8.7-eksbuild.3 + resolve_conflicts_on_update = "PRESERVE" } ``` @@ -58,11 +56,24 @@ Example to create a `coredns` managed addon with custom `configuration_values`. ```terraform resource "aws_eks_addon" "example" { - cluster_name = "mycluster" - addon_name = "coredns" - addon_version = "v1.8.7-eksbuild.3" - resolve_conflicts = "OVERWRITE" - configuration_values = "{\"replicaCount\":4,\"resources\":{\"limits\":{\"cpu\":\"100m\",\"memory\":\"150Mi\"},\"requests\":{\"cpu\":\"100m\",\"memory\":\"150Mi\"}}}" + cluster_name = "mycluster" + addon_name = "coredns" + addon_version = "v1.8.7-eksbuild.3" + resolve_conflicts_on_create = "OVERWRITE" + + configuration_values = jsonencode({ + replicaCount = 4 + resources = { + limits = { + cpu = "100m" + memory = "150Mi" + } + requests = { + cpu = "100m" + memory = "150Mi" + } + } + }) } ``` @@ -125,9 +136,9 @@ The following arguments are optional: * `addon_version` – (Optional) The version of the EKS add-on. The version must match one of the versions returned by [describe-addon-versions](https://docs.aws.amazon.com/cli/latest/reference/eks/describe-addon-versions.html). * `configuration_values` - (Optional) custom configuration values for addons with single JSON string. This JSON string value must match the JSON schema derived from [describe-addon-configuration](https://docs.aws.amazon.com/cli/latest/reference/eks/describe-addon-configuration.html). -* `resolve_conflicts` - (Optional) Define how to resolve parameter value conflicts - when migrating an existing add-on to an Amazon EKS add-on or when applying - version updates to the add-on. Valid values are `NONE`, `OVERWRITE` and `PRESERVE`. For more details check [UpdateAddon](https://docs.aws.amazon.com/eks/latest/APIReference/API_UpdateAddon.html) API Docs. +* `resolve_conflicts_on_create` - (Optional) How to resolve field value conflicts when migrating a self-managed add-on to an Amazon EKS add-on. Valid values are `NONE` and `OVERWRITE`. For more details see the [CreateAddon](https://docs.aws.amazon.com/eks/latest/APIReference/API_CreateAddon.html) API Docs. +* `resolve_conflicts_on_update` - (Optional) How to resolve field value conflicts for an Amazon EKS add-on if you've changed a value from the Amazon EKS default value. Valid values are `NONE` and `OVERWRITE`. For more details see the [UpdateAddon](https://docs.aws.amazon.com/eks/latest/APIReference/API_UpdateAddon.html) API Docs. +* `resolve_conflicts` - (**Deprecated** use the `resolve_conflicts_on_create` and `resolve_conflicts_on_update` attributes instead) Define how to resolve parameter value conflicts when migrating an existing add-on to an Amazon EKS add-on or when applying version updates to the add-on. Valid values are `NONE`, `OVERWRITE` and `PRESERVE`. Note that `PRESERVE` is only valid on addon update, not for initial addon creation. If you need to set this to `PRESERVE`, use the `resolve_conflicts_on_create` and `resolve_conflicts_on_update` attributes instead. For more details check [UpdateAddon](https://docs.aws.amazon.com/eks/latest/APIReference/API_UpdateAddon.html) API Docs. * `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. * `preserve` - (Optional) Indicates if you want to preserve the created resources when deleting the EKS add-on. * `service_account_role_arn` - (Optional) The Amazon Resource Name (ARN) of an