Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge v0.8.0 into main #503

Merged
merged 32 commits into from
May 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
937154e
feat: detect & exclude unsupported Terraform versions
sundowndev Apr 16, 2021
6e68f81
Fix version check lambda version bump
Apr 27, 2021
885a404
Limited glob support.
Mar 29, 2021
0414c02
refactor: disable file matching when not using glob
sundowndev Apr 28, 2021
65704bf
chore: fix a minor typo
sundowndev Apr 30, 2021
c088a2f
feat: add support for ** in s3
sundowndev May 6, 2021
87ad272
feat: create gen-driftignore
sundowndev May 4, 2021
252674c
feat: add iac progress bar
sundowndev May 3, 2021
71bc55c
refactor: stop progress bar before error handling
sundowndev May 4, 2021
a45b2e4
Add telemetry
Apr 27, 2021
7d903fd
Add analysis duration for telemetry
Apr 28, 2021
8116ac4
test: mock http client
sundowndev Apr 28, 2021
9a8a4b4
fix: response body overrided by buffer
sundowndev Apr 28, 2021
942ff40
refactor(http): perform request in Read method
sundowndev Apr 29, 2021
bcff002
refactor: create pkg/http package
sundowndev Apr 30, 2021
62f6f99
feat: display ec2 instance name when tag name exist
sundowndev Apr 30, 2021
73c0387
feat(schemes): add tfcloud
ayshiff Apr 24, 2021
b555b8b
feat(state): add cloud reader
ayshiff Apr 24, 2021
609d3ec
fix(cloud_reader): make tests pass
ayshiff Apr 25, 2021
a031271
fix(scan_test): add tfcloud
ayshiff Apr 25, 2021
499c121
fix(cloud_reader): update tests + tfcloud token flag
ayshiff Apr 27, 2021
2ac9f89
fix(cloud_reader): requested changes
ayshiff Apr 27, 2021
57df7fe
fix(tfcloud): rename tfcloud -> tfc
ayshiff Apr 30, 2021
d010451
fix(tfcloud): rename tfcloud -> tfc
ayshiff May 3, 2021
53a17a3
refactor(tfcloud): rebase
ayshiff May 3, 2021
623ff3d
Move all AWS mocks to test/aws
May 4, 2021
56aa95f
chore: fix rebasing of branch
sundowndev May 7, 2021
6b6e4d6
refactor: fix error handling & simplify code
sundowndev May 7, 2021
2c76d30
fix: do not ignore default policy attachments
sundowndev May 7, 2021
6337493
fix: add line break in warning message
sundowndev May 10, 2021
0232696
Revert "Merge pull request #433 from cloudskiff/feat/genDriftIgnore"
sundowndev May 10, 2021
b22e6fa
test: fix a test case about strict mode
sundowndev May 10, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
version: 2.1
orbs:
aws-cli: circleci/aws-cli@1.3.0
go: circleci/go@1.5.0
jobs:
build:
Expand Down Expand Up @@ -167,15 +166,18 @@ jobs:
git commit -m "Updated to version ${CIRCLE_TAG}"
git push
update-lambda:
executor: aws-cli/default
environment:
FUNCTION_NAME: driftctl-version
docker:
- image: cimg/base:2021.04
steps:
- aws-cli/install
- run:
name: "Update Lambda version"
command: |
aws lambda update-function-configuration --function-name $FUNCTION_NAME --environment "{\"Variables\":{\"LATEST_VERSION\":\"$CIRCLE_TAG\"}}"
wget "https://github.com/cloudskiff/lambda-env-updater/releases/download/v1.0.0/lambda-env-updater_linux_amd64" && chmod +x lambda-env-updater_linux_amd64
./lambda-env-updater_linux_amd64\
-name ${FUNCTION_NAME}\
-env "LATEST_VERSION=${CIRCLE_TAG}"
workflows:
nightly:
jobs:
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.16

