github.com/subuk/terraform@v0.6.14-0.20160317140351-de1567c2e732/builtin/providers/google/resource_compute_vpn_tunnel.go (about) 1 package google 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "net" 8 9 "github.com/hashicorp/terraform/helper/schema" 10 11 "google.golang.org/api/compute/v1" 12 "google.golang.org/api/googleapi" 13 ) 14 15 func resourceComputeVpnTunnel() *schema.Resource { 16 return &schema.Resource{ 17 // Unfortunately, the VPNTunnelService does not support update 18 // operations. This is why everything is marked forcenew 19 Create: resourceComputeVpnTunnelCreate, 20 Read: resourceComputeVpnTunnelRead, 21 Delete: resourceComputeVpnTunnelDelete, 22 23 Schema: map[string]*schema.Schema{ 24 "name": &schema.Schema{ 25 Type: schema.TypeString, 26 Required: true, 27 ForceNew: true, 28 }, 29 "description": &schema.Schema{ 30 Type: schema.TypeString, 31 Optional: true, 32 ForceNew: true, 33 }, 34 "region": &schema.Schema{ 35 Type: schema.TypeString, 36 Optional: true, 37 ForceNew: true, 38 }, 39 "peer_ip": &schema.Schema{ 40 Type: schema.TypeString, 41 Required: true, 42 ForceNew: true, 43 ValidateFunc: validatePeerAddr, 44 }, 45 "shared_secret": &schema.Schema{ 46 Type: schema.TypeString, 47 Required: true, 48 ForceNew: true, 49 }, 50 "target_vpn_gateway": &schema.Schema{ 51 Type: schema.TypeString, 52 Required: true, 53 ForceNew: true, 54 }, 55 "ike_version": &schema.Schema{ 56 Type: schema.TypeInt, 57 Optional: true, 58 Default: 2, 59 ForceNew: true, 60 }, 61 "local_traffic_selector": &schema.Schema{ 62 Type: schema.TypeSet, 63 Optional: true, 64 ForceNew: true, 65 Elem: &schema.Schema{Type: schema.TypeString}, 66 Set: schema.HashString, 67 }, 68 "detailed_status": &schema.Schema{ 69 Type: schema.TypeString, 70 Computed: true, 71 }, 72 "self_link": &schema.Schema{ 73 Type: schema.TypeString, 74 Computed: true, 75 }, 76 }, 77 } 78 } 79 80 func resourceComputeVpnTunnelCreate(d *schema.ResourceData, meta interface{}) error { 81 config := meta.(*Config) 82 83 name := d.Get("name").(string) 84 region := getOptionalRegion(d, config) 85 peerIp := d.Get("peer_ip").(string) 86 sharedSecret := d.Get("shared_secret").(string) 87 targetVpnGateway := d.Get("target_vpn_gateway").(string) 88 ikeVersion := d.Get("ike_version").(int) 89 project := config.Project 90 91 if ikeVersion < 1 || ikeVersion > 2 { 92 return fmt.Errorf("Only IKE version 1 or 2 supported, not %d", ikeVersion) 93 } 94 95 // Build up the list of sources 96 var localTrafficSelectors []string 97 if v := d.Get("local_traffic_selector").(*schema.Set); v.Len() > 0 { 98 localTrafficSelectors = make([]string, v.Len()) 99 for i, v := range v.List() { 100 localTrafficSelectors[i] = v.(string) 101 } 102 } 103 104 vpnTunnelsService := compute.NewVpnTunnelsService(config.clientCompute) 105 106 vpnTunnel := &compute.VpnTunnel{ 107 Name: name, 108 PeerIp: peerIp, 109 SharedSecret: sharedSecret, 110 TargetVpnGateway: targetVpnGateway, 111 IkeVersion: int64(ikeVersion), 112 LocalTrafficSelector: localTrafficSelectors, 113 } 114 115 if v, ok := d.GetOk("description"); ok { 116 vpnTunnel.Description = v.(string) 117 } 118 119 op, err := vpnTunnelsService.Insert(project, region, vpnTunnel).Do() 120 if err != nil { 121 return fmt.Errorf("Error Inserting VPN Tunnel %s : %s", name, err) 122 } 123 124 err = computeOperationWaitRegion(config, op, region, "Inserting VPN Tunnel") 125 if err != nil { 126 return fmt.Errorf("Error Waiting to Insert VPN Tunnel %s: %s", name, err) 127 } 128 129 return resourceComputeVpnTunnelRead(d, meta) 130 } 131 132 func resourceComputeVpnTunnelRead(d *schema.ResourceData, meta interface{}) error { 133 config := meta.(*Config) 134 135 name := d.Get("name").(string) 136 region := getOptionalRegion(d, config) 137 project := config.Project 138 139 vpnTunnelsService := compute.NewVpnTunnelsService(config.clientCompute) 140 141 vpnTunnel, err := vpnTunnelsService.Get(project, region, name).Do() 142 if err != nil { 143 if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { 144 log.Printf("[WARN] Removing VPN Tunnel %q because it's gone", d.Get("name").(string)) 145 // The resource doesn't exist anymore 146 d.SetId("") 147 148 return nil 149 } 150 151 return fmt.Errorf("Error Reading VPN Tunnel %s: %s", name, err) 152 } 153 154 d.Set("detailed_status", vpnTunnel.DetailedStatus) 155 d.Set("self_link", vpnTunnel.SelfLink) 156 157 d.SetId(name) 158 159 return nil 160 } 161 162 func resourceComputeVpnTunnelDelete(d *schema.ResourceData, meta interface{}) error { 163 config := meta.(*Config) 164 165 name := d.Get("name").(string) 166 region := getOptionalRegion(d, config) 167 project := config.Project 168 169 vpnTunnelsService := compute.NewVpnTunnelsService(config.clientCompute) 170 171 op, err := vpnTunnelsService.Delete(project, region, name).Do() 172 if err != nil { 173 return fmt.Errorf("Error Reading VPN Tunnel %s: %s", name, err) 174 } 175 176 err = computeOperationWaitRegion(config, op, region, "Deleting VPN Tunnel") 177 if err != nil { 178 return fmt.Errorf("Error Waiting to Delete VPN Tunnel %s: %s", name, err) 179 } 180 181 return nil 182 } 183 184 // validatePeerAddr returns false if a tunnel's peer_ip property 185 // is invalid. Currently, only addresses that collide with RFC 186 // 5735 (https://tools.ietf.org/html/rfc5735) fail validation. 187 func validatePeerAddr(i interface{}, val string) ([]string, []error) { 188 ip := net.ParseIP(i.(string)) 189 if ip == nil { 190 return nil, []error{fmt.Errorf("could not parse %q to IP address", val)} 191 } 192 for _, test := range invalidPeerAddrs { 193 if bytes.Compare(ip, test.from) >= 0 && bytes.Compare(ip, test.to) <= 0 { 194 return nil, []error{fmt.Errorf("address is invalid (is between %q and %q, conflicting with RFC5735)", test.from, test.to)} 195 } 196 } 197 return nil, nil 198 } 199 200 // invalidPeerAddrs is a collection of IP addres ranges that represent 201 // a conflict with RFC 5735 (https://tools.ietf.org/html/rfc5735#page-3). 202 // CIDR range notations in the RFC were converted to a (from, to) pair 203 // for easy checking with bytes.Compare. 204 var invalidPeerAddrs = []struct { 205 from net.IP 206 to net.IP 207 }{ 208 { 209 from: net.ParseIP("0.0.0.0"), 210 to: net.ParseIP("0.255.255.255"), 211 }, 212 { 213 from: net.ParseIP("10.0.0.0"), 214 to: net.ParseIP("10.255.255.255"), 215 }, 216 { 217 from: net.ParseIP("127.0.0.0"), 218 to: net.ParseIP("127.255.255.255"), 219 }, 220 { 221 from: net.ParseIP("169.254.0.0"), 222 to: net.ParseIP("169.254.255.255"), 223 }, 224 { 225 from: net.ParseIP("172.16.0.0"), 226 to: net.ParseIP("172.31.255.255"), 227 }, 228 { 229 from: net.ParseIP("192.0.0.0"), 230 to: net.ParseIP("192.0.0.255"), 231 }, 232 { 233 from: net.ParseIP("192.0.2.0"), 234 to: net.ParseIP("192.0.2.255"), 235 }, 236 { 237 from: net.ParseIP("192.88.99.0"), 238 to: net.ParseIP("192.88.99.255"), 239 }, 240 { 241 from: net.ParseIP("192.168.0.0"), 242 to: net.ParseIP("192.168.255.255"), 243 }, 244 { 245 from: net.ParseIP("198.18.0.0"), 246 to: net.ParseIP("198.19.255.255"), 247 }, 248 { 249 from: net.ParseIP("198.51.100.0"), 250 to: net.ParseIP("198.51.100.255"), 251 }, 252 { 253 from: net.ParseIP("203.0.113.0"), 254 to: net.ParseIP("203.0.113.255"), 255 }, 256 { 257 from: net.ParseIP("224.0.0.0"), 258 to: net.ParseIP("239.255.255.255"), 259 }, 260 { 261 from: net.ParseIP("240.0.0.0"), 262 to: net.ParseIP("255.255.255.255"), 263 }, 264 { 265 from: net.ParseIP("255.255.255.255"), 266 to: net.ParseIP("255.255.255.255"), 267 }, 268 }