github.com/ndarilek/terraform@v0.3.8-0.20150320140257-d3135c1b2bac/builtin/providers/aws/resource_aws_network_interface.go (about)

     1  package aws
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  	"strconv"
     8  	"time"
     9  
    10  	"github.com/hashicorp/aws-sdk-go/aws"
    11  	"github.com/hashicorp/aws-sdk-go/gen/ec2"
    12  	"github.com/hashicorp/terraform/helper/hashcode"
    13  	"github.com/hashicorp/terraform/helper/resource"
    14  	"github.com/hashicorp/terraform/helper/schema"
    15  )
    16  
    17  func resourceAwsNetworkInterface() *schema.Resource {
    18  	return &schema.Resource{
    19  		Create: resourceAwsNetworkInterfaceCreate,
    20  		Read:   resourceAwsNetworkInterfaceRead,
    21  		Update: resourceAwsNetworkInterfaceUpdate,
    22  		Delete: resourceAwsNetworkInterfaceDelete,
    23  
    24  		Schema: map[string]*schema.Schema{
    25  
    26  			"subnet_id": &schema.Schema{
    27  				Type:     schema.TypeString,
    28  				Required: true,
    29  				ForceNew: true,
    30  			},
    31  
    32  			"private_ips": &schema.Schema{
    33  				Type:     schema.TypeSet,
    34  				Optional: true,
    35  				ForceNew: true,
    36  				Elem:     &schema.Schema{Type: schema.TypeString},
    37  				Set: func(v interface{}) int {
    38  					return hashcode.String(v.(string))
    39  				},
    40  			},
    41  
    42  			"security_groups": &schema.Schema{
    43  				Type:     schema.TypeSet,
    44  				Optional: true,
    45  				Computed: true,
    46  				Elem:     &schema.Schema{Type: schema.TypeString},
    47  				Set: func(v interface{}) int {
    48  					return hashcode.String(v.(string))
    49  				},
    50  			},
    51  
    52  			"attachment": &schema.Schema{
    53  				Type:     schema.TypeSet,
    54  				Optional: true,
    55  				Elem: &schema.Resource{
    56  					Schema: map[string]*schema.Schema{
    57  						"instance": &schema.Schema{
    58  							Type:     schema.TypeString,
    59  							Required: true,
    60  						},
    61  						"device_index": &schema.Schema{
    62  							Type:     schema.TypeInt,
    63  							Required: true,
    64  						},
    65  						"attachment_id": &schema.Schema{
    66  							Type:     schema.TypeString,
    67  							Computed: true,
    68  						},
    69  					},
    70  				},
    71  				Set: resourceAwsEniAttachmentHash,
    72  			},
    73  
    74  			"tags": tagsSchema(),
    75  		},
    76  	}
    77  }
    78  
    79  func resourceAwsNetworkInterfaceCreate(d *schema.ResourceData, meta interface{}) error {
    80  
    81  	ec2conn := meta.(*AWSClient).ec2conn
    82  
    83  	request := &ec2.CreateNetworkInterfaceRequest{
    84  		Groups:             expandStringList(d.Get("security_groups").(*schema.Set).List()),
    85  		SubnetID:           aws.String(d.Get("subnet_id").(string)),
    86  		PrivateIPAddresses: expandPrivateIPAddesses(d.Get("private_ips").(*schema.Set).List()),
    87  	}
    88  
    89  	log.Printf("[DEBUG] Creating network interface")
    90  	resp, err := ec2conn.CreateNetworkInterface(request)
    91  	if err != nil {
    92  		return fmt.Errorf("Error creating ENI: %s", err)
    93  	}
    94  
    95  	d.SetId(*resp.NetworkInterface.NetworkInterfaceID)
    96  	log.Printf("[INFO] ENI ID: %s", d.Id())
    97  
    98  	return resourceAwsNetworkInterfaceUpdate(d, meta)
    99  }
   100  
   101  func resourceAwsNetworkInterfaceRead(d *schema.ResourceData, meta interface{}) error {
   102  
   103  	ec2conn := meta.(*AWSClient).ec2conn
   104  	describe_network_interfaces_request := &ec2.DescribeNetworkInterfacesRequest{
   105  		NetworkInterfaceIDs: []string{d.Id()},
   106  	}
   107  	describeResp, err := ec2conn.DescribeNetworkInterfaces(describe_network_interfaces_request)
   108  
   109  	if err != nil {
   110  		if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidNetworkInterfaceID.NotFound" {
   111  			// The ENI is gone now, so just remove it from the state
   112  			d.SetId("")
   113  			return nil
   114  		}
   115  
   116  		return fmt.Errorf("Error retrieving ENI: %s", err)
   117  	}
   118  	if len(describeResp.NetworkInterfaces) != 1 {
   119  		return fmt.Errorf("Unable to find ENI: %#v", describeResp.NetworkInterfaces)
   120  	}
   121  
   122  	eni := describeResp.NetworkInterfaces[0]
   123  	d.Set("subnet_id", eni.SubnetID)
   124  	d.Set("private_ips", flattenNetworkInterfacesPrivateIPAddesses(eni.PrivateIPAddresses))
   125  	d.Set("security_groups", flattenGroupIdentifiers(eni.Groups))
   126  
   127  	// Tags
   128  	d.Set("tags", tagsToMap(eni.TagSet))
   129  
   130  	if eni.Attachment != nil {
   131  		attachment := []map[string]interface{}{flattenAttachment(eni.Attachment)}
   132  		d.Set("attachment", attachment)
   133  	} else {
   134  		d.Set("attachment", nil)
   135  	}
   136  
   137  	return nil
   138  }
   139  
   140  func networkInterfaceAttachmentRefreshFunc(ec2conn *ec2.EC2, id string) resource.StateRefreshFunc {
   141  	return func() (interface{}, string, error) {
   142  
   143  		describe_network_interfaces_request := &ec2.DescribeNetworkInterfacesRequest{
   144  			NetworkInterfaceIDs: []string{id},
   145  		}
   146  		describeResp, err := ec2conn.DescribeNetworkInterfaces(describe_network_interfaces_request)
   147  
   148  		if err != nil {
   149  			log.Printf("[ERROR] Could not find network interface %s. %s", id, err)
   150  			return nil, "", err
   151  		}
   152  
   153  		eni := describeResp.NetworkInterfaces[0]
   154  		hasAttachment := strconv.FormatBool(eni.Attachment != nil)
   155  		log.Printf("[DEBUG] ENI %s has attachment state %s", id, hasAttachment)
   156  		return eni, hasAttachment, nil
   157  	}
   158  }
   159  
   160  func resourceAwsNetworkInterfaceDetach(oa *schema.Set, meta interface{}, eniId string) error {
   161  	// if there was an old attachment, remove it
   162  	if oa != nil && len(oa.List()) > 0 {
   163  		old_attachment := oa.List()[0].(map[string]interface{})
   164  		detach_request := &ec2.DetachNetworkInterfaceRequest{
   165  			AttachmentID: aws.String(old_attachment["attachment_id"].(string)),
   166  			Force:        aws.Boolean(true),
   167  		}
   168  		ec2conn := meta.(*AWSClient).ec2conn
   169  		detach_err := ec2conn.DetachNetworkInterface(detach_request)
   170  		if detach_err != nil {
   171  			return fmt.Errorf("Error detaching ENI: %s", detach_err)
   172  		}
   173  
   174  		log.Printf("[DEBUG] Waiting for ENI (%s) to become dettached", eniId)
   175  		stateConf := &resource.StateChangeConf{
   176  			Pending: []string{"true"},
   177  			Target:  "false",
   178  			Refresh: networkInterfaceAttachmentRefreshFunc(ec2conn, eniId),
   179  			Timeout: 10 * time.Minute,
   180  		}
   181  		if _, err := stateConf.WaitForState(); err != nil {
   182  			return fmt.Errorf(
   183  				"Error waiting for ENI (%s) to become dettached: %s", eniId, err)
   184  		}
   185  	}
   186  
   187  	return nil
   188  }
   189  
   190  func resourceAwsNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) error {
   191  	ec2conn := meta.(*AWSClient).ec2conn
   192  	d.Partial(true)
   193  
   194  	if d.HasChange("attachment") {
   195  		ec2conn := meta.(*AWSClient).ec2conn
   196  		oa, na := d.GetChange("attachment")
   197  
   198  		detach_err := resourceAwsNetworkInterfaceDetach(oa.(*schema.Set), meta, d.Id())
   199  		if detach_err != nil {
   200  			return detach_err
   201  		}
   202  
   203  		// if there is a new attachment, attach it
   204  		if na != nil && len(na.(*schema.Set).List()) > 0 {
   205  			new_attachment := na.(*schema.Set).List()[0].(map[string]interface{})
   206  			attach_request := &ec2.AttachNetworkInterfaceRequest{
   207  				DeviceIndex:        aws.Integer(new_attachment["device_index"].(int)),
   208  				InstanceID:         aws.String(new_attachment["instance"].(string)),
   209  				NetworkInterfaceID: aws.String(d.Id()),
   210  			}
   211  			_, attach_err := ec2conn.AttachNetworkInterface(attach_request)
   212  			if attach_err != nil {
   213  				return fmt.Errorf("Error attaching ENI: %s", attach_err)
   214  			}
   215  		}
   216  
   217  		d.SetPartial("attachment")
   218  	}
   219  
   220  	if d.HasChange("security_groups") {
   221  		request := &ec2.ModifyNetworkInterfaceAttributeRequest{
   222  			NetworkInterfaceID: aws.String(d.Id()),
   223  			Groups:             expandStringList(d.Get("security_groups").(*schema.Set).List()),
   224  		}
   225  
   226  		err := ec2conn.ModifyNetworkInterfaceAttribute(request)
   227  		if err != nil {
   228  			return fmt.Errorf("Failure updating ENI: %s", err)
   229  		}
   230  
   231  		d.SetPartial("security_groups")
   232  	}
   233  
   234  	if err := setTags(ec2conn, d); err != nil {
   235  		return err
   236  	} else {
   237  		d.SetPartial("tags")
   238  	}
   239  
   240  	d.Partial(false)
   241  
   242  	return resourceAwsNetworkInterfaceRead(d, meta)
   243  }
   244  
   245  func resourceAwsNetworkInterfaceDelete(d *schema.ResourceData, meta interface{}) error {
   246  	ec2conn := meta.(*AWSClient).ec2conn
   247  
   248  	log.Printf("[INFO] Deleting ENI: %s", d.Id())
   249  
   250  	detach_err := resourceAwsNetworkInterfaceDetach(d.Get("attachment").(*schema.Set), meta, d.Id())
   251  	if detach_err != nil {
   252  		return detach_err
   253  	}
   254  
   255  	deleteEniOpts := ec2.DeleteNetworkInterfaceRequest{
   256  		NetworkInterfaceID: aws.String(d.Id()),
   257  	}
   258  	if err := ec2conn.DeleteNetworkInterface(&deleteEniOpts); err != nil {
   259  		return fmt.Errorf("Error deleting ENI: %s", err)
   260  	}
   261  
   262  	return nil
   263  }
   264  
   265  func resourceAwsEniAttachmentHash(v interface{}) int {
   266  	var buf bytes.Buffer
   267  	m := v.(map[string]interface{})
   268  	buf.WriteString(fmt.Sprintf("%s-", m["instance"].(string)))
   269  	buf.WriteString(fmt.Sprintf("%d-", m["device_index"].(int)))
   270  	return hashcode.String(buf.String())
   271  }