Skip to content

Commit

Permalink
Merge pull request #1359 from snyk/fea/only-mode
Browse files Browse the repository at this point in the history
New --only-managed / --only-unmanaged flags
  • Loading branch information
eliecharra authored Mar 1, 2022
2 parents 39dae70 + d2cc564 commit e318395
Show file tree
Hide file tree
Showing 11 changed files with 310 additions and 7 deletions.
4 changes: 4 additions & 0 deletions pkg/analyser/analysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ func (a *Analysis) SetAlerts(alerts alerter.Alerts) {
a.alerts = alerts
}

func (a *Analysis) SetOptions(options AnalyzerOptions) {
a.options = options
}

func (a *Analysis) Coverage() int {
if a.summary.TotalResources > 0 {
return int((float32(a.summary.TotalManaged) / float32(a.summary.TotalResources)) * 100.0)
Expand Down
12 changes: 9 additions & 3 deletions pkg/analyser/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ func (c *ComputedDiffAlert) ShouldIgnoreResource() bool {
}

type AnalyzerOptions struct {
Deep bool
Deep bool
OnlyManaged bool
OnlyUnmanaged bool
}

type Analyzer struct {
Expand Down Expand Up @@ -72,7 +74,9 @@ func (a Analyzer) Analyze(remoteResources, resourcesFromState []*resource.Resour
}

if !found {
analysis.AddDeleted(stateRes)
if !analysis.Options().OnlyUnmanaged {
analysis.AddDeleted(stateRes)
}
continue
}

Expand Down Expand Up @@ -130,7 +134,9 @@ func (a Analyzer) Analyze(remoteResources, resourcesFromState []*resource.Resour
}

// Add remaining unmanaged resources
analysis.AddUnmanaged(filteredRemoteResource...)
if !analysis.Options().OnlyManaged {
analysis.AddUnmanaged(filteredRemoteResource...)
}

// Sort resources by Terraform Id
// The purpose is to have a predictable output
Expand Down
164 changes: 163 additions & 1 deletion pkg/analyser/analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func TestAnalyze(t *testing.T) {
alerts alerter.Alerts
expected Analysis
hasDrifted bool
options *AnalyzerOptions
}{
{
name: "TestNilValues", // Cover division by zero case
Expand Down Expand Up @@ -980,6 +981,162 @@ func TestAnalyze(t *testing.T) {
},
},
},
{
name: "Test --only-managed flag",
iac: []*resource.Resource{
{
Id: "foo",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test2",
},
},
{
Id: "baz",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test3",
},
},
},
cloud: []*resource.Resource{
{
Id: "foo",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test1",
},
},
{
Id: "bar",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test2",
},
},
},
hasDrifted: true,
expected: Analysis{
managed: []*resource.Resource{
{
Id: "foo",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test2",
},
},
},
deleted: []*resource.Resource{
{
Id: "baz",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test3",
},
},
},
differences: []Difference{
{
Res: &resource.Resource{
Id: "foo",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test2",
},
},
Changelog: Changelog{
{
Change: diff.Change{
Type: "update",
From: "test2",
To: "test1",
Path: []string{
"instance_type",
},
},
},
},
},
},
summary: Summary{
TotalResources: 2,
TotalManaged: 1,
TotalUnmanaged: 0,
TotalDeleted: 1,
TotalDrifted: 1,
},
},
options: &AnalyzerOptions{
OnlyManaged: true,
Deep: true,
},
},
{
name: "Test --only-unmanaged flag",
iac: []*resource.Resource{
{
Id: "foo",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test2",
},
},
{
Id: "baz",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test3",
},
},
},
cloud: []*resource.Resource{
{
Id: "foo",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test1",
},
},
{
Id: "bar",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test2",
},
},
},
hasDrifted: true,
expected: Analysis{
managed: []*resource.Resource{
{
Id: "foo",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test2",
},
},
},
unmanaged: []*resource.Resource{
{
Id: "bar",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test2",
},
},
},
summary: Summary{
TotalResources: 2,
TotalManaged: 1,
TotalUnmanaged: 1,
TotalDeleted: 0,
TotalDrifted: 0,
},
},
options: &AnalyzerOptions{
OnlyUnmanaged: true,
},
},
}

