From 8c3b0a378bf10e3876e1b4bbcf9728e119e44d77 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 3 Sep 2019 15:06:46 -0400 Subject: [PATCH 1/5] provider: New shared libary for managing resource tags --- GNUmakefile | 10 +- aws/internal/keyvaluetags/README.md | 28 + .../generators/listtags/README.md | 91 + .../keyvaluetags/generators/listtags/main.go | 311 ++ .../generators/servicetags/README.md | 123 + .../generators/servicetags/main.go | 267 ++ .../generators/updatetags/README.md | 165 ++ .../generators/updatetags/main.go | 406 +++ aws/internal/keyvaluetags/key_value_tags.go | 171 ++ .../keyvaluetags/key_value_tags_test.go | 581 ++++ aws/internal/keyvaluetags/list_tags_gen.go | 1124 ++++++++ .../service_generation_customizations.go | 248 ++ aws/internal/keyvaluetags/service_tags_gen.go | 2203 ++++++++++++++ .../keyvaluetags/service_tags_gen_test.go | 483 ++++ aws/internal/keyvaluetags/update_tags_gen.go | 2564 +++++++++++++++++ 15 files changed, 8772 insertions(+), 3 deletions(-) create mode 100644 aws/internal/keyvaluetags/README.md create mode 100644 aws/internal/keyvaluetags/generators/listtags/README.md create mode 100644 aws/internal/keyvaluetags/generators/listtags/main.go create mode 100644 aws/internal/keyvaluetags/generators/servicetags/README.md create mode 100644 aws/internal/keyvaluetags/generators/servicetags/main.go create mode 100644 aws/internal/keyvaluetags/generators/updatetags/README.md create mode 100644 aws/internal/keyvaluetags/generators/updatetags/main.go create mode 100644 aws/internal/keyvaluetags/key_value_tags.go create mode 100644 aws/internal/keyvaluetags/key_value_tags_test.go create mode 100644 aws/internal/keyvaluetags/list_tags_gen.go create mode 100644 aws/internal/keyvaluetags/service_generation_customizations.go create mode 100644 aws/internal/keyvaluetags/service_tags_gen.go create mode 100644 aws/internal/keyvaluetags/service_tags_gen_test.go create mode 100644 aws/internal/keyvaluetags/update_tags_gen.go diff --git a/GNUmakefile b/GNUmakefile index 640dd91013b..f9cd4ec7aff 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -9,6 +9,10 @@ default: build build: fmtcheck go install +gen: + rm -f aws/internal/keyvaluetags/*_gen.go + go generate ./... + sweep: @echo "WARNING: This will destroy infrastructure. Use only in development accounts." go test $(TEST) -v -sweep=$(SWEEP) $(SWEEPARGS) @@ -32,8 +36,8 @@ websitefmtcheck: lint: @echo "==> Checking source code against linters..." - @golangci-lint run --no-config --deadline 5m --disable-all --enable staticcheck --exclude SA1019 --max-issues-per-linter 0 --max-same-issues 0 ./$(PKG_NAME) - @golangci-lint run ./$(PKG_NAME) + @golangci-lint run --no-config --deadline 5m --disable-all --enable staticcheck --exclude SA1019 --max-issues-per-linter 0 --max-same-issues 0 ./$(PKG_NAME)/... + @golangci-lint run ./$(PKG_NAME)/... @tfproviderlint \ -c 1 \ -AT001 \ @@ -87,5 +91,5 @@ ifeq (,$(wildcard $(GOPATH)/src/$(WEBSITE_REPO))) endif @$(MAKE) -C $(GOPATH)/src/$(WEBSITE_REPO) website-provider-test PROVIDER_PATH=$(shell pwd) PROVIDER_NAME=$(PKG_NAME) -.PHONY: build sweep test testacc fmt fmtcheck lint tools test-compile website website-lint website-test +.PHONY: build gen sweep test testacc fmt fmtcheck lint tools test-compile website website-lint website-test diff --git a/aws/internal/keyvaluetags/README.md b/aws/internal/keyvaluetags/README.md new file mode 100644 index 00000000000..127195a4369 --- /dev/null +++ b/aws/internal/keyvaluetags/README.md @@ -0,0 +1,28 @@ +# keyvaluetags + +The `keyvaluetags` package is designed to provide a consistent interface for handling AWS resource key-value tags. Many of the AWS Go SDK services, implement their own Go struct with `Key` and `Value` fields (e.g. `athena.Tag`) while others simply use a map (e.g. `map[string]string`). These inconsistent implementations and numerous Go types makes the process of correctly working with each of the services a tedius, previously copy-paste-modify process. + +This package instead implements a single `KeyValueTags` type, which covers all key-value handling logic such as merging tags and ignoring keys via functions on the single type. The underlying implementation is compatible with Go operations such as `len()`. + +Full documentation for this package can be found on [GoDoc](https://godoc.org/github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags). + +Many AWS Go SDK services that support tagging have their service-specific Go type conversion functions to and from `KeyValueTags` code generated. Converting from `KeyValueTags` to AWS Go SDK types is done via `{SERVICE}Tags()` functions on the type, while converting from AWS Go SDK types to the `KeyValueTags` type is done via `{SERVICE}KeyValueTags()` functions. For more information about this code generation, see the [`generators/servicetags` README](generators/servicetags/README.md). + +Some AWS Go SDK services that have common tag listing functionality (such as `ListTagsForResource` API call), also have auto-generated list functions. For more information about this code generation, see the [`generators/listtags` README](generators/listtags/README.md). + +Some AWS Go SDK services that have common tagging update functionality (such as `TagResource` and `UntagResource` API calls), also have auto-generated update functions. For more information about this code generation, see the [`generators/updatetags` README](generators/updatetags/README.md). + +## Code Structure + +```text +aws/internal/keyvaluetags +├── generators +│ ├── listtags (generates list_tags_gen.go) +│ ├── servicetags (generates service_tags_gen.go) +│ └── updatetags (generates update_tags_gen.go) +├── key_value_tags.go (core logic) +├── list_tags_gen.go (generated AWS Go SDK service list tag functions) +├── service_generation_customizations.go (shared AWS Go SDK service customizations for generators) +├── service_tags_gen.go (generated AWS Go SDK service conversion functions) +└── update_tags_gen.go (generated AWS Go SDK service tagging update functions) +``` diff --git a/aws/internal/keyvaluetags/generators/listtags/README.md b/aws/internal/keyvaluetags/generators/listtags/README.md new file mode 100644 index 00000000000..a26e28c06f6 --- /dev/null +++ b/aws/internal/keyvaluetags/generators/listtags/README.md @@ -0,0 +1,91 @@ +# listtags + +This package contains a code generator to consistently handle the various AWS Go SDK service implementations for listing resource tags. Not all AWS Go SDK services that support tagging are generated in this manner. + +To run this code generator, execute `go generate ./...` from the root of the repository. The general workflow for the generator is: + +- Generate Go file contents via template from local variables and functions +- Go format file contents +- Write file contents to `list_tags_gen.go` file + +## Example Output + +```go + +``` + +## Implementing a New Generated Service + +### Requirements + +Before a new service can be added to the generator, the new service must: + +- Have the `KeyValueTags` conversion functions implemented for the AWS Go SDK service type/map. See also the [`servicetags` generator README](../servicetags/README.md). +- Implement a function for listing resource tags (e.g. `ListTagsforResource`) +- Have the service included in `aws/internal/keyvaluetags/service_generation_customizations.go`, if not present the following compilation error will be seen: + +```text +2019/09/03 09:22:21 error executing template: template: listtags:19:41: executing "listtags" at : error calling ClientType: unrecognized ServiceClientType: acmpca +``` + +Once the service has met all the requirements, in `main.go`: + +- Add import for new service, e.g. `"github.com/aws/aws-sdk-go/service/athena"` +- Add service name to `serviceNames`, e.g. `athena` +- Run `go generate ./...` (or `make gen`) from the root of the repository to regenerate the code +- Run `go test ./...` (or `make test`) from the root of the repository to ensure the generated code compiles +- (Optional) Customize the service generation, if necessary (see below) + +### Customizations + +By default, the generator creates a `{SERVICE}ListTags()` function with the following structs and function calls: + +- `{SERVICE}.ListTagsForResourceInput` struct with `ResourceArn` field for calling `ListTagsForResource()` API call + +If these do not match the actual AWS Go SDK service implementation, the generated code will compile with errors. See the sections below for certain errors and how to handle them. + +#### ServiceListTagsFunction + +Given the following compilation error: + +```text +./list_tags_gen.go:183:12: undefined: backup.ListTagsForResourceInput +./list_tags_gen.go:187:21: conn.ListTagsForResource undefined (type *backup.Backup has no field or method ListTagsForResource) +``` + +The function for listing resource tags must be updated. Add an entry within the `ServiceListTagsFunction()` function of the generator to customize the naming of the `ListTagsForResource()` function and matching `ListTagsForResourceInput` struct. In the above case: + +```go +case "backup": + return "ListTags" +``` + +#### ServiceListTagsInputIdentifierField + +Given the following compilation error: + +```text +./list_tags_gen.go:1118:3: unknown field 'ResourceArn' in struct literal of type transfer.ListTagsForResourceInput +``` + +The field name to identify the resource for tag listing must be updated. Add an entry within the `ServiceListTagsInputIdentifierField()` function of the generator to customize the naming of the `ResourceArn` field for the list tags input struct. In the above case: + +```go +case "transfer": + return "Arn" +``` + +#### ServiceListTagsOutputTagsField + +Given the following compilation error: + +```text +./list_tags_gen.go:206:38: output.Tags undefined (type *cloudhsmv2.ListTagsOutput has no field or method Tags) +``` + +The field name of the tags from the tag listing must be updated. Add an entry within the `ServiceListTagsOutputTagsField()` function of the generator to customize the naming of the `Tags` field for the list tags output struct. In the above case: + +```go +case "cloudhsmv2": + return "TagList" +``` diff --git a/aws/internal/keyvaluetags/generators/listtags/main.go b/aws/internal/keyvaluetags/generators/listtags/main.go new file mode 100644 index 00000000000..778d4815df9 --- /dev/null +++ b/aws/internal/keyvaluetags/generators/listtags/main.go @@ -0,0 +1,311 @@ +// +build ignore + +package main + +import ( + "bytes" + "go/format" + "log" + "os" + "sort" + "strings" + "text/template" + + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" +) + +const filename = `list_tags_gen.go` + +var serviceNames = []string{ + "acmpca", + "amplify", + "appmesh", + "appstream", + "appsync", + "athena", + "backup", + "cloudhsmv2", + "cloudwatch", + "cloudwatchevents", + "codecommit", + "codedeploy", + "codepipeline", + "cognitoidentity", + "cognitoidentityprovider", + "configservice", + "databasemigrationservice", + "datasync", + "dax", + "devicefarm", + "directoryservice", + "docdb", + "dynamodb", + "ecr", + "ecs", + "efs", + "elasticache", + "elasticbeanstalk", + "elasticsearchservice", + "firehose", + "fsx", + "glue", + "guardduty", + "inspector", + "iot", + "iotanalytics", + "iotevents", + "kafka", + "kinesisanalytics", + "kinesisanalyticsv2", + "kms", + "lambda", + "licensemanager", + "mediaconnect", + "medialive", + "mediapackage", + "mediastore", + "mq", + "neptune", + "opsworks", + "organizations", + "rds", + "route53resolver", + "sagemaker", + "securityhub", + "sfn", + "sns", + "ssm", + "storagegateway", + "swf", + "transfer", + "workspaces", +} + +type TemplateData struct { + ServiceNames []string +} + +func main() { + // Always sort to reduce any potential generation churn + sort.Strings(serviceNames) + + templateData := TemplateData{ + ServiceNames: serviceNames, + } + templateFuncMap := template.FuncMap{ + "ClientType": keyvaluetags.ServiceClientType, + "ListTagsFunction": ServiceListTagsFunction, + "ListTagsInputIdentifierField": ServiceListTagsInputIdentifierField, + "ListTagsInputResourceTypeField": ServiceListTagsInputResourceTypeField, + "ListTagsOutputTagsField": ServiceListTagsOutputTagsField, + "Title": strings.Title, + } + + tmpl, err := template.New("listtags").Funcs(templateFuncMap).Parse(templateBody) + + if err != nil { + log.Fatalf("error parsing template: %s", err) + } + + var buffer bytes.Buffer + err = tmpl.Execute(&buffer, templateData) + + if err != nil { + log.Fatalf("error executing template: %s", err) + } + + generatedFileContents, err := format.Source(buffer.Bytes()) + + if err != nil { + log.Fatalf("error formatting generated file: %s", err) + } + + f, err := os.Create(filename) + + if err != nil { + log.Fatalf("error creating file (%s): %s", filename, err) + } + + defer f.Close() + + _, err = f.Write(generatedFileContents) + + if err != nil { + log.Fatalf("error writing to file (%s): %s", filename, err) + } +} + +var templateBody = ` +// Code generated by generators/listtags/main.go; DO NOT EDIT. + +package keyvaluetags + +import ( + "github.com/aws/aws-sdk-go/aws" +{{- range .ServiceNames }} + "github.com/aws/aws-sdk-go/service/{{ . }}" +{{- end }} +) +{{ range .ServiceNames }} + +// {{ . | Title }}ListTags lists {{ . }} service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func {{ . | Title }}ListTags(conn {{ . | ClientType }}, identifier string{{ if . | ListTagsInputResourceTypeField }}, resourceType string{{ end }}) (KeyValueTags, error) { + input := &{{ . }}.{{ . | ListTagsFunction }}Input{ + {{ . | ListTagsInputIdentifierField }}: aws.String(identifier), + {{- if . | ListTagsInputResourceTypeField }} + {{ . | ListTagsInputResourceTypeField }}: aws.String(resourceType), + {{- end }} + } + + output, err := conn.{{ . | ListTagsFunction }}(input) + + if err != nil { + return New(nil), err + } + + return {{ . | Title }}KeyValueTags(output.{{ . | ListTagsOutputTagsField }}), nil +} +{{- end }} +` + +// ServiceListTagsFunction determines the service tagging function. +func ServiceListTagsFunction(serviceName string) string { + switch serviceName { + case "acmpca": + return "ListTags" + case "backup": + return "ListTags" + case "cloudhsmv2": + return "ListTags" + case "dax": + return "ListTags" + case "dynamodb": + return "ListTagsOfResource" + case "efs": + return "DescribeTags" + case "elasticsearchservice": + return "ListTags" + case "firehose": + return "ListTagsForDeliveryStream" + case "glue": + return "GetTags" + case "kms": + return "ListResourceTags" + case "lambda": + return "ListTags" + case "mq": + return "ListTags" + case "opsworks": + return "ListTags" + case "redshift": + return "DescribeTags" + case "sagemaker": + return "ListTags" + case "workspaces": + return "DescribeTags" + default: + return "ListTagsForResource" + } +} + +// ServiceListTagsInputIdentifierField determines the service tag identifier field. +func ServiceListTagsInputIdentifierField(serviceName string) string { + switch serviceName { + case "acmpca": + return "CertificateAuthorityArn" + case "athena": + return "ResourceARN" + case "cloudhsmv2": + return "ResourceId" + case "cloudwatch": + return "ResourceARN" + case "cloudwatchevents": + return "ResourceARN" + case "dax": + return "ResourceName" + case "devicefarm": + return "ResourceARN" + case "directoryservice": + return "ResourceId" + case "docdb": + return "ResourceName" + case "efs": + return "FileSystemId" + case "elasticache": + return "ResourceName" + case "elasticsearchservice": + return "ARN" + case "firehose": + return "DeliveryStreamName" + case "fsx": + return "ResourceARN" + case "kinesisanalytics": + return "ResourceARN" + case "kinesisanalyticsv2": + return "ResourceARN" + case "kms": + return "KeyId" + case "lambda": + return "Resource" + case "mediastore": + return "Resource" + case "neptune": + return "ResourceName" + case "organizations": + return "ResourceId" + case "rds": + return "ResourceName" + case "redshift": + return "ResourceName" + case "ssm": + return "ResourceId" + case "storagegateway": + return "ResourceARN" + case "transfer": + return "Arn" + case "workspaces": + return "ResourceId" + default: + return "ResourceArn" + } +} + +// ServiceListTagsInputResourceTypeField determines the service tagging resource type field. +func ServiceListTagsInputResourceTypeField(serviceName string) string { + switch serviceName { + case "ssm": + return "ResourceType" + default: + return "" + } +} + +// ServiceListTagsOutputTagsField determines the service tag field. +func ServiceListTagsOutputTagsField(serviceName string) string { + switch serviceName { + case "cloudhsmv2": + return "TagList" + case "databasemigrationservice": + return "TagList" + case "docdb": + return "TagList" + case "elasticache": + return "TagList" + case "elasticbeanstalk": + return "ResourceTags" + case "elasticsearchservice": + return "TagList" + case "neptune": + return "TagList" + case "rds": + return "TagList" + case "ssm": + return "TagList" + case "workspaces": + return "TagList" + default: + return "Tags" + } +} diff --git a/aws/internal/keyvaluetags/generators/servicetags/README.md b/aws/internal/keyvaluetags/generators/servicetags/README.md new file mode 100644 index 00000000000..dc07d1e943a --- /dev/null +++ b/aws/internal/keyvaluetags/generators/servicetags/README.md @@ -0,0 +1,123 @@ +# updatetags + +This package contains a code generator to consistently handle the various AWS Go SDK service implementations for converting service tag/map types to/from `KeyValueTags`. Not all AWS Go SDK services that support tagging are generated in this manner. + +To run this code generator, execute `go generate ./...` from the root of the repository. The general workflow for the generator is: + +- Generate Go file contents via template from local variables and functions +- Go format file contents +- Write file contents to `service_tags_gen.go` file + +## Example Output + +For services with a specific Go type: + +```go +// AthenaTags returns athena service tags. +func (tags KeyValueTags) AthenaTags() []*athena.Tag { + result := make([]*athena.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &athena.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// AthenaKeyValueTags creates KeyValueTags from athena service tags. +func AthenaKeyValueTags(tags []*athena.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} +``` + +For services that implement a map instead: + +```go +// AmplifyTags returns amplify service tags. +func (tags KeyValueTags) AmplifyTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// AmplifyKeyValueTags creates KeyValueTags from amplify service tags. +func AmplifyKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} +``` + +## Implementing a New Generated Service + +- In `main.go`: Add service name, e.g. `athena`, to one of the implementation handlers + - Use `sliceServiceNames` if the AWS Go SDK service implements a specific Go type such as `Tag` + - Use `mapServiceNames` if the AWS Go SDK service implements `map[string]*string` +- Run `go generate ./...` (or `make gen`) from the root of the repository to regenerate the code +- Run `go test ./...` (or `make test`) from the root of the repository to ensure the generated code compiles +- (Optional, only for services with a specific Go type such as `Tag`) Customize the service generation, if necessary (see below) + +### Customizations + +By default, the generator creates `KeyValueTags.{SERVICE}Tags()` and `{SERVICE}KeyValueTags()` functions with the following expectations: + +- `Tag` struct with `Key` field and `Value` field + +If these do not match the actual AWS Go SDK service implementation, the generated code will compile with errors. See the sections below for certain errors and how to handle them. + +#### ServiceTagType + +Given the following compilation error: + +```text +aws/internal/keyvaluetags/service_tags_gen.go:397:43: undefined: appmesh.Tag +aws/internal/keyvaluetags/service_tags_gen.go:398:20: undefined: appmesh.Tag +aws/internal/keyvaluetags/service_tags_gen.go:401:11: undefined: appmesh.Tag +aws/internal/keyvaluetags/service_tags_gen.go:413:34: undefined: appmesh.Tag +``` + +The Go type that represents a tag must be updated. Add an entry within the `ServiceTagType()` function of the generator to customize the naming of the Go type. In the above case: + +```go +case "appmesh": + return "TagRef" +``` + +#### ServiceTagTypeKeyField + +Given the following compilation error: + +```text +aws/internal/keyvaluetags/service_tags_gen.go:1563:4: unknown field 'Key' in struct literal of type kms.Tag +aws/internal/keyvaluetags/service_tags_gen.go:1578:24: tag.Key undefined (type *kms.Tag has no field or method Key) +``` + +The field name to identify the tag key within the Go type for tagging must be updated. Add an entry within the `ServiceTagTypeKeyField` function of the generator to customize the naming of the `Key` field for the tagging Go type. In the above case: + +```go +case "kms": + return "TagKey" +``` + +#### ServiceTagTypeValueField + +Given the following compilation error: + +```text +aws/internal/keyvaluetags/service_tags_gen.go:1564:4: unknown field 'Value' in struct literal of type kms.Tag +aws/internal/keyvaluetags/service_tags_gen.go:1578:39: tag.Value undefined (type *kms.Tag has no field or method Value) +``` + +The field name to identify the tag value within the Go type for tagging must be updated. Add an entry within the `ServiceTagTypeValueField` function of the generator to customize the naming of the `Value` field for the tagging Go type. In the above case: + +```go +case "kms": + return "TagValue" +``` diff --git a/aws/internal/keyvaluetags/generators/servicetags/main.go b/aws/internal/keyvaluetags/generators/servicetags/main.go new file mode 100644 index 00000000000..ad81f7a4b05 --- /dev/null +++ b/aws/internal/keyvaluetags/generators/servicetags/main.go @@ -0,0 +1,267 @@ +// +build ignore + +package main + +import ( + "bytes" + "go/format" + "log" + "os" + "sort" + "strings" + "text/template" +) + +const filename = `service_tags_gen.go` + +// Representing types such as []*athena.Tag, []*ec2.Tag, ... +var sliceServiceNames = []string{ + "acm", + "acmpca", + "appmesh", + "athena", + /* "autoscaling", // includes extra PropagateAtLaunch, skip for now */ + "cloudformation", + "cloudfront", + "cloudhsmv2", + "cloudtrail", + "cloudwatch", + "cloudwatchevents", + "codebuild", + "codedeploy", + "codepipeline", + "configservice", + "databasemigrationservice", + "datapipeline", + "datasync", + "dax", + "devicefarm", + "directconnect", + "directoryservice", + "dlm", + "docdb", + "dynamodb", + "ec2", + "ecr", + "ecs", + "efs", + "elasticache", + "elasticbeanstalk", + "elasticsearchservice", + "elb", + "elbv2", + "emr", + "firehose", + "fms", + "fsx", + "iam", + "inspector", + "iot", + "iotanalytics", + "iotevents", + "kinesis", + "kinesisanalytics", + "kinesisanalyticsv2", + "kms", + "licensemanager", + "lightsail", + "mediastore", + "neptune", + "organizations", + "ram", + "rds", + "redshift", + "route53", + "route53resolver", + "s3", + "sagemaker", + "secretsmanager", + "serverlessapplicationrepository", + "servicecatalog", + "sfn", + "sns", + "ssm", + "storagegateway", + "swf", + "transfer", + "waf", + "workspaces", +} + +var mapServiceNames = []string{ + "amplify", + "apigateway", + "apigatewayv2", + "appstream", + "appsync", + "backup", + "batch", + "cloudwatchlogs", + "codecommit", + "cognitoidentity", + "cognitoidentityprovider", + "glacier", + "glue", + "guardduty", + "kafka", + "lambda", + "mediaconnect", + "mediaconvert", + "medialive", + "mediapackage", + "mq", + "opsworks", + "pinpoint", + "resourcegroups", + "securityhub", + "sqs", +} + +type TemplateData struct { + MapServiceNames []string + SliceServiceNames []string +} + +func main() { + // Always sort to reduce any potential generation churn + sort.Strings(mapServiceNames) + sort.Strings(sliceServiceNames) + + templateData := TemplateData{ + MapServiceNames: mapServiceNames, + SliceServiceNames: sliceServiceNames, + } + templateFuncMap := template.FuncMap{ + "TagType": ServiceTagType, + "TagTypeKeyField": ServiceTagTypeKeyField, + "TagTypeValueField": ServiceTagTypeValueField, + "Title": strings.Title, + } + + tmpl, err := template.New("servicetags").Funcs(templateFuncMap).Parse(templateBody) + + if err != nil { + log.Fatalf("error parsing template: %s", err) + } + + var buffer bytes.Buffer + err = tmpl.Execute(&buffer, templateData) + + if err != nil { + log.Fatalf("error executing template: %s", err) + } + + generatedFileContents, err := format.Source(buffer.Bytes()) + + if err != nil { + log.Fatalf("error formatting generated file: %s", err) + } + + f, err := os.Create(filename) + + if err != nil { + log.Fatalf("error creating file (%s): %s", filename, err) + } + + defer f.Close() + + _, err = f.Write(generatedFileContents) + + if err != nil { + log.Fatalf("error writing to file (%s): %s", filename, err) + } +} + +var templateBody = ` +// Code generated by generators/servicetags/main.go; DO NOT EDIT. + +package keyvaluetags + +import ( + "github.com/aws/aws-sdk-go/aws" +{{- range .SliceServiceNames }} + "github.com/aws/aws-sdk-go/service/{{ . }}" +{{- end }} +) + +// map[string]*string handling +{{- range .MapServiceNames }} + +// {{ . | Title }}Tags returns {{ . }} service tags. +func (tags KeyValueTags) {{ . | Title }}Tags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// {{ . | Title }}KeyValueTags creates KeyValueTags from {{ . }} service tags. +func {{ . | Title }}KeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} +{{- end }} + +// []*SERVICE.Tag handling +{{- range .SliceServiceNames }} + +// {{ . | Title }}Tags returns {{ . }} service tags. +func (tags KeyValueTags) {{ . | Title }}Tags() []*{{ . }}.{{ . | TagType }} { + result := make([]*{{ . }}.{{ . | TagType }}, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &{{ . }}.{{ . | TagType }}{ + {{ . | TagTypeKeyField }}: aws.String(k), + {{ . | TagTypeValueField }}: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// {{ . | Title }}KeyValueTags creates KeyValueTags from {{ . }} service tags. +func {{ . | Title }}KeyValueTags(tags []*{{ . }}.{{ . | TagType }}) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.{{ . | TagTypeKeyField }})] = tag.{{ . | TagTypeValueField }} + } + + return New(m) +} +{{- end }} +` + +// ServiceTagType determines the service tagging tag type. +func ServiceTagType(serviceName string) string { + switch serviceName { + case "appmesh": + return "TagRef" + case "datasync": + return "TagListEntry" + case "fms": + return "ResourceTag" + case "swf": + return "ResourceTag" + default: + return "Tag" + } +} + +// ServiceTagTypeKeyField determines the service tagging tag type key field. +func ServiceTagTypeKeyField(serviceName string) string { + switch serviceName { + case "kms": + return "TagKey" + default: + return "Key" + } +} + +// ServiceTagTypeValueField determines the service tagging tag type value field. +func ServiceTagTypeValueField(serviceName string) string { + switch serviceName { + case "kms": + return "TagValue" + default: + return "Value" + } +} diff --git a/aws/internal/keyvaluetags/generators/updatetags/README.md b/aws/internal/keyvaluetags/generators/updatetags/README.md new file mode 100644 index 00000000000..c18da86c3ce --- /dev/null +++ b/aws/internal/keyvaluetags/generators/updatetags/README.md @@ -0,0 +1,165 @@ +# updatetags + +This package contains a code generator to consistently handle the various AWS Go SDK service implementations for updating resource tags. Not all AWS Go SDK services that support tagging are generated in this manner. + +To run this code generator, execute `go generate ./...` from the root of the repository. The general workflow for the generator is: + +- Generate Go file contents via template from local variables and functions +- Go format file contents +- Write file contents to `update_tags_gen.go` file + +## Example Output + +```go +// AthenaUpdateTags updates athena service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func AthenaUpdateTags(conn *athena.Athena, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &athena.UntagResourceInput{ + ResourceARN: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &athena.TagResourceInput{ + ResourceARN: aws.String(identifier), + Tags: updatedTags.IgnoreAws().AthenaTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} +``` + +## Implementing a New Generated Service + +### Requirements + +Before a new service can be added to the generator, the new service must: + +- Have the `KeyValueTags` conversion functions implemented for the AWS Go SDK service type/map. See also the [`servicetags` generator README](../servicetags/README.md). +- Implement a function for tagging (e.g. `TagResource`) and a function for untagging via keys (e.g. `UntagResource`) +- Have the service included in `aws/internal/keyvaluetags/service_generation_customizations.go`, if not present the following compilation error will be seen: + +```text +2019/09/03 09:22:21 error executing template: template: listtags:19:41: executing "updatetags" at : error calling ClientType: unrecognized ServiceClientType: acmpca +``` + +Once the service has met all the requirements, in `main.go`: + +- Add import for new service, e.g. `"github.com/aws/aws-sdk-go/service/athena"` +- Add service name to `serviceNames`, e.g. `athena` +- Add reflection handling to `ServiceClientType()` function, e.g. + +```go +case "athena": + funcType = reflect.TypeOf(athena.New) +``` + +- Run `go generate ./...` (or `make gen`) from the root of the repository to regenerate the code +- Run `go test ./...` (or `make test`) from the root of the repository to ensure the generated code compiles +- (Optional) Customize the service generation, if necessary (see below) + +### Customizations + +By default, the generator creates a `{SERVICE}UpdateTags()` function with the following structs and function calls: + +- `{SERVICE}.TagResourceInput` struct with `ResourceArn` field and `Tags` field for calling `TagResource()` API call +- `{SERVICE}.UntagResourceInput` struct with `ResourceArn` field and `TagKeys` field for calling `UntagResource()` API call + +If these do not match the actual AWS Go SDK service implementation, the generated code will compile with errors. See the sections below for certain errors and how to handle them. + +#### ServiceTagFunction + +Given the following compilation error: + +```text +aws/internal/keyvaluetags/update_tags_gen.go:704:13: undefined: datapipeline.TagResourceInput +aws/internal/keyvaluetags/update_tags_gen.go:709:17: conn.TagResource undefined (type *datapipeline.DataPipeline has no field or method TagResource) +``` + +The function for resource tagging must be updated. Add an entry within the `ServiceTagFunction()` function of the generator to customize the naming of the `TagResource()` function and matching `TagResourceInput` struct. In the above case: + +```go +case "datapipeline": + return "AddTags" +``` + +#### ServiceTagInputIdentifierField + +Given the following compilation error: + +```text +aws/internal/keyvaluetags/update_tags_gen.go:296:4: unknown field 'ResourceArn' in struct literal of type athena.UntagResourceInput (but does have ResourceARN) +aws/internal/keyvaluetags/update_tags_gen.go:309:4: unknown field 'ResourceArn' in struct literal of type athena.TagResourceInput (but does have ResourceARN) +``` + +The field name to identify the resource for tagging must be updated. Add an entry within the `ServiceTagInputIdentifierField()` function of the generator to customize the naming of the `ResourceArn` field for the tagging and untagging input structs. In the above case: + +```go +case "athena": + return "ResourceARN" +``` + +#### ServiceTagInputTagsField + +Given the following compilation error: + +```text +aws/internal/keyvaluetags/update_tags_gen.go:382:4: unknown field 'Tags' in struct literal of type cloudhsmv2.TagResourceInput +``` + +The field name with the tags for tagging must be updated. Add an entry within the `ServiceTagInputTagsField()` function of the generator to customize the naming of the `Tags` field for the tagging input struct. In the above case: + +```go +case "cloudhsmv2": + return "TagList" +``` + +#### ServiceUntagFunction + +Given the following compilation error: + +```text +aws/internal/keyvaluetags/update_tags_gen.go:691:13: undefined: datapipeline.UntagResourceInput +aws/internal/keyvaluetags/update_tags_gen.go:696:17: conn.UntagResource undefined (type *datapipeline.DataPipeline has no field or method UntagResource) +``` + +The function for resource untagging must be updated. Add an entry within the `ServiceUntagFunction()` function of the generator to customize the naming of the `UntagResource()` function and matching `UntagResourceInput` struct. In the above case: + +```go +case "datapipeline": + return "RemoveTags" +``` + +#### ServiceUntagInputTagsField + +Given the following compilation error: + +```text +aws/internal/keyvaluetags/update_tags_gen.go:369:4: unknown field 'TagKeys' in struct literal of type cloudhsmv2.UntagResourceInput +``` + +The field name with the tag keys for untagging must be updated. Add an entry within the `ServiceUntagInputTagsField()` function of the generator to customize the naming of the `TagKeys` field for the untagging input struct. In the above case: + +```go +case "cloudhsmv2": + return "TagKeyList" +``` diff --git a/aws/internal/keyvaluetags/generators/updatetags/main.go b/aws/internal/keyvaluetags/generators/updatetags/main.go new file mode 100644 index 00000000000..8ff741e619e --- /dev/null +++ b/aws/internal/keyvaluetags/generators/updatetags/main.go @@ -0,0 +1,406 @@ +// +build ignore + +package main + +import ( + "bytes" + "go/format" + "log" + "os" + "sort" + "strings" + "text/template" + + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" +) + +const filename = `update_tags_gen.go` + +var serviceNames = []string{ + "amplify", + "apigateway", + "apigatewayv2", + "appmesh", + "appstream", + "appsync", + "athena", + "backup", + "cloudhsmv2", + "cloudwatch", + "cloudwatchevents", + "codecommit", + "codedeploy", + "codepipeline", + "cognitoidentity", + "cognitoidentityprovider", + "configservice", + "databasemigrationservice", + "datapipeline", + "datasync", + "dax", + "devicefarm", + "directconnect", + "directoryservice", + "docdb", + "dynamodb", + "ecr", + "ecs", + "efs", + "elasticache", + "elasticsearchservice", + "emr", + "firehose", + "fsx", + "glue", + "guardduty", + "iot", + "iotanalytics", + "iotevents", + "kafka", + "kinesisanalytics", + "kinesisanalyticsv2", + "kms", + "lambda", + "licensemanager", + "lightsail", + "mediaconnect", + "mediaconvert", + "medialive", + "mediapackage", + "mediastore", + "mq", + "neptune", + "opsworks", + "organizations", + "ram", + "rds", + "redshift", + "route53resolver", + "secretsmanager", + "securityhub", + "sfn", + "sns", + "ssm", + "storagegateway", + "swf", + "transfer", + "waf", + "workspaces", +} + +type TemplateData struct { + ServiceNames []string +} + +func main() { + // Always sort to reduce any potential generation churn + sort.Strings(serviceNames) + + templateData := TemplateData{ + ServiceNames: serviceNames, + } + templateFuncMap := template.FuncMap{ + "ClientType": keyvaluetags.ServiceClientType, + "TagFunction": ServiceTagFunction, + "TagInputIdentifierField": ServiceTagInputIdentifierField, + "TagInputResourceTypeField": ServiceTagInputResourceTypeField, + "TagInputTagsField": ServiceTagInputTagsField, + "Title": strings.Title, + "UntagFunction": ServiceUntagFunction, + "UntagInputTagsField": ServiceUntagInputTagsField, + } + + tmpl, err := template.New("updatetags").Funcs(templateFuncMap).Parse(templateBody) + + if err != nil { + log.Fatalf("error parsing template: %s", err) + } + + var buffer bytes.Buffer + err = tmpl.Execute(&buffer, templateData) + + if err != nil { + log.Fatalf("error executing template: %s", err) + } + + generatedFileContents, err := format.Source(buffer.Bytes()) + + if err != nil { + log.Fatalf("error formatting generated file: %s", err) + } + + f, err := os.Create(filename) + + if err != nil { + log.Fatalf("error creating file (%s): %s", filename, err) + } + + defer f.Close() + + _, err = f.Write(generatedFileContents) + + if err != nil { + log.Fatalf("error writing to file (%s): %s", filename, err) + } +} + +var templateBody = ` +// Code generated by generators/updatetags/main.go; DO NOT EDIT. + +package keyvaluetags + +import ( + "fmt" + + "github.com/aws/aws-sdk-go/aws" +{{- range .ServiceNames }} + "github.com/aws/aws-sdk-go/service/{{ . }}" +{{- end }} +) +{{ range .ServiceNames }} + +// {{ . | Title }}UpdateTags updates {{ . }} service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func {{ . | Title }}UpdateTags(conn {{ . | ClientType }}, identifier string{{ if . | TagInputResourceTypeField }}, resourceType string{{ end }}, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &{{ . }}.{{ . | UntagFunction }}Input{ + {{ . | TagInputIdentifierField }}: aws.String(identifier), + {{- if . | TagInputResourceTypeField }} + {{ . | TagInputResourceTypeField }}: aws.String(resourceType), + {{- end }} + {{ . | UntagInputTagsField }}: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.{{ . | UntagFunction }}(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &{{ . }}.{{ . | TagFunction }}Input{ + {{ . | TagInputIdentifierField }}: aws.String(identifier), + {{- if . | TagInputResourceTypeField }} + {{ . | TagInputResourceTypeField }}: aws.String(resourceType), + {{- end }} + {{ . | TagInputTagsField }}: updatedTags.IgnoreAws().{{ . | Title }}Tags(), + } + + _, err := conn.{{ . | TagFunction }}(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} +{{- end }} +` + +// ServiceTagFunction determines the service tagging function. +func ServiceTagFunction(serviceName string) string { + switch serviceName { + case "databasemigrationservice": + return "AddTagsToResource" + case "datapipeline": + return "AddTags" + case "directoryservice": + return "AddTagsToResource" + case "docdb": + return "AddTagsToResource" + case "efs": + return "CreateTags" + case "elasticache": + return "AddTagsToResource" + case "elasticsearchservice": + return "AddTags" + case "emr": + return "AddTags" + case "firehose": + return "TagDeliveryStream" + case "medialive": + return "CreateTags" + case "mq": + return "CreateTags" + case "neptune": + return "AddTagsToResource" + case "rds": + return "AddTagsToResource" + case "redshift": + return "CreateTags" + case "sagemaker": + return "AddTags" + case "ssm": + return "AddTagsToResource" + case "storagegateway": + return "AddTagsToResource" + case "workspaces": + return "CreateTags" + default: + return "TagResource" + } +} + +// ServiceTagInputIdentifierField determines the service tag identifier field. +func ServiceTagInputIdentifierField(serviceName string) string { + switch serviceName { + case "athena": + return "ResourceARN" + case "cloudhsmv2": + return "ResourceId" + case "cloudwatch": + return "ResourceARN" + case "cloudwatchevents": + return "ResourceARN" + case "datapipeline": + return "PipelineId" + case "dax": + return "ResourceName" + case "devicefarm": + return "ResourceARN" + case "directoryservice": + return "ResourceId" + case "docdb": + return "ResourceName" + case "efs": + return "FileSystemId" + case "elasticache": + return "ResourceName" + case "elasticsearchservice": + return "ARN" + case "emr": + return "ResourceId" + case "firehose": + return "DeliveryStreamName" + case "fsx": + return "ResourceARN" + case "kinesisanalytics": + return "ResourceARN" + case "kinesisanalyticsv2": + return "ResourceARN" + case "kms": + return "KeyId" + case "lambda": + return "Resource" + case "lightsail": + return "ResourceName" + case "mediaconvert": + return "Arn" + case "mediastore": + return "Resource" + case "neptune": + return "ResourceName" + case "organizations": + return "ResourceId" + case "ram": + return "ResourceShareArn" + case "rds": + return "ResourceName" + case "redshift": + return "ResourceName" + case "secretsmanager": + return "SecretId" + case "ssm": + return "ResourceId" + case "storagegateway": + return "ResourceARN" + case "transfer": + return "Arn" + case "waf": + return "ResourceARN" + case "workspaces": + return "ResourceId" + default: + return "ResourceArn" + } +} + +// ServiceTagInputTagsField determines the service tagging tags field. +func ServiceTagInputTagsField(serviceName string) string { + switch serviceName { + case "cloudhsmv2": + return "TagList" + case "elasticsearchservice": + return "TagList" + case "glue": + return "TagsToAdd" + default: + return "Tags" + } +} + +// ServiceTagInputResourceTypeField determines the service tagging resource type field. +func ServiceTagInputResourceTypeField(serviceName string) string { + switch serviceName { + case "ssm": + return "ResourceType" + default: + return "" + } +} + +// ServiceUntagFunction determines the service untagging function. +func ServiceUntagFunction(serviceName string) string { + switch serviceName { + case "databasemigrationservice": + return "RemoveTagsFromResource" + case "datapipeline": + return "RemoveTags" + case "directoryservice": + return "RemoveTagsFromResource" + case "docdb": + return "RemoveTagsFromResource" + case "efs": + return "DeleteTags" + case "elasticache": + return "RemoveTagsFromResource" + case "elasticsearchservice": + return "RemoveTags" + case "emr": + return "RemoveTags" + case "firehose": + return "UntagDeliveryStream" + case "medialive": + return "DeleteTags" + case "mq": + return "DeleteTags" + case "neptune": + return "RemoveTagsFromResource" + case "rds": + return "RemoveTagsFromResource" + case "redshift": + return "DeleteTags" + case "sagemaker": + return "DeleteTags" + case "ssm": + return "RemoveTagsFromResource" + case "storagegateway": + return "RemoveTagsFromResource" + case "workspaces": + return "DeleteTags" + default: + return "UntagResource" + } +} + +// ServiceUntagInputTagsField determines the service untagging tags field. +func ServiceUntagInputTagsField(serviceName string) string { + switch serviceName { + case "backup": + return "TagKeyList" + case "cloudhsmv2": + return "TagKeyList" + case "datasync": + return "Keys" + case "glue": + return "TagsToRemove" + default: + return "TagKeys" + } +} diff --git a/aws/internal/keyvaluetags/key_value_tags.go b/aws/internal/keyvaluetags/key_value_tags.go new file mode 100644 index 00000000000..6e618788596 --- /dev/null +++ b/aws/internal/keyvaluetags/key_value_tags.go @@ -0,0 +1,171 @@ +//go:generate go run generators/listtags/main.go +//go:generate go run generators/servicetags/main.go +//go:generate go run generators/updatetags/main.go + +package keyvaluetags + +import ( + "strings" +) + +const AwsTagKeyPrefix = `aws:` +const ElasticbeanstalkTagKeyPrefix = `elasticbeanstalk:` +const NameTagKey = `Name` + +// KeyValueTags is a standard implementation for AWS key-value resource tags. +// The AWS Go SDK is split into multiple service packages, each service with +// its own Go struct type representing a resource tag. To standardize logic +// across all these Go types, we convert them into this Go type. +type KeyValueTags map[string]*string + +// IgnoreAws returns non-AWS tag keys. +func (tags KeyValueTags) IgnoreAws() KeyValueTags { + result := make(KeyValueTags) + + for k, v := range tags { + if !strings.HasPrefix(k, AwsTagKeyPrefix) { + result[k] = v + } + } + + return result +} + +// IgnoreAws returns non-AWS and non-Elasticbeanstalk tag keys. +func (tags KeyValueTags) IgnoreElasticbeanstalk() KeyValueTags { + result := make(KeyValueTags) + + for k, v := range tags { + if strings.HasPrefix(k, AwsTagKeyPrefix) { + continue + } + + if strings.HasPrefix(k, ElasticbeanstalkTagKeyPrefix) { + continue + } + + if k == NameTagKey { + continue + } + + result[k] = v + } + + return result +} + +// Ignore returns non-matching tag keys. +func (tags KeyValueTags) Ignore(ignoreTags KeyValueTags) KeyValueTags { + result := make(KeyValueTags) + + for k, v := range tags { + if _, ok := ignoreTags[k]; ok { + continue + } + + result[k] = v + } + + return result +} + +// Keys returns tag keys. +func (tags KeyValueTags) Keys() []string { + result := make([]string, 0, len(tags)) + + for k := range tags { + result = append(result, k) + } + + return result +} + +// Map returns tag keys mapped to their values. +func (tags KeyValueTags) Map() map[string]string { + result := make(map[string]string, len(tags)) + + for k, v := range tags { + result[k] = *v + } + + return result +} + +// Merge adds missing and updates existing tags. +func (tags KeyValueTags) Merge(mergeTags KeyValueTags) KeyValueTags { + result := make(KeyValueTags) + + for k, v := range tags { + result[k] = v + } + + for k, v := range mergeTags { + result[k] = v + } + + return result +} + +// Removed returns tags removed. +func (tags KeyValueTags) Removed(newTags KeyValueTags) KeyValueTags { + result := make(KeyValueTags) + + for k, v := range tags { + if _, ok := newTags[k]; !ok { + result[k] = v + } + } + + return result +} + +// Updated returns tags added and updated. +func (tags KeyValueTags) Updated(newTags KeyValueTags) KeyValueTags { + result := make(KeyValueTags) + + for k, newV := range newTags { + if oldV, ok := tags[k]; !ok || *oldV != *newV { + result[k] = newV + } + } + + return result +} + +// New creates KeyValueTags from common Terraform Provider SDK types. +// Supports map[string]string, map[string]*string, map[string]interface{}, and []interface{}. +// When passed []interface{}, all elements are treated as keys and assigned nil values. +func New(i interface{}) KeyValueTags { + switch value := i.(type) { + case map[string]string: + kvtm := make(KeyValueTags, len(value)) + + for k, v := range value { + str := v // Prevent referencing issues + kvtm[k] = &str + } + + return kvtm + case map[string]*string: + return KeyValueTags(value) + case map[string]interface{}: + kvtm := make(KeyValueTags, len(value)) + + for k, v := range value { + str := v.(string) + kvtm[k] = &str + } + + return kvtm + case []interface{}: + kvtm := make(KeyValueTags, len(value)) + + for _, v := range value { + kvtm[v.(string)] = nil + } + + return kvtm + default: + return make(KeyValueTags) + } +} diff --git a/aws/internal/keyvaluetags/key_value_tags_test.go b/aws/internal/keyvaluetags/key_value_tags_test.go new file mode 100644 index 00000000000..91865710a72 --- /dev/null +++ b/aws/internal/keyvaluetags/key_value_tags_test.go @@ -0,0 +1,581 @@ +package keyvaluetags + +import ( + "testing" +) + +func TestKeyValueTagsIgnoreAws(t *testing.T) { + testCases := []struct { + name string + tags KeyValueTags + want map[string]string + }{ + { + name: "empty", + tags: New(map[string]string{}), + want: map[string]string{}, + }, + { + name: "all", + tags: New(map[string]string{ + "aws:cloudformation:key1": "value1", + "aws:cloudformation:key2": "value2", + "aws:cloudformation:key3": "value3", + }), + want: map[string]string{}, + }, + { + name: "mixed", + tags: New(map[string]string{ + "aws:cloudformation:key1": "value1", + "key2": "value2", + "key3": "value3", + }), + want: map[string]string{ + "key2": "value2", + "key3": "value3", + }, + }, + { + name: "none", + tags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + want: map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := testCase.tags.IgnoreAws() + + testKeyValueTagsVerifyMap(t, got.Map(), testCase.want) + }) + } +} + +func TestKeyValueTagsIgnoreElasticbeanstalk(t *testing.T) { + testCases := []struct { + name string + tags KeyValueTags + want map[string]string + }{ + { + name: "empty", + tags: New(map[string]string{}), + want: map[string]string{}, + }, + { + name: "all", + tags: New(map[string]string{ + "aws:cloudformation:key1": "value1", + "elasticbeanstalk:key2": "value2", + "Name": "value3", + }), + want: map[string]string{}, + }, + { + name: "mixed", + tags: New(map[string]string{ + "aws:cloudformation:key1": "value1", + "key2": "value2", + "elasticbeanstalk:key3": "value3", + "key4": "value4", + "Name": "value5", + }), + want: map[string]string{ + "key2": "value2", + "key4": "value4", + }, + }, + { + name: "none", + tags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + want: map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := testCase.tags.IgnoreElasticbeanstalk() + + testKeyValueTagsVerifyMap(t, got.Map(), testCase.want) + }) + } +} + +func TestKeyValueTagsIgnore(t *testing.T) { + testCases := []struct { + name string + tags KeyValueTags + ignoreTags KeyValueTags + want map[string]string + }{ + { + name: "empty", + tags: New(map[string]string{}), + ignoreTags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + want: map[string]string{}, + }, + { + name: "all", + tags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + ignoreTags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + want: map[string]string{}, + }, + { + name: "mixed", + tags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + ignoreTags: New(map[string]string{ + "key1": "value1", + }), + want: map[string]string{ + "key2": "value2", + "key3": "value3", + }, + }, + { + name: "none", + tags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + ignoreTags: New(map[string]string{ + "key4": "value4", + "key5": "value5", + "key6": "value6", + }), + want: map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := testCase.tags.Ignore(testCase.ignoreTags) + + testKeyValueTagsVerifyMap(t, got.Map(), testCase.want) + }) + } +} + +func TestKeyValueTagsKeys(t *testing.T) { + testCases := []struct { + name string + tags KeyValueTags + want []string + }{ + { + name: "empty", + tags: New(map[string]string{}), + want: []string{}, + }, + { + name: "non_empty", + tags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + want: []string{ + "key1", + "key2", + "key3", + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := testCase.tags.Keys() + + testKeyValueTagsVerifyKeys(t, got, testCase.want) + }) + } +} + +func TestKeyValueTagsMap(t *testing.T) { + testCases := []struct { + name string + tags KeyValueTags + want map[string]string + }{ + { + name: "empty_map_string_interface", + tags: New(map[string]interface{}{}), + want: map[string]string{}, + }, + { + name: "empty_map_string_string", + tags: New(map[string]string{}), + want: map[string]string{}, + }, + { + name: "empty_map_string_stringPointer", + tags: New(map[string]*string{}), + want: map[string]string{}, + }, + { + name: "non_empty_map_string_interface", + tags: New(map[string]interface{}{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + want: map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }, + }, + { + name: "non_empty_map_string_string", + tags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + want: map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }, + }, + { + name: "non_empty_map_string_stringPointer", + tags: New(map[string]*string{ + "key1": testStringPtr("value1"), + "key2": testStringPtr("value2"), + "key3": testStringPtr("value3"), + }), + want: map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := testCase.tags.Map() + + testKeyValueTagsVerifyMap(t, got, testCase.want) + }) + } +} + +func TestKeyValueTagsMerge(t *testing.T) { + testCases := []struct { + name string + tags KeyValueTags + mergeTags KeyValueTags + want map[string]string + }{ + { + name: "empty", + tags: New(map[string]string{}), + mergeTags: New(map[string]string{}), + want: map[string]string{}, + }, + { + name: "add_all", + tags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + mergeTags: New(map[string]string{ + "key4": "value4", + "key5": "value5", + "key6": "value6", + }), + want: map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + "key4": "value4", + "key5": "value5", + "key6": "value6", + }, + }, + { + name: "mixed", + tags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + mergeTags: New(map[string]string{ + "key1": "value1updated", + "key4": "value4", + }), + want: map[string]string{ + "key1": "value1updated", + "key2": "value2", + "key3": "value3", + "key4": "value4", + }, + }, + { + name: "update_all", + tags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + mergeTags: New(map[string]string{ + "key1": "value1updated", + "key2": "value2updated", + "key3": "value3updated", + }), + want: map[string]string{ + "key1": "value1updated", + "key2": "value2updated", + "key3": "value3updated", + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := testCase.tags.Merge(testCase.mergeTags) + + testKeyValueTagsVerifyMap(t, got.Map(), testCase.want) + }) + } +} + +func TestKeyValueTagsRemoved(t *testing.T) { + testCases := []struct { + name string + oldTags KeyValueTags + newTags KeyValueTags + want map[string]string + }{ + { + name: "empty", + oldTags: New(map[string]string{}), + newTags: New(map[string]string{}), + want: map[string]string{}, + }, + { + name: "all_new", + oldTags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + newTags: New(map[string]string{ + "key4": "value4", + "key5": "value5", + "key6": "value6", + }), + want: map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }, + }, + { + name: "mixed", + oldTags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + newTags: New(map[string]string{ + "key1": "value1", + }), + want: map[string]string{ + "key2": "value2", + "key3": "value3", + }, + }, + { + name: "no_changes", + oldTags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + newTags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + want: map[string]string{}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := testCase.oldTags.Removed(testCase.newTags) + + testKeyValueTagsVerifyMap(t, got.Map(), testCase.want) + }) + } +} + +func TestKeyValueTagsUpdated(t *testing.T) { + testCases := []struct { + name string + oldTags KeyValueTags + newTags KeyValueTags + want map[string]string + }{ + { + name: "empty", + oldTags: New(map[string]string{}), + newTags: New(map[string]string{}), + want: map[string]string{}, + }, + { + name: "all_new", + oldTags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + newTags: New(map[string]string{ + "key4": "value4", + "key5": "value5", + "key6": "value6", + }), + want: map[string]string{ + "key4": "value4", + "key5": "value5", + "key6": "value6", + }, + }, + { + name: "mixed", + oldTags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + newTags: New(map[string]string{ + "key1": "value1updated", + "key4": "value4", + }), + want: map[string]string{ + "key1": "value1updated", + "key4": "value4", + }, + }, + { + name: "no_changes", + oldTags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + newTags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + want: map[string]string{}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := testCase.oldTags.Updated(testCase.newTags) + + testKeyValueTagsVerifyMap(t, got.Map(), testCase.want) + }) + } +} + +func testKeyValueTagsVerifyKeys(t *testing.T, got []string, want []string) { + for _, g := range got { + found := false + + for _, w := range want { + if w == g { + found = true + break + } + } + + if !found { + t.Errorf("got extra key: %s", g) + } + } + + for _, w := range want { + found := false + + for _, g := range got { + if g == w { + found = true + break + } + } + + if !found { + t.Errorf("want missing key: %s", w) + } + } +} + +func testKeyValueTagsVerifyMap(t *testing.T, got map[string]string, want map[string]string) { + for k, wantV := range want { + gotV, ok := got[k] + + if !ok { + t.Errorf("want missing key: %s", k) + continue + } + + if gotV != wantV { + t.Errorf("got key (%s) value %s; want value %s", k, gotV, wantV) + } + } + + for k := range got { + if _, ok := want[k]; !ok { + t.Errorf("got extra key: %s", k) + } + } +} + +func testStringPtr(str string) *string { + return &str +} diff --git a/aws/internal/keyvaluetags/list_tags_gen.go b/aws/internal/keyvaluetags/list_tags_gen.go new file mode 100644 index 00000000000..43ba5c20c60 --- /dev/null +++ b/aws/internal/keyvaluetags/list_tags_gen.go @@ -0,0 +1,1124 @@ +// Code generated by generators/listtags/main.go; DO NOT EDIT. + +package keyvaluetags + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/acmpca" + "github.com/aws/aws-sdk-go/service/amplify" + "github.com/aws/aws-sdk-go/service/appmesh" + "github.com/aws/aws-sdk-go/service/appstream" + "github.com/aws/aws-sdk-go/service/appsync" + "github.com/aws/aws-sdk-go/service/athena" + "github.com/aws/aws-sdk-go/service/backup" + "github.com/aws/aws-sdk-go/service/cloudhsmv2" + "github.com/aws/aws-sdk-go/service/cloudwatch" + "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "github.com/aws/aws-sdk-go/service/codecommit" + "github.com/aws/aws-sdk-go/service/codedeploy" + "github.com/aws/aws-sdk-go/service/codepipeline" + "github.com/aws/aws-sdk-go/service/cognitoidentity" + "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" + "github.com/aws/aws-sdk-go/service/configservice" + "github.com/aws/aws-sdk-go/service/databasemigrationservice" + "github.com/aws/aws-sdk-go/service/datasync" + "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/docdb" + "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/aws/aws-sdk-go/service/ecr" + "github.com/aws/aws-sdk-go/service/ecs" + "github.com/aws/aws-sdk-go/service/efs" + "github.com/aws/aws-sdk-go/service/elasticache" + "github.com/aws/aws-sdk-go/service/elasticbeanstalk" + "github.com/aws/aws-sdk-go/service/elasticsearchservice" + "github.com/aws/aws-sdk-go/service/firehose" + "github.com/aws/aws-sdk-go/service/fsx" + "github.com/aws/aws-sdk-go/service/glue" + "github.com/aws/aws-sdk-go/service/guardduty" + "github.com/aws/aws-sdk-go/service/inspector" + "github.com/aws/aws-sdk-go/service/iot" + "github.com/aws/aws-sdk-go/service/iotanalytics" + "github.com/aws/aws-sdk-go/service/iotevents" + "github.com/aws/aws-sdk-go/service/kafka" + "github.com/aws/aws-sdk-go/service/kinesisanalytics" + "github.com/aws/aws-sdk-go/service/kinesisanalyticsv2" + "github.com/aws/aws-sdk-go/service/kms" + "github.com/aws/aws-sdk-go/service/lambda" + "github.com/aws/aws-sdk-go/service/licensemanager" + "github.com/aws/aws-sdk-go/service/mediaconnect" + "github.com/aws/aws-sdk-go/service/medialive" + "github.com/aws/aws-sdk-go/service/mediapackage" + "github.com/aws/aws-sdk-go/service/mediastore" + "github.com/aws/aws-sdk-go/service/mq" + "github.com/aws/aws-sdk-go/service/neptune" + "github.com/aws/aws-sdk-go/service/opsworks" + "github.com/aws/aws-sdk-go/service/organizations" + "github.com/aws/aws-sdk-go/service/rds" + "github.com/aws/aws-sdk-go/service/route53resolver" + "github.com/aws/aws-sdk-go/service/sagemaker" + "github.com/aws/aws-sdk-go/service/securityhub" + "github.com/aws/aws-sdk-go/service/sfn" + "github.com/aws/aws-sdk-go/service/sns" + "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go/service/storagegateway" + "github.com/aws/aws-sdk-go/service/swf" + "github.com/aws/aws-sdk-go/service/transfer" + "github.com/aws/aws-sdk-go/service/workspaces" +) + +// AcmpcaListTags lists acmpca service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func AcmpcaListTags(conn *acmpca.ACMPCA, identifier string) (KeyValueTags, error) { + input := &acmpca.ListTagsInput{ + CertificateAuthorityArn: aws.String(identifier), + } + + output, err := conn.ListTags(input) + + if err != nil { + return New(nil), err + } + + return AcmpcaKeyValueTags(output.Tags), nil +} + +// AmplifyListTags lists amplify service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func AmplifyListTags(conn *amplify.Amplify, identifier string) (KeyValueTags, error) { + input := &lify.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return AmplifyKeyValueTags(output.Tags), nil +} + +// AppmeshListTags lists appmesh service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func AppmeshListTags(conn *appmesh.AppMesh, identifier string) (KeyValueTags, error) { + input := &appmesh.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return AppmeshKeyValueTags(output.Tags), nil +} + +// AppstreamListTags lists appstream service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func AppstreamListTags(conn *appstream.AppStream, identifier string) (KeyValueTags, error) { + input := &appstream.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return AppstreamKeyValueTags(output.Tags), nil +} + +// AppsyncListTags lists appsync service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func AppsyncListTags(conn *appsync.AppSync, identifier string) (KeyValueTags, error) { + input := &appsync.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return AppsyncKeyValueTags(output.Tags), nil +} + +// AthenaListTags lists athena service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func AthenaListTags(conn *athena.Athena, identifier string) (KeyValueTags, error) { + input := &athena.ListTagsForResourceInput{ + ResourceARN: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return AthenaKeyValueTags(output.Tags), nil +} + +// BackupListTags lists backup service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func BackupListTags(conn *backup.Backup, identifier string) (KeyValueTags, error) { + input := &backup.ListTagsInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTags(input) + + if err != nil { + return New(nil), err + } + + return BackupKeyValueTags(output.Tags), nil +} + +// Cloudhsmv2ListTags lists cloudhsmv2 service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func Cloudhsmv2ListTags(conn *cloudhsmv2.CloudHSMV2, identifier string) (KeyValueTags, error) { + input := &cloudhsmv2.ListTagsInput{ + ResourceId: aws.String(identifier), + } + + output, err := conn.ListTags(input) + + if err != nil { + return New(nil), err + } + + return Cloudhsmv2KeyValueTags(output.TagList), nil +} + +// CloudwatchListTags lists cloudwatch service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func CloudwatchListTags(conn *cloudwatch.CloudWatch, identifier string) (KeyValueTags, error) { + input := &cloudwatch.ListTagsForResourceInput{ + ResourceARN: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return CloudwatchKeyValueTags(output.Tags), nil +} + +// CloudwatcheventsListTags lists cloudwatchevents service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func CloudwatcheventsListTags(conn *cloudwatchevents.CloudWatchEvents, identifier string) (KeyValueTags, error) { + input := &cloudwatchevents.ListTagsForResourceInput{ + ResourceARN: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return CloudwatcheventsKeyValueTags(output.Tags), nil +} + +// CodecommitListTags lists codecommit service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func CodecommitListTags(conn *codecommit.CodeCommit, identifier string) (KeyValueTags, error) { + input := &codecommit.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return CodecommitKeyValueTags(output.Tags), nil +} + +// CodedeployListTags lists codedeploy service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func CodedeployListTags(conn *codedeploy.CodeDeploy, identifier string) (KeyValueTags, error) { + input := &codedeploy.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return CodedeployKeyValueTags(output.Tags), nil +} + +// CodepipelineListTags lists codepipeline service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func CodepipelineListTags(conn *codepipeline.CodePipeline, identifier string) (KeyValueTags, error) { + input := &codepipeline.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return CodepipelineKeyValueTags(output.Tags), nil +} + +// CognitoidentityListTags lists cognitoidentity service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func CognitoidentityListTags(conn *cognitoidentity.CognitoIdentity, identifier string) (KeyValueTags, error) { + input := &cognitoidentity.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return CognitoidentityKeyValueTags(output.Tags), nil +} + +// CognitoidentityproviderListTags lists cognitoidentityprovider service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func CognitoidentityproviderListTags(conn *cognitoidentityprovider.CognitoIdentityProvider, identifier string) (KeyValueTags, error) { + input := &cognitoidentityprovider.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return CognitoidentityproviderKeyValueTags(output.Tags), nil +} + +// ConfigserviceListTags lists configservice service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func ConfigserviceListTags(conn *configservice.ConfigService, identifier string) (KeyValueTags, error) { + input := &configservice.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return ConfigserviceKeyValueTags(output.Tags), nil +} + +// DatabasemigrationserviceListTags lists databasemigrationservice service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func DatabasemigrationserviceListTags(conn *databasemigrationservice.DatabaseMigrationService, identifier string) (KeyValueTags, error) { + input := &databasemigrationservice.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return DatabasemigrationserviceKeyValueTags(output.TagList), nil +} + +// DatasyncListTags lists datasync service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func DatasyncListTags(conn *datasync.DataSync, identifier string) (KeyValueTags, error) { + input := &datasync.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return DatasyncKeyValueTags(output.Tags), nil +} + +// DaxListTags lists dax service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func DaxListTags(conn *dax.DAX, identifier string) (KeyValueTags, error) { + input := &dax.ListTagsInput{ + ResourceName: aws.String(identifier), + } + + output, err := conn.ListTags(input) + + if err != nil { + return New(nil), err + } + + return DaxKeyValueTags(output.Tags), nil +} + +// DevicefarmListTags lists devicefarm service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func DevicefarmListTags(conn *devicefarm.DeviceFarm, identifier string) (KeyValueTags, error) { + input := &devicefarm.ListTagsForResourceInput{ + ResourceARN: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return DevicefarmKeyValueTags(output.Tags), nil +} + +// DirectoryserviceListTags lists directoryservice service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func DirectoryserviceListTags(conn *directoryservice.DirectoryService, identifier string) (KeyValueTags, error) { + input := &directoryservice.ListTagsForResourceInput{ + ResourceId: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return DirectoryserviceKeyValueTags(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. +func DocdbListTags(conn *docdb.DocDB, identifier string) (KeyValueTags, error) { + input := &docdb.ListTagsForResourceInput{ + ResourceName: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return DocdbKeyValueTags(output.TagList), nil +} + +// DynamodbListTags lists dynamodb service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func DynamodbListTags(conn *dynamodb.DynamoDB, identifier string) (KeyValueTags, error) { + input := &dynamodb.ListTagsOfResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsOfResource(input) + + if err != nil { + return New(nil), err + } + + return DynamodbKeyValueTags(output.Tags), nil +} + +// EcrListTags lists ecr service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func EcrListTags(conn *ecr.ECR, identifier string) (KeyValueTags, error) { + input := &ecr.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return EcrKeyValueTags(output.Tags), nil +} + +// EcsListTags lists ecs service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func EcsListTags(conn *ecs.ECS, identifier string) (KeyValueTags, error) { + input := &ecs.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return EcsKeyValueTags(output.Tags), nil +} + +// EfsListTags lists efs service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func EfsListTags(conn *efs.EFS, identifier string) (KeyValueTags, error) { + input := &efs.DescribeTagsInput{ + FileSystemId: aws.String(identifier), + } + + output, err := conn.DescribeTags(input) + + if err != nil { + return New(nil), err + } + + return EfsKeyValueTags(output.Tags), nil +} + +// ElasticacheListTags lists elasticache service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func ElasticacheListTags(conn *elasticache.ElastiCache, identifier string) (KeyValueTags, error) { + input := &elasticache.ListTagsForResourceInput{ + ResourceName: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return ElasticacheKeyValueTags(output.TagList), nil +} + +// ElasticbeanstalkListTags lists elasticbeanstalk service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func ElasticbeanstalkListTags(conn *elasticbeanstalk.ElasticBeanstalk, identifier string) (KeyValueTags, error) { + input := &elasticbeanstalk.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return ElasticbeanstalkKeyValueTags(output.ResourceTags), nil +} + +// ElasticsearchserviceListTags lists elasticsearchservice service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func ElasticsearchserviceListTags(conn *elasticsearchservice.ElasticsearchService, identifier string) (KeyValueTags, error) { + input := &elasticsearchservice.ListTagsInput{ + ARN: aws.String(identifier), + } + + output, err := conn.ListTags(input) + + if err != nil { + return New(nil), err + } + + return ElasticsearchserviceKeyValueTags(output.TagList), nil +} + +// FirehoseListTags lists firehose service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func FirehoseListTags(conn *firehose.Firehose, identifier string) (KeyValueTags, error) { + input := &firehose.ListTagsForDeliveryStreamInput{ + DeliveryStreamName: aws.String(identifier), + } + + output, err := conn.ListTagsForDeliveryStream(input) + + if err != nil { + return New(nil), err + } + + return FirehoseKeyValueTags(output.Tags), nil +} + +// FsxListTags lists fsx service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func FsxListTags(conn *fsx.FSx, identifier string) (KeyValueTags, error) { + input := &fsx.ListTagsForResourceInput{ + ResourceARN: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return FsxKeyValueTags(output.Tags), nil +} + +// GlueListTags lists glue service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func GlueListTags(conn *glue.Glue, identifier string) (KeyValueTags, error) { + input := &glue.GetTagsInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.GetTags(input) + + if err != nil { + return New(nil), err + } + + return GlueKeyValueTags(output.Tags), nil +} + +// GuarddutyListTags lists guardduty service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func GuarddutyListTags(conn *guardduty.GuardDuty, identifier string) (KeyValueTags, error) { + input := &guardduty.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return GuarddutyKeyValueTags(output.Tags), nil +} + +// InspectorListTags lists inspector service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func InspectorListTags(conn *inspector.Inspector, identifier string) (KeyValueTags, error) { + input := &inspector.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return InspectorKeyValueTags(output.Tags), nil +} + +// IotListTags lists iot service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func IotListTags(conn *iot.IoT, identifier string) (KeyValueTags, error) { + input := &iot.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return IotKeyValueTags(output.Tags), nil +} + +// IotanalyticsListTags lists iotanalytics service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func IotanalyticsListTags(conn *iotanalytics.IoTAnalytics, identifier string) (KeyValueTags, error) { + input := &iotanalytics.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return IotanalyticsKeyValueTags(output.Tags), nil +} + +// IoteventsListTags lists iotevents service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func IoteventsListTags(conn *iotevents.IoTEvents, identifier string) (KeyValueTags, error) { + input := &iotevents.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return IoteventsKeyValueTags(output.Tags), nil +} + +// KafkaListTags lists kafka service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func KafkaListTags(conn *kafka.Kafka, identifier string) (KeyValueTags, error) { + input := &kafka.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return KafkaKeyValueTags(output.Tags), nil +} + +// KinesisanalyticsListTags lists kinesisanalytics service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func KinesisanalyticsListTags(conn *kinesisanalytics.KinesisAnalytics, identifier string) (KeyValueTags, error) { + input := &kinesisanalytics.ListTagsForResourceInput{ + ResourceARN: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return KinesisanalyticsKeyValueTags(output.Tags), nil +} + +// Kinesisanalyticsv2ListTags lists kinesisanalyticsv2 service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func Kinesisanalyticsv2ListTags(conn *kinesisanalyticsv2.KinesisAnalyticsV2, identifier string) (KeyValueTags, error) { + input := &kinesisanalyticsv2.ListTagsForResourceInput{ + ResourceARN: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return Kinesisanalyticsv2KeyValueTags(output.Tags), nil +} + +// KmsListTags lists kms service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func KmsListTags(conn *kms.KMS, identifier string) (KeyValueTags, error) { + input := &kms.ListResourceTagsInput{ + KeyId: aws.String(identifier), + } + + output, err := conn.ListResourceTags(input) + + if err != nil { + return New(nil), err + } + + return KmsKeyValueTags(output.Tags), nil +} + +// LambdaListTags lists lambda service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func LambdaListTags(conn *lambda.Lambda, identifier string) (KeyValueTags, error) { + input := &lambda.ListTagsInput{ + Resource: aws.String(identifier), + } + + output, err := conn.ListTags(input) + + if err != nil { + return New(nil), err + } + + return LambdaKeyValueTags(output.Tags), nil +} + +// LicensemanagerListTags lists licensemanager service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func LicensemanagerListTags(conn *licensemanager.LicenseManager, identifier string) (KeyValueTags, error) { + input := &licensemanager.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return LicensemanagerKeyValueTags(output.Tags), nil +} + +// MediaconnectListTags lists mediaconnect service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func MediaconnectListTags(conn *mediaconnect.MediaConnect, identifier string) (KeyValueTags, error) { + input := &mediaconnect.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return MediaconnectKeyValueTags(output.Tags), nil +} + +// MedialiveListTags lists medialive service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func MedialiveListTags(conn *medialive.MediaLive, identifier string) (KeyValueTags, error) { + input := &medialive.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return MedialiveKeyValueTags(output.Tags), nil +} + +// MediapackageListTags lists mediapackage service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func MediapackageListTags(conn *mediapackage.MediaPackage, identifier string) (KeyValueTags, error) { + input := &mediapackage.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return MediapackageKeyValueTags(output.Tags), nil +} + +// MediastoreListTags lists mediastore service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func MediastoreListTags(conn *mediastore.MediaStore, identifier string) (KeyValueTags, error) { + input := &mediastore.ListTagsForResourceInput{ + Resource: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return MediastoreKeyValueTags(output.Tags), nil +} + +// MqListTags lists mq service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func MqListTags(conn *mq.MQ, identifier string) (KeyValueTags, error) { + input := &mq.ListTagsInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTags(input) + + if err != nil { + return New(nil), err + } + + return MqKeyValueTags(output.Tags), nil +} + +// NeptuneListTags lists neptune service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func NeptuneListTags(conn *neptune.Neptune, identifier string) (KeyValueTags, error) { + input := &neptune.ListTagsForResourceInput{ + ResourceName: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return NeptuneKeyValueTags(output.TagList), nil +} + +// OpsworksListTags lists opsworks service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func OpsworksListTags(conn *opsworks.OpsWorks, identifier string) (KeyValueTags, error) { + input := &opsworks.ListTagsInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTags(input) + + if err != nil { + return New(nil), err + } + + return OpsworksKeyValueTags(output.Tags), nil +} + +// OrganizationsListTags lists organizations service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func OrganizationsListTags(conn *organizations.Organizations, identifier string) (KeyValueTags, error) { + input := &organizations.ListTagsForResourceInput{ + ResourceId: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return OrganizationsKeyValueTags(output.Tags), nil +} + +// RdsListTags lists rds service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func RdsListTags(conn *rds.RDS, identifier string) (KeyValueTags, error) { + input := &rds.ListTagsForResourceInput{ + ResourceName: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return RdsKeyValueTags(output.TagList), nil +} + +// Route53resolverListTags lists route53resolver service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func Route53resolverListTags(conn *route53resolver.Route53Resolver, identifier string) (KeyValueTags, error) { + input := &route53resolver.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return Route53resolverKeyValueTags(output.Tags), nil +} + +// SagemakerListTags lists sagemaker service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func SagemakerListTags(conn *sagemaker.SageMaker, identifier string) (KeyValueTags, error) { + input := &sagemaker.ListTagsInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTags(input) + + if err != nil { + return New(nil), err + } + + return SagemakerKeyValueTags(output.Tags), nil +} + +// SecurityhubListTags lists securityhub service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func SecurityhubListTags(conn *securityhub.SecurityHub, identifier string) (KeyValueTags, error) { + input := &securityhub.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return SecurityhubKeyValueTags(output.Tags), nil +} + +// SfnListTags lists sfn service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func SfnListTags(conn *sfn.SFN, identifier string) (KeyValueTags, error) { + input := &sfn.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return SfnKeyValueTags(output.Tags), nil +} + +// SnsListTags lists sns service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func SnsListTags(conn *sns.SNS, identifier string) (KeyValueTags, error) { + input := &sns.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return SnsKeyValueTags(output.Tags), nil +} + +// SsmListTags lists ssm service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func SsmListTags(conn *ssm.SSM, identifier string, resourceType string) (KeyValueTags, error) { + input := &ssm.ListTagsForResourceInput{ + ResourceId: aws.String(identifier), + ResourceType: aws.String(resourceType), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return SsmKeyValueTags(output.TagList), nil +} + +// StoragegatewayListTags lists storagegateway service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func StoragegatewayListTags(conn *storagegateway.StorageGateway, identifier string) (KeyValueTags, error) { + input := &storagegateway.ListTagsForResourceInput{ + ResourceARN: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return StoragegatewayKeyValueTags(output.Tags), nil +} + +// SwfListTags lists swf service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func SwfListTags(conn *swf.SWF, identifier string) (KeyValueTags, error) { + input := &swf.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return SwfKeyValueTags(output.Tags), nil +} + +// TransferListTags lists transfer service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func TransferListTags(conn *transfer.Transfer, identifier string) (KeyValueTags, error) { + input := &transfer.ListTagsForResourceInput{ + Arn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return TransferKeyValueTags(output.Tags), nil +} + +// WorkspacesListTags lists workspaces service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func WorkspacesListTags(conn *workspaces.WorkSpaces, identifier string) (KeyValueTags, error) { + input := &workspaces.DescribeTagsInput{ + ResourceId: aws.String(identifier), + } + + output, err := conn.DescribeTags(input) + + if err != nil { + return New(nil), err + } + + return WorkspacesKeyValueTags(output.TagList), nil +} diff --git a/aws/internal/keyvaluetags/service_generation_customizations.go b/aws/internal/keyvaluetags/service_generation_customizations.go new file mode 100644 index 00000000000..8dee8812376 --- /dev/null +++ b/aws/internal/keyvaluetags/service_generation_customizations.go @@ -0,0 +1,248 @@ +// This file contains code generation customizations for each AWS Go SDK service. + +package keyvaluetags + +import ( + "fmt" + "reflect" + + "github.com/aws/aws-sdk-go/service/acmpca" + "github.com/aws/aws-sdk-go/service/amplify" + "github.com/aws/aws-sdk-go/service/apigateway" + "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/aws/aws-sdk-go/service/appmesh" + "github.com/aws/aws-sdk-go/service/appstream" + "github.com/aws/aws-sdk-go/service/appsync" + "github.com/aws/aws-sdk-go/service/athena" + "github.com/aws/aws-sdk-go/service/backup" + "github.com/aws/aws-sdk-go/service/cloudfront" + "github.com/aws/aws-sdk-go/service/cloudhsmv2" + "github.com/aws/aws-sdk-go/service/cloudwatch" + "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "github.com/aws/aws-sdk-go/service/codecommit" + "github.com/aws/aws-sdk-go/service/codedeploy" + "github.com/aws/aws-sdk-go/service/codepipeline" + "github.com/aws/aws-sdk-go/service/cognitoidentity" + "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" + "github.com/aws/aws-sdk-go/service/configservice" + "github.com/aws/aws-sdk-go/service/databasemigrationservice" + "github.com/aws/aws-sdk-go/service/datapipeline" + "github.com/aws/aws-sdk-go/service/datasync" + "github.com/aws/aws-sdk-go/service/dax" + "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/docdb" + "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/aws/aws-sdk-go/service/ecr" + "github.com/aws/aws-sdk-go/service/ecs" + "github.com/aws/aws-sdk-go/service/efs" + "github.com/aws/aws-sdk-go/service/elasticache" + "github.com/aws/aws-sdk-go/service/elasticbeanstalk" + "github.com/aws/aws-sdk-go/service/elasticsearchservice" + "github.com/aws/aws-sdk-go/service/emr" + "github.com/aws/aws-sdk-go/service/firehose" + "github.com/aws/aws-sdk-go/service/fsx" + "github.com/aws/aws-sdk-go/service/glue" + "github.com/aws/aws-sdk-go/service/guardduty" + "github.com/aws/aws-sdk-go/service/inspector" + "github.com/aws/aws-sdk-go/service/iot" + "github.com/aws/aws-sdk-go/service/iotanalytics" + "github.com/aws/aws-sdk-go/service/iotevents" + "github.com/aws/aws-sdk-go/service/kafka" + "github.com/aws/aws-sdk-go/service/kinesisanalytics" + "github.com/aws/aws-sdk-go/service/kinesisanalyticsv2" + "github.com/aws/aws-sdk-go/service/kms" + "github.com/aws/aws-sdk-go/service/lambda" + "github.com/aws/aws-sdk-go/service/licensemanager" + "github.com/aws/aws-sdk-go/service/lightsail" + "github.com/aws/aws-sdk-go/service/mediaconnect" + "github.com/aws/aws-sdk-go/service/mediaconvert" + "github.com/aws/aws-sdk-go/service/medialive" + "github.com/aws/aws-sdk-go/service/mediapackage" + "github.com/aws/aws-sdk-go/service/mediastore" + "github.com/aws/aws-sdk-go/service/mq" + "github.com/aws/aws-sdk-go/service/neptune" + "github.com/aws/aws-sdk-go/service/opsworks" + "github.com/aws/aws-sdk-go/service/organizations" + "github.com/aws/aws-sdk-go/service/pinpoint" + "github.com/aws/aws-sdk-go/service/ram" + "github.com/aws/aws-sdk-go/service/rds" + "github.com/aws/aws-sdk-go/service/redshift" + "github.com/aws/aws-sdk-go/service/route53resolver" + "github.com/aws/aws-sdk-go/service/sagemaker" + "github.com/aws/aws-sdk-go/service/secretsmanager" + "github.com/aws/aws-sdk-go/service/securityhub" + "github.com/aws/aws-sdk-go/service/sfn" + "github.com/aws/aws-sdk-go/service/sns" + "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go/service/storagegateway" + "github.com/aws/aws-sdk-go/service/swf" + "github.com/aws/aws-sdk-go/service/transfer" + "github.com/aws/aws-sdk-go/service/waf" + "github.com/aws/aws-sdk-go/service/workspaces" +) + +// ServiceClientType determines the service client Go type. +// The AWS Go SDK does not provide a constant or reproducible inference methodology +// to get the correct type name of each service, so we resort to reflection for now. +func ServiceClientType(serviceName string) string { + var funcType reflect.Type + + switch serviceName { + case "acmpca": + funcType = reflect.TypeOf(acmpca.New) + case "amplify": + funcType = reflect.TypeOf(amplify.New) + case "apigateway": + funcType = reflect.TypeOf(apigateway.New) + case "apigatewayv2": + funcType = reflect.TypeOf(apigatewayv2.New) + case "appmesh": + funcType = reflect.TypeOf(appmesh.New) + case "appstream": + funcType = reflect.TypeOf(appstream.New) + case "appsync": + funcType = reflect.TypeOf(appsync.New) + case "athena": + funcType = reflect.TypeOf(athena.New) + case "backup": + funcType = reflect.TypeOf(backup.New) + case "cloudfront": + funcType = reflect.TypeOf(cloudfront.New) + case "cloudhsmv2": + funcType = reflect.TypeOf(cloudhsmv2.New) + case "cloudwatch": + funcType = reflect.TypeOf(cloudwatch.New) + case "cloudwatchevents": + funcType = reflect.TypeOf(cloudwatchevents.New) + case "codecommit": + funcType = reflect.TypeOf(codecommit.New) + case "codedeploy": + funcType = reflect.TypeOf(codedeploy.New) + case "codepipeline": + funcType = reflect.TypeOf(codepipeline.New) + case "cognitoidentity": + funcType = reflect.TypeOf(cognitoidentity.New) + case "cognitoidentityprovider": + funcType = reflect.TypeOf(cognitoidentityprovider.New) + case "configservice": + funcType = reflect.TypeOf(configservice.New) + case "databasemigrationservice": + funcType = reflect.TypeOf(databasemigrationservice.New) + case "datapipeline": + funcType = reflect.TypeOf(datapipeline.New) + case "datasync": + funcType = reflect.TypeOf(datasync.New) + case "dax": + funcType = reflect.TypeOf(dax.New) + case "devicefarm": + funcType = reflect.TypeOf(devicefarm.New) + case "directconnect": + funcType = reflect.TypeOf(directconnect.New) + case "directoryservice": + funcType = reflect.TypeOf(directoryservice.New) + case "docdb": + funcType = reflect.TypeOf(docdb.New) + case "dynamodb": + funcType = reflect.TypeOf(dynamodb.New) + case "ecr": + funcType = reflect.TypeOf(ecr.New) + case "ecs": + funcType = reflect.TypeOf(ecs.New) + case "efs": + funcType = reflect.TypeOf(efs.New) + case "elasticache": + funcType = reflect.TypeOf(elasticache.New) + case "elasticbeanstalk": + funcType = reflect.TypeOf(elasticbeanstalk.New) + case "elasticsearchservice": + funcType = reflect.TypeOf(elasticsearchservice.New) + case "emr": + funcType = reflect.TypeOf(emr.New) + case "firehose": + funcType = reflect.TypeOf(firehose.New) + case "fsx": + funcType = reflect.TypeOf(fsx.New) + case "glue": + funcType = reflect.TypeOf(glue.New) + case "guardduty": + funcType = reflect.TypeOf(guardduty.New) + case "inspector": + funcType = reflect.TypeOf(inspector.New) + case "iot": + funcType = reflect.TypeOf(iot.New) + case "iotanalytics": + funcType = reflect.TypeOf(iotanalytics.New) + case "iotevents": + funcType = reflect.TypeOf(iotevents.New) + case "kafka": + funcType = reflect.TypeOf(kafka.New) + case "kinesisanalytics": + funcType = reflect.TypeOf(kinesisanalytics.New) + case "kinesisanalyticsv2": + funcType = reflect.TypeOf(kinesisanalyticsv2.New) + case "kms": + funcType = reflect.TypeOf(kms.New) + case "lambda": + funcType = reflect.TypeOf(lambda.New) + case "licensemanager": + funcType = reflect.TypeOf(licensemanager.New) + case "lightsail": + funcType = reflect.TypeOf(lightsail.New) + case "mediaconnect": + funcType = reflect.TypeOf(mediaconnect.New) + case "mediaconvert": + funcType = reflect.TypeOf(mediaconvert.New) + case "medialive": + funcType = reflect.TypeOf(medialive.New) + case "mediapackage": + funcType = reflect.TypeOf(mediapackage.New) + case "mediastore": + funcType = reflect.TypeOf(mediastore.New) + case "mq": + funcType = reflect.TypeOf(mq.New) + case "neptune": + funcType = reflect.TypeOf(neptune.New) + case "opsworks": + funcType = reflect.TypeOf(opsworks.New) + case "organizations": + funcType = reflect.TypeOf(organizations.New) + case "pinpoint": + funcType = reflect.TypeOf(pinpoint.New) + case "ram": + funcType = reflect.TypeOf(ram.New) + case "rds": + funcType = reflect.TypeOf(rds.New) + case "redshift": + funcType = reflect.TypeOf(redshift.New) + case "route53resolver": + funcType = reflect.TypeOf(route53resolver.New) + case "sagemaker": + funcType = reflect.TypeOf(sagemaker.New) + case "secretsmanager": + funcType = reflect.TypeOf(secretsmanager.New) + case "securityhub": + funcType = reflect.TypeOf(securityhub.New) + case "sfn": + funcType = reflect.TypeOf(sfn.New) + case "sns": + funcType = reflect.TypeOf(sns.New) + case "ssm": + funcType = reflect.TypeOf(ssm.New) + case "storagegateway": + funcType = reflect.TypeOf(storagegateway.New) + case "swf": + funcType = reflect.TypeOf(swf.New) + case "transfer": + funcType = reflect.TypeOf(transfer.New) + case "waf": + funcType = reflect.TypeOf(waf.New) + case "workspaces": + funcType = reflect.TypeOf(workspaces.New) + default: + panic(fmt.Sprintf("unrecognized ServiceClientType: %s", serviceName)) + } + + return funcType.Out(0).String() +} diff --git a/aws/internal/keyvaluetags/service_tags_gen.go b/aws/internal/keyvaluetags/service_tags_gen.go new file mode 100644 index 00000000000..1fc05de3356 --- /dev/null +++ b/aws/internal/keyvaluetags/service_tags_gen.go @@ -0,0 +1,2203 @@ +// Code generated by generators/servicetags/main.go; DO NOT EDIT. + +package keyvaluetags + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/acm" + "github.com/aws/aws-sdk-go/service/acmpca" + "github.com/aws/aws-sdk-go/service/appmesh" + "github.com/aws/aws-sdk-go/service/athena" + "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go/service/cloudfront" + "github.com/aws/aws-sdk-go/service/cloudhsmv2" + "github.com/aws/aws-sdk-go/service/cloudtrail" + "github.com/aws/aws-sdk-go/service/cloudwatch" + "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "github.com/aws/aws-sdk-go/service/codebuild" + "github.com/aws/aws-sdk-go/service/codedeploy" + "github.com/aws/aws-sdk-go/service/codepipeline" + "github.com/aws/aws-sdk-go/service/configservice" + "github.com/aws/aws-sdk-go/service/databasemigrationservice" + "github.com/aws/aws-sdk-go/service/datapipeline" + "github.com/aws/aws-sdk-go/service/datasync" + "github.com/aws/aws-sdk-go/service/dax" + "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" + "github.com/aws/aws-sdk-go/service/ecr" + "github.com/aws/aws-sdk-go/service/ecs" + "github.com/aws/aws-sdk-go/service/efs" + "github.com/aws/aws-sdk-go/service/elasticache" + "github.com/aws/aws-sdk-go/service/elasticbeanstalk" + "github.com/aws/aws-sdk-go/service/elasticsearchservice" + "github.com/aws/aws-sdk-go/service/elb" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/aws/aws-sdk-go/service/emr" + "github.com/aws/aws-sdk-go/service/firehose" + "github.com/aws/aws-sdk-go/service/fms" + "github.com/aws/aws-sdk-go/service/fsx" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go/service/inspector" + "github.com/aws/aws-sdk-go/service/iot" + "github.com/aws/aws-sdk-go/service/iotanalytics" + "github.com/aws/aws-sdk-go/service/iotevents" + "github.com/aws/aws-sdk-go/service/kinesis" + "github.com/aws/aws-sdk-go/service/kinesisanalytics" + "github.com/aws/aws-sdk-go/service/kinesisanalyticsv2" + "github.com/aws/aws-sdk-go/service/kms" + "github.com/aws/aws-sdk-go/service/licensemanager" + "github.com/aws/aws-sdk-go/service/lightsail" + "github.com/aws/aws-sdk-go/service/mediastore" + "github.com/aws/aws-sdk-go/service/neptune" + "github.com/aws/aws-sdk-go/service/organizations" + "github.com/aws/aws-sdk-go/service/ram" + "github.com/aws/aws-sdk-go/service/rds" + "github.com/aws/aws-sdk-go/service/redshift" + "github.com/aws/aws-sdk-go/service/route53" + "github.com/aws/aws-sdk-go/service/route53resolver" + "github.com/aws/aws-sdk-go/service/s3" + "github.com/aws/aws-sdk-go/service/sagemaker" + "github.com/aws/aws-sdk-go/service/secretsmanager" + "github.com/aws/aws-sdk-go/service/serverlessapplicationrepository" + "github.com/aws/aws-sdk-go/service/servicecatalog" + "github.com/aws/aws-sdk-go/service/sfn" + "github.com/aws/aws-sdk-go/service/sns" + "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go/service/storagegateway" + "github.com/aws/aws-sdk-go/service/swf" + "github.com/aws/aws-sdk-go/service/transfer" + "github.com/aws/aws-sdk-go/service/waf" + "github.com/aws/aws-sdk-go/service/workspaces" +) + +// map[string]*string handling + +// AmplifyTags returns amplify service tags. +func (tags KeyValueTags) AmplifyTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// AmplifyKeyValueTags creates KeyValueTags from amplify service tags. +func AmplifyKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// ApigatewayTags returns apigateway service tags. +func (tags KeyValueTags) ApigatewayTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// ApigatewayKeyValueTags creates KeyValueTags from apigateway service tags. +func ApigatewayKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// Apigatewayv2Tags returns apigatewayv2 service tags. +func (tags KeyValueTags) Apigatewayv2Tags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// Apigatewayv2KeyValueTags creates KeyValueTags from apigatewayv2 service tags. +func Apigatewayv2KeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// AppstreamTags returns appstream service tags. +func (tags KeyValueTags) AppstreamTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// AppstreamKeyValueTags creates KeyValueTags from appstream service tags. +func AppstreamKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// AppsyncTags returns appsync service tags. +func (tags KeyValueTags) AppsyncTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// AppsyncKeyValueTags creates KeyValueTags from appsync service tags. +func AppsyncKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// BackupTags returns backup service tags. +func (tags KeyValueTags) BackupTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// BackupKeyValueTags creates KeyValueTags from backup service tags. +func BackupKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// BatchTags returns batch service tags. +func (tags KeyValueTags) BatchTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// BatchKeyValueTags creates KeyValueTags from batch service tags. +func BatchKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// CloudwatchlogsTags returns cloudwatchlogs service tags. +func (tags KeyValueTags) CloudwatchlogsTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// CloudwatchlogsKeyValueTags creates KeyValueTags from cloudwatchlogs service tags. +func CloudwatchlogsKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// CodecommitTags returns codecommit service tags. +func (tags KeyValueTags) CodecommitTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// CodecommitKeyValueTags creates KeyValueTags from codecommit service tags. +func CodecommitKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// CognitoidentityTags returns cognitoidentity service tags. +func (tags KeyValueTags) CognitoidentityTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// CognitoidentityKeyValueTags creates KeyValueTags from cognitoidentity service tags. +func CognitoidentityKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// CognitoidentityproviderTags returns cognitoidentityprovider service tags. +func (tags KeyValueTags) CognitoidentityproviderTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// CognitoidentityproviderKeyValueTags creates KeyValueTags from cognitoidentityprovider service tags. +func CognitoidentityproviderKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// GlacierTags returns glacier service tags. +func (tags KeyValueTags) GlacierTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// GlacierKeyValueTags creates KeyValueTags from glacier service tags. +func GlacierKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// GlueTags returns glue service tags. +func (tags KeyValueTags) GlueTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// GlueKeyValueTags creates KeyValueTags from glue service tags. +func GlueKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// GuarddutyTags returns guardduty service tags. +func (tags KeyValueTags) GuarddutyTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// GuarddutyKeyValueTags creates KeyValueTags from guardduty service tags. +func GuarddutyKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// KafkaTags returns kafka service tags. +func (tags KeyValueTags) KafkaTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// KafkaKeyValueTags creates KeyValueTags from kafka service tags. +func KafkaKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// LambdaTags returns lambda service tags. +func (tags KeyValueTags) LambdaTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// LambdaKeyValueTags creates KeyValueTags from lambda service tags. +func LambdaKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// MediaconnectTags returns mediaconnect service tags. +func (tags KeyValueTags) MediaconnectTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// MediaconnectKeyValueTags creates KeyValueTags from mediaconnect service tags. +func MediaconnectKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// MediaconvertTags returns mediaconvert service tags. +func (tags KeyValueTags) MediaconvertTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// MediaconvertKeyValueTags creates KeyValueTags from mediaconvert service tags. +func MediaconvertKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// MedialiveTags returns medialive service tags. +func (tags KeyValueTags) MedialiveTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// MedialiveKeyValueTags creates KeyValueTags from medialive service tags. +func MedialiveKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// MediapackageTags returns mediapackage service tags. +func (tags KeyValueTags) MediapackageTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// MediapackageKeyValueTags creates KeyValueTags from mediapackage service tags. +func MediapackageKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// MqTags returns mq service tags. +func (tags KeyValueTags) MqTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// MqKeyValueTags creates KeyValueTags from mq service tags. +func MqKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// OpsworksTags returns opsworks service tags. +func (tags KeyValueTags) OpsworksTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// OpsworksKeyValueTags creates KeyValueTags from opsworks service tags. +func OpsworksKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// PinpointTags returns pinpoint service tags. +func (tags KeyValueTags) PinpointTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// PinpointKeyValueTags creates KeyValueTags from pinpoint service tags. +func PinpointKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// ResourcegroupsTags returns resourcegroups service tags. +func (tags KeyValueTags) ResourcegroupsTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// ResourcegroupsKeyValueTags creates KeyValueTags from resourcegroups service tags. +func ResourcegroupsKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// SecurityhubTags returns securityhub service tags. +func (tags KeyValueTags) SecurityhubTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// SecurityhubKeyValueTags creates KeyValueTags from securityhub service tags. +func SecurityhubKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// SqsTags returns sqs service tags. +func (tags KeyValueTags) SqsTags() map[string]*string { + return aws.StringMap(tags.Map()) +} + +// SqsKeyValueTags creates KeyValueTags from sqs service tags. +func SqsKeyValueTags(tags map[string]*string) KeyValueTags { + return New(tags) +} + +// []*SERVICE.Tag handling + +// AcmTags returns acm service tags. +func (tags KeyValueTags) AcmTags() []*acm.Tag { + result := make([]*acm.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &acm.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// AcmKeyValueTags creates KeyValueTags from acm service tags. +func AcmKeyValueTags(tags []*acm.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// AcmpcaTags returns acmpca service tags. +func (tags KeyValueTags) AcmpcaTags() []*acmpca.Tag { + result := make([]*acmpca.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &acmpca.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// AcmpcaKeyValueTags creates KeyValueTags from acmpca service tags. +func AcmpcaKeyValueTags(tags []*acmpca.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// AppmeshTags returns appmesh service tags. +func (tags KeyValueTags) AppmeshTags() []*appmesh.TagRef { + result := make([]*appmesh.TagRef, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &appmesh.TagRef{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// AppmeshKeyValueTags creates KeyValueTags from appmesh service tags. +func AppmeshKeyValueTags(tags []*appmesh.TagRef) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// AthenaTags returns athena service tags. +func (tags KeyValueTags) AthenaTags() []*athena.Tag { + result := make([]*athena.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &athena.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// AthenaKeyValueTags creates KeyValueTags from athena service tags. +func AthenaKeyValueTags(tags []*athena.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// CloudformationTags returns cloudformation service tags. +func (tags KeyValueTags) CloudformationTags() []*cloudformation.Tag { + result := make([]*cloudformation.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &cloudformation.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// CloudformationKeyValueTags creates KeyValueTags from cloudformation service tags. +func CloudformationKeyValueTags(tags []*cloudformation.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// CloudfrontTags returns cloudfront service tags. +func (tags KeyValueTags) CloudfrontTags() []*cloudfront.Tag { + result := make([]*cloudfront.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &cloudfront.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// CloudfrontKeyValueTags creates KeyValueTags from cloudfront service tags. +func CloudfrontKeyValueTags(tags []*cloudfront.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// Cloudhsmv2Tags returns cloudhsmv2 service tags. +func (tags KeyValueTags) Cloudhsmv2Tags() []*cloudhsmv2.Tag { + result := make([]*cloudhsmv2.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &cloudhsmv2.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// Cloudhsmv2KeyValueTags creates KeyValueTags from cloudhsmv2 service tags. +func Cloudhsmv2KeyValueTags(tags []*cloudhsmv2.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// CloudtrailTags returns cloudtrail service tags. +func (tags KeyValueTags) CloudtrailTags() []*cloudtrail.Tag { + result := make([]*cloudtrail.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &cloudtrail.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// CloudtrailKeyValueTags creates KeyValueTags from cloudtrail service tags. +func CloudtrailKeyValueTags(tags []*cloudtrail.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// CloudwatchTags returns cloudwatch service tags. +func (tags KeyValueTags) CloudwatchTags() []*cloudwatch.Tag { + result := make([]*cloudwatch.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &cloudwatch.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// CloudwatchKeyValueTags creates KeyValueTags from cloudwatch service tags. +func CloudwatchKeyValueTags(tags []*cloudwatch.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// CloudwatcheventsTags returns cloudwatchevents service tags. +func (tags KeyValueTags) CloudwatcheventsTags() []*cloudwatchevents.Tag { + result := make([]*cloudwatchevents.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &cloudwatchevents.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// CloudwatcheventsKeyValueTags creates KeyValueTags from cloudwatchevents service tags. +func CloudwatcheventsKeyValueTags(tags []*cloudwatchevents.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// CodebuildTags returns codebuild service tags. +func (tags KeyValueTags) CodebuildTags() []*codebuild.Tag { + result := make([]*codebuild.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &codebuild.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// CodebuildKeyValueTags creates KeyValueTags from codebuild service tags. +func CodebuildKeyValueTags(tags []*codebuild.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// CodedeployTags returns codedeploy service tags. +func (tags KeyValueTags) CodedeployTags() []*codedeploy.Tag { + result := make([]*codedeploy.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &codedeploy.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// CodedeployKeyValueTags creates KeyValueTags from codedeploy service tags. +func CodedeployKeyValueTags(tags []*codedeploy.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// CodepipelineTags returns codepipeline service tags. +func (tags KeyValueTags) CodepipelineTags() []*codepipeline.Tag { + result := make([]*codepipeline.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &codepipeline.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// CodepipelineKeyValueTags creates KeyValueTags from codepipeline service tags. +func CodepipelineKeyValueTags(tags []*codepipeline.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// ConfigserviceTags returns configservice service tags. +func (tags KeyValueTags) ConfigserviceTags() []*configservice.Tag { + result := make([]*configservice.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &configservice.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// ConfigserviceKeyValueTags creates KeyValueTags from configservice service tags. +func ConfigserviceKeyValueTags(tags []*configservice.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// DatabasemigrationserviceTags returns databasemigrationservice service tags. +func (tags KeyValueTags) DatabasemigrationserviceTags() []*databasemigrationservice.Tag { + result := make([]*databasemigrationservice.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &databasemigrationservice.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// DatabasemigrationserviceKeyValueTags creates KeyValueTags from databasemigrationservice service tags. +func DatabasemigrationserviceKeyValueTags(tags []*databasemigrationservice.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// DatapipelineTags returns datapipeline service tags. +func (tags KeyValueTags) DatapipelineTags() []*datapipeline.Tag { + result := make([]*datapipeline.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &datapipeline.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// DatapipelineKeyValueTags creates KeyValueTags from datapipeline service tags. +func DatapipelineKeyValueTags(tags []*datapipeline.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// DatasyncTags returns datasync service tags. +func (tags KeyValueTags) DatasyncTags() []*datasync.TagListEntry { + result := make([]*datasync.TagListEntry, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &datasync.TagListEntry{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// DatasyncKeyValueTags creates KeyValueTags from datasync service tags. +func DatasyncKeyValueTags(tags []*datasync.TagListEntry) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// DaxTags returns dax service tags. +func (tags KeyValueTags) DaxTags() []*dax.Tag { + result := make([]*dax.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &dax.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// DaxKeyValueTags creates KeyValueTags from dax service tags. +func DaxKeyValueTags(tags []*dax.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// DevicefarmTags returns devicefarm service tags. +func (tags KeyValueTags) DevicefarmTags() []*devicefarm.Tag { + result := make([]*devicefarm.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &devicefarm.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// DevicefarmKeyValueTags creates KeyValueTags from devicefarm service tags. +func DevicefarmKeyValueTags(tags []*devicefarm.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// DirectconnectTags returns directconnect service tags. +func (tags KeyValueTags) DirectconnectTags() []*directconnect.Tag { + result := make([]*directconnect.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &directconnect.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// DirectconnectKeyValueTags creates KeyValueTags from directconnect service tags. +func DirectconnectKeyValueTags(tags []*directconnect.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// DirectoryserviceTags returns directoryservice service tags. +func (tags KeyValueTags) DirectoryserviceTags() []*directoryservice.Tag { + result := make([]*directoryservice.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &directoryservice.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// DirectoryserviceKeyValueTags creates KeyValueTags from directoryservice service tags. +func DirectoryserviceKeyValueTags(tags []*directoryservice.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + 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)) + + for k, v := range tags.Map() { + tag := &docdb.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// DocdbKeyValueTags creates KeyValueTags from docdb service tags. +func DocdbKeyValueTags(tags []*docdb.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// DynamodbTags returns dynamodb service tags. +func (tags KeyValueTags) DynamodbTags() []*dynamodb.Tag { + result := make([]*dynamodb.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &dynamodb.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// DynamodbKeyValueTags creates KeyValueTags from dynamodb service tags. +func DynamodbKeyValueTags(tags []*dynamodb.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// Ec2Tags returns ec2 service tags. +func (tags KeyValueTags) Ec2Tags() []*ec2.Tag { + result := make([]*ec2.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &ec2.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// Ec2KeyValueTags creates KeyValueTags from ec2 service tags. +func Ec2KeyValueTags(tags []*ec2.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// EcrTags returns ecr service tags. +func (tags KeyValueTags) EcrTags() []*ecr.Tag { + result := make([]*ecr.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &ecr.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// EcrKeyValueTags creates KeyValueTags from ecr service tags. +func EcrKeyValueTags(tags []*ecr.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// EcsTags returns ecs service tags. +func (tags KeyValueTags) EcsTags() []*ecs.Tag { + result := make([]*ecs.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &ecs.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// EcsKeyValueTags creates KeyValueTags from ecs service tags. +func EcsKeyValueTags(tags []*ecs.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// EfsTags returns efs service tags. +func (tags KeyValueTags) EfsTags() []*efs.Tag { + result := make([]*efs.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &efs.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// EfsKeyValueTags creates KeyValueTags from efs service tags. +func EfsKeyValueTags(tags []*efs.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// ElasticacheTags returns elasticache service tags. +func (tags KeyValueTags) ElasticacheTags() []*elasticache.Tag { + result := make([]*elasticache.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &elasticache.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// ElasticacheKeyValueTags creates KeyValueTags from elasticache service tags. +func ElasticacheKeyValueTags(tags []*elasticache.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// ElasticbeanstalkTags returns elasticbeanstalk service tags. +func (tags KeyValueTags) ElasticbeanstalkTags() []*elasticbeanstalk.Tag { + result := make([]*elasticbeanstalk.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &elasticbeanstalk.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// ElasticbeanstalkKeyValueTags creates KeyValueTags from elasticbeanstalk service tags. +func ElasticbeanstalkKeyValueTags(tags []*elasticbeanstalk.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// ElasticsearchserviceTags returns elasticsearchservice service tags. +func (tags KeyValueTags) ElasticsearchserviceTags() []*elasticsearchservice.Tag { + result := make([]*elasticsearchservice.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &elasticsearchservice.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// ElasticsearchserviceKeyValueTags creates KeyValueTags from elasticsearchservice service tags. +func ElasticsearchserviceKeyValueTags(tags []*elasticsearchservice.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// ElbTags returns elb service tags. +func (tags KeyValueTags) ElbTags() []*elb.Tag { + result := make([]*elb.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &elb.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// ElbKeyValueTags creates KeyValueTags from elb service tags. +func ElbKeyValueTags(tags []*elb.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// Elbv2Tags returns elbv2 service tags. +func (tags KeyValueTags) Elbv2Tags() []*elbv2.Tag { + result := make([]*elbv2.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &elbv2.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// Elbv2KeyValueTags creates KeyValueTags from elbv2 service tags. +func Elbv2KeyValueTags(tags []*elbv2.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// EmrTags returns emr service tags. +func (tags KeyValueTags) EmrTags() []*emr.Tag { + result := make([]*emr.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &emr.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// EmrKeyValueTags creates KeyValueTags from emr service tags. +func EmrKeyValueTags(tags []*emr.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// FirehoseTags returns firehose service tags. +func (tags KeyValueTags) FirehoseTags() []*firehose.Tag { + result := make([]*firehose.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &firehose.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// FirehoseKeyValueTags creates KeyValueTags from firehose service tags. +func FirehoseKeyValueTags(tags []*firehose.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// FmsTags returns fms service tags. +func (tags KeyValueTags) FmsTags() []*fms.ResourceTag { + result := make([]*fms.ResourceTag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &fms.ResourceTag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// FmsKeyValueTags creates KeyValueTags from fms service tags. +func FmsKeyValueTags(tags []*fms.ResourceTag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// FsxTags returns fsx service tags. +func (tags KeyValueTags) FsxTags() []*fsx.Tag { + result := make([]*fsx.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &fsx.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// FsxKeyValueTags creates KeyValueTags from fsx service tags. +func FsxKeyValueTags(tags []*fsx.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// IamTags returns iam service tags. +func (tags KeyValueTags) IamTags() []*iam.Tag { + result := make([]*iam.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &iam.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// IamKeyValueTags creates KeyValueTags from iam service tags. +func IamKeyValueTags(tags []*iam.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// InspectorTags returns inspector service tags. +func (tags KeyValueTags) InspectorTags() []*inspector.Tag { + result := make([]*inspector.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &inspector.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// InspectorKeyValueTags creates KeyValueTags from inspector service tags. +func InspectorKeyValueTags(tags []*inspector.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// IotTags returns iot service tags. +func (tags KeyValueTags) IotTags() []*iot.Tag { + result := make([]*iot.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &iot.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// IotKeyValueTags creates KeyValueTags from iot service tags. +func IotKeyValueTags(tags []*iot.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// IotanalyticsTags returns iotanalytics service tags. +func (tags KeyValueTags) IotanalyticsTags() []*iotanalytics.Tag { + result := make([]*iotanalytics.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &iotanalytics.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// IotanalyticsKeyValueTags creates KeyValueTags from iotanalytics service tags. +func IotanalyticsKeyValueTags(tags []*iotanalytics.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// IoteventsTags returns iotevents service tags. +func (tags KeyValueTags) IoteventsTags() []*iotevents.Tag { + result := make([]*iotevents.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &iotevents.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// IoteventsKeyValueTags creates KeyValueTags from iotevents service tags. +func IoteventsKeyValueTags(tags []*iotevents.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// KinesisTags returns kinesis service tags. +func (tags KeyValueTags) KinesisTags() []*kinesis.Tag { + result := make([]*kinesis.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &kinesis.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// KinesisKeyValueTags creates KeyValueTags from kinesis service tags. +func KinesisKeyValueTags(tags []*kinesis.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// KinesisanalyticsTags returns kinesisanalytics service tags. +func (tags KeyValueTags) KinesisanalyticsTags() []*kinesisanalytics.Tag { + result := make([]*kinesisanalytics.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &kinesisanalytics.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// KinesisanalyticsKeyValueTags creates KeyValueTags from kinesisanalytics service tags. +func KinesisanalyticsKeyValueTags(tags []*kinesisanalytics.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// Kinesisanalyticsv2Tags returns kinesisanalyticsv2 service tags. +func (tags KeyValueTags) Kinesisanalyticsv2Tags() []*kinesisanalyticsv2.Tag { + result := make([]*kinesisanalyticsv2.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &kinesisanalyticsv2.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// Kinesisanalyticsv2KeyValueTags creates KeyValueTags from kinesisanalyticsv2 service tags. +func Kinesisanalyticsv2KeyValueTags(tags []*kinesisanalyticsv2.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// KmsTags returns kms service tags. +func (tags KeyValueTags) KmsTags() []*kms.Tag { + result := make([]*kms.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &kms.Tag{ + TagKey: aws.String(k), + TagValue: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// KmsKeyValueTags creates KeyValueTags from kms service tags. +func KmsKeyValueTags(tags []*kms.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.TagKey)] = tag.TagValue + } + + return New(m) +} + +// LicensemanagerTags returns licensemanager service tags. +func (tags KeyValueTags) LicensemanagerTags() []*licensemanager.Tag { + result := make([]*licensemanager.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &licensemanager.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// LicensemanagerKeyValueTags creates KeyValueTags from licensemanager service tags. +func LicensemanagerKeyValueTags(tags []*licensemanager.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// LightsailTags returns lightsail service tags. +func (tags KeyValueTags) LightsailTags() []*lightsail.Tag { + result := make([]*lightsail.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &lightsail.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// LightsailKeyValueTags creates KeyValueTags from lightsail service tags. +func LightsailKeyValueTags(tags []*lightsail.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// MediastoreTags returns mediastore service tags. +func (tags KeyValueTags) MediastoreTags() []*mediastore.Tag { + result := make([]*mediastore.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &mediastore.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// MediastoreKeyValueTags creates KeyValueTags from mediastore service tags. +func MediastoreKeyValueTags(tags []*mediastore.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// NeptuneTags returns neptune service tags. +func (tags KeyValueTags) NeptuneTags() []*neptune.Tag { + result := make([]*neptune.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &neptune.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// NeptuneKeyValueTags creates KeyValueTags from neptune service tags. +func NeptuneKeyValueTags(tags []*neptune.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// OrganizationsTags returns organizations service tags. +func (tags KeyValueTags) OrganizationsTags() []*organizations.Tag { + result := make([]*organizations.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &organizations.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// OrganizationsKeyValueTags creates KeyValueTags from organizations service tags. +func OrganizationsKeyValueTags(tags []*organizations.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// RamTags returns ram service tags. +func (tags KeyValueTags) RamTags() []*ram.Tag { + result := make([]*ram.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &ram.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// RamKeyValueTags creates KeyValueTags from ram service tags. +func RamKeyValueTags(tags []*ram.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// RdsTags returns rds service tags. +func (tags KeyValueTags) RdsTags() []*rds.Tag { + result := make([]*rds.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &rds.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// RdsKeyValueTags creates KeyValueTags from rds service tags. +func RdsKeyValueTags(tags []*rds.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// RedshiftTags returns redshift service tags. +func (tags KeyValueTags) RedshiftTags() []*redshift.Tag { + result := make([]*redshift.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &redshift.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// RedshiftKeyValueTags creates KeyValueTags from redshift service tags. +func RedshiftKeyValueTags(tags []*redshift.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// Route53Tags returns route53 service tags. +func (tags KeyValueTags) Route53Tags() []*route53.Tag { + result := make([]*route53.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &route53.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// Route53KeyValueTags creates KeyValueTags from route53 service tags. +func Route53KeyValueTags(tags []*route53.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// Route53resolverTags returns route53resolver service tags. +func (tags KeyValueTags) Route53resolverTags() []*route53resolver.Tag { + result := make([]*route53resolver.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &route53resolver.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// Route53resolverKeyValueTags creates KeyValueTags from route53resolver service tags. +func Route53resolverKeyValueTags(tags []*route53resolver.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// S3Tags returns s3 service tags. +func (tags KeyValueTags) S3Tags() []*s3.Tag { + result := make([]*s3.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &s3.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// S3KeyValueTags creates KeyValueTags from s3 service tags. +func S3KeyValueTags(tags []*s3.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// SagemakerTags returns sagemaker service tags. +func (tags KeyValueTags) SagemakerTags() []*sagemaker.Tag { + result := make([]*sagemaker.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &sagemaker.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// SagemakerKeyValueTags creates KeyValueTags from sagemaker service tags. +func SagemakerKeyValueTags(tags []*sagemaker.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// SecretsmanagerTags returns secretsmanager service tags. +func (tags KeyValueTags) SecretsmanagerTags() []*secretsmanager.Tag { + result := make([]*secretsmanager.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &secretsmanager.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// SecretsmanagerKeyValueTags creates KeyValueTags from secretsmanager service tags. +func SecretsmanagerKeyValueTags(tags []*secretsmanager.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// ServerlessapplicationrepositoryTags returns serverlessapplicationrepository service tags. +func (tags KeyValueTags) ServerlessapplicationrepositoryTags() []*serverlessapplicationrepository.Tag { + result := make([]*serverlessapplicationrepository.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &serverlessapplicationrepository.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// ServerlessapplicationrepositoryKeyValueTags creates KeyValueTags from serverlessapplicationrepository service tags. +func ServerlessapplicationrepositoryKeyValueTags(tags []*serverlessapplicationrepository.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// ServicecatalogTags returns servicecatalog service tags. +func (tags KeyValueTags) ServicecatalogTags() []*servicecatalog.Tag { + result := make([]*servicecatalog.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &servicecatalog.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// ServicecatalogKeyValueTags creates KeyValueTags from servicecatalog service tags. +func ServicecatalogKeyValueTags(tags []*servicecatalog.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// SfnTags returns sfn service tags. +func (tags KeyValueTags) SfnTags() []*sfn.Tag { + result := make([]*sfn.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &sfn.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// SfnKeyValueTags creates KeyValueTags from sfn service tags. +func SfnKeyValueTags(tags []*sfn.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// SnsTags returns sns service tags. +func (tags KeyValueTags) SnsTags() []*sns.Tag { + result := make([]*sns.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &sns.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// SnsKeyValueTags creates KeyValueTags from sns service tags. +func SnsKeyValueTags(tags []*sns.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// SsmTags returns ssm service tags. +func (tags KeyValueTags) SsmTags() []*ssm.Tag { + result := make([]*ssm.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &ssm.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// SsmKeyValueTags creates KeyValueTags from ssm service tags. +func SsmKeyValueTags(tags []*ssm.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// StoragegatewayTags returns storagegateway service tags. +func (tags KeyValueTags) StoragegatewayTags() []*storagegateway.Tag { + result := make([]*storagegateway.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &storagegateway.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// StoragegatewayKeyValueTags creates KeyValueTags from storagegateway service tags. +func StoragegatewayKeyValueTags(tags []*storagegateway.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// SwfTags returns swf service tags. +func (tags KeyValueTags) SwfTags() []*swf.ResourceTag { + result := make([]*swf.ResourceTag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &swf.ResourceTag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// SwfKeyValueTags creates KeyValueTags from swf service tags. +func SwfKeyValueTags(tags []*swf.ResourceTag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// TransferTags returns transfer service tags. +func (tags KeyValueTags) TransferTags() []*transfer.Tag { + result := make([]*transfer.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &transfer.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// TransferKeyValueTags creates KeyValueTags from transfer service tags. +func TransferKeyValueTags(tags []*transfer.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// WafTags returns waf service tags. +func (tags KeyValueTags) WafTags() []*waf.Tag { + result := make([]*waf.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &waf.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// WafKeyValueTags creates KeyValueTags from waf service tags. +func WafKeyValueTags(tags []*waf.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} + +// WorkspacesTags returns workspaces service tags. +func (tags KeyValueTags) WorkspacesTags() []*workspaces.Tag { + result := make([]*workspaces.Tag, 0, len(tags)) + + for k, v := range tags.Map() { + tag := &workspaces.Tag{ + Key: aws.String(k), + Value: aws.String(v), + } + + result = append(result, tag) + } + + return result +} + +// WorkspacesKeyValueTags creates KeyValueTags from workspaces service tags. +func WorkspacesKeyValueTags(tags []*workspaces.Tag) KeyValueTags { + m := make(map[string]*string, len(tags)) + + for _, tag := range tags { + m[aws.StringValue(tag.Key)] = tag.Value + } + + return New(m) +} diff --git a/aws/internal/keyvaluetags/service_tags_gen_test.go b/aws/internal/keyvaluetags/service_tags_gen_test.go new file mode 100644 index 00000000000..525f90a4214 --- /dev/null +++ b/aws/internal/keyvaluetags/service_tags_gen_test.go @@ -0,0 +1,483 @@ +package keyvaluetags + +import ( + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/appmesh" + "github.com/aws/aws-sdk-go/service/athena" + "github.com/aws/aws-sdk-go/service/datasync" + "github.com/aws/aws-sdk-go/service/kms" +) + +// map[string]*string handling + +func TestAmplifyKeyValueTags(t *testing.T) { + testCases := []struct { + name string + tags map[string]*string + want map[string]string + }{ + { + name: "empty", + tags: map[string]*string{}, + want: map[string]string{}, + }, + { + name: "non_empty", + tags: map[string]*string{ + "key1": aws.String("value1"), + "key2": aws.String("value2"), + "key3": aws.String("value3"), + }, + want: map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := AmplifyKeyValueTags(testCase.tags) + + testKeyValueTagsVerifyMap(t, got.Map(), testCase.want) + }) + } +} + +func TestKeyValueTagsAmplifyTags(t *testing.T) { + testCases := []struct { + name string + tags KeyValueTags + want map[string]string + }{ + { + name: "empty", + tags: New(map[string]string{}), + want: map[string]string{}, + }, + { + name: "non_empty", + tags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + want: map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := testCase.tags.AmplifyTags() + + testKeyValueTagsVerifyMap(t, aws.StringValueMap(got), testCase.want) + }) + } +} + +// []*SERVICE.Tag handling + +func TestAthenaKeyValueTags(t *testing.T) { + testCases := []struct { + name string + tags []*athena.Tag + want map[string]string + }{ + { + name: "empty", + tags: []*athena.Tag{}, + want: map[string]string{}, + }, + { + name: "non_empty", + tags: []*athena.Tag{ + { + Key: aws.String("key1"), + Value: aws.String("value1"), + }, + { + Key: aws.String("key2"), + Value: aws.String("value2"), + }, + { + Key: aws.String("key3"), + Value: aws.String("value3"), + }, + }, + want: map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := AthenaKeyValueTags(testCase.tags) + + testKeyValueTagsVerifyMap(t, got.Map(), testCase.want) + }) + } +} + +func TestKeyValueTagsAthenaTags(t *testing.T) { + testCases := []struct { + name string + tags KeyValueTags + want []*athena.Tag + }{ + { + name: "empty", + tags: New(map[string]string{}), + want: []*athena.Tag{}, + }, + { + name: "non_empty", + tags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + want: []*athena.Tag{ + { + Key: aws.String("key1"), + Value: aws.String("value1"), + }, + { + Key: aws.String("key2"), + Value: aws.String("value2"), + }, + { + Key: aws.String("key3"), + Value: aws.String("value3"), + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := testCase.tags.AthenaTags() + + gotMap := make(map[string]string, len(got)) + for _, tag := range got { + gotMap[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value) + } + + wantMap := make(map[string]string, len(testCase.want)) + for _, tag := range testCase.want { + wantMap[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value) + } + + testKeyValueTagsVerifyMap(t, gotMap, wantMap) + }) + } +} + +// []*SERVICE.Tag (with TagKey and TagValue fields) handling + +func TestKmsKeyValueTags(t *testing.T) { + testCases := []struct { + name string + tags []*kms.Tag + want map[string]string + }{ + { + name: "empty", + tags: []*kms.Tag{}, + want: map[string]string{}, + }, + { + name: "non_empty", + tags: []*kms.Tag{ + { + TagKey: aws.String("key1"), + TagValue: aws.String("value1"), + }, + { + TagKey: aws.String("key2"), + TagValue: aws.String("value2"), + }, + { + TagKey: aws.String("key3"), + TagValue: aws.String("value3"), + }, + }, + want: map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := KmsKeyValueTags(testCase.tags) + + testKeyValueTagsVerifyMap(t, got.Map(), testCase.want) + }) + } +} + +func TestKeyValueTagsKmsTags(t *testing.T) { + testCases := []struct { + name string + tags KeyValueTags + want []*kms.Tag + }{ + { + name: "empty", + tags: New(map[string]string{}), + want: []*kms.Tag{}, + }, + { + name: "non_empty", + tags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + want: []*kms.Tag{ + { + TagKey: aws.String("key1"), + TagValue: aws.String("value1"), + }, + { + TagKey: aws.String("key2"), + TagValue: aws.String("value2"), + }, + { + TagKey: aws.String("key3"), + TagValue: aws.String("value3"), + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := testCase.tags.KmsTags() + + gotMap := make(map[string]string, len(got)) + for _, tag := range got { + gotMap[aws.StringValue(tag.TagKey)] = aws.StringValue(tag.TagValue) + } + + wantMap := make(map[string]string, len(testCase.want)) + for _, tag := range testCase.want { + wantMap[aws.StringValue(tag.TagKey)] = aws.StringValue(tag.TagValue) + } + + testKeyValueTagsVerifyMap(t, gotMap, wantMap) + }) + } +} + +// []*SERVICE.TagListEntry handling + +func TestDatasyncKeyValueTags(t *testing.T) { + testCases := []struct { + name string + tags []*datasync.TagListEntry + want map[string]string + }{ + { + name: "empty", + tags: []*datasync.TagListEntry{}, + want: map[string]string{}, + }, + { + name: "non_empty", + tags: []*datasync.TagListEntry{ + { + Key: aws.String("key1"), + Value: aws.String("value1"), + }, + { + Key: aws.String("key2"), + Value: aws.String("value2"), + }, + { + Key: aws.String("key3"), + Value: aws.String("value3"), + }, + }, + want: map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := DatasyncKeyValueTags(testCase.tags) + + testKeyValueTagsVerifyMap(t, got.Map(), testCase.want) + }) + } +} + +func TestKeyValueTagsDatasyncTags(t *testing.T) { + testCases := []struct { + name string + tags KeyValueTags + want []*datasync.TagListEntry + }{ + { + name: "empty", + tags: New(map[string]string{}), + want: []*datasync.TagListEntry{}, + }, + { + name: "non_empty", + tags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + want: []*datasync.TagListEntry{ + { + Key: aws.String("key1"), + Value: aws.String("value1"), + }, + { + Key: aws.String("key2"), + Value: aws.String("value2"), + }, + { + Key: aws.String("key3"), + Value: aws.String("value3"), + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := testCase.tags.DatasyncTags() + + gotMap := make(map[string]string, len(got)) + for _, tag := range got { + gotMap[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value) + } + + wantMap := make(map[string]string, len(testCase.want)) + for _, tag := range testCase.want { + wantMap[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value) + } + + testKeyValueTagsVerifyMap(t, gotMap, wantMap) + }) + } +} + +// []*SERVICE.TagRef handling + +func TestAppmeshKeyValueTags(t *testing.T) { + testCases := []struct { + name string + tags []*appmesh.TagRef + want map[string]string + }{ + { + name: "empty", + tags: []*appmesh.TagRef{}, + want: map[string]string{}, + }, + { + name: "non_empty", + tags: []*appmesh.TagRef{ + { + Key: aws.String("key1"), + Value: aws.String("value1"), + }, + { + Key: aws.String("key2"), + Value: aws.String("value2"), + }, + { + Key: aws.String("key3"), + Value: aws.String("value3"), + }, + }, + want: map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := AppmeshKeyValueTags(testCase.tags) + + testKeyValueTagsVerifyMap(t, got.Map(), testCase.want) + }) + } +} + +func TestKeyValueTagsAppmeshTags(t *testing.T) { + testCases := []struct { + name string + tags KeyValueTags + want []*appmesh.TagRef + }{ + { + name: "empty", + tags: New(map[string]string{}), + want: []*appmesh.TagRef{}, + }, + { + name: "non_empty", + tags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + want: []*appmesh.TagRef{ + { + Key: aws.String("key1"), + Value: aws.String("value1"), + }, + { + Key: aws.String("key2"), + Value: aws.String("value2"), + }, + { + Key: aws.String("key3"), + Value: aws.String("value3"), + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := testCase.tags.AppmeshTags() + + gotMap := make(map[string]string, len(got)) + for _, tag := range got { + gotMap[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value) + } + + wantMap := make(map[string]string, len(testCase.want)) + for _, tag := range testCase.want { + wantMap[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value) + } + + testKeyValueTagsVerifyMap(t, gotMap, wantMap) + }) + } +} diff --git a/aws/internal/keyvaluetags/update_tags_gen.go b/aws/internal/keyvaluetags/update_tags_gen.go new file mode 100644 index 00000000000..5bcc5a20d23 --- /dev/null +++ b/aws/internal/keyvaluetags/update_tags_gen.go @@ -0,0 +1,2564 @@ +// Code generated by generators/updatetags/main.go; DO NOT EDIT. + +package keyvaluetags + +import ( + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/amplify" + "github.com/aws/aws-sdk-go/service/apigateway" + "github.com/aws/aws-sdk-go/service/apigatewayv2" + "github.com/aws/aws-sdk-go/service/appmesh" + "github.com/aws/aws-sdk-go/service/appstream" + "github.com/aws/aws-sdk-go/service/appsync" + "github.com/aws/aws-sdk-go/service/athena" + "github.com/aws/aws-sdk-go/service/backup" + "github.com/aws/aws-sdk-go/service/cloudhsmv2" + "github.com/aws/aws-sdk-go/service/cloudwatch" + "github.com/aws/aws-sdk-go/service/cloudwatchevents" + "github.com/aws/aws-sdk-go/service/codecommit" + "github.com/aws/aws-sdk-go/service/codedeploy" + "github.com/aws/aws-sdk-go/service/codepipeline" + "github.com/aws/aws-sdk-go/service/cognitoidentity" + "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" + "github.com/aws/aws-sdk-go/service/configservice" + "github.com/aws/aws-sdk-go/service/databasemigrationservice" + "github.com/aws/aws-sdk-go/service/datapipeline" + "github.com/aws/aws-sdk-go/service/datasync" + "github.com/aws/aws-sdk-go/service/dax" + "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/docdb" + "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/aws/aws-sdk-go/service/ecr" + "github.com/aws/aws-sdk-go/service/ecs" + "github.com/aws/aws-sdk-go/service/efs" + "github.com/aws/aws-sdk-go/service/elasticache" + "github.com/aws/aws-sdk-go/service/elasticsearchservice" + "github.com/aws/aws-sdk-go/service/emr" + "github.com/aws/aws-sdk-go/service/firehose" + "github.com/aws/aws-sdk-go/service/fsx" + "github.com/aws/aws-sdk-go/service/glue" + "github.com/aws/aws-sdk-go/service/guardduty" + "github.com/aws/aws-sdk-go/service/iot" + "github.com/aws/aws-sdk-go/service/iotanalytics" + "github.com/aws/aws-sdk-go/service/iotevents" + "github.com/aws/aws-sdk-go/service/kafka" + "github.com/aws/aws-sdk-go/service/kinesisanalytics" + "github.com/aws/aws-sdk-go/service/kinesisanalyticsv2" + "github.com/aws/aws-sdk-go/service/kms" + "github.com/aws/aws-sdk-go/service/lambda" + "github.com/aws/aws-sdk-go/service/licensemanager" + "github.com/aws/aws-sdk-go/service/lightsail" + "github.com/aws/aws-sdk-go/service/mediaconnect" + "github.com/aws/aws-sdk-go/service/mediaconvert" + "github.com/aws/aws-sdk-go/service/medialive" + "github.com/aws/aws-sdk-go/service/mediapackage" + "github.com/aws/aws-sdk-go/service/mediastore" + "github.com/aws/aws-sdk-go/service/mq" + "github.com/aws/aws-sdk-go/service/neptune" + "github.com/aws/aws-sdk-go/service/opsworks" + "github.com/aws/aws-sdk-go/service/organizations" + "github.com/aws/aws-sdk-go/service/ram" + "github.com/aws/aws-sdk-go/service/rds" + "github.com/aws/aws-sdk-go/service/redshift" + "github.com/aws/aws-sdk-go/service/route53resolver" + "github.com/aws/aws-sdk-go/service/secretsmanager" + "github.com/aws/aws-sdk-go/service/securityhub" + "github.com/aws/aws-sdk-go/service/sfn" + "github.com/aws/aws-sdk-go/service/sns" + "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go/service/storagegateway" + "github.com/aws/aws-sdk-go/service/swf" + "github.com/aws/aws-sdk-go/service/transfer" + "github.com/aws/aws-sdk-go/service/waf" + "github.com/aws/aws-sdk-go/service/workspaces" +) + +// AmplifyUpdateTags updates amplify service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func AmplifyUpdateTags(conn *amplify.Amplify, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &lify.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &lify.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().AmplifyTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// ApigatewayUpdateTags updates apigateway service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func ApigatewayUpdateTags(conn *apigateway.APIGateway, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &apigateway.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &apigateway.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().ApigatewayTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// Apigatewayv2UpdateTags updates apigatewayv2 service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func Apigatewayv2UpdateTags(conn *apigatewayv2.ApiGatewayV2, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &apigatewayv2.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &apigatewayv2.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().Apigatewayv2Tags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// AppmeshUpdateTags updates appmesh service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func AppmeshUpdateTags(conn *appmesh.AppMesh, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &appmesh.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &appmesh.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().AppmeshTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// AppstreamUpdateTags updates appstream service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func AppstreamUpdateTags(conn *appstream.AppStream, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &appstream.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &appstream.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().AppstreamTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// AppsyncUpdateTags updates appsync service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func AppsyncUpdateTags(conn *appsync.AppSync, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &appsync.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &appsync.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().AppsyncTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// AthenaUpdateTags updates athena service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func AthenaUpdateTags(conn *athena.Athena, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &athena.UntagResourceInput{ + ResourceARN: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &athena.TagResourceInput{ + ResourceARN: aws.String(identifier), + Tags: updatedTags.IgnoreAws().AthenaTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// BackupUpdateTags updates backup service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func BackupUpdateTags(conn *backup.Backup, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &backup.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeyList: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &backup.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().BackupTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// Cloudhsmv2UpdateTags updates cloudhsmv2 service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func Cloudhsmv2UpdateTags(conn *cloudhsmv2.CloudHSMV2, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &cloudhsmv2.UntagResourceInput{ + ResourceId: aws.String(identifier), + TagKeyList: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &cloudhsmv2.TagResourceInput{ + ResourceId: aws.String(identifier), + TagList: updatedTags.IgnoreAws().Cloudhsmv2Tags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// CloudwatchUpdateTags updates cloudwatch service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func CloudwatchUpdateTags(conn *cloudwatch.CloudWatch, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &cloudwatch.UntagResourceInput{ + ResourceARN: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &cloudwatch.TagResourceInput{ + ResourceARN: aws.String(identifier), + Tags: updatedTags.IgnoreAws().CloudwatchTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// CloudwatcheventsUpdateTags updates cloudwatchevents service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func CloudwatcheventsUpdateTags(conn *cloudwatchevents.CloudWatchEvents, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &cloudwatchevents.UntagResourceInput{ + ResourceARN: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &cloudwatchevents.TagResourceInput{ + ResourceARN: aws.String(identifier), + Tags: updatedTags.IgnoreAws().CloudwatcheventsTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// CodecommitUpdateTags updates codecommit service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func CodecommitUpdateTags(conn *codecommit.CodeCommit, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &codecommit.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &codecommit.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().CodecommitTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// CodedeployUpdateTags updates codedeploy service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func CodedeployUpdateTags(conn *codedeploy.CodeDeploy, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &codedeploy.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &codedeploy.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().CodedeployTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// CodepipelineUpdateTags updates codepipeline service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func CodepipelineUpdateTags(conn *codepipeline.CodePipeline, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &codepipeline.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &codepipeline.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().CodepipelineTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// CognitoidentityUpdateTags updates cognitoidentity service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func CognitoidentityUpdateTags(conn *cognitoidentity.CognitoIdentity, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &cognitoidentity.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &cognitoidentity.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().CognitoidentityTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// CognitoidentityproviderUpdateTags updates cognitoidentityprovider service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func CognitoidentityproviderUpdateTags(conn *cognitoidentityprovider.CognitoIdentityProvider, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &cognitoidentityprovider.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &cognitoidentityprovider.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().CognitoidentityproviderTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// ConfigserviceUpdateTags updates configservice service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func ConfigserviceUpdateTags(conn *configservice.ConfigService, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &configservice.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &configservice.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().ConfigserviceTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// DatabasemigrationserviceUpdateTags updates databasemigrationservice service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func DatabasemigrationserviceUpdateTags(conn *databasemigrationservice.DatabaseMigrationService, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &databasemigrationservice.RemoveTagsFromResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.RemoveTagsFromResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &databasemigrationservice.AddTagsToResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().DatabasemigrationserviceTags(), + } + + _, err := conn.AddTagsToResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// DatapipelineUpdateTags updates datapipeline service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func DatapipelineUpdateTags(conn *datapipeline.DataPipeline, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &datapipeline.RemoveTagsInput{ + PipelineId: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.RemoveTags(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &datapipeline.AddTagsInput{ + PipelineId: aws.String(identifier), + Tags: updatedTags.IgnoreAws().DatapipelineTags(), + } + + _, err := conn.AddTags(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// DatasyncUpdateTags updates datasync service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func DatasyncUpdateTags(conn *datasync.DataSync, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &datasync.UntagResourceInput{ + ResourceArn: aws.String(identifier), + Keys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &datasync.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().DatasyncTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// DaxUpdateTags updates dax service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func DaxUpdateTags(conn *dax.DAX, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &dax.UntagResourceInput{ + ResourceName: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &dax.TagResourceInput{ + ResourceName: aws.String(identifier), + Tags: updatedTags.IgnoreAws().DaxTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// DevicefarmUpdateTags updates devicefarm service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func DevicefarmUpdateTags(conn *devicefarm.DeviceFarm, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &devicefarm.UntagResourceInput{ + ResourceARN: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &devicefarm.TagResourceInput{ + ResourceARN: aws.String(identifier), + Tags: updatedTags.IgnoreAws().DevicefarmTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// DirectconnectUpdateTags updates directconnect service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func DirectconnectUpdateTags(conn *directconnect.DirectConnect, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &directconnect.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &directconnect.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().DirectconnectTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// DirectoryserviceUpdateTags updates directoryservice service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func DirectoryserviceUpdateTags(conn *directoryservice.DirectoryService, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &directoryservice.RemoveTagsFromResourceInput{ + ResourceId: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.RemoveTagsFromResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &directoryservice.AddTagsToResourceInput{ + ResourceId: aws.String(identifier), + Tags: updatedTags.IgnoreAws().DirectoryserviceTags(), + } + + _, err := conn.AddTagsToResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", 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. +func DocdbUpdateTags(conn *docdb.DocDB, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &docdb.RemoveTagsFromResourceInput{ + ResourceName: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.RemoveTagsFromResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &docdb.AddTagsToResourceInput{ + ResourceName: aws.String(identifier), + Tags: updatedTags.IgnoreAws().DocdbTags(), + } + + _, err := conn.AddTagsToResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// DynamodbUpdateTags updates dynamodb service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func DynamodbUpdateTags(conn *dynamodb.DynamoDB, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &dynamodb.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &dynamodb.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().DynamodbTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// EcrUpdateTags updates ecr service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func EcrUpdateTags(conn *ecr.ECR, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &ecr.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &ecr.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().EcrTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// EcsUpdateTags updates ecs service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func EcsUpdateTags(conn *ecs.ECS, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &ecs.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &ecs.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().EcsTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// EfsUpdateTags updates efs service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func EfsUpdateTags(conn *efs.EFS, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &efs.DeleteTagsInput{ + FileSystemId: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.DeleteTags(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &efs.CreateTagsInput{ + FileSystemId: aws.String(identifier), + Tags: updatedTags.IgnoreAws().EfsTags(), + } + + _, err := conn.CreateTags(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// ElasticacheUpdateTags updates elasticache service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func ElasticacheUpdateTags(conn *elasticache.ElastiCache, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &elasticache.RemoveTagsFromResourceInput{ + ResourceName: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.RemoveTagsFromResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &elasticache.AddTagsToResourceInput{ + ResourceName: aws.String(identifier), + Tags: updatedTags.IgnoreAws().ElasticacheTags(), + } + + _, err := conn.AddTagsToResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// ElasticsearchserviceUpdateTags updates elasticsearchservice service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func ElasticsearchserviceUpdateTags(conn *elasticsearchservice.ElasticsearchService, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &elasticsearchservice.RemoveTagsInput{ + ARN: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.RemoveTags(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &elasticsearchservice.AddTagsInput{ + ARN: aws.String(identifier), + TagList: updatedTags.IgnoreAws().ElasticsearchserviceTags(), + } + + _, err := conn.AddTags(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// EmrUpdateTags updates emr service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func EmrUpdateTags(conn *emr.EMR, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &emr.RemoveTagsInput{ + ResourceId: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.RemoveTags(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &emr.AddTagsInput{ + ResourceId: aws.String(identifier), + Tags: updatedTags.IgnoreAws().EmrTags(), + } + + _, err := conn.AddTags(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// FirehoseUpdateTags updates firehose service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func FirehoseUpdateTags(conn *firehose.Firehose, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &firehose.UntagDeliveryStreamInput{ + DeliveryStreamName: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagDeliveryStream(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &firehose.TagDeliveryStreamInput{ + DeliveryStreamName: aws.String(identifier), + Tags: updatedTags.IgnoreAws().FirehoseTags(), + } + + _, err := conn.TagDeliveryStream(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// FsxUpdateTags updates fsx service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func FsxUpdateTags(conn *fsx.FSx, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &fsx.UntagResourceInput{ + ResourceARN: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &fsx.TagResourceInput{ + ResourceARN: aws.String(identifier), + Tags: updatedTags.IgnoreAws().FsxTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// GlueUpdateTags updates glue service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func GlueUpdateTags(conn *glue.Glue, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &glue.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagsToRemove: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &glue.TagResourceInput{ + ResourceArn: aws.String(identifier), + TagsToAdd: updatedTags.IgnoreAws().GlueTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// GuarddutyUpdateTags updates guardduty service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func GuarddutyUpdateTags(conn *guardduty.GuardDuty, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &guardduty.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &guardduty.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().GuarddutyTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// IotUpdateTags updates iot service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func IotUpdateTags(conn *iot.IoT, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &iot.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &iot.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().IotTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// IotanalyticsUpdateTags updates iotanalytics service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func IotanalyticsUpdateTags(conn *iotanalytics.IoTAnalytics, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &iotanalytics.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &iotanalytics.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().IotanalyticsTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// IoteventsUpdateTags updates iotevents service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func IoteventsUpdateTags(conn *iotevents.IoTEvents, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &iotevents.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &iotevents.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().IoteventsTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// KafkaUpdateTags updates kafka service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func KafkaUpdateTags(conn *kafka.Kafka, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &kafka.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &kafka.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().KafkaTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// KinesisanalyticsUpdateTags updates kinesisanalytics service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func KinesisanalyticsUpdateTags(conn *kinesisanalytics.KinesisAnalytics, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &kinesisanalytics.UntagResourceInput{ + ResourceARN: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &kinesisanalytics.TagResourceInput{ + ResourceARN: aws.String(identifier), + Tags: updatedTags.IgnoreAws().KinesisanalyticsTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// Kinesisanalyticsv2UpdateTags updates kinesisanalyticsv2 service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func Kinesisanalyticsv2UpdateTags(conn *kinesisanalyticsv2.KinesisAnalyticsV2, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &kinesisanalyticsv2.UntagResourceInput{ + ResourceARN: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &kinesisanalyticsv2.TagResourceInput{ + ResourceARN: aws.String(identifier), + Tags: updatedTags.IgnoreAws().Kinesisanalyticsv2Tags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// KmsUpdateTags updates kms service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func KmsUpdateTags(conn *kms.KMS, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &kms.UntagResourceInput{ + KeyId: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &kms.TagResourceInput{ + KeyId: aws.String(identifier), + Tags: updatedTags.IgnoreAws().KmsTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// LambdaUpdateTags updates lambda service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func LambdaUpdateTags(conn *lambda.Lambda, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &lambda.UntagResourceInput{ + Resource: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &lambda.TagResourceInput{ + Resource: aws.String(identifier), + Tags: updatedTags.IgnoreAws().LambdaTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// LicensemanagerUpdateTags updates licensemanager service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func LicensemanagerUpdateTags(conn *licensemanager.LicenseManager, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &licensemanager.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &licensemanager.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().LicensemanagerTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// LightsailUpdateTags updates lightsail service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func LightsailUpdateTags(conn *lightsail.Lightsail, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &lightsail.UntagResourceInput{ + ResourceName: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &lightsail.TagResourceInput{ + ResourceName: aws.String(identifier), + Tags: updatedTags.IgnoreAws().LightsailTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// MediaconnectUpdateTags updates mediaconnect service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func MediaconnectUpdateTags(conn *mediaconnect.MediaConnect, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &mediaconnect.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &mediaconnect.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().MediaconnectTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// MediaconvertUpdateTags updates mediaconvert service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func MediaconvertUpdateTags(conn *mediaconvert.MediaConvert, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &mediaconvert.UntagResourceInput{ + Arn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &mediaconvert.TagResourceInput{ + Arn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().MediaconvertTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// MedialiveUpdateTags updates medialive service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func MedialiveUpdateTags(conn *medialive.MediaLive, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &medialive.DeleteTagsInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.DeleteTags(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &medialive.CreateTagsInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().MedialiveTags(), + } + + _, err := conn.CreateTags(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// MediapackageUpdateTags updates mediapackage service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func MediapackageUpdateTags(conn *mediapackage.MediaPackage, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &mediapackage.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &mediapackage.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().MediapackageTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// MediastoreUpdateTags updates mediastore service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func MediastoreUpdateTags(conn *mediastore.MediaStore, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &mediastore.UntagResourceInput{ + Resource: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &mediastore.TagResourceInput{ + Resource: aws.String(identifier), + Tags: updatedTags.IgnoreAws().MediastoreTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// MqUpdateTags updates mq service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func MqUpdateTags(conn *mq.MQ, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &mq.DeleteTagsInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.DeleteTags(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &mq.CreateTagsInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().MqTags(), + } + + _, err := conn.CreateTags(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// NeptuneUpdateTags updates neptune service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func NeptuneUpdateTags(conn *neptune.Neptune, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &neptune.RemoveTagsFromResourceInput{ + ResourceName: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.RemoveTagsFromResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &neptune.AddTagsToResourceInput{ + ResourceName: aws.String(identifier), + Tags: updatedTags.IgnoreAws().NeptuneTags(), + } + + _, err := conn.AddTagsToResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// OpsworksUpdateTags updates opsworks service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func OpsworksUpdateTags(conn *opsworks.OpsWorks, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &opsworks.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &opsworks.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().OpsworksTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// OrganizationsUpdateTags updates organizations service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func OrganizationsUpdateTags(conn *organizations.Organizations, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &organizations.UntagResourceInput{ + ResourceId: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &organizations.TagResourceInput{ + ResourceId: aws.String(identifier), + Tags: updatedTags.IgnoreAws().OrganizationsTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// RamUpdateTags updates ram service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func RamUpdateTags(conn *ram.RAM, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &ram.UntagResourceInput{ + ResourceShareArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &ram.TagResourceInput{ + ResourceShareArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().RamTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// RdsUpdateTags updates rds service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func RdsUpdateTags(conn *rds.RDS, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &rds.RemoveTagsFromResourceInput{ + ResourceName: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.RemoveTagsFromResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &rds.AddTagsToResourceInput{ + ResourceName: aws.String(identifier), + Tags: updatedTags.IgnoreAws().RdsTags(), + } + + _, err := conn.AddTagsToResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// RedshiftUpdateTags updates redshift service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func RedshiftUpdateTags(conn *redshift.Redshift, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &redshift.DeleteTagsInput{ + ResourceName: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.DeleteTags(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &redshift.CreateTagsInput{ + ResourceName: aws.String(identifier), + Tags: updatedTags.IgnoreAws().RedshiftTags(), + } + + _, err := conn.CreateTags(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// Route53resolverUpdateTags updates route53resolver service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func Route53resolverUpdateTags(conn *route53resolver.Route53Resolver, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &route53resolver.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &route53resolver.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().Route53resolverTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// SecretsmanagerUpdateTags updates secretsmanager service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func SecretsmanagerUpdateTags(conn *secretsmanager.SecretsManager, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &secretsmanager.UntagResourceInput{ + SecretId: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &secretsmanager.TagResourceInput{ + SecretId: aws.String(identifier), + Tags: updatedTags.IgnoreAws().SecretsmanagerTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// SecurityhubUpdateTags updates securityhub service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func SecurityhubUpdateTags(conn *securityhub.SecurityHub, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &securityhub.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &securityhub.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().SecurityhubTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// SfnUpdateTags updates sfn service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func SfnUpdateTags(conn *sfn.SFN, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &sfn.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &sfn.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().SfnTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// SnsUpdateTags updates sns service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func SnsUpdateTags(conn *sns.SNS, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &sns.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &sns.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().SnsTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// SsmUpdateTags updates ssm service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func SsmUpdateTags(conn *ssm.SSM, identifier string, resourceType string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &ssm.RemoveTagsFromResourceInput{ + ResourceId: aws.String(identifier), + ResourceType: aws.String(resourceType), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.RemoveTagsFromResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &ssm.AddTagsToResourceInput{ + ResourceId: aws.String(identifier), + ResourceType: aws.String(resourceType), + Tags: updatedTags.IgnoreAws().SsmTags(), + } + + _, err := conn.AddTagsToResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// StoragegatewayUpdateTags updates storagegateway service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func StoragegatewayUpdateTags(conn *storagegateway.StorageGateway, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &storagegateway.RemoveTagsFromResourceInput{ + ResourceARN: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.RemoveTagsFromResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &storagegateway.AddTagsToResourceInput{ + ResourceARN: aws.String(identifier), + Tags: updatedTags.IgnoreAws().StoragegatewayTags(), + } + + _, err := conn.AddTagsToResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// SwfUpdateTags updates swf service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func SwfUpdateTags(conn *swf.SWF, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &swf.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &swf.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().SwfTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// TransferUpdateTags updates transfer service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func TransferUpdateTags(conn *transfer.Transfer, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &transfer.UntagResourceInput{ + Arn: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &transfer.TagResourceInput{ + Arn: aws.String(identifier), + Tags: updatedTags.IgnoreAws().TransferTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// WafUpdateTags updates waf service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func WafUpdateTags(conn *waf.WAF, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &waf.UntagResourceInput{ + ResourceARN: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.UntagResource(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &waf.TagResourceInput{ + ResourceARN: aws.String(identifier), + Tags: updatedTags.IgnoreAws().WafTags(), + } + + _, err := conn.TagResource(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} + +// WorkspacesUpdateTags updates workspaces service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func WorkspacesUpdateTags(conn *workspaces.WorkSpaces, identifier string, oldTagsMap interface{}, newTagsMap interface{}) error { + oldTags := New(oldTagsMap) + newTags := New(newTagsMap) + + if removedTags := oldTags.Removed(newTags); len(removedTags) > 0 { + input := &workspaces.DeleteTagsInput{ + ResourceId: aws.String(identifier), + TagKeys: aws.StringSlice(removedTags.Keys()), + } + + _, err := conn.DeleteTags(input) + + if err != nil { + return fmt.Errorf("error untagging resource (%s): %s", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &workspaces.CreateTagsInput{ + ResourceId: aws.String(identifier), + Tags: updatedTags.IgnoreAws().WorkspacesTags(), + } + + _, err := conn.CreateTags(input) + + if err != nil { + return fmt.Errorf("error tagging resource (%s): %s", identifier, err) + } + } + + return nil +} From ea9bfebf99b720f4ad33c399024e528109b5fef9 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 3 Sep 2019 15:07:38 -0400 Subject: [PATCH 2/5] resource/aws_athena_workgroup: Refactor to use keyvaluetags Output from acceptance testing: ``` --- PASS: TestAccAWSAthenaWorkGroup_disappears (13.62s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_ResultConfiguration_EncryptionConfiguration_SseS3 (20.73s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_BytesScannedCutoffPerQuery (25.21s) --- PASS: TestAccAWSAthenaWorkGroup_Description (29.82s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_EnforceWorkgroupConfiguration (31.01s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_PublishCloudWatchMetricsEnabled (36.91s) --- PASS: TestAccAWSAthenaWorkGroup_Tags (40.80s) --- PASS: TestAccAWSAthenaWorkGroup_State (43.45s) --- PASS: TestAccAWSAthenaWorkGroup_basic (57.10s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_ResultConfiguration_EncryptionConfiguration_Kms (59.79s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_ResultConfiguration_OutputLocation (60.00s) ``` --- aws/resource_aws_athena_workgroup.go | 18 ++-- aws/tagsAthena.go | 133 --------------------------- aws/tagsAthena_test.go | 115 ----------------------- 3 files changed, 8 insertions(+), 258 deletions(-) delete mode 100644 aws/tagsAthena.go delete mode 100644 aws/tagsAthena_test.go diff --git a/aws/resource_aws_athena_workgroup.go b/aws/resource_aws_athena_workgroup.go index 4bd1b45ef15..f9dfd813645 100644 --- a/aws/resource_aws_athena_workgroup.go +++ b/aws/resource_aws_athena_workgroup.go @@ -10,6 +10,7 @@ import ( "github.com/aws/aws-sdk-go/service/athena" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsAthenaWorkgroup() *schema.Resource { @@ -136,7 +137,7 @@ func resourceAwsAthenaWorkgroupCreate(d *schema.ResourceData, meta interface{}) // Prevent the below error: // InvalidRequestException: Tags provided upon WorkGroup creation must not be empty if v := d.Get("tags").(map[string]interface{}); len(v) > 0 { - input.Tags = tagsFromMapAthena(v) + input.Tags = keyvaluetags.New(v).IgnoreAws().AthenaTags() } _, err := conn.CreateWorkGroup(input) @@ -198,15 +199,13 @@ func resourceAwsAthenaWorkgroupRead(d *schema.ResourceData, meta interface{}) er d.Set("name", resp.WorkGroup.Name) d.Set("state", resp.WorkGroup.State) - err = saveTagsAthena(conn, d, d.Get("arn").(string)) + tags, err := keyvaluetags.AthenaListTags(conn, arn.String()) - if isAWSErr(err, athena.ErrCodeInvalidRequestException, "is not found") { - log.Printf("[WARN] Athena WorkGroup (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil + if err != nil { + return fmt.Errorf("error listing tags for resource (%s): %s", arn, err) } - if err != nil { + if d.Set("tags", tags.IgnoreAws().Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } @@ -262,9 +261,8 @@ func resourceAwsAthenaWorkgroupUpdate(d *schema.ResourceData, meta interface{}) } if d.HasChange("tags") { - err := setTagsAthena(conn, d, d.Get("arn").(string)) - - if err != nil { + o, n := d.GetChange("tags") + if err := keyvaluetags.AthenaUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { return fmt.Errorf("error updating tags: %s", err) } } diff --git a/aws/tagsAthena.go b/aws/tagsAthena.go deleted file mode 100644 index ba004e8786e..00000000000 --- a/aws/tagsAthena.go +++ /dev/null @@ -1,133 +0,0 @@ -package aws - -import ( - "fmt" - "log" - "regexp" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/athena" - "github.com/hashicorp/terraform/helper/schema" -) - -// setTags is a helper to set the tags for a resource. It expects the -// tags field to be named "tags" -func setTagsAthena(conn *athena.Athena, d *schema.ResourceData, arn string) error { - if d.HasChange("tags") { - oraw, nraw := d.GetChange("tags") - o := oraw.(map[string]interface{}) - n := nraw.(map[string]interface{}) - create, remove := diffTagsAthena(tagsFromMapAthena(o), tagsFromMapAthena(n)) - - // Set tags - if len(remove) > 0 { - input := athena.UntagResourceInput{ - ResourceARN: aws.String(arn), - TagKeys: remove, - } - log.Printf("[DEBUG] Removing Athena tags: %s", input) - _, err := conn.UntagResource(&input) - if err != nil { - return err - } - } - if len(create) > 0 { - input := athena.TagResourceInput{ - ResourceARN: aws.String(arn), - Tags: create, - } - log.Printf("[DEBUG] Adding Athena tags: %s", input) - _, err := conn.TagResource(&input) - if err != nil { - return err - } - } - } - - return nil -} - -// diffTags takes our tags locally and the ones remotely and returns -// the set of tags that must be created, and the set of tags that must -// be destroyed. -func diffTagsAthena(oldTags, newTags []*athena.Tag) ([]*athena.Tag, []*string) { - // First, we're creating everything we have - create := make(map[string]interface{}) - for _, t := range newTags { - create[aws.StringValue(t.Key)] = aws.StringValue(t.Value) - } - - // Build the list of what to remove - var remove []*string - for _, t := range oldTags { - old, ok := create[aws.StringValue(t.Key)] - if !ok || old != aws.StringValue(t.Value) { - remove = append(remove, t.Key) - } else if ok { - // already present so remove from new - delete(create, aws.StringValue(t.Key)) - } - } - - return tagsFromMapAthena(create), remove -} - -// tagsFromMap returns the tags for the given map of data. -func tagsFromMapAthena(m map[string]interface{}) []*athena.Tag { - result := make([]*athena.Tag, 0, len(m)) - for k, v := range m { - t := &athena.Tag{ - Key: aws.String(k), - Value: aws.String(v.(string)), - } - if !tagIgnoredAthena(t) { - result = append(result, t) - } - } - - return result -} - -// tagsToMap turns the list of tags into a map. -func tagsToMapAthena(ts []*athena.Tag) map[string]string { - result := make(map[string]string) - for _, t := range ts { - if !tagIgnoredAthena(t) { - result[aws.StringValue(t.Key)] = aws.StringValue(t.Value) - } - } - - return result -} - -func saveTagsAthena(conn *athena.Athena, d *schema.ResourceData, arn string) error { - resp, err := conn.ListTagsForResource(&athena.ListTagsForResourceInput{ - ResourceARN: aws.String(arn), - }) - - if err != nil { - return fmt.Errorf("Error retreiving tags for ARN: %s", arn) - } - - var tagList []*athena.Tag - if len(resp.Tags) > 0 { - tagList = resp.Tags - } - - return d.Set("tags", tagsToMapAthena(tagList)) -} - -// compare a tag against a list of strings and checks if it should -// be ignored or not -func tagIgnoredAthena(t *athena.Tag) bool { - filter := []string{"^aws:"} - for _, v := range filter { - log.Printf("[DEBUG] Matching %v with %v\n", v, aws.StringValue(t.Key)) - r, _ := regexp.MatchString(v, aws.StringValue(t.Key)) - if r { - log.Printf("[DEBUG] Found AWS specific tag %s (val: %s), ignoring.\n", aws.StringValue(t.Key), aws.StringValue(t.Value)) - return true - } - } - return false -} diff --git a/aws/tagsAthena_test.go b/aws/tagsAthena_test.go deleted file mode 100644 index 63f4bdeab48..00000000000 --- a/aws/tagsAthena_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package aws - -import ( - "reflect" - "testing" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/athena" -) - -// go test -v -run="TestDiffAthenaTags" -func TestDiffAthenaTags(t *testing.T) { - cases := []struct { - Old, New map[string]interface{} - Create map[string]string - Remove []string - }{ - // Add - { - Old: map[string]interface{}{ - "foo": "bar", - }, - New: map[string]interface{}{ - "foo": "bar", - "bar": "baz", - }, - Create: map[string]string{ - "bar": "baz", - }, - Remove: []string{}, - }, - - // Modify - { - Old: map[string]interface{}{ - "foo": "bar", - }, - New: map[string]interface{}{ - "foo": "baz", - }, - Create: map[string]string{ - "foo": "baz", - }, - Remove: []string{ - "foo", - }, - }, - - // Overlap - { - Old: map[string]interface{}{ - "foo": "bar", - "hello": "world", - }, - New: map[string]interface{}{ - "foo": "baz", - "hello": "world", - }, - Create: map[string]string{ - "foo": "baz", - }, - Remove: []string{ - "foo", - }, - }, - - // Remove - { - Old: map[string]interface{}{ - "foo": "bar", - "bar": "baz", - }, - New: map[string]interface{}{ - "foo": "bar", - }, - Create: map[string]string{}, - Remove: []string{ - "bar", - }, - }, - } - - for i, tc := range cases { - c, r := diffTagsAthena(tagsFromMapAthena(tc.Old), tagsFromMapAthena(tc.New)) - cm := tagsToMapAthena(c) - rl := []string{} - for _, tagName := range r { - rl = append(rl, *tagName) - } - if !reflect.DeepEqual(cm, tc.Create) { - t.Fatalf("%d: bad create: %#v", i, cm) - } - if !reflect.DeepEqual(rl, tc.Remove) { - t.Fatalf("%d: bad remove: %#v", i, rl) - } - } -} - -// go test -v -run="TestIgnoringTagsAthena" -func TestIgnoringTagsAthena(t *testing.T) { - var ignoredTags []*athena.Tag - ignoredTags = append(ignoredTags, &athena.Tag{ - Key: aws.String("aws:cloudformation:logical-id"), - Value: aws.String("foo"), - }) - ignoredTags = append(ignoredTags, &athena.Tag{ - Key: aws.String("aws:foo:bar"), - Value: aws.String("baz"), - }) - for _, tag := range ignoredTags { - if !tagIgnoredAthena(tag) { - t.Fatalf("Tag %v with value %v not ignored, but should be!", *tag.Key, *tag.Value) - } - } -} From 6bad392122deb57d82bad5cc532f850a4dd8d83b Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 3 Sep 2019 15:15:06 -0400 Subject: [PATCH 3/5] internal/keyvaluetags/generators: Adjust README content to include listtags example and fix title of servicetags --- .../keyvaluetags/generators/listtags/README.md | 17 ++++++++++++++++- .../generators/servicetags/README.md | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/aws/internal/keyvaluetags/generators/listtags/README.md b/aws/internal/keyvaluetags/generators/listtags/README.md index a26e28c06f6..81ea0ecc6cb 100644 --- a/aws/internal/keyvaluetags/generators/listtags/README.md +++ b/aws/internal/keyvaluetags/generators/listtags/README.md @@ -11,7 +11,22 @@ To run this code generator, execute `go generate ./...` from the root of the rep ## Example Output ```go - +// AmplifyListTags lists amplify service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func AmplifyListTags(conn *amplify.Amplify, identifier string) (KeyValueTags, error) { + input := &lify.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(input) + + if err != nil { + return New(nil), err + } + + return AmplifyKeyValueTags(output.Tags), nil +} ``` ## Implementing a New Generated Service diff --git a/aws/internal/keyvaluetags/generators/servicetags/README.md b/aws/internal/keyvaluetags/generators/servicetags/README.md index dc07d1e943a..014b1b3cecd 100644 --- a/aws/internal/keyvaluetags/generators/servicetags/README.md +++ b/aws/internal/keyvaluetags/generators/servicetags/README.md @@ -1,4 +1,4 @@ -# updatetags +# servicetags This package contains a code generator to consistently handle the various AWS Go SDK service implementations for converting service tag/map types to/from `KeyValueTags`. Not all AWS Go SDK services that support tagging are generated in this manner. From 3d99d3fcf2a4f9c84198ac6c7f106c1b6f7d0613 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 5 Sep 2019 22:17:39 -0400 Subject: [PATCH 4/5] resource/aws_athena_workgroup: Ensure we check tags attribute setting error Output from acceptance testing: ``` --- PASS: TestAccAWSAthenaWorkGroup_disappears (10.58s) --- PASS: TestAccAWSAthenaWorkGroup_basic (14.71s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_ResultConfiguration_EncryptionConfiguration_SseS3 (14.98s) --- PASS: TestAccAWSAthenaWorkGroup_Description (22.34s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_PublishCloudWatchMetricsEnabled (22.90s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_BytesScannedCutoffPerQuery (22.92s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_EnforceWorkgroupConfiguration (23.13s) --- PASS: TestAccAWSAthenaWorkGroup_State (32.09s) --- PASS: TestAccAWSAthenaWorkGroup_Tags (32.27s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_ResultConfiguration_EncryptionConfiguration_Kms (54.86s) --- PASS: TestAccAWSAthenaWorkGroup_Configuration_ResultConfiguration_OutputLocation (54.90s) ``` --- aws/resource_aws_athena_workgroup.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_athena_workgroup.go b/aws/resource_aws_athena_workgroup.go index f9dfd813645..e9f25f37479 100644 --- a/aws/resource_aws_athena_workgroup.go +++ b/aws/resource_aws_athena_workgroup.go @@ -205,7 +205,7 @@ func resourceAwsAthenaWorkgroupRead(d *schema.ResourceData, meta interface{}) er return fmt.Errorf("error listing tags for resource (%s): %s", arn, err) } - if d.Set("tags", tags.IgnoreAws().Map()); err != nil { + if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } From 6a3765b85ea79f58c730869d5ac38b926dd9beef Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Sun, 8 Sep 2019 10:48:21 -0400 Subject: [PATCH 5/5] internal/keyvaluetags: Implement IgnoreRds for Neptune and RDS Reference: https://github.com/terraform-providers/terraform-provider-aws/pull/10018#pullrequestreview-284844876 --- aws/internal/keyvaluetags/key_value_tags.go | 30 ++++++++-- .../keyvaluetags/key_value_tags_test.go | 56 +++++++++++++++++++ 2 files changed, 82 insertions(+), 4 deletions(-) diff --git a/aws/internal/keyvaluetags/key_value_tags.go b/aws/internal/keyvaluetags/key_value_tags.go index 6e618788596..6ac2e380b3a 100644 --- a/aws/internal/keyvaluetags/key_value_tags.go +++ b/aws/internal/keyvaluetags/key_value_tags.go @@ -8,9 +8,12 @@ import ( "strings" ) -const AwsTagKeyPrefix = `aws:` -const ElasticbeanstalkTagKeyPrefix = `elasticbeanstalk:` -const NameTagKey = `Name` +const ( + AwsTagKeyPrefix = `aws:` + ElasticbeanstalkTagKeyPrefix = `elasticbeanstalk:` + NameTagKey = `Name` + RdsTagKeyPrefix = `rds:` +) // KeyValueTags is a standard implementation for AWS key-value resource tags. // The AWS Go SDK is split into multiple service packages, each service with @@ -31,7 +34,7 @@ func (tags KeyValueTags) IgnoreAws() KeyValueTags { return result } -// IgnoreAws returns non-AWS and non-Elasticbeanstalk tag keys. +// IgnoreElasticbeanstalk returns non-AWS and non-Elasticbeanstalk tag keys. func (tags KeyValueTags) IgnoreElasticbeanstalk() KeyValueTags { result := make(KeyValueTags) @@ -54,6 +57,25 @@ func (tags KeyValueTags) IgnoreElasticbeanstalk() KeyValueTags { return result } +// IgnoreRDS returns non-AWS and non-RDS tag keys. +func (tags KeyValueTags) IgnoreRds() KeyValueTags { + result := make(KeyValueTags) + + for k, v := range tags { + if strings.HasPrefix(k, AwsTagKeyPrefix) { + continue + } + + if strings.HasPrefix(k, RdsTagKeyPrefix) { + continue + } + + result[k] = v + } + + return result +} + // Ignore returns non-matching tag keys. func (tags KeyValueTags) Ignore(ignoreTags KeyValueTags) KeyValueTags { result := make(KeyValueTags) diff --git a/aws/internal/keyvaluetags/key_value_tags_test.go b/aws/internal/keyvaluetags/key_value_tags_test.go index 91865710a72..9a7f80365ad 100644 --- a/aws/internal/keyvaluetags/key_value_tags_test.go +++ b/aws/internal/keyvaluetags/key_value_tags_test.go @@ -118,6 +118,62 @@ func TestKeyValueTagsIgnoreElasticbeanstalk(t *testing.T) { } } +func TestKeyValueTagsIgnoreRds(t *testing.T) { + testCases := []struct { + name string + tags KeyValueTags + want map[string]string + }{ + { + name: "empty", + tags: New(map[string]string{}), + want: map[string]string{}, + }, + { + name: "all", + tags: New(map[string]string{ + "aws:cloudformation:key1": "value1", + "rds:key2": "value2", + }), + want: map[string]string{}, + }, + { + name: "mixed", + tags: New(map[string]string{ + "aws:cloudformation:key1": "value1", + "key2": "value2", + "rds:key3": "value3", + "key4": "value4", + }), + want: map[string]string{ + "key2": "value2", + "key4": "value4", + }, + }, + { + name: "none", + tags: New(map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }), + want: map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := testCase.tags.IgnoreRds() + + testKeyValueTagsVerifyMap(t, got.Map(), testCase.want) + }) + } +} + func TestKeyValueTagsIgnore(t *testing.T) { testCases := []struct { name string