Skip to content

Commit e318395

Browse files
authored
Merge pull request #1359 from snyk/fea/only-mode
New --only-managed / --only-unmanaged flags
2 parents 39dae70 + d2cc564 commit e318395

File tree

11 files changed

+310
-7
lines changed

11 files changed

+310
-7
lines changed

pkg/analyser/analysis.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,10 @@ func (a *Analysis) SetAlerts(alerts alerter.Alerts) {
204204
a.alerts = alerts
205205
}
206206

207+
func (a *Analysis) SetOptions(options AnalyzerOptions) {
208+
a.options = options
209+
}
210+
207211
func (a *Analysis) Coverage() int {
208212
if a.summary.TotalResources > 0 {
209213
return int((float32(a.summary.TotalManaged) / float32(a.summary.TotalResources)) * 100.0)

pkg/analyser/analyzer.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ func (c *ComputedDiffAlert) ShouldIgnoreResource() bool {
3838
}
3939

4040
type AnalyzerOptions struct {
41-
Deep bool
41+
Deep bool
42+
OnlyManaged bool
43+
OnlyUnmanaged bool
4244
}
4345

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

7476
if !found {
75-
analysis.AddDeleted(stateRes)
77+
if !analysis.Options().OnlyUnmanaged {
78+
analysis.AddDeleted(stateRes)
79+
}
7680
continue
7781
}
7882

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

132136
// Add remaining unmanaged resources
133-
analysis.AddUnmanaged(filteredRemoteResource...)
137+
if !analysis.Options().OnlyManaged {
138+
analysis.AddUnmanaged(filteredRemoteResource...)
139+
}
134140

135141
// Sort resources by Terraform Id
136142
// The purpose is to have a predictable output

pkg/analyser/analyzer_test.go

Lines changed: 163 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ func TestAnalyze(t *testing.T) {
3434
alerts alerter.Alerts
3535
expected Analysis
3636
hasDrifted bool
37+
options *AnalyzerOptions
3738
}{
3839
{
3940
name: "TestNilValues", // Cover division by zero case
@@ -980,6 +981,162 @@ func TestAnalyze(t *testing.T) {
980981
},
981982
},
982983
},
984+
{
985+
name: "Test --only-managed flag",
986+
iac: []*resource.Resource{
987+
{
988+
Id: "foo",
989+
Type: aws.AwsInstanceResourceType,
990+
Attrs: &resource.Attributes{
991+
"instance_type": "test2",
992+
},
993+
},
994+
{
995+
Id: "baz",
996+
Type: aws.AwsInstanceResourceType,
997+
Attrs: &resource.Attributes{
998+
"instance_type": "test3",
999+
},
1000+
},
1001+
},
1002+
cloud: []*resource.Resource{
1003+
{
1004+
Id: "foo",
1005+
Type: aws.AwsInstanceResourceType,
1006+
Attrs: &resource.Attributes{
1007+
"instance_type": "test1",
1008+
},
1009+
},
1010+
{
1011+
Id: "bar",
1012+
Type: aws.AwsInstanceResourceType,
1013+
Attrs: &resource.Attributes{
1014+
"instance_type": "test2",
1015+
},
1016+
},
1017+
},
1018+
hasDrifted: true,
1019+
expected: Analysis{
1020+
managed: []*resource.Resource{
1021+
{
1022+
Id: "foo",
1023+
Type: aws.AwsInstanceResourceType,
1024+
Attrs: &resource.Attributes{
1025+
"instance_type": "test2",
1026+
},
1027+
},
1028+
},
1029+
deleted: []*resource.Resource{
1030+
{
1031+
Id: "baz",
1032+
Type: aws.AwsInstanceResourceType,
1033+
Attrs: &resource.Attributes{
1034+
"instance_type": "test3",
1035+
},
1036+
},
1037+
},
1038+
differences: []Difference{
1039+
{
1040+
Res: &resource.Resource{
1041+
Id: "foo",
1042+
Type: aws.AwsInstanceResourceType,
1043+
Attrs: &resource.Attributes{
1044+
"instance_type": "test2",
1045+
},
1046+
},
1047+
Changelog: Changelog{
1048+
{
1049+
Change: diff.Change{
1050+
Type: "update",
1051+
From: "test2",
1052+
To: "test1",
1053+
Path: []string{
1054+
"instance_type",
1055+
},
1056+
},
1057+
},
1058+
},
1059+
},
1060+
},
1061+
summary: Summary{
1062+
TotalResources: 2,
1063+
TotalManaged: 1,
1064+
TotalUnmanaged: 0,
1065+
TotalDeleted: 1,
1066+
TotalDrifted: 1,
1067+
},
1068+
},
1069+
options: &AnalyzerOptions{
1070+
OnlyManaged: true,
1071+
Deep: true,
1072+
},
1073+
},
1074+
{
1075+
name: "Test --only-unmanaged flag",
1076+
iac: []*resource.Resource{
1077+
{
1078+
Id: "foo",
1079+
Type: aws.AwsInstanceResourceType,
1080+
Attrs: &resource.Attributes{
1081+
"instance_type": "test2",
1082+
},
1083+
},
1084+
{
1085+
Id: "baz",
1086+
Type: aws.AwsInstanceResourceType,
1087+
Attrs: &resource.Attributes{
1088+
"instance_type": "test3",
1089+
},
1090+
},
1091+
},
1092+
cloud: []*resource.Resource{
1093+
{
1094+
Id: "foo",
1095+
Type: aws.AwsInstanceResourceType,
1096+
Attrs: &resource.Attributes{
1097+
"instance_type": "test1",
1098+
},
1099+
},
1100+
{
1101+
Id: "bar",
1102+
Type: aws.AwsInstanceResourceType,
1103+
Attrs: &resource.Attributes{
1104+
"instance_type": "test2",
1105+
},
1106+
},
1107+
},
1108+
hasDrifted: true,
1109+
expected: Analysis{
1110+
managed: []*resource.Resource{
1111+
{
1112+
Id: "foo",
1113+
Type: aws.AwsInstanceResourceType,
1114+
Attrs: &resource.Attributes{
1115+
"instance_type": "test2",
1116+
},
1117+
},
1118+
},
1119+
unmanaged: []*resource.Resource{
1120+
{
1121+
Id: "bar",
1122+
Type: aws.AwsInstanceResourceType,
1123+
Attrs: &resource.Attributes{
1124+
"instance_type": "test2",
1125+
},
1126+
},
1127+
},
1128+
summary: Summary{
1129+
TotalResources: 2,
1130+
TotalManaged: 1,
1131+
TotalUnmanaged: 1,
1132+
TotalDeleted: 0,
1133+
TotalDrifted: 0,
1134+
},
1135+
},
1136+
options: &AnalyzerOptions{
1137+
OnlyUnmanaged: true,
1138+
},
1139+
},
9831140
}
9841141

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

1011-
analyzer := NewAnalyzer(al, AnalyzerOptions{Deep: true}, testFilter)
1168+
options := AnalyzerOptions{Deep: true}
1169+
if c.options != nil {
1170+
options = *c.options
1171+
}
1172+
1173+
analyzer := NewAnalyzer(al, options, testFilter)
10121174

10131175
for _, res := range c.cloud {
10141176
addSchemaToRes(res, repo)

pkg/cmd/scan.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ func NewScanCmd(opts *pkg.ScanOptions) *cobra.Command {
109109

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

112+
if onlyManaged, _ := cmd.Flags().GetBool("only-managed"); onlyManaged {
113+
opts.Deep = true
114+
}
115+
112116
return nil
113117
},
114118
RunE: func(cmd *cobra.Command, args []string) error {
@@ -228,6 +232,16 @@ func NewScanCmd(opts *pkg.ScanOptions) *cobra.Command {
228232
configDir,
229233
"Directory path that driftctl uses for configuration.\n",
230234
)
235+
fl.BoolVar(&opts.OnlyManaged,
236+
"only-managed",
237+
false,
238+
"Report only what's managed by your IaC\n",
239+
)
240+
fl.BoolVar(&opts.OnlyUnmanaged,
241+
"only-unmanaged",
242+
false,
243+
"Report only what's not managed by your IaC\n",
244+
)
231245

232246
return cmd
233247
}
@@ -282,7 +296,7 @@ func scanRun(opts *pkg.ScanOptions) error {
282296
scanner,
283297
iacSupplier,
284298
alerter,
285-
analyser.NewAnalyzer(alerter, analyser.AnalyzerOptions{Deep: opts.Deep}, driftIgnore),
299+
analyser.NewAnalyzer(alerter, analyser.AnalyzerOptions{Deep: opts.Deep, OnlyManaged: opts.OnlyManaged, OnlyUnmanaged: opts.OnlyUnmanaged}, driftIgnore),
286300
resFactory,
287301
opts,
288302
scanProgress,

pkg/cmd/scan/output/console.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,13 +215,17 @@ func (c Console) writeSummary(analysis *analyser.Analysis) {
215215
if analysis.Summary().TotalUnmanaged > 0 {
216216
unmanaged = warningWriter.Sprintf("%d", analysis.Summary().TotalUnmanaged)
217217
}
218-
fmt.Printf(" - %s resource(s) not managed by Terraform\n", unmanaged)
218+
if !analysis.Options().OnlyManaged {
219+
fmt.Printf(" - %s resource(s) not managed by Terraform\n", unmanaged)
220+
}
219221

220222
deleted := successWriter.Sprintf("0")
221223
if analysis.Summary().TotalDeleted > 0 {
222224
deleted = errorWriter.Sprintf("%d", analysis.Summary().TotalDeleted)
223225
}
224-
fmt.Printf(" - %s resource(s) found in a Terraform state but missing on the cloud provider\n", deleted)
226+
if !analysis.Options().OnlyUnmanaged {
227+
fmt.Printf(" - %s resource(s) found in a Terraform state but missing on the cloud provider\n", deleted)
228+
}
225229
}
226230
if analysis.IsSync() {
227231
fmt.Println(color.GreenString("Congrats! Your infrastructure is fully in sync."))

pkg/cmd/scan/output/console_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,18 @@ func TestConsole_Write(t *testing.T) {
114114
args: args{analysis: fakeAnalysisWithoutDeep()},
115115
wantErr: false,
116116
},
117+
{
118+
name: "test console output with --only-managed",
119+
goldenfile: "output_with_only_managed.txt",
120+
args: args{analysis: fakeAnalysisWithOnlyManagedFlag()},
121+
wantErr: false,
122+
},
123+
{
124+
name: "test console output with --only-unmanaged",
125+
goldenfile: "output_with_only_unmanaged.txt",
126+
args: args{analysis: fakeAnalysisWithOnlyUnmanagedFlag()},
127+
wantErr: false,
128+
},
117129
}
118130
for _, tt := range tests {
119131
t.Run(tt.name, func(t *testing.T) {

pkg/cmd/scan/output/output_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/snyk/driftctl/pkg/remote/common"
1515
remoteerr "github.com/snyk/driftctl/pkg/remote/error"
1616
"github.com/snyk/driftctl/pkg/resource"
17+
"github.com/snyk/driftctl/pkg/resource/aws"
1718
)
1819

1920
func fakeAnalysis(opts analyser.AnalyzerOptions) *analyser.Analysis {
@@ -465,6 +466,85 @@ func fakeAnalysisWithoutDeep() *analyser.Analysis {
465466
return &a
466467
}
467468

469+
func fakeAnalysisWithOnlyManagedFlag() *analyser.Analysis {
470+
a := analyser.Analysis{}
471+
a.SetOptions(analyser.AnalyzerOptions{
472+
OnlyManaged: true,
473+
Deep: true,
474+
})
475+
a.AddManaged(
476+
&resource.Resource{
477+
Id: "foo",
478+
Type: aws.AwsInstanceResourceType,
479+
Attrs: &resource.Attributes{
480+
"instance_type": "test2",
481+
},
482+
},
483+
)
484+
a.AddDifference(
485+
analyser.Difference{
486+
Res: &resource.Resource{
487+
Id: "foo",
488+
Type: aws.AwsInstanceResourceType,
489+
Attrs: &resource.Attributes{
490+
"instance_type": "test2",
491+
},
492+
},
493+
Changelog: []analyser.Change{
494+
{
495+
Change: diff.Change{
496+
Type: "update",
497+
From: "test2",
498+
To: "test1",
499+
Path: []string{
500+
"instance_type",
501+
},
502+
},
503+
},
504+
},
505+
})
506+
a.AddDeleted(
507+
&resource.Resource{
508+
Id: "baz",
509+
Type: aws.AwsInstanceResourceType,
510+
Attrs: &resource.Attributes{
511+
"instance_type": "test3",
512+
},
513+
},
514+
)
515+
a.ProviderName = "AWS"
516+
a.ProviderVersion = "3.19.0"
517+
return &a
518+
}
519+
520+
func fakeAnalysisWithOnlyUnmanagedFlag() *analyser.Analysis {
521+
a := analyser.Analysis{}
522+
a.SetOptions(analyser.AnalyzerOptions{
523+
OnlyUnmanaged: true,
524+
})
525+
a.AddManaged(
526+
&resource.Resource{
527+
Id: "foo",
528+
Type: aws.AwsInstanceResourceType,
529+
Attrs: &resource.Attributes{
530+
"instance_type": "test2",
531+
},
532+
},
533+
)
534+
a.AddUnmanaged(
535+
&resource.Resource{
536+
Id: "bar",
537+
Type: aws.AwsInstanceResourceType,
538+
Attrs: &resource.Attributes{
539+
"instance_type": "test2",
540+
},
541+
},
542+
)
543+
a.ProviderName = "AWS"
544+
a.ProviderVersion = "3.19.0"
545+
return &a
546+
}
547+
468548
func TestGetPrinter(t *testing.T) {
469549
tests := []struct {
470550
name string

0 commit comments

Comments
 (0)