Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into add-volumes, had to…
Browse files Browse the repository at this point in the history
… modify config to run

* origin/master:
  fix link generation using reapable ID twice instead of reapable region
  make shared filters consistent across resources
  add initial FILTERS.md, modify some filters to make more sense
  fix initial state to avoid race condition
  • Loading branch information
Miles Crabill committed Apr 7, 2016
2 parents 5178d6d + e4a9d08 commit 1c92a77
Show file tree
Hide file tree
Showing 11 changed files with 379 additions and 121 deletions.
184 changes: 184 additions & 0 deletions FILTERS.md
@@ -0,0 +1,184 @@
# Filters

## About Filters

Filters are implemented per resource. To use a filter for a resource, add it to a filtergroup in that resource's section of your configuration file.

For example:

```
[AutoScalingGroups]
Enabled = false
[AutoScalingGroups.FilterGroups]
[AutoScalingGroups.FilterGroups.ExampleGroup]
[AutoScalingGroups.FilterGroups.ExampleGroup.SizeGreaterThan1]
function = "SizeGreaterThanOrEqualTo"
arguments = ["1"]
```

Here, we have a filter called `SizeGreaterThan1`, which calls the function `SizeGreaterThanOrEqualTo` with the arguments `["1"]`. `SizeGreaterThan1` is in a filtergroup called `ExampleGroup`.

_All filters take an array of arguments. Many filters take a single argument. All arguments are quoted._

## Filter Types:

#### Boolean Filters:

These filters take a single argument, a string that is parsed to a boolean value that is compared with the resource's value for the specified function. This boolean value can be anything parseable by Go's strconv.ParseBool. See: http://golang.org/pkg/strconv/#ParseBool.

#### String Filters:

These filters take a single argument (except where noted), a string that is compared with the resource's value for the specified function.

#### Time Filters:

These filters take a single argument, a string that is parsed to a time in RFC3339 format (parseable by http://godoc.org/time#Parse) or a duration (see: http://godoc.org/time#ParseDuration).

#### Integer Filters:

These filters take a single argument, a string that is parsed to an int64 and compared with the resource's value for the specified function.

## Shared Filters (All Resource Types)

#### Boolean Filters:

- IsDependency
+ Whether the resource is a dependency for another resource (a bit abstract)
+ Currently, a resource is a dependency if any of the following are satisfied:
* the resource is in the list of resources of a Cloudformation
* the resource is in an AutoScalingGroup
* the resource is a SecurityGroup used by an Instance

#### String Filters:

- Tagged
+ True if the resource has a tag equal to the input string
- NotTagged
+ True if the resource does not have a tag equal to the input string
- Tag (takes two arguments)
+ argument 1: the key of a tag
+ argument 2: the value of that tag
+ True if the resource has a tag equal to the first argument with a value equal to the second
- TagNotEqual (takes two arguments)
+ argument 1: the key of a tag
+ argument 2: the value of that tag
+ True if the resource does not have a tag equal to the first argument with a value equal to the second
- Region (takes any number of arguments)
+ True if the resource's region matches the input string
- NotRegion
+ True if the resource's region does not match the input string
- ReaperState:
+ True if the resource's ReaperState is equal to the input string
+ One of:
* FirstState
* SecondState
* ThirdState
* FinalState
* IgnoreState
- NotReaperState:
+ True if the resource's ReaperState is not equal to the input string
- NameContains:
+ True if the resource's name contains the input string
- NotNameContains:
+ True if the resource's name does not contain the input string
- Named:
+ True if the resource's name is equal to the input string
- NotNamed:
+ True if the resource's name is not equal to the input string

## Instance Only Filters:

#### Boolean Filters:

- InCloudformation
+ Whether the Instance is in a Cloudformation (directly)
- HasPublicIPAddress
+ True if the Instance has a public IP address
- AutoScaled
+ True if the Instance is in an AutoScalingGroup

#### String Filters:

- InstanceType
+ True if the InstanceType of the Instance matches the input string
- State
+ True if the Instance's State matches the input string
+ One of:
* pending
* running
* shutting-down
* terminated
* stopping
* stopped
- PublicIPAddress
+ True if the public IP address of the Instance matches the input string

#### Time Filters:

- LaunchTimeBefore
+ True if the Instance's LaunchTime is before time input time
- LaunchTimeAfter
+ True if the Instance's LaunchTime is after time input time
- LaunchTimeInTheLast
+ True if the Instance's LaunchTime is within the input duration
- LaunchTimeNotInTheLast
+ True if the Instance's LaunchTime is not within the input duration


## AutoScalingGroup Only Filters

#### Time Filters:

- InCloudformation
+ Whether the AutoScalingGroup is in a Cloudformation (directly)
- CreatedTimeInTheLast
+ True if the AutoScalingGroup's CreatedTime is within the input duration
- CreatedTimeNotInTheLast
+ True if the AutoScalingGroup's CreatedTime is not within the input duration

#### Integer Filters:

- SizeGreaterThan
+ True if the AutoScalingGroup's DesiredCapacity is greater than the input size
- SizeLessThan
+ True if the AutoScalingGroup's DesiredCapacity is less than the input size
- SizeEqualTo
+ True if the AutoScalingGroup's DesiredCapacity is equal to the input size
- SizeLessThanOrEqualTo
+ True if the AutoScalingGroup's DesiredCapacity is less than or equal to the input size
- SizeGreaterThanOrEqualTo
+ True if the AutoScalingGroup's DesiredCapacity is greater than or equal to the input size

## Cloudformation Only Filters

#### String Filters:

- Status
+ True if the Status of the Cloudformation matches the input string
* One of:
- CREATE_COMPLETE
- CREATE_IN_PROGRESS
- CREATE_FAILED
- DELETE_COMPLETE
- DELETE_FAILED
- DELETE_IN_PROGRESS
- ROLLBACK_COMPLETE
- ROLLBACK_FAILED
- ROLLBACK_IN_PROGRESS
- UPDATE_COMPLETE
- UPDATE_COMPLETE_CLEANUP_IN_PROGRESS
- UPDATE_IN_PROGRESS
- UPDATE_ROLLBACK_COMPLETE
- UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS
- UPDATE_ROLLBACK_FAILED
- UPDATE_ROLLBACK_IN_PROGRESS
- NotStatus
+ True if the Status of the Cloudformation does not match the input string

#### Time Filters:

- CreatedTimeInTheLast
+ True if the Cloudformation's CreatedTime is within the input duration
- CreatedTimeNotInTheLast
+ True if the Cloudformation's CreatedTime is not within the input duration
63 changes: 43 additions & 20 deletions aws/autoscaling.go
Expand Up @@ -118,9 +118,7 @@ func NewAutoScalingGroup(region string, asg *autoscaling.Group) *AutoScalingGrou
a.reaperState = state.NewStateWithTag(a.Tag(reaperTag))
} else {
// initial state
a.reaperState = state.NewStateWithUntilAndState(
time.Now().Add(config.Notifications.FirstStateDuration.Duration),
state.FirstState)
a.reaperState = state.NewState()
}

