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  }