Add resource type hierarchy for smart ignore

main
Elie 2021-10-12 17:59:48 +02:00
parent ca49fa2921
commit e9dc238c94
No known key found for this signature in database
GPG Key ID: 399AF69092C727B6
6 changed files with 272 additions and 78 deletions

View File

@ -67,7 +67,26 @@ func (r *DriftIgnore) readIgnoreFile() error {
return nil
}
func (r *DriftIgnore) isAnyOfChildrenTypesNotIgnored(ty resource.ResourceType) bool {
childrenTypes := resource.GetMeta(ty).GetChildrenTypes()
for _, childrenType := range childrenTypes {
if !r.match(fmt.Sprintf("%s.*", childrenType)) {
return true
}
if r.isAnyOfChildrenTypesNotIgnored(childrenType) {
return true
}
}
return false
}
func (r *DriftIgnore) IsTypeIgnored(ty resource.ResourceType) bool {
// Iterate over children types, and do not ignore parent resource
// if at least one of children type is not ignored.
if r.isAnyOfChildrenTypesNotIgnored(ty) {
return false
}
return r.match(fmt.Sprintf("%s.*", ty))
}

View File

@ -435,3 +435,102 @@ func TestDriftIgnore_IsFieldIgnored(t *testing.T) {
})
}
}
func TestDriftIgnore_IsTypeIgnored(t *testing.T) {
tests := []struct {
name string
resources []*resource.Resource
want []bool
path string
}{
{
name: "drift_ignore_type_exclude_with_child_1_nesting",
resources: []*resource.Resource{
{
Type: "aws_route",
},
{
Type: "aws_route_table",
},
{
Type: "non_ignored_type",
},
{
Type: "ignored_type",
},
},
want: []bool{
false,
false,
false,
true,
},
path: "testdata/drift_ignore_type/.driftignore_child_1",
},
{
name: "drift_ignore_type_exclude_with_child_2_nesting",
resources: []*resource.Resource{
{
Type: "non_ignored_type",
},
{
Type: "aws_iam_user",
},
{
Type: "aws_iam_user_policy",
},
{
Type: "aws_iam_user_policy_attachment",
},
{
Type: "ignored_type",
},
},
want: []bool{
false,
false,
false,
false,
true,
},
path: "testdata/drift_ignore_type/.driftignore_child_2",
},
{
name: "drift_ignore_type_exclude",
resources: []*resource.Resource{
{
Type: "type",
},
{
Type: "type_1",
},
{
Type: "type_2",
},
{
Type: "type_3",
},
},
want: []bool{
true,
false,
true,
true,
},
path: "testdata/drift_ignore_type/.driftignore",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cwd, _ := os.Getwd()
defer func() { _ = os.Chdir(cwd) }()
r := NewDriftIgnore(tt.path)
got := make([]bool, 0, len(tt.want))
for _, res := range tt.resources {
got = append(got, r.IsTypeIgnored(resource.ResourceType(res.ResourceType())))
}
assert.Equal(t, tt.want, got)
})
}
}

View File

@ -0,0 +1,3 @@
type
type_2
type_3.*

View File

@ -0,0 +1,3 @@
*
!aws_route
!non_ignored_type.*

View File

@ -0,0 +1,3 @@
*
!aws_iam_user_policy_attachment
!non_ignored_type.*

View File