differ, err := diff.NewDiffer(diff.SliceOrdering(true))
Expand Down Expand Up @@ -1008,7 +1165,12 @@ func TestAnalyze(t *testing.T) {
repo := testresource.InitFakeSchemaRepository("aws", "3.19.0")
aws.InitResourcesMetadata(repo)

analyzer := NewAnalyzer(al, AnalyzerOptions{Deep: true}, testFilter)
options := AnalyzerOptions{Deep: true}
if c.options != nil {
options = *c.options
}

analyzer := NewAnalyzer(al, options, testFilter)

for _, res := range c.cloud {
addSchemaToRes(res, repo)
Expand Down
16 changes: 15 additions & 1 deletion pkg/cmd/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ func NewScanCmd(opts *pkg.ScanOptions) *cobra.Command {

opts.ConfigDir, _ = cmd.Flags().GetString("config-dir")

if onlyManaged, _ := cmd.Flags().GetBool("only-managed"); onlyManaged {
opts.Deep = true
}

return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
Expand Down Expand Up @@ -228,6 +232,16 @@ func NewScanCmd(opts *pkg.ScanOptions) *cobra.Command {
configDir,
"Directory path that driftctl uses for configuration.\n",
)
fl.BoolVar(&opts.OnlyManaged,
"only-managed",
false,
"Report only what's managed by your IaC\n",
)
fl.BoolVar(&opts.OnlyUnmanaged,
"only-unmanaged",
false,
"Report only what's not managed by your IaC\n",
)

return cmd
}
Expand Down Expand Up @@ -282,7 +296,7 @@ func scanRun(opts *pkg.ScanOptions) error {
scanner,
iacSupplier,
alerter,
analyser.NewAnalyzer(alerter, analyser.AnalyzerOptions{Deep: opts.Deep}, driftIgnore),
analyser.NewAnalyzer(alerter, analyser.AnalyzerOptions{Deep: opts.Deep, OnlyManaged: opts.OnlyManaged, OnlyUnmanaged: opts.OnlyUnmanaged}, driftIgnore),
resFactory,
opts,
scanProgress,
Expand Down
8 changes: 6 additions & 2 deletions pkg/cmd/scan/output/console.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,13 +215,17 @@ func (c Console) writeSummary(analysis *analyser.Analysis) {
if analysis.Summary().TotalUnmanaged > 0 {
unmanaged = warningWriter.Sprintf("%d", analysis.Summary().TotalUnmanaged)
}
fmt.Printf(" - %s resource(s) not managed by Terraform\n", unmanaged)
if !analysis.Options().OnlyManaged {
fmt.Printf(" - %s resource(s) not managed by Terraform\n", unmanaged)
}

deleted := successWriter.Sprintf("0")
if analysis.Summary().TotalDeleted > 0 {
deleted = errorWriter.Sprintf("%d", analysis.Summary().TotalDeleted)
}
fmt.Printf(" - %s resource(s) found in a Terraform state but missing on the cloud provider\n", deleted)
if !analysis.Options().OnlyUnmanaged {
fmt.Printf(" - %s resource(s) found in a Terraform state but missing on the cloud provider\n", deleted)
}
}
if analysis.IsSync() {
fmt.Println(color.GreenString("Congrats! Your infrastructure is fully in sync."))
Expand Down
12 changes: 12 additions & 0 deletions pkg/cmd/scan/output/console_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,18 @@ func TestConsole_Write(t *testing.T) {
args: args{analysis: fakeAnalysisWithoutDeep()},
wantErr: false,
},
{
name: "test console output with --only-managed",
goldenfile: "output_with_only_managed.txt",
args: args{analysis: fakeAnalysisWithOnlyManagedFlag()},
wantErr: false,
},
{
name: "test console output with --only-unmanaged",
goldenfile: "output_with_only_unmanaged.txt",
args: args{analysis: fakeAnalysisWithOnlyUnmanagedFlag()},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
80 changes: 80 additions & 0 deletions pkg/cmd/scan/output/output_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/snyk/driftctl/pkg/remote/common"
remoteerr "github.com/snyk/driftctl/pkg/remote/error"
"github.com/snyk/driftctl/pkg/resource"
"github.com/snyk/driftctl/pkg/resource/aws"
)

func fakeAnalysis(opts analyser.AnalyzerOptions) *analyser.Analysis {
Expand Down Expand Up @@ -465,6 +466,85 @@ func fakeAnalysisWithoutDeep() *analyser.Analysis {
return &a
}

func fakeAnalysisWithOnlyManagedFlag() *analyser.Analysis {
a := analyser.Analysis{}
a.SetOptions(analyser.AnalyzerOptions{
OnlyManaged: true,
Deep: true,
})
a.AddManaged(
&resource.Resource{
Id: "foo",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test2",
},
},
)
a.AddDifference(
analyser.Difference{
Res: &resource.Resource{
Id: "foo",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test2",
},
},
Changelog: []analyser.Change{
{
Change: diff.Change{
Type: "update",
From: "test2",
To: "test1",
Path: []string{
"instance_type",
},
},
},
},
})
a.AddDeleted(
&resource.Resource{
Id: "baz",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test3",
},
},
)
a.ProviderName = "AWS"
a.ProviderVersion = "3.19.0"
return &a
}

func fakeAnalysisWithOnlyUnmanagedFlag() *analyser.Analysis {
a := analyser.Analysis{}
a.SetOptions(analyser.AnalyzerOptions{
OnlyUnmanaged: true,
})
a.AddManaged(
&resource.Resource{
Id: "foo",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test2",
},
},
)
a.AddUnmanaged(
&resource.Resource{
Id: "bar",
Type: aws.AwsInstanceResourceType,
Attrs: &resource.Attributes{
"instance_type": "test2",
},
},
)
a.ProviderName = "AWS"
a.ProviderVersion = "3.19.0"
return &a
}

func TestGetPrinter(t *testing.T) {
tests := []struct {
name string
Expand Down
Loading

0 comments on commit e318395

Please sign in to comment.