Merge pull request #356 from cloudskiff/refact/sortResources

Sort unmanaged & deleted resources in a predictable order
main
Elie 2021-03-23 11:23:07 +01:00 committed by GitHub
commit 82f74f74f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 113 additions and 17 deletions

View File

@ -189,3 +189,8 @@ func (a *Analysis) Summary() Summary {
func (a *Analysis) Alerts() alerter.Alerts { func (a *Analysis) Alerts() alerter.Alerts {
return a.alerts return a.alerts
} }
func (a *Analysis) SortResources() {
a.unmanaged = resource.Sort(a.unmanaged)
a.deleted = resource.Sort(a.deleted)
}

View File

@ -6,9 +6,10 @@ import (
resourceaws "github.com/cloudskiff/driftctl/pkg/resource/aws" resourceaws "github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/r3labs/diff/v2"
"github.com/cloudskiff/driftctl/pkg/alerter" "github.com/cloudskiff/driftctl/pkg/alerter"
"github.com/cloudskiff/driftctl/pkg/resource" "github.com/cloudskiff/driftctl/pkg/resource"
"github.com/r3labs/diff/v2"
) )
type UnmanagedSecurityGroupRulesAlert struct{} type UnmanagedSecurityGroupRulesAlert struct{}
@ -118,6 +119,10 @@ func (a Analyzer) Analyze(remoteResources, resourcesFromState []resource.Resourc
// Add remaining unmanaged resources // Add remaining unmanaged resources
analysis.AddUnmanaged(filteredRemoteResource...) analysis.AddUnmanaged(filteredRemoteResource...)
// Sort resources by Terraform Id
// The purpose is to have a predictable output
analysis.SortResources()
analysis.SetAlerts(a.alerter.Retrieve()) analysis.SetAlerts(a.alerter.Retrieve())
return analysis, nil return analysis, nil

View File

@ -3,14 +3,16 @@ package analyser
import ( import (
"encoding/json" "encoding/json"
"io/ioutil" "io/ioutil"
"testing"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
"github.com/cloudskiff/driftctl/mocks" "github.com/cloudskiff/driftctl/mocks"
testresource "github.com/cloudskiff/driftctl/test/resource"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
testresource "github.com/cloudskiff/driftctl/test/resource"
"github.com/cloudskiff/driftctl/test/goldenfile" "github.com/cloudskiff/driftctl/test/goldenfile"
"github.com/cloudskiff/driftctl/pkg/alerter" "github.com/cloudskiff/driftctl/pkg/alerter"
@ -18,8 +20,6 @@ import (
"github.com/cloudskiff/driftctl/pkg/resource/aws" "github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/r3labs/diff/v2" "github.com/r3labs/diff/v2"
"testing"
) )
func TestAnalyze(t *testing.T) { func TestAnalyze(t *testing.T) {
@ -615,13 +615,12 @@ func TestAnalyze(t *testing.T) {
{ {
Change: diff.Change{ Change: diff.Change{
Type: "update", Type: "update",
From: "foo", From: "one",
To: "oof", To: "two",
Path: []string{ Path: []string{
"StructSlice", "StructSlice",
"0", "0",
"Array", "String",
"0",
}, },
}, },
Computed: true, Computed: true,
@ -629,12 +628,13 @@ func TestAnalyze(t *testing.T) {
{ {
Change: diff.Change{ Change: diff.Change{
Type: "update", Type: "update",
From: "one", From: "foo",
To: "two", To: "oof",
Path: []string{ Path: []string{
"StructSlice", "StructSlice",
"0", "0",
"String", "Array",
"0",
}, },
}, },
Computed: true, Computed: true,
@ -898,6 +898,81 @@ func TestAnalyze(t *testing.T) {
}, },
hasDrifted: true, hasDrifted: true,
}, },
{
name: "Test sorted unmanaged & deleted resources",
iac: []resource.Resource{
&testresource.FakeResource{
Id: "deleted resource 22",
Type: "aws_s3_bucket",
},
&testresource.FakeResource{
Id: "deleted resource 20",
Type: "aws_ebs_volume",
},
&testresource.FakeResource{
Id: "deleted resource 20",
Type: "aws_s3_bucket",
},
},
cloud: []resource.Resource{
&testresource.FakeResource{
Id: "unmanaged resource 12",
Type: "aws_s3_bucket",
},
&testresource.FakeResource{
Id: "unmanaged resource 10",
Type: "aws_s3_bucket",
},
&testresource.FakeResource{
Id: "unmanaged resource 11",
Type: "aws_ebs_volume",
},
},
expected: Analysis{
managed: []resource.Resource{},
unmanaged: []resource.Resource{
&testresource.FakeResource{
Id: "unmanaged resource 11",
Type: "aws_ebs_volume",
},
&testresource.FakeResource{
Id: "unmanaged resource 10",
Type: "aws_s3_bucket",
},
&testresource.FakeResource{
Id: "unmanaged resource 12",
Type: "aws_s3_bucket",
},
},
deleted: []resource.Resource{
&testresource.FakeResource{
Id: "deleted resource 20",
Type: "aws_ebs_volume",
},
&testresource.FakeResource{
Id: "deleted resource 20",
Type: "aws_s3_bucket",
},
&testresource.FakeResource{
Id: "deleted resource 22",
Type: "aws_s3_bucket",
},
},
summary: Summary{
TotalResources: 6,
TotalManaged: 0,
TotalUnmanaged: 3,
TotalDeleted: 3,
},
alerts: alerter.Alerts{},
},
hasDrifted: true,
},
}
differ, err := diff.NewDiffer(diff.SliceOrdering(true))
if err != nil {
t.Fatalf("Error creating new differ: %e", err)
} }
for _, c := range cases { for _, c := range cases {
@ -930,7 +1005,7 @@ func TestAnalyze(t *testing.T) {
t.Errorf("Drifted state does not match, got %t expected %t", result.IsSync(), !c.hasDrifted) t.Errorf("Drifted state does not match, got %t expected %t", result.IsSync(), !c.hasDrifted)
} }
managedChanges, err := diff.Diff(result.Managed(), c.expected.Managed()) managedChanges, err := differ.Diff(result.Managed(), c.expected.Managed())
if err != nil { if err != nil {
t.Fatalf("Unable to compare %+v", err) t.Fatalf("Unable to compare %+v", err)
} }
@ -940,7 +1015,7 @@ func TestAnalyze(t *testing.T) {
} }
} }
unmanagedChanges, err := diff.Diff(result.Unmanaged(), c.expected.Unmanaged()) unmanagedChanges, err := differ.Diff(result.Unmanaged(), c.expected.Unmanaged())
if err != nil { if err != nil {
t.Fatalf("Unable to compare %+v", err) t.Fatalf("Unable to compare %+v", err)
} }
@ -950,7 +1025,7 @@ func TestAnalyze(t *testing.T) {
} }
} }
deletedChanges, err := diff.Diff(result.Deleted(), c.expected.Deleted()) deletedChanges, err := differ.Diff(result.Deleted(), c.expected.Deleted())
if err != nil { if err != nil {
t.Fatalf("Unable to compare %+v", err) t.Fatalf("Unable to compare %+v", err)
} }
@ -960,7 +1035,7 @@ func TestAnalyze(t *testing.T) {
} }
} }
diffChanges, err := diff.Diff(result.Differences(), c.expected.Differences()) diffChanges, err := differ.Diff(result.Differences(), c.expected.Differences())
if err != nil { if err != nil {
t.Fatalf("Unable to compare %+v", err) t.Fatalf("Unable to compare %+v", err)
} }
@ -970,7 +1045,7 @@ func TestAnalyze(t *testing.T) {
} }
} }
summaryChanges, err := diff.Diff(c.expected.Summary(), result.Summary()) summaryChanges, err := differ.Diff(c.expected.Summary(), result.Summary())
if err != nil { if err != nil {
t.Fatalf("Unable to compare %+v", err) t.Fatalf("Unable to compare %+v", err)
} }
@ -980,7 +1055,7 @@ func TestAnalyze(t *testing.T) {
} }
} }
alertsChanges, err := diff.Diff(result.Alerts(), c.expected.Alerts()) alertsChanges, err := differ.Diff(result.Alerts(), c.expected.Alerts())
if err != nil { if err != nil {
t.Fatalf("Unable to compare %+v", err) t.Fatalf("Unable to compare %+v", err)
} }

View File

@ -2,6 +2,7 @@ package resource
import ( import (
"encoding/json" "encoding/json"
"sort"
) )
type Resource interface { type Resource interface {
@ -48,3 +49,13 @@ type NormalizedResource interface {
func IsSameResource(rRs, lRs Resource) bool { func IsSameResource(rRs, lRs Resource) bool {
return rRs.TerraformType() == lRs.TerraformType() && rRs.TerraformId() == lRs.TerraformId() return rRs.TerraformType() == lRs.TerraformType() && rRs.TerraformId() == lRs.TerraformId()
} }
func Sort(res []Resource) []Resource {
sort.SliceStable(res, func(i, j int) bool {
if res[i].TerraformType() != res[j].TerraformType() {
return res[i].TerraformType() < res[j].TerraformType()
}
return res[i].TerraformId() < res[j].TerraformId()
})
return res
}