Skip to content

Commit

Permalink
feat: remove ttl and use mark and delete instead
Browse files Browse the repository at this point in the history
Signed-off-by: Carlos Salas <carlos.salas@suse.com>
  • Loading branch information
salasberryfin committed Mar 4, 2024
1 parent a065032 commit ff49900
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 39 deletions.
4 changes: 4 additions & 0 deletions action/cleanup.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import (
"github.com/aws/aws-sdk-go/aws/session"
)

const (
DeletionTag = "aws-janitor/marked-for-deletion"
)

type CleanupScope struct {
Session *session.Session
TTL time.Duration
Expand Down
32 changes: 25 additions & 7 deletions action/cleanup_asg.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package action
import (
"context"
"fmt"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/autoscaling"
Expand All @@ -15,13 +14,12 @@ func (a *action) cleanASGs(ctx context.Context, input *CleanupScope) error {
asgToDelete := []*autoscaling.Group{}
pageFunc := func(page *autoscaling.DescribeAutoScalingGroupsOutput, _ bool) bool {
for _, asg := range page.AutoScalingGroups {
maxAge := asg.CreatedTime.Add(input.TTL)

var ignore bool
var ignore, markedForDeletion bool
for _, tag := range asg.Tags {
if *tag.Key == input.IgnoreTag {
ignore = true
break
} else if *tag.Key == DeletionTag {
markedForDeletion = true
}
}

Expand All @@ -30,8 +28,14 @@ func (a *action) cleanASGs(ctx context.Context, input *CleanupScope) error {
continue
}

if time.Now().Before(maxAge) {
LogDebug("asg %s has max age greater than now, skipping cleanup", *asg.AutoScalingGroupName)
if !markedForDeletion {
// NOTE: only mark for future deletion if we're not running in dry-mode
if a.commit {
LogDebug("asg %s does not have deletion tag, marking for future deletion and skipping cleanup", *asg.AutoScalingGroupName)
if err := a.markAsgForFutureDeletion(ctx, *asg.AutoScalingGroupName, client); err != nil {
LogError("failed to mark asg %s for future deletion: %s", *asg.AutoScalingGroupName, err.Error())
}
}
continue
}

Expand Down Expand Up @@ -77,3 +81,17 @@ func (a *action) cleanASGs(ctx context.Context, input *CleanupScope) error {

return nil
}

func (a *action) markAsgForFutureDeletion(ctx context.Context, asgName string, client *autoscaling.AutoScaling) error {
Log("Marking ASG %s for future deletion", asgName)

_, err := client.CreateOrUpdateTagsWithContext(ctx, &autoscaling.CreateOrUpdateTagsInput{Tags: []*autoscaling.Tag{
{
ResourceId: aws.String(asgName),
Key: aws.String(DeletionTag),
Value: aws.String("true"),
},
}})

return err
}
28 changes: 20 additions & 8 deletions action/cleanup_cf.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package action
import (
"context"
"fmt"
"time"

"github.com/aws/aws-sdk-go/aws"
cf "github.com/aws/aws-sdk-go/service/cloudformation"
Expand All @@ -15,11 +14,12 @@ func (a *action) cleanCfStacks(ctx context.Context, input *CleanupScope) error {
stacksToDelete := []*string{}
pageFunc := func(page *cf.DescribeStacksOutput, _ bool) bool {
for _, stack := range page.Stacks {
var ignore bool
var ignore, markedForDeletion bool
for _, tag := range stack.Tags {
if *tag.Key == input.IgnoreTag {
ignore = true
break
} else if *tag.Key == DeletionTag {
markedForDeletion = true
}
}

Expand All @@ -28,11 +28,15 @@ func (a *action) cleanCfStacks(ctx context.Context, input *CleanupScope) error {
continue
}

maxAge := stack.CreationTime.Add(input.TTL)

if time.Now().Before(maxAge) {
LogDebug("cloudformation stack %s has max age greater than now, skipping cleanup", *stack.StackName)
continue
if !markedForDeletion {
// NOTE: only mark for future deletion if we're not running in dry-mode
if a.commit {
LogDebug("cloudformation stack %s does not have deletion tag, marking for future deletion and skipping cleanup", *stack.StackName)
if err := a.markCfStackForFutureDeletion(ctx, stack, client); err != nil {
LogError("failed to mark cloudformation stack %s for future deletion: %s", *stack.StackName, err.Error())
}
continue
}
}

switch aws.StringValue(stack.StackStatus) {
Expand Down Expand Up @@ -72,6 +76,14 @@ func (a *action) cleanCfStacks(ctx context.Context, input *CleanupScope) error {
return nil
}

func (a *action) markCfStackForFutureDeletion(ctx context.Context, stack *cf.Stack, client *cf.CloudFormation) error {
Log("Marking CloudFormation stack %s for future deletion", *stack.StackName)

stack.SetTags(append(stack.Tags, &cf.Tag{Key: aws.String(DeletionTag), Value: aws.String("true")}))

return nil
}

func (a *action) deleteCfStack(ctx context.Context, stackName string, client *cf.CloudFormation) error {
Log("Deleting CloudFormation stack %s", stackName)

Expand Down
36 changes: 24 additions & 12 deletions action/cleanup_eks.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ package action
import (
"context"
"fmt"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/eks"
)

func (a *action) cleanEKSClusters(ctx context.Context, input *CleanupScope) error {
client := eks.New(input.Session)

clustersToDelete := []*string{}
clustersToDelete := []*eks.Cluster{}
pageFunc := func(page *eks.ListClustersOutput, _ bool) bool {
for _, name := range page.Clusters {
cluster, err := client.DescribeClusterWithContext(ctx, &eks.DescribeClusterInput{
Expand All @@ -27,15 +27,19 @@ func (a *action) cleanEKSClusters(ctx context.Context, input *CleanupScope) erro
continue
}

maxAge := cluster.Cluster.CreatedAt.Add(input.TTL)

if time.Now().Before(maxAge) {
LogDebug("eks cluster %s has max age greater than now, skipping cleanup", *name)
if _, ok := cluster.Cluster.Tags[DeletionTag]; !ok {
// NOTE: only mark for future deletion if we're not running in dry-mode
if a.commit {
LogDebug("eks cluster %s does not have deletion tag, marking for future deletion and skipping cleanup", *name)
if err := a.markEKSClusterForFutureDeletion(ctx, *cluster.Cluster.Arn, client); err != nil {
LogError("failed to mark cluster %s for future deletion: %s", *cluster.Cluster.Arn, err.Error())
}
}
continue
}

LogDebug("adding eks cluster %s to delete list", *name)
clustersToDelete = append(clustersToDelete, name)
clustersToDelete = append(clustersToDelete, cluster.Cluster)
}

return true
Expand All @@ -50,26 +54,34 @@ func (a *action) cleanEKSClusters(ctx context.Context, input *CleanupScope) erro
return nil
}

for _, clusterName := range clustersToDelete {
for _, clusterObj := range clustersToDelete {
if !a.commit {
LogDebug("skipping deletion of eks cluster %s as running in dry-mode", *clusterName)
LogDebug("skipping deletion of eks cluster %s as running in dry-mode", *clusterObj.Name)
continue
}

if err := a.deleteEKSCluster(ctx, *clusterName, client); err != nil {
LogError("failed to delete cluster %s: %s", *clusterName, err.Error())
if err := a.deleteEKSCluster(ctx, *clusterObj.Name, client); err != nil {
LogError("failed to delete cluster %s: %s", *clusterObj.Name, err.Error())
}
}

return nil
}

func (a *action) markEKSClusterForFutureDeletion(ctx context.Context, clusterArn string, client *eks.EKS) error {
Log("Marking EKS cluster %s for future deletion", clusterArn)

_, err := client.TagResourceWithContext(ctx, &eks.TagResourceInput{ResourceArn: &clusterArn, Tags: map[string]*string{DeletionTag: aws.String("true")}})

return err
}

func (a *action) deleteEKSCluster(ctx context.Context, clusterName string, client *eks.EKS) error {
Log("Deleting EKS cluster %s", clusterName)

LogDebug("Deleting nodegroups for cluster %s", clusterName)

listErr := client.ListNodegroupsPagesWithContext(ctx, &eks.ListNodegroupsInput{ClusterName: &clusterName}, func(page *eks.ListNodegroupsOutput, b bool) bool {
listErr := client.ListNodegroupsPagesWithContext(ctx, &eks.ListNodegroupsInput{ClusterName: &clusterName}, func(page *eks.ListNodegroupsOutput, _ bool) bool {
for _, ngName := range page.Nodegroups {
Log("Deleting nodegroup %s in cluster %s", *ngName, clusterName)
if _, err := client.DeleteNodegroupWithContext(ctx, &eks.DeleteNodegroupInput{ClusterName: &clusterName, NodegroupName: ngName}); err != nil {
Expand Down
33 changes: 26 additions & 7 deletions action/cleanup_lb.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package action
import (
"context"
"fmt"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/elb"
)

Expand All @@ -19,12 +19,13 @@ func (a *action) cleanLoadBalancers(ctx context.Context, input *CleanupScope) er
LogError("failed getting tags for load balancer %s: %s", *lb.LoadBalancerName, err.Error())
}

var ignore bool
var ignore, markedForDeletion bool
for _, tagDescription := range tags.TagDescriptions {
for _, tag := range tagDescription.Tags {
if *tag.Key == input.IgnoreTag {
ignore = true
break
} else if *tag.Key == DeletionTag {
markedForDeletion = true
}
}
}
Expand All @@ -34,10 +35,14 @@ func (a *action) cleanLoadBalancers(ctx context.Context, input *CleanupScope) er
continue
}

maxAge := lb.CreatedTime.Add(input.TTL)

if time.Now().Before(maxAge) {
LogDebug("load balancer %s has max age greater than now, skipping cleanup", *lb.LoadBalancerName)
if !markedForDeletion {
// NOTE: only mark for future deletion if we're not running in dry-mode
if a.commit {
LogDebug("load balancer %s does not have deletion tag, marking for future deletion and skipping cleanup", *lb.LoadBalancerName)
if err := a.markLoadBalancerForFutureDeletion(ctx, *lb.LoadBalancerName, client); err != nil {
LogError("failed to mark load balancer %s for future deletion: %s", *lb.LoadBalancerName, err.Error())
}
}
continue
}

Expand Down Expand Up @@ -70,6 +75,20 @@ func (a *action) cleanLoadBalancers(ctx context.Context, input *CleanupScope) er

return nil
}
func (a *action) markLoadBalancerForFutureDeletion(ctx context.Context, lbName string, client *elb.ELB) error {
Log("Marking Load Balancer %s for future deletion", lbName)

_, err := client.AddTagsWithContext(ctx, &elb.AddTagsInput{
LoadBalancerNames: []*string{&lbName},
Tags: []*elb.Tag{
{
Key: aws.String(DeletionTag),
Value: aws.String("true")},
},
})

return err
}

func (a *action) deleteLoadBalancer(ctx context.Context, lbName string, client *elb.ELB) error {
Log("Deleting Load Balancer %s", lbName)
Expand Down
28 changes: 26 additions & 2 deletions action/cleanup_sgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ func (a *action) cleanSecurityGroups(ctx context.Context, input *CleanupScope) e
pageFunc := func(page *ec2.DescribeVpcsOutput, _ bool) bool {
sgPageFunc := func(sgPage *ec2.GetSecurityGroupsForVpcOutput, _ bool) bool {
for _, sg := range sgPage.SecurityGroupForVpcs {
var ignore bool
var ignore, markedForDeletion bool
for _, tag := range sg.Tags {
if *tag.Key == input.IgnoreTag {
ignore = true
break
} else if *tag.Key == DeletionTag {
markedForDeletion = true
}
}

Expand All @@ -29,6 +30,17 @@ func (a *action) cleanSecurityGroups(ctx context.Context, input *CleanupScope) e
continue
}

if !markedForDeletion {
// NOTE: only mark for future deletion if we're not running in dry-mode
if a.commit {
LogDebug("security group %s does not have deletion tag, marking for future deletion and skipping cleanup", *sg.GroupId)
if err := a.markSecurityGroupForFutureDeletion(ctx, *sg.GroupId, client); err != nil {
LogError("failed to mark security group %s for future deletion: %s", *sg.GroupId, err.Error())
}
continue
}
}

securityGroups, err := client.DescribeSecurityGroupsWithContext(ctx, &ec2.DescribeSecurityGroupsInput{GroupIds: []*string{sg.GroupId}})
if err != nil || len(securityGroups.SecurityGroups) != 1 {
LogError("failed to describe security group %s: %s", *sg.GroupId, err.Error())
Expand Down Expand Up @@ -104,6 +116,18 @@ func (a *action) cleanSecurityGroups(ctx context.Context, input *CleanupScope) e
return nil
}

func (a *action) markSecurityGroupForFutureDeletion(ctx context.Context, sgId string, client *ec2.EC2) error {
Log("Marking Security Group %s for future deletion", sgId)

_, err := client.CreateTagsWithContext(ctx, &ec2.CreateTagsInput{
Resources: []*string{&sgId}, Tags: []*ec2.Tag{
{Key: aws.String(DeletionTag), Value: aws.String("true")},
},
})

return err
}

func (a *action) deleteSecurityGroupRules(ctx context.Context, sgId string, sgIngress, sgEgress []*ec2.IpPermission, client *ec2.EC2) error {
Log("Deleting Ingress/Egress Rules from security group %s", sgId)

Expand Down
6 changes: 3 additions & 3 deletions action/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ func (i *Input) Validate() error {
err = multierr.Append(err, ErrAllRegionsNotAllowed)
}

if i.TTL.Seconds() == 0 {
err = multierr.Append(err, ErrTTLRequired)
}
//if i.TTL.Seconds() == 0 {
// err = multierr.Append(err, ErrTTLRequired)
//}

return err
}

0 comments on commit ff49900

Please sign in to comment.