// purgeAMIs purges AMIs based on specified windows func purgeAMIs(awsec2 *ec2.EC2, instanceNameTag string, windows []window, s *session) error { filter := ec2.NewFilter() filter.Add("tag:hostname", instanceNameTag) imageList, err := awsec2.Images(nil, filter) if err != nil { return fmt.Errorf("EC2 API Images failed: %s", err.Error()) } s.debug(fmt.Sprintf("Found %d total images for %s in %s", len(imageList.Images), instanceNameTag, awsec2.Region.Name)) images := map[string]time.Time{} for _, image := range imageList.Images { timestampTag := "" for _, tag := range image.Tags { if tag.Key == "timestamp" { timestampTag = tag.Value } } if len(timestampTag) < 1 { s.debug(fmt.Sprintf("AMI is missing timestamp tag - skipping: %s", image.Id)) continue } timestamp, err := strconv.ParseInt(timestampTag, 10, 64) if err != nil { s.debug(fmt.Sprintf("AMI timestamp tag is corrupt - skipping: %s", image.Id)) continue } images[image.Id] = time.Unix(timestamp, 0) } for _, window := range windows { s.debug(fmt.Sprintf("Window: 1 per %s from %s-%s", window.interval.String(), window.start, window.stop)) for cursor := window.start; cursor.Before(window.stop); cursor = cursor.Add(window.interval) { imagesInThisInterval := []string{} imagesTimes := make(map[string]time.Time) oldestImage := "" oldestImageTime := time.Now() for id, when := range images { if when.After(cursor) && when.Before(cursor.Add(window.interval)) { imagesInThisInterval = append(imagesInThisInterval, id) imagesTimes[id] = when if when.Before(oldestImageTime) { oldestImageTime = when oldestImage = id } } } if len(imagesInThisInterval) > 1 { for _, id := range imagesInThisInterval { if id == oldestImage { // keep the oldest one s.debug(fmt.Sprintf("Keeping oldest AMI in this window: %s @ %s (%s->%s)", id, imagesTimes[id].Format(timeShortFormat), window.start.Format(timeShortFormat), window.stop.Format(timeShortFormat))) continue } // find snapshots associated with this AMI. snaps, err := findSnapshots(id, awsec2) if err != nil { return fmt.Errorf("EC2 API findSnapshots failed for %s: %s", id, err.Error()) } // deregister the AMI. resp, err := awsec2.DeregisterImage(id) if err != nil { return fmt.Errorf("EC2 API DeregisterImage failed for %s: %s", id, err.Error()) } if resp.Return != true { return fmt.Errorf("EC2 API DeregisterImage error for %s", id) } // delete snapshots associated with this AMI. for snap, _ := range snaps { if _, err := awsec2.DeleteSnapshots([]string{snap}); err != nil { return fmt.Errorf("EC2 API DeleteSnapshot failed: %s", err.Error()) } } s.debug(fmt.Sprintf("Purged old AMI %s @ %s (%s->%s)", id, imagesTimes[id].Format(timeShortFormat), window.start.Format(timeShortFormat), window.stop.Format(timeShortFormat))) } } } } return nil }