// InstanceStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch // an EC2 instance. func InstanceStateRefreshFunc(conn *ec2.EC2, instanceID string) resource.StateRefreshFunc { return func() (interface{}, string, error) { resp, err := conn.DescribeInstances(&ec2.DescribeInstancesRequest{ InstanceIDs: []string{instanceID}, }) if err != nil { if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidInstanceID.NotFound" { // Set this to nil 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 } }
// resourceAwsVpcPeeringConnectionStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch // a VpcPeeringConnection. func resourceAwsVpcPeeringConnectionStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { resp, err := conn.DescribeVPCPeeringConnections(&ec2.DescribeVPCPeeringConnectionsRequest{ VPCPeeringConnectionIDs: []string{id}, }) if err != nil { if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidVpcPeeringConnectionID.NotFound" { resp = nil } else { log.Printf("Error on VpcPeeringConnectionStateRefresh: %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 } pc := &resp.VPCPeeringConnections[0] return pc, "ready", 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) { req := &ec2.DescribeSecurityGroupsRequest{ GroupIDs: []string{id}, } resp, err := conn.DescribeSecurityGroups(req) if err != nil { if ec2err, ok := err.(aws.APIError); 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.SecurityGroups[0] return group, "exists", 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) err := conn.DeleteTags(&ec2.DeleteTagsRequest{ Resources: []string{d.Id()}, Tags: remove, }) if err != nil { return err } } if len(create) > 0 { log.Printf("[DEBUG] Creating tags: %#v", create) err := conn.CreateTags(&ec2.CreateTagsRequest{ Resources: []string{d.Id()}, Tags: create, }) if err != nil { return err } } } return nil }
func updateNetworkAclEntries(d *schema.ResourceData, entryType string, ec2conn *ec2.EC2) error { o, n := d.GetChange(entryType) if o == nil { o = new(schema.Set) } if n == nil { n = new(schema.Set) } os := o.(*schema.Set) ns := n.(*schema.Set) toBeDeleted, err := expandNetworkAclEntries(os.Difference(ns).List(), entryType) if err != nil { return err } for _, remove := range toBeDeleted { // Delete old Acl err := ec2conn.DeleteNetworkACLEntry(&ec2.DeleteNetworkACLEntryRequest{ NetworkACLID: aws.String(d.Id()), RuleNumber: remove.RuleNumber, Egress: remove.Egress, }) if err != nil { return fmt.Errorf("Error deleting %s entry: %s", entryType, err) } } toBeCreated, err := expandNetworkAclEntries(ns.Difference(os).List(), entryType) if err != nil { return err } for _, add := range toBeCreated { // Add new Acl entry err := ec2conn.CreateNetworkACLEntry(&ec2.CreateNetworkACLEntryRequest{ NetworkACLID: aws.String(d.Id()), CIDRBlock: add.CIDRBlock, Egress: add.Egress, PortRange: add.PortRange, Protocol: add.Protocol, RuleAction: add.RuleAction, RuleNumber: add.RuleNumber, }) if err != nil { return fmt.Errorf("Error creating %s entry: %s", entryType, err) } } return nil }
func fetchRootDeviceName(ami string, conn *ec2.EC2) (aws.StringValue, error) { if ami == "" { return nil, fmt.Errorf("Cannot fetch root device name for blank AMI ID.") } log.Printf("[DEBUG] Describing AMI %q to get root block device name", ami) req := &ec2.DescribeImagesRequest{ImageIDs: []string{ami}} if res, err := conn.DescribeImages(req); err == nil { if len(res.Images) == 1 { return res.Images[0].RootDeviceName, nil } else { return nil, fmt.Errorf("Expected 1 AMI for ID: %s, got: %#v", ami, res.Images) } } else { return nil, err } }
func networkInterfaceAttachmentRefreshFunc(ec2conn *ec2.EC2, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { describe_network_interfaces_request := &ec2.DescribeNetworkInterfacesRequest{ NetworkInterfaceIDs: []string{id}, } describeResp, err := ec2conn.DescribeNetworkInterfaces(describe_network_interfaces_request) if err != nil { log.Printf("[ERROR] Could not find network interface %s. %s", id, err) return nil, "", err } eni := describeResp.NetworkInterfaces[0] hasAttachment := strconv.FormatBool(eni.Attachment != nil) log.Printf("[DEBUG] ENI %s has attachment state %s", id, hasAttachment) return eni, hasAttachment, nil } }
func getDefaultNetworkAcl(vpc_id string, ec2conn *ec2.EC2) (defaultAcl *ec2.NetworkACL, err error) { resp, err := ec2conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsRequest{ NetworkACLIDs: []string{}, Filters: []ec2.Filter{ ec2.Filter{ Name: aws.String("default"), Values: []string{"true"}, }, ec2.Filter{ Name: aws.String("vpc-id"), Values: []string{vpc_id}, }, }, }) if err != nil { return nil, err } return &resp.NetworkACLs[0], nil }
func findNetworkAclAssociation(subnetId string, ec2conn *ec2.EC2) (networkAclAssociation *ec2.NetworkACLAssociation, err error) { resp, err := ec2conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsRequest{ NetworkACLIDs: []string{}, Filters: []ec2.Filter{ ec2.Filter{ Name: aws.String("association.subnet-id"), Values: []string{subnetId}, }, }, }) if err != nil { return nil, err } for _, association := range resp.NetworkACLs[0].Associations { if *association.SubnetID == subnetId { return &association, nil } } return nil, fmt.Errorf("could not find association for subnet %s ", subnetId) }
// VpnGatewayAttachStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch // the state of a VPN gateway's attachment func VpnGatewayAttachStateRefreshFunc(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.DescribeVPNGateways(&ec2.DescribeVPNGatewaysRequest{ VPNGatewayIDs: []string{id}, }) if err != nil { if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidVpnGatewayID.NotFound" { resp = nil } else { log.Printf("[ERROR] Error on VpnGatewayStateRefresh: %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 } vpnGateway := &resp.VPNGateways[0] if time.Now().Sub(start) > 10*time.Second { return vpnGateway, expected, nil } if len(vpnGateway.VPCAttachments) == 0 { // No attachments, we're detached return vpnGateway, "detached", nil } return vpnGateway, *vpnGateway.VPCAttachments[0].State, nil } }
func findMainRouteTable(ec2conn *ec2.EC2, vpcId string) (*ec2.RouteTable, error) { mainFilter := ec2.Filter{ aws.String("association.main"), []string{"true"}, } vpcFilter := ec2.Filter{ aws.String("vpc-id"), []string{vpcId}, } routeResp, err := ec2conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{ Filters: []ec2.Filter{mainFilter, vpcFilter}, }) if err != nil { return nil, err } else if len(routeResp.RouteTables) != 1 { return nil, fmt.Errorf( "Expected to find a single main routing table for VPC: %s, but found %d", vpcId, len(routeResp.RouteTables)) } return &routeResp.RouteTables[0], nil }
// vpnGatewayStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch a VPNGateway. func vpnGatewayStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { resp, err := conn.DescribeVPNGateways(&ec2.DescribeVPNGatewaysRequest{ VPNGatewayIDs: []string{id}, }) if err != nil { if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidVpnGatewayID.NotFound" { resp = nil } else { log.Printf("[ERROR] Error on VpnGatewayStateRefresh: %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 } vpnGateway := &resp.VPNGateways[0] return vpnGateway, *vpnGateway.State, nil } }
// SubnetStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch a Subnet. func SubnetStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { resp, err := conn.DescribeSubnets(&ec2.DescribeSubnetsRequest{ SubnetIDs: []string{id}, }) if err != nil { if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidSubnetID.NotFound" { resp = nil } else { log.Printf("Error on SubnetStateRefresh: %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 } subnet := &resp.Subnets[0] return subnet, *subnet.State, nil } }
func readBlockDevicesFromInstance(instance *ec2.Instance, ec2conn *ec2.EC2) (map[string]interface{}, error) { blockDevices := make(map[string]interface{}) blockDevices["ebs"] = make([]map[string]interface{}, 0) blockDevices["root"] = nil instanceBlockDevices := make(map[string]ec2.InstanceBlockDeviceMapping) for _, bd := range instance.BlockDeviceMappings { if bd.EBS != nil { instanceBlockDevices[*(bd.EBS.VolumeID)] = bd } } if len(instanceBlockDevices) == 0 { return nil, nil } volIDs := make([]string, 0, len(instanceBlockDevices)) for volID := range instanceBlockDevices { volIDs = append(volIDs, volID) } // Need to call DescribeVolumes to get volume_size and volume_type for each // EBS block device volResp, err := ec2conn.DescribeVolumes(&ec2.DescribeVolumesRequest{ VolumeIDs: volIDs, }) if err != nil { return nil, err } for _, vol := range volResp.Volumes { instanceBd := instanceBlockDevices[*vol.VolumeID] bd := make(map[string]interface{}) if instanceBd.EBS != nil && instanceBd.EBS.DeleteOnTermination != nil { bd["delete_on_termination"] = *instanceBd.EBS.DeleteOnTermination } if vol.Size != nil { bd["volume_size"] = *vol.Size } if vol.VolumeType != nil { bd["volume_type"] = *vol.VolumeType } if vol.IOPS != nil { bd["iops"] = *vol.IOPS } if blockDeviceIsRoot(instanceBd, instance) { blockDevices["root"] = bd } else { if instanceBd.DeviceName != nil { bd["device_name"] = *instanceBd.DeviceName } if vol.Encrypted != nil { bd["encrypted"] = *vol.Encrypted } if vol.SnapshotID != nil { bd["snapshot_id"] = *vol.SnapshotID } blockDevices["ebs"] = append(blockDevices["ebs"].([]map[string]interface{}), bd) } } return blockDevices, nil }