Skip to content

Commit

Permalink
provider: Support ignore tags configuration
Browse files Browse the repository at this point in the history
Reference: #7926

Creates a new `ignore_tags` provider configuration, that wires into the `AWSClient` struct provided to all provider resources. This can be used to ignore certain tag keys across all resources of the provider, once the resource implements support.

Output from acceptance testing:

```
--- PASS: TestAccAWSProvider_IgnoreTags_One (3.70s)
--- PASS: TestAccAWSProvider_IgnoreTags_Multiple (3.71s)
--- PASS: TestAccAWSProvider_IgnoreTags_None (3.71s)
```
  • Loading branch information
bflad committed Oct 7, 2019
1 parent 62be6a5 commit 636c088
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 2 deletions.
8 changes: 6 additions & 2 deletions aws/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ import (
"github.com/aws/aws-sdk-go/service/xray"
awsbase "github.com/hashicorp/aws-sdk-go-base"
"github.com/hashicorp/terraform-plugin-sdk/helper/logging"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
)

type Config struct {
Expand All @@ -158,8 +159,9 @@ type Config struct {
AllowedAccountIds []string
ForbiddenAccountIds []string

Endpoints map[string]string
Insecure bool
Endpoints map[string]string
IgnoreTags []string
Insecure bool

SkipCredsValidation bool
SkipGetEC2Platforms bool
Expand Down Expand Up @@ -239,6 +241,7 @@ type AWSClient struct {
glueconn *glue.Glue
guarddutyconn *guardduty.GuardDuty
iamconn *iam.IAM
ignoreTags keyvaluetags.KeyValueTags
inspectorconn *inspector.Inspector
iotconn *iot.IoT
iotanalyticsconn *iotanalytics.IoTAnalytics
Expand Down Expand Up @@ -432,6 +435,7 @@ func (c *Config) Client() (interface{}, error) {
glueconn: glue.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["glue"])})),
guarddutyconn: guardduty.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["guardduty"])})),
iamconn: iam.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["iam"])})),
ignoreTags: keyvaluetags.New(c.IgnoreTags),
inspectorconn: inspector.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["inspector"])})),
iotconn: iot.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["iot"])})),
iotanalyticsconn: iotanalytics.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["iotanalytics"])})),
Expand Down
14 changes: 14 additions & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ func Provider() terraform.ResourceProvider {

"endpoints": endpointsSchema(),

"ignore_tags": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
Description: "Resource tag keys to ignore configuring across all resources.",
},

"insecure": {
Type: schema.TypeBool,
Optional: true,
Expand Down Expand Up @@ -1090,6 +1098,12 @@ func providerConfigure(d *schema.ResourceData, terraformVersion string) (interfa
}
}

if v, ok := d.GetOk("ignore_tags"); ok {
for _, ignoreTagRaw := range v.(*schema.Set).List() {
config.IgnoreTags = append(config.IgnoreTags, ignoreTagRaw.(string))
}
}