return &a
Expand Down Expand Up @@ -417,42 +415,63 @@ func (a *AutoScalingGroup) Filter(filter filters.Filter) bool {
if i, err := filter.Int64Value(0); err == nil && a.sizeGreaterThanOrEqualTo(i) {
matched = true
}
case "Tagged":
if a.Tagged(filter.Arguments[0]) {
case "CreatedTimeInTheLast":
d, err := time.ParseDuration(filter.Arguments[0])
if err == nil && a.CreatedTime != nil && time.Since(*a.CreatedTime) < d {
matched = true
}
case "NotTagged":
if !a.Tagged(filter.Arguments[0]) {
case "CreatedTimeNotInTheLast":
d, err := time.ParseDuration(filter.Arguments[0])
if err == nil && a.CreatedTime != nil && time.Since(*a.CreatedTime) > d {
matched = true
}
case "TagNotEqual":
if a.Tag(filter.Arguments[0]) != filter.Arguments[1] {
case "InCloudformation":
if b, err := filter.BoolValue(0); err == nil && a.IsInCloudformation == b {
matched = true
}
case "Region":
for region := range filter.Arguments {
for _, region := range filter.Arguments {
if a.Region == reapable.Region(region) {
matched = true
}
}
case "NotRegion":
for region := range filter.Arguments {
// was this resource's region one of those in the NOT list
regionSpecified := false
for _, region := range filter.Arguments {
if a.Region == reapable.Region(region) {
matched = false
regionSpecified = true
}
}
case "CreatedTimeInTheLast":
d, err := time.ParseDuration(filter.Arguments[0])
if err == nil && a.CreatedTime != nil && time.Since(*a.CreatedTime) < d {
if !regionSpecified {
matched = true
}
case "CreatedTimeNotInTheLast":
d, err := time.ParseDuration(filter.Arguments[0])
if err == nil && a.CreatedTime != nil && time.Since(*a.CreatedTime) > d {
case "Tagged":
if a.Tagged(filter.Arguments[0]) {
matched = true
}
case "InCloudformation":
if b, err := filter.BoolValue(0); err == nil && a.IsInCloudformation == b {
case "NotTagged":
if !a.Tagged(filter.Arguments[0]) {
matched = true
}
case "TagNotEqual":
if a.Tag(filter.Arguments[0]) != filter.Arguments[1] {
matched = true
}
case "ReaperState":
if a.reaperState.State.String() == filter.Arguments[0] {
matched = true
}
case "NotReaperState":
if a.reaperState.State.String() != filter.Arguments[0] {
matched = true
}
case "Named":
if a.Name == filter.Arguments[0] {
matched = true
}
case "NotNamed":
if a.Name != filter.Arguments[0] {
matched = true
}
case "IsDependency":
Expand All @@ -463,6 +482,10 @@ func (a *AutoScalingGroup) Filter(filter filters.Filter) bool {
if strings.Contains(a.Name, filter.Arguments[0]) {
matched = true
}
case "NotNameContains":
if !strings.Contains(a.Name, filter.Arguments[0]) {
matched = true
}
default:
log.Error("No function %s could be found for filtering AutoScalingGroups.", filter.Function)
}
Expand Down
53 changes: 44 additions & 9 deletions aws/cloudformation.go
Expand Up @@ -62,9 +62,7 @@ func NewCloudformation(region string, stack *cloudformation.Stack) *Cloudformati
a.reaperState = state.NewStateWithTag(a.Resource.Tag(reaperTag))
} else {
// initial state
a.reaperState = state.NewStateWithUntilAndState(
time.Now().Add(config.Notifications.FirstStateDuration.Duration),
state.FirstState)
a.reaperState = state.NewState()
}

return &a
Expand Down Expand Up @@ -242,6 +240,33 @@ func (a *Cloudformation) Filter(filter filters.Filter) bool {
if a.StackStatus != nil && *a.StackStatus != filter.Arguments[0] {
matched = true
}
case "CreatedTimeInTheLast":
d, err := time.ParseDuration(filter.Arguments[0])
if err == nil && a.CreationTime != nil && time.Since(*a.CreationTime) < d {
matched = true
}
case "CreatedTimeNotInTheLast":
d, err := time.ParseDuration(filter.Arguments[0])
if err == nil && a.CreationTime != nil && time.Since(*a.CreationTime) > d {
matched = true
}
case "Region":
for _, region := range filter.Arguments {
if a.Region == reapable.Region(region) {
matched = true
}
}
case "NotRegion":
// was this resource's region one of those in the NOT list
regionSpecified := false
for _, region := range filter.Arguments {
if a.Region == reapable.Region(region) {
regionSpecified = true
}
}
if !regionSpecified {
matched = true
}
case "Tagged":
if a.Tagged(filter.Arguments[0]) {
matched = true
Expand All @@ -254,14 +279,20 @@ func (a *Cloudformation) Filter(filter filters.Filter) bool {
if a.Tag(filter.Arguments[0]) != filter.Arguments[1] {
matched = true
}
case "CreatedTimeInTheLast":
d, err := time.ParseDuration(filter.Arguments[0])
if err == nil && a.CreationTime != nil && time.Since(*a.CreationTime) < d {
case "ReaperState":
if a.reaperState.State.String() == filter.Arguments[0] {
matched = true
}
case "CreatedTimeNotInTheLast":
d, err := time.ParseDuration(filter.Arguments[0])
if err == nil && a.CreationTime != nil && time.Since(*a.CreationTime) > d {
case "NotReaperState":
if a.reaperState.State.String() != filter.Arguments[0] {
matched = true
}
case "Named":
if a.Name == filter.Arguments[0] {
matched = true
}
case "NotNamed":
if a.Name != filter.Arguments[0] {
matched = true
}
case "IsDependency":
Expand All @@ -272,6 +303,10 @@ func (a *Cloudformation) Filter(filter filters.Filter) bool {
if strings.Contains(a.Name, filter.Arguments[0]) {
matched = true
}
case "NotNameContains":
if !strings.Contains(a.Name, filter.Arguments[0]) {
matched = true
}
default:
log.Error("No function %s could be found for filtering Cloudformations.", filter.Function)
}
Expand Down
4 changes: 2 additions & 2 deletions aws/http.go
Expand Up @@ -24,7 +24,7 @@ func makeScheduleLink(region reapable.Region, id reapable.ID, tokenSecret, apiUR
// MakeTerminateLink creates a tokenized link scheduling a resource
func makeTerminateLink(region reapable.Region, id reapable.ID, tokenSecret, apiURL string) (string, error) {
term, err := token.Tokenize(tokenSecret,
token.NewTerminateJob(id.String(), id.String()))
token.NewTerminateJob(region.String(), id.String()))

if err != nil {
return "", err
Expand All @@ -37,7 +37,7 @@ func makeTerminateLink(region reapable.Region, id reapable.ID, tokenSecret, apiU
func makeIgnoreLink(region reapable.Region, id reapable.ID, tokenSecret, apiURL string,
duration time.Duration) (string, error) {
delay, err := token.Tokenize(tokenSecret,
token.NewDelayJob(id.String(), id.String(),
token.NewDelayJob(region.String(), id.String(),
duration))

if err != nil {
Expand Down

0 comments on commit 1c92a77

Please sign in to comment.