Skip to content

Commit

Permalink
provider: Update preview ignore tags handling to configuration block …
Browse files Browse the repository at this point in the history
…and shared struct type (#12586)

Reference: #10689

Based on feedback and for future extensibility.

Output from acceptance testing:

```
--- PASS: TestAccAWSProvider_Endpoints (4.06s)
--- PASS: TestAccAWSProvider_Endpoints_Deprecated (4.04s)
--- PASS: TestAccAWSProvider_IgnoreTags_EmptyConfigurationBlock (3.99s)
--- PASS: TestAccAWSProvider_IgnoreTags_KeyPrefixes_Multiple (4.01s)
--- PASS: TestAccAWSProvider_IgnoreTags_KeyPrefixes_None (4.00s)
--- PASS: TestAccAWSProvider_IgnoreTags_KeyPrefixes_One (4.02s)
--- PASS: TestAccAWSProvider_IgnoreTags_Keys_Multiple (4.02s)
--- PASS: TestAccAWSProvider_IgnoreTags_Keys_None (3.96s)
--- PASS: TestAccAWSProvider_IgnoreTags_Keys_One (4.01s)
--- PASS: TestAccAWSProvider_Region_AwsChina (3.83s)
--- PASS: TestAccAWSProvider_Region_AwsCommercial (3.83s)
--- PASS: TestAccAWSProvider_Region_AwsGovCloudUs (3.77s)

--- PASS: TestAccAWSSubnet_availabilityZoneId (30.61s)
--- PASS: TestAccAWSSubnet_basic (30.88s)
--- PASS: TestAccAWSSubnet_enableIpv6 (49.79s)
--- PASS: TestAccAWSSubnet_ignoreTags (57.70s)
--- PASS: TestAccAWSSubnet_ipv6 (79.46s)

--- PASS: TestAccAWSVpc_AssignGeneratedIpv6CidrBlock (70.48s)
--- PASS: TestAccAWSVpc_basic (29.30s)
--- PASS: TestAccAWSVpc_bothDnsOptionsSet (30.18s)
--- PASS: TestAccAWSVpc_classiclinkDnsSupportOptionSet (31.10s)
--- PASS: TestAccAWSVpc_classiclinkOptionSet (30.48s)
--- PASS: TestAccAWSVpc_coreMismatchedDiffs (25.43s)
--- PASS: TestAccAWSVpc_DisabledDnsSupport (29.98s)
--- PASS: TestAccAWSVpc_disappears (15.64s)
--- PASS: TestAccAWSVpc_ignoreTags (51.16s)
--- PASS: TestAccAWSVpc_tags (48.55s)
--- PASS: TestAccAWSVpc_Tenancy (70.60s)
--- PASS: TestAccAWSVpc_update (44.36s)
```
  • Loading branch information
bflad authored Apr 7, 2020
1 parent 20559e2 commit 2b7cc8a
Show file tree
Hide file tree
Showing 10 changed files with 417 additions and 100 deletions.
13 changes: 5 additions & 8 deletions aws/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,9 @@ type Config struct {
AllowedAccountIds []string
ForbiddenAccountIds []string

Endpoints map[string]string
IgnoreTagPrefixes []string
IgnoreTags []string
Insecure bool
Endpoints map[string]string
IgnoreTagsConfig *keyvaluetags.IgnoreConfig
Insecure bool

SkipCredsValidation bool
SkipGetEC2Platforms bool
Expand Down Expand Up @@ -254,8 +253,7 @@ type AWSClient struct {
guarddutyconn *guardduty.GuardDuty
greengrassconn *greengrass.Greengrass
iamconn *iam.IAM
ignoreTagPrefixes keyvaluetags.KeyValueTags
ignoreTags keyvaluetags.KeyValueTags
IgnoreTagsConfig *keyvaluetags.IgnoreConfig
imagebuilderconn *imagebuilder.Imagebuilder
inspectorconn *inspector.Inspector
iotconn *iot.IoT
Expand Down Expand Up @@ -472,8 +470,7 @@ func (c *Config) Client() (interface{}, error) {
guarddutyconn: guardduty.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["guardduty"])})),
greengrassconn: greengrass.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["greengrass"])})),
iamconn: iam.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["iam"])})),
ignoreTagPrefixes: keyvaluetags.New(c.IgnoreTagPrefixes),
ignoreTags: keyvaluetags.New(c.IgnoreTags),
IgnoreTagsConfig: c.IgnoreTagsConfig,
imagebuilderconn: imagebuilder.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["imagebuilder"])})),
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"])})),
Expand Down
18 changes: 18 additions & 0 deletions aws/internal/keyvaluetags/key_value_tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ const (
RdsTagKeyPrefix = `rds:`
)

// IgnoreConfig contains various options for removing resource tags.
type IgnoreConfig struct {
Keys KeyValueTags
KeyPrefixes KeyValueTags
}

// 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
Expand All @@ -38,6 +44,18 @@ func (tags KeyValueTags) IgnoreAws() KeyValueTags {
return result
}

// IgnoreConfig returns any tags not removed by a given configuration.
func (tags KeyValueTags) IgnoreConfig(config *IgnoreConfig) KeyValueTags {
if config == nil {
return tags
}

result := tags.IgnorePrefixes(config.KeyPrefixes)
result = result.Ignore(config.Keys)

return result
}

