github.com/bengesoff/terraform@v0.3.1-0.20141018223233-b25a53629922/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 return resource.Retry(5*time.Minute, func() error { 92 _, err := ec2conn.DeleteSubnet(s.ID) 93 if err != nil { 94 ec2err, ok := err.(*ec2.Error) 95 if !ok { 96 return err 97 } 98 99 switch ec2err.Code { 100 case "InvalidSubnetID.NotFound": 101 return nil 102 case "DependencyViolation": 103 return err // retry 104 default: 105 return resource.RetryError{err} 106 } 107 } 108 109 return fmt.Errorf("Error deleting subnet: %s", err) 110 }) 111 112 // Wait for the Subnet to actually delete 113 log.Printf("[DEBUG] Waiting for subnet (%s) to delete", s.ID) 114 stateConf := &resource.StateChangeConf{ 115 Pending: []string{"available", "pending"}, 116 Target: "", 117 Refresh: SubnetStateRefreshFunc(ec2conn, s.ID), 118 Timeout: 10 * time.Minute, 119 } 120 if _, err := stateConf.WaitForState(); err != nil { 121 return fmt.Errorf( 122 "Error waiting for subnet (%s) to destroy: %s", 123 s.ID, err) 124 } 125 126 return nil 127 } 128 129 func resource_aws_subnet_refresh( 130 s *terraform.InstanceState, 131 meta interface{}) (*terraform.InstanceState, error) { 132 p := meta.(*ResourceProvider) 133 ec2conn := p.ec2conn 134 135 subnetRaw, _, err := SubnetStateRefreshFunc(ec2conn, s.ID)() 136 if err != nil { 137 return s, err 138 } 139 if subnetRaw == nil { 140 return nil, nil 141 } 142 143 subnet := subnetRaw.(*ec2.Subnet) 144 return resource_aws_subnet_update_state(s, subnet) 145 } 146 147 func resource_aws_subnet_diff( 148 s *terraform.InstanceState, 149 c *terraform.ResourceConfig, 150 meta interface{}) (*terraform.InstanceDiff, error) { 151 b := &diff.ResourceBuilder{ 152 Attrs: map[string]diff.AttrType{ 153 "availability_zone": diff.AttrTypeCreate, 154 "cidr_block": diff.AttrTypeCreate, 155 "vpc_id": diff.AttrTypeCreate, 156 "map_public_ip_on_launch": diff.AttrTypeCreate, 157 }, 158 159 ComputedAttrs: []string{ 160 "availability_zone", 161 }, 162 } 163 164 return b.Diff(s, c) 165 } 166 167 func resource_aws_subnet_update_state( 168 s *terraform.InstanceState, 169 subnet *ec2.Subnet) (*terraform.InstanceState, error) { 170 s.Attributes["availability_zone"] = subnet.AvailabilityZone 171 s.Attributes["cidr_block"] = subnet.CidrBlock 172 s.Attributes["vpc_id"] = subnet.VpcId 173 if subnet.MapPublicIpOnLaunch { 174 s.Attributes["map_public_ip_on_launch"] = "true" 175 } 176 177 return s, nil 178 } 179 180 // SubnetStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch 181 // a Subnet. 182 func SubnetStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { 183 return func() (interface{}, string, error) { 184 resp, err := conn.DescribeSubnets([]string{id}, ec2.NewFilter()) 185 if err != nil { 186 if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidSubnetID.NotFound" { 187 resp = nil 188 } else { 189 log.Printf("Error on SubnetStateRefresh: %s", err) 190 return nil, "", err 191 } 192 } 193 194 if resp == nil { 195 // Sometimes AWS just has consistency issues and doesn't see 196 // our instance yet. Return an empty state. 197 return nil, "", nil 198 } 199 200 subnet := &resp.Subnets[0] 201 return subnet, subnet.State, nil 202 } 203 }