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 }