github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_vpn_gateway_attachment.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/hashcode"
    12  	"github.com/hashicorp/terraform/helper/resource"
    13  	"github.com/hashicorp/terraform/helper/schema"
    14  )
    15  
    16  func resourceAwsVpnGatewayAttachment() *schema.Resource {
    17  	return &schema.Resource{
    18  		Create: resourceAwsVpnGatewayAttachmentCreate,
    19  		Read:   resourceAwsVpnGatewayAttachmentRead,
    20  		Delete: resourceAwsVpnGatewayAttachmentDelete,
    21  
    22  		Schema: map[string]*schema.Schema{
    23  			"vpc_id": &schema.Schema{
    24  				Type:     schema.TypeString,
    25  				Required: true,
    26  				ForceNew: true,
    27  			},
    28  			"vpn_gateway_id": &schema.Schema{
    29  				Type:     schema.TypeString,
    30  				Required: true,
    31  				ForceNew: true,
    32  			},
    33  		},
    34  	}
    35  }
    36  
    37  func resourceAwsVpnGatewayAttachmentCreate(d *schema.ResourceData, meta interface{}) error {
    38  	conn := meta.(*AWSClient).ec2conn
    39  
    40  	vpcId := d.Get("vpc_id").(string)
    41  	vgwId := d.Get("vpn_gateway_id").(string)
    42  
    43  	createOpts := &ec2.AttachVpnGatewayInput{
    44  		VpcId:        aws.String(vpcId),
    45  		VpnGatewayId: aws.String(vgwId),
    46  	}
    47  	log.Printf("[DEBUG] VPN Gateway attachment options: %#v", *createOpts)
    48  
    49  	_, err := conn.AttachVpnGateway(createOpts)
    50  	if err != nil {
    51  		return fmt.Errorf("Error attaching VPN Gateway %q to VPC %q: %s",
    52  			vgwId, vpcId, err)
    53  	}
    54  
    55  	d.SetId(vpnGatewayAttachmentId(vpcId, vgwId))
    56  	log.Printf("[INFO] VPN Gateway %q attachment ID: %s", vgwId, d.Id())
    57  
    58  	stateConf := &resource.StateChangeConf{
    59  		Pending:    []string{"detached", "attaching"},
    60  		Target:     []string{"attached"},
    61  		Refresh:    vpnGatewayAttachmentStateRefresh(conn, vpcId, vgwId),
    62  		Timeout:    15 * time.Minute,
    63  		Delay:      10 * time.Second,
    64  		MinTimeout: 5 * time.Second,
    65  	}
    66  
    67  	_, err = stateConf.WaitForState()
    68  	if err != nil {
    69  		return fmt.Errorf("Error waiting for VPN Gateway %q to attach to VPC %q: %s",
    70  			vgwId, vpcId, err)
    71  	}
    72  	log.Printf("[DEBUG] VPN Gateway %q attached to VPC %q.", vgwId, vpcId)
    73  
    74  	return resourceAwsVpnGatewayAttachmentRead(d, meta)
    75  }
    76  
    77  func resourceAwsVpnGatewayAttachmentRead(d *schema.ResourceData, meta interface{}) error {
    78  	conn := meta.(*AWSClient).ec2conn
    79  
    80  	vgwId := d.Get("vpn_gateway_id").(string)
    81  
    82  	resp, err := conn.DescribeVpnGateways(&ec2.DescribeVpnGatewaysInput{
    83  		VpnGatewayIds: []*string{aws.String(vgwId)},
    84  	})
    85  
    86  	if err != nil {
    87  		awsErr, ok := err.(awserr.Error)
    88  		if ok && awsErr.Code() == "InvalidVPNGatewayID.NotFound" {
    89  			log.Printf("[WARN] VPN Gateway %q not found.", vgwId)
    90  			d.SetId("")
    91  			return nil
    92  		}
    93  		return err
    94  	}
    95  
    96  	vgw := resp.VpnGateways[0]
    97  	if *vgw.State == "deleted" {
    98  		log.Printf("[INFO] VPN Gateway %q appears to have been deleted.", vgwId)
    99  		d.SetId("")
   100  		return nil
   101  	}
   102  
   103  	vga := vpnGatewayGetAttachment(vgw)
   104  	if len(vgw.VpcAttachments) == 0 || *vga.State == "detached" {
   105  		d.Set("vpc_id", "")
   106  		return nil
   107  	}
   108  
   109  	d.Set("vpc_id", *vga.VpcId)
   110  	return nil
   111  }
   112  
   113  func resourceAwsVpnGatewayAttachmentDelete(d *schema.ResourceData, meta interface{}) error {
   114  	conn := meta.(*AWSClient).ec2conn
   115  
   116  	vpcId := d.Get("vpc_id").(string)
   117  	vgwId := d.Get("vpn_gateway_id").(string)
   118  
   119  	if vpcId == "" {
   120  		log.Printf("[DEBUG] Not detaching VPN Gateway %q as no VPC ID is set.", vgwId)
   121  		return nil
   122  	}
   123  
   124  	_, err := conn.DetachVpnGateway(&ec2.DetachVpnGatewayInput{
   125  		VpcId:        aws.String(vpcId),
   126  		VpnGatewayId: aws.String(vgwId),
   127  	})
   128  
   129  	if err != nil {
   130  		awsErr, ok := err.(awserr.Error)
   131  		if ok {
   132  			switch awsErr.Code() {
   133  			case "InvalidVPNGatewayID.NotFound":
   134  				log.Printf("[WARN] VPN Gateway %q not found.", vgwId)
   135  				d.SetId("")
   136  				return nil
   137  			case "InvalidVpnGatewayAttachment.NotFound":
   138  				log.Printf(
   139  					"[WARN] VPN Gateway %q attachment to VPC %q not found.",
   140  					vgwId, vpcId)
   141  				d.SetId("")
   142  				return nil
   143  			}
   144  		}
   145  
   146  		return fmt.Errorf("Error detaching VPN Gateway %q from VPC %q: %s",
   147  			vgwId, vpcId, err)
   148  	}
   149  
   150  	stateConf := &resource.StateChangeConf{
   151  		Pending:    []string{"attached", "detaching"},
   152  		Target:     []string{"detached"},
   153  		Refresh:    vpnGatewayAttachmentStateRefresh(conn, vpcId, vgwId),
   154  		Timeout:    15 * time.Minute,
   155  		Delay:      10 * time.Second,
   156  		MinTimeout: 5 * time.Second,
   157  	}
   158  
   159  	_, err = stateConf.WaitForState()
   160  	if err != nil {
   161  		return fmt.Errorf("Error waiting for VPN Gateway %q to detach from VPC %q: %s",
   162  			vgwId, vpcId, err)
   163  	}
   164  	log.Printf("[DEBUG] VPN Gateway %q detached from VPC %q.", vgwId, vpcId)
   165  
   166  	d.SetId("")
   167  	return nil
   168  }
   169  
   170  func vpnGatewayAttachmentStateRefresh(conn *ec2.EC2, vpcId, vgwId string) resource.StateRefreshFunc {
   171  	return func() (interface{}, string, error) {
   172  		resp, err := conn.DescribeVpnGateways(&ec2.DescribeVpnGatewaysInput{
   173  			Filters: []*ec2.Filter{
   174  				&ec2.Filter{
   175  					Name:   aws.String("attachment.vpc-id"),
   176  					Values: []*string{aws.String(vpcId)},
   177  				},
   178  			},
   179  			VpnGatewayIds: []*string{aws.String(vgwId)},
   180  		})
   181  
   182  		if err != nil {
   183  			awsErr, ok := err.(awserr.Error)
   184  			if ok {
   185  				switch awsErr.Code() {
   186  				case "InvalidVPNGatewayID.NotFound":
   187  					fallthrough
   188  				case "InvalidVpnGatewayAttachment.NotFound":
   189  					return nil, "", nil
   190  				}
   191  			}
   192  
   193  			return nil, "", err
   194  		}
   195  
   196  		vgw := resp.VpnGateways[0]
   197  		if len(vgw.VpcAttachments) == 0 {
   198  			return vgw, "detached", nil
   199  		}
   200  
   201  		vga := vpnGatewayGetAttachment(vgw)
   202  
   203  		log.Printf("[DEBUG] VPN Gateway %q attachment status: %s", vgwId, *vga.State)
   204  		return vgw, *vga.State, nil
   205  	}
   206  }
   207  
   208  func vpnGatewayAttachmentId(vpcId, vgwId string) string {
   209  	return fmt.Sprintf("vpn-attachment-%x", hashcode.String(fmt.Sprintf("%s-%s", vpcId, vgwId)))
   210  }