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