From d8fb20e07972adde85d97e7f7e0ebcce0dd0b5e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Christoph=20K=C3=BCster?= Date: Sun, 6 Sep 2020 20:44:47 +0200 Subject: [PATCH] Fix: Close Terraform AWS Provider binary (#116) * Fix: Shutdown provider binary when done The binary process kept running in the background after the awsweeper process terminated. Other features/fixes in this commit are included by bumping up the version of terradozer to v0.1.2: 1. Ignore non-existing resources (of type cty.Nil): This means, AWS instances that are in state TERMINATED, NAT gateways that are not available anymore, etc. are filtered out and not shown 2. Fix panic of nil pointer dereference when trying to destroy a resource that doesn't exist anymore (however, nil pointer shouldn't happen anymore because of 1.) 3. Offline mode: don't re-download Terraform provider binary if binary exists already in ~/.awsweeper/terraform-provider-aws_v2.68.0_x4 * Remove aws-sdk-go dependency Only using v2 now * Fix failing tests --- Makefile | 2 +- go.mod | 8 +- go.sum | 44 +++--- main.go | 61 ++++---- pkg/resource/filter_test.go | 50 ++++--- pkg/resource/list.go | 203 +++++++++++++++----------- pkg/resource/resource.go | 32 +---- pkg/resource/resource_test.go | 51 +++---- pkg/resource/select_test.go | 83 ++++++----- pkg/resource/supported.go | 227 +++++++++--------------------- pkg/resource/supported_test.go | 133 ----------------- test/acc_test.go | 2 +- test/cloudtrail_test.go | 12 +- test/cloudwatch_log_group_test.go | 13 +- test/db_instance_test.go | 12 +- test/ebs_snapshot_test.go | 17 ++- test/ecs_cluster_test.go | 12 +- test/elb_test.go | 16 ++- test/helper_test.go | 18 +-- test/iam_policy_test.go | 13 +- test/iam_user_test.go | 14 +- test/lambda_function_test.go | 16 ++- test/vpc_test.go | 18 ++- 23 files changed, 433 insertions(+), 624 deletions(-) delete mode 100644 pkg/resource/supported_test.go diff --git a/Makefile b/Makefile index cb3c01819..4fba8efaf 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ PKG_LIST := $(shell go list ./...) .PHONY: setup setup: ## Install build, test, and lint dependencies - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s v1.21.0 + curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s v1.29.0 go install github.com/golang/mock/mockgen curl -sSfL https://raw.githubusercontent.com/jckuester/go-acc/master/install.sh | sh -s v0.2.1 diff --git a/go.mod b/go.mod index 29d6b4b97..a5aa3b43b 100644 --- a/go.mod +++ b/go.mod @@ -4,14 +4,14 @@ go 1.14 require ( github.com/apex/log v1.1.2 - github.com/aws/aws-sdk-go v1.30.12 + github.com/aws/aws-sdk-go-v2 v0.23.0 github.com/fatih/color v1.9.0 - github.com/golang/mock v1.4.0 github.com/gruntwork-io/terratest v0.24.2 - github.com/jckuester/awsls v0.1.1 - github.com/jckuester/terradozer v0.1.2 + github.com/jckuester/awsls v0.5.2-0.20200903074820-ccd52c21d8fe + github.com/jckuester/terradozer v0.1.3 github.com/onsi/gomega v1.9.0 github.com/pkg/errors v0.9.1 + github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.5.1 github.com/zclconf/go-cty v1.4.0 gopkg.in/yaml.v2 v2.2.8 diff --git a/go.sum b/go.sum index 16316c4a2..6f4e13e1d 100644 --- a/go.sum +++ b/go.sum @@ -102,10 +102,13 @@ github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/aws/aws-sdk-go v1.23.8/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.30.12 h1:KrjyosZvkpJjcwMk0RNxMZewQ47v7+ZkbQDXjWsJMs8= github.com/aws/aws-sdk-go v1.30.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go-v2 v0.22.0 h1:mlixfS5HVzn7Sf3KVhjAIM2H3bB7uoTbLCtKHvteUfE= -github.com/aws/aws-sdk-go-v2 v0.22.0/go.mod h1:2LhT7UgHOXK3UXONKI5OMgIyoQL6zTAw/jwIeX6yqzw= +github.com/aws/aws-sdk-go v1.32.12 h1:l/djCeLI4ggBFWLlYUGTqkHraoLnVMubNlLXPdEtoYc= +github.com/aws/aws-sdk-go v1.32.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go-v2 v0.23.0 h1:+E1q1LLSfHSDn/DzOtdJOX+pLZE2HiNV2yO5AjZINwM= +github.com/aws/aws-sdk-go-v2 v0.23.0/go.mod h1:2LhT7UgHOXK3UXONKI5OMgIyoQL6zTAw/jwIeX6yqzw= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -152,6 +155,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/disneystreaming/go-ssmhelpers v0.2.1 h1:vdYa3NPnPgB4QaqA6yZ030DLaQqrmRrkyMZ/x8vFWag= +github.com/disneystreaming/go-ssmhelpers v0.2.1/go.mod h1:1DzuN6mMT/+m+944fuHkN+L+BH/O4nHQXJh7iv1t6t4= github.com/dnaeon/go-vcr v0.0.0-20180920040454-5637cf3d8a31/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= @@ -234,6 +239,8 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -299,9 +306,8 @@ github.com/hashicorp/go-immutable-radix v0.0.0-20180129170900-7f3cd4390caa/go.mo github.com/hashicorp/go-msgpack v0.5.4/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-plugin v1.0.1-0.20190610192547-a1bc61569a26/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= -github.com/hashicorp/go-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE= -github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= +github.com/hashicorp/go-plugin v1.3.0 h1:4d/wJojzvHV1I4i/rrjVaeuyxWrLzDE1mDCyDy8fXS8= +github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0= github.com/hashicorp/go-retryablehttp v0.5.2 h1:AoISa4P4IsW0/m4T6St8Yw38gTl5GtBAgfkhYh1xAz4= github.com/hashicorp/go-retryablehttp v0.5.2/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= @@ -309,7 +315,7 @@ github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhE github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= github.com/hashicorp/go-slug v0.4.1/go.mod h1:I5tq5Lv0E2xcNXNkmx7BSfzi1PsJ2cNjs3cC3LwyhK8= github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-tfe v0.3.27/go.mod h1:DVPSW2ogH+M9W1/i50ASgMht8cHP7NxxK0nrY9aFikQ= +github.com/hashicorp/go-tfe v0.8.1/go.mod h1:XAV72S4O1iP8BDaqiaPLmL2B4EE6almocnOn8E8stHc= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -329,8 +335,8 @@ github.com/hashicorp/hil v0.0.0-20190212112733-ab17b08d6590 h1:2yzhWGdgQUWZUCNK+ github.com/hashicorp/hil v0.0.0-20190212112733-ab17b08d6590/go.mod h1:n2TSygSNwsLJ76m8qFXTSc7beTb+auJxYdqrnoqwZWE= github.com/hashicorp/memberlist v0.1.0/go.mod h1:ncdBp14cuox2iFOq3kDiquKU6fqsTBc3W6JvZwjxxsE= github.com/hashicorp/serf v0.0.0-20160124182025-e4ec8cc423bb/go.mod h1:h/Ru6tmZazX7WO/GDmwdpS975F019L4t5ng5IgwbNrE= -github.com/hashicorp/terraform v0.12.25 h1:4RCbJeJvBTl+t9SDa3xqEU9G9sH5khqjlabr/89bshk= -github.com/hashicorp/terraform v0.12.25/go.mod h1:B9VZ/cn0j1wpi16bdgLBCw5D5wNOqM8DVP0al92nPXc= +github.com/hashicorp/terraform v0.12.28 h1:mBA+A9dvMXk1xDpflKEP5mL/KOD0sXap+M4F4Vlgnvc= +github.com/hashicorp/terraform v0.12.28/go.mod h1:CBxNAiTW0pLap44/3GU4j7cYE2bMhkKZNlHPcr4P55U= github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7 h1:Pc5TCv9mbxFN6UVX0LH6CpQrdTM5YjbVI2w15237Pjk= github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7/go.mod h1:p+ivJws3dpqbp1iP84+npOyAmTTOLMgCzrXd3GSdn/A= github.com/hashicorp/terraform-svchost v0.0.0-20191011084731-65d371908596 h1:hjyO2JsNZUKT1ym+FAdlBEkGPevazYsmVgIMw7dVELg= @@ -344,12 +350,12 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jckuester/awsls v0.1.1 h1:mGiVUZ8b/ZSeweMyxQfBg8Ri28+NabObKuUv6+52lqg= -github.com/jckuester/awsls v0.1.1/go.mod h1:QSYGMRWZLtSibkUbHmjXKov9pogJ8gD2OSFqQanOVHk= -github.com/jckuester/terradozer v0.1.0 h1:dsZHaY1vH0XNDDIAensa4IkoL7+WKUqDpEu7xl5hg/E= -github.com/jckuester/terradozer v0.1.0/go.mod h1:ZHLoxb3vdsXGCmxeUb7vPy/T6yPzecD0rn1NWdH9aww= -github.com/jckuester/terradozer v0.1.2 h1:E4oN3pk9aVTJgzmVySMiMr/dEwd6s6LqNTTDpaRh/mc= -github.com/jckuester/terradozer v0.1.2/go.mod h1:ZHLoxb3vdsXGCmxeUb7vPy/T6yPzecD0rn1NWdH9aww= +github.com/jckuester/awsls v0.5.2-0.20200903074820-ccd52c21d8fe h1:g8Eza2qnJHrmjLIjySB5WU8WIzrg+is9T/QlYRoIIdM= +github.com/jckuester/awsls v0.5.2-0.20200903074820-ccd52c21d8fe/go.mod h1:Lcu9NaT8/S86wH4MQ4d7GNUuvxml97XEQuwIQxSY+Uo= +github.com/jckuester/terradozer v0.1.3 h1:xrRxr+L58QAVz5Kwq2fyWCNiK1NWOuKo8g5Q2664WZ4= +github.com/jckuester/terradozer v0.1.3/go.mod h1:ER3EJojZmO2u6lfcdgnmC+Nrg/TV2T2bacY5FZpqgks= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -543,6 +549,7 @@ github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzu github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -641,6 +648,7 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -665,6 +673,8 @@ golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -686,7 +696,6 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -769,6 +778,7 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -780,7 +790,7 @@ google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBr google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f h1:2wh8dWY8959cBGQvk1RD+/eQBgRYYDaZ+hT0/zsARoA= google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -789,6 +799,8 @@ google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= diff --git a/main.go b/main.go index 6fef56e2e..4320ae221 100644 --- a/main.go +++ b/main.go @@ -1,12 +1,6 @@ package main -//go:generate mockgen -package mocks -destination pkg/resource/mocks/autoscaling.go -source=$GOPATH/pkg/mod/github.com/aws/aws-sdk-go@v1.30.12/service/autoscaling/autoscalingiface/interface.go -//go:generate mockgen -package mocks -destination pkg/resource/mocks/ec2.go -source=$GOPATH/pkg/mod/github.com/aws/aws-sdk-go@v1.30.12/service/ec2/ec2iface/interface.go -//go:generate mockgen -package mocks -destination pkg/resource/mocks/sts.go -source=$GOPATH/pkg/mod/github.com/aws/aws-sdk-go@v1.30.12/service/sts/stsiface/interface.go -//go:generate mockgen -package mocks -destination pkg/resource/mocks/rds.go -source=$GOPATH/pkg/mod/github.com/aws/aws-sdk-go@v1.30.12/service/rds/rdsiface/interface.go - import ( - "flag" "fmt" "io/ioutil" stdlog "log" @@ -16,14 +10,12 @@ import ( "github.com/apex/log" "github.com/apex/log/handlers/cli" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" "github.com/fatih/color" - awsls "github.com/jckuester/awsls/aws" + "github.com/jckuester/awsls/util" "github.com/jckuester/awsweeper/internal" "github.com/jckuester/awsweeper/pkg/resource" - "github.com/jckuester/terradozer/pkg/provider" terradozerRes "github.com/jckuester/terradozer/pkg/resource" + flag "github.com/spf13/pflag" ) func main() { @@ -50,8 +42,8 @@ func mainExitCode() int { flags.StringVar(&outputType, "output", "string", "The type of output result (String, JSON or YAML)") flags.BoolVar(&dryRun, "dry-run", false, "Don't delete anything, just show what would be deleted") flags.BoolVar(&logDebug, "debug", false, "Enable debug logging") - flags.StringVar(&profile, "profile", "", "The AWS named profile to use as credential") - flags.StringVar(®ion, "region", "", "The region to delete resources in") + flags.StringVarP(&profile, "profile", "p", "", "The AWS profile for the account to delete resources in") + flags.StringVarP(®ion, "region", "r", "", "The region to delete resources in") flags.IntVar(¶llel, "parallel", 10, "Limit the number of concurrent delete operations") flags.BoolVar(&version, "version", false, "Show application version") flags.BoolVar(&force, "force", false, "Delete without asking for confirmation") @@ -112,17 +104,20 @@ func mainExitCode() int { return 1 } + var profiles []string + var regions []string + if profile != "" { - err := os.Setenv("AWS_PROFILE", profile) - if err != nil { - log.WithError(err).Error("failed to set AWS profile") + profiles = []string{profile} + } else { + env, ok := os.LookupEnv("AWS_PROFILE") + if ok { + profiles = []string{env} } } + if region != "" { - err := os.Setenv("AWS_DEFAULT_REGION", region) - if err != nil { - log.WithError(err).Error("failed to set AWS region") - } + regions = []string{region} } timeoutDuration, err := time.ParseDuration(timeout) @@ -131,30 +126,34 @@ func mainExitCode() int { return 1 } - provider, err := provider.Init("aws", "~/.awsweeper", timeoutDuration) + clients, err := util.NewAWSClientPool(profiles, regions) if err != nil { - log.WithError(err).Error("failed to initialize Terraform AWS Providers") + fmt.Fprint(os.Stderr, color.RedString("\nError: %s\n", err)) + return 1 } - // TODO remove resource.NewAWS(sess) with awsls.NewClient() - sess := session.Must(session.NewSessionWithOptions(session.Options{ - Config: aws.Config{Region: ®ion}, - SharedConfigState: session.SharedConfigEnable, - Profile: profile, - })) - - client := resource.NewAWS(sess) + clientKeys := make([]util.AWSClientKey, 0, len(clients)) + for k := range clients { + clientKeys = append(clientKeys, k) + } - awsClient, err := awsls.NewClient() + // initialize a Terraform AWS provider for each AWS client with a matching config + providers, err := util.NewProviderPool(clientKeys, "2.68.0", "~/.awsweeper", timeoutDuration) if err != nil { fmt.Fprint(os.Stderr, color.RedString("\nError: %s\n", err)) return 1 } + defer func() { + for _, p := range providers { + _ = p.Close() + } + }() + internal.LogTitle("showing resources that would be deleted (dry run)") - resources := resource.List(filter, client, awsClient, provider, outputType) + resources := resource.List(filter, clients, providers, outputType) if len(resources) == 0 { internal.LogTitle("no resources found to delete") diff --git a/pkg/resource/filter_test.go b/pkg/resource/filter_test.go index 724bb697b..55d66109b 100644 --- a/pkg/resource/filter_test.go +++ b/pkg/resource/filter_test.go @@ -5,12 +5,10 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws" - + "github.com/aws/aws-sdk-go-v2/aws" "github.com/jckuester/awsweeper/pkg/resource" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/yaml.v2" ) @@ -27,7 +25,7 @@ func TestFilter_Validate(t *testing.T) { { name: "unsupported type", f: resource.Filter{ - resource.Instance: {}, + "aws_instance": {}, "not_supported_type": {}, }, wantErr: "unsupported resource type: not_supported_type", @@ -37,7 +35,7 @@ func TestFilter_Validate(t *testing.T) { f: resource.Filter{ "aws_iam_role": {}, "aws_security_group": {}, - resource.Instance: {}, + "aws_instance": {}, "aws_vpc": {}, }, }, @@ -46,7 +44,7 @@ func TestFilter_Validate(t *testing.T) { f: resource.Filter{ "aws_iam_role": {}, "aws_security_group": {}, - resource.Instance: {}, + "aws_instance": {}, "aws_glue_job": {}, }, }, @@ -73,10 +71,10 @@ func TestFilter_Types(t *testing.T) { { name: "dependency order", f: resource.Filter{ - "aws_vpc": {}, - resource.Instance: {}, + "aws_vpc": {}, + "aws_instance": {}, }, - want: []string{resource.Instance, "aws_vpc"}, + want: []string{"aws_instance", "aws_vpc"}, }, { name: "dependency order not specified", @@ -109,23 +107,23 @@ func Test_ParseFile(t *testing.T) { var cfg resource.Filter err := yaml.UnmarshalStrict(input, &cfg) require.NoError(t, err) - require.NotNil(t, cfg[resource.Instance]) - require.Len(t, cfg[resource.Instance], 2) - require.NotNil(t, cfg[resource.Instance][0].ID) - assert.Equal(t, "^foo.*", cfg[resource.Instance][0].ID.Pattern) - assert.True(t, cfg[resource.Instance][0].ID.Negate) - require.NotNil(t, cfg[resource.Instance][0].Created.Before) - assert.True(t, cfg[resource.Instance][0].Created.Before.Before(time.Now().UTC().AddDate(0, 0, -4))) - assert.True(t, cfg[resource.Instance][0].Created.Before.After(time.Now().UTC().AddDate(0, 0, -6))) - require.NotNil(t, cfg[resource.Instance][0].Created.After) - assert.Equal(t, resource.CreatedTime{Time: time.Date(2018, 10, 28, 12, 28, 39, 0000, time.UTC)}, *cfg[resource.Instance][0].Created.After) - require.NotNil(t, cfg[resource.Instance][1].ID) - assert.Equal(t, "^foo.*", cfg[resource.Instance][1].ID.Pattern) - assert.False(t, cfg[resource.Instance][1].ID.Negate) - require.NotNil(t, cfg[resource.Instance][1].Created.Before) - assert.True(t, cfg[resource.Instance][1].Created.Before.Before(time.Now().UTC().Add(-22*time.Hour))) - assert.True(t, cfg[resource.Instance][1].Created.Before.After(time.Now().UTC().Add(-24*time.Hour))) - require.Nil(t, cfg[resource.Instance][1].Created.After) + require.NotNil(t, cfg["aws_instance"]) + require.Len(t, cfg["aws_instance"], 2) + require.NotNil(t, cfg["aws_instance"][0].ID) + assert.Equal(t, "^foo.*", cfg["aws_instance"][0].ID.Pattern) + assert.True(t, cfg["aws_instance"][0].ID.Negate) + require.NotNil(t, cfg["aws_instance"][0].Created.Before) + assert.True(t, cfg["aws_instance"][0].Created.Before.Before(time.Now().UTC().AddDate(0, 0, -4))) + assert.True(t, cfg["aws_instance"][0].Created.Before.After(time.Now().UTC().AddDate(0, 0, -6))) + require.NotNil(t, cfg["aws_instance"][0].Created.After) + assert.Equal(t, resource.CreatedTime{Time: time.Date(2018, 10, 28, 12, 28, 39, 0000, time.UTC)}, *cfg["aws_instance"][0].Created.After) + require.NotNil(t, cfg["aws_instance"][1].ID) + assert.Equal(t, "^foo.*", cfg["aws_instance"][1].ID.Pattern) + assert.False(t, cfg["aws_instance"][1].ID.Negate) + require.NotNil(t, cfg["aws_instance"][1].Created.Before) + assert.True(t, cfg["aws_instance"][1].Created.Before.Before(time.Now().UTC().Add(-22*time.Hour))) + assert.True(t, cfg["aws_instance"][1].Created.Before.After(time.Now().UTC().Add(-24*time.Hour))) + require.Nil(t, cfg["aws_instance"][1].Created.After) } func TestTypeFilter_MatchTagged(t *testing.T) { diff --git a/pkg/resource/list.go b/pkg/resource/list.go index b647bd0e1..fc61dde3a 100644 --- a/pkg/resource/list.go +++ b/pkg/resource/list.go @@ -1,6 +1,7 @@ package resource import ( + "context" "encoding/json" "fmt" "os" @@ -8,79 +9,99 @@ import ( "strings" "github.com/apex/log" - "github.com/aws/aws-sdk-go/service/efs" - "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go-v2/service/efs" + "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/fatih/color" awsls "github.com/jckuester/awsls/aws" awslsRes "github.com/jckuester/awsls/resource" + "github.com/jckuester/awsls/util" "github.com/jckuester/terradozer/pkg/provider" terradozerRes "github.com/jckuester/terradozer/pkg/resource" "github.com/zclconf/go-cty/cty" "gopkg.in/yaml.v2" ) -func List(filter *Filter, client *AWS, awsClient *awsls.Client, - provider *provider.TerraformProvider, outputType string) []terradozerRes.DestroyableResource { +func List(filter *Filter, clients map[util.AWSClientKey]awsls.Client, + providers map[util.AWSClientKey]provider.TerraformProvider, outputType string) []terradozerRes.DestroyableResource { var destroyableRes []terradozerRes.DestroyableResource for _, rType := range filter.Types() { if SupportedResourceType(rType) { - rawResources, err := client.RawResources(rType) - if err != nil { - log.WithError(err).Fatal("failed to get raw resources") - } + for key, client := range clients { + err := client.SetAccountID() + if err != nil { + log.WithError(err).Fatal("failed to set account ID") + continue + } - deletableResources, err := DeletableResources(rType, rawResources) - if err != nil { - log.WithError(err).Fatal("failed to convert raw resources into deletable resources") - } + rawResources, err := AWS(client).RawResources(rType) + if err != nil { + log.WithError(err).Fatal("failed to get raw resources") + } + + deletableResources, err := DeletableResources(rType, rawResources, client) + if err != nil { + log.WithError(err).Fatal("failed to convert raw resources into deletable resources") + } + + resourcesWithStates := awslsRes.GetStates(deletableResources, providers) - resourcesWithStates := awslsRes.GetStates(deletableResources, provider) + filteredRes := filter.Apply(resourcesWithStates) + print(filteredRes, outputType) - filteredRes := filter.Apply(resourcesWithStates) - print(filteredRes, outputType) + p := providers[key] - for _, r := range filteredRes { - destroyableRes = append(destroyableRes, terradozerRes.NewWithState(r.Type, r.ID, provider, r.State())) + for _, r := range filteredRes { + destroyableRes = append(destroyableRes, terradozerRes.NewWithState(r.Type, r.ID, &p, r.State())) + } } } else { - resources, err := awsls.ListResourcesByType(awsClient, rType) - if err != nil { - log.WithError(err).Fatal("failed to list awsls supported resources") + for key, client := range clients { + err := client.SetAccountID() + if err != nil { + log.WithError(err).Fatal("failed to set account ID") + continue + } - continue - } + resources, err := awsls.ListResourcesByType(&client, rType) + if err != nil { + log.WithError(err).Fatal("failed to list awsls supported resources") + continue + } - resourcesWithStates := awslsRes.GetStates(resources, provider) + resourcesWithStates := awslsRes.GetStates(resources, providers) - filteredRes := filter.Apply(resourcesWithStates) - print(filteredRes, outputType) + filteredRes := filter.Apply(resourcesWithStates) + print(filteredRes, outputType) - switch rType { - case "aws_iam_user": - attachedPolicies := getAttachedUserPolicies(filteredRes, client, provider) - print(attachedPolicies, outputType) + p := providers[key] - inlinePolicies := getInlineUserPolicies(filteredRes, client, provider) - print(inlinePolicies, outputType) + switch rType { + case "aws_iam_user": + attachedPolicies := getAttachedUserPolicies(filteredRes, client, &p) + print(attachedPolicies, outputType) - filteredRes = append(filteredRes, attachedPolicies...) - filteredRes = append(filteredRes, inlinePolicies...) - case "aws_iam_policy": - policyAttachments := getPolicyAttachments(filteredRes, provider) - print(policyAttachments, outputType) + inlinePolicies := getInlineUserPolicies(filteredRes, client, &p) + print(inlinePolicies, outputType) - filteredRes = append(filteredRes, policyAttachments...) + filteredRes = append(filteredRes, attachedPolicies...) + filteredRes = append(filteredRes, inlinePolicies...) + case "aws_iam_policy": + policyAttachments := getPolicyAttachments(filteredRes, &p) + print(policyAttachments, outputType) - case "aws_efs_file_system": - mountTargets := getEfsMountTargets(filteredRes, client, provider) - print(mountTargets, outputType) + filteredRes = append(filteredRes, policyAttachments...) - filteredRes = append(filteredRes, mountTargets...) - } + case "aws_efs_file_system": + mountTargets := getEfsMountTargets(filteredRes, client, &p) + print(mountTargets, outputType) + + filteredRes = append(filteredRes, mountTargets...) + } - for _, r := range filteredRes { - destroyableRes = append(destroyableRes, terradozerRes.NewWithState(r.Type, r.ID, provider, r.State())) + for _, r := range filteredRes { + destroyableRes = append(destroyableRes, terradozerRes.NewWithState(r.Type, r.ID, &p, r.State())) + } } } } @@ -88,71 +109,83 @@ func List(filter *Filter, client *AWS, awsClient *awsls.Client, return destroyableRes } -func getAttachedUserPolicies(users []awsls.Resource, client *AWS, +func getAttachedUserPolicies(users []awsls.Resource, client awsls.Client, provider *provider.TerraformProvider) []awsls.Resource { var result []awsls.Resource for _, user := range users { - attachedPolicies, err := client.ListAttachedUserPolicies(&iam.ListAttachedUserPoliciesInput{ + req := client.Iamconn.ListAttachedUserPoliciesRequest(&iam.ListAttachedUserPoliciesInput{ UserName: &user.ID, }) - if err != nil { - fmt.Fprint(os.Stderr, color.RedString("Error: %s\n", err)) - continue - } - for _, attachedPolicy := range attachedPolicies.AttachedPolicies { - r := awsls.Resource{ - Type: "aws_iam_user_policy_attachment", - ID: *attachedPolicy.PolicyArn, - } + pg := iam.NewListAttachedUserPoliciesPaginator(req) + for pg.Next(context.Background()) { + page := pg.CurrentPage() - r.UpdatableResource = terradozerRes.New(r.Type, r.ID, map[string]cty.Value{ - "user": cty.StringVal(user.ID), - "policy_arn": cty.StringVal(*attachedPolicy.PolicyArn), - }, provider) + for _, attachedPolicy := range page.AttachedPolicies { + r := awsls.Resource{ + Type: "aws_iam_user_policy_attachment", + ID: *attachedPolicy.PolicyArn, + } - err = r.UpdateState() - if err != nil { - fmt.Fprint(os.Stderr, color.RedString("Error: %s\n", err)) - continue + r.UpdatableResource = terradozerRes.New(r.Type, r.ID, map[string]cty.Value{ + "user": cty.StringVal(user.ID), + "policy_arn": cty.StringVal(*attachedPolicy.PolicyArn), + }, provider) + + err := r.UpdateState() + if err != nil { + fmt.Fprint(os.Stderr, color.RedString("Error: %s\n", err)) + continue + } + + result = append(result, r) } + } - result = append(result, r) + if err := pg.Err(); err != nil { + fmt.Fprint(os.Stderr, color.RedString("Error: %s\n", err)) + continue } } return result } -func getInlineUserPolicies(users []awsls.Resource, client *AWS, +func getInlineUserPolicies(users []awsls.Resource, client awsls.Client, provider *provider.TerraformProvider) []awsls.Resource { var result []awsls.Resource for _, user := range users { - inlinePolicies, err := client.ListUserPolicies(&iam.ListUserPoliciesInput{ + req := client.Iamconn.ListUserPoliciesRequest(&iam.ListUserPoliciesInput{ UserName: &user.ID, }) - if err != nil { - fmt.Fprint(os.Stderr, color.RedString("Error: %s\n", err)) - continue - } - for _, inlinePolicy := range inlinePolicies.PolicyNames { - r := awsls.Resource{ - Type: "aws_iam_user_policy", - ID: user.ID + ":" + *inlinePolicy, - } + pg := iam.NewListUserPoliciesPaginator(req) + for pg.Next(context.Background()) { + page := pg.CurrentPage() - r.UpdatableResource = terradozerRes.New(r.Type, r.ID, nil, provider) + for _, inlinePolicy := range page.PolicyNames { + r := awsls.Resource{ + Type: "aws_iam_user_policy", + ID: user.ID + ":" + inlinePolicy, + } - err = r.UpdateState() - if err != nil { - fmt.Fprint(os.Stderr, color.RedString("Error: %s\n", err)) - continue + r.UpdatableResource = terradozerRes.New(r.Type, r.ID, nil, provider) + + err := r.UpdateState() + if err != nil { + fmt.Fprint(os.Stderr, color.RedString("Error: %s\n", err)) + continue + } + + result = append(result, r) } + } - result = append(result, r) + if err := pg.Err(); err != nil { + fmt.Fprint(os.Stderr, color.RedString("Error: %s\n", err)) + continue } } @@ -191,21 +224,23 @@ func getPolicyAttachments(policies []awsls.Resource, provider *provider.Terrafor return result } -func getEfsMountTargets(efsFileSystems []awsls.Resource, client *AWS, +func getEfsMountTargets(efsFileSystems []awsls.Resource, client awsls.Client, provider *provider.TerraformProvider) []awsls.Resource { var result []awsls.Resource for _, fs := range efsFileSystems { - mountTargets, err := client.DescribeMountTargets(&efs.DescribeMountTargetsInput{ + // TODO result is paginated, but there is no paginator API function + req := client.Efsconn.DescribeMountTargetsRequest(&efs.DescribeMountTargetsInput{ FileSystemId: &fs.ID, }) + resp, err := req.Send(context.Background()) if err != nil { fmt.Fprint(os.Stderr, color.RedString("Error: %s\n", err)) continue } - for _, mountTarget := range mountTargets.MountTargets { + for _, mountTarget := range resp.MountTargets { r := awsls.Resource{ Type: "aws_efs_mount_target", ID: *mountTarget.MountTargetId, diff --git a/pkg/resource/resource.go b/pkg/resource/resource.go index 2733550c7..2afcaa1c7 100644 --- a/pkg/resource/resource.go +++ b/pkg/resource/resource.go @@ -5,15 +5,12 @@ import ( "time" awsls "github.com/jckuester/awsls/aws" - - "github.com/apex/log" - "github.com/pkg/errors" ) // Resources converts given raw resources for a given resource type // into a format that can be deleted by the Terraform API. -func DeletableResources(resType string, resources interface{}) ([]awsls.Resource, error) { +func DeletableResources(resType string, resources interface{}, client awsls.Client) ([]awsls.Resource, error) { var deletableResources []awsls.Resource reflectResources := reflect.ValueOf(resources) @@ -28,11 +25,6 @@ func DeletableResources(resType string, resources interface{}) ([]awsls.Resource return nil, errors.Wrapf(err, "Field with delete ID required for deleting resource") } - tags, err := findTags(reflectResources.Index(i)) - if err != nil { - log.WithError(err).Debug("failed to find tags") - } - var creationTime *time.Time creationTimeField, err := findField(creationTimeFieldNames, reflect.Indirect(reflectResources.Index(i))) if err == nil { @@ -53,8 +45,10 @@ func DeletableResources(resType string, resources interface{}) ([]awsls.Resource deletableResources = append(deletableResources, awsls.Resource{ Type: resType, ID: deleteIDField.Elem().String(), - Tags: tags, CreatedAt: creationTime, + Region: client.Region, + Profile: client.Profile, + AccountID: client.AccountID, }) } @@ -79,21 +73,3 @@ func findField(names []string, v reflect.Value) (reflect.Value, error) { } return reflect.Value{}, errors.Errorf("Fields not found: %s", names) } - -// findTags finds findTags via reflection in the describe output. -func findTags(res reflect.Value) (map[string]string, error) { - tags := map[string]string{} - - ts, err := findField(tagFieldNames, reflect.Indirect(res)) - if err != nil { - return nil, errors.Wrap(err, "No tags found") - } - - for i := 0; i < ts.Len(); i++ { - key := reflect.Indirect(ts.Index(i)).FieldByName("Key").Elem() - value := reflect.Indirect(ts.Index(i)).FieldByName("Value").Elem() - tags[key.String()] = value.String() - } - - return tags, nil -} diff --git a/pkg/resource/resource_test.go b/pkg/resource/resource_test.go index a8481137d..42e32ac1f 100644 --- a/pkg/resource/resource_test.go +++ b/pkg/resource/resource_test.go @@ -4,55 +4,42 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ec2" + awsls "github.com/jckuester/awsls/aws" - "github.com/aws/aws-sdk-go/service/autoscaling" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/autoscaling" + "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/jckuester/awsweeper/pkg/resource" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func TestDeletableResources(t *testing.T) { +var ( + testImageId = "test-ami" + testAutoscalingGroupName = "test-auto-scaling-group" +) + +func TestDeletableResources_CreationDateIsTypeTime(t *testing.T) { // given - rawResources := []*autoscaling.Group{ + testCreationDate := aws.Time(time.Date(2018, 11, 17, 5, 0, 0, 0, time.UTC)) + rawResources := []*autoscaling.AutoScalingGroup{ { AutoScalingGroupName: &testAutoscalingGroupName, - Tags: convertTags(testTags), + CreatedTime: testCreationDate, }, } // when - res, err := resource.DeletableResources(resource.AutoscalingGroup, rawResources) + res, err := resource.DeletableResources(resource.AutoscalingGroup, rawResources, awsls.Client{}) require.NoError(t, err) - - // then require.Len(t, res, 1) - require.Equal(t, testAutoscalingGroupName, res[0].ID) - require.Equal(t, testTags, res[0].Tags) -} - -func TestDeletableResources_Created(t *testing.T) { - // given - testLaunchTime := aws.Time(time.Date(2018, 11, 17, 5, 0, 0, 0, time.UTC)) - rawResources := []*ec2.Instance{ - { - InstanceId: &testInstanceID, - LaunchTime: testLaunchTime, - }, - } - - // when - res, err := resource.DeletableResources(resource.Instance, rawResources) - require.NoError(t, err) // then - require.Len(t, res, 1) - require.Equal(t, testInstanceID, res[0].ID) - require.Equal(t, testLaunchTime, res[0].CreatedAt) - + assert.Equal(t, testAutoscalingGroupName, res[0].ID) + assert.Equal(t, testCreationDate, res[0].CreatedAt) } -func TestDeletableResources_CreatedFieldIsTypeString(t *testing.T) { +func TestDeletableResources_CreationDateIsTypeString(t *testing.T) { // given testCreationDate := "2018-12-16T19:40:28.000Z" rawResources := []*ec2.Image{ @@ -63,7 +50,7 @@ func TestDeletableResources_CreatedFieldIsTypeString(t *testing.T) { } // when - res, err := resource.DeletableResources(resource.Ami, rawResources) + res, err := resource.DeletableResources(resource.Ami, rawResources, awsls.Client{}) require.NoError(t, err) // then diff --git a/pkg/resource/select_test.go b/pkg/resource/select_test.go index bfc9e371f..3f2990df7 100644 --- a/pkg/resource/select_test.go +++ b/pkg/resource/select_test.go @@ -5,14 +5,13 @@ import ( "testing" "time" - "github.com/zclconf/go-cty/cty" - - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" awsls "github.com/jckuester/awsls/aws" "github.com/jckuester/awsweeper/pkg/resource" terradozerRes "github.com/jckuester/terradozer/pkg/resource" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/zclconf/go-cty/cty" ) func TestYamlFilter_Apply_EmptyConfig(t *testing.T) { @@ -21,7 +20,7 @@ func TestYamlFilter_Apply_EmptyConfig(t *testing.T) { res := []awsls.Resource{ { - Type: resource.Instance, + Type: "aws_instance", ID: "foo", }, } @@ -36,11 +35,11 @@ func TestYamlFilter_Apply_EmptyConfig(t *testing.T) { func TestYamlFilter_Apply_FilterAll(t *testing.T) { //given f := &resource.Filter{ - resource.Instance: {}, + "aws_instance": {}, } res := []awsls.Resource{ { - Type: resource.Instance, + Type: "aws_instance", ID: "foo", }, } @@ -56,7 +55,7 @@ func TestYamlFilter_Apply_FilterAll(t *testing.T) { func TestYamlFilter_Apply_FilterByID(t *testing.T) { //given f := &resource.Filter{ - resource.Instance: { + "aws_instance": { { ID: &resource.StringFilter{Pattern: "^select"}, }, @@ -66,11 +65,11 @@ func TestYamlFilter_Apply_FilterByID(t *testing.T) { // when res := []awsls.Resource{ { - Type: resource.Instance, + Type: "aws_instance", ID: "select-this", }, { - Type: resource.Instance, + Type: "aws_instance", ID: "do-not-select-this", }, } @@ -85,7 +84,7 @@ func TestYamlFilter_Apply_FilterByID(t *testing.T) { func TestYamlFilter_Apply_FilterByTag(t *testing.T) { //given f := &resource.Filter{ - resource.Instance: { + "aws_instance": { { Tags: map[string]resource.StringFilter{ "foo": {Pattern: "^bar"}, @@ -96,21 +95,21 @@ func TestYamlFilter_Apply_FilterByTag(t *testing.T) { res := []awsls.Resource{ { - Type: resource.Instance, + Type: "aws_instance", ID: "select-this", Tags: map[string]string{ "foo": "bar-bab", }, }, { - Type: resource.Instance, + Type: "aws_instance", ID: "do-not-select-this", Tags: map[string]string{ "foo": "blub", }, }, { - Type: resource.Instance, + Type: "aws_instance", ID: "do-not-select-this-either", }, } @@ -126,7 +125,7 @@ func TestYamlFilter_Apply_FilterByTag(t *testing.T) { func TestYamlFilter_Apply_FilterByMultipleTags(t *testing.T) { //given f := &resource.Filter{ - resource.Instance: { + "aws_instance": { { Tags: map[string]resource.StringFilter{ "foo": {Pattern: "^bar"}, @@ -138,7 +137,7 @@ func TestYamlFilter_Apply_FilterByMultipleTags(t *testing.T) { res := []awsls.Resource{ { - Type: resource.Instance, + Type: "aws_instance", ID: "select-this", Tags: map[string]string{ "foo": "bar-bab", @@ -146,7 +145,7 @@ func TestYamlFilter_Apply_FilterByMultipleTags(t *testing.T) { }, }, { - Type: resource.Instance, + Type: "aws_instance", ID: "do-not-select-this", Tags: map[string]string{ "foo": "bar-bab", @@ -165,7 +164,7 @@ func TestYamlFilter_Apply_FilterByMultipleTags(t *testing.T) { func TestYamlFilter_Apply_FilterByIDandTag(t *testing.T) { //given f := &resource.Filter{ - resource.Instance: { + "aws_instance": { { ID: &resource.StringFilter{Pattern: "^foo"}, Tags: map[string]resource.StringFilter{ @@ -177,21 +176,21 @@ func TestYamlFilter_Apply_FilterByIDandTag(t *testing.T) { res := []awsls.Resource{ { - Type: resource.Instance, + Type: "aws_instance", ID: "foo", Tags: map[string]string{ "foo": "bar", }, }, { - Type: resource.Instance, + Type: "aws_instance", ID: "do-not-select-this", Tags: map[string]string{ "foo": "bar", }, }, { - Type: resource.Instance, + Type: "aws_instance", ID: "this-neither", }, } @@ -207,7 +206,7 @@ func TestYamlFilter_Apply_FilterByIDandTag(t *testing.T) { func TestYamlFilter_Apply_Created(t *testing.T) { //given f := &resource.Filter{ - resource.Instance: { + "aws_instance": { { Created: &resource.Created{ After: &resource.CreatedTime{Time: time.Date(2018, 11, 17, 0, 0, 0, 0, time.UTC)}, @@ -219,27 +218,27 @@ func TestYamlFilter_Apply_Created(t *testing.T) { res := []awsls.Resource{ { - Type: resource.Instance, + Type: "aws_instance", ID: "foo", CreatedAt: aws.Time(time.Date(2018, 11, 17, 5, 0, 0, 0, time.UTC)), }, { - Type: resource.Instance, + Type: "aws_instance", ID: "do-not-select-this1", CreatedAt: aws.Time(time.Date(2018, 11, 17, 0, 0, 0, 0, time.UTC)), }, { - Type: resource.Instance, + Type: "aws_instance", ID: "do-not-select-this2", CreatedAt: aws.Time(time.Date(2018, 11, 20, 0, 0, 0, 0, time.UTC)), }, { - Type: resource.Instance, + Type: "aws_instance", ID: "do-not-select-this3", CreatedAt: aws.Time(time.Date(2018, 11, 22, 0, 0, 0, 0, time.UTC)), }, { - Type: resource.Instance, + Type: "aws_instance", ID: "do-not-select-this2", }, } @@ -255,7 +254,7 @@ func TestYamlFilter_Apply_Created(t *testing.T) { func TestYamlFilter_Apply_CreatedBefore(t *testing.T) { //given f := &resource.Filter{ - resource.Instance: { + "aws_instance": { { Created: &resource.Created{ Before: &resource.CreatedTime{Time: time.Date(2018, 11, 20, 0, 0, 0, 0, time.UTC)}, @@ -266,17 +265,17 @@ func TestYamlFilter_Apply_CreatedBefore(t *testing.T) { res := []awsls.Resource{ { - Type: resource.Instance, + Type: "aws_instance", ID: "foo", CreatedAt: aws.Time(time.Date(2018, 11, 17, 5, 0, 0, 0, time.UTC)), }, { - Type: resource.Instance, + Type: "aws_instance", ID: "do-not-select-this", CreatedAt: aws.Time(time.Date(2018, 11, 22, 0, 0, 0, 0, time.UTC)), }, { - Type: resource.Instance, + Type: "aws_instance", ID: "do-not-select-this2", }, } @@ -292,7 +291,7 @@ func TestYamlFilter_Apply_CreatedBefore(t *testing.T) { func TestYamlFilter_Apply_CreatedAfter(t *testing.T) { //given f := &resource.Filter{ - resource.Instance: { + "aws_instance": { { Created: &resource.Created{ After: &resource.CreatedTime{Time: time.Date(2018, 11, 20, 0, 0, 0, 0, time.UTC)}, @@ -303,17 +302,17 @@ func TestYamlFilter_Apply_CreatedAfter(t *testing.T) { res := []awsls.Resource{ { - Type: resource.Instance, + Type: "aws_instance", ID: "foo", CreatedAt: aws.Time(time.Date(2018, 11, 22, 5, 0, 0, 0, time.UTC)), }, { - Type: resource.Instance, + Type: "aws_instance", ID: "do-not-select-this", CreatedAt: aws.Time(time.Date(2018, 11, 17, 0, 0, 0, 0, time.UTC)), }, { - Type: resource.Instance, + Type: "aws_instance", ID: "do-not-select-this2", }, } @@ -329,7 +328,7 @@ func TestYamlFilter_Apply_CreatedAfter(t *testing.T) { func TestYamlFilter_Apply_MultipleFiltersPerResourceType(t *testing.T) { //given f := &resource.Filter{ - resource.Instance: { + "aws_instance": { { ID: &resource.StringFilter{Pattern: "^select"}, }, @@ -343,21 +342,21 @@ func TestYamlFilter_Apply_MultipleFiltersPerResourceType(t *testing.T) { res := []awsls.Resource{ { - Type: resource.Instance, + Type: "aws_instance", ID: "select-this", Tags: map[string]string{ "foo": "bar-bab", }, }, { - Type: resource.Instance, + Type: "aws_instance", ID: "select-this-too", Tags: map[string]string{ "bla": "blub", }, }, { - Type: resource.Instance, + Type: "aws_instance", ID: "do-not-select-this", Tags: map[string]string{ "bla": "blub", @@ -377,7 +376,7 @@ func TestYamlFilter_Apply_MultipleFiltersPerResourceType(t *testing.T) { func TestYamlFilter_Apply_NegatedStringFilter(t *testing.T) { //given f := &resource.Filter{ - resource.Instance: { + "aws_instance": { { ID: &resource.StringFilter{Pattern: "^select", Negate: true}, }, @@ -391,14 +390,14 @@ func TestYamlFilter_Apply_NegatedStringFilter(t *testing.T) { res := []awsls.Resource{ { - Type: resource.Instance, + Type: "aws_instance", ID: "select-this-not", Tags: map[string]string{ "foo": "bar-bab", }, }, { - Type: resource.Instance, + Type: "aws_instance", ID: "select-this", Tags: map[string]string{ "foo": "baz", @@ -428,7 +427,7 @@ func TestGetTags(t *testing.T) { { name: "embedded updatable resource is nil", arg: &awsls.Resource{}, - wantErr: "resource is nil: &{Type: ID: Region: Tags:map[] CreatedAt: UpdatableResource:}", + wantErr: "resource is nil: &{Type: ID: Region: Profile: AccountID: Tags:map[] CreatedAt: UpdatableResource:}", }, { name: "state is nil", diff --git a/pkg/resource/supported.go b/pkg/resource/supported.go index d15665b12..f139eeaa4 100644 --- a/pkg/resource/supported.go +++ b/pkg/resource/supported.go @@ -1,40 +1,15 @@ package resource import ( - "log" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/autoscaling" - "github.com/aws/aws-sdk-go/service/autoscaling/autoscalingiface" - "github.com/aws/aws-sdk-go/service/cloudformation" - "github.com/aws/aws-sdk-go/service/cloudformation/cloudformationiface" - "github.com/aws/aws-sdk-go/service/cloudtrail" - "github.com/aws/aws-sdk-go/service/cloudtrail/cloudtrailiface" - "github.com/aws/aws-sdk-go/service/cloudwatchlogs" - "github.com/aws/aws-sdk-go/service/cloudwatchlogs/cloudwatchlogsiface" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/aws/aws-sdk-go/service/ec2/ec2iface" - "github.com/aws/aws-sdk-go/service/ecs" - "github.com/aws/aws-sdk-go/service/ecs/ecsiface" - "github.com/aws/aws-sdk-go/service/efs" - "github.com/aws/aws-sdk-go/service/efs/efsiface" - "github.com/aws/aws-sdk-go/service/elb" - "github.com/aws/aws-sdk-go/service/elb/elbiface" - "github.com/aws/aws-sdk-go/service/iam" - "github.com/aws/aws-sdk-go/service/iam/iamiface" - "github.com/aws/aws-sdk-go/service/kms" - "github.com/aws/aws-sdk-go/service/kms/kmsiface" - "github.com/aws/aws-sdk-go/service/lambda" - "github.com/aws/aws-sdk-go/service/lambda/lambdaiface" - "github.com/aws/aws-sdk-go/service/rds" - "github.com/aws/aws-sdk-go/service/rds/rdsiface" - "github.com/aws/aws-sdk-go/service/route53" - "github.com/aws/aws-sdk-go/service/route53/route53iface" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3iface" - "github.com/aws/aws-sdk-go/service/sts" - "github.com/aws/aws-sdk-go/service/sts/stsiface" + "context" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/autoscaling" + + "github.com/aws/aws-sdk-go-v2/service/cloudtrail" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ecs" + awsls "github.com/jckuester/awsls/aws" "github.com/pkg/errors" ) @@ -43,8 +18,6 @@ const ( AutoscalingGroup = "aws_autoscaling_group" EbsSnapshot = "aws_ebs_snapshot" EcsCluster = "aws_ecs_cluster" - Instance = "aws_instance" - NatGateway = "aws_nat_gateway" CloudTrail = "aws_cloudtrail" ) @@ -52,10 +25,9 @@ var ( deleteIDs = map[string]string{ Ami: "ImageId", AutoscalingGroup: "AutoScalingGroupName", + EbsSnapshot: "SnapshotId", // Note: to import a cluster, the name is used as ID EcsCluster: "ClusterArn", - Instance: "InstanceId", - NatGateway: "NatGatewayId", CloudTrail: "Name", } @@ -66,11 +38,11 @@ var ( "aws_lambda_function": 10100, "aws_ecs_cluster": 10000, AutoscalingGroup: 9990, - Instance: 9980, + "aws_instance": 9980, "aws_key_pair": 9970, "aws_elb": 9960, "aws_vpc_endpoint": 9950, - NatGateway: 9940, + "aws_nat_gateway": 9940, "aws_cloudformation_stack": 9930, "aws_route53_zone": 9920, "aws_efs_file_system": 9910, @@ -99,11 +71,6 @@ var ( CloudTrail: 8800, } - tagFieldNames = []string{ - "Tags", - "TagSet", - } - // creationTimeFieldNames are a list field names that are used to find the creation date of a resource. creationTimeFieldNames = []string{ "LaunchTime", @@ -133,47 +100,10 @@ func getDeleteID(resType string) (string, error) { } // AWS wraps the AWS API -type AWS struct { - autoscalingiface.AutoScalingAPI - cloudformationiface.CloudFormationAPI - cloudtrailiface.CloudTrailAPI - cloudwatchlogsiface.CloudWatchLogsAPI - ec2iface.EC2API - ecsiface.ECSAPI - efsiface.EFSAPI - elbiface.ELBAPI - iamiface.IAMAPI - kmsiface.KMSAPI - lambdaiface.LambdaAPI - rdsiface.RDSAPI - route53iface.Route53API - s3iface.S3API - stsiface.STSAPI -} - -// NewAWS creates an AWS instance -func NewAWS(s *session.Session) *AWS { - return &AWS{ - AutoScalingAPI: autoscaling.New(s), - CloudFormationAPI: cloudformation.New(s), - CloudTrailAPI: cloudtrail.New(s), - CloudWatchLogsAPI: cloudwatchlogs.New(s), - EC2API: ec2.New(s), - ECSAPI: ecs.New(s), - EFSAPI: efs.New(s), - ELBAPI: elb.New(s), - IAMAPI: iam.New(s), - KMSAPI: kms.New(s), - LambdaAPI: lambda.New(s), - Route53API: route53.New(s), - RDSAPI: rds.New(s), - S3API: s3.New(s), - STSAPI: sts.New(s), - } -} +type AWS awsls.Client // RawResources lists all resources of a particular type -func (a *AWS) RawResources(resType string) (interface{}, error) { +func (a AWS) RawResources(resType string) (interface{}, error) { switch resType { case Ami: return a.amis() @@ -183,10 +113,6 @@ func (a *AWS) RawResources(resType string) (interface{}, error) { return a.ebsSnapshots() case EcsCluster: return a.ecsClusters() - case Instance: - return a.instances() - case NatGateway: - return a.natGateways() case CloudTrail: return a.cloudTrails() default: @@ -194,121 +120,106 @@ func (a *AWS) RawResources(resType string) (interface{}, error) { } } -func (a *AWS) instances() (interface{}, error) { - output, err := a.DescribeInstances(&ec2.DescribeInstancesInput{ - Filters: []*ec2.Filter{ - { - Name: aws.String("instance-state-name"), - Values: []*string{ - aws.String("pending"), aws.String("running"), - aws.String("stopping"), aws.String("stopped"), - }, - }, - }, - }) - - if err != nil { - return nil, err - } +func (a *AWS) ecsClusters() (interface{}, error) { + listClustersRequest := a.Ecsconn.ListClustersRequest(&ecs.ListClustersInput{}) - var instances []*ec2.Instance - for _, r := range output.Reservations { - instances = append(instances, r.Instances...) - } + var clusterARNs []string - return instances, nil -} + pg := ecs.NewListClustersPaginator(listClustersRequest) + for pg.Next(context.Background()) { + page := pg.CurrentPage() -// TODO support findTags -func (a *AWS) natGateways() (interface{}, error) { - output, err := a.DescribeNatGateways(&ec2.DescribeNatGatewaysInput{ - Filter: []*ec2.Filter{ - { - Name: aws.String("state"), - Values: []*string{ - aws.String("available"), - }, - }, - }, - }) + clusterARNs = append(clusterARNs, page.ClusterArns...) + } - if err != nil { + if err := pg.Err(); err != nil { return nil, err } - return output.NatGateways, nil -} -func (a *AWS) ecsClusters() (interface{}, error) { - listOutput, err := a.ListClusters(&ecs.ListClustersInput{}) + // TODO is paginated, but not paginator API + req := a.Ecsconn.DescribeClustersRequest(&ecs.DescribeClustersInput{ + Clusters: clusterARNs, + Include: []ecs.ClusterField{"TAGS"}, + }) + + resp, err := req.Send(context.Background()) if err != nil { return nil, err } - descOutput, err := a.DescribeClusters(&ecs.DescribeClustersInput{ - Clusters: listOutput.ClusterArns, - Include: []*string{aws.String("TAGS")}, - }) - - return descOutput.Clusters, nil + return resp.Clusters, nil } func (a *AWS) cloudTrails() (interface{}, error) { - output, err := a.DescribeTrails(&cloudtrail.DescribeTrailsInput{}) + req := a.Cloudtrailconn.DescribeTrailsRequest(&cloudtrail.DescribeTrailsInput{}) + + resp, err := req.Send(context.Background()) if err != nil { return nil, err } - return output.TrailList, nil + + return resp.TrailList, nil } func (a *AWS) ebsSnapshots() (interface{}, error) { - output, err := a.DescribeSnapshots(&ec2.DescribeSnapshotsInput{ - Filters: []*ec2.Filter{ + req := a.Ec2conn.DescribeSnapshotsRequest(&ec2.DescribeSnapshotsInput{ + Filters: []ec2.Filter{ { Name: aws.String("owner-id"), - Values: []*string{ - a.callerIdentity(), + Values: []string{ + a.AccountID, }, }, }, }) - if err != nil { - return nil, err + var snapshots []ec2.Snapshot + + pg := ec2.NewDescribeSnapshotsPaginator(req) + for pg.Next(context.Background()) { + page := pg.CurrentPage() + + snapshots = append(snapshots, page.Snapshots...) } - return output.Snapshots, nil + + return snapshots, nil } func (a *AWS) amis() (interface{}, error) { - output, err := a.DescribeImages(&ec2.DescribeImagesInput{ - Filters: []*ec2.Filter{ + req := a.Ec2conn.DescribeImagesRequest(&ec2.DescribeImagesInput{ + Filters: []ec2.Filter{ { Name: aws.String("owner-id"), - Values: []*string{ - a.callerIdentity(), + Values: []string{ + a.AccountID, }, }, }, }) + resp, err := req.Send(context.Background()) if err != nil { return nil, err } - return output.Images, nil + + return resp.Images, nil } func (a *AWS) autoscalingGroups() (interface{}, error) { - output, err := a.DescribeAutoScalingGroups(&autoscaling.DescribeAutoScalingGroupsInput{}) - if err != nil { - return nil, err + req := a.Autoscalingconn.DescribeAutoScalingGroupsRequest(&autoscaling.DescribeAutoScalingGroupsInput{}) + + var autoScalingGroups []autoscaling.AutoScalingGroup + + pg := autoscaling.NewDescribeAutoScalingGroupsPaginator(req) + for pg.Next(context.Background()) { + page := pg.CurrentPage() + + autoScalingGroups = append(autoScalingGroups, page.AutoScalingGroups...) } - return output.AutoScalingGroups, nil -} -// callerIdentity returns the account ID of the AWS account for the currently used credentials -func (a *AWS) callerIdentity() *string { - res, err := a.GetCallerIdentity(&sts.GetCallerIdentityInput{}) - if err != nil { - log.Fatal(err) + if err := pg.Err(); err != nil { + return nil, err } - return res.Account + + return autoScalingGroups, nil } diff --git a/pkg/resource/supported_test.go b/pkg/resource/supported_test.go deleted file mode 100644 index 11a32d2c4..000000000 --- a/pkg/resource/supported_test.go +++ /dev/null @@ -1,133 +0,0 @@ -package resource_test - -import ( - "testing" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/autoscaling" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/golang/mock/gomock" - "github.com/jckuester/awsweeper/pkg/resource" - "github.com/jckuester/awsweeper/pkg/resource/mocks" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -var ( - testImageId = "test-ami" - testAmi = &ec2.DescribeImagesOutput{ - Images: []*ec2.Image{ - { - ImageId: &testImageId, - }, - }, - } - - testInstanceID = "test-instance" - testInstance = &ec2.DescribeInstancesOutput{ - Reservations: []*ec2.Reservation{ - { - Instances: []*ec2.Instance{ - { - ImageId: &testInstanceID, - }, - }, - }, - }, - } - - testAutoscalingGroupName = "test-auto-scaling-group" - testTags = map[string]string{ - "test-tag-key": "test-tag-value", - } - testAutoscalingGroup = &autoscaling.DescribeAutoScalingGroupsOutput{ - AutoScalingGroups: []*autoscaling.Group{ - { - AutoScalingGroupName: &testAutoscalingGroupName, - Tags: convertTags(testTags), - }, - }, - } -) - -/* -func TestAWS_Resources_Amis(t *testing.T) { - mockCtrl := gomock.NewController(t) - defer mockCtrl.Finish() - - // given - awsMock := createAmiMock(mockCtrl) - - // when - resources, err := awsMock.RawResources(resource.Ami) - require.NoError(t, err) - res := resources.([]*ec2.Image) - - // then - assert.Len(t, res, 1) - assert.Equal(t, *res[0].ImageId, testImageId) -} -*/ - -func TestAWS_Resources_AutoScalingGroups(t *testing.T) { - mockCtrl := gomock.NewController(t) - defer mockCtrl.Finish() - - // given - awsMock := createAutoScalingGroupMock(mockCtrl) - - // when - resources, err := awsMock.RawResources(resource.AutoscalingGroup) - require.NoError(t, err) - groups := resources.([]*autoscaling.Group) - - // then - assert.Len(t, groups, 1) - assert.Equal(t, *groups[0].AutoScalingGroupName, testAutoscalingGroupName) -} - -/* -func createAmiMock(mockCtrl *gomock.Controller) *resource.AWS { - mockObj := mocks.NewMockEC2API(mockCtrl) - mockObjSts := mocks.NewMockSTSAPI(mockCtrl) - - awsMock := &resource.AWS{ - EC2API: mockObj, - STSAPI: mockObjSts, - } - - mockObj.EXPECT().DescribeImages(gomock.Any()).Return( - testAmi, nil) - - mockObjSts.EXPECT().GetCallerIdentity(&sts.GetCallerIdentityInput{}).Return( - &sts.GetCallerIdentityOutput{ - Account: aws.String("123456789"), - }, nil) - - return awsMock -} -*/ - -func createAutoScalingGroupMock(mockCtrl *gomock.Controller) *resource.AWS { - mockObj := mocks.NewMockAutoScalingAPI(mockCtrl) - awsMock := &resource.AWS{ - AutoScalingAPI: mockObj, - } - - mockObj.EXPECT().DescribeAutoScalingGroups(&autoscaling.DescribeAutoScalingGroupsInput{}).Return( - testAutoscalingGroup, nil) - - return awsMock -} - -func convertTags(tags map[string]string) []*autoscaling.TagDescription { - var tagDescriptions = make([]*autoscaling.TagDescription, 0, len(tags)) - - for key, value := range tags { - tagDescriptions = append(tagDescriptions, &autoscaling.TagDescription{ - Key: aws.String(key), - Value: aws.String(value), - }) - } - return tagDescriptions -} diff --git a/test/acc_test.go b/test/acc_test.go index 210f2d864..a4dae6fbc 100644 --- a/test/acc_test.go +++ b/test/acc_test.go @@ -93,7 +93,7 @@ func TestAcc_Version(t *testing.T) { t.Skip("Skipping acceptance test.") } - logBuffer, err := runBinary(t, "", "", "-version") + logBuffer, err := runBinary(t, "", "", "--version") require.NoError(t, err) actualLogs := logBuffer.String() diff --git a/test/cloudtrail_test.go b/test/cloudtrail_test.go index 4100f796e..d6c723ae7 100644 --- a/test/cloudtrail_test.go +++ b/test/cloudtrail_test.go @@ -1,11 +1,12 @@ package test import ( + "context" "fmt" "os" "testing" - "github.com/aws/aws-sdk-go/service/cloudtrail" + "github.com/aws/aws-sdk-go-v2/service/cloudtrail" "github.com/gruntwork-io/terratest/modules/terraform" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -78,10 +79,11 @@ func assertCloudTrailDeleted(t *testing.T, env EnvVars, id string) { } func cloudTrailExists(t *testing.T, env EnvVars, id string) bool { - opts := &cloudtrail.DescribeTrailsInput{ - TrailNameList: []*string{&id}, - } - resp, err := env.AWSClient.DescribeTrails(opts) + req := env.AWSClient.Cloudtrailconn.DescribeTrailsRequest(&cloudtrail.DescribeTrailsInput{ + TrailNameList: []string{id}, + }) + + resp, err := req.Send(context.Background()) if err != nil { t.Fatal() } diff --git a/test/cloudwatch_log_group_test.go b/test/cloudwatch_log_group_test.go index ee96922c7..a15ac109c 100644 --- a/test/cloudwatch_log_group_test.go +++ b/test/cloudwatch_log_group_test.go @@ -1,11 +1,13 @@ package test import ( + "context" "fmt" "os" "testing" - "github.com/aws/aws-sdk-go/service/cloudwatchlogs" + "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs" + "github.com/gruntwork-io/terratest/modules/terraform" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -78,11 +80,12 @@ func assertCloudWatchLogGroupDeleted(t *testing.T, env EnvVars, id string) { } func cloudWatchLogGroupExists(t *testing.T, env EnvVars, id string) bool { - opts := &cloudwatchlogs.DescribeLogGroupsInput{ - LogGroupNamePrefix: &id, - } + req := env.AWSClient.Cloudwatchlogsconn.DescribeLogGroupsRequest( + &cloudwatchlogs.DescribeLogGroupsInput{ + LogGroupNamePrefix: &id, + }) - resp, err := env.AWSClient.CloudWatchLogsAPI.DescribeLogGroups(opts) + resp, err := req.Send(context.Background()) if err != nil { t.Fatal(err) } diff --git a/test/db_instance_test.go b/test/db_instance_test.go index 88da48f09..e55cb6c8c 100644 --- a/test/db_instance_test.go +++ b/test/db_instance_test.go @@ -1,13 +1,14 @@ package test import ( + "context" "fmt" "os" "testing" - "github.com/aws/aws-sdk-go/service/rds" + "github.com/aws/aws-sdk-go-v2/aws/awserr" - "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go-v2/service/rds" "github.com/gruntwork-io/terratest/modules/terraform" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -82,11 +83,12 @@ func assertDBInstanceDeleted(t *testing.T, env EnvVars, id string) { } func dbInstanceExists(t *testing.T, env EnvVars, id string) bool { - opts := &rds.DescribeDBInstancesInput{ + req := env.AWSClient.Rdsconn.DescribeDBInstancesRequest(&rds.DescribeDBInstancesInput{ DBInstanceIdentifier: &id, - } + }) + + resp, err := req.Send(context.Background()) - resp, err := env.AWSClient.DescribeDBInstances(opts) if err != nil { awsErr, ok := err.(awserr.Error) if !ok { diff --git a/test/ebs_snapshot_test.go b/test/ebs_snapshot_test.go index 320b812de..02cd20477 100644 --- a/test/ebs_snapshot_test.go +++ b/test/ebs_snapshot_test.go @@ -1,12 +1,13 @@ package test import ( + "context" "fmt" "os" "testing" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go-v2/aws/awserr" + "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/gruntwork-io/terratest/modules/terraform" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -33,7 +34,7 @@ func TestAcc_EbsSnapshot_DeleteByID(t *testing.T) { writeConfigID(t, terraformDir, "aws_ebs_snapshot", id) defer os.Remove(terraformDir + "/config.yml") - logBuffer, err := runBinary(t, terraformDir, "YES\n", "-debug") + logBuffer, err := runBinary(t, terraformDir, "YES\n", "--debug") require.NoError(t, err) assertEbsSnapshotDeleted(t, env, id) @@ -79,11 +80,13 @@ func assertEbsSnapshotDeleted(t *testing.T, env EnvVars, id string) { } func ebsSnapshotExists(t *testing.T, env EnvVars, id string) bool { - opts := &ec2.DescribeSnapshotsInput{ - SnapshotIds: []*string{&id}, - } + req := env.AWSClient.Ec2conn.DescribeSnapshotsRequest( + &ec2.DescribeSnapshotsInput{ + SnapshotIds: []string{id}, + }) + + resp, err := req.Send(context.Background()) - resp, err := env.AWSClient.DescribeSnapshots(opts) if err != nil { ec2err, ok := err.(awserr.Error) if !ok { diff --git a/test/ecs_cluster_test.go b/test/ecs_cluster_test.go index c9a750684..045e8d184 100644 --- a/test/ecs_cluster_test.go +++ b/test/ecs_cluster_test.go @@ -1,11 +1,12 @@ package test import ( + "context" "fmt" "os" "testing" - "github.com/aws/aws-sdk-go/service/ecs" + "github.com/aws/aws-sdk-go-v2/service/ecs" "github.com/gruntwork-io/terratest/modules/terraform" "github.com/stretchr/testify/assert" @@ -81,11 +82,12 @@ func assertEcsClusterDeleted(t *testing.T, env EnvVars, id string) { } func ecsClusterExists(t *testing.T, env EnvVars, id string) bool { - opts := &ecs.DescribeClustersInput{ - Clusters: []*string{&id}, - } + req := env.AWSClient.Ecsconn.DescribeClustersRequest( + &ecs.DescribeClustersInput{ + Clusters: []string{id}, + }) - resp, err := env.AWSClient.DescribeClusters(opts) + resp, err := req.Send(context.Background()) if err != nil { t.Fatal(err) } diff --git a/test/elb_test.go b/test/elb_test.go index df73082b3..1b130f224 100644 --- a/test/elb_test.go +++ b/test/elb_test.go @@ -1,12 +1,14 @@ package test import ( + "context" "fmt" "os" "testing" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/elb" + "github.com/aws/aws-sdk-go-v2/aws/awserr" + + "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing" "github.com/gruntwork-io/terratest/modules/terraform" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -79,11 +81,13 @@ func assertElbDeleted(t *testing.T, env EnvVars, id string) { } func elbExists(t *testing.T, env EnvVars, id string) bool { - opts := &elb.DescribeLoadBalancersInput{ - LoadBalancerNames: []*string{&id}, - } + req := env.AWSClient.Elasticloadbalancingconn.DescribeLoadBalancersRequest( + &elasticloadbalancing.DescribeLoadBalancersInput{ + LoadBalancerNames: []string{id}, + }) + + resp, err := req.Send(context.Background()) - resp, err := env.AWSClient.ELBAPI.DescribeLoadBalancers(opts) if err != nil { elbErr, ok := err.(awserr.Error) if !ok { diff --git a/test/helper_test.go b/test/helper_test.go index c88a57dd5..1112c2094 100644 --- a/test/helper_test.go +++ b/test/helper_test.go @@ -9,11 +9,11 @@ import ( "strings" "testing" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws/external" + awsls "github.com/jckuester/awsls/aws" + "github.com/gruntwork-io/terratest/modules/random" "github.com/gruntwork-io/terratest/modules/terraform" - res "github.com/jckuester/awsweeper/pkg/resource" "github.com/onsi/gomega/gexec" "github.com/stretchr/testify/require" ) @@ -27,7 +27,7 @@ const ( type EnvVars struct { AWSRegion string AWSProfile string - AWSClient *res.AWS + AWSClient *awsls.Client } // InitEnv sets environment variables for acceptance tests. @@ -44,15 +44,15 @@ func InitEnv(t *testing.T) EnvVars { t.Fatal("env variable AWS_DEFAULT_REGION needs to be set for tests") } - sess := session.Must(session.NewSessionWithOptions(session.Options{ - Config: aws.Config{Region: aws.String(region)}, - SharedConfigState: session.SharedConfigEnable, - })) + client, err := awsls.NewClient( + external.WithSharedConfigProfile(profile), + external.WithRegion(region)) + require.NoError(t, err) return EnvVars{ AWSProfile: profile, AWSRegion: region, - AWSClient: res.NewAWS(sess), + AWSClient: client, } } diff --git a/test/iam_policy_test.go b/test/iam_policy_test.go index 056c263ea..ae03c1962 100644 --- a/test/iam_policy_test.go +++ b/test/iam_policy_test.go @@ -1,12 +1,14 @@ package test import ( + "context" "fmt" "os" "testing" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go-v2/aws/awserr" + + "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/gruntwork-io/terratest/modules/terraform" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -52,11 +54,12 @@ func assertIamPolicyDeleted(t *testing.T, env EnvVars, arn string) { } func iamPolicyExists(t *testing.T, env EnvVars, arn string) bool { - opts := &iam.GetPolicyInput{ + req := env.AWSClient.Iamconn.GetPolicyRequest(&iam.GetPolicyInput{ PolicyArn: &arn, - } + }) + + _, err := req.Send(context.Background()) - _, err := env.AWSClient.IAMAPI.GetPolicy(opts) if err != nil { ec2err, ok := err.(awserr.Error) if !ok { diff --git a/test/iam_user_test.go b/test/iam_user_test.go index 589e770e9..891dd2ea8 100644 --- a/test/iam_user_test.go +++ b/test/iam_user_test.go @@ -1,17 +1,16 @@ package test import ( + "context" "fmt" "os" "testing" - "github.com/aws/aws-sdk-go/service/iam" - + "github.com/aws/aws-sdk-go-v2/aws/awserr" + "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/gruntwork-io/terratest/modules/terraform" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "github.com/aws/aws-sdk-go/aws/awserr" ) func TestAcc_IamUser_DeleteByID(t *testing.T) { @@ -81,11 +80,12 @@ func assertIamUserDeleted(t *testing.T, env EnvVars, id string) { } func iamUserExists(t *testing.T, env EnvVars, id string) bool { - opts := &iam.GetUserInput{ + req := env.AWSClient.Iamconn.GetUserRequest(&iam.GetUserInput{ UserName: &id, - } + }) + + _, err := req.Send(context.Background()) - _, err := env.AWSClient.GetUser(opts) if err != nil { ec2err, ok := err.(awserr.Error) if !ok { diff --git a/test/lambda_function_test.go b/test/lambda_function_test.go index 7017ff868..40c43cc3d 100644 --- a/test/lambda_function_test.go +++ b/test/lambda_function_test.go @@ -1,14 +1,14 @@ package test import ( + "context" "fmt" "os" "testing" - "github.com/aws/aws-sdk-go/aws/awserr" - - "github.com/aws/aws-sdk-go/service/lambda" + "github.com/aws/aws-sdk-go-v2/aws/awserr" + "github.com/aws/aws-sdk-go-v2/service/lambda" "github.com/gruntwork-io/terratest/modules/terraform" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -83,11 +83,13 @@ func assertLambdaFunctionDeleted(t *testing.T, env EnvVars, id string) { } func lambdaFunctionExists(t *testing.T, env EnvVars, id string) bool { - opts := &lambda.GetFunctionInput{ - FunctionName: &id, - } + req := env.AWSClient.Lambdaconn.GetFunctionRequest( + &lambda.GetFunctionInput{ + FunctionName: &id, + }) + + _, err := req.Send(context.Background()) - _, err := env.AWSClient.GetFunction(opts) if err != nil { awsErr, ok := err.(awserr.Error) if !ok { diff --git a/test/vpc_test.go b/test/vpc_test.go index 18d31d4a9..5c47cf665 100644 --- a/test/vpc_test.go +++ b/test/vpc_test.go @@ -1,16 +1,17 @@ package test import ( + "context" "fmt" "os" "testing" + "github.com/aws/aws-sdk-go-v2/aws/awserr" + + "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/gruntwork-io/terratest/modules/terraform" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/ec2" ) func TestAcc_Vpc_DeleteByID(t *testing.T) { @@ -80,10 +81,13 @@ func assertVpcDeleted(t *testing.T, env EnvVars, id string) { } func vpcExists(t *testing.T, env EnvVars, id string) bool { - opts := &ec2.DescribeVpcsInput{ - VpcIds: []*string{&id}, - } - resp, err := env.AWSClient.DescribeVpcs(opts) + req := env.AWSClient.Ec2conn.DescribeVpcsRequest( + &ec2.DescribeVpcsInput{ + VpcIds: []string{id}, + }) + + resp, err := req.Send(context.Background()) + if err != nil { ec2err, ok := err.(awserr.Error) if !ok {