From 1fa471631507e54511161c97bd93ff02b8927a7b Mon Sep 17 00:00:00 2001 From: Matt Burgess <549318+mattburgess@users.noreply.github.com> Date: Tue, 21 Feb 2023 21:47:13 +0000 Subject: [PATCH 01/10] r/eks_addon: Deprecate `resolve_conflicts` attribute --- internal/service/eks/addon.go | 35 +++++++++++- internal/service/eks/addon_test.go | 79 ++++++++++++++++++++++---- website/docs/r/eks_addon.html.markdown | 43 ++++++++------ 3 files changed, 129 insertions(+), 28 deletions(-) diff --git a/internal/service/eks/addon.go b/internal/service/eks/addon.go index 8249063e973..bfa8f738df3 100644 --- a/internal/service/eks/addon.go +++ b/internal/service/eks/addon.go @@ -86,6 +86,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 \"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, @@ -117,6 +133,10 @@ func resourceAddonCreate(ctx context.Context, d *schema.ResourceData, meta inter input.AddonVersion = aws.String(v.(string)) } + if v, ok := d.GetOk("resolve_conflicts_on_create"); ok { + input.ResolveConflicts = aws.String(v.(string)) + } + if v, ok := d.GetOk("resolve_conflicts"); ok { input.ResolveConflicts = aws.String(v.(string)) } @@ -250,7 +270,18 @@ func resourceAddonUpdate(ctx context.Context, d *schema.ResourceData, meta inter input.ConfigurationValues = aws.String(d.Get("configuration_values").(string)) } + conflictResolutionAttr := "" + conflictResolution := "" + if v, ok := d.GetOk("resolve_conflicts"); ok { + conflictResolutionAttr = "resolve_conflicts" + conflictResolution = v.(string) + input.ResolveConflicts = aws.String(v.(string)) + } + + if v, ok := d.GetOk("resolve_conflicts_on_update"); ok { + conflictResolutionAttr = "resolve_conflicts_on_update" + conflictResolution = v.(string) input.ResolveConflicts = aws.String(v.(string)) } @@ -271,12 +302,12 @@ func resourceAddonUpdate(ctx context.Context, d *schema.ResourceData, meta inter _, err = waitAddonUpdateSuccessful(ctx, conn, clusterName, addonName, updateID, d.Timeout(schema.TimeoutUpdate)) if err != nil { - if d.Get("resolve_conflicts") != eks.ResolveConflictsOverwrite { + 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)) + 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)) diff --git a/internal/service/eks/addon_test.go b/internal/service/eks/addon_test.go index 27937c4c637..38b243499fd 100644 --- a/internal/service/eks/addon_test.go +++ b/internal/service/eks/addon_test.go @@ -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(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 @@ -884,10 +931,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)) } @@ -902,7 +950,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 @@ -912,6 +960,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 4f2ef3b0187..5eb0020359a 100644 --- a/website/docs/r/eks_addon.html.markdown +++ b/website/docs/r/eks_addon.html.markdown @@ -24,17 +24,15 @@ resource "aws_eks_addon" "example" { } ``` -## Example Update add-on usage with resolve_conflicts 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. +## Example Update add-on usage with resolve_conflicts_on_update and PRESERVE +`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" } ``` @@ -56,11 +54,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" + } + } + }) } ``` @@ -123,9 +134,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 From 666f57d9f0bc52c45103d2d46efec05cade827f0 Mon Sep 17 00:00:00 2001 From: Matt Burgess <549318+mattburgess@users.noreply.github.com> Date: Tue, 21 Feb 2023 21:52:57 +0000 Subject: [PATCH 02/10] Add Changelog --- .changelog/29555.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changelog/29555.txt diff --git a/.changelog/29555.txt b/.changelog/29555.txt new file mode 100644 index 00000000000..8b20e915d78 --- /dev/null +++ b/.changelog/29555.txt @@ -0,0 +1,2 @@ +```release-note:note +resource/aws_eks_addon: The resolve_conflicts attribute is being deprecated in favour of separate resolve_conflicts_on_create and resolve_conflicts_on_update attributes From 61b09eeca093cb20fc6bbd6212ee4139f86a5d1c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 9 May 2023 10:38:44 -0400 Subject: [PATCH 03/10] Tweak CHANGELOG entry. --- .changelog/29555.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/29555.txt b/.changelog/29555.txt index 8b20e915d78..6675db4b300 100644 --- a/.changelog/29555.txt +++ b/.changelog/29555.txt @@ -1,2 +1,2 @@ ```release-note:note -resource/aws_eks_addon: The resolve_conflicts attribute is being deprecated in favour of separate resolve_conflicts_on_create and resolve_conflicts_on_update attributes +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 From 99a04f65a430d6da23e7c5639dd0c3bbbca83650 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 9 May 2023 10:59:01 -0400 Subject: [PATCH 04/10] r/aws_eks_addon: A bit of modernization. --- internal/service/eks/addon.go | 115 +++++++++++++---------------- internal/service/eks/addon_test.go | 2 +- 2 files changed, 51 insertions(+), 66 deletions(-) diff --git a/internal/service/eks/addon.go b/internal/service/eks/addon.go index 49a726ebfa5..6679ec4c59c 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,7 +89,7 @@ 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 \"resolve_conflicts_on_update\" instead", + 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, @@ -119,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), } @@ -135,53 +135,44 @@ func resourceAddonCreate(ctx context.Context, d *schema.ResourceData, meta inter input.AddonVersion = aws.String(v.(string)) } - if v, ok := d.GetOk("resolve_conflicts_on_create"); ok { - input.ResolveConflicts = 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) + d.SetId(id) - _, err = waitAddonCreated(ctx, conn, clusterName, addonName, d.Timeout(schema.TimeoutCreate)) - - 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: @@ -191,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) @@ -216,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) @@ -230,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), } @@ -257,16 +250,13 @@ func resourceAddonUpdate(ctx context.Context, d *schema.ResourceData, meta inter input.ConfigurationValues = aws.String(d.Get("configuration_values").(string)) } - conflictResolutionAttr := "" - conflictResolution := "" + var conflictResolutionAttr, conflictResolution string if v, ok := d.GetOk("resolve_conflicts"); ok { conflictResolutionAttr = "resolve_conflicts" conflictResolution = v.(string) input.ResolveConflicts = aws.String(v.(string)) - } - - if v, ok := d.GetOk("resolve_conflicts_on_update"); ok { + } 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)) @@ -281,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 _, 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, conflictResolutionAttr, 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{ @@ -326,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 a0c881d5cdd..2da77483040 100644 --- a/internal/service/eks/addon_test.go +++ b/internal/service/eks/addon_test.go @@ -181,7 +181,7 @@ func TestAccEKSAddon_deprecated(t *testing.T) { addonName := "vpc-cni" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t); testAccPreCheck(ctx, t); testAccPreCheckAddon(ctx, t) }, + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(ctx, t); testAccPreCheckAddon(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, eks.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckAddonDestroy(ctx), From f4192840e77878380951c769aae153af6d8c5de6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 9 May 2023 11:06:42 -0400 Subject: [PATCH 05/10] Fix markdown-lint 'MD022/blanks-around-headings/blanks-around-headers Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below]'. --- website/docs/r/eks_addon.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/eks_addon.html.markdown b/website/docs/r/eks_addon.html.markdown index 42eda17af35..dd7d66e995e 100644 --- a/website/docs/r/eks_addon.html.markdown +++ b/website/docs/r/eks_addon.html.markdown @@ -25,6 +25,7 @@ resource "aws_eks_addon" "example" { ``` ## Example Update add-on usage with resolve_conflicts_on_update and PRESERVE + `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 From f45ccb9ae16d2c2bdd00b3e6e0ff0fe4dbd65295 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 9 May 2023 12:57:39 -0400 Subject: [PATCH 06/10] r/aws_eks_addon: Update versions used in acceptance test configurations. --- internal/service/eks/addon_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/eks/addon_test.go b/internal/service/eks/addon_test.go index 2da77483040..fa3fba9e339 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) }, @@ -304,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) }, From 1ceed6dc19239f81a84cc6588962c5eaf773c181 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 9 May 2023 13:31:13 -0400 Subject: [PATCH 07/10] Apply v4.66.1 transparent tagging changes to 'tagsUpdateFunc' and 'tagsReadFunc'. --- internal/provider/tags_interceptor.go | 82 ++++++++++++++------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/internal/provider/tags_interceptor.go b/internal/provider/tags_interceptor.go index 83de6c05cc3..896d77e23f0 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. From c70256cb32c7ba53626c3474e6ee190fd6a0e5f3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 9 May 2023 13:33:54 -0400 Subject: [PATCH 08/10] Remove 'TestAccEKSAddon_DefaultTagsProviderAndResource_duplicateTag'. --- internal/service/eks/addon_test.go | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/internal/service/eks/addon_test.go b/internal/service/eks/addon_test.go index fa3fba9e339..f50344472c3 100644 --- a/internal/service/eks/addon_test.go +++ b/internal/service/eks/addon_test.go @@ -669,29 +669,6 @@ func TestAccEKSAddon_DefaultTagsProviderAndResource_overlappingTag(t *testing.T) }) } -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 From 81700eaee3340bf9c8342fc0db17bfd2dfe7cba3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 9 May 2023 13:36:45 -0400 Subject: [PATCH 09/10] Remove 'TestAccVPCSubnet_DefaultTagsProviderAndResource_duplicateTag'. --- internal/service/ec2/vpc_subnet_test.go | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/internal/service/ec2/vpc_subnet_test.go b/internal/service/ec2/vpc_subnet_test.go index 596d0e2100d..f44723645b3 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 From 09996686dea84ea3b4c07b5c2ddb465c79291a08 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 9 May 2023 13:40:36 -0400 Subject: [PATCH 10/10] r/aws_eks_addon: 'default_tags' and 'ignore_tags' test aren't necessary. --- internal/service/eks/addon_test.go | 353 ----------------------------- 1 file changed, 353 deletions(-) diff --git a/internal/service/eks/addon_test.go b/internal/service/eks/addon_test.go index f50344472c3..5edc28eb573 100644 --- a/internal/service/eks/addon_test.go +++ b/internal/service/eks/addon_test.go @@ -394,359 +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_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]