if v, ok := d.GetOk("allowed_account_ids"); ok {
for _, accountIDRaw := range v.(*schema.Set).List() {
config.AllowedAccountIds = append(config.AllowedAccountIds, accountIDRaw.(string))
Expand Down
166 changes: 166 additions & 0 deletions aws/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,14 @@ provider "aws" {
`, testAccGetAlternateRegion())
}

func testAccProviderConfigIgnoreTags1(key1 string) string {
return fmt.Sprintf(`
provider "aws" {
ignore_tags = [%[1]q]
}
`, key1)
}

// Provider configuration hardcoded for us-east-1.
// This should only be necessary for testing ACM Certificates with CloudFront
// related infrastucture such as API Gateway Domain Names for EDGE endpoints,
Expand Down Expand Up @@ -476,6 +484,60 @@ func TestAccAWSProvider_Endpoints_Deprecated(t *testing.T) {
})
}

func TestAccAWSProvider_IgnoreTags_None(t *testing.T) {
var providers []*schema.Provider

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: testAccProviderFactories(&providers),
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: testAccAWSProviderConfigIgnoreTags0(),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSProviderIgnoreTags(&providers, []string{}),
),
},
},
})
}

func TestAccAWSProvider_IgnoreTags_One(t *testing.T) {
var providers []*schema.Provider

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: testAccProviderFactories(&providers),
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: testAccAWSProviderConfigIgnoreTags1("test"),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSProviderIgnoreTags(&providers, []string{"test"}),
),
},
},
})
}

func TestAccAWSProvider_IgnoreTags_Multiple(t *testing.T) {
var providers []*schema.Provider

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: testAccProviderFactories(&providers),
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: testAccAWSProviderConfigIgnoreTags2("test1", "test2"),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSProviderIgnoreTags(&providers, []string{"test1", "test2"}),
),
},
},
})
}

func TestAccAWSProvider_Region_AwsChina(t *testing.T) {
var providers []*schema.Provider

Expand Down Expand Up @@ -691,6 +753,60 @@ func testAccCheckAWSProviderEndpointsDeprecated(providers *[]*schema.Provider) r
}
}

func testAccCheckAWSProviderIgnoreTags(providers *[]*schema.Provider, expectedIgnoreTags []string) resource.TestCheckFunc {
return func(s *terraform.State) error {
if providers == nil {
return fmt.Errorf("no providers initialized")
}

for _, provider := range *providers {
if provider == nil || provider.Meta() == nil || provider.Meta().(*AWSClient) == nil {
continue
}

providerClient := provider.Meta().(*AWSClient)

actualIgnoreTags := providerClient.ignoreTags.Keys()

if len(actualIgnoreTags) != len(expectedIgnoreTags) {
return fmt.Errorf("expected ignore_tags (%d) length, got: %d", len(expectedIgnoreTags), len(actualIgnoreTags))
}

for _, expectedElement := range expectedIgnoreTags {
var found bool

for _, actualElement := range actualIgnoreTags {
if actualElement == expectedElement {
found = true
break
}
}

if !found {
return fmt.Errorf("expected ignore_tags element, but was missing: %s", expectedElement)
}
}

for _, actualElement := range actualIgnoreTags {
var found bool

for _, expectedElement := range expectedIgnoreTags {
if actualElement == expectedElement {
found = true
break
}
}

if !found {
return fmt.Errorf("unexpected ignore_tags element: %s", actualElement)
}
}
}

return nil
}
}

func testAccCheckAWSProviderPartition(providers *[]*schema.Provider, expectedPartition string) resource.TestCheckFunc {
return func(s *terraform.State) error {
if providers == nil {
Expand Down Expand Up @@ -733,6 +849,56 @@ data "aws_arn" "test" {
`, endpoints)
}

func testAccAWSProviderConfigIgnoreTags0() string {
return fmt.Sprintf(`
provider "aws" {
skip_credentials_validation = true
skip_get_ec2_platforms = true
skip_metadata_api_check = true
skip_requesting_account_id = true
}
# Required to initialize the provider
data "aws_arn" "test" {
arn = "arn:aws:s3:::test"
}
`)
}

func testAccAWSProviderConfigIgnoreTags1(tag1 string) string {
return fmt.Sprintf(`
provider "aws" {
ignore_tags = [%[1]q]
skip_credentials_validation = true
skip_get_ec2_platforms = true
skip_metadata_api_check = true
skip_requesting_account_id = true
}
# Required to initialize the provider
data "aws_arn" "test" {
arn = "arn:aws:s3:::test"
}
`, tag1)
}

func testAccAWSProviderConfigIgnoreTags2(tag1, tag2 string) string {
return fmt.Sprintf(`
provider "aws" {
ignore_tags = [%[1]q, %[2]q]
skip_credentials_validation = true
skip_get_ec2_platforms = true
skip_metadata_api_check = true
skip_requesting_account_id = true
}
# Required to initialize the provider
data "aws_arn" "test" {
arn = "arn:aws:s3:::test"
}
`, tag1, tag2)
}

func testAccAWSProviderConfigRegion(region string) string {
return fmt.Sprintf(`
provider "aws" {
Expand Down
2 changes: 2 additions & 0 deletions website/docs/index.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ for more information about connecting to alternate AWS endpoints or AWS compatib
potentially end up destroying a live environment). Conflicts with
`allowed_account_ids`.

* `ignore_tags` - (Optional) List of exact resource tag keys to ignore across all resources handled by this provider (see the [Terraform multiple provider instances documentation](/docs/configuration/providers.html#alias-multiple-provider-instances) for more information about additional provider configurations). This is designed for situations where external systems are managing certain resource tags. It prevents Terraform from returning the tag in any `tags` attributes and displaying any configuration difference for the tag value. If any resource configuration still has this tag key configured in the `tags` argument, it will display a perpetual difference until the tag is removed from the argument or [`ignore_changes`](/docs/configuration/resources.html#ignore_changes) is also used.

* `insecure` - (Optional) Explicitly allow the provider to
perform "insecure" SSL requests. If omitted, default value is `false`.

Expand Down

0 comments on commit 636c088

Please sign in to comment.