Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement configuring ignore_tags via environment variables #35264

Merged
merged 8 commits into from
Aug 6, 2024
9 changes: 9 additions & 0 deletions internal/envvar/envvar.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ const (
AccAssumeRoleARN = "TF_ACC_ASSUME_ROLE_ARN"
)

// Custom environment variables used for provider configuration via environment.
const (
// A list of tag keys to be ignored by the provider.
IgnoreTagsKeys = "TF_AWS_IGNORE_TAGS_KEYS"

// A list of tag key prefixes to be ignored by the provider.
IgnoreTagsKeyPrefixes = "TF_AWS_IGNORE_TAGS_KEY_PREFIXES"
)

// Custom environment variables used for assuming a role with resource sweepers
const (
// The ARN of the IAM Role to assume
Expand Down
7 changes: 5 additions & 2 deletions internal/provider/fwprovider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/envvar"
fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/names"
Expand Down Expand Up @@ -269,12 +270,14 @@ func (p *fwprovider) Schema(ctx context.Context, req provider.SchemaRequest, res
"key_prefixes": schema.SetAttribute{
ElementType: types.StringType,
Optional: true,
Description: "Resource tag key prefixes to ignore across all resources.",
Description: "Resource tag key prefixes to ignore across all resources. " +
"Can also be configured with the " + envvar.IgnoreTagsKeyPrefixes + " environment variable.",
},
"keys": schema.SetAttribute{
ElementType: types.StringType,
Optional: true,
Description: "Resource tag keys to ignore across all resources.",
Description: "Resource tag keys to ignore across all resources. " +
"Can also be configured with the " + envvar.IgnoreTagsKeys + " environment variable.",
},
},
},
Expand Down
58 changes: 42 additions & 16 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"log"
"os"
"strings"
"time"

"github.com/YakDriver/regexache"
Expand All @@ -20,6 +21,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/envvar"
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
"github.com/hashicorp/terraform-provider-aws/internal/flex"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
Expand Down Expand Up @@ -111,16 +113,18 @@ func New(ctx context.Context) (*schema.Provider, error) {
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"keys": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Description: "Resource tag keys to ignore across all resources.",
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Description: "Resource tag keys to ignore across all resources. " +
"Can also be configured with the " + envvar.IgnoreTagsKeys + " environment variable.",
},
"key_prefixes": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Description: "Resource tag key prefixes to ignore across all resources.",
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Description: "Resource tag key prefixes to ignore across all resources. " +
"Can also be configured with the " + envvar.IgnoreTagsKeyPrefixes + " environment variable.",
},
},
},
Expand Down Expand Up @@ -559,6 +563,8 @@ func configure(ctx context.Context, provider *schema.Provider, d *schema.Resourc

if v, ok := d.GetOk("ignore_tags"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil {
config.IgnoreTagsConfig = expandIgnoreTags(ctx, v.([]interface{})[0].(map[string]interface{}))
} else {
config.IgnoreTagsConfig = expandIgnoreTags(ctx, nil)
}

if v, ok := d.GetOk("max_retries"); ok {
Expand Down Expand Up @@ -847,21 +853,41 @@ func expandDefaultTags(ctx context.Context, tfMap map[string]interface{}) *tftag
}

func expandIgnoreTags(ctx context.Context, tfMap map[string]interface{}) *tftags.IgnoreConfig {
if tfMap == nil {
return nil
var keys, keyPrefixes []interface{}

if tfMap != nil {
if v, ok := tfMap["keys"].(*schema.Set); ok {
keys = v.List()
}
if v, ok := tfMap["key_prefixes"].(*schema.Set); ok {
keyPrefixes = v.List()
}
}

ignoreConfig := &tftags.IgnoreConfig{}
if v := os.Getenv(envvar.IgnoreTagsKeys); v != "" {
for _, k := range strings.Split(v, ",") {
if trimmed := strings.TrimSpace(k); trimmed != "" {
keys = append(keys, trimmed)
}
}
}

if v, ok := tfMap["keys"].(*schema.Set); ok {
ignoreConfig.Keys = tftags.New(ctx, v.List())
if v := os.Getenv(envvar.IgnoreTagsKeyPrefixes); v != "" {
for _, kp := range strings.Split(v, ",") {
if trimmed := strings.TrimSpace(kp); trimmed != "" {
keyPrefixes = append(keyPrefixes, trimmed)
}
}
}

if v, ok := tfMap["key_prefixes"].(*schema.Set); ok {
ignoreConfig.KeyPrefixes = tftags.New(ctx, v.List())
if len(keys) == 0 && len(keyPrefixes) == 0 {
return nil
}

return ignoreConfig
return &tftags.IgnoreConfig{
Keys: tftags.New(ctx, keys),
KeyPrefixes: tftags.New(ctx, keyPrefixes),
}
}

func expandEndpoints(_ context.Context, tfList []interface{}) (map[string]string, error) {
Expand Down
89 changes: 89 additions & 0 deletions internal/provider/provider_acc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/hashicorp/terraform-plugin-testing/terraform"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/envvar"
"github.com/hashicorp/terraform-provider-aws/internal/provider"
"github.com/hashicorp/terraform-provider-aws/names"
)
Expand Down Expand Up @@ -347,6 +348,94 @@ func TestAccProvider_IgnoreTagsKeys_multiple(t *testing.T) {
})
}

func TestAccProvider_IgnoreTagsKeys_envVarOnly(t *testing.T) {
ctx := acctest.Context(t)
var provider *schema.Provider

t.Setenv(envvar.IgnoreTagsKeys, "test3,test4")

resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t),
ProtoV5ProviderFactories: testAccProtoV5ProviderFactoriesInternal(ctx, t, &provider),
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: testAccProviderConfig_ignoreTagsKeys0(),
Check: resource.ComposeTestCheckFunc(
testAccCheckIgnoreTagsKeys(ctx, t, &provider, []string{"test3", "test4"}),
),
},
},
})
}

