github.com/nalum/terraform@v0.3.2-0.20141223102918-aa2c22ffeff6/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 "tags": tagsSchema(), 51 }, 52 } 53 } 54 55 func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error { 56 ec2conn := meta.(*AWSClient).ec2conn 57 58 // Create the VPC 59 createOpts := &ec2.CreateVpc{ 60 CidrBlock: d.Get("cidr_block").(string), 61 InstanceTenancy: d.Get("instance_tenancy").(string), 62 } 63 log.Printf("[DEBUG] VPC create config: %#v", createOpts) 64 vpcResp, err := ec2conn.CreateVpc(createOpts) 65 if err != nil { 66 return fmt.Errorf("Error creating VPC: %s", err) 67 } 68 69 // Get the ID and store it 70 vpc := &vpcResp.VPC 71 log.Printf("[INFO] VPC ID: %s", vpc.VpcId) 72 d.SetId(vpc.VpcId) 73 74 // Set partial mode and say that we setup the cidr block 75 d.Partial(true) 76 d.SetPartial("cidr_block") 77 78 // Wait for the VPC to become available 79 log.Printf( 80 "[DEBUG] Waiting for VPC (%s) to become available", 81 d.Id()) 82 stateConf := &resource.StateChangeConf{ 83 Pending: []string{"pending"}, 84 Target: "available", 85 Refresh: VPCStateRefreshFunc(ec2conn, d.Id()), 86 Timeout: 10 * time.Minute, 87 } 88 if _, err := stateConf.WaitForState(); err != nil { 89 return fmt.Errorf( 90 "Error waiting for VPC (%s) to become available: %s", 91 d.Id(), err) 92 } 93 94 // Update our attributes and return 95 return resourceAwsVpcUpdate(d, meta) 96 } 97 98 func resourceAwsVpcRead(d *schema.ResourceData, meta interface{}) error { 99 ec2conn := meta.(*AWSClient).ec2conn 100 101 // Refresh the VPC state 102 vpcRaw, _, err := VPCStateRefreshFunc(ec2conn, d.Id())() 103 if err != nil { 104 return err 105 } 106 if vpcRaw == nil { 107 return nil 108 } 109 110 // VPC stuff 111 vpc := vpcRaw.(*ec2.VPC) 112 d.Set("cidr_block", vpc.CidrBlock) 113 114 // Tags 115 d.Set("tags", tagsToMap(vpc.Tags)) 116 117 // Attributes 118 resp, err := ec2conn.VpcAttribute(d.Id(), "enableDnsSupport") 119 if err != nil { 120 return err 121 } 122 d.Set("enable_dns_support", resp.EnableDnsSupport) 123 124 resp, err = ec2conn.VpcAttribute(d.Id(), "enableDnsHostnames") 125 if err != nil { 126 return err 127 } 128 d.Set("enable_dns_hostnames", resp.EnableDnsHostnames) 129 130 // Get the main routing table for this VPC 131 filter := ec2.NewFilter() 132 filter.Add("association.main", "true") 133 filter.Add("vpc-id", d.Id()) 134 routeResp, err := ec2conn.DescribeRouteTables(nil, filter) 135 if err != nil { 136 return err 137 } 138 if v := routeResp.RouteTables; len(v) > 0 { 139 d.Set("main_route_table_id", v[0].RouteTableId) 140 } 141 142 return nil 143 } 144 145 func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error { 146 ec2conn := meta.(*AWSClient).ec2conn 147 148 // Turn on partial mode 149 d.Partial(true) 150 151 if d.HasChange("enable_dns_hostnames") { 152 options := new(ec2.ModifyVpcAttribute) 153 options.EnableDnsHostnames = d.Get("enable_dns_hostnames").(bool) 154 options.SetEnableDnsHostnames = true 155 156 log.Printf( 157 "[INFO] Modifying enable_dns_hostnames vpc attribute for %s: %#v", 158 d.Id(), options) 159 if _, err := ec2conn.ModifyVpcAttribute(d.Id(), options); err != nil { 160 return err 161 } 162 163 d.SetPartial("enable_dns_hostnames") 164 } 165 166 if d.HasChange("enable_dns_support") { 167 options := new(ec2.ModifyVpcAttribute) 168 options.EnableDnsSupport = d.Get("enable_dns_support").(bool) 169 options.SetEnableDnsSupport = true 170 171 log.Printf( 172 "[INFO] Modifying enable_dns_support vpc attribute for %s: %#v", 173 d.Id(), options) 174 if _, err := ec2conn.ModifyVpcAttribute(d.Id(), options); err != nil { 175 return err 176 } 177 178 d.SetPartial("enable_dns_support") 179 } 180 181 if err := setTags(ec2conn, d); err != nil { 182 return err 183 } else { 184 d.SetPartial("tags") 185 } 186 187 d.Partial(false) 188 return resourceAwsVpcRead(d, meta) 189 } 190 191 func resourceAwsVpcDelete(d *schema.ResourceData, meta interface{}) error { 192 ec2conn := meta.(*AWSClient).ec2conn 193 194 log.Printf("[INFO] Deleting VPC: %s", d.Id()) 195 if _, err := ec2conn.DeleteVpc(d.Id()); err != nil { 196 ec2err, ok := err.(*ec2.Error) 197 if ok && ec2err.Code == "InvalidVpcID.NotFound" { 198 return nil 199 } 200 201 return fmt.Errorf("Error deleting VPC: %s", err) 202 } 203 204 return nil 205 } 206 207 // VPCStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch 208 // a VPC. 209 func VPCStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { 210 return func() (interface{}, string, error) { 211 resp, err := conn.DescribeVpcs([]string{id}, ec2.NewFilter()) 212 if err != nil { 213 if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidVpcID.NotFound" { 214 resp = nil 215 } else { 216 log.Printf("Error on VPCStateRefresh: %s", err) 217 return nil, "", err 218 } 219 } 220 221 if resp == nil { 222 // Sometimes AWS just has consistency issues and doesn't see 223 // our instance yet. Return an empty state. 224 return nil, "", nil 225 } 226 227 vpc := &resp.VPCs[0] 228 return vpc, vpc.State, nil 229 } 230 }