github.com/bendemaree/terraform@v0.5.4-0.20150613200311-f50d97d6eee6/builtin/providers/aws/resource_aws_vpc.go (about)

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