github.com/i0n/terraform@v0.4.3-0.20150506151324-010a39a58ec1/builtin/providers/aws/resource_aws_vpc.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "time" 7 8 "github.com/awslabs/aws-sdk-go/aws" 9 "github.com/awslabs/aws-sdk-go/service/ec2" 10 "github.com/hashicorp/terraform/helper/resource" 11 "github.com/hashicorp/terraform/helper/schema" 12 ) 13 14 func resourceAwsVpc() *schema.Resource { 15 return &schema.Resource{ 16 Create: resourceAwsVpcCreate, 17 Read: resourceAwsVpcRead, 18 Update: resourceAwsVpcUpdate, 19 Delete: resourceAwsVpcDelete, 20 21 Schema: map[string]*schema.Schema{ 22 "cidr_block": &schema.Schema{ 23 Type: schema.TypeString, 24 Required: true, 25 ForceNew: true, 26 }, 27 28 "instance_tenancy": &schema.Schema{ 29 Type: schema.TypeString, 30 Optional: true, 31 ForceNew: true, 32 }, 33 34 "enable_dns_hostnames": &schema.Schema{ 35 Type: schema.TypeBool, 36 Optional: true, 37 Computed: true, 38 }, 39 40 "enable_dns_support": &schema.Schema{ 41 Type: schema.TypeBool, 42 Optional: true, 43 Computed: true, 44 }, 45 46 "main_route_table_id": &schema.Schema{ 47 Type: schema.TypeString, 48 Computed: true, 49 }, 50 51 "default_network_acl_id": &schema.Schema{ 52 Type: schema.TypeString, 53 Computed: true, 54 }, 55 56 "dhcp_options_id": &schema.Schema{ 57 Type: schema.TypeString, 58 Computed: true, 59 }, 60 61 "default_security_group_id": &schema.Schema{ 62 Type: schema.TypeString, 63 Computed: true, 64 }, 65 66 "tags": tagsSchema(), 67 }, 68 } 69 } 70 71 func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error { 72 conn := meta.(*AWSClient).ec2conn 73 instance_tenancy := "default" 74 if v, ok := d.GetOk("instance_tenancy"); ok { 75 instance_tenancy = v.(string) 76 } 77 // Create the VPC 78 createOpts := &ec2.CreateVPCInput{ 79 CIDRBlock: aws.String(d.Get("cidr_block").(string)), 80 InstanceTenancy: aws.String(instance_tenancy), 81 } 82 log.Printf("[DEBUG] VPC create config: %#v", *createOpts) 83 vpcResp, err := conn.CreateVPC(createOpts) 84 if err != nil { 85 return fmt.Errorf("Error creating VPC: %s", err) 86 } 87 88 // Get the ID and store it 89 vpc := vpcResp.VPC 90 d.SetId(*vpc.VPCID) 91 log.Printf("[INFO] VPC ID: %s", d.Id()) 92 93 // Set partial mode and say that we setup the cidr block 94 d.Partial(true) 95 d.SetPartial("cidr_block") 96 97 // Wait for the VPC to become available 98 log.Printf( 99 "[DEBUG] Waiting for VPC (%s) to become available", 100 d.Id()) 101 stateConf := &resource.StateChangeConf{ 102 Pending: []string{"pending"}, 103 Target: "available", 104 Refresh: VPCStateRefreshFunc(conn, d.Id()), 105 Timeout: 10 * time.Minute, 106 } 107 if _, err := stateConf.WaitForState(); err != nil { 108 return fmt.Errorf( 109 "Error waiting for VPC (%s) to become available: %s", 110 d.Id(), err) 111 } 112 113 // Update our attributes and return 114 return resourceAwsVpcUpdate(d, meta) 115 } 116 117 func resourceAwsVpcRead(d *schema.ResourceData, meta interface{}) error { 118 conn := meta.(*AWSClient).ec2conn 119 120 // Refresh the VPC state 121 vpcRaw, _, err := VPCStateRefreshFunc(conn, d.Id())() 122 if err != nil { 123 return err 124 } 125 if vpcRaw == nil { 126 d.SetId("") 127 return nil 128 } 129 130 // VPC stuff 131 vpc := vpcRaw.(*ec2.VPC) 132 vpcid := d.Id() 133 d.Set("cidr_block", vpc.CIDRBlock) 134 d.Set("dhcp_options_id", vpc.DHCPOptionsID) 135 136 // Tags 137 d.Set("tags", tagsToMapSDK(vpc.Tags)) 138 139 // Attributes 140 attribute := "enableDnsSupport" 141 DescribeAttrOpts := &ec2.DescribeVPCAttributeInput{ 142 Attribute: aws.String(attribute), 143 VPCID: aws.String(vpcid), 144 } 145 resp, err := conn.DescribeVPCAttribute(DescribeAttrOpts) 146 if err != nil { 147 return err 148 } 149 d.Set("enable_dns_support", *resp.EnableDNSSupport) 150 attribute = "enableDnsHostnames" 151 DescribeAttrOpts = &ec2.DescribeVPCAttributeInput{ 152 Attribute: &attribute, 153 VPCID: &vpcid, 154 } 155 resp, err = conn.DescribeVPCAttribute(DescribeAttrOpts) 156 if err != nil { 157 return err 158 } 159 d.Set("enable_dns_hostnames", *resp.EnableDNSHostnames) 160 161 // Get the main routing table for this VPC 162 // Really Ugly need to make this better - rmenn 163 filter1 := &ec2.Filter{ 164 Name: aws.String("association.main"), 165 Values: []*string{aws.String("true")}, 166 } 167 filter2 := &ec2.Filter{ 168 Name: aws.String("vpc-id"), 169 Values: []*string{aws.String(d.Id())}, 170 } 171 DescribeRouteOpts := &ec2.DescribeRouteTablesInput{ 172 Filters: []*ec2.Filter{filter1, filter2}, 173 } 174 routeResp, err := conn.DescribeRouteTables(DescribeRouteOpts) 175 if err != nil { 176 return err 177 } 178 if v := routeResp.RouteTables; len(v) > 0 { 179 d.Set("main_route_table_id", *v[0].RouteTableID) 180 } 181 182 resourceAwsVpcSetDefaultNetworkAcl(conn, d) 183 resourceAwsVpcSetDefaultSecurityGroup(conn, d) 184 185 return nil 186 } 187 188 func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error { 189 conn := meta.(*AWSClient).ec2conn 190 191 // Turn on partial mode 192 d.Partial(true) 193 vpcid := d.Id() 194 if d.HasChange("enable_dns_hostnames") { 195 val := d.Get("enable_dns_hostnames").(bool) 196 modifyOpts := &ec2.ModifyVPCAttributeInput{ 197 VPCID: &vpcid, 198 EnableDNSHostnames: &ec2.AttributeBooleanValue{ 199 Value: &val, 200 }, 201 } 202 203 log.Printf( 204 "[INFO] Modifying enable_dns_support vpc attribute for %s: %#v", 205 d.Id(), modifyOpts) 206 if _, err := conn.ModifyVPCAttribute(modifyOpts); err != nil { 207 return err 208 } 209 210 d.SetPartial("enable_dns_support") 211 } 212 213 if d.HasChange("enable_dns_support") { 214 val := d.Get("enable_dns_support").(bool) 215 modifyOpts := &ec2.ModifyVPCAttributeInput{ 216 VPCID: &vpcid, 217 EnableDNSSupport: &ec2.AttributeBooleanValue{ 218 Value: &val, 219 }, 220 } 221 222 log.Printf( 223 "[INFO] Modifying enable_dns_support vpc attribute for %s: %#v", 224 d.Id(), modifyOpts) 225 if _, err := conn.ModifyVPCAttribute(modifyOpts); err != nil { 226 return err 227 } 228 229 d.SetPartial("enable_dns_support") 230 } 231 232 if err := setTagsSDK(conn, d); err != nil { 233 return err 234 } else { 235 d.SetPartial("tags") 236 } 237 238 d.Partial(false) 239 return resourceAwsVpcRead(d, meta) 240 } 241 242 func resourceAwsVpcDelete(d *schema.ResourceData, meta interface{}) error { 243 conn := meta.(*AWSClient).ec2conn 244 vpcID := d.Id() 245 DeleteVpcOpts := &ec2.DeleteVPCInput{ 246 VPCID: &vpcID, 247 } 248 log.Printf("[INFO] Deleting VPC: %s", d.Id()) 249 if _, err := conn.DeleteVPC(DeleteVpcOpts); err != nil { 250 ec2err, ok := err.(aws.APIError) 251 if ok && ec2err.Code == "InvalidVpcID.NotFound" { 252 return nil 253 } 254 255 return fmt.Errorf("Error deleting VPC: %s", err) 256 } 257 258 return nil 259 } 260 261 // VPCStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch 262 // a VPC. 263 func VPCStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { 264 return func() (interface{}, string, error) { 265 DescribeVpcOpts := &ec2.DescribeVPCsInput{ 266 VPCIDs: []*string{aws.String(id)}, 267 } 268 resp, err := conn.DescribeVPCs(DescribeVpcOpts) 269 if err != nil { 270 if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidVpcID.NotFound" { 271 resp = nil 272 } else { 273 log.Printf("Error on VPCStateRefresh: %s", err) 274 return nil, "", err 275 } 276 } 277 278 if resp == nil { 279 // Sometimes AWS just has consistency issues and doesn't see 280 // our instance yet. Return an empty state. 281 return nil, "", nil 282 } 283 284 vpc := resp.VPCs[0] 285 return vpc, *vpc.State, nil 286 } 287 } 288 289 func resourceAwsVpcSetDefaultNetworkAcl(conn *ec2.EC2, d *schema.ResourceData) error { 290 filter1 := &ec2.Filter{ 291 Name: aws.String("default"), 292 Values: []*string{aws.String("true")}, 293 } 294 filter2 := &ec2.Filter{ 295 Name: aws.String("vpc-id"), 296 Values: []*string{aws.String(d.Id())}, 297 } 298 DescribeNetworkACLOpts := &ec2.DescribeNetworkACLsInput{ 299 Filters: []*ec2.Filter{filter1, filter2}, 300 } 301 networkAclResp, err := conn.DescribeNetworkACLs(DescribeNetworkACLOpts) 302 303 if err != nil { 304 return err 305 } 306 if v := networkAclResp.NetworkACLs; len(v) > 0 { 307 d.Set("default_network_acl_id", v[0].NetworkACLID) 308 } 309 310 return nil 311 } 312 313 func resourceAwsVpcSetDefaultSecurityGroup(conn *ec2.EC2, d *schema.ResourceData) error { 314 filter1 := &ec2.Filter{ 315 Name: aws.String("group-name"), 316 Values: []*string{aws.String("default")}, 317 } 318 filter2 := &ec2.Filter{ 319 Name: aws.String("vpc-id"), 320 Values: []*string{aws.String(d.Id())}, 321 } 322 DescribeSgOpts := &ec2.DescribeSecurityGroupsInput{ 323 Filters: []*ec2.Filter{filter1, filter2}, 324 } 325 securityGroupResp, err := conn.DescribeSecurityGroups(DescribeSgOpts) 326 327 if err != nil { 328 return err 329 } 330 if v := securityGroupResp.SecurityGroups; len(v) > 0 { 331 d.Set("default_security_group_id", v[0].GroupID) 332 } 333 334 return nil 335 }