diff --git a/pkg/driftctl.go b/pkg/driftctl.go index c9de92c2..44a05284 100644 --- a/pkg/driftctl.go +++ b/pkg/driftctl.go @@ -97,6 +97,7 @@ func (d DriftCTL) Run() (*analyser.Analysis, error) { middlewares.NewAwsDefaultSqsQueuePolicy(), middlewares.NewAwsSNSTopicPolicyExpander(d.resourceFactory, d.resourceSchemaRepository), middlewares.NewAwsRoleManagedPolicyExpander(d.resourceFactory), + middlewares.NewTagsAllManager(), ) if !d.opts.StrictMode { diff --git a/pkg/middlewares/tags_all_manager.go b/pkg/middlewares/tags_all_manager.go new file mode 100644 index 00000000..d29bd378 --- /dev/null +++ b/pkg/middlewares/tags_all_manager.go @@ -0,0 +1,31 @@ +package middlewares + +import ( + "github.com/cloudskiff/driftctl/pkg/resource" +) + +// Manage tags_all attribute on each compatible resources +type TagsAllManager struct{} + +func NewTagsAllManager() TagsAllManager { + return TagsAllManager{} +} + +func (a TagsAllManager) Execute(remoteResources, resourcesFromState *[]resource.Resource) error { + for _, remoteRes := range *remoteResources { + if res, ok := remoteRes.(*resource.AbstractResource); ok { + if _, exist := res.Attrs.Get("tags_all"); exist { + res.Attrs.SafeDelete([]string{"tags_all"}) + } + } + } + for _, stateRes := range *resourcesFromState { + if res, ok := stateRes.(*resource.AbstractResource); ok { + if allTags, exist := res.Attrs.Get("tags_all"); exist { + _ = res.Attrs.SafeSet([]string{"tags"}, allTags) + res.Attrs.SafeDelete([]string{"tags_all"}) + } + } + } + return nil +} diff --git a/pkg/middlewares/tags_all_manager_test.go b/pkg/middlewares/tags_all_manager_test.go new file mode 100644 index 00000000..3233cfc3 --- /dev/null +++ b/pkg/middlewares/tags_all_manager_test.go @@ -0,0 +1,98 @@ +package middlewares + +import ( + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws/awsutil" + "github.com/cloudskiff/driftctl/pkg/resource" + "github.com/r3labs/diff/v2" +) + +func TestTagsAllManager_Execute(t *testing.T) { + tests := []struct { + name string + remoteResources *[]resource.Resource + resourcesFromState *[]resource.Resource + wantErr bool + }{ + { + name: "With multiple resources that are tags_all compatible", + remoteResources: &[]resource.Resource{ + &resource.AbstractResource{ + Id: "dummy-instance", + Type: "aws_instance", + Attrs: &resource.Attributes{ + "tags": map[string]interface{}{ + "Name": "toto", + "Terraform": "true", + }, + "tags_all": map[string]interface{}{ + "Name": "toto", + "Terraform": "true", + }, + }, + }, + &resource.AbstractResource{ + Id: "dummy-ebs-volume", + Type: "aws_ebs_volume", + Attrs: &resource.Attributes{ + "tags": map[string]interface{}{ + "Name": "tata", + "Terraform": "true", + }, + "tags_all": map[string]interface{}{ + "Name": "tata", + "Terraform": "true", + }, + }, + }, + }, + resourcesFromState: &[]resource.Resource{ + &resource.AbstractResource{ + Id: "dummy-instance", + Type: "aws_instance", + Attrs: &resource.Attributes{ + "tags": map[string]interface{}{ + "Name": "toto", + }, + "tags_all": map[string]interface{}{ + "Name": "toto", + "Terraform": "true", + }, + }, + }, + &resource.AbstractResource{ + Id: "dummy-ebs-volume", + Type: "aws_ebs_volume", + Attrs: &resource.Attributes{ + "tags": map[string]interface{}{ + "Name": "tata", + }, + "tags_all": map[string]interface{}{ + "Name": "tata", + "Terraform": "true", + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := NewTagsAllManager() + if err := a.Execute(tt.remoteResources, tt.resourcesFromState); (err != nil) != tt.wantErr { + t.Errorf("Execute() error = %v, wantErr %v", err, tt.wantErr) + } + changelog, err := diff.Diff(tt.resourcesFromState, tt.remoteResources) + if err != nil { + t.Error(err) + } + if len(changelog) > 0 { + for _, change := range changelog { + t.Errorf("%s got = %v, want %v", strings.Join(change.Path, "."), awsutil.Prettify(change.From), awsutil.Prettify(change.To)) + } + } + }) + } +}