Skip to content

Commit

Permalink
Fix using matchTags and matchNoTags together
Browse files Browse the repository at this point in the history
  • Loading branch information
jckuester committed May 10, 2020
1 parent 24a0f0d commit 9b62601
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 26 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ test: ## Run unit tests
.PHONY: test-all
test-all: ## Run tests (including acceptance and integration tests)
go clean -testcache ${PKG_LIST}
./bin/go-acc ${PKG_LIST} -- -v -$(TESTARGS) -p 1 -race -timeout 30m
./bin/go-acc ${PKG_LIST} -- -v $(TESTARGS) -p 1 -race -timeout 30m

.PHONY: build
build: ## Build binary
Expand Down
8 changes: 2 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Delete resources via a filter declared in a YAML file.
The following filter deletes all EC2 instances that ID matches `^foo.*` and that have been created between
`2018-06-28 12:28:39` and `2018-10-14` UTC (instance filter part 1); additionally, EC2 instances having a tag
`foo: bar` *AND* not a tag key `owner` with arbitrary value are deleted (instance filter part 2); last but not least,
ALL security groups are deleted.
ALL security groups are deleted:

aws_instance:

Expand All @@ -66,8 +66,6 @@ The following filter deletes all EC2 instances that ID matches `^foo.*` and that
The general filter syntax is as follows:

<resource type>:

# filter 1
- id: <regex to filter by id> | NOT(<regex to filter by id>)
tagged: bool (optional)
tags:
Expand All @@ -76,10 +74,8 @@ The general filter syntax is as follows:
created:
before: <timestamp> (optional)
after: <timestamp> (optional)

# filter 2
# OR
- ...

<resource type>:
...

Expand Down
64 changes: 46 additions & 18 deletions resource/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"gopkg.in/yaml.v2"
)

// Filter represents the content of a yaml file that is used filter resources for deletion.
// Filter represents the content of a yaml file that is used to filter resources for deletion.
type Filter map[TerraformResourceType][]TypeFilter

// TypeFilter represents an entry in the yaml file to filter the resources of a particular resource type.
Expand Down Expand Up @@ -121,15 +121,13 @@ func (f TypeFilter) MatchTagged(tags map[string]string) bool {
//
//The keys must match exactly, whereas the tag value is checked against a regex.
func (f TypeFilter) MatchTags(tags map[string]string) bool {
if f.Tags == nil {
tagFilters := notNegatedTags(f.Tags)

if len(tagFilters) == 0 {
return true
}

for key, valueFilter := range f.Tags {
if isNegated(key) {
continue
}

for key, valueFilter := range tagFilters {
value, ok := tags[key]
if !ok {
return false
Expand All @@ -147,25 +145,37 @@ func (f TypeFilter) MatchTags(tags map[string]string) bool {
return true
}

func isNegated(s string) bool {
if strings.HasPrefix(s, "NOT(") && strings.HasSuffix(s, ")") {
// notNegatedTags return the tag keys not surrounded by NOT(...)
func notNegatedTags(tags map[string]StringFilter) map[string]StringFilter {
result := map[string]StringFilter{}

for key, value := range tags {
if isNegatedTagKey(key) {
continue
}

result[key] = value
}

return result
}

func isNegatedTagKey(key string) bool {
if strings.HasPrefix(key, "NOT(") && strings.HasSuffix(key, ")") {
return true
}

return false
}

func (f TypeFilter) MatchNoTags(tags map[string]string) bool {
if f.Tags == nil {
func (f TypeFilter) MatchNegatedTags(tags map[string]string) bool {
tagFilters := negatedTags(f.Tags)

if len(tagFilters) == 0 {
return true
}

for key, valueFilter := range f.Tags {
if !isNegated(key) {
continue
}
key = strings.TrimSuffix(strings.TrimPrefix(key, "NOT("), ")")

for key, valueFilter := range tagFilters {
value, ok := tags[key]
if !ok {
return true
Expand All @@ -183,6 +193,24 @@ func (f TypeFilter) MatchNoTags(tags map[string]string) bool {
return false
}

// notNegatedTags return the tag keys surrounded by NOT(...)
func negatedTags(tags map[string]StringFilter) map[string]StringFilter {
result := map[string]StringFilter{}

for key, value := range tags {
if !isNegatedTagKey(key) {
continue
}

key = strings.TrimSuffix(strings.TrimPrefix(key, "NOT("), ")")

result[key] = value

}

return result
}

func (f TypeFilter) matchCreated(creationTime *time.Time) bool {
if f.Created == nil {
return true
Expand Down Expand Up @@ -219,7 +247,7 @@ func (f Filter) matches(r *Resource) bool {
for _, rtf := range resTypeFilters {
if rtf.MatchTagged(r.Tags) &&
rtf.MatchTags(r.Tags) &&
rtf.MatchNoTags(r.Tags) &&
rtf.MatchNegatedTags(r.Tags) &&
rtf.matchID(r.ID) &&
rtf.matchCreated(r.Created) {
return true
Expand Down
2 changes: 1 addition & 1 deletion resource/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ func TestTypeFilter_MatchNoTags(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.filter.MatchNoTags(tt.tags); got != tt.want {
if got := tt.filter.MatchNegatedTags(tt.tags); got != tt.want {
t.Errorf("MatchTags() = %v, want %v", got, tt.want)
}
})
Expand Down

0 comments on commit 9b62601

Please sign in to comment.