// IgnoreElasticbeanstalk returns non-AWS and non-Elasticbeanstalk tag keys.
func (tags KeyValueTags) IgnoreElasticbeanstalk() KeyValueTags {
result := make(KeyValueTags)
Expand Down
197 changes: 197 additions & 0 deletions aws/internal/keyvaluetags/key_value_tags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,203 @@ func TestKeyValueTagsIgnoreAws(t *testing.T) {
}
}

func TestKeyValueTagsIgnoreConfig(t *testing.T) {
testCases := []struct {
name string
tags KeyValueTags
ignoreConfig *IgnoreConfig
want map[string]string
}{
{
name: "empty config",
tags: New(map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
}),
ignoreConfig: &IgnoreConfig{},
want: map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
},
},
{
name: "no config",
tags: New(map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
}),
ignoreConfig: nil,
want: map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
},
},
{
name: "no tags",
tags: New(map[string]string{}),
ignoreConfig: &IgnoreConfig{
KeyPrefixes: New([]string{
"key1",
"key2",
"key3",
}),
},
want: map[string]string{},
},
{
name: "keys all matching",
tags: New(map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
}),
ignoreConfig: &IgnoreConfig{
Keys: New(map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
}),
},
want: map[string]string{},
},
{
name: "keys some matching",
tags: New(map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
}),
ignoreConfig: &IgnoreConfig{
Keys: New(map[string]string{
"key1": "value1",
}),
},
want: map[string]string{
"key2": "value2",
"key3": "value3",
},
},
{
name: "keys none matching",
tags: New(map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
}),
ignoreConfig: &IgnoreConfig{
Keys: New(map[string]string{
"key4": "value4",
"key5": "value5",
"key6": "value6",
}),
},
want: map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
},
},
{
name: "keys and key prefixes",
tags: New(map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
}),
ignoreConfig: &IgnoreConfig{
Keys: New([]string{
"key1",
}),
KeyPrefixes: New([]string{
"key2",
}),
},
want: map[string]string{
"key3": "value3",
},
},
{
name: "key prefixes all exact",
tags: New(map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
}),
ignoreConfig: &IgnoreConfig{
KeyPrefixes: New([]string{
"key1",
"key2",
"key3",
}),
},
want: map[string]string{},
},
{
name: "key prefixes all prefixed",
tags: New(map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
}),
ignoreConfig: &IgnoreConfig{
KeyPrefixes: New([]string{
"key",
}),
},
want: map[string]string{},
},
{
name: "key prefixes some prefixed",
tags: New(map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
}),
ignoreConfig: &IgnoreConfig{
KeyPrefixes: New([]string{
"key1",
}),
},
want: map[string]string{
"key2": "value2",
"key3": "value3",
},
},
{
name: "key prefixes none prefixed",
tags: New(map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "value3",
}),
ignoreConfig: &IgnoreConfig{
KeyPrefixes: New([]string{
"key4",
"key5",
"key6",
}),
},
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.IgnoreConfig(testCase.ignoreConfig)

testKeyValueTagsVerifyMap(t, got.Map(), testCase.want)
})
}
}

func TestKeyValueTagsIgnoreElasticbeanstalk(t *testing.T) {
testCases := []struct {
name string
Expand Down
66 changes: 42 additions & 24 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
homedir "github.com/mitchellh/go-homedir"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
)

// Provider returns a terraform.ResourceProvider.
Expand Down Expand Up @@ -90,20 +91,29 @@ func Provider() terraform.ResourceProvider {

"endpoints": endpointsSchema(),

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

"ignore_tags": {
Type: schema.TypeSet,
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
Description: "Resource tag keys to ignore across all resources.",
MaxItems: 1,
Description: "Configuration block with settings to ignore resource tags across all resources.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"keys": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
Description: "Resource tag keys to ignore across all resources.",
},
"key_prefixes": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
Description: "Resource tag key prefixes to ignore across all resources.",
},
},
},
},

"insecure": {
Expand Down Expand Up @@ -1109,6 +1119,7 @@ func providerConfigure(d *schema.ResourceData, terraformVersion string) (interfa
Region: d.Get("region").(string),
Endpoints: make(map[string]string),
MaxRetries: d.Get("max_retries").(int),
IgnoreTagsConfig: expandProviderIgnoreTags(d.Get("ignore_tags").([]interface{})),
Insecure: d.Get("insecure").(bool),
SkipCredsValidation: d.Get("skip_credentials_validation").(bool),
SkipGetEC2Platforms: d.Get("skip_get_ec2_platforms").(bool),
Expand Down Expand Up @@ -1152,18 +1163,6 @@ func providerConfigure(d *schema.ResourceData, terraformVersion string) (interfa
}
}

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

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 Expand Up @@ -1241,3 +1240,22 @@ func endpointsSchema() *schema.Schema {
},
}
}

func expandProviderIgnoreTags(l []interface{}) *keyvaluetags.IgnoreConfig {
if len(l) == 0 || l[0] == nil {
return nil
}

ignoreConfig := &keyvaluetags.IgnoreConfig{}
m := l[0].(map[string]interface{})

if v, ok := m["keys"].(*schema.Set); ok {
ignoreConfig.Keys = keyvaluetags.New(v.List())
}

if v, ok := m["key_prefixes"].(*schema.Set); ok {
ignoreConfig.KeyPrefixes = keyvaluetags.New(v.List())
}

return ignoreConfig
}
Loading

0 comments on commit 2b7cc8a

Please sign in to comment.