driftctl/pkg/analyser/analyzer_test.go

1221 lines
25 KiB
Go
Raw Normal View History

package analyser
import (
"encoding/json"
"io/ioutil"
"testing"
2021-07-26 09:17:32 +00:00
"github.com/cloudskiff/driftctl/pkg/filter"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/assert"
testresource "github.com/cloudskiff/driftctl/test/resource"
"github.com/cloudskiff/driftctl/test/goldenfile"
2020-12-16 12:02:02 +00:00
"github.com/cloudskiff/driftctl/pkg/alerter"
"github.com/cloudskiff/driftctl/pkg/resource"
2021-02-15 14:49:20 +00:00
"github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/r3labs/diff/v2"
)
func TestAnalyze(t *testing.T) {
cases := []struct {
name string
2021-08-09 14:03:04 +00:00
iac []*resource.Resource
ignoredRes []*resource.Resource
cloud []*resource.Resource
ignoredDrift []struct {
2021-08-09 14:03:04 +00:00
res *resource.Resource
path []string
}
2020-12-16 12:02:02 +00:00
alerts alerter.Alerts
expected Analysis
hasDrifted bool
}{
{
name: "TestNilValues", // Cover division by zero case
iac: nil,
cloud: nil,
expected: Analysis{},
},
{
name: "TestNothingToCompare", // Cover division by zero case
2021-08-09 14:03:04 +00:00
iac: []*resource.Resource{},
cloud: []*resource.Resource{},
expected: Analysis{},
},
{
name: "TestIgnoreFromCoverageIacNotInCloud",
2021-08-09 14:03:04 +00:00
iac: []*resource.Resource{
{
Id: "foobar",
},
},
2021-08-09 14:03:04 +00:00
cloud: []*resource.Resource{},
expected: Analysis{
summary: Summary{
TotalResources: 1,
TotalDeleted: 1,
},
2021-08-09 14:03:04 +00:00
deleted: []*resource.Resource{
{
Id: "foobar",
},
},
},
hasDrifted: true,
},
{
name: "TestResourceIgnoredDeleted",
2021-08-09 14:03:04 +00:00
iac: []*resource.Resource{
{
Id: "foobar",
},
},
2021-08-09 14:03:04 +00:00
ignoredRes: []*resource.Resource{
{
Id: "foobar",
},
},
2021-08-09 14:03:04 +00:00
cloud: []*resource.Resource{},
expected: Analysis{
summary: Summary{
TotalResources: 0,
TotalDeleted: 0,
},
},
hasDrifted: false,
},
{
name: "Test100PercentCoverage with ignore",
2021-08-09 14:03:04 +00:00
iac: []*resource.Resource{
{
Id: "foobar",
},
2021-08-09 14:03:04 +00:00
{
Id: "foobar2",
},
},
2021-08-09 14:03:04 +00:00
ignoredRes: []*resource.Resource{
{
Id: "foobar2",
},
},
2021-08-09 14:03:04 +00:00
cloud: []*resource.Resource{
{
Id: "foobar",
},
2021-08-09 14:03:04 +00:00
{
Id: "foobar2",
},
},
expected: Analysis{
2021-08-09 14:03:04 +00:00
managed: []*resource.Resource{
{
Id: "foobar",
},
},
summary: Summary{
TotalManaged: 1,
TotalResources: 1,
},
},
},
{
name: "Test100PercentCoverage",
2021-08-09 14:03:04 +00:00
iac: []*resource.Resource{
{
Id: "foobar",
},
},
2021-08-09 14:03:04 +00:00
cloud: []*resource.Resource{
{
Id: "foobar",
},
},
expected: Analysis{
2021-08-09 14:03:04 +00:00
managed: []*resource.Resource{
{
Id: "foobar",
},
},
summary: Summary{
TotalManaged: 1,
TotalResources: 1,
},
},
},
{
name: "TestUnmanagedResource",
2021-08-09 14:03:04 +00:00
iac: []*resource.Resource{},
cloud: []*resource.Resource{
{
Id: "foobar",
},
},
expected: Analysis{
summary: Summary{
TotalResources: 1,
TotalUnmanaged: 1,
},
2021-08-09 14:03:04 +00:00
unmanaged: []*resource.Resource{
{
Id: "foobar",
},
},
},
hasDrifted: true,
},
{
name: "TestDiff",
2021-08-09 14:03:04 +00:00
iac: []*resource.Resource{
{
2021-05-21 14:09:45 +00:00
Id: "foobar",
Type: aws.AwsAmiResourceType,
Attrs: &resource.Attributes{
"architecture": "foobar",
"arn": "barfoo",
"ebs_block_device": []map[string]interface{}{
{
"volume_type": "bar",
"volume_size": 0,
},
},
},
},
},
2021-08-09 14:03:04 +00:00
cloud: []*resource.Resource{
{
2021-05-21 14:09:45 +00:00
Id: "foobar",
Type: aws.AwsAmiResourceType,
Attrs: &resource.Attributes{
"architecture": "barfoo",
"arn": "foobar",
"ebs_block_device": []map[string]interface{}{
{
"volume_type": "baz",
"volume_size": 1,
},
},
},
},
},
expected: Analysis{
2021-08-09 14:03:04 +00:00
managed: []*resource.Resource{
{
2021-05-21 14:09:45 +00:00
Id: "foobar",
Type: aws.AwsAmiResourceType,
Attrs: &resource.Attributes{
"architecture": "foobar",
"arn": "barfoo",
"ebs_block_device": []map[string]interface{}{
{
"volume_type": "bar",
"volume_size": 0,
},
},
},
},
},
summary: Summary{
TotalResources: 1,
TotalDrifted: 1,
TotalManaged: 1,
},
differences: []Difference{
{
2021-08-09 14:03:04 +00:00
Res: &resource.Resource{
2021-05-21 14:09:45 +00:00
Id: "foobar",
Type: aws.AwsAmiResourceType,
Attrs: &resource.Attributes{
"architecture": "foobar",
"arn": "barfoo",
"ebs_block_device": []map[string]interface{}{
{
"volume_type": "bar",
"volume_size": 0,
},
},
},
},
2021-01-08 17:14:26 +00:00
Changelog: Changelog{
{
Change: diff.Change{
Type: "update",
2021-05-21 14:09:45 +00:00
From: "foobar",
To: "barfoo",
2021-01-08 17:14:26 +00:00
Path: []string{
2021-05-21 14:09:45 +00:00
"architecture",
2021-01-08 17:14:26 +00:00
},
},
},
2021-01-08 17:14:26 +00:00
{
Change: diff.Change{
Type: "update",
2021-05-21 14:09:45 +00:00
From: "barfoo",
To: "foobar",
2021-01-08 17:14:26 +00:00
Path: []string{
2021-05-21 14:09:45 +00:00
"arn",
2021-01-08 17:14:26 +00:00
},
},
2021-05-21 14:09:45 +00:00
Computed: true,
},
2021-01-08 17:14:26 +00:00
{
Change: diff.Change{
Type: "update",
2021-05-21 14:09:45 +00:00
From: 0,
To: 1,
2021-01-08 17:14:26 +00:00
Path: []string{
2021-05-21 14:09:45 +00:00
"ebs_block_device",
"0",
"volume_size",
2021-01-08 17:14:26 +00:00
},
2020-12-16 12:02:02 +00:00
},
},
2021-01-08 17:14:26 +00:00
{
Change: diff.Change{
Type: "update",
2021-05-21 14:09:45 +00:00
From: "bar",
To: "baz",
2021-01-08 17:14:26 +00:00
Path: []string{
2021-05-21 14:09:45 +00:00
"ebs_block_device",
"0",
"volume_type",
2021-01-08 17:14:26 +00:00
},
2020-12-16 12:02:02 +00:00
},
},
},
},
},
alerts: alerter.Alerts{
"": {
NewComputedDiffAlert(),
},
},
},
hasDrifted: true,
},
{
name: "TestDiff with partial ignore",
2021-08-09 14:03:04 +00:00
iac: []*resource.Resource{
{
2021-05-21 14:09:45 +00:00
Id: "foobar",
Type: aws.AwsAmiResourceType,
Attrs: &resource.Attributes{
"architecture": "foobar",
"arn": "barfoo",
},
},
},
2021-08-09 14:03:04 +00:00
cloud: []*resource.Resource{
{
2021-05-21 14:09:45 +00:00
Id: "foobar",
Type: aws.AwsAmiResourceType,
Attrs: &resource.Attributes{
"architecture": "barfoo",
"arn": "foobar",
},
},
},
ignoredDrift: []struct {
2021-08-09 14:03:04 +00:00
res *resource.Resource
path []string
}{
{
2021-08-09 14:03:04 +00:00
res: &resource.Resource{
2021-05-21 14:09:45 +00:00
Id: "foobar",
Type: aws.AwsAmiResourceType,
Attrs: &resource.Attributes{
"architecture": "foobar",
"arn": "barfoo",
},
},
2021-05-21 14:09:45 +00:00
path: []string{"architecture"},
},
},
expected: Analysis{
2021-08-09 14:03:04 +00:00
managed: []*resource.Resource{
{
2021-05-21 14:09:45 +00:00
Id: "foobar",
Type: aws.AwsAmiResourceType,
Attrs: &resource.Attributes{
"architecture": "foobar",
"arn": "barfoo",
},
},
},
summary: Summary{
TotalResources: 1,
TotalDrifted: 1,
TotalManaged: 1,
},
differences: []Difference{
{
2021-08-09 14:03:04 +00:00
Res: &resource.Resource{
2021-05-21 14:09:45 +00:00
Id: "foobar",
Type: aws.AwsAmiResourceType,
Attrs: &resource.Attributes{
"architecture": "foobar",
"arn": "barfoo",
},
},
2021-01-08 17:14:26 +00:00
Changelog: Changelog{
{
Change: diff.Change{
Type: "update",
From: "barfoo",
To: "foobar",
Path: []string{
2021-05-21 14:09:45 +00:00
"arn",
2021-01-08 17:14:26 +00:00
},
},
2021-01-08 17:14:26 +00:00
Computed: true,
},
},
},
},
2020-12-16 12:02:02 +00:00
alerts: alerter.Alerts{
"": {
NewComputedDiffAlert(),
2020-12-16 12:02:02 +00:00
},
},
},
hasDrifted: true,
},
{
name: "TestDiff with full ignore",
2021-08-09 14:03:04 +00:00
iac: []*resource.Resource{
{
2021-05-21 14:09:45 +00:00
Id: "foobar",
Attrs: &resource.Attributes{
"foobar": "foobar",
"barfoo": "barfoo",
},
},
},
2021-08-09 14:03:04 +00:00
ignoredRes: []*resource.Resource{
{
2021-05-21 14:09:45 +00:00
Id: "should_be_ignored",
Attrs: &resource.Attributes{},
2021-01-04 15:19:34 +00:00
},
},
2021-08-09 14:03:04 +00:00
cloud: []*resource.Resource{
{
2021-05-21 14:09:45 +00:00
Id: "foobar",
Attrs: &resource.Attributes{
"foobar": "barfoo",
"barfoo": "foobar",
},
},
2021-08-09 14:03:04 +00:00
{
2021-05-21 14:09:45 +00:00
Id: "should_be_ignored",
Attrs: &resource.Attributes{},
2021-01-04 15:19:34 +00:00
},
},
ignoredDrift: []struct {
2021-08-09 14:03:04 +00:00
res *resource.Resource
path []string
}{
{
2021-08-09 14:03:04 +00:00
res: &resource.Resource{
2021-05-21 14:09:45 +00:00
Id: "foobar",
Attrs: &resource.Attributes{
"foobar": "foobar",
"barfoo": "barfoo",
},
},
2021-05-21 14:09:45 +00:00
path: []string{"foobar"},
},
{
2021-08-09 14:03:04 +00:00
res: &resource.Resource{
2021-05-21 14:09:45 +00:00
Id: "foobar",
Attrs: &resource.Attributes{
"foobar": "foobar",
"barfoo": "barfoo",
},
},
2021-05-21 14:09:45 +00:00
path: []string{"barfoo"},
},
},
expected: Analysis{
2021-08-09 14:03:04 +00:00
managed: []*resource.Resource{
{
2021-05-21 14:09:45 +00:00
Id: "foobar",
Attrs: &resource.Attributes{
"foobar": "foobar",
"barfoo": "barfoo",
},
},
},
summary: Summary{
TotalResources: 1,
TotalDrifted: 0,
TotalManaged: 1,
},
},
hasDrifted: false,
},
2020-12-16 12:02:02 +00:00
{
name: "TestDiffWithAlertFiltering",
2021-08-09 14:03:04 +00:00
iac: []*resource.Resource{
{
2021-05-21 14:09:45 +00:00
Id: "foobar",
Type: "fakeres",
Attrs: &resource.Attributes{
"foobar": "foobar",
"barfoo": "barfoo",
"struct": map[string]interface{}{
"baz": "baz",
"bar": "bar",
},
},
2020-12-16 12:02:02 +00:00
},
2021-08-09 14:03:04 +00:00
{
2021-05-21 14:09:45 +00:00
Id: "barfoo",
Type: "fakeres",
Attrs: &resource.Attributes{
"foobar": "foobar",
"barfoo": "barfoo",
"struct": map[string]interface{}{
"baz": "baz",
"bar": "bar",
},
},
2020-12-16 12:02:02 +00:00
},
2021-08-09 14:03:04 +00:00
{
2021-05-21 14:09:45 +00:00
Id: "foobaz",
Type: "other",
Attrs: &resource.Attributes{
"foobar": "foobar",
"barfoo": "barfoo",
"struct": map[string]interface{}{
"baz": "baz",
"bar": "bar",
},
},
2020-12-16 12:02:02 +00:00
},
2021-08-09 14:03:04 +00:00
{
2021-05-21 14:09:45 +00:00
Id: "resource",
Type: "other",
Attrs: &resource.Attributes{
"foobar": "foobar",
"barfoo": "barfoo",
"struct": map[string]interface{}{
"baz": "baz",
"bar": "bar",
},
"structslice": []map[string]interface{}{
{
"string": "one",
"array": []string{"foo"},
},
},
2020-12-16 12:02:02 +00:00
},
},
},
2021-08-09 14:03:04 +00:00
cloud: []*resource.Resource{
{
2021-05-21 14:09:45 +00:00
Id: "foobar",
Type: "fakeres",
Attrs: &resource.Attributes{
"foobar": "barfoo",
"barfoo": "foobar",
"struct": map[string]interface{}{
"baz": "bar",
"bar": "baz",
},
},
2020-12-16 12:02:02 +00:00
},
2021-08-09 14:03:04 +00:00
{
2021-05-21 14:09:45 +00:00
Id: "barfoo",
Type: "fakeres",
Attrs: &resource.Attributes{
"foobar": "barfoo",
"barfoo": "foobar",
"struct": map[string]interface{}{
"baz": "bar",
"bar": "baz",
},
},
2020-12-16 12:02:02 +00:00
},
2021-08-09 14:03:04 +00:00
{
2021-05-21 14:09:45 +00:00
Id: "foobaz",
Type: "other",
Attrs: &resource.Attributes{
"foobar": "barfoo",
"barfoo": "foobar",
"struct": map[string]interface{}{
"baz": "bar",
"bar": "baz",
},
},
2020-12-16 12:02:02 +00:00
},
2021-08-09 14:03:04 +00:00
{
2021-05-21 14:09:45 +00:00
Id: "resource",
Type: "other",
Attrs: &resource.Attributes{
"foobar": "barfoo",
"barfoo": "foobar",
"struct": map[string]interface{}{
"baz": "bar",
"bar": "baz",
},
"structslice": []map[string]interface{}{
{
"string": "two",
"array": []string{"oof"},
},
},
2020-12-16 12:02:02 +00:00
},
},
},
alerts: alerter.Alerts{
"fakeres": {
&alerter.FakeAlert{Msg: "Should be ignored", IgnoreResource: true},
2020-12-16 12:02:02 +00:00
},
"other.foobaz": {
&alerter.FakeAlert{Msg: "Should be ignored", IgnoreResource: true},
2020-12-16 12:02:02 +00:00
},
"other.resource": {
&alerter.FakeAlert{Msg: "Should not be ignored"},
2020-12-16 12:02:02 +00:00
},
},
expected: Analysis{
2021-08-09 14:03:04 +00:00
managed: []*resource.Resource{
{
2021-05-21 14:09:45 +00:00
Id: "resource",
Type: "other",
Attrs: &resource.Attributes{
"foobar": "foobar",
"barfoo": "barfoo",
"struct": map[string]interface{}{
"baz": "baz",
"bar": "bar",
},
"structslice": []map[string]interface{}{
{
"string": "one",
"array": []string{"foo"},
},
},
2020-12-16 12:02:02 +00:00
},
},
},
summary: Summary{
TotalResources: 1,
TotalDrifted: 1,
TotalManaged: 1,
},
differences: []Difference{
{
2021-08-09 14:03:04 +00:00
Res: &resource.Resource{
2021-05-21 14:09:45 +00:00
Id: "resource",
Type: "other",
Attrs: &resource.Attributes{
"foobar": "foobar",
"barfoo": "barfoo",
"struct": map[string]interface{}{
"baz": "baz",
"bar": "bar",
},
"structslice": []map[string]interface{}{
{
"string": "one",
"array": []string{"foo"},
},
},
2020-12-16 12:02:02 +00:00
},
},
2021-01-08 17:14:26 +00:00
Changelog: Changelog{
{
Change: diff.Change{
Type: "update",
From: "barfoo",
To: "foobar",
Path: []string{
2021-05-21 14:09:45 +00:00
"barfoo",
2021-01-08 17:14:26 +00:00
},
2020-12-16 12:02:02 +00:00
},
},
2021-01-08 17:14:26 +00:00
{
Change: diff.Change{
Type: "update",
From: "foobar",
To: "barfoo",
2021-01-08 17:14:26 +00:00
Path: []string{
2021-05-21 14:09:45 +00:00
"foobar",
2021-01-08 17:14:26 +00:00
},
2020-12-16 12:02:02 +00:00
},
},
2021-01-08 17:14:26 +00:00
{
Change: diff.Change{
Type: "update",
From: "bar",
To: "baz",
Path: []string{
2021-05-21 14:09:45 +00:00
"struct",
"bar",
2021-01-08 17:14:26 +00:00
},
2020-12-16 12:02:02 +00:00
},
},
2021-01-08 17:14:26 +00:00
{
Change: diff.Change{
Type: "update",
From: "baz",
To: "bar",
2021-01-08 17:14:26 +00:00
Path: []string{
2021-05-21 14:09:45 +00:00
"struct",
"baz",
2021-01-08 17:14:26 +00:00
},
2020-12-16 12:02:02 +00:00
},
},
2021-01-08 17:14:26 +00:00
{
Change: diff.Change{
Type: "update",
2021-03-22 11:08:53 +00:00
From: "foo",
To: "oof",
2021-01-08 17:14:26 +00:00
Path: []string{
2021-05-21 14:09:45 +00:00
"structslice",
2021-01-08 17:14:26 +00:00
"0",
2021-05-21 14:09:45 +00:00
"array",
2021-03-22 11:08:53 +00:00
"0",
2021-01-08 17:14:26 +00:00
},
2020-12-16 12:02:02 +00:00
},
},
{
Change: diff.Change{
Type: "update",
From: "one",
To: "two",
Path: []string{
2021-05-21 14:09:45 +00:00
"structslice",
"0",
2021-05-21 14:09:45 +00:00
"string",
},
},
},
2020-12-16 12:02:02 +00:00
},
},
},
alerts: alerter.Alerts{
"fakeres": {
&alerter.FakeAlert{Msg: "Should be ignored", IgnoreResource: true},
2020-12-16 12:02:02 +00:00
},
"other.foobaz": {
&alerter.FakeAlert{Msg: "Should be ignored", IgnoreResource: true},
2020-12-16 12:02:02 +00:00
},
"other.resource": {
&alerter.FakeAlert{Msg: "Should not be ignored"},
2021-01-21 17:05:29 +00:00
},
2020-12-16 12:02:02 +00:00
},
},
hasDrifted: true,
},
{
name: "TestDiff with computed field send 1 alert",
2021-08-09 14:03:04 +00:00
iac: []*resource.Resource{
{
2021-05-21 14:09:45 +00:00
Id: "ID",
Type: aws.AwsAmiResourceType,
Attrs: &resource.Attributes{
"id": "ID",
"arn": "ARN",
},
},
},
2021-08-09 14:03:04 +00:00
cloud: []*resource.Resource{
{
2021-05-21 14:09:45 +00:00
Id: "ID",
Type: aws.AwsAmiResourceType,
Attrs: &resource.Attributes{
"id": "IDCHANGED",
"arn": "ARNCHANGED",
},
},
},
alerts: alerter.Alerts{},
expected: Analysis{
2021-08-09 14:03:04 +00:00
managed: []*resource.Resource{
{
2021-05-21 14:09:45 +00:00
Id: "ID",
Type: aws.AwsAmiResourceType,
Attrs: &resource.Attributes{
"id": "ID",
"arn": "ARN",
},
},
},
summary: Summary{
2021-05-21 14:09:45 +00:00
TotalResources: 1,
TotalDrifted: 1,
TotalManaged: 1,
},
differences: []Difference{
{
2021-08-09 14:03:04 +00:00
Res: &resource.Resource{
2021-05-21 14:09:45 +00:00
Id: "ID",
Type: aws.AwsAmiResourceType,
Attrs: &resource.Attributes{
"id": "ID",
"arn": "ARN",
},
},
Changelog: Changelog{
{
Change: diff.Change{
Type: "update",
2021-05-21 14:09:45 +00:00
From: "ARN",
To: "ARNCHANGED",
Path: []string{
2021-05-21 14:09:45 +00:00
"arn",
},
},
Computed: true,
},
2021-03-26 18:10:38 +00:00
{
Change: diff.Change{
Type: "update",
2021-05-21 14:09:45 +00:00
From: "ID",
To: "IDCHANGED",
2021-03-26 18:10:38 +00:00
Path: []string{
2021-05-21 14:09:45 +00:00
"id",
2021-03-26 18:10:38 +00:00
},
},
Computed: true,
},
},
},
},
alerts: alerter.Alerts{
"": {
NewComputedDiffAlert(),
},
},
},
hasDrifted: true,
},
2021-02-15 14:49:20 +00:00
{
name: "Test alert on unmanaged security group rules",
2021-08-09 14:03:04 +00:00
iac: []*resource.Resource{
{
2021-05-10 16:02:57 +00:00
Id: "managed security group",
Type: aws.AwsSecurityGroupResourceType,
Attrs: &resource.Attributes{
"id": "managed security group",
},
2021-02-15 14:49:20 +00:00
},
},
2021-08-09 14:03:04 +00:00
cloud: []*resource.Resource{
{
2021-05-10 16:02:57 +00:00
Id: "managed security group",
Type: aws.AwsSecurityGroupResourceType,
Attrs: &resource.Attributes{
"id": "managed security group",
},
2021-02-15 14:49:20 +00:00
},
2021-08-09 14:03:04 +00:00
{
2021-05-10 16:02:57 +00:00
Id: "unmanaged rule",
Type: aws.AwsSecurityGroupRuleResourceType,
Attrs: &resource.Attributes{
"id": "unmanaged rule",
},
2021-02-15 14:49:20 +00:00
},
},
expected: Analysis{
2021-08-09 14:03:04 +00:00
managed: []*resource.Resource{
{
2021-05-10 16:02:57 +00:00
Id: "managed security group",
Type: aws.AwsSecurityGroupResourceType,
Attrs: &resource.Attributes{
"id": "managed security group",
},
2021-02-15 14:49:20 +00:00
},
},
2021-08-09 14:03:04 +00:00
unmanaged: []*resource.Resource{
{
2021-05-10 16:02:57 +00:00
Id: "unmanaged rule",
Type: aws.AwsSecurityGroupRuleResourceType,
Attrs: &resource.Attributes{
"id": "unmanaged rule",
},
2021-02-15 14:49:20 +00:00
},
},
summary: Summary{
TotalResources: 2,
TotalManaged: 1,
TotalUnmanaged: 1,
},
alerts: alerter.Alerts{
"": {
newUnmanagedSecurityGroupRulesAlert(),
2021-02-15 14:49:20 +00:00
},
},
},
hasDrifted: true,
},
{
name: "Test sorted unmanaged & deleted resources",
2021-08-09 14:03:04 +00:00
iac: []*resource.Resource{
{
2021-03-22 10:35:23 +00:00
Id: "deleted resource 22",
Type: "aws_s3_bucket",
},
2021-08-09 14:03:04 +00:00
{
2021-03-22 10:35:23 +00:00
Id: "deleted resource 20",
Type: "aws_ebs_volume",
},
2021-08-09 14:03:04 +00:00
{
2021-03-22 10:35:23 +00:00
Id: "deleted resource 20",
Type: "aws_s3_bucket",
},
},
2021-08-09 14:03:04 +00:00
cloud: []*resource.Resource{
{
2021-03-22 10:35:23 +00:00
Id: "unmanaged resource 12",
Type: "aws_s3_bucket",
},
2021-08-09 14:03:04 +00:00
{
2021-03-22 10:35:23 +00:00
Id: "unmanaged resource 10",
Type: "aws_s3_bucket",
},
2021-08-09 14:03:04 +00:00
{
2021-03-22 10:35:23 +00:00
Id: "unmanaged resource 11",
Type: "aws_ebs_volume",
},
},
expected: Analysis{
2021-08-09 14:03:04 +00:00
managed: []*resource.Resource{},
unmanaged: []*resource.Resource{
{
2021-03-22 10:35:23 +00:00
Id: "unmanaged resource 11",
Type: "aws_ebs_volume",
},
2021-08-09 14:03:04 +00:00
{
2021-03-22 10:35:23 +00:00
Id: "unmanaged resource 10",
Type: "aws_s3_bucket",
},
2021-08-09 14:03:04 +00:00
{
2021-03-22 10:35:23 +00:00
Id: "unmanaged resource 12",
Type: "aws_s3_bucket",
},
},
2021-08-09 14:03:04 +00:00
deleted: []*resource.Resource{
{
2021-03-22 10:35:23 +00:00
Id: "deleted resource 20",
Type: "aws_ebs_volume",
},
2021-08-09 14:03:04 +00:00
{
2021-03-22 10:35:23 +00:00
Id: "deleted resource 20",
Type: "aws_s3_bucket",
},
2021-08-09 14:03:04 +00:00
{
2021-03-22 10:35:23 +00:00
Id: "deleted resource 22",
Type: "aws_s3_bucket",
},
},
summary: Summary{
2021-03-22 10:35:23 +00:00
TotalResources: 6,
TotalManaged: 0,
2021-03-22 10:35:23 +00:00
TotalUnmanaged: 3,
TotalDeleted: 3,
},
2021-03-22 10:35:23 +00:00
alerts: alerter.Alerts{},
},
hasDrifted: true,
},
}
2021-03-22 10:17:50 +00:00
differ, err := diff.NewDiffer(diff.SliceOrdering(true))
if err != nil {
2021-03-22 11:02:06 +00:00
t.Fatalf("Error creating new differ: %e", err)
2021-03-22 10:17:50 +00:00
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
2021-07-26 09:17:32 +00:00
testFilter := &filter.MockFilter{}
for _, ignored := range c.ignoredRes {
2021-07-26 09:17:32 +00:00
testFilter.On("IsResourceIgnored", ignored).Return(true)
}
2021-07-26 09:17:32 +00:00
testFilter.On("IsResourceIgnored", mock.Anything).Return(false)
for _, s := range c.ignoredDrift {
2021-07-26 09:17:32 +00:00
testFilter.On("IsFieldIgnored", s.res, s.path).Return(true)
}
2021-07-26 09:17:32 +00:00
testFilter.On("IsFieldIgnored", mock.Anything, mock.Anything).Return(false)
2021-01-08 17:14:26 +00:00
al := alerter.NewAlerter()
2020-12-16 12:02:02 +00:00
if c.alerts != nil {
2021-01-08 17:14:26 +00:00
al.SetAlerts(c.alerts)
2020-12-16 12:02:02 +00:00
}
2021-03-26 08:44:55 +00:00
repo := testresource.InitFakeSchemaRepository("aws", "3.19.0")
aws.InitResourcesMetadata(repo)
2021-07-26 09:17:32 +00:00
analyzer := NewAnalyzer(al, AnalyzerOptions{Deep: true}, testFilter)
2021-05-21 14:09:45 +00:00
for _, res := range c.cloud {
addSchemaToRes(res, repo)
}
for _, res := range c.iac {
addSchemaToRes(res, repo)
}
for _, res := range c.ignoredRes {
addSchemaToRes(res, repo)
}
for _, drift := range c.ignoredDrift {
addSchemaToRes(drift.res, repo)
}
2021-07-26 09:17:32 +00:00
result, err := analyzer.Analyze(c.cloud, c.iac)
if err != nil {
t.Error(err)
return
}
if result.IsSync() == c.hasDrifted {
t.Errorf("Drifted state does not match, got %t expected %t", result.IsSync(), !c.hasDrifted)
}
2021-03-22 10:17:50 +00:00
managedChanges, err := differ.Diff(result.Managed(), c.expected.Managed())
if err != nil {
t.Fatalf("Unable to compare %+v", err)
}
if len(managedChanges) > 0 {
for _, change := range managedChanges {
t.Errorf("%+v", change)
}
}
2021-03-22 10:17:50 +00:00
unmanagedChanges, err := differ.Diff(result.Unmanaged(), c.expected.Unmanaged())
if err != nil {
t.Fatalf("Unable to compare %+v", err)
}
if len(unmanagedChanges) > 0 {
for _, change := range unmanagedChanges {
t.Errorf("%+v", change)
}
}
2021-03-22 10:17:50 +00:00
deletedChanges, err := differ.Diff(result.Deleted(), c.expected.Deleted())
if err != nil {
t.Fatalf("Unable to compare %+v", err)
}
if len(deletedChanges) > 0 {
for _, change := range deletedChanges {
t.Errorf("%+v", change)
}
}
2021-03-22 11:08:53 +00:00
diffChanges, err := differ.Diff(result.Differences(), c.expected.Differences())
if err != nil {
t.Fatalf("Unable to compare %+v", err)
}
if len(diffChanges) > 0 {
for _, change := range diffChanges {
t.Errorf("%+v", change)
}
}
2021-03-22 10:17:50 +00:00
summaryChanges, err := differ.Diff(c.expected.Summary(), result.Summary())
if err != nil {
t.Fatalf("Unable to compare %+v", err)
}
if len(summaryChanges) > 0 {
for _, change := range summaryChanges {
t.Errorf("%+v", change)
}
}
2021-03-22 10:17:50 +00:00
alertsChanges, err := differ.Diff(result.Alerts(), c.expected.Alerts())
2020-12-16 12:02:02 +00:00
if err != nil {
t.Fatalf("Unable to compare %+v", err)
}
if len(alertsChanges) > 0 {
for _, change := range alertsChanges {
t.Errorf("%+v", change)
}
}
})
}
}
2021-08-09 14:03:04 +00:00
func addSchemaToRes(res *resource.Resource, repo resource.SchemaRepositoryInterface) {
schema, _ := repo.GetSchema(res.ResourceType())
2021-08-09 14:03:04 +00:00
res.Sch = schema
2021-05-21 14:09:45 +00:00
}
func TestAnalysis_MarshalJSON(t *testing.T) {
goldenFile := "./testdata/output.json"
analysis := Analysis{}
analysis.AddManaged(
2021-08-09 14:03:04 +00:00
&resource.Resource{
Id: "AKIA5QYBVVD25KFXJHYJ",
Type: "aws_iam_access_key",
2021-08-09 14:03:04 +00:00
}, &resource.Resource{
Id: "driftctl2",
Type: "aws_managed_resource",
},
)
analysis.AddUnmanaged(
2021-08-09 14:03:04 +00:00
&resource.Resource{
Id: "driftctl",
Type: "aws_s3_bucket_policy",
2021-08-09 14:03:04 +00:00
}, &resource.Resource{
Id: "driftctl",
Type: "aws_s3_bucket_notification",
},
)
analysis.AddDeleted(
2021-08-09 14:03:04 +00:00
&resource.Resource{
2021-05-21 14:09:45 +00:00
Id: "test-driftctl2",
Type: "aws_iam_user",
Attrs: &resource.Attributes{
"foobar": "test",
},
},
2021-08-09 14:03:04 +00:00
&resource.Resource{
Id: "AKIA5QYBVVD2Y6PBAAPY",
Type: "aws_iam_access_key",
},
)
analysis.AddDifference(Difference{
2021-08-09 14:03:04 +00:00
Res: &resource.Resource{
Id: "AKIA5QYBVVD25KFXJHYJ",
Type: "aws_iam_access_key",
2021-08-03 08:26:38 +00:00
Source: &resource.TerraformStateSource{
State: "tfstate://terraform.tfstate",
Module: "module",
Name: "my_name",
},
},
2021-01-08 17:14:26 +00:00
Changelog: []Change{
{
2021-01-08 17:14:26 +00:00
Change: diff.Change{
Type: "update",
2021-05-21 14:09:45 +00:00
Path: []string{"status"},
2021-01-08 17:14:26 +00:00
From: "Active",
To: "Inactive",
},
},
},
})
2021-01-11 16:33:23 +00:00
analysis.SetAlerts(alerter.Alerts{
2020-12-16 12:02:02 +00:00
"aws_iam_access_key": {
&alerter.FakeAlert{Msg: "This is an alert"},
2020-12-16 12:02:02 +00:00
},
})
2021-07-29 09:50:35 +00:00
analysis.ProviderName = "AWS"
analysis.ProviderVersion = "2.18.5"
got, err := json.MarshalIndent(analysis, "", "\t")
if err != nil {
t.Fatal(err)
}
if *goldenfile.Update == "TestAnalysis_MarshalJSON" {
if err := ioutil.WriteFile(goldenFile, got, 0600); err != nil {
t.Fatal(err)
}
}
expected, err := ioutil.ReadFile(goldenFile)
if err != nil {
t.Fatal(err)
}
assert.Nil(t, err)
assert.Equal(t, string(expected), string(got))
}
func TestAnalysis_UnmarshalJSON(t *testing.T) {
expected := Analysis{
summary: Summary{
TotalResources: 6,
TotalDrifted: 1,
TotalUnmanaged: 2,
TotalDeleted: 2,
TotalManaged: 2,
},
2021-08-09 14:03:04 +00:00
managed: []*resource.Resource{
{
Id: "AKIA5QYBVVD25KFXJHYJ",
Type: "aws_iam_access_key",
},
2021-08-09 14:03:04 +00:00
{
Id: "test-managed",
Type: "aws_iam_user",
},
},
2021-08-09 14:03:04 +00:00
unmanaged: []*resource.Resource{
{
Id: "driftctl",
Type: "aws_s3_bucket_policy",
},
2021-08-09 14:03:04 +00:00
{
Id: "driftctl",
Type: "aws_s3_bucket_notification",
},
},
2021-08-09 14:03:04 +00:00
deleted: []*resource.Resource{
{
Id: "test-driftctl2",
Type: "aws_iam_user",
},
2021-08-09 14:03:04 +00:00
{
Id: "AKIA5QYBVVD2Y6PBAAPY",
Type: "aws_iam_access_key",
},
},
differences: []Difference{
{
2021-08-09 14:03:04 +00:00
Res: &resource.Resource{
Id: "AKIA5QYBVVD25KFXJHYJ",
Type: "aws_iam_access_key",
},
2021-01-08 17:14:26 +00:00
Changelog: []Change{
{
2021-01-08 17:14:26 +00:00
Change: diff.Change{
Type: "update",
2021-05-21 14:09:45 +00:00
Path: []string{"status"},
2021-01-08 17:14:26 +00:00
From: "Active",
To: "Inactive",
},
},
},
},
},
2020-12-16 12:02:02 +00:00
alerts: alerter.Alerts{
"aws_iam_access_key": {
&alerter.SerializedAlert{
Msg: "This is an alert",
2020-12-16 12:02:02 +00:00
},
},
},
2021-07-29 09:50:35 +00:00
ProviderName: "AWS",
ProviderVersion: "2.18.5",
}
got := Analysis{}
input, err := ioutil.ReadFile("./testdata/input.json")
if err != nil {
t.Fatal(err)
}
err = json.Unmarshal(input, &got)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, expected, got)
assert.Equal(t, 33, got.Coverage())
assert.Equal(t, 2, got.Summary().TotalUnmanaged)
assert.Equal(t, 2, got.Summary().TotalManaged)
assert.Equal(t, 2, got.Summary().TotalDeleted)
assert.Equal(t, 6, got.Summary().TotalResources)
assert.Equal(t, 1, got.Summary().TotalDrifted)
assert.Len(t, got.alerts, 1)
assert.Equal(t, got.alerts["aws_iam_access_key"][0].Message(), "This is an alert")
}