Merge pull request #13123 from UKCloud/master

provider/vcd: Adding VPN Support to vCloud Provider
This commit is contained in:
Jake Champlin 2017-06-02 09:14:11 -04:00 committed by GitHub
commit 7d06a9bf43
4 changed files with 464 additions and 5 deletions

View File

@ -60,11 +60,12 @@ func Provider() terraform.ResourceProvider {
},
ResourcesMap: map[string]*schema.Resource{
"vcd_network": resourceVcdNetwork(),
"vcd_vapp": resourceVcdVApp(),
"vcd_firewall_rules": resourceVcdFirewallRules(),
"vcd_dnat": resourceVcdDNAT(),
"vcd_snat": resourceVcdSNAT(),
"vcd_network": resourceVcdNetwork(),
"vcd_vapp": resourceVcdVApp(),
"vcd_firewall_rules": resourceVcdFirewallRules(),
"vcd_dnat": resourceVcdDNAT(),
"vcd_snat": resourceVcdSNAT(),
"vcd_edgegateway_vpn": resourceVcdEdgeGatewayVpn(),
},
ConfigureFunc: providerConfigure,

View File

@ -0,0 +1,290 @@
package vcd
import (
"fmt"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
types "github.com/ukcloud/govcloudair/types/v56"
"log"
)
func resourceVcdEdgeGatewayVpn() *schema.Resource {
return &schema.Resource{
Create: resourceVcdEdgeGatewayVpnCreate,
Read: resourceVcdEdgeGatewayVpnRead,
Delete: resourceVcdEdgeGatewayVpnDelete,
Schema: map[string]*schema.Schema{
"edge_gateway": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"description": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"encryption_protocol": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"local_ip_address": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"local_id": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"mtu": &schema.Schema{
Type: schema.TypeInt,
Required: true,
ForceNew: true,
},
"peer_ip_address": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"peer_id": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"shared_secret": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"local_subnets": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"local_subnet_name": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"local_subnet_gateway": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"local_subnet_mask": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
},
},
},
"peer_subnets": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"peer_subnet_name": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"peer_subnet_gateway": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"peer_subnet_mask": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
},
},
},
},
}
}
func resourceVcdEdgeGatewayVpnCreate(d *schema.ResourceData, meta interface{}) error {
vcdClient := meta.(*VCDClient)
log.Printf("[TRACE] CLIENT: %#v", vcdClient)
vcdClient.Mutex.Lock()
defer vcdClient.Mutex.Unlock()
edgeGateway, err := vcdClient.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string))
localSubnetsList := d.Get("local_subnets").(*schema.Set).List()
peerSubnetsList := d.Get("peer_subnets").(*schema.Set).List()
localSubnets := make([]*types.IpsecVpnSubnet, len(localSubnetsList))
peerSubnets := make([]*types.IpsecVpnSubnet, len(peerSubnetsList))
for i, s := range localSubnetsList {
ls := s.(map[string]interface{})
localSubnets[i] = &types.IpsecVpnSubnet{
Name: ls["local_subnet_name"].(string),
Gateway: ls["local_subnet_gateway"].(string),
Netmask: ls["local_subnet_mask"].(string),
}
}
for i, s := range peerSubnetsList {
ls := s.(map[string]interface{})
peerSubnets[i] = &types.IpsecVpnSubnet{
Name: ls["peer_subnet_name"].(string),
Gateway: ls["peer_subnet_gateway"].(string),
Netmask: ls["peer_subnet_mask"].(string),
}
}
tunnel := &types.GatewayIpsecVpnTunnel{
Name: d.Get("name").(string),
Description: d.Get("description").(string),
IpsecVpnLocalPeer: &types.IpsecVpnLocalPeer{
ID: "",
Name: "",
},
EncryptionProtocol: d.Get("encryption_protocol").(string),
LocalIPAddress: d.Get("local_ip_address").(string),
LocalID: d.Get("local_id").(string),
LocalSubnet: localSubnets,
Mtu: d.Get("mtu").(int),
PeerID: d.Get("peer_id").(string),
PeerIPAddress: d.Get("peer_ip_address").(string),
PeerSubnet: peerSubnets,
SharedSecret: d.Get("shared_secret").(string),
IsEnabled: true,
}
tunnels := make([]*types.GatewayIpsecVpnTunnel, 1)
tunnels[0] = tunnel
ipsecVPNConfig := &types.EdgeGatewayServiceConfiguration{
Xmlns: "http://www.vmware.com/vcloud/v1.5",
GatewayIpsecVpnService: &types.GatewayIpsecVpnService{
IsEnabled: true,
Tunnel: tunnels,
},
}
log.Printf("[INFO] ipsecVPNConfig: %#v", ipsecVPNConfig)
err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
edgeGateway.Refresh()
task, err := edgeGateway.AddIpsecVPN(ipsecVPNConfig)
if err != nil {
log.Printf("[INFO] Error setting ipsecVPNConfig rules: %s", err)
return resource.RetryableError(
fmt.Errorf("Error setting ipsecVPNConfig rules: %#v", err))
}
return resource.RetryableError(task.WaitTaskCompletion())
})
if err != nil {
return fmt.Errorf("Error completing tasks: %#v", err)
}
d.SetId(d.Get("edge_gateway").(string))
return resourceVcdEdgeGatewayVpnRead(d, meta)
}
func resourceVcdEdgeGatewayVpnDelete(d *schema.ResourceData, meta interface{}) error {
vcdClient := meta.(*VCDClient)
log.Printf("[TRACE] CLIENT: %#v", vcdClient)
vcdClient.Mutex.Lock()
defer vcdClient.Mutex.Unlock()
edgeGateway, err := vcdClient.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string))
ipsecVPNConfig := &types.EdgeGatewayServiceConfiguration{
Xmlns: "http://www.vmware.com/vcloud/v1.5",
GatewayIpsecVpnService: &types.GatewayIpsecVpnService{
IsEnabled: false,
},
}
log.Printf("[INFO] ipsecVPNConfig: %#v", ipsecVPNConfig)
err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
edgeGateway.Refresh()
task, err := edgeGateway.AddIpsecVPN(ipsecVPNConfig)
if err != nil {
log.Printf("[INFO] Error setting ipsecVPNConfig rules: %s", err)
return resource.RetryableError(
fmt.Errorf("Error setting ipsecVPNConfig rules: %#v", err))
}
return resource.RetryableError(task.WaitTaskCompletion())
})
if err != nil {
return fmt.Errorf("Error completing tasks: %#v", err)
}
d.SetId(d.Get("edge_gateway").(string))
if err != nil {
return fmt.Errorf("Error finding edge gateway: %#v", err)
}
return nil
}
func resourceVcdEdgeGatewayVpnRead(d *schema.ResourceData, meta interface{}) error {
vcdClient := meta.(*VCDClient)
edgeGateway, err := vcdClient.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string))
if err != nil {
return fmt.Errorf("Error finding edge gateway: %#v", err)
}
egsc := edgeGateway.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration.GatewayIpsecVpnService
if len(egsc.Tunnel) == 0 {
d.SetId("")
return nil
}
if len(egsc.Tunnel) == 1 {
tunnel := egsc.Tunnel[0]
d.Set("name", tunnel.Name)
d.Set("description", tunnel.Description)
d.Set("encryption_protocol", tunnel.EncryptionProtocol)
d.Set("local_ip_address", tunnel.LocalIPAddress)
d.Set("local_id", tunnel.LocalID)
d.Set("mtu", tunnel.Mtu)
d.Set("peer_ip_address", tunnel.PeerIPAddress)
d.Set("peer_id", tunnel.PeerID)
d.Set("shared_secret", tunnel.SharedSecret)
d.Set("local_subnets", tunnel.LocalSubnet)
d.Set("peer_subnets", tunnel.PeerSubnet)
} else {
return fmt.Errorf("Multiple tunnels not currently supported")
}
return nil
}

