github.com/adamar/terraform@v0.2.2-0.20141016210445-2e703afdad0e/builtin/providers/aws/resource_aws_subnet.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"time"
     7  
     8  	"github.com/hashicorp/terraform/helper/diff"
     9  	"github.com/hashicorp/terraform/helper/resource"
    10  	"github.com/hashicorp/terraform/terraform"
    11  	"github.com/mitchellh/goamz/ec2"
    12  )
    13  
    14  func resource_aws_subnet_create(
    15  	s *terraform.InstanceState,
    16  	d *terraform.InstanceDiff,
    17  	meta interface{}) (*terraform.InstanceState, error) {
    18  	p := meta.(*ResourceProvider)
    19  	ec2conn := p.ec2conn
    20  
    21  	// Merge the diff so that we have all the proper attributes
    22  	s = s.MergeDiff(d)
    23  
    24  	// Create the Subnet
    25  	createOpts := &ec2.CreateSubnet{
    26  		AvailabilityZone: s.Attributes["availability_zone"],
    27  		CidrBlock:        s.Attributes["cidr_block"],
    28  		VpcId:            s.Attributes["vpc_id"],
    29  	}
    30  	log.Printf("[DEBUG] Subnet create config: %#v", createOpts)
    31  	resp, err := ec2conn.CreateSubnet(createOpts)
    32  	if err != nil {
    33  		return nil, fmt.Errorf("Error creating subnet: %s", err)
    34  	}
    35  
    36  	// Get the ID and store it
    37  	subnet := &resp.Subnet
    38  	s.ID = subnet.SubnetId
    39  	log.Printf("[INFO] Subnet ID: %s", s.ID)
    40  
    41  	// Wait for the Subnet to become available
    42  	log.Printf(
    43  		"[DEBUG] Waiting for subnet (%s) to become available",
    44  		s.ID)
    45  	stateConf := &resource.StateChangeConf{
    46  		Pending: []string{"pending"},
    47  		Target:  "available",
    48  		Refresh: SubnetStateRefreshFunc(ec2conn, s.ID),
    49  		Timeout: 10 * time.Minute,
    50  	}
    51  	subnetRaw, err := stateConf.WaitForState()
    52  	if err != nil {
    53  		return s, fmt.Errorf(
    54  			"Error waiting for subnet (%s) to become available: %s",
    55  			s.ID, err)
    56  	}
    57  
    58  	// Map public ip on launch must be set in another API call
    59  	if attr := s.Attributes["map_public_ip_on_launch"]; attr == "true" {
    60  		modifyOpts := &ec2.ModifySubnetAttribute{
    61  			SubnetId:            s.ID,
    62  			MapPublicIpOnLaunch: true,
    63  		}
    64  		log.Printf("[DEBUG] Subnet modify attributes: %#v", modifyOpts)
    65  		_, err := ec2conn.ModifySubnetAttribute(modifyOpts)
    66  		if err != nil {
    67  			return nil, fmt.Errorf("Error modify subnet attributes: %s", err)
    68  		}
    69  	}
    70  
    71  	// Update our attributes and return
    72  	return resource_aws_subnet_update_state(s, subnetRaw.(*ec2.Subnet))
    73  }
    74  
    75  func resource_aws_subnet_update(
    76  	s *terraform.InstanceState,
    77  	d *terraform.InstanceDiff,
    78  	meta interface{}) (*terraform.InstanceState, error) {
    79  	// This should never be called because we have no update-able
    80  	// attributes
    81  	panic("Update for subnet is not supported")
    82  }
    83  
    84  func resource_aws_subnet_destroy(
    85  	s *terraform.InstanceState,
    86  	meta interface{}) error {
    87  	p := meta.(*ResourceProvider)
    88  	ec2conn := p.ec2conn
    89  
    90  	log.Printf("[INFO] Deleting Subnet: %s", s.ID)
    91  	f := func() error {
    92  		_, err := ec2conn.DeleteSubnet(s.ID)
    93  		return err
    94  	}
    95  	if err := resource.Retry(10*time.Second, f); err != nil {
    96  		ec2err, ok := err.(*ec2.Error)
    97  		if ok && ec2err.Code == "InvalidSubnetID.NotFound" {
    98  			return nil
    99  		}
   100  
   101  		return fmt.Errorf("Error deleting subnet: %s", err)
   102  	}
   103  
   104  	// Wait for the Subnet to actually delete
   105  	log.Printf("[DEBUG] Waiting for subnet (%s) to delete", s.ID)
   106  	stateConf := &resource.StateChangeConf{
   107  		Pending: []string{"available", "pending"},
   108  		Target:  "",
   109  		Refresh: SubnetStateRefreshFunc(ec2conn, s.ID),
   110  		Timeout: 10 * time.Minute,
   111  	}
   112  	if _, err := stateConf.WaitForState(); err != nil {
   113  		return fmt.Errorf(
   114  			"Error waiting for subnet (%s) to destroy: %s",
   115  			s.ID, err)
   116  	}
   117  
   118  	return nil
   119  }
   120  
   121  func resource_aws_subnet_refresh(
   122  	s *terraform.InstanceState,
   123  	meta interface{}) (*terraform.InstanceState, error) {
   124  	p := meta.(*ResourceProvider)
   125  	ec2conn := p.ec2conn
   126  
   127  	subnetRaw, _, err := SubnetStateRefreshFunc(ec2conn, s.ID)()
   128  	if err != nil {
   129  		return s, err
   130  	}
   131  	if subnetRaw == nil {
   132  		return nil, nil
   133  	}
   134  
   135  	subnet := subnetRaw.(*ec2.Subnet)
   136  	return resource_aws_subnet_update_state(s, subnet)
   137  }
   138  
   139  func resource_aws_subnet_diff(
   140  	s *terraform.InstanceState,
   141  	c *terraform.ResourceConfig,
   142  	meta interface{}) (*terraform.InstanceDiff, error) {
   143  	b := &diff.ResourceBuilder{
   144  		Attrs: map[string]diff.AttrType{
   145  			"availability_zone":       diff.AttrTypeCreate,
   146  			"cidr_block":              diff.AttrTypeCreate,
   147  			"vpc_id":                  diff.AttrTypeCreate,
   148  			"map_public_ip_on_launch": diff.AttrTypeCreate,
   149  		},
   150  
   151  		ComputedAttrs: []string{
   152  			"availability_zone",
   153  		},
   154  	}
   155  
   156  	return b.Diff(s, c)
   157  }
   158  
   159  func resource_aws_subnet_update_state(
   160  	s *terraform.InstanceState,
   161  	subnet *ec2.Subnet) (*terraform.InstanceState, error) {
   162  	s.Attributes["availability_zone"] = subnet.AvailabilityZone
   163  	s.Attributes["cidr_block"] = subnet.CidrBlock
   164  	s.Attributes["vpc_id"] = subnet.VpcId
   165  	if subnet.MapPublicIpOnLaunch {
   166  		s.Attributes["map_public_ip_on_launch"] = "true"
   167  	}
   168  
   169  	return s, nil
   170  }
   171  
   172  // SubnetStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
   173  // a Subnet.
   174  func SubnetStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
   175  	return func() (interface{}, string, error) {
   176  		resp, err := conn.DescribeSubnets([]string{id}, ec2.NewFilter())
   177  		if err != nil {
   178  			if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidSubnetID.NotFound" {
   179  				resp = nil
   180  			} else {
   181  				log.Printf("Error on SubnetStateRefresh: %s", err)
   182  				return nil, "", err
   183  			}
   184  		}
   185  
   186  		if resp == nil {
   187  			// Sometimes AWS just has consistency issues and doesn't see
   188  			// our instance yet. Return an empty state.
   189  			return nil, "", nil
   190  		}
   191  
   192  		subnet := &resp.Subnets[0]
   193  		return subnet, subnet.State, nil
   194  	}
   195  }