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  }