// copyAMI starts the AMI copy func copyAMI(awsec2dest *ec2.EC2, s *session, amis *map[string]string) { if s.destRegion.Name != s.sourceRegion.Name { for amiId, instanceId := range *amis { backupAmiName := fmt.Sprintf("%s-%s-%s", s.instanceNameTag, timeStamp, amiId) backupDesc := fmt.Sprintf("%s %s %s", s.instanceNameTag, timeString, amiId) copyOpts := ec2.CopyImage{ SourceRegion: s.sourceRegion.Name, SourceImageId: amiId, Name: backupAmiName, Description: backupDesc, ClientToken: "", } copyResp, err := awsec2dest.CopyImage(©Opts) if err != nil { s.fatal("EC2 API CopyImage failed") } s.debug(fmt.Sprintf("Started copy of %s from %s (%s) to %s (%s).", s.instanceNameTag, s.sourceRegion.Name, amiId, s.destRegion.Name, copyResp.ImageId)) _, err = awsec2dest.CreateTags([]string{copyResp.ImageId}, []ec2.Tag{ {"hostname", s.instanceNameTag}, {"instance", instanceId}, {"sourceregion", s.sourceRegion.Name}, {"date", timeString}, {"timestamp", timeSecs}, }) if err != nil { s.fatal(fmt.Sprintf("Error tagging new AMI: %s", err.Error())) } } } else { s.debug("Not copying AMI - source and dest regions match") } }
//attachTags makes a call to EC2 to attach the given map of tags to a resource. func attachTags(ec2Handle *ec2.EC2, tags map[string]string, instance string) error { tagSlice := []ec2.Tag{} for tag, value := range tags { tagSlice = append(tagSlice, ec2.Tag{tag, value}) } _, err := ec2Handle.CreateTags([]string{instance}, tagSlice) return err }
// setTags is a helper to set the tags for a resource. It expects the // tags field to be named "tags" func setTags(conn *ec2.EC2, d *schema.ResourceData) error { if d.HasChange("tags") { oraw, nraw := d.GetChange("tags") o := oraw.(map[string]interface{}) n := nraw.(map[string]interface{}) create, remove := diffTags(tagsFromMap(o), tagsFromMap(n)) // Set tags if len(remove) > 0 { log.Printf("[DEBUG] Removing tags: %#v", remove) if _, err := conn.DeleteTags([]string{d.Id()}, remove); err != nil { return err } } if len(create) > 0 { log.Printf("[DEBUG] Creating tags: %#v", create) if _, err := conn.CreateTags([]string{d.Id()}, create); err != nil { return err } } } return nil }
// createAMIs actually creates the AMI(s) func createAMIs(awsec2 *ec2.EC2, instances []ec2.Instance, s *session) map[string]string { newAMIs := make(map[string]string) pendingAMIs := make(map[string]bool) for _, instance := range instances { backupAmiName := fmt.Sprintf("%s-%s-%s", s.instanceNameTag, timeStamp, instance.InstanceId) backupDesc := fmt.Sprintf("%s %s %s", s.instanceNameTag, timeString, instance.InstanceId) blockDevices := []ec2.BlockDeviceMapping{} for _, i := range s.ignoreVolumes { blockDevices = append(blockDevices, ec2.BlockDeviceMapping{DeviceName: i, NoDevice: true}) } createOpts := ec2.CreateImage{ InstanceId: instance.InstanceId, Name: backupAmiName, Description: backupDesc, NoReboot: true, BlockDevices: blockDevices, } resp, err := awsec2.CreateImage(&createOpts) if err != nil { s.fatal(fmt.Sprintf("Error creating new AMI: %s", err.Error())) } _, err = awsec2.CreateTags([]string{resp.ImageId}, []ec2.Tag{ {"hostname", s.instanceNameTag}, {"instance", instance.InstanceId}, {"date", timeString}, {"timestamp", timeSecs}, }) if err != nil { s.fatal(fmt.Sprintf("Error tagging new AMI: %s", err.Error())) } newAMIs[resp.ImageId] = instance.InstanceId pendingAMIs[resp.ImageId] = true s.debug(fmt.Sprintf("Creating new AMI %s for %s (%s)", resp.ImageId, s.instanceNameTag, instance.InstanceId)) } // wait for AMIs to be ready done := make(chan bool) go func() { for len(pendingAMIs) > 0 { s.debug(fmt.Sprintf("Sleeping for %d pending AMIs", len(pendingAMIs))) time.Sleep(apiPollInterval) list := []string{} for k, _ := range pendingAMIs { list = append(list, k) } images, err := awsec2.Images(list, nil) if err != nil { s.fatal("EC2 API Images failed") } for _, image := range images.Images { if image.State == "available" { delete(pendingAMIs, image.Id) s.ok(fmt.Sprintf("Created new AMI %s", image.Id)) } } } done <- true }() select { case <-done: case <-time.After(s.timeout): list := []string{} for k, _ := range pendingAMIs { list = append(list, k) } s.fatal(fmt.Sprintf("Timeout waiting for AMIs in region %s: %s", s.sourceRegion.Name, strings.Join(list, " ,"))) } return newAMIs }