From 203e5aeeb70e2ca1a36ba5da3f76ad11fbcbacd7 Mon Sep 17 00:00:00 2001 From: Sven Walter Date: Fri, 26 Jan 2018 23:01:22 +0100 Subject: [PATCH 1/4] Add resource filters to config --- README.md | 48 ++++++++++++++++++++++++++ cmd/config.go | 11 +++++- cmd/nuke.go | 25 +++++++++++--- cmd/params.go | 18 ++++------ cmd/root.go | 41 ++++++++++++++-------- cmd/scan.go | 5 +-- cmd/test-fixtures/example.yaml | 10 ++++++ cmd/util.go | 16 +++++++++ cmd/util_test.go | 63 ++++++++++++++++++++++++++++++++++ config/example.yaml | 10 ++++++ pkg/types/list.go | 39 +++++++++++++++++++++ pkg/types/list_test.go | 20 +++++++++++ resources/interface.go | 13 +++++++ 13 files changed, 286 insertions(+), 33 deletions(-) create mode 100644 cmd/util_test.go create mode 100644 pkg/types/list.go create mode 100644 pkg/types/list_test.go diff --git a/README.md b/README.md index 866396fb2..614ca35f6 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,54 @@ for debugging, if the error is not about dependencies. *aws-nuke* retries deleting all resources until all specified ones are deleted or until there are only resources with errors left. +### Specifying Resource Types to Delete + +*aws-nuke* deletes a lot of resources and there might be added more at any +release. Eventually, every resources should get deleted. You might to restrict +which resources to delete. There are multiple ways to configure this. + +One way are filter, which already got mentioned. This requires to know the +identifier of each resource. It is also possible to prevent whole resource +types (eg `S3Bucket`) from getting deleted with two methods. + +* The `--target` flag limits nuking to the specified resource types. +* The `--exclude` flag prevent nuking of the specified resource types. + +It is also possible to configure the resource types in the config file like in +this example: + +``` +--- +regions: + - "eu-west-1" +account-blacklist: +- 1234567890 + +resource-types: + target: + - S3Object + - S3Bucket + exclude: + - IAMRole + +accounts: + 555133742: + resource-types: + target: + - S3Bucket +``` + +If targets are specified in multiple places (eg CLI and account specific), then +a resource type must be specified in all places. In other words each +configuration limits the previous ones. + +If a exclude is defined in any place, then if will be ignored in any case. + +**Hint:** You can see all available resources types with this command: + +``` +aws-nuke resource-types +``` ## Install diff --git a/cmd/config.go b/cmd/config.go index 18617c0b6..0b1ddfbb5 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -5,17 +5,26 @@ import ( "io/ioutil" "strings" + "github.com/rebuy-de/aws-nuke/pkg/types" + "gopkg.in/yaml.v2" ) +type ResourceConfig struct { + Include types.Set `yaml:"include"` + Exclude types.Set `yaml:"exclude"` +} + type NukeConfig struct { AccountBlacklist []string `yaml:"account-blacklist"` Regions []string `yaml:"regions"` Accounts map[string]NukeConfigAccount `yaml:"accounts"` + ResourceTypes ResourceConfig `yaml:"resource-types"` } type NukeConfigAccount struct { - Filters map[string][]string `yaml:"filters"` + Filters map[string][]string `yaml:"filters"` + ResourceTypes ResourceConfig `yaml:"resource-types"` } func LoadConfig(path string) (*NukeConfig, error) { diff --git a/cmd/nuke.go b/cmd/nuke.go index 55a7448d5..fb049e7dd 100644 --- a/cmd/nuke.go +++ b/cmd/nuke.go @@ -5,6 +5,7 @@ import ( "time" "github.com/rebuy-de/aws-nuke/pkg/awsutil" + "github.com/rebuy-de/aws-nuke/pkg/types" "github.com/rebuy-de/aws-nuke/resources" ) @@ -13,6 +14,8 @@ type Nuke struct { Account awsutil.Account Config *NukeConfig + ResourceTypes types.Set + ForceSleep time.Duration items Queue @@ -106,6 +109,22 @@ func (n *Nuke) Run() error { } func (n *Nuke) Scan() error { + accountConfig := n.Config.Accounts[n.Account.ID()] + + resourceTypes := ResolveResourceTypes( + resources.GetListerNames(), + []types.Set{ + types.Set(n.Parameters.Targets).Union(n.Parameters.Include), + n.Config.ResourceTypes.Include, + accountConfig.ResourceTypes.Include, + }, + []types.Set{ + n.Parameters.Exclude, + n.Config.ResourceTypes.Exclude, + accountConfig.ResourceTypes.Exclude, + }, + ) + queue := make(Queue, 0) for _, regionName := range n.Config.Regions { @@ -119,12 +138,8 @@ func (n *Nuke) Scan() error { Session: sess, } - items := Scan(region) + items := Scan(region, resourceTypes) for item := range items { - if !n.Parameters.WantsTarget(item.Type) { - continue - } - queue = append(queue, item) n.Filter(item) item.Print() diff --git a/cmd/params.go b/cmd/params.go index 87070b190..d8f454fa5 100644 --- a/cmd/params.go +++ b/cmd/params.go @@ -9,6 +9,8 @@ type NukeParameters struct { ConfigPath string Targets []string + Include []string + Exclude []string NoDryRun bool Force bool @@ -19,19 +21,13 @@ func (p *NukeParameters) Validate() error { return fmt.Errorf("You have to specify the --config flag.\n") } - return nil -} - -func (p *NukeParameters) WantsTarget(name string) bool { - if p.Targets == nil || len(p.Targets) < 1 { - return true + if len(p.Targets) > 0 { + LogWarn("The flag --target is deprecated. Please use --include instead.\n") } - for _, wants := range p.Targets { - if wants == name { - return true - } + if len(p.Targets) > 0 && len(p.Include) > 0 { + return fmt.Errorf("The flag --include cannot used together with --target.") } - return false + return nil } diff --git a/cmd/root.go b/cmd/root.go index 2ee3e0624..b24c9f175 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -53,25 +53,42 @@ func NewRootCommand() *cobra.Command { command.PersistentFlags().StringVarP( ¶ms.ConfigPath, "config", "c", "", - "path to config (required)") + "(required) Path to the nuke config file.") command.PersistentFlags().StringVar( &creds.Profile, "profile", "", - "profile name to nuke") + "Name of the AWS profile name for accessing the AWS API. "+ + "Cannot be used together with --access-key-id and --secret-access-key.") command.PersistentFlags().StringVar( &creds.AccessKeyID, "access-key-id", "", - "AWS access-key-id") + "AWS access key ID for accessing the AWS API. "+ + "Must be used together with --secret-access-key."+ + "Cannot be used together with --profile.") command.PersistentFlags().StringVar( &creds.SecretAccessKey, "secret-access-key", "", - "AWS secret-access-key") + "AWS secret access key for accessing the AWS API. "+ + "Must be used together with --access-key-id."+ + "Cannot be used together with --profile.") + command.PersistentFlags().StringSliceVarP( ¶ms.Targets, "target", "t", []string{}, - "limit nuking to certain resource types (eg IAMServerCertificate)") + "(deprecated) Limit nuking to certain resource types (eg IAMServerCertificate). "+ + "This flag is deprecated. Please use --include instead.") + command.PersistentFlags().StringSliceVar( + ¶ms.Include, "include", []string{}, + "Limit nuking to certain resource types (eg IAMServerCertificate). "+ + "This flag can be used multiple times.") + command.PersistentFlags().StringSliceVar( + ¶ms.Exclude, "exclude", []string{}, + "Prevent nuking of certain resource types (eg IAMServerCertificate). "+ + "This flag can be used multiple times.") command.PersistentFlags().BoolVar( ¶ms.NoDryRun, "no-dry-run", false, - "actually delete found resources") + "If specified, it actually deletes found resources. "+ + "Otherwise it just lists all candidates.") command.PersistentFlags().BoolVar( ¶ms.Force, "force", false, - "don't ask for confirmation") + "Don't ask for confirmation before deleting resources. "+ + "Instead it waits 15s before continuing.") command.AddCommand(NewVersionCommand()) command.AddCommand(NewResourceTypesCommand()) @@ -84,14 +101,10 @@ func NewResourceTypesCommand() *cobra.Command { Use: "resource-types", Short: "lists all available resource types", Run: func(cmd *cobra.Command, args []string) { - types := []string{} - for resourceType, _ := range resources.GetListers() { - types = append(types, resourceType) - } - - sort.Strings(types) + names := resources.GetListerNames() + sort.Strings(names) - for _, resourceType := range types { + for _, resourceType := range names { fmt.Println(resourceType) } }, diff --git a/cmd/scan.go b/cmd/scan.go index 3db437fe1..02c1e426c 100644 --- a/cmd/scan.go +++ b/cmd/scan.go @@ -8,11 +8,12 @@ import ( "github.com/rebuy-de/aws-nuke/resources" ) -func Scan(region Region) <-chan *Item { +func Scan(region Region, resourceTypes []string) <-chan *Item { items := make(chan *Item, 100) go func() { - for resourceType, lister := range resources.GetListers() { + for _, resourceType := range resourceTypes { + lister := resources.GetLister(resourceType) rs, err := safeLister(region.Session, lister) if err != nil { LogErrorf(fmt.Errorf("\n=============\n\n"+ diff --git a/cmd/test-fixtures/example.yaml b/cmd/test-fixtures/example.yaml index dc5b2434e..18332b8df 100644 --- a/cmd/test-fixtures/example.yaml +++ b/cmd/test-fixtures/example.yaml @@ -4,8 +4,18 @@ regions: account-blacklist: - 1234567890 +resource-types: + target: + - S3Object + - S3Bucket + exclude: + - IAMRole + accounts: 555133742: + resource-types: + target: + - S3Bucket filters: IAMRole: - "uber.admin" diff --git a/cmd/util.go b/cmd/util.go index 1b1ab6eaa..361197dd8 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -5,6 +5,8 @@ import ( "fmt" "os" "strings" + + "github.com/rebuy-de/aws-nuke/pkg/types" ) func Prompt(expect string) error { @@ -22,3 +24,17 @@ func Prompt(expect string) error { return nil } + +func ResolveResourceTypes(base types.Set, include, exclude []types.Set) types.Set { + for _, i := range include { + if len(i) > 0 { + base = base.Intersect(i) + } + } + + for _, e := range exclude { + base = base.Remove(e) + } + + return base +} diff --git a/cmd/util_test.go b/cmd/util_test.go new file mode 100644 index 000000000..c7c6b125b --- /dev/null +++ b/cmd/util_test.go @@ -0,0 +1,63 @@ +package cmd + +import ( + "fmt" + "sort" + "testing" + + "github.com/rebuy-de/aws-nuke/pkg/types" +) + +func TestResolveResourceTypes(t *testing.T) { + cases := []struct { + base types.Set + include []types.Set + exclude []types.Set + result types.Set + }{ + { + base: types.Set{"a", "b", "c", "d"}, + include: []types.Set{types.Set{"a", "b", "c"}}, + result: types.Set{"a", "b", "c"}, + }, + { + base: types.Set{"a", "b", "c", "d"}, + exclude: []types.Set{types.Set{"b", "d"}}, + result: types.Set{"a", "c"}, + }, + { + base: types.Set{"a", "b"}, + include: []types.Set{types.Set{}}, + result: types.Set{"a", "b"}, + }, + { + base: types.Set{"c", "b"}, + exclude: []types.Set{types.Set{}}, + result: types.Set{"c", "b"}, + }, + { + base: types.Set{"a", "b", "c", "d"}, + include: []types.Set{types.Set{"a", "b", "c"}}, + exclude: []types.Set{types.Set{"a"}}, + result: types.Set{"b", "c"}, + }, + } + + for i, tc := range cases { + t.Run(fmt.Sprint(i), func(t *testing.T) { + r := ResolveResourceTypes(tc.base, tc.include, tc.exclude) + + sort.Strings(r) + sort.Strings(tc.result) + + var ( + want = fmt.Sprint(tc.result) + have = fmt.Sprint(r) + ) + + if want != have { + t.Fatalf("Wrong result. Want: %s. Have: %s", want, have) + } + }) + } +} diff --git a/config/example.yaml b/config/example.yaml index dc5b2434e..18332b8df 100644 --- a/config/example.yaml +++ b/config/example.yaml @@ -4,8 +4,18 @@ regions: account-blacklist: - 1234567890 +resource-types: + target: + - S3Object + - S3Bucket + exclude: + - IAMRole + accounts: 555133742: + resource-types: + target: + - S3Bucket filters: IAMRole: - "uber.admin" diff --git a/pkg/types/list.go b/pkg/types/list.go new file mode 100644 index 000000000..2a5a6ef26 --- /dev/null +++ b/pkg/types/list.go @@ -0,0 +1,39 @@ +package types + +type Set []string + +func (s Set) Intersect(o Set) Set { + m := map[string]bool{} + for _, t := range o { + m[t] = true + } + + result := Set{} + for _, t := range s { + if m[t] { + result = append(result, t) + } + } + + return result +} + +func (s Set) Remove(o Set) Set { + m := map[string]bool{} + for _, t := range o { + m[t] = true + } + + result := Set{} + for _, t := range s { + if !m[t] { + result = append(result, t) + } + } + + return result +} + +func (s Set) Union(o Set) Set { + return Set(append(s, o...)) +} diff --git a/pkg/types/list_test.go b/pkg/types/list_test.go new file mode 100644 index 000000000..f82815078 --- /dev/null +++ b/pkg/types/list_test.go @@ -0,0 +1,20 @@ +package types_test + +import ( + "sort" + "testing" + + "github.com/rebuy-de/aws-nuke/pkg/types" +) + +func TestSetRetain(t *testing.T) { + s1 := types.Set{"a", "b", "c"} + s2 := types.Set{"b", "a", "d"} + + r := s1.Intersect(s2) + sort.Strings(r) + + if len(r) != 2 || r[0] != "a" || r[1] != "b" { + t.Errorf("Wrong result. Want: [a, b]. Got: %v", r) + } +} diff --git a/resources/interface.go b/resources/interface.go index 685a74815..27be41ca3 100644 --- a/resources/interface.go +++ b/resources/interface.go @@ -34,3 +34,16 @@ func register(name string, lister ResourceLister) { func GetListers() ResourceListers { return resourceListers } + +func GetLister(name string) ResourceLister { + return resourceListers[name] +} + +func GetListerNames() []string { + names := []string{} + for resourceType, _ := range GetListers() { + names = append(names, resourceType) + } + + return names +} From b3e5e5e15f6f47a47e213f35658effe093489401 Mon Sep 17 00:00:00 2001 From: Sven Walter Date: Fri, 26 Jan 2018 23:56:31 +0100 Subject: [PATCH 2/4] rename target flag --- cmd/config.go | 4 ++-- cmd/nuke.go | 12 ++++++------ cmd/params.go | 13 ++----------- cmd/root.go | 8 ++------ 4 files changed, 12 insertions(+), 25 deletions(-) diff --git a/cmd/config.go b/cmd/config.go index 0b1ddfbb5..071401a11 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -11,8 +11,8 @@ import ( ) type ResourceConfig struct { - Include types.Set `yaml:"include"` - Exclude types.Set `yaml:"exclude"` + Targets types.Set `yaml:"targets"` + Excludes types.Set `yaml:"excludes"` } type NukeConfig struct { diff --git a/cmd/nuke.go b/cmd/nuke.go index fb049e7dd..4aebe2077 100644 --- a/cmd/nuke.go +++ b/cmd/nuke.go @@ -114,14 +114,14 @@ func (n *Nuke) Scan() error { resourceTypes := ResolveResourceTypes( resources.GetListerNames(), []types.Set{ - types.Set(n.Parameters.Targets).Union(n.Parameters.Include), - n.Config.ResourceTypes.Include, - accountConfig.ResourceTypes.Include, + n.Parameters.Targets, + n.Config.ResourceTypes.Targets, + accountConfig.ResourceTypes.Targets, }, []types.Set{ - n.Parameters.Exclude, - n.Config.ResourceTypes.Exclude, - accountConfig.ResourceTypes.Exclude, + n.Parameters.Excludes, + n.Config.ResourceTypes.Excludes, + accountConfig.ResourceTypes.Excludes, }, ) diff --git a/cmd/params.go b/cmd/params.go index d8f454fa5..bed41d0ea 100644 --- a/cmd/params.go +++ b/cmd/params.go @@ -8,9 +8,8 @@ import ( type NukeParameters struct { ConfigPath string - Targets []string - Include []string - Exclude []string + Targets []string + Excludes []string NoDryRun bool Force bool @@ -21,13 +20,5 @@ func (p *NukeParameters) Validate() error { return fmt.Errorf("You have to specify the --config flag.\n") } - if len(p.Targets) > 0 { - LogWarn("The flag --target is deprecated. Please use --include instead.\n") - } - - if len(p.Targets) > 0 && len(p.Include) > 0 { - return fmt.Errorf("The flag --include cannot used together with --target.") - } - return nil } diff --git a/cmd/root.go b/cmd/root.go index b24c9f175..9dad48dba 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -71,14 +71,10 @@ func NewRootCommand() *cobra.Command { command.PersistentFlags().StringSliceVarP( ¶ms.Targets, "target", "t", []string{}, - "(deprecated) Limit nuking to certain resource types (eg IAMServerCertificate). "+ - "This flag is deprecated. Please use --include instead.") - command.PersistentFlags().StringSliceVar( - ¶ms.Include, "include", []string{}, "Limit nuking to certain resource types (eg IAMServerCertificate). "+ "This flag can be used multiple times.") - command.PersistentFlags().StringSliceVar( - ¶ms.Exclude, "exclude", []string{}, + command.PersistentFlags().StringSliceVarP( + ¶ms.Excludes, "exclude", "e", []string{}, "Prevent nuking of certain resource types (eg IAMServerCertificate). "+ "This flag can be used multiple times.") command.PersistentFlags().BoolVar( From 4629deddd2308a0514e5a62a974fe6a5d4ae382d Mon Sep 17 00:00:00 2001 From: Sven Walter Date: Mon, 29 Jan 2018 10:29:06 +0100 Subject: [PATCH 3/4] review fixes --- README.md | 37 +++++++++++++++++--------- config/example.yaml | 6 ++--- pkg/types/list_test.go | 20 -------------- pkg/types/{list.go => set.go} | 33 +++++++++++++++-------- pkg/types/set_test.go | 50 +++++++++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 46 deletions(-) delete mode 100644 pkg/types/list_test.go rename pkg/types/{list.go => set.go} (57%) create mode 100644 pkg/types/set_test.go diff --git a/README.md b/README.md index 614ca35f6..306f50385 100644 --- a/README.md +++ b/README.md @@ -199,10 +199,10 @@ or until there are only resources with errors left. ### Specifying Resource Types to Delete *aws-nuke* deletes a lot of resources and there might be added more at any -release. Eventually, every resources should get deleted. You might to restrict -which resources to delete. There are multiple ways to configure this. +release. Eventually, every resources should get deleted. You might want to +restrict which resources to delete. There are multiple ways to configure this. -One way are filter, which already got mentioned. This requires to know the +One way are filters, which already got mentioned. This requires to know the identifier of each resource. It is also possible to prevent whole resource types (eg `S3Bucket`) from getting deleted with two methods. @@ -210,7 +210,7 @@ types (eg `S3Bucket`) from getting deleted with two methods. * The `--exclude` flag prevent nuking of the specified resource types. It is also possible to configure the resource types in the config file like in -this example: +these examples: ``` --- @@ -220,26 +220,39 @@ account-blacklist: - 1234567890 resource-types: - target: + # only nuke these three resources + targets: - S3Object - S3Bucket - exclude: - IAMRole accounts: - 555133742: - resource-types: - target: - - S3Bucket + 555133742: {} +``` + +``` +--- +regions: + - "eu-west-1" +account-blacklist: +- 1234567890 + +resource-types: + # don't nuke IAM users + exclude: + - IAMUser + +accounts: + 555133742: {} ``` If targets are specified in multiple places (eg CLI and account specific), then a resource type must be specified in all places. In other words each configuration limits the previous ones. -If a exclude is defined in any place, then if will be ignored in any case. +If an exclude is used, then all its resource types will not be deleted. -**Hint:** You can see all available resources types with this command: +**Hint:** You can see all available resource types with this command: ``` aws-nuke resource-types diff --git a/config/example.yaml b/config/example.yaml index 18332b8df..0f78ab279 100644 --- a/config/example.yaml +++ b/config/example.yaml @@ -5,16 +5,16 @@ account-blacklist: - 1234567890 resource-types: - target: + targets: - S3Object - S3Bucket - exclude: + excludes: - IAMRole accounts: 555133742: resource-types: - target: + targets: - S3Bucket filters: IAMRole: diff --git a/pkg/types/list_test.go b/pkg/types/list_test.go deleted file mode 100644 index f82815078..000000000 --- a/pkg/types/list_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package types_test - -import ( - "sort" - "testing" - - "github.com/rebuy-de/aws-nuke/pkg/types" -) - -func TestSetRetain(t *testing.T) { - s1 := types.Set{"a", "b", "c"} - s2 := types.Set{"b", "a", "d"} - - r := s1.Intersect(s2) - sort.Strings(r) - - if len(r) != 2 || r[0] != "a" || r[1] != "b" { - t.Errorf("Wrong result. Want: [a, b]. Got: %v", r) - } -} diff --git a/pkg/types/list.go b/pkg/types/set.go similarity index 57% rename from pkg/types/list.go rename to pkg/types/set.go index 2a5a6ef26..00dc187a9 100644 --- a/pkg/types/list.go +++ b/pkg/types/set.go @@ -3,14 +3,11 @@ package types type Set []string func (s Set) Intersect(o Set) Set { - m := map[string]bool{} - for _, t := range o { - m[t] = true - } + mo := o.toMap() result := Set{} for _, t := range s { - if m[t] { + if mo[t] { result = append(result, t) } } @@ -19,14 +16,11 @@ func (s Set) Intersect(o Set) Set { } func (s Set) Remove(o Set) Set { - m := map[string]bool{} - for _, t := range o { - m[t] = true - } + mo := o.toMap() result := Set{} for _, t := range s { - if !m[t] { + if !mo[t] { result = append(result, t) } } @@ -35,5 +29,22 @@ func (s Set) Remove(o Set) Set { } func (s Set) Union(o Set) Set { - return Set(append(s, o...)) + ms := s.toMap() + + result := []string(s) + for _, oi := range o { + if !ms[oi] { + result = append(result, oi) + } + } + + return Set(result) +} + +func (s Set) toMap() map[string]bool { + m := map[string]bool{} + for _, t := range s { + m[t] = true + } + return m } diff --git a/pkg/types/set_test.go b/pkg/types/set_test.go new file mode 100644 index 000000000..71562d308 --- /dev/null +++ b/pkg/types/set_test.go @@ -0,0 +1,50 @@ +package types_test + +import ( + "fmt" + "testing" + + "github.com/rebuy-de/aws-nuke/pkg/types" +) + +func TestSetInterset(t *testing.T) { + s1 := types.Set{"a", "b", "c"} + s2 := types.Set{"b", "a", "d"} + + r := s1.Intersect(s2) + + want := fmt.Sprint([]string{"a", "b"}) + have := fmt.Sprint(r) + + if want != have { + t.Errorf("Wrong result. Want: %s. Have: %s", want, have) + } +} + +func TestSetRemove(t *testing.T) { + s1 := types.Set{"a", "b", "c"} + s2 := types.Set{"b", "a", "d"} + + r := s1.Remove(s2) + + want := fmt.Sprint([]string{"c"}) + have := fmt.Sprint(r) + + if want != have { + t.Errorf("Wrong result. Want: %s. Have: %s", want, have) + } +} + +func TestSetUnion(t *testing.T) { + s1 := types.Set{"a", "b", "c"} + s2 := types.Set{"b", "a", "d"} + + r := s1.Union(s2) + + want := fmt.Sprint([]string{"a", "b", "c", "d"}) + have := fmt.Sprint(r) + + if want != have { + t.Errorf("Wrong result. Want: %s. Have: %s", want, have) + } +} From 88419ca58fe90efdf7ec9764558ac7e82b1d305b Mon Sep 17 00:00:00 2001 From: Sven Walter Date: Mon, 5 Feb 2018 09:26:52 +0100 Subject: [PATCH 4/4] rename Set type to Collection --- cmd/config.go | 4 +- cmd/nuke.go | 6 +-- cmd/util.go | 2 +- cmd/util_test.go | 40 +++++++-------- pkg/types/collection.go | 50 +++++++++++++++++++ pkg/types/{set_test.go => collection_test.go} | 12 ++--- pkg/types/set.go | 50 ------------------- 7 files changed, 82 insertions(+), 82 deletions(-) create mode 100644 pkg/types/collection.go rename pkg/types/{set_test.go => collection_test.go} (75%) delete mode 100644 pkg/types/set.go diff --git a/cmd/config.go b/cmd/config.go index 071401a11..12621e54a 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -11,8 +11,8 @@ import ( ) type ResourceConfig struct { - Targets types.Set `yaml:"targets"` - Excludes types.Set `yaml:"excludes"` + Targets types.Collection `yaml:"targets"` + Excludes types.Collection `yaml:"excludes"` } type NukeConfig struct { diff --git a/cmd/nuke.go b/cmd/nuke.go index 4aebe2077..826bea4fb 100644 --- a/cmd/nuke.go +++ b/cmd/nuke.go @@ -14,7 +14,7 @@ type Nuke struct { Account awsutil.Account Config *NukeConfig - ResourceTypes types.Set + ResourceTypes types.Collection ForceSleep time.Duration @@ -113,12 +113,12 @@ func (n *Nuke) Scan() error { resourceTypes := ResolveResourceTypes( resources.GetListerNames(), - []types.Set{ + []types.Collection{ n.Parameters.Targets, n.Config.ResourceTypes.Targets, accountConfig.ResourceTypes.Targets, }, - []types.Set{ + []types.Collection{ n.Parameters.Excludes, n.Config.ResourceTypes.Excludes, accountConfig.ResourceTypes.Excludes, diff --git a/cmd/util.go b/cmd/util.go index 361197dd8..5ca8f1f29 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -25,7 +25,7 @@ func Prompt(expect string) error { return nil } -func ResolveResourceTypes(base types.Set, include, exclude []types.Set) types.Set { +func ResolveResourceTypes(base types.Collection, include, exclude []types.Collection) types.Collection { for _, i := range include { if len(i) > 0 { base = base.Intersect(i) diff --git a/cmd/util_test.go b/cmd/util_test.go index c7c6b125b..59c5bdb8b 100644 --- a/cmd/util_test.go +++ b/cmd/util_test.go @@ -10,36 +10,36 @@ import ( func TestResolveResourceTypes(t *testing.T) { cases := []struct { - base types.Set - include []types.Set - exclude []types.Set - result types.Set + base types.Collection + include []types.Collection + exclude []types.Collection + result types.Collection }{ { - base: types.Set{"a", "b", "c", "d"}, - include: []types.Set{types.Set{"a", "b", "c"}}, - result: types.Set{"a", "b", "c"}, + base: types.Collection{"a", "b", "c", "d"}, + include: []types.Collection{types.Collection{"a", "b", "c"}}, + result: types.Collection{"a", "b", "c"}, }, { - base: types.Set{"a", "b", "c", "d"}, - exclude: []types.Set{types.Set{"b", "d"}}, - result: types.Set{"a", "c"}, + base: types.Collection{"a", "b", "c", "d"}, + exclude: []types.Collection{types.Collection{"b", "d"}}, + result: types.Collection{"a", "c"}, }, { - base: types.Set{"a", "b"}, - include: []types.Set{types.Set{}}, - result: types.Set{"a", "b"}, + base: types.Collection{"a", "b"}, + include: []types.Collection{types.Collection{}}, + result: types.Collection{"a", "b"}, }, { - base: types.Set{"c", "b"}, - exclude: []types.Set{types.Set{}}, - result: types.Set{"c", "b"}, + base: types.Collection{"c", "b"}, + exclude: []types.Collection{types.Collection{}}, + result: types.Collection{"c", "b"}, }, { - base: types.Set{"a", "b", "c", "d"}, - include: []types.Set{types.Set{"a", "b", "c"}}, - exclude: []types.Set{types.Set{"a"}}, - result: types.Set{"b", "c"}, + base: types.Collection{"a", "b", "c", "d"}, + include: []types.Collection{types.Collection{"a", "b", "c"}}, + exclude: []types.Collection{types.Collection{"a"}}, + result: types.Collection{"b", "c"}, }, } diff --git a/pkg/types/collection.go b/pkg/types/collection.go new file mode 100644 index 000000000..408a696b6 --- /dev/null +++ b/pkg/types/collection.go @@ -0,0 +1,50 @@ +package types + +type Collection []string + +func (c Collection) Intersect(o Collection) Collection { + mo := o.toMap() + + result := Collection{} + for _, t := range c { + if mo[t] { + result = append(result, t) + } + } + + return result +} + +func (c Collection) Remove(o Collection) Collection { + mo := o.toMap() + + result := Collection{} + for _, t := range c { + if !mo[t] { + result = append(result, t) + } + } + + return result +} + +func (c Collection) Union(o Collection) Collection { + ms := c.toMap() + + result := []string(c) + for _, oi := range o { + if !ms[oi] { + result = append(result, oi) + } + } + + return Collection(result) +} + +func (c Collection) toMap() map[string]bool { + m := map[string]bool{} + for _, t := range c { + m[t] = true + } + return m +} diff --git a/pkg/types/set_test.go b/pkg/types/collection_test.go similarity index 75% rename from pkg/types/set_test.go rename to pkg/types/collection_test.go index 71562d308..95b8bce01 100644 --- a/pkg/types/set_test.go +++ b/pkg/types/collection_test.go @@ -8,8 +8,8 @@ import ( ) func TestSetInterset(t *testing.T) { - s1 := types.Set{"a", "b", "c"} - s2 := types.Set{"b", "a", "d"} + s1 := types.Collection{"a", "b", "c"} + s2 := types.Collection{"b", "a", "d"} r := s1.Intersect(s2) @@ -22,8 +22,8 @@ func TestSetInterset(t *testing.T) { } func TestSetRemove(t *testing.T) { - s1 := types.Set{"a", "b", "c"} - s2 := types.Set{"b", "a", "d"} + s1 := types.Collection{"a", "b", "c"} + s2 := types.Collection{"b", "a", "d"} r := s1.Remove(s2) @@ -36,8 +36,8 @@ func TestSetRemove(t *testing.T) { } func TestSetUnion(t *testing.T) { - s1 := types.Set{"a", "b", "c"} - s2 := types.Set{"b", "a", "d"} + s1 := types.Collection{"a", "b", "c"} + s2 := types.Collection{"b", "a", "d"} r := s1.Union(s2) diff --git a/pkg/types/set.go b/pkg/types/set.go deleted file mode 100644 index 00dc187a9..000000000 --- a/pkg/types/set.go +++ /dev/null @@ -1,50 +0,0 @@ -package types - -type Set []string - -func (s Set) Intersect(o Set) Set { - mo := o.toMap() - - result := Set{} - for _, t := range s { - if mo[t] { - result = append(result, t) - } - } - - return result -} - -func (s Set) Remove(o Set) Set { - mo := o.toMap() - - result := Set{} - for _, t := range s { - if !mo[t] { - result = append(result, t) - } - } - - return result -} - -func (s Set) Union(o Set) Set { - ms := s.toMap() - - result := []string(s) - for _, oi := range o { - if !ms[oi] { - result = append(result, oi) - } - } - - return Set(result) -} - -func (s Set) toMap() map[string]bool { - m := map[string]bool{} - for _, t := range s { - m[t] = true - } - return m -}