-
Notifications
You must be signed in to change notification settings - Fork 9.2k
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
resourcegroupstaggingapi_resources - new data source #17804
Changes from all commits
593405d
f46a3bb
bd95c60
696e18a
ee73990
8679651
85128cb
aabf7d0
3e1561f
411a3ca
3a306cf
c601d00
6a61156
6a066b7
f1a4c07
974b36e
9408f23
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
```release-note:new-data-source | ||
aws_resourcegroupstaggingapi_resources | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
package aws | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" | ||
) | ||
|
||
func dataSourceAwsResourceGroupsTaggingAPIResources() *schema.Resource { | ||
return &schema.Resource{ | ||
Read: dataSourceAwsResourceGroupsTaggingAPIResourcesRead, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"exclude_compliant_resources": { | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
}, | ||
"include_compliance_details": { | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
}, | ||
"resource_arn_list": { | ||
Type: schema.TypeSet, | ||
Optional: true, | ||
Elem: &schema.Schema{Type: schema.TypeString}, | ||
ConflictsWith: []string{"tag_filter"}, | ||
}, | ||
"resource_type_filters": { | ||
Type: schema.TypeSet, | ||
Optional: true, | ||
MaxItems: 100, | ||
Elem: &schema.Schema{Type: schema.TypeString}, | ||
ConflictsWith: []string{"resource_arn_list"}, | ||
}, | ||
"tag_filter": { | ||
Type: schema.TypeList, | ||
Optional: true, | ||
MaxItems: 50, | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"key": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
"values": { | ||
Type: schema.TypeSet, | ||
Optional: true, | ||
MaxItems: 20, | ||
Elem: &schema.Schema{Type: schema.TypeString}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
"resource_tag_mapping_list": { | ||
Type: schema.TypeList, | ||
Computed: true, | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"resource_arn": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"compliance_details": { | ||
Type: schema.TypeList, | ||
Computed: true, | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"compliance_status": { | ||
Type: schema.TypeBool, | ||
Computed: true, | ||
}, | ||
"keys_with_noncompliant_values": { | ||
Type: schema.TypeSet, | ||
Computed: true, | ||
Elem: &schema.Schema{Type: schema.TypeString}, | ||
}, | ||
"non_compliant_keys": { | ||
Type: schema.TypeSet, | ||
Computed: true, | ||
Elem: &schema.Schema{Type: schema.TypeString}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
"tags": tagsSchemaComputed(), | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func dataSourceAwsResourceGroupsTaggingAPIResourcesRead(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*AWSClient).resourcegroupstaggingapiconn | ||
|
||
input := &resourcegroupstaggingapi.GetResourcesInput{} | ||
|
||
if v, ok := d.GetOk("include_compliance_details"); ok { | ||
input.IncludeComplianceDetails = aws.Bool(v.(bool)) | ||
} | ||
|
||
if v, ok := d.GetOk("exclude_compliant_resources"); ok { | ||
input.ExcludeCompliantResources = aws.Bool(v.(bool)) | ||
} | ||
|
||
if v, ok := d.GetOk("resource_arn_list"); ok && v.(*schema.Set).Len() > 0 { | ||
input.ResourceARNList = expandStringSet(v.(*schema.Set)) | ||
} | ||
|
||
if v, ok := d.GetOk("tag_filter"); ok { | ||
input.TagFilters = expandAwsResourceGroupsTaggingAPITagFilters(v.([]interface{})) | ||
} | ||
|
||
if v, ok := d.GetOk("resource_type_filters"); ok && v.(*schema.Set).Len() > 0 { | ||
input.ResourceTypeFilters = expandStringSet(v.(*schema.Set)) | ||
} | ||
|
||
var taggings []*resourcegroupstaggingapi.ResourceTagMapping | ||
|
||
err := conn.GetResourcesPages(input, func(page *resourcegroupstaggingapi.GetResourcesOutput, lastPage bool) bool { | ||
if page == nil { | ||
return !lastPage | ||
} | ||
|
||
taggings = append(taggings, page.ResourceTagMappingList...) | ||
return !lastPage | ||
}) | ||
if err != nil { | ||
return fmt.Errorf("error getting Resource Groups Tags API Resources: %w", err) | ||
} | ||
|
||
d.SetId(meta.(*AWSClient).partition) | ||
|
||
if err := d.Set("resource_tag_mapping_list", flattenAwsResourceGroupsTaggingAPIResourcesTagMappingList(taggings)); err != nil { | ||
return fmt.Errorf("error setting resource tag mapping list: %w", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func expandAwsResourceGroupsTaggingAPITagFilters(filters []interface{}) []*resourcegroupstaggingapi.TagFilter { | ||
result := make([]*resourcegroupstaggingapi.TagFilter, len(filters)) | ||
|
||
for i, filter := range filters { | ||
m := filter.(map[string]interface{}) | ||
|
||
result[i] = &resourcegroupstaggingapi.TagFilter{ | ||
Key: aws.String(m["key"].(string)), | ||
} | ||
|
||
if v, ok := m["values"]; ok && v.(*schema.Set).Len() > 0 { | ||
result[i].Values = expandStringSet(v.(*schema.Set)) | ||
} | ||
} | ||
|
||
return result | ||
} | ||
|
||
func flattenAwsResourceGroupsTaggingAPIResourcesTagMappingList(list []*resourcegroupstaggingapi.ResourceTagMapping) []map[string]interface{} { | ||
result := make([]map[string]interface{}, 0, len(list)) | ||
|
||
for _, i := range list { | ||
l := map[string]interface{}{ | ||
"resource_arn": aws.StringValue(i.ResourceARN), | ||
"tags": keyvaluetags.ResourcegroupstaggingapiKeyValueTags(i.Tags).Map(), | ||
} | ||
|
||
if i.ComplianceDetails != nil { | ||
l["compliance_details"] = flattenAwsResourceGroupsTaggingAPIComplianceDetails(i.ComplianceDetails) | ||
} | ||
|
||
result = append(result, l) | ||
} | ||
|
||
return result | ||
} | ||
|
||
func flattenAwsResourceGroupsTaggingAPIComplianceDetails(details *resourcegroupstaggingapi.ComplianceDetails) []map[string]interface{} { | ||
if details == nil { | ||
return []map[string]interface{}{} | ||
} | ||
|
||
m := map[string]interface{}{ | ||
"compliance_status": aws.BoolValue(details.ComplianceStatus), | ||
"keys_with_noncompliant_values": flattenStringSet(details.KeysWithNoncompliantValues), | ||
"non_compliant_keys": flattenStringSet(details.NoncompliantKeys), | ||
} | ||
|
||
return []map[string]interface{}{m} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
package aws | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" | ||
) | ||
|
||
func TestAccDataSourceAwsResourceGroupsTaggingAPIResources_basic(t *testing.T) { | ||
dataSourceName := "data.aws_resourcegroupstaggingapi_resources.test" | ||
|
||
resource.ParallelTest(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
ErrorCheck: testAccErrorCheck(t, resourcegroupstaggingapi.EndpointsID), | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccDataSourceAwsResourceGroupsTaggingAPIResourcesBasicConfig, | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttrSet(dataSourceName, "resource_tag_mapping_list.#"), | ||
resource.TestCheckResourceAttrSet(dataSourceName, "resource_tag_mapping_list.0.resource_arn"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccDataSourceAwsResourceGroupsTaggingAPIResources_tag_key_filter(t *testing.T) { | ||
dataSourceName := "data.aws_resourcegroupstaggingapi_resources.test" | ||
resourceName := "aws_api_gateway_rest_api.test" | ||
rName := acctest.RandomWithPrefix("tf-acc-test") | ||
|
||
resource.ParallelTest(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
ErrorCheck: testAccErrorCheck(t, resourcegroupstaggingapi.EndpointsID), | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccDataSourceAwsResourceGroupsTaggingAPIResourcesTagKeyFilterConfig(rName), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckTypeSetElemNestedAttrs(dataSourceName, "resource_tag_mapping_list.*", map[string]string{ | ||
"tags.Key": rName, | ||
}), | ||
resource.TestCheckTypeSetElemAttrPair(dataSourceName, "resource_tag_mapping_list.*.resource_arn", resourceName, "arn"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccDataSourceAwsResourceGroupsTaggingAPIResources_compliance(t *testing.T) { | ||
dataSourceName := "data.aws_resourcegroupstaggingapi_resources.test" | ||
|
||
resource.ParallelTest(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
ErrorCheck: testAccErrorCheck(t, resourcegroupstaggingapi.EndpointsID), | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccDataSourceAwsResourceGroupsTaggingAPIResourcesComplianceConfig, | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr(dataSourceName, "resource_tag_mapping_list.0.compliance_details.#", "1"), | ||
resource.TestCheckResourceAttr(dataSourceName, "resource_tag_mapping_list.0.compliance_details.0.compliance_status", "true"), | ||
resource.TestCheckResourceAttrSet(dataSourceName, "resource_tag_mapping_list.0.resource_arn"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccDataSourceAwsResourceGroupsTaggingAPIResources_resource_type_filters(t *testing.T) { | ||
dataSourceName := "data.aws_resourcegroupstaggingapi_resources.test" | ||
resourceName := "aws_api_gateway_rest_api.test" | ||
rName := acctest.RandomWithPrefix("tf-acc-test") | ||
|
||
resource.ParallelTest(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
ErrorCheck: testAccErrorCheck(t, resourcegroupstaggingapi.EndpointsID), | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccDataSourceAwsResourceGroupsTaggingAPIResourcesResourceTypeFiltersConfig(rName), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckTypeSetElemNestedAttrs(dataSourceName, "resource_tag_mapping_list.*", map[string]string{ | ||
"tags.Key": rName, | ||
}), | ||
resource.TestCheckTypeSetElemAttrPair(dataSourceName, "resource_tag_mapping_list.*.resource_arn", resourceName, "arn"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccDataSourceAwsResourceGroupsTaggingAPIResources_resource_arn_list(t *testing.T) { | ||
dataSourceName := "data.aws_resourcegroupstaggingapi_resources.test" | ||
resourceName := "aws_api_gateway_rest_api.test" | ||
rName := acctest.RandomWithPrefix("tf-acc-test") | ||
|
||
resource.ParallelTest(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
ErrorCheck: testAccErrorCheck(t, resourcegroupstaggingapi.EndpointsID), | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccDataSourceAwsResourceGroupsTaggingAPIResourcesResourceARNListConfig(rName), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckTypeSetElemNestedAttrs(dataSourceName, "resource_tag_mapping_list.*", map[string]string{ | ||
"tags.Key": rName, | ||
}), | ||
resource.TestCheckTypeSetElemAttrPair(dataSourceName, "resource_tag_mapping_list.*.resource_arn", resourceName, "arn"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
const testAccDataSourceAwsResourceGroupsTaggingAPIResourcesBasicConfig = ` | ||
data "aws_resourcegroupstaggingapi_resources" "test" {} | ||
` | ||
|
||
func testAccDataSourceAwsResourceGroupsTaggingAPIResourcesTagKeyFilterConfig(rName string) string { | ||
return fmt.Sprintf(` | ||
resource "aws_api_gateway_rest_api" "test" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. API Gateway REST APIs can be slightly problematic:
Going to switch this to an easier resource such as a VPC to see if that cooperates a little better. 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i tinkered a lot with this. was the simplest one i could think of at the time. i remember trying vpc but dont remember why i dropped it. IIRC it didn't propagate and results were empty. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I might be having really good luck today as it seems to be passing with |
||
name = %[1]q | ||
|
||
tags = { | ||
Key = %[1]q | ||
} | ||
} | ||
|
||
data "aws_resourcegroupstaggingapi_resources" "test" { | ||
tag_filter { | ||
key = "Key" | ||
} | ||
|
||
depends_on = [aws_api_gateway_rest_api.test] | ||
} | ||
`, rName) | ||
} | ||
|
||
func testAccDataSourceAwsResourceGroupsTaggingAPIResourcesResourceTypeFiltersConfig(rName string) string { | ||
return fmt.Sprintf(` | ||
resource "aws_api_gateway_rest_api" "test" { | ||
name = %[1]q | ||
|
||
tags = { | ||
Key = %[1]q | ||
} | ||
} | ||
|
||
data "aws_resourcegroupstaggingapi_resources" "test" { | ||
resource_type_filters = ["apigateway"] | ||
|
||
depends_on = [aws_api_gateway_rest_api.test] | ||
} | ||
`, rName) | ||
} | ||
|
||
func testAccDataSourceAwsResourceGroupsTaggingAPIResourcesResourceARNListConfig(rName string) string { | ||
return fmt.Sprintf(` | ||
resource "aws_api_gateway_rest_api" "test" { | ||
name = %[1]q | ||
|
||
tags = { | ||
Key = %[1]q | ||
} | ||
} | ||
|
||
data "aws_resourcegroupstaggingapi_resources" "test" { | ||
resource_arn_list = [aws_api_gateway_rest_api.test.arn] | ||
} | ||
`, rName) | ||
} | ||
|
||
const testAccDataSourceAwsResourceGroupsTaggingAPIResourcesComplianceConfig = ` | ||
data "aws_resourcegroupstaggingapi_resources" "test" { | ||
include_compliance_details = true | ||
exclude_compliant_resources = false | ||
} | ||
` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Empty configuration is taking 30+ minutes to paginate in our testing accounts 😢 In this case, I think it is probably okay to omit the testing since the API doesn't provide any sort of "maximum results" parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i was afraid of this. i'm ok with omitting it. maybe hide it behind a flag?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have a similar issue with
aws_ami
where unfiltered results would result in a huge result set as well. We skip including that testing with the hope that the unfiltered API operation would operate the same as a filtered one. Not aware of any particular issues with that in the last 3 years. We could put this behind an environment variable, but it is probably okay without it.