View File

@ -0,0 +1,80 @@
package vcd
import (
"fmt"
"os"
"testing"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccVcdVpn_Basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVcdVpnDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: fmt.Sprintf(testAccCheckVcdVpn_basic, os.Getenv("VCD_EDGE_GATEWAY")),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"vcd_edgegateway_vpn.vpn", "encryption_protocol", "AES256"),
),
},
},
})
}
func testAccCheckVcdVpnDestroy(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
if rs.Type != "vcd_edgegateway_vpn" {
continue
}
return nil
}
return nil
}
const testAccCheckVcdVpn_basic = `
resource "vcd_edgegateway_vpn" "vpn" {
edge_gateway = "%s"
name = "west-to-east"
description = "Description"
encryption_protocol = "AES256"
mtu = 1400
peer_id = "51.179.218.195"
peer_ip_address = "51.179.218.195"
local_id = "51.179.218.196"
local_ip_address = "51.179.218.196"
shared_secret = "yZ4B8pxS5334m6ho692hjbtb7zo2vbesn7pe8ry5hyud86M433tbnnfxt6Dqn73g"
peer_subnets {
peer_subnet_name = "DMZ_WEST"
peer_subnet_gateway = "10.0.10.1"
peer_subnet_mask = "255.255.255.0"
}
peer_subnets {
peer_subnet_name = "WEB_WEST"
peer_subnet_gateway = "10.0.20.1"
peer_subnet_mask = "255.255.255.0"
}
local_subnets {
local_subnet_name = "DMZ_EAST"
local_subnet_gateway = "10.0.1.1"
local_subnet_mask = "255.255.255.0"
}
local_subnets {
local_subnet_name = "WEB_EAST"
local_subnet_gateway = "10.0.22.1"
local_subnet_mask = "255.255.255.0"
}
}
`

