github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/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  
    30  			"peer_ip": &schema.Schema{
    31  				Type:         schema.TypeString,
    32  				Required:     true,
    33  				ForceNew:     true,
    34  				ValidateFunc: validatePeerAddr,
    35  			},
    36  
    37  			"shared_secret": &schema.Schema{
    38  				Type:     schema.TypeString,
    39  				Required: true,
    40  				ForceNew: true,
    41  			},
    42  
    43  			"target_vpn_gateway": &schema.Schema{
    44  				Type:     schema.TypeString,
    45  				Required: true,
    46  				ForceNew: true,
    47  			},
    48  
    49  			"description": &schema.Schema{
    50  				Type:     schema.TypeString,
    51  				Optional: true,
    52  				ForceNew: true,
    53  			},
    54  
    55  			"detailed_status": &schema.Schema{
    56  				Type:     schema.TypeString,
    57  				Computed: true,
    58  			},
    59  
    60  			"ike_version": &schema.Schema{
    61  				Type:     schema.TypeInt,
    62  				Optional: true,
    63  				Default:  2,
    64  				ForceNew: true,
    65  			},
    66  
    67  			"local_traffic_selector": &schema.Schema{
    68  				Type:     schema.TypeSet,
    69  				Optional: true,
    70  				ForceNew: true,
    71  				Computed: true,
    72  				Elem:     &schema.Schema{Type: schema.TypeString},
    73  				Set:      schema.HashString,
    74  			},
    75  
    76  			"remote_traffic_selector": &schema.Schema{
    77  				Type:     schema.TypeSet,
    78  				Optional: true,
    79  				ForceNew: true,
    80  				Elem:     &schema.Schema{Type: schema.TypeString},
    81  				Set:      schema.HashString,
    82  			},
    83  
    84  			"project": &schema.Schema{
    85  				Type:     schema.TypeString,
    86  				Optional: true,
    87  				ForceNew: true,
    88  			},
    89  
    90  			"region": &schema.Schema{
    91  				Type:     schema.TypeString,
    92  				Optional: true,
    93  				ForceNew: true,
    94  			},
    95  
    96  			"self_link": &schema.Schema{
    97  				Type:     schema.TypeString,
    98  				Computed: true,
    99  			},
   100  		},
   101  	}
   102  }
   103  
   104  func resourceComputeVpnTunnelCreate(d *schema.ResourceData, meta interface{}) error {
   105  	config := meta.(*Config)
   106  
   107  	region, err := getRegion(d, config)
   108  	if err != nil {
   109  		return err
   110  	}
   111  
   112  	project, err := getProject(d, config)
   113  	if err != nil {
   114  		return err
   115  	}
   116  
   117  	name := d.Get("name").(string)
   118  	peerIp := d.Get("peer_ip").(string)
   119  	sharedSecret := d.Get("shared_secret").(string)
   120  	targetVpnGateway := d.Get("target_vpn_gateway").(string)
   121  	ikeVersion := d.Get("ike_version").(int)
   122  
   123  	if ikeVersion < 1 || ikeVersion > 2 {
   124  		return fmt.Errorf("Only IKE version 1 or 2 supported, not %d", ikeVersion)
   125  	}
   126  
   127  	// Build up the list of sources
   128  	var localTrafficSelectors []string
   129  	if v := d.Get("local_traffic_selector").(*schema.Set); v.Len() > 0 {
   130  		localTrafficSelectors = make([]string, v.Len())
   131  		for i, v := range v.List() {
   132  			localTrafficSelectors[i] = v.(string)
   133  		}
   134  	}
   135  
   136  	var remoteTrafficSelectors []string
   137  	if v := d.Get("remote_traffic_selector").(*schema.Set); v.Len() > 0 {
   138  		remoteTrafficSelectors = make([]string, v.Len())
   139  		for i, v := range v.List() {
   140  			remoteTrafficSelectors[i] = v.(string)
   141  		}
   142  	}
   143  
   144  	vpnTunnelsService := compute.NewVpnTunnelsService(config.clientCompute)
   145  
   146  	vpnTunnel := &compute.VpnTunnel{
   147  		Name:                  name,
   148  		PeerIp:                peerIp,
   149  		SharedSecret:          sharedSecret,
   150  		TargetVpnGateway:      targetVpnGateway,
   151  		IkeVersion:            int64(ikeVersion),
   152  		LocalTrafficSelector:  localTrafficSelectors,
   153  		RemoteTrafficSelector: remoteTrafficSelectors,
   154  	}
   155  
   156  	if v, ok := d.GetOk("description"); ok {
   157  		vpnTunnel.Description = v.(string)
   158  	}
   159  
   160  	op, err := vpnTunnelsService.Insert(project, region, vpnTunnel).Do()
   161  	if err != nil {
   162  		return fmt.Errorf("Error Inserting VPN Tunnel %s : %s", name, err)
   163  	}
   164  
   165  	err = computeOperationWaitRegion(config, op, project, region, "Inserting VPN Tunnel")
   166  	if err != nil {
   167  		return fmt.Errorf("Error Waiting to Insert VPN Tunnel %s: %s", name, err)
   168  	}
   169  
   170  	return resourceComputeVpnTunnelRead(d, meta)
   171  }
   172  
   173  func resourceComputeVpnTunnelRead(d *schema.ResourceData, meta interface{}) error {
   174  	config := meta.(*Config)
   175  
   176  	region, err := getRegion(d, config)
   177  	if err != nil {
   178  		return err
   179  	}
   180  
   181  	project, err := getProject(d, config)
   182  	if err != nil {
   183  		return err
   184  	}
   185  
   186  	name := d.Get("name").(string)
   187  
   188  	vpnTunnelsService := compute.NewVpnTunnelsService(config.clientCompute)
   189  
   190  	vpnTunnel, err := vpnTunnelsService.Get(project, region, name).Do()
   191  	if err != nil {
   192  		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
   193  			log.Printf("[WARN] Removing VPN Tunnel %q because it's gone", d.Get("name").(string))
   194  			// The resource doesn't exist anymore
   195  			d.SetId("")
   196  
   197  			return nil
   198  		}
   199  
   200  		return fmt.Errorf("Error Reading VPN Tunnel %s: %s", name, err)
   201  	}
   202  
   203  	localTrafficSelectors := []string{}
   204  	for _, lts := range vpnTunnel.LocalTrafficSelector {
   205  		localTrafficSelectors = append(localTrafficSelectors, lts)
   206  	}
   207  	d.Set("local_traffic_selector", localTrafficSelectors)
   208  
   209  	remoteTrafficSelectors := []string{}
   210  	for _, rts := range vpnTunnel.RemoteTrafficSelector {
   211  		remoteTrafficSelectors = append(remoteTrafficSelectors, rts)
   212  	}
   213  	d.Set("remote_traffic_selector", remoteTrafficSelectors)
   214  
   215  	d.Set("detailed_status", vpnTunnel.DetailedStatus)
   216  	d.Set("self_link", vpnTunnel.SelfLink)
   217  
   218  	d.SetId(name)
   219  
   220  	return nil
   221  }
   222  
   223  func resourceComputeVpnTunnelDelete(d *schema.ResourceData, meta interface{}) error {
   224  	config := meta.(*Config)
   225  
   226  	region, err := getRegion(d, config)
   227  	if err != nil {
   228  		return err
   229  	}
   230  
   231  	project, err := getProject(d, config)
   232  	if err != nil {
   233  		return err
   234  	}
   235  
   236  	name := d.Get("name").(string)
   237  
   238  	vpnTunnelsService := compute.NewVpnTunnelsService(config.clientCompute)
   239  
   240  	op, err := vpnTunnelsService.Delete(project, region, name).Do()
   241  	if err != nil {
   242  		return fmt.Errorf("Error Reading VPN Tunnel %s: %s", name, err)
   243  	}
   244  
   245  	err = computeOperationWaitRegion(config, op, project, region, "Deleting VPN Tunnel")
   246  	if err != nil {
   247  		return fmt.Errorf("Error Waiting to Delete VPN Tunnel %s: %s", name, err)
   248  	}
   249  
   250  	return nil
   251  }
   252  
   253  // validatePeerAddr returns false if a tunnel's peer_ip property
   254  // is invalid. Currently, only addresses that collide with RFC
   255  // 5735 (https://tools.ietf.org/html/rfc5735) fail validation.
   256  func validatePeerAddr(i interface{}, val string) ([]string, []error) {
   257  	ip := net.ParseIP(i.(string))
   258  	if ip == nil {
   259  		return nil, []error{fmt.Errorf("could not parse %q to IP address", val)}
   260  	}
   261  	for _, test := range invalidPeerAddrs {
   262  		if bytes.Compare(ip, test.from) >= 0 && bytes.Compare(ip, test.to) <= 0 {
   263  			return nil, []error{fmt.Errorf("address is invalid (is between %q and %q, conflicting with RFC5735)", test.from, test.to)}
   264  		}
   265  	}
   266  	return nil, nil
   267  }
   268  
   269  // invalidPeerAddrs is a collection of IP addres ranges that represent
   270  // a conflict with RFC 5735 (https://tools.ietf.org/html/rfc5735#page-3).
   271  // CIDR range notations in the RFC were converted to a (from, to) pair
   272  // for easy checking with bytes.Compare.
   273  var invalidPeerAddrs = []struct {
   274  	from net.IP
   275  	to   net.IP
   276  }{
   277  	{
   278  		from: net.ParseIP("0.0.0.0"),
   279  		to:   net.ParseIP("0.255.255.255"),
   280  	},
   281  	{
   282  		from: net.ParseIP("10.0.0.0"),
   283  		to:   net.ParseIP("10.255.255.255"),
   284  	},
   285  	{
   286  		from: net.ParseIP("127.0.0.0"),
   287  		to:   net.ParseIP("127.255.255.255"),
   288  	},
   289  	{
   290  		from: net.ParseIP("169.254.0.0"),
   291  		to:   net.ParseIP("169.254.255.255"),
   292  	},
   293  	{
   294  		from: net.ParseIP("172.16.0.0"),
   295  		to:   net.ParseIP("172.31.255.255"),
   296  	},
   297  	{
   298  		from: net.ParseIP("192.0.0.0"),
   299  		to:   net.ParseIP("192.0.0.255"),
   300  	},
   301  	{
   302  		from: net.ParseIP("192.0.2.0"),
   303  		to:   net.ParseIP("192.0.2.255"),
   304  	},
   305  	{
   306  		from: net.ParseIP("192.88.99.0"),
   307  		to:   net.ParseIP("192.88.99.255"),
   308  	},
   309  	{
   310  		from: net.ParseIP("192.168.0.0"),
   311  		to:   net.ParseIP("192.168.255.255"),
   312  	},
   313  	{
   314  		from: net.ParseIP("198.18.0.0"),
   315  		to:   net.ParseIP("198.19.255.255"),
   316  	},
   317  	{
   318  		from: net.ParseIP("198.51.100.0"),
   319  		to:   net.ParseIP("198.51.100.255"),
   320  	},
   321  	{
   322  		from: net.ParseIP("203.0.113.0"),
   323  		to:   net.ParseIP("203.0.113.255"),
   324  	},
   325  	{
   326  		from: net.ParseIP("224.0.0.0"),
   327  		to:   net.ParseIP("239.255.255.255"),
   328  	},
   329  	{
   330  		from: net.ParseIP("240.0.0.0"),
   331  		to:   net.ParseIP("255.255.255.255"),
   332  	},
   333  	{
   334  		from: net.ParseIP("255.255.255.255"),
   335  		to:   net.ParseIP("255.255.255.255"),
   336  	},
   337  }