github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/imagepublishers/amipublisher/expire.go (about) 1 package amipublisher 2 3 import ( 4 "time" 5 6 "github.com/Cloud-Foundations/Dominator/lib/awsutil" 7 "github.com/Cloud-Foundations/Dominator/lib/log" 8 "github.com/aws/aws-sdk-go/aws" 9 "github.com/aws/aws-sdk-go/service/ec2" 10 ) 11 12 func expireResources(targets awsutil.TargetList, skipList awsutil.TargetList, 13 logger log.Logger) error { 14 currentTime := time.Now() // Need a common "now" time. 15 waitChannel := make(chan struct{}) 16 numTargets, err := awsutil.ForEachTarget(targets, skipList, 17 func(awsService *ec2.EC2, account, region string, logger log.Logger) { 18 expireRegionResources(awsService, currentTime, logger) 19 waitChannel <- struct{}{} 20 }, 21 logger) 22 for i := 0; i < numTargets; i++ { 23 <-waitChannel 24 } 25 return err 26 } 27 28 func expireRegionResources(awsService *ec2.EC2, currentTime time.Time, 29 logger log.Logger) { 30 images, err := awsService.DescribeImages(&ec2.DescribeImagesInput{ 31 Filters: []*ec2.Filter{ 32 { 33 Name: aws.String("tag-key"), 34 Values: aws.StringSlice([]string{"ExpiresAt"}), 35 }, 36 { 37 Name: aws.String("is-public"), 38 Values: aws.StringSlice([]string{"false"}), 39 }, 40 }, 41 }) 42 if err == nil { 43 for _, image := range images.Images { 44 expireImage(awsService, image, currentTime, logger) 45 } 46 } 47 filters := []*ec2.Filter{ 48 { 49 Name: aws.String("tag-key"), 50 Values: aws.StringSlice([]string{"ExpiresAt"}), 51 }, 52 } 53 instances, err := awsService.DescribeInstances(&ec2.DescribeInstancesInput{ 54 Filters: filters, 55 }) 56 if err == nil { 57 for _, reservation := range instances.Reservations { 58 for _, instance := range reservation.Instances { 59 expireInstance(awsService, instance, currentTime, logger) 60 } 61 } 62 } 63 snapshots, err := awsService.DescribeSnapshots(&ec2.DescribeSnapshotsInput{ 64 Filters: filters, 65 }) 66 if err == nil { 67 for _, snapshot := range snapshots.Snapshots { 68 expireSnapshot(awsService, snapshot, currentTime, logger) 69 } 70 } 71 volumes, err := awsService.DescribeVolumes(&ec2.DescribeVolumesInput{ 72 Filters: filters, 73 }) 74 if err == nil { 75 for _, volume := range volumes.Volumes { 76 expireVolume(awsService, volume, currentTime, logger) 77 } 78 } 79 } 80 81 func expireImage(awsService *ec2.EC2, image *ec2.Image, currentTime time.Time, 82 logger log.Logger) { 83 if hasExpired(image.Tags, currentTime) { 84 imageId := aws.StringValue(image.ImageId) 85 if err := deregisterAmi(awsService, imageId); err != nil { 86 logger.Printf("error deleting: %s: %s\n", imageId, err) 87 } else { 88 logger.Printf("deleted: %s\n", imageId) 89 } 90 } 91 } 92 93 func expireInstance(awsService *ec2.EC2, instance *ec2.Instance, 94 currentTime time.Time, logger log.Logger) { 95 if aws.StringValue(instance.State.Name) == ec2.InstanceStateNameTerminated { 96 return 97 } 98 if hasExpired(instance.Tags, currentTime) { 99 instanceId := aws.StringValue(instance.InstanceId) 100 if err := libTerminateInstances(awsService, instanceId); err != nil { 101 logger.Printf("error terminating: %s: %s\n", instanceId, err) 102 } else { 103 logger.Printf("terminated: %s\n", instanceId) 104 } 105 } 106 } 107 108 func expireSnapshot(awsService *ec2.EC2, snapshot *ec2.Snapshot, 109 currentTime time.Time, logger log.Logger) { 110 if hasExpired(snapshot.Tags, currentTime) { 111 snapshotId := aws.StringValue(snapshot.SnapshotId) 112 if err := deleteSnapshot(awsService, snapshotId); err != nil { 113 logger.Printf("error deleting: %s: %s\n", snapshotId, err) 114 } else { 115 logger.Printf("deleted: %s\n", snapshotId) 116 } 117 } 118 } 119 120 func expireVolume(awsService *ec2.EC2, volume *ec2.Volume, 121 currentTime time.Time, logger log.Logger) { 122 if hasExpired(volume.Tags, currentTime) { 123 volumeId := aws.StringValue(volume.VolumeId) 124 if err := deleteVolume(awsService, volumeId); err != nil { 125 logger.Printf("error deleting: %s: %s\n", volumeId, err) 126 } else { 127 logger.Printf("deleted: %s\n", volumeId) 128 } 129 } 130 } 131 132 func hasExpired(tags []*ec2.Tag, currentTime time.Time) bool { 133 for _, tag := range tags { 134 if *tag.Key != "ExpiresAt" { 135 continue 136 } 137 expirationTime, err := time.Parse(ExpiresAtFormat, *tag.Value) 138 if err != nil { 139 continue 140 } 141 return currentTime.After(expirationTime) 142 } 143 return false 144 }