View File

@ -0,0 +1,88 @@
---
layout: "vcd"
page_title: "vCloudDirector: vcd_edgegateway_vpn"
sidebar_current: "docs-vcd-resource-edgegateway-vpn"
description: |-
Provides a vCloud Director IPsec VPN. This can be used to create, modify, and delete VPN settings and rules.
---
# vcd\_edgegateway\_vpn
Provides a vCloud Director IPsec VPN. This can be used to create,
modify, and delete VPN settings and rules.
## Example Usage
```
resource "vcd_edgegateway_vpn" "vpn" {
edge_gateway = "Internet_01(nti0000bi2_123-456-2)"
name = "west-to-east"
description = "Description"
encryption_protocol = "AES256"
mtu = 1400
peer_id = "64.121.123.11"
peer_ip_address = "64.121.123.11"
local_id = "64.121.123.10"
local_ip_address = "64.121.123.10"
shared_secret = "***********************"
peer_subnets {
peer_subnet_name = "DMZ_WEST"
peer_subnet_gateway = "10.0.10.1"
peer_subnet_mask = "255.255.255.0"
}
peer_subnets {
peer_subnet_name = "WEB_WEST"
peer_subnet_gateway = "10.0.20.1"
peer_subnet_mask = "255.255.255.0"
}
local_subnets {
local_subnet_name = "DMZ_EAST"
local_subnet_gateway = "10.0.1.1"
local_subnet_mask = "255.255.255.0"
}
local_subnets {
local_subnet_name = "WEB_EAST"
local_subnet_gateway = "10.0.22.1"
local_subnet_mask = "255.255.255.0"
}
}
```
## Argument Reference
The following arguments are supported:
* `edge_gateway` - (Required) The name of the edge gateway on which to apply the Firewall Rules
* `name` - (Required) The name of the VPN
* `description` - (Required) A description for the VPN
* `encryption_protocol` - (Required) - E.g. `AES256`
* `local_ip_address` - (Required) - Local IP Address
* `local_id` - (Required) - Local ID
* `mtu` - (Required) - The MTU setting
* `peer_ip_address` - (Required) - Peer IP Address
* `peer_id` - (Required) - Peer ID
* `shared_secret` - (Required) - Shared Secret
* `local_subnets` - (Required) - List of Local Subnets see [Local Subnets](#localsubnets) below for details.
* `peer_subnets` - (Required) - List of Peer Subnets see [Peer Subnets](#peersubnets) below for details.
<a id="localsubnets"></a>
## Local Subnets
Each Local Subnet supports the following attributes:
* `local_subnet_name` - (Required) Name of the local subnet
* `local_subnet_gateway` - (Required) Gateway of the local subnet
* `local_subnet_mask` - (Required) Subnet mask of the local subnet
<a id="peersubnets"></a>
## Peer Subnets
Each Peer Subnet supports the following attributes:
* `peer_subnet_name` - (Required) Name of the peer subnet
* `peer_subnet_gateway` - (Required) Gateway of the peer subnet
* `peer_subnet_mask` - (Required) Subnet mask of the peer subnet