github.com/ndarilek/terraform@v0.3.8-0.20150320140257-d3135c1b2bac/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/aws-sdk-go/aws" 9 "github.com/hashicorp/aws-sdk-go/gen/ec2" 10 "github.com/hashicorp/terraform/helper/resource" 11 "github.com/hashicorp/terraform/helper/schema" 12 ) 13 14 func resourceAwsSubnet() *schema.Resource { 15 return &schema.Resource{ 16 Create: resourceAwsSubnetCreate, 17 Read: resourceAwsSubnetRead, 18 Update: resourceAwsSubnetUpdate, 19 Delete: resourceAwsSubnetDelete, 20 21 Schema: map[string]*schema.Schema{ 22 "vpc_id": &schema.Schema{ 23 Type: schema.TypeString, 24 Optional: true, 25 ForceNew: true, 26 Computed: true, 27 }, 28 29 "cidr_block": &schema.Schema{ 30 Type: schema.TypeString, 31 Required: true, 32 ForceNew: true, 33 }, 34 35 "availability_zone": &schema.Schema{ 36 Type: schema.TypeString, 37 Optional: true, 38 Computed: true, 39 ForceNew: true, 40 }, 41 42 "map_public_ip_on_launch": &schema.Schema{ 43 Type: schema.TypeBool, 44 Optional: true, 45 Computed: true, 46 }, 47 48 "tags": tagsSchema(), 49 }, 50 } 51 } 52 53 func resourceAwsSubnetCreate(d *schema.ResourceData, meta interface{}) error { 54 ec2conn := meta.(*AWSClient).ec2conn 55 56 createOpts := &ec2.CreateSubnetRequest{ 57 AvailabilityZone: aws.String(d.Get("availability_zone").(string)), 58 CIDRBlock: aws.String(d.Get("cidr_block").(string)), 59 VPCID: aws.String(d.Get("vpc_id").(string)), 60 } 61 62 resp, err := ec2conn.CreateSubnet(createOpts) 63 64 if err != nil { 65 return fmt.Errorf("Error creating subnet: %s", err) 66 } 67 68 // Get the ID and store it 69 subnet := resp.Subnet 70 d.SetId(*subnet.SubnetID) 71 log.Printf("[INFO] Subnet ID: %s", *subnet.SubnetID) 72 73 // Wait for the Subnet to become available 74 log.Printf("[DEBUG] Waiting for subnet (%s) to become available", *subnet.SubnetID) 75 stateConf := &resource.StateChangeConf{ 76 Pending: []string{"pending"}, 77 Target: "available", 78 Refresh: SubnetStateRefreshFunc(ec2conn, *subnet.SubnetID), 79 Timeout: 10 * time.Minute, 80 } 81 82 _, err = stateConf.WaitForState() 83 84 if err != nil { 85 return fmt.Errorf( 86 "Error waiting for subnet (%s) to become ready: %s", 87 d.Id(), err) 88 } 89 90 return resourceAwsSubnetUpdate(d, meta) 91 } 92 93 func resourceAwsSubnetRead(d *schema.ResourceData, meta interface{}) error { 94 ec2conn := meta.(*AWSClient).ec2conn 95 96 resp, err := ec2conn.DescribeSubnets(&ec2.DescribeSubnetsRequest{ 97 SubnetIDs: []string{d.Id()}, 98 }) 99 100 if err != nil { 101 if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidSubnetID.NotFound" { 102 // Update state to indicate the subnet no longer exists. 103 d.SetId("") 104 return nil 105 } 106 return err 107 } 108 if resp == nil { 109 return nil 110 } 111 112 subnet := &resp.Subnets[0] 113 114 d.Set("vpc_id", subnet.VPCID) 115 d.Set("availability_zone", subnet.AvailabilityZone) 116 d.Set("cidr_block", subnet.CIDRBlock) 117 d.Set("map_public_ip_on_launch", subnet.MapPublicIPOnLaunch) 118 d.Set("tags", tagsToMap(subnet.Tags)) 119 120 return nil 121 } 122 123 func resourceAwsSubnetUpdate(d *schema.ResourceData, meta interface{}) error { 124 ec2conn := meta.(*AWSClient).ec2conn 125 126 d.Partial(true) 127 128 if err := setTags(ec2conn, d); err != nil { 129 return err 130 } else { 131 d.SetPartial("tags") 132 } 133 134 if d.HasChange("map_public_ip_on_launch") { 135 modifyOpts := &ec2.ModifySubnetAttributeRequest{ 136 SubnetID: aws.String(d.Id()), 137 MapPublicIPOnLaunch: &ec2.AttributeBooleanValue{aws.Boolean(true)}, 138 } 139 140 log.Printf("[DEBUG] Subnet modify attributes: %#v", modifyOpts) 141 142 err := ec2conn.ModifySubnetAttribute(modifyOpts) 143 144 if err != nil { 145 return err 146 } else { 147 d.SetPartial("map_public_ip_on_launch") 148 } 149 } 150 151 d.Partial(false) 152 153 return resourceAwsSubnetRead(d, meta) 154 } 155 156 func resourceAwsSubnetDelete(d *schema.ResourceData, meta interface{}) error { 157 ec2conn := meta.(*AWSClient).ec2conn 158 159 log.Printf("[INFO] Deleting subnet: %s", d.Id()) 160 req := &ec2.DeleteSubnetRequest{ 161 SubnetID: aws.String(d.Id()), 162 } 163 164 wait := resource.StateChangeConf{ 165 Pending: []string{"pending"}, 166 Target: "destroyed", 167 Timeout: 5 * time.Minute, 168 MinTimeout: 1 * time.Second, 169 Refresh: func() (interface{}, string, error) { 170 err := ec2conn.DeleteSubnet(req) 171 if err != nil { 172 if apiErr, ok := err.(aws.APIError); ok { 173 if apiErr.Code == "DependencyViolation" { 174 // There is some pending operation, so just retry 175 // in a bit. 176 return 42, "pending", nil 177 } 178 179 if apiErr.Code == "InvalidSubnetID.NotFound" { 180 return 42, "destroyed", nil 181 } 182 } 183 184 return 42, "failure", err 185 } 186 187 return 42, "destroyed", nil 188 }, 189 } 190 191 if _, err := wait.WaitForState(); err != nil { 192 return fmt.Errorf("Error deleting subnet: %s", err) 193 } 194 195 return nil 196 } 197 198 // SubnetStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch a Subnet. 199 func SubnetStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { 200 return func() (interface{}, string, error) { 201 resp, err := conn.DescribeSubnets(&ec2.DescribeSubnetsRequest{ 202 SubnetIDs: []string{id}, 203 }) 204 if err != nil { 205 if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidSubnetID.NotFound" { 206 resp = nil 207 } else { 208 log.Printf("Error on SubnetStateRefresh: %s", err) 209 return nil, "", err 210 } 211 } 212 213 if resp == nil { 214 // Sometimes AWS just has consistency issues and doesn't see 215 // our instance yet. Return an empty state. 216 return nil, "", nil 217 } 218 219 subnet := &resp.Subnets[0] 220 return subnet, *subnet.State, nil 221 } 222 }