diff --git a/aws/internal/keyvaluetags/generators/listtags/main.go b/aws/internal/keyvaluetags/generators/listtags/main.go index ea6a7fc65cbd..ba44df015c27 100644 --- a/aws/internal/keyvaluetags/generators/listtags/main.go +++ b/aws/internal/keyvaluetags/generators/listtags/main.go @@ -40,6 +40,7 @@ var serviceNames = []string{ "dax", "devicefarm", "directoryservice", + "dlm", "docdb", "dynamodb", "ecr", diff --git a/aws/internal/keyvaluetags/generators/servicetags/main.go b/aws/internal/keyvaluetags/generators/servicetags/main.go index a074e68aad88..3a9fab9f8799 100644 --- a/aws/internal/keyvaluetags/generators/servicetags/main.go +++ b/aws/internal/keyvaluetags/generators/servicetags/main.go @@ -40,7 +40,6 @@ var sliceServiceNames = []string{ "devicefarm", "directconnect", "directoryservice", - "dlm", "docdb", "dynamodb", "ec2", @@ -103,6 +102,7 @@ var mapServiceNames = []string{ "codecommit", "cognitoidentity", "cognitoidentityprovider", + "dlm", "eks", "glacier", "glue", diff --git a/aws/internal/keyvaluetags/generators/updatetags/main.go b/aws/internal/keyvaluetags/generators/updatetags/main.go index 9e8cef5c391a..f218cc8d364a 100644 --- a/aws/internal/keyvaluetags/generators/updatetags/main.go +++ b/aws/internal/keyvaluetags/generators/updatetags/main.go @@ -44,6 +44,7 @@ var serviceNames = []string{ "devicefarm", "directconnect", "directoryservice", + "dlm", "docdb", "dynamodb", "ec2", diff --git a/aws/internal/keyvaluetags/key_value_tags.go b/aws/internal/keyvaluetags/key_value_tags.go index 63e9ad5fc1d6..1e4e5be93107 100644 --- a/aws/internal/keyvaluetags/key_value_tags.go +++ b/aws/internal/keyvaluetags/key_value_tags.go @@ -1,5 +1,5 @@ -//go:generate go run generators/listtags/main.go //go:generate go run generators/servicetags/main.go +//go:generate go run generators/listtags/main.go //go:generate go run generators/updatetags/main.go package keyvaluetags diff --git a/aws/internal/keyvaluetags/list_tags_gen.go b/aws/internal/keyvaluetags/list_tags_gen.go index 71899c8a4f7a..387284b4d8e2 100644 --- a/aws/internal/keyvaluetags/list_tags_gen.go +++ b/aws/internal/keyvaluetags/list_tags_gen.go @@ -27,6 +27,7 @@ import ( "github.com/aws/aws-sdk-go/service/dax" "github.com/aws/aws-sdk-go/service/devicefarm" "github.com/aws/aws-sdk-go/service/directoryservice" + "github.com/aws/aws-sdk-go/service/dlm" "github.com/aws/aws-sdk-go/service/docdb" "github.com/aws/aws-sdk-go/service/dynamodb" "github.com/aws/aws-sdk-go/service/ecr" @@ -468,6 +469,23 @@ func DirectoryserviceListTags(conn *directoryservice.DirectoryService, identifie return DirectoryserviceKeyValueTags(output.Tags), nil } +// DlmListTags lists dlm service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func DlmListTags(conn *dlm.DLM, identifier string) (KeyValueTags, error) { + input := &dlm.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return DlmKeyValueTags(output.Tags), nil +} + // DocdbListTags lists docdb service tags. // The identifier is typically the Amazon Resource Name (ARN), although // it may also be a different identifier depending on the service. diff --git a/aws/internal/keyvaluetags/service_generation_customizations.go b/aws/internal/keyvaluetags/service_generation_customizations.go index c2851e2a12e8..8321bab3b1fe 100644 --- a/aws/internal/keyvaluetags/service_generation_customizations.go +++ b/aws/internal/keyvaluetags/service_generation_customizations.go @@ -34,6 +34,7 @@ import ( "github.com/aws/aws-sdk-go/service/devicefarm" "github.com/aws/aws-sdk-go/service/directconnect" "github.com/aws/aws-sdk-go/service/directoryservice" + "github.com/aws/aws-sdk-go/service/dlm" "github.com/aws/aws-sdk-go/service/docdb" "github.com/aws/aws-sdk-go/service/dynamodb" "github.com/aws/aws-sdk-go/service/ec2" @@ -155,6 +156,8 @@ func ServiceClientType(serviceName string) string { funcType = reflect.TypeOf(directconnect.New) case "directoryservice": funcType = reflect.TypeOf(directoryservice.New) + case "dlm": + funcType = reflect.TypeOf(dlm.New) case "docdb": funcType = reflect.TypeOf(docdb.New) case "dynamodb": diff --git a/aws/internal/keyvaluetags/service_tags_gen.go b/aws/internal/keyvaluetags/service_tags_gen.go index 2a31af4a6430..597bc03ce126 100644 --- a/aws/internal/keyvaluetags/service_tags_gen.go +++ b/aws/internal/keyvaluetags/service_tags_gen.go @@ -25,7 +25,6 @@ import ( "github.com/aws/aws-sdk-go/service/devicefarm" "github.com/aws/aws-sdk-go/service/directconnect" "github.com/aws/aws-sdk-go/service/directoryservice" - "github.com/aws/aws-sdk-go/service/dlm" "github.com/aws/aws-sdk-go/service/docdb" "github.com/aws/aws-sdk-go/service/dynamodb" "github.com/aws/aws-sdk-go/service/ec2" @@ -187,6 +186,16 @@ func CognitoidentityproviderKeyValueTags(tags map[string]*string) KeyValueTags { return New(tags) } +// DlmTags returns dlm service tags. +func (tags KeyValueTags) DlmTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// DlmKeyValueTags creates KeyValueTags from dlm service tags. +func DlmKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + // EksTags returns eks service tags. func (tags KeyValueTags) EksTags() map[string]*string { return aws.StringMap(tags.Map()) @@ -926,33 +935,6 @@ func DirectoryserviceKeyValueTags(tags []*directoryservice.Tag) KeyValueTags { return New(m) } -// DlmTags returns dlm service tags. -func (tags KeyValueTags) DlmTags() []*dlm.Tag { - result := make([]*dlm.Tag, 0, len(tags)) - - for k, v := range tags.Map() { - tag := &dlm.Tag{ - Key: aws.String(k), - Value: aws.String(v), - } - - result = append(result, tag) - } - - return result -} - -// DlmKeyValueTags creates KeyValueTags from dlm service tags. -func DlmKeyValueTags(tags []*dlm.Tag) KeyValueTags { - m := make(map[string]*string, len(tags)) - - for _, tag := range tags { - m[aws.StringValue(tag.Key)] = tag.Value - } - - return New(m) -} - // DocdbTags returns docdb service tags. func (tags KeyValueTags) DocdbTags() []*docdb.Tag { result := make([]*docdb.Tag, 0, len(tags)) diff --git a/aws/internal/keyvaluetags/update_tags_gen.go b/aws/internal/keyvaluetags/update_tags_gen.go index 676e748edde6..79500f801419 100644 --- a/aws/internal/keyvaluetags/update_tags_gen.go +++ b/aws/internal/keyvaluetags/update_tags_gen.go @@ -33,6 +33,7 @@ import ( "github.com/aws/aws-sdk-go/service/devicefarm" "github.com/aws/aws-sdk-go/service/directconnect" "github.com/aws/aws-sdk-go/service/directoryservice" + "github.com/aws/aws-sdk-go/service/dlm" "github.com/aws/aws-sdk-go/service/docdb" "github.com/aws/aws-sdk-go/service/dynamodb" "github.com/aws/aws-sdk-go/service/ec2" @@ -1059,6 +1060,42 @@ func DirectoryserviceUpdateTags(conn *directoryservice.DirectoryService, identif return nil } +// DlmUpdateTags updates dlm service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func DlmUpdateTags(conn *dlm.DLM, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &dlm.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %w", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &dlm.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().DlmTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %w", identifier, err) + } + } + + return nil +} + // DocdbUpdateTags updates docdb service tags. // The identifier is typically the Amazon Resource Name (ARN), although // it may also be a different identifier depending on the service. diff --git a/aws/resource_aws_dlm_lifecycle_policy.go b/aws/resource_aws_dlm_lifecycle_policy.go index 0dbfd6cf052e..8b4f1e305bdb 100644 --- a/aws/resource_aws_dlm_lifecycle_policy.go +++ b/aws/resource_aws_dlm_lifecycle_policy.go @@ -9,6 +9,7 @@ import ( "github.com/aws/aws-sdk-go/service/dlm" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsDlmLifecyclePolicy() *schema.Resource { @@ -22,6 +23,10 @@ func resourceAwsDlmLifecyclePolicy() *schema.Resource { }, Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, "description": { Type: schema.TypeString, Required: true, @@ -130,6 +135,7 @@ func resourceAwsDlmLifecyclePolicy() *schema.Resource { dlm.SettablePolicyStateValuesEnabled, }, false), }, + "tags": tagsSchema(), }, } } @@ -144,6 +150,10 @@ func resourceAwsDlmLifecyclePolicyCreate(d *schema.ResourceData, meta interface{ State: aws.String(d.Get("state").(string)), } + if v := d.Get("tags").(map[string]interface{}); len(v) > 0 { + input.Tags = keyvaluetags.New(v).IgnoreAws().DlmTags() + } + log.Printf("[INFO] Creating DLM lifecycle policy: %s", input) out, err := conn.CreateLifecyclePolicy(&input) if err != nil { @@ -173,6 +183,7 @@ func resourceAwsDlmLifecyclePolicyRead(d *schema.ResourceData, meta interface{}) return fmt.Errorf("error reading DLM Lifecycle Policy (%s): %s", d.Id(), err) } + d.Set("arn", out.Policy.PolicyArn) d.Set("description", out.Policy.Description) d.Set("execution_role_arn", out.Policy.ExecutionRoleArn) d.Set("state", out.Policy.State) @@ -180,6 +191,10 @@ func resourceAwsDlmLifecyclePolicyRead(d *schema.ResourceData, meta interface{}) return fmt.Errorf("error setting policy details %s", err) } + if err := d.Set("tags", keyvaluetags.DlmKeyValueTags(out.Policy.Tags).IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + return nil } @@ -189,24 +204,38 @@ func resourceAwsDlmLifecyclePolicyUpdate(d *schema.ResourceData, meta interface{ input := dlm.UpdateLifecyclePolicyInput{ PolicyId: aws.String(d.Id()), } + updateLifecyclePolicy := false if d.HasChange("description") { input.Description = aws.String(d.Get("description").(string)) + updateLifecyclePolicy = true } if d.HasChange("execution_role_arn") { input.ExecutionRoleArn = aws.String(d.Get("execution_role_arn").(string)) + updateLifecyclePolicy = true } if d.HasChange("state") { input.State = aws.String(d.Get("state").(string)) + updateLifecyclePolicy = true } if d.HasChange("policy_details") { input.PolicyDetails = expandDlmPolicyDetails(d.Get("policy_details").([]interface{})) + updateLifecyclePolicy = true } - log.Printf("[INFO] Updating lifecycle policy %s", d.Id()) - _, err := conn.UpdateLifecyclePolicy(&input) - if err != nil { - return fmt.Errorf("error updating DLM Lifecycle Policy (%s): %s", d.Id(), err) + if updateLifecyclePolicy { + log.Printf("[INFO] Updating lifecycle policy %s", d.Id()) + _, err := conn.UpdateLifecyclePolicy(&input) + if err != nil { + return fmt.Errorf("error updating DLM Lifecycle Policy (%s): %s", d.Id(), err) + } + } + + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.DlmUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) + } } return resourceAwsDlmLifecyclePolicyRead(d, meta) diff --git a/aws/resource_aws_dlm_lifecycle_policy_test.go b/aws/resource_aws_dlm_lifecycle_policy_test.go index a859a14a4546..10b84f5be56a 100644 --- a/aws/resource_aws_dlm_lifecycle_policy_test.go +++ b/aws/resource_aws_dlm_lifecycle_policy_test.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "regexp" "testing" "github.com/aws/aws-sdk-go/aws" @@ -24,6 +25,7 @@ func TestAccAWSDlmLifecyclePolicy_Basic(t *testing.T) { Config: dlmLifecyclePolicyBasicConfig(rName), Check: resource.ComposeTestCheckFunc( checkDlmLifecyclePolicyExists(resourceName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "dlm", regexp.MustCompile(`policy/.+`)), resource.TestCheckResourceAttr(resourceName, "description", "tf-acc-basic"), resource.TestCheckResourceAttrSet(resourceName, "execution_role_arn"), resource.TestCheckResourceAttr(resourceName, "state", "ENABLED"), @@ -34,6 +36,7 @@ func TestAccAWSDlmLifecyclePolicy_Basic(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, "policy_details.0.schedule.0.create_rule.0.times.0"), resource.TestCheckResourceAttr(resourceName, "policy_details.0.schedule.0.retain_rule.0.count", "10"), resource.TestCheckResourceAttr(resourceName, "policy_details.0.target_tags.tf-acc-test", "basic"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -94,6 +97,49 @@ func TestAccAWSDlmLifecyclePolicy_Full(t *testing.T) { }) } +func TestAccAWSDlmLifecyclePolicy_Tags(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_dlm_lifecycle_policy.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSDlm(t) }, + Providers: testAccProviders, + CheckDestroy: dlmLifecyclePolicyDestroy, + Steps: []resource.TestStep{ + { + Config: dlmLifecyclePolicyConfigTags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + checkDlmLifecyclePolicyExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: dlmLifecyclePolicyConfigTags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + checkDlmLifecyclePolicyExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: dlmLifecyclePolicyConfigTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + checkDlmLifecyclePolicyExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + func dlmLifecyclePolicyDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).dlmconn @@ -327,3 +373,110 @@ resource "aws_dlm_lifecycle_policy" "full" { } `, rName) } + +func dlmLifecyclePolicyConfigTags1(rName, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_iam_role" "test" { + name = %[1]q + + assume_role_policy = <