@ -2,77 +2,124 @@ package resource
type ResourceType string
var supportedTypes = map[string]struct{}{
"aws_ami": {},
"aws_cloudfront_distribution": {},
"aws_db_instance": {},
"aws_db_subnet_group": {},
"aws_default_network_acl": {},
"aws_default_route_table": {},
"aws_default_security_group": {},
"aws_default_subnet": {},
"aws_default_vpc": {},
"aws_dynamodb_table": {},
"aws_ebs_snapshot": {},
"aws_ebs_volume": {},
"aws_ecr_repository": {},
"aws_eip": {},
"aws_eip_association": {},
"aws_iam_access_key": {},
"aws_iam_policy": {},
"aws_iam_policy_attachment": {},
"aws_iam_role": {},
"aws_iam_role_policy": {},
"aws_iam_role_policy_attachment": {},
"aws_iam_user": {},
"aws_iam_user_policy": {},
"aws_iam_user_policy_attachment": {},
"aws_instance": {},
"aws_internet_gateway": {},
"aws_key_pair": {},
"aws_kms_alias": {},
"aws_kms_key": {},
"aws_lambda_event_source_mapping": {},
"aws_lambda_function": {},
"aws_nat_gateway": {},
"aws_network_acl": {},
"aws_network_acl_rule": {},
"aws_route": {},
"aws_route53_health_check": {},
"aws_route53_record": {},
"aws_route53_zone": {},
"aws_route_table": {},
"aws_route_table_association": {},
"aws_s3_bucket": {},
var supportedTypes = map[string]ResourceTypeMeta{
"aws_ami": {},
"aws_cloudfront_distribution": {},
"aws_db_instance": {},
"aws_db_subnet_group": {},
"aws_default_network_acl": {children: []ResourceType{
"aws_network_acl_rule",
}},
"aws_default_route_table": {children: []ResourceType{
"aws_route",
}},
"aws_default_security_group": {children: []ResourceType{
"aws_security_group_rule",
}},
"aws_default_subnet": {},
"aws_default_vpc": {children: []ResourceType{
// VPC are used by aws_internet_gateway to determine if internet gateway is the default one in middleware
"aws_internet_gateway",
}},
"aws_dynamodb_table": {},
"aws_ebs_snapshot": {},
"aws_ebs_volume": {},
"aws_ecr_repository": {},
"aws_eip": {children: []ResourceType{
"aws_eip_association",
}},
"aws_eip_association": {},
"aws_iam_access_key": {},
"aws_iam_policy": {},
"aws_iam_policy_attachment": {},
"aws_iam_role": {children: []ResourceType{
"aws_iam_role_policy",
"aws_iam_policy_attachment",
}},
"aws_iam_role_policy": {children: []ResourceType{
"aws_iam_role_policy_attachment",
}},
"aws_iam_role_policy_attachment": {children: []ResourceType{
"aws_iam_policy_attachment",
}},
"aws_iam_user": {children: []ResourceType{
"aws_iam_user_policy",
}},
"aws_iam_user_policy": {children: []ResourceType{
"aws_iam_user_policy_attachment",
}},
"aws_iam_user_policy_attachment": {children: []ResourceType{
"aws_iam_policy_attachment",
}},
"aws_instance": {children: []ResourceType{
"aws_ebs_volume",
}},
"aws_internet_gateway": {children: []ResourceType{
// This is used to determine internet gateway default rule
"aws_route",
}},
"aws_key_pair": {},
"aws_kms_alias": {},
"aws_kms_key": {},
"aws_lambda_event_source_mapping": {},
"aws_lambda_function": {},
"aws_nat_gateway": {},
"aws_network_acl": {children: []ResourceType{
"aws_network_acl_rule",
}},
"aws_network_acl_rule": {},
"aws_route": {},
"aws_route53_health_check": {},
"aws_route53_record": {},
"aws_route53_zone": {},
"aws_route_table": {children: []ResourceType{
"aws_route",
}},
"aws_route_table_association": {},
"aws_s3_bucket": {children: []ResourceType{
"aws_s3_bucket_policy",
}},
"aws_s3_bucket_analytics_configuration": {},
"aws_s3_bucket_inventory": {},
"aws_s3_bucket_metric": {},
"aws_s3_bucket_notification": {},
"aws_s3_bucket_policy": {},
"aws_security_group": {},
"aws_security_group_rule": {},
"aws_sns_topic": {},
"aws_sns_topic_policy": {},
"aws_sns_topic_subscription": {},
"aws_sqs_queue": {},
"aws_sqs_queue_policy": {},
"aws_subnet": {},
"aws_vpc": {},
"aws_rds_cluster": {},
"aws_cloudformation_stack": {},
"aws_api_gateway_rest_api": {},
"aws_api_gateway_account": {},
"aws_api_gateway_api_key": {},
"aws_api_gateway_authorizer": {},
"aws_api_gateway_deployment": {},
"aws_api_gateway_stage": {},
"aws_api_gateway_resource": {},
"aws_api_gateway_domain_name": {},
"aws_api_gateway_vpc_link": {},
"aws_appautoscaling_target": {},
"aws_rds_cluster_instance": {},
"aws_appautoscaling_policy": {},
"aws_appautoscaling_scheduled_action": {},
"aws_security_group": {children: []ResourceType{
"aws_security_group_rule",
}},
"aws_security_group_rule": {},
"aws_sns_topic": {children: []ResourceType{
"aws_sns_topic_policy",
}},
"aws_sns_topic_policy": {},
"aws_sns_topic_subscription": {},
"aws_sqs_queue": {children: []ResourceType{
"aws_sqs_queue_policy",
}},
"aws_sqs_queue_policy": {},
"aws_subnet": {},
"aws_vpc": {},
"aws_rds_cluster": {},
"aws_cloudformation_stack": {},
"aws_api_gateway_rest_api": {children: []ResourceType{
"aws_api_gateway_resource",
}},
"aws_api_gateway_account": {},
"aws_api_gateway_api_key": {},
"aws_api_gateway_authorizer": {},
"aws_api_gateway_deployment": {children: []ResourceType{
"aws_api_gateway_stage",
}},
"aws_api_gateway_stage": {},
"aws_api_gateway_resource": {},
"aws_api_gateway_domain_name": {},
"aws_api_gateway_vpc_link": {},
"aws_appautoscaling_target": {},
"aws_rds_cluster_instance": {children: []ResourceType{
"aws_db_instance",
}},
"aws_appautoscaling_policy": {},
"aws_appautoscaling_scheduled_action": {},
"github_branch_protection": {},
"github_membership": {},
@ -80,19 +127,27 @@ var supportedTypes = map[string]struct{}{
"github_team": {},
"github_team_membership": {},
"google_storage_bucket": {},
"google_compute_firewall": {},
"google_compute_router": {},
"google_compute_instance": {},
"google_compute_network": {},
"google_storage_bucket_iam_binding": {},
"google_storage_bucket_iam_member": {},
"google_storage_bucket_iam_policy": {},
"google_storage_bucket": {},
"google_compute_firewall": {},
"google_compute_router": {},
"google_compute_instance": {},
"google_compute_network": {},
"google_storage_bucket_iam_binding": {children: []ResourceType{
"google_storage_bucket_iam_member",
}},
"google_storage_bucket_iam_member": {},
"google_storage_bucket_iam_policy": {children: []ResourceType{
"google_storage_bucket_iam_member",
}},
"azurerm_storage_account": {},
"azurerm_storage_container": {},
"azurerm_virtual_network": {},
"azurerm_route_table": {},
"azurerm_storage_account": {},
"azurerm_storage_container": {},
"azurerm_virtual_network": {children: []ResourceType{
"azurerm_subnet",
}},
"azurerm_route_table": {children: []ResourceType{
"azurerm_route",
}},
"azurerm_route": {},
"azurerm_resource_group": {},
"azurerm_subnet": {},
@ -110,3 +165,15 @@ func IsResourceTypeSupported(ty string) bool {
func (ty ResourceType) String() string {
return string(ty)
}
func GetMeta(ty ResourceType) ResourceTypeMeta {
return supportedTypes[ty.String()]
}
type ResourceTypeMeta struct {
children []ResourceType
}
func (ty ResourceTypeMeta) GetChildrenTypes() []ResourceType {
return ty.children
}