require (
github.com/aws/aws-sdk-go v1.34.2
github.com/bmatcuk/doublestar/v4 v4.0.1 // indirect
github.com/eapache/go-resiliency v1.2.0
github.com/fatih/color v1.9.0
github.com/getsentry/sentry-go v0.10.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c h1:+0HFd5KSZ/mm3
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/bmatcuk/doublestar v1.1.5 h1:2bNwBOmhyFEFcoB3tGvTD5xanq+4kyOZlB8wFYbMjkk=
github.com/bmatcuk/doublestar v1.1.5/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
github.com/bmatcuk/doublestar/v4 v4.0.1 h1:v5DFrvGpNnIKPlG7gcF4TlceHwBTvHdmjgDEkbDk9t8=
github.com/bmatcuk/doublestar/v4 v4.0.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
Expand Down
2 changes: 2 additions & 0 deletions pkg/analyser/analysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"sort"
"strings"
"time"

"github.com/r3labs/diff/v2"

Expand Down Expand Up @@ -39,6 +40,7 @@ type Analysis struct {
differences []Difference
summary Summary
alerts alerter.Alerts
Duration time.Duration
}

type serializableDifference struct {
Expand Down
1 change: 1 addition & 0 deletions pkg/cmd/driftctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func NewDriftctlCmd(build build.BuildInterface) *DriftctlCmd {

cmd.PersistentFlags().BoolP("help", "h", false, "Display help for command")
cmd.PersistentFlags().BoolP("no-version-check", "", false, "Disable the version check")
cmd.PersistentFlags().BoolP("disable-telemetry", "", false, "Disable telemetry")
cmd.PersistentFlags().BoolP("send-crash-report", "", false, "Enable error reporting. Crash data will be sent to us via Sentry.\nWARNING: may leak sensitive data (please read the documentation for more details)\nThis flag should be used only if an error occurs during execution")

cmd.AddCommand(NewScanCmd())
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/driftctl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func TestDriftctlCmd_Scan(t *testing.T) {
env: map[string]string{
"DCTL_FROM": "test",
},
err: fmt.Errorf("Unable to parse from flag 'test': \nAccepted schemes are: tfstate://,tfstate+s3://,tfstate+http://,tfstate+https://"),
err: fmt.Errorf("Unable to parse from flag 'test': \nAccepted schemes are: tfstate://,tfstate+s3://,tfstate+http://,tfstate+https://,tfstate+tfcloud://"),
},
{
env: map[string]string{
Expand Down
24 changes: 17 additions & 7 deletions pkg/cmd/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strings"
"syscall"

"github.com/cloudskiff/driftctl/pkg/telemetry"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -75,6 +76,7 @@ func NewScanCmd() *cobra.Command {
}

opts.Quiet, _ = cmd.Flags().GetBool("quiet")
opts.DisableTelemetry, _ = cmd.Flags().GetBool("disable-telemetry")

return nil
},
Expand Down Expand Up @@ -128,6 +130,12 @@ func NewScanCmd() *cobra.Command {
"Use those HTTP headers to query the provided URL.\n"+
"Only used with tfstate+http(s) backend for now.\n",
)
fl.StringVar(&opts.BackendOptions.TFCloudToken,
"tfc-token",
"",
"Terraform Cloud / Enterprise API token.\n"+
"Only used with tfstate+tfcloud backend.\n",
)
fl.BoolVar(&opts.StrictMode,
"strict",
false,
Expand All @@ -147,11 +155,12 @@ func scanRun(opts *pkg.ScanOptions) error {
providerLibrary := terraform.NewProviderLibrary()
supplierLibrary := resource.NewSupplierLibrary()

progress := globaloutput.NewProgress()
iacProgress := globaloutput.NewProgress("Scanning states", "Scanned states", true)
scanProgress := globaloutput.NewProgress("Scanning resources", "Scanned resources", true)

resourceSchemaRepository := resource.NewSchemaRepository()

err := remote.Activate(opts.To, alerter, providerLibrary, supplierLibrary, progress, resourceSchemaRepository)
err := remote.Activate(opts.To, alerter, providerLibrary, supplierLibrary, scanProgress, resourceSchemaRepository)
if err != nil {
return err
}
Expand All @@ -165,25 +174,22 @@ func scanRun(opts *pkg.ScanOptions) error {

scanner := pkg.NewScanner(supplierLibrary.Suppliers(), alerter, resourceSchemaRepository)

iacSupplier, err := supplier.GetIACSupplier(opts.From, providerLibrary, opts.BackendOptions, resourceSchemaRepository)
iacSupplier, err := supplier.GetIACSupplier(opts.From, providerLibrary, opts.BackendOptions, iacProgress, resourceSchemaRepository)
if err != nil {
return err
}

resFactory := terraform.NewTerraformResourceFactory(providerLibrary, resourceSchemaRepository)

ctl := pkg.NewDriftCTL(scanner, iacSupplier, alerter, resFactory, opts, resourceSchemaRepository)
ctl := pkg.NewDriftCTL(scanner, iacSupplier, alerter, resFactory, opts, scanProgress, iacProgress, resourceSchemaRepository)

go func() {
<-c
logrus.Warn("Detected interrupt, cleanup ...")
ctl.Stop()
}()

progress.Start()
analysis, err := ctl.Run()
progress.Stop()

if err != nil {
return err
}
Expand All @@ -193,6 +199,10 @@ func scanRun(opts *pkg.ScanOptions) error {
return err
}

if !opts.DisableTelemetry {
telemetry.SendTelemetry(analysis)
}

if !analysis.IsSync() {
return cmderrors.InfrastructureNotInSync{}
}
Expand Down
16 changes: 9 additions & 7 deletions pkg/cmd/scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ func TestScanCmd_Valid(t *testing.T) {
{args: []string{"scan", "-t", "aws+tf", "-f", "tfstate://test"}},
{args: []string{"scan", "--to", "aws+tf", "--from", "tfstate://test"}},
{args: []string{"scan", "--to", "aws+tf", "--from", "tfstate+https://github.com/state.tfstate"}},
{args: []string{"scan", "--to", "aws+tf", "--from", "tfstate+tfcloud://workspace_id"}},
{args: []string{"scan", "--tfc-token", "token"}},
{args: []string{"scan", "--filter", "Type=='aws_s3_bucket'"}},
{args: []string{"scan", "--strict"}},
}
Expand Down Expand Up @@ -69,14 +71,14 @@ func TestScanCmd_Invalid(t *testing.T) {
{args: []string{"scan", "-f"}, expected: `flag needs an argument: 'f' in -f`},
{args: []string{"scan", "--from"}, expected: `flag needs an argument: --from`},
{args: []string{"scan", "--from"}, expected: `flag needs an argument: --from`},
{args: []string{"scan", "--from", "tosdgjhgsdhgkjs"}, expected: "Unable to parse from flag 'tosdgjhgsdhgkjs': \nAccepted schemes are: tfstate://,tfstate+s3://,tfstate+http://,tfstate+https://"},
{args: []string{"scan", "--from", "://"}, expected: "Unable to parse from flag '://': \nAccepted schemes are: tfstate://,tfstate+s3://,tfstate+http://,tfstate+https://"},
{args: []string{"scan", "--from", "://test"}, expected: "Unable to parse from flag '://test': \nAccepted schemes are: tfstate://,tfstate+s3://,tfstate+http://,tfstate+https://"},
{args: []string{"scan", "--from", "tosdgjhgsdhgkjs://"}, expected: "Unable to parse from flag 'tosdgjhgsdhgkjs://': \nAccepted schemes are: tfstate://,tfstate+s3://,tfstate+http://,tfstate+https://"},
{args: []string{"scan", "--from", "terraform+foo+bar://test"}, expected: "Unable to parse from scheme 'terraform+foo+bar': \nAccepted schemes are: tfstate://,tfstate+s3://,tfstate+http://,tfstate+https://"},
{args: []string{"scan", "--from", "tosdgjhgsdhgkjs"}, expected: "Unable to parse from flag 'tosdgjhgsdhgkjs': \nAccepted schemes are: tfstate://,tfstate+s3://,tfstate+http://,tfstate+https://,tfstate+tfcloud://"},
{args: []string{"scan", "--from", "://"}, expected: "Unable to parse from flag '://': \nAccepted schemes are: tfstate://,tfstate+s3://,tfstate+http://,tfstate+https://,tfstate+tfcloud://"},
{args: []string{"scan", "--from", "://test"}, expected: "Unable to parse from flag '://test': \nAccepted schemes are: tfstate://,tfstate+s3://,tfstate+http://,tfstate+https://,tfstate+tfcloud://"},
{args: []string{"scan", "--from", "tosdgjhgsdhgkjs://"}, expected: "Unable to parse from flag 'tosdgjhgsdhgkjs://': \nAccepted schemes are: tfstate://,tfstate+s3://,tfstate+http://,tfstate+https://,tfstate+tfcloud://"},
{args: []string{"scan", "--from", "terraform+foo+bar://test"}, expected: "Unable to parse from scheme 'terraform+foo+bar': \nAccepted schemes are: tfstate://,tfstate+s3://,tfstate+http://,tfstate+https://,tfstate+tfcloud://"},
{args: []string{"scan", "--from", "unsupported://test"}, expected: "Unsupported IaC source 'unsupported': \nAccepted values are: tfstate"},
{args: []string{"scan", "--from", "tfstate+foobar://test"}, expected: "Unsupported IaC backend 'foobar': \nAccepted values are: s3,http,https"},
{args: []string{"scan", "--from", "tfstate:///tmp/test", "--from", "tfstate+toto://test"}, expected: "Unsupported IaC backend 'toto': \nAccepted values are: s3,http,https"},
{args: []string{"scan", "--from", "tfstate+foobar://test"}, expected: "Unsupported IaC backend 'foobar': \nAccepted values are: s3,http,https,tfcloud"},
{args: []string{"scan", "--from", "tfstate:///tmp/test", "--from", "tfstate+toto://test"}, expected: "Unsupported IaC backend 'toto': \nAccepted values are: s3,http,https,tfcloud"},
{args: []string{"scan", "--filter", "Type='test'"}, expected: "unable to parse filter expression: SyntaxError: Expected tRbracket, received: tUnknown"},
{args: []string{"scan", "--filter", "Type='test'", "--filter", "Type='test2'"}, expected: "Filter flag should be specified only once"},
}
Expand Down
33 changes: 23 additions & 10 deletions pkg/driftctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package pkg

import (
"fmt"
"time"

globaloutput "github.com/cloudskiff/driftctl/pkg/output"
"github.com/jmespath/go-jmespath"
"github.com/sirupsen/logrus"

Expand All @@ -17,15 +19,16 @@ import (
)

type ScanOptions struct {
Coverage bool
Detect bool
From []config.SupplierConfig
To string
Output output.OutputConfig
Filter *jmespath.JMESPath
Quiet bool
BackendOptions *backend.Options
StrictMode bool
Coverage bool
Detect bool
From []config.SupplierConfig
To string
Output output.OutputConfig
Filter *jmespath.JMESPath
Quiet bool
BackendOptions *backend.Options
StrictMode bool
DisableTelemetry bool
}

type DriftCTL struct {
Expand All @@ -36,10 +39,12 @@ type DriftCTL struct {
filter *jmespath.JMESPath
resourceFactory resource.ResourceFactory
strictMode bool
scanProgress globaloutput.Progress
iacProgress globaloutput.Progress
resourceSchemaRepository resource.SchemaRepositoryInterface
}

func NewDriftCTL(remoteSupplier resource.Supplier, iacSupplier resource.Supplier, alerter *alerter.Alerter, resFactory resource.ResourceFactory, opts *ScanOptions, resourceSchemaRepository resource.SchemaRepositoryInterface) *DriftCTL {
func NewDriftCTL(remoteSupplier resource.Supplier, iacSupplier resource.Supplier, alerter *alerter.Alerter, resFactory resource.ResourceFactory, opts *ScanOptions, scanProgress globaloutput.Progress, iacProgress globaloutput.Progress, resourceSchemaRepository resource.SchemaRepositoryInterface) *DriftCTL {
return &DriftCTL{
remoteSupplier,
iacSupplier,
Expand All @@ -48,11 +53,14 @@ func NewDriftCTL(remoteSupplier resource.Supplier, iacSupplier resource.Supplier
opts.Filter,
resFactory,
opts.StrictMode,
scanProgress,
iacProgress,
resourceSchemaRepository,
}
}

func (d DriftCTL) Run() (*analyser.Analysis, error) {
start := time.Now()
remoteResources, resourcesFromState, err := d.scan()
if err != nil {
return nil, err
Expand Down Expand Up @@ -108,6 +116,7 @@ func (d DriftCTL) Run() (*analyser.Analysis, error) {
driftIgnore := filter.NewDriftIgnore()

analysis, err := d.analyzer.Analyze(remoteResources, resourcesFromState, driftIgnore)
analysis.Duration = time.Since(start)

if err != nil {
return nil, err
Expand All @@ -133,12 +142,16 @@ func (d DriftCTL) Stop() {

func (d DriftCTL) scan() (remoteResources []resource.Resource, resourcesFromState []resource.Resource, err error) {
logrus.Info("Start reading IaC")
d.iacProgress.Start()
resourcesFromState, err = d.iacSupplier.Resources()
d.iacProgress.Stop()
if err != nil {
return nil, nil, err
}

logrus.Info("Start scanning cloud provider")
d.scanProgress.Start()
defer d.scanProgress.Stop()
remoteResources, err = d.remoteSupplier.Resources()
if err != nil {
return nil, nil, err
Expand Down
23 changes: 21 additions & 2 deletions pkg/driftctl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/cloudskiff/driftctl/pkg/alerter"
"github.com/cloudskiff/driftctl/pkg/analyser"
"github.com/cloudskiff/driftctl/pkg/filter"
"github.com/cloudskiff/driftctl/pkg/output"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/aws"
"github.com/cloudskiff/driftctl/pkg/resource/github"
Expand Down Expand Up @@ -72,11 +73,20 @@ func runTest(t *testing.T, cases TestCases) {
c.mocks(resourceFactory)
}

driftctl := pkg.NewDriftCTL(remoteSupplier, stateSupplier, testAlerter, resourceFactory, c.options, repo)
scanProgress := &output.MockProgress{}
scanProgress.On("Start").Return().Once()
scanProgress.On("Stop").Return().Once()

iacProgress := &output.MockProgress{}
iacProgress.On("Start").Return().Once()
iacProgress.On("Stop").Return().Once()

driftctl := pkg.NewDriftCTL(remoteSupplier, stateSupplier, testAlerter, resourceFactory, c.options, scanProgress, iacProgress, repo)

analysis, err := driftctl.Run()

c.assert(test.NewScanResult(t, analysis), err)
scanProgress.AssertExpectations(t)
})
}
}
Expand All @@ -93,6 +103,15 @@ func matchByAttributes(input, attrs map[string]interface{}) bool {
func TestDriftctlRun_BasicBehavior(t *testing.T) {

cases := TestCases{
{
name: "analysis duration is set",
stateResources: []resource.Resource{},
remoteResources: []resource.Resource{},
assert: func(result *test.ScanResult, err error) {
result.NotZero(result.Duration)
},
options: &pkg.ScanOptions{},
},
{
name: "infrastructure should be in sync",
stateResources: []resource.Resource{
Expand Down Expand Up @@ -296,7 +315,7 @@ func TestDriftctlRun_BasicBehavior(t *testing.T) {
},
assert: func(result *test.ScanResult, err error) {
result.AssertManagedCount(2)
result.AssertUnmanagedCount(1)
result.AssertUnmanagedCount(2)
result.AssertDeletedCount(0)
result.AssertDriftCountTotal(0)
},
Expand Down
8 changes: 8 additions & 0 deletions pkg/http/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package http

import "net/http"

// HTTPClient is an interface for http.Client type
type HTTPClient interface {
Do(req *http.Request) (*http.Response, error)
}
37 changes: 37 additions & 0 deletions pkg/http/mock_HTTPClient.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading