Example #1
0
// 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
}