Skip to content

Commit

Permalink
add logic for tag_exist, part of gruntwork-io#822.
Browse files Browse the repository at this point in the history
  • Loading branch information
wakeful committed Dec 24, 2024
1 parent f2f26a8 commit f67b0de
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 9 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,14 @@ s3:
exclude:
tag: 'foo'
```

You can also exclude a resource by specifying only the tag key.

```yaml
s3:
exclude:
tag_exist: 'bar'
```
#### Timeout
You have the flexibility to set individual timeout options for specific resources. The execution will pause until the designated timeout is reached for each resource.
```yaml
Expand Down
42 changes: 34 additions & 8 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ type FilterRule struct {
TimeAfter *time.Time `yaml:"time_after"`
TimeBefore *time.Time `yaml:"time_before"`
Tag *string `yaml:"tag"` // A tag to filter resources by. (e.g., If set under ExcludedRule, resources with this tag will be excluded).
TagExist *string `yaml:"tag_exist"`
}

type Expression struct {
Expand Down Expand Up @@ -401,17 +402,40 @@ func (r ResourceType) ShouldIncludeBasedOnTag(tags map[string]string) bool {
}

if r.ProtectUntilExpire {
// Check if the tags contain "cloud-nuke-after" and if the date is before today.
if value, ok := tags[CloudNukeAfterExclusionTagKey]; ok {
nukeDate, err := ParseTimestamp(value)
if err == nil {
if !nukeDate.Before(time.Now()) {
logging.Debugf("[Skip] the resource is protected until %v", nukeDate)
return false
}
return nukeAfterTagValue(tags)
}

return true
}

func nukeAfterTagValue(tags map[string]string) bool {
// Check if the tags contain "cloud-nuke-after" and if the date is before today.
if value, ok := tags[CloudNukeAfterExclusionTagKey]; ok {
nukeDate, err := ParseTimestamp(value)
if err == nil {
if !nukeDate.Before(time.Now()) {
logging.Debugf("[Skip] the resource is protected until %v", nukeDate)
return false
}
}
}

return true
}

func (r ResourceType) ShouldIncludeBasedOnTagName(tags map[string]string) bool {
if r.ExcludeRule.TagExist != nil {
tagName := *r.ExcludeRule.TagExist

if _, ok := tags[tagName]; ok {
return false
}
}

if r.ProtectUntilExpire {
return nukeAfterTagValue(tags)
}

return true
}

Expand All @@ -422,6 +446,8 @@ func (r ResourceType) ShouldInclude(value ResourceValue) bool {
return false
} else if value.Tags != nil && len(value.Tags) != 0 && !r.ShouldIncludeBasedOnTag(value.Tags) {
return false
} else if value.Tags != nil && len(value.Tags) != 0 && !r.ShouldIncludeBasedOnTagName(value.Tags) {
return false
}

return true
Expand Down
100 changes: 99 additions & 1 deletion config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,105 @@ func TestShouldIncludeWithTags(t *testing.T) {
ACM: ResourceType{},
}

assert.Equal(t, tt.want, testConfig.ACM.ShouldInclude(ResourceValue{
require.Equal(t, tt.want, testConfig.ACM.ShouldInclude(ResourceValue{
Tags: tt.tags,
}))
})
}
}

func TestShouldIncludeBasedOnTagName(t *testing.T) {
timeIn2h := time.Now().Add(2 * time.Hour)

type arg struct {
ExcludeRule FilterRule
ProtectUntilExpire bool
}
tests := []struct {
name string
fields arg
when map[string]string
expected bool
}{
{
name: "should include if no tag set",
fields: arg{},
when: nil,
expected: true,
},
{
name: "should exclude if tag was found",
fields: arg{
ExcludeRule: FilterRule{
TagExist: aws.String("if-this-tag-exist-skip-resource"),
},
},
when: map[string]string{"if-this-tag-exist-skip-resource": "true"},
expected: false,
},

{
name: "should skip resource with protect until expire is set",
fields: arg{
ExcludeRule: FilterRule{},
ProtectUntilExpire: true,
},
when: map[string]string{CloudNukeAfterExclusionTagKey: timeIn2h.Format(time.RFC3339)},
expected: false,
},
{
name: "should include resource with if protection expire is in the past",
fields: arg{
ExcludeRule: FilterRule{},
ProtectUntilExpire: true,
},
when: map[string]string{CloudNukeAfterExclusionTagKey: time.Now().Format(time.RFC3339)},
expected: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := ResourceType{
ExcludeRule: tt.fields.ExcludeRule,
ProtectUntilExpire: tt.fields.ProtectUntilExpire,
}

require.Equal(t, tt.expected, r.ShouldIncludeBasedOnTagName(tt.when))
})
}
}

func TestResourceType_ShouldInclude(t *testing.T) {
tests := []struct {
name string
excludeRule FilterRule
tags map[string]string
want bool
}{
{
name: "should include if no config pass",
want: true,
},
{
name: "skip if tag with given name was found",
excludeRule: FilterRule{
TagExist: aws.String("if-this-tag-exist-skip-resource"),
},
tags: map[string]string{"if-this-tag-exist-skip-resource": "true"},
want: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
testConfig := &Config{
ACM: ResourceType{
ExcludeRule: tt.excludeRule,
},
}

require.Equal(t, tt.want, testConfig.ACM.ShouldInclude(ResourceValue{
Tags: tt.tags,
}))
})
Expand Down

0 comments on commit f67b0de

Please sign in to comment.