github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_customer_gateway.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "strconv" 7 "time" 8 9 "github.com/aws/aws-sdk-go/aws" 10 "github.com/aws/aws-sdk-go/aws/awserr" 11 "github.com/aws/aws-sdk-go/service/ec2" 12 13 "github.com/hashicorp/terraform/helper/resource" 14 "github.com/hashicorp/terraform/helper/schema" 15 ) 16 17 func resourceAwsCustomerGateway() *schema.Resource { 18 return &schema.Resource{ 19 Create: resourceAwsCustomerGatewayCreate, 20 Read: resourceAwsCustomerGatewayRead, 21 Update: resourceAwsCustomerGatewayUpdate, 22 Delete: resourceAwsCustomerGatewayDelete, 23 Importer: &schema.ResourceImporter{ 24 State: schema.ImportStatePassthrough, 25 }, 26 27 Schema: map[string]*schema.Schema{ 28 "bgp_asn": { 29 Type: schema.TypeInt, 30 Required: true, 31 ForceNew: true, 32 }, 33 34 "ip_address": { 35 Type: schema.TypeString, 36 Required: true, 37 ForceNew: true, 38 }, 39 40 "type": { 41 Type: schema.TypeString, 42 Required: true, 43 ForceNew: true, 44 }, 45 46 "tags": tagsSchema(), 47 }, 48 } 49 } 50 51 func resourceAwsCustomerGatewayCreate(d *schema.ResourceData, meta interface{}) error { 52 conn := meta.(*AWSClient).ec2conn 53 54 ipAddress := d.Get("ip_address").(string) 55 vpnType := d.Get("type").(string) 56 bgpAsn := d.Get("bgp_asn").(int) 57 58 alreadyExists, err := resourceAwsCustomerGatewayExists(vpnType, ipAddress, bgpAsn, conn) 59 if err != nil { 60 return err 61 } 62 63 if alreadyExists { 64 return fmt.Errorf("An existing customer gateway for IpAddress: %s, VpnType: %s, BGP ASN: %d has been found", ipAddress, vpnType, bgpAsn) 65 } 66 67 createOpts := &ec2.CreateCustomerGatewayInput{ 68 BgpAsn: aws.Int64(int64(bgpAsn)), 69 PublicIp: aws.String(ipAddress), 70 Type: aws.String(vpnType), 71 } 72 73 // Create the Customer Gateway. 74 log.Printf("[DEBUG] Creating customer gateway") 75 resp, err := conn.CreateCustomerGateway(createOpts) 76 if err != nil { 77 return fmt.Errorf("Error creating customer gateway: %s", err) 78 } 79 80 // Store the ID 81 customerGateway := resp.CustomerGateway 82 d.SetId(*customerGateway.CustomerGatewayId) 83 log.Printf("[INFO] Customer gateway ID: %s", *customerGateway.CustomerGatewayId) 84 85 // Wait for the CustomerGateway to be available. 86 stateConf := &resource.StateChangeConf{ 87 Pending: []string{"pending"}, 88 Target: []string{"available"}, 89 Refresh: customerGatewayRefreshFunc(conn, *customerGateway.CustomerGatewayId), 90 Timeout: 10 * time.Minute, 91 Delay: 10 * time.Second, 92 MinTimeout: 3 * time.Second, 93 } 94 95 _, stateErr := stateConf.WaitForState() 96 if stateErr != nil { 97 return fmt.Errorf( 98 "Error waiting for customer gateway (%s) to become ready: %s", 99 *customerGateway.CustomerGatewayId, err) 100 } 101 102 // Create tags. 103 if err := setTags(conn, d); err != nil { 104 return err 105 } 106 107 return nil 108 } 109 110 func customerGatewayRefreshFunc(conn *ec2.EC2, gatewayId string) resource.StateRefreshFunc { 111 return func() (interface{}, string, error) { 112 gatewayFilter := &ec2.Filter{ 113 Name: aws.String("customer-gateway-id"), 114 Values: []*string{aws.String(gatewayId)}, 115 } 116 117 resp, err := conn.DescribeCustomerGateways(&ec2.DescribeCustomerGatewaysInput{ 118 Filters: []*ec2.Filter{gatewayFilter}, 119 }) 120 if err != nil { 121 if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidCustomerGatewayID.NotFound" { 122 resp = nil 123 } else { 124 log.Printf("Error on CustomerGatewayRefresh: %s", err) 125 return nil, "", err 126 } 127 } 128 129 if resp == nil || len(resp.CustomerGateways) == 0 { 130 // handle consistency issues 131 return nil, "", nil 132 } 133 134 gateway := resp.CustomerGateways[0] 135 return gateway, *gateway.State, nil 136 } 137 } 138 139 func resourceAwsCustomerGatewayExists(vpnType, ipAddress string, bgpAsn int, conn *ec2.EC2) (bool, error) { 140 ipAddressFilter := &ec2.Filter{ 141 Name: aws.String("ip-address"), 142 Values: []*string{aws.String(ipAddress)}, 143 } 144 145 typeFilter := &ec2.Filter{ 146 Name: aws.String("type"), 147 Values: []*string{aws.String(vpnType)}, 148 } 149 150 bgp := strconv.Itoa(bgpAsn) 151 bgpAsnFilter := &ec2.Filter{ 152 Name: aws.String("bgp-asn"), 153 Values: []*string{aws.String(bgp)}, 154 } 155 156 resp, err := conn.DescribeCustomerGateways(&ec2.DescribeCustomerGatewaysInput{ 157 Filters: []*ec2.Filter{ipAddressFilter, typeFilter, bgpAsnFilter}, 158 }) 159 if err != nil { 160 return false, err 161 } 162 163 if len(resp.CustomerGateways) > 0 && *resp.CustomerGateways[0].State != "deleted" { 164 return true, nil 165 } 166 167 return false, nil 168 } 169 170 func resourceAwsCustomerGatewayRead(d *schema.ResourceData, meta interface{}) error { 171 conn := meta.(*AWSClient).ec2conn 172 173 gatewayFilter := &ec2.Filter{ 174 Name: aws.String("customer-gateway-id"), 175 Values: []*string{aws.String(d.Id())}, 176 } 177 178 resp, err := conn.DescribeCustomerGateways(&ec2.DescribeCustomerGatewaysInput{ 179 Filters: []*ec2.Filter{gatewayFilter}, 180 }) 181 if err != nil { 182 if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidCustomerGatewayID.NotFound" { 183 d.SetId("") 184 return nil 185 } else { 186 log.Printf("[ERROR] Error finding CustomerGateway: %s", err) 187 return err 188 } 189 } 190 191 if len(resp.CustomerGateways) != 1 { 192 return fmt.Errorf("[ERROR] Error finding CustomerGateway: %s", d.Id()) 193 } 194 195 if *resp.CustomerGateways[0].State == "deleted" { 196 log.Printf("[INFO] Customer Gateway is in `deleted` state: %s", d.Id()) 197 d.SetId("") 198 return nil 199 } 200 201 customerGateway := resp.CustomerGateways[0] 202 d.Set("ip_address", customerGateway.IpAddress) 203 d.Set("type", customerGateway.Type) 204 d.Set("tags", tagsToMap(customerGateway.Tags)) 205 206 if *customerGateway.BgpAsn != "" { 207 val, err := strconv.ParseInt(*customerGateway.BgpAsn, 0, 0) 208 if err != nil { 209 return fmt.Errorf("error parsing bgp_asn: %s", err) 210 } 211 212 d.Set("bgp_asn", int(val)) 213 } 214 215 return nil 216 } 217 218 func resourceAwsCustomerGatewayUpdate(d *schema.ResourceData, meta interface{}) error { 219 conn := meta.(*AWSClient).ec2conn 220 221 // Update tags if required. 222 if err := setTags(conn, d); err != nil { 223 return err 224 } 225 226 d.SetPartial("tags") 227 228 return resourceAwsCustomerGatewayRead(d, meta) 229 } 230 231 func resourceAwsCustomerGatewayDelete(d *schema.ResourceData, meta interface{}) error { 232 conn := meta.(*AWSClient).ec2conn 233 234 _, err := conn.DeleteCustomerGateway(&ec2.DeleteCustomerGatewayInput{ 235 CustomerGatewayId: aws.String(d.Id()), 236 }) 237 if err != nil { 238 if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidCustomerGatewayID.NotFound" { 239 d.SetId("") 240 return nil 241 } else { 242 log.Printf("[ERROR] Error deleting CustomerGateway: %s", err) 243 return err 244 } 245 } 246 247 gatewayFilter := &ec2.Filter{ 248 Name: aws.String("customer-gateway-id"), 249 Values: []*string{aws.String(d.Id())}, 250 } 251 252 err = resource.Retry(5*time.Minute, func() *resource.RetryError { 253 resp, err := conn.DescribeCustomerGateways(&ec2.DescribeCustomerGatewaysInput{ 254 Filters: []*ec2.Filter{gatewayFilter}, 255 }) 256 257 if err != nil { 258 if awserr, ok := err.(awserr.Error); ok && awserr.Code() == "InvalidCustomerGatewayID.NotFound" { 259 return nil 260 } 261 return resource.NonRetryableError(err) 262 } 263 264 if len(resp.CustomerGateways) != 1 { 265 return resource.RetryableError(fmt.Errorf("[ERROR] Error finding CustomerGateway for delete: %s", d.Id())) 266 } 267 268 switch *resp.CustomerGateways[0].State { 269 case "pending", "available", "deleting": 270 return resource.RetryableError(fmt.Errorf("[DEBUG] Gateway (%s) in state (%s), retrying", d.Id(), *resp.CustomerGateways[0].State)) 271 case "deleted": 272 return nil 273 default: 274 return resource.RetryableError(fmt.Errorf("[DEBUG] Unrecognized state (%s) for Customer Gateway delete on (%s)", *resp.CustomerGateways[0].State, d.Id())) 275 } 276 }) 277 278 if err != nil { 279 return err 280 } 281 282 return nil 283 }