github.com/rmenn/terraform@v0.3.8-0.20150225065417-fc84b3a78802/builtin/providers/aws/resource_aws_vpc.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "time" 7 8 "github.com/hashicorp/terraform/helper/resource" 9 "github.com/hashicorp/terraform/helper/schema" 10 "github.com/mitchellh/goamz/ec2" 11 ) 12 13 func resourceAwsVpc() *schema.Resource { 14 return &schema.Resource{ 15 Create: resourceAwsVpcCreate, 16 Read: resourceAwsVpcRead, 17 Update: resourceAwsVpcUpdate, 18 Delete: resourceAwsVpcDelete, 19 20 Schema: map[string]*schema.Schema{ 21 "cidr_block": &schema.Schema{ 22 Type: schema.TypeString, 23 Required: true, 24 ForceNew: true, 25 }, 26 27 "instance_tenancy": &schema.Schema{ 28 Type: schema.TypeString, 29 Optional: true, 30 ForceNew: true, 31 }, 32 33 "enable_dns_hostnames": &schema.Schema{ 34 Type: schema.TypeBool, 35 Optional: true, 36 Computed: true, 37 }, 38 39 "enable_dns_support": &schema.Schema{ 40 Type: schema.TypeBool, 41 Optional: true, 42 Computed: true, 43 }, 44 45 "main_route_table_id": &schema.Schema{ 46 Type: schema.TypeString, 47 Computed: true, 48 }, 49 50 "default_network_acl_id": &schema.Schema{ 51 Type: schema.TypeString, 52 Computed: true, 53 }, 54 55 "default_security_group_id": &schema.Schema{ 56 Type: schema.TypeString, 57 Computed: true, 58 }, 59 60 "tags": tagsSchema(), 61 }, 62 } 63 } 64 65 func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error { 66 ec2conn := meta.(*AWSClient).ec2conn 67 68 // Create the VPC 69 createOpts := &ec2.CreateVpc{ 70 CidrBlock: d.Get("cidr_block").(string), 71 InstanceTenancy: d.Get("instance_tenancy").(string), 72 } 73 log.Printf("[DEBUG] VPC create config: %#v", createOpts) 74 vpcResp, err := ec2conn.CreateVpc(createOpts) 75 if err != nil { 76 return fmt.Errorf("Error creating VPC: %s", err) 77 } 78 79 // Get the ID and store it 80 vpc := &vpcResp.VPC 81 log.Printf("[INFO] VPC ID: %s", vpc.VpcId) 82 d.SetId(vpc.VpcId) 83 84 // Set partial mode and say that we setup the cidr block 85 d.Partial(true) 86 d.SetPartial("cidr_block") 87 88 // Wait for the VPC to become available 89 log.Printf( 90 "[DEBUG] Waiting for VPC (%s) to become available", 91 d.Id()) 92 stateConf := &resource.StateChangeConf{ 93 Pending: []string{"pending"}, 94 Target: "available", 95 Refresh: VPCStateRefreshFunc(ec2conn, d.Id()), 96 Timeout: 10 * time.Minute, 97 } 98 if _, err := stateConf.WaitForState(); err != nil { 99 return fmt.Errorf( 100 "Error waiting for VPC (%s) to become available: %s", 101 d.Id(), err) 102 } 103 104 // Update our attributes and return 105 return resourceAwsVpcUpdate(d, meta) 106 } 107 108 func resourceAwsVpcRead(d *schema.ResourceData, meta interface{}) error { 109 ec2conn := meta.(*AWSClient).ec2conn 110 111 // Refresh the VPC state 112 vpcRaw, _, err := VPCStateRefreshFunc(ec2conn, d.Id())() 113 if err != nil { 114 return err 115 } 116 if vpcRaw == nil { 117 d.SetId("") 118 return nil 119 } 120 121 // VPC stuff 122 vpc := vpcRaw.(*ec2.VPC) 123 d.Set("cidr_block", vpc.CidrBlock) 124 125 // Tags 126 d.Set("tags", tagsToMap(vpc.Tags)) 127 128 // Attributes 129 resp, err := ec2conn.VpcAttribute(d.Id(), "enableDnsSupport") 130 if err != nil { 131 return err 132 } 133 d.Set("enable_dns_support", resp.EnableDnsSupport) 134 135 resp, err = ec2conn.VpcAttribute(d.Id(), "enableDnsHostnames") 136 if err != nil { 137 return err 138 } 139 d.Set("enable_dns_hostnames", resp.EnableDnsHostnames) 140 141 // Get the main routing table for this VPC 142 filter := ec2.NewFilter() 143 filter.Add("association.main", "true") 144 filter.Add("vpc-id", d.Id()) 145 routeResp, err := ec2conn.DescribeRouteTables(nil, filter) 146 if err != nil { 147 return err 148 } 149 if v := routeResp.RouteTables; len(v) > 0 { 150 d.Set("main_route_table_id", v[0].RouteTableId) 151 } 152 153 resourceAwsVpcSetDefaultNetworkAcl(ec2conn, d) 154 resourceAwsVpcSetDefaultSecurityGroup(ec2conn, d) 155 156 return nil 157 } 158 159 func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error { 160 ec2conn := meta.(*AWSClient).ec2conn 161 162 // Turn on partial mode 163 d.Partial(true) 164 165 if d.HasChange("enable_dns_hostnames") { 166 options := new(ec2.ModifyVpcAttribute) 167 options.EnableDnsHostnames = d.Get("enable_dns_hostnames").(bool) 168 options.SetEnableDnsHostnames = true 169 170 log.Printf( 171 "[INFO] Modifying enable_dns_hostnames vpc attribute for %s: %#v", 172 d.Id(), options) 173 if _, err := ec2conn.ModifyVpcAttribute(d.Id(), options); err != nil { 174 return err 175 } 176 177 d.SetPartial("enable_dns_hostnames") 178 } 179 180 if d.HasChange("enable_dns_support") { 181 options := new(ec2.ModifyVpcAttribute) 182 options.EnableDnsSupport = d.Get("enable_dns_support").(bool) 183 options.SetEnableDnsSupport = true 184 185 log.Printf( 186 "[INFO] Modifying enable_dns_support vpc attribute for %s: %#v", 187 d.Id(), options) 188 if _, err := ec2conn.ModifyVpcAttribute(d.Id(), options); err != nil { 189 return err 190 } 191 192 d.SetPartial("enable_dns_support") 193 } 194 195 if err := setTags(ec2conn, d); err != nil { 196 return err 197 } else { 198 d.SetPartial("tags") 199 } 200 201 d.Partial(false) 202 return resourceAwsVpcRead(d, meta) 203 } 204 205 func resourceAwsVpcDelete(d *schema.ResourceData, meta interface{}) error { 206 ec2conn := meta.(*AWSClient).ec2conn 207 208 log.Printf("[INFO] Deleting VPC: %s", d.Id()) 209 if _, err := ec2conn.DeleteVpc(d.Id()); err != nil { 210 ec2err, ok := err.(*ec2.Error) 211 if ok && ec2err.Code == "InvalidVpcID.NotFound" { 212 return nil 213 } 214 215 return fmt.Errorf("Error deleting VPC: %s", err) 216 } 217 218 return nil 219 } 220 221 // VPCStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch 222 // a VPC. 223 func VPCStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { 224 return func() (interface{}, string, error) { 225 resp, err := conn.DescribeVpcs([]string{id}, ec2.NewFilter()) 226 if err != nil { 227 if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidVpcID.NotFound" { 228 resp = nil 229 } else { 230 log.Printf("Error on VPCStateRefresh: %s", err) 231 return nil, "", err 232 } 233 } 234 235 if resp == nil { 236 // Sometimes AWS just has consistency issues and doesn't see 237 // our instance yet. Return an empty state. 238 return nil, "", nil 239 } 240 241 vpc := &resp.VPCs[0] 242 return vpc, vpc.State, nil 243 } 244 } 245 246 func resourceAwsVpcSetDefaultNetworkAcl(conn *ec2.EC2, d *schema.ResourceData) error { 247 filter := ec2.NewFilter() 248 filter.Add("default", "true") 249 filter.Add("vpc-id", d.Id()) 250 networkAclResp, err := conn.NetworkAcls(nil, filter) 251 252 if err != nil { 253 return err 254 } 255 if v := networkAclResp.NetworkAcls; len(v) > 0 { 256 d.Set("default_network_acl_id", v[0].NetworkAclId) 257 } 258 259 return nil 260 } 261 262 func resourceAwsVpcSetDefaultSecurityGroup(conn *ec2.EC2, d *schema.ResourceData) error { 263 filter := ec2.NewFilter() 264 filter.Add("group-name", "default") 265 filter.Add("vpc-id", d.Id()) 266 securityGroupResp, err := conn.SecurityGroups(nil, filter) 267 268 if err != nil { 269 return err 270 } 271 if v := securityGroupResp.Groups; len(v) > 0 { 272 d.Set("default_security_group_id", v[0].Id) 273 } 274 275 return nil 276 }