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