func TestAccProvider_IgnoreTagsKeys_envVarMerged(t *testing.T) {
ctx := acctest.Context(t)
var provider *schema.Provider

t.Setenv(envvar.IgnoreTagsKeys, "test3,test4")

resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t),
ProtoV5ProviderFactories: testAccProtoV5ProviderFactoriesInternal(ctx, t, &provider),
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: testAccProviderConfig_ignoreTagsKeys2("test1", "test2"),
Check: resource.ComposeTestCheckFunc(
testAccCheckIgnoreTagsKeys(ctx, t, &provider, []string{"test1", "test2", "test3", "test4"}),
),
},
},
})
}

func TestAccProvider_IgnoreTagsKeyPrefixes_envVarOnly(t *testing.T) {
ctx := acctest.Context(t)
var provider *schema.Provider

t.Setenv(envvar.IgnoreTagsKeyPrefixes, "test3,test4")

resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t),
ProtoV5ProviderFactories: testAccProtoV5ProviderFactoriesInternal(ctx, t, &provider),
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: testAccProviderConfig_ignoreTagsKeyPrefixes0(),
Check: resource.ComposeTestCheckFunc(
testAccCheckIgnoreTagsKeyPrefixes(ctx, t, &provider, []string{"test3", "test4"}),
),
},
},
})
}

func TestAccProvider_IgnoreTagsKeyPrefixes_envVarMerged(t *testing.T) {
ctx := acctest.Context(t)
var provider *schema.Provider

t.Setenv(envvar.IgnoreTagsKeyPrefixes, "test3,test4")

resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t),
ProtoV5ProviderFactories: testAccProtoV5ProviderFactoriesInternal(ctx, t, &provider),
CheckDestroy: nil,
Steps: []resource.TestStep{
{
Config: testAccProviderConfig_ignoreTagsKeyPrefixes2("test1", "test2"),
Check: resource.ComposeTestCheckFunc(
testAccCheckIgnoreTagsKeyPrefixes(ctx, t, &provider, []string{"test1", "test2", "test3", "test4"}),
),
},
},
})
}

func TestAccProvider_Region_c2s(t *testing.T) {
ctx := acctest.Context(t)
var provider *schema.Provider
Expand Down