func resource_aws_internet_gateway_attach( ec2conn *ec2.EC2, s *terraform.ResourceState, vpcId string) error { log.Printf( "[INFO] Attaching Internet Gateway '%s' to VPC '%s'", s.ID, vpcId) _, err := ec2conn.AttachInternetGateway(s.ID, vpcId) if err != nil { return err } // Wait for it to be fully attached before continuing log.Printf("[DEBUG] Waiting for internet gateway (%s) to attach", s.ID) stateConf := &resource.StateChangeConf{ Pending: []string{"detached", "attaching"}, Target: "available", Refresh: IGAttachStateRefreshFunc(ec2conn, s.ID, "available"), Timeout: 1 * time.Minute, } if _, err := stateConf.WaitForState(); err != nil { return fmt.Errorf( "Error waiting for internet gateway (%s) to attach: %s", s.ID, err) } return nil }
func waitForState(ec2conn *ec2.EC2, originalInstance *ec2.Instance, pending []string, target string) (i *ec2.Instance, err error) { log.Printf("Waiting for instance state to become: %s", target) i = originalInstance for i.State.Name != target { found := false for _, allowed := range pending { if i.State.Name == allowed { found = true break } } if !found { fmt.Errorf("unexpected state '%s', wanted target '%s'", i.State.Name, target) return } var resp *ec2.InstancesResp resp, err = ec2conn.Instances([]string{i.InstanceId}, ec2.NewFilter()) if err != nil { return } i = &resp.Reservations[0].Instances[0] time.Sleep(2 * time.Second) } return }
// 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") } }
// SSHAddress returns a function that can be given to the SSH communicator // for determining the SSH address based on the instance DNS name. func SSHAddress(e *ec2.EC2, port int) func(multistep.StateBag) (string, error) { return func(state multistep.StateBag) (string, error) { for j := 0; j < 2; j++ { var host string i := state.Get("instance").(*ec2.Instance) if i.DNSName != "" { host = i.DNSName } else if i.VpcId != "" { if i.PublicIpAddress != "" { host = i.PublicIpAddress } else { host = i.PrivateIpAddress } } if host != "" { return fmt.Sprintf("%s:%d", host, port), nil } r, err := e.Instances([]string{i.InstanceId}, ec2.NewFilter()) if err != nil { return "", err } if len(r.Reservations) == 0 || len(r.Reservations[0].Instances) == 0 { return "", fmt.Errorf("instance not found: %s", i.InstanceId) } state.Put("instance", &r.Reservations[0].Instances[0]) time.Sleep(1 * time.Second) } return "", errors.New("couldn't determine IP address for instance") } }
// InstanceStateRefreshFunc returns a StateRefreshFunc that is used to watch // an EC2 instance. func InstanceStateRefreshFunc(conn *ec2.EC2, i *ec2.Instance) StateRefreshFunc { return func() (interface{}, string, error) { resp, err := conn.Instances([]string{i.InstanceId}, ec2.NewFilter()) if err != nil { if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" { // Set this to nil as if we didn't find anything. resp = nil } else if isTransientNetworkError(err) { // Transient network error, treat it as if we didn't find anything resp = nil } else { log.Printf("Error on InstanceStateRefresh: %s", err) return nil, "", err } } if resp == nil || len(resp.Reservations) == 0 || len(resp.Reservations[0].Instances) == 0 { // Sometimes AWS just has consistency issues and doesn't see // our instance yet. Return an empty state. return nil, "", nil } i = &resp.Reservations[0].Instances[0] return i, i.State.Name, nil } }
// SpotRequestStateRefreshFunc returns a StateRefreshFunc that is used to watch // a spot request for state changes. func SpotRequestStateRefreshFunc(conn *ec2.EC2, spotRequestId string) StateRefreshFunc { return func() (interface{}, string, error) { resp, err := conn.DescribeSpotRequests([]string{spotRequestId}, ec2.NewFilter()) if err != nil { if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidSpotInstanceRequestID.NotFound" { // Set this to nil as if we didn't find anything. resp = nil } else if isTransientNetworkError(err) { // Transient network error, treat it as if we didn't find anything resp = nil } else { log.Printf("Error on SpotRequestStateRefresh: %s", err) return nil, "", err } } if resp == nil || len(resp.SpotRequestResults) == 0 { // Sometimes AWS has consistency issues and doesn't see the // SpotRequest. Return an empty state. return nil, "", nil } i := resp.SpotRequestResults[0] return i, i.State, nil } }
// Returns a single address by its ID func resource_aws_eip_retrieve_address(id string, vpc bool, ec2conn *ec2.EC2) (*ec2.Address, error) { // Get the full address description for saving to state for // use in other resources assocIds := []string{} publicIps := []string{} if vpc { assocIds = []string{id} } else { publicIps = []string{id} } log.Printf("[DEBUG] EIP describe configuration: %#v, %#v (vpc: %v)", assocIds, publicIps, vpc) describeAddresses, err := ec2conn.Addresses(publicIps, assocIds, nil) if err != nil { return nil, fmt.Errorf("Error retrieving EIP: %s", err) } // Verify AWS returned our EIP if len(describeAddresses.Addresses) != 1 || describeAddresses.Addresses[0].AllocationId != id || describeAddresses.Addresses[0].PublicIp != id { if err != nil { return nil, fmt.Errorf("Unable to find EIP: %#v", describeAddresses.Addresses) } } address := describeAddresses.Addresses[0] return &address, nil }
// SGStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch // a security group. func SGStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { sgs := []ec2.SecurityGroup{ec2.SecurityGroup{Id: id}} resp, err := conn.SecurityGroups(sgs, nil) if err != nil { if ec2err, ok := err.(*ec2.Error); ok { if ec2err.Code == "InvalidSecurityGroupID.NotFound" || ec2err.Code == "InvalidGroup.NotFound" { resp = nil err = nil } } if err != nil { log.Printf("Error on SGStateRefresh: %s", err) return nil, "", err } } if resp == nil { return nil, "", nil } group := &resp.Groups[0] return group, "exists", nil } }
func terminateInstances(c *C, e *ec2.EC2, insts []*ec2.Instance) { var ids []string for _, inst := range insts { if inst != nil { ids = append(ids, inst.InstanceId) } } _, err := e.TerminateInstances(ids) c.Check(err, IsNil, Commentf("%d INSTANCES LEFT RUNNING!!!", len(ids))) }
//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 }
// InstanceStateRefreshFunc returns a StateRefreshFunc that is used to watch // an EC2 instance. func InstanceStateRefreshFunc(conn *ec2.EC2, i *ec2.Instance) StateRefreshFunc { return func() (interface{}, string, error) { resp, err := conn.Instances([]string{i.InstanceId}, ec2.NewFilter()) if err != nil { return nil, "", err } i = &resp.Reservations[0].Instances[0] return i, i.State.Name, nil } }
func resource_aws_internet_gateway_detach( ec2conn *ec2.EC2, s *terraform.ResourceState) error { if s.Attributes["vpc_id"] == "" { return nil } log.Printf( "[INFO] Detaching Internet Gateway '%s' from VPC '%s'", s.ID, s.Attributes["vpc_id"]) wait := true _, err := ec2conn.DetachInternetGateway(s.ID, s.Attributes["vpc_id"]) if err != nil { ec2err, ok := err.(*ec2.Error) if ok { if ec2err.Code == "InvalidInternetGatewayID.NotFound" { err = nil wait = false } else if ec2err.Code == "Gateway.NotAttached" { err = nil wait = false } } if err != nil { return err } } delete(s.Attributes, "vpc_id") if !wait { return nil } // Wait for it to be fully detached before continuing log.Printf("[DEBUG] Waiting for internet gateway (%s) to detach", s.ID) stateConf := &resource.StateChangeConf{ Pending: []string{"attached", "detaching", "available"}, Target: "detached", Refresh: IGAttachStateRefreshFunc(ec2conn, s.ID, "detached"), Timeout: 1 * time.Minute, } if _, err := stateConf.WaitForState(); err != nil { return fmt.Errorf( "Error waiting for internet gateway (%s) to detach: %s", s.ID, err) } return nil }
// findInstances searches for our instances func findInstances(awsec2 *ec2.EC2, s *session) []ec2.Instance { filter := ec2.NewFilter() filter.Add("tag:Name", s.instanceNameTag) resp, err := awsec2.Instances(nil, filter) if err != nil { s.fatal(fmt.Sprintf("EC2 API DescribeInstances failed: %s", err.Error())) } instances := []ec2.Instance{} for _, reservation := range resp.Reservations { for _, instance := range reservation.Instances { instances = append(instances, instance) } } return instances }
// findSnapshots returns a map of snapshots associated with an AMI func findSnapshots(amiid string, awsec2 *ec2.EC2) (map[string]string, error) { snaps := make(map[string]string) resp, err := awsec2.Images([]string{amiid}, nil) if err != nil { return snaps, fmt.Errorf("EC2 API DescribeImages failed: %s", err.Error()) } for _, image := range resp.Images { for _, bd := range image.BlockDevices { if len(bd.SnapshotId) > 0 { snaps[bd.SnapshotId] = bd.DeviceName } } } return snaps, nil }
// WaitForAMI waits for the given AMI ID to become ready. func WaitForAMI(c *ec2.EC2, imageId string) error { for { imageResp, err := c.Images([]string{imageId}, ec2.NewFilter()) if err != nil { return err } if imageResp.Images[0].State == "available" { return nil } log.Printf("Image in state %s, sleeping 2s before checking again", imageResp.Images[0].State) time.Sleep(2 * time.Second) } }
// InstanceStateRefreshFunc returns a StateRefreshFunc that is used to watch // an EC2 instance. func InstanceStateRefreshFunc(conn *ec2.EC2, i *ec2.Instance) StateRefreshFunc { return func() (interface{}, string, error) { resp, err := conn.Instances([]string{i.InstanceId}, ec2.NewFilter()) if err != nil { log.Printf("Error on InstanceStateRefresh: %s", err) return nil, "", err } if len(resp.Reservations) == 0 || len(resp.Reservations[0].Instances) == 0 { // Sometimes AWS just has consistency issues and doesn't see // our instance yet. Return an empty state. return nil, "", nil } i = &resp.Reservations[0].Instances[0] return i, i.State.Name, nil } }
func (client *Client) ListRegion(c chan []types.Ship, parameters url.Values, region *ec2.EC2) { log.Infof("List Instances for Region %s", region.Name) var final []types.Ship filter := ec2.NewFilter() filter.Add("tag-key", "docker") resp, err := region.Instances(nil, filter) if err != nil { c <- final } for _, pool := range resp.Reservations { for _, ship := range pool.Instances { if client.State(ship.State) != "end" { final = append(final, types.Ship{ship.InstanceId, client.SearchTag(ship.Tags, "Name"), ship.DNSName, ship.PublicIpAddress, client.State(ship.State), "Ubuntu 14.04", ship.InstanceType, 27017, "http", 0, nil, false}) } } } c <- final }
//getInstanceInfo returns the full ec2 instance info for the given instance ID. //Note that this is the *instance* id, not the spot request ID, which is different. func getInstanceInfo(ec2Handle *ec2.EC2, instanceId string) (*ec2.Instance, error) { amis := []string{instanceId} resp, err := ec2Handle.Instances(amis, nil) if err != nil { return nil, err } reservation := resp.Reservations if len(reservation) < 1 { return nil, evergreen.Logger.Errorf(slogger.ERROR, "No reservation found for "+ "instance id: %v", instanceId) } instances := reservation[0].Instances if len(instances) < 1 { return nil, evergreen.Logger.Errorf(slogger.ERROR, "'%v' was not found in "+ "reservation '%v'", instanceId, resp.Reservations[0].ReservationId) } return &instances[0], nil }
// WaitForAMI waits for the given AMI ID to become ready. func WaitForAMI(c *ec2.EC2, imageId string) error { for { imageResp, err := c.Images([]string{imageId}, ec2.NewFilter()) if err != nil { if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidAMIID.NotFound" { log.Println("AMI not found, probably state issues on AWS side. Trying again.") continue } return err } if imageResp.Images[0].State == "available" { return nil } log.Printf("Image in state %s, sleeping 2s before checking again", imageResp.Images[0].State) time.Sleep(2 * time.Second) } }
// VPCStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch // a VPC. func VPCStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { resp, err := conn.DescribeVpcs([]string{id}, ec2.NewFilter()) if err != nil { if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidVpcID.NotFound" { resp = nil } else { log.Printf("Error on VPCStateRefresh: %s", err) return nil, "", err } } if resp == nil { // Sometimes AWS just has consistency issues and doesn't see // our instance yet. Return an empty state. return nil, "", nil } vpc := &resp.VPCs[0] return vpc, vpc.State, nil } }
// resourceAwsRouteTableStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch // a RouteTable. func resourceAwsRouteTableStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { resp, err := conn.DescribeRouteTables([]string{id}, ec2.NewFilter()) if err != nil { if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidRouteTableID.NotFound" { resp = nil } else { log.Printf("Error on RouteTableStateRefresh: %s", err) return nil, "", err } } if resp == nil { // Sometimes AWS just has consistency issues and doesn't see // our instance yet. Return an empty state. return nil, "", nil } rt := &resp.RouteTables[0] return rt, "ready", nil } }
// IGAttachStateRefreshFunc returns a resource.StateRefreshFunc that is used // watch the state of an internet gateway's attachment. func IGAttachStateRefreshFunc(conn *ec2.EC2, id string, expected string) resource.StateRefreshFunc { var start time.Time return func() (interface{}, string, error) { if start.IsZero() { start = time.Now() } resp, err := conn.DescribeInternetGateways([]string{id}, ec2.NewFilter()) if err != nil { ec2err, ok := err.(*ec2.Error) if ok && ec2err.Code == "InvalidInternetGatewayID.NotFound" { resp = nil } else { log.Printf("[ERROR] Error on IGStateRefresh: %s", err) return nil, "", err } } if resp == nil { // Sometimes AWS just has consistency issues and doesn't see // our instance yet. Return an empty state. return nil, "", nil } ig := &resp.InternetGateways[0] if time.Now().Sub(start) > 10*time.Second { return ig, expected, nil } if len(ig.Attachments) == 0 { // No attachments, we're detached return ig, "detached", nil } return ig, ig.Attachments[0].State, nil } }
// IGStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch // an internet gateway. func IGStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { resp, err := conn.DescribeInternetGateways([]string{id}, ec2.NewFilter()) if err != nil { ec2err, ok := err.(*ec2.Error) if ok && ec2err.Code == "InvalidInternetGatewayID.NotFound" { resp = nil } else { log.Printf("[ERROR] Error on IGStateRefresh: %s", err) return nil, "", err } } if resp == nil { // Sometimes AWS just has consistency issues and doesn't see // our instance yet. Return an empty state. return nil, "", nil } ig := &resp.InternetGateways[0] return ig, "available", nil } }
// AMIStateRefreshFunc returns a StateRefreshFunc that is used to watch // an AMI for state changes. func AMIStateRefreshFunc(conn *ec2.EC2, imageId string) StateRefreshFunc { return func() (interface{}, string, error) { resp, err := conn.Images([]string{imageId}, ec2.NewFilter()) if err != nil { if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidAMIID.NotFound" { // Set this to nil as if we didn't find anything. resp = nil } else { log.Printf("Error on AMIStateRefresh: %s", err) return nil, "", err } } if resp == nil || len(resp.Images) == 0 { // Sometimes AWS has consistency issues and doesn't see the // AMI. Return an empty state. return nil, "", nil } i := resp.Images[0] return i, i.State, nil } }
// 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 }
// 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 }
func startEC2Instance(ec2Handle *ec2.EC2, options *ec2.RunInstances, intentHost *host.Host) (*host.Host, *ec2.RunInstancesResp, error) { // start the instance resp, err := ec2Handle.RunInstances(options) if err != nil { // remove the intent host document rmErr := intentHost.Remove() if rmErr != nil { evergreen.Logger.Errorf(slogger.ERROR, "Could not remove intent host "+ "“%v”: %v", intentHost.Id, rmErr) } return nil, nil, evergreen.Logger.Errorf(slogger.ERROR, "EC2 RunInstances API call returned error: %v", err) } evergreen.Logger.Logf(slogger.DEBUG, "Spawned %v instance", len(resp.Instances)) // the instance should have been successfully spawned instance := resp.Instances[0] evergreen.Logger.Logf(slogger.DEBUG, "Started %v", instance.InstanceId) evergreen.Logger.Logf(slogger.DEBUG, "Key name: %v", string(options.KeyName)) // find old intent host host, err := host.FindOne(host.ById(intentHost.Id)) if host == nil { return nil, nil, evergreen.Logger.Errorf(slogger.ERROR, "Can't locate "+ "record inserted for intended host “%v”", intentHost.Id) } if err != nil { return nil, nil, evergreen.Logger.Errorf(slogger.ERROR, "Can't locate "+ "record inserted for intended host “%v” due to error: %v", intentHost.Id, err) } // we found the old document now we can insert the new one host.Id = instance.InstanceId err = host.Insert() if err != nil { return nil, nil, evergreen.Logger.Errorf(slogger.ERROR, "Could not insert "+ "updated host information for “%v” with “%v”: %v", intentHost.Id, host.Id, err) } // remove the intent host document err = intentHost.Remove() if err != nil { return nil, nil, evergreen.Logger.Errorf(slogger.ERROR, "Could not remove "+ "insert host “%v” (replaced by “%v”): %v", intentHost.Id, host.Id, err) } var infoResp *ec2.InstancesResp instanceInfoRetryCount := 0 instanceInfoMaxRetries := 5 for { infoResp, err = ec2Handle.Instances([]string{instance.InstanceId}, nil) if err != nil { instanceInfoRetryCount++ if instanceInfoRetryCount == instanceInfoMaxRetries { evergreen.Logger.Errorf(slogger.ERROR, "There was an error querying for the "+ "instance's information and retries are exhausted. The insance may "+ "be up.") return nil, resp, err } evergreen.Logger.Errorf(slogger.DEBUG, "There was an error querying for the "+ "instance's information. Retrying in 30 seconds. Error: %v", err) time.Sleep(30 * time.Second) continue } break } reservations := infoResp.Reservations if len(reservations) < 1 { return nil, resp, fmt.Errorf("Reservation was returned as nil, you " + "may have to check manually") } instancesInfo := reservations[0].Instances if len(instancesInfo) < 1 { return nil, resp, fmt.Errorf("Reservation appears to have no " + "associated instances") } return host, resp, nil }