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