Merge pull request #356 from cloudskiff/refact/sortResources
Sort unmanaged & deleted resources in a predictable ordermain
commit
82f74f74f0
|
@ -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)
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue