Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vpnaas: Create IPSec site connection #810

Merged
merged 9 commits into from
Mar 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// +build acceptance networking vpnaas

package vpnaas

import (
"testing"

"github.com/gophercloud/gophercloud/acceptance/clients"
networks "github.com/gophercloud/gophercloud/acceptance/openstack/networking/v2"
layer3 "github.com/gophercloud/gophercloud/acceptance/openstack/networking/v2/extensions/layer3"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers"

"github.com/gophercloud/gophercloud/acceptance/tools"
)

func TestConnectionCRUD(t *testing.T) {
client, err := clients.NewNetworkV2Client()
if err != nil {
t.Fatalf("Unable to create a network client: %v", err)
}

// Create Network
network, err := networks.CreateNetwork(t, client)
if err != nil {
t.Fatalf("Unable to create network: %v", err)
}

// Create Subnet
subnet, err := networks.CreateSubnet(t, client, network.ID)
if err != nil {
t.Fatalf("Unable to create subnet: %v", err)
}

router, err := layer3.CreateExternalRouter(t, client)
if err != nil {
t.Fatalf("Unable to create router: %v", err)
}

// Link router and subnet
aiOpts := routers.AddInterfaceOpts{
SubnetID: subnet.ID,
}

_, err = routers.AddInterface(client, router.ID, aiOpts).Extract()
if err != nil {
t.Fatalf("Failed to add interface to router: %v", err)
}

// Create all needed resources for the connection
service, err := CreateService(t, client, router.ID)
if err != nil {
t.Fatalf("Unable to create service: %v", err)
}

ikepolicy, err := CreateIKEPolicy(t, client)
if err != nil {
t.Fatalf("Unable to create IKE policy: %v", err)
}

ipsecpolicy, err := CreateIPSecPolicy(t, client)
if err != nil {
t.Fatalf("Unable to create IPSec Policy: %v", err)
}

peerEPGroup, err := CreateEndpointGroup(t, client)
if err != nil {
t.Fatalf("Unable to create Endpoint Group with CIDR endpoints: %v", err)
}

localEPGroup, err := CreateEndpointGroupWithSubnet(t, client, subnet.ID)
if err != nil {
t.Fatalf("Unable to create Endpoint Group with subnet endpoints: %v", err)
}

conn, err := CreateSiteConnection(t, client, ikepolicy.ID, ipsecpolicy.ID, service.ID, peerEPGroup.ID, localEPGroup.ID)
if err != nil {
t.Fatalf("Unable to create IPSec Site Connection: %v", err)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The resources here don't get deleted because they can't get deleted without deletion of the IPSec site connection. I will change this in a future PR as soon as it's possible to delete Site connections and endpoint groups

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep - that's the way to go here :)


tools.PrintResource(t, conn)

}
60 changes: 59 additions & 1 deletion acceptance/openstack/networking/v2/extensions/vpnaas/vpnaas.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/vpnaas/ikepolicies"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/vpnaas/ipsecpolicies"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/vpnaas/services"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/vpnaas/siteconnections"
)

// CreateService will create a Service with a random name and a specified router ID
Expand Down Expand Up @@ -53,7 +54,7 @@ func DeleteService(t *testing.T, client *gophercloud.ServiceClient, serviceID st
func CreateIPSecPolicy(t *testing.T, client *gophercloud.ServiceClient) (*ipsecpolicies.Policy, error) {
policyName := tools.RandomString("TESTACC-", 8)

t.Logf("Attempting to create policy %s", policyName)
t.Logf("Attempting to create IPSec policy %s", policyName)

createOpts := ipsecpolicies.CreateOpts{
Name: policyName,
Expand Down Expand Up @@ -157,4 +158,61 @@ func DeleteEndpointGroup(t *testing.T, client *gophercloud.ServiceClient, epGrou
}

t.Logf("Deleted endpoint group: %s", epGroupID)

}

// CreateEndpointGroupWithSubnet will create an endpoint group with a random name.
// An error will be returned if the group could not be created.
func CreateEndpointGroupWithSubnet(t *testing.T, client *gophercloud.ServiceClient, subnetID string) (*endpointgroups.EndpointGroup, error) {
groupName := tools.RandomString("TESTACC-", 8)

t.Logf("Attempting to create group %s", groupName)

createOpts := endpointgroups.CreateOpts{
Name: groupName,
Type: endpointgroups.TypeSubnet,
Endpoints: []string{
subnetID,
},
}
group, err := endpointgroups.Create(client, createOpts).Extract()
if err != nil {
return group, err
}

t.Logf("Successfully created group %s", groupName)

return group, nil
}

// CreateSiteConnection will create an IPSec site connection with a random name and specified
// IKE policy, IPSec policy, service, peer EP group and local EP Group.
// An error will be returned if the connection could not be created.
func CreateSiteConnection(t *testing.T, client *gophercloud.ServiceClient, ikepolicyID string, ipsecpolicyID string, serviceID string, peerEPGroupID string, localEPGroupID string) (*siteconnections.Connection, error) {
connectionName := tools.RandomString("TESTACC-", 8)

t.Logf("Attempting to create IPSec site connection %s", connectionName)

createOpts := siteconnections.CreateOpts{
Name: connectionName,
PSK: "secret",
Initiator: siteconnections.InitiatorBiDirectional,
AdminStateUp: gophercloud.Enabled,
IPSecPolicyID: ipsecpolicyID,
PeerEPGroupID: peerEPGroupID,
IKEPolicyID: ikepolicyID,
VPNServiceID: serviceID,
LocalEPGroupID: localEPGroupID,
PeerAddress: "172.24.4.233",
PeerID: "172.24.4.233",
MTU: 1500,
}
connection, err := siteconnections.Create(client, createOpts).Extract()
if err != nil {
return connection, err
}

t.Logf("Successfully created IPSec Site Connection %s", connectionName)

return connection, nil
}
27 changes: 27 additions & 0 deletions openstack/networking/v2/extensions/vpnaas/siteconnections/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
Package siteconnections allows management and retrieval of IPSec site connections in the
OpenStack Networking Service.


Example to create an IPSec site connection

createOpts := siteconnections.CreateOpts{
Name: "Connection1",
PSK: "secret",
Initiator: siteconnections.InitiatorBiDirectional,
AdminStateUp: gophercloud.Enabled,
IPSecPolicyID: "4ab0a72e-64ef-4809-be43-c3f7e0e5239b",
PeerEPGroupID: "5f5801b1-b383-4cf0-bf61-9e85d4044b2d",
IKEPolicyID: "47a880f9-1da9-468c-b289-219c9eca78f0",
VPNServiceID: "692c1ec8-a7cd-44d9-972b-8ed3fe4cc476",
LocalEPGroupID: "498bb96a-1517-47ea-b1eb-c4a53db46a16",
PeerAddress: "172.24.4.233",
PeerID: "172.24.4.233",
MTU: 1500,
}
connection, err := siteconnections.Create(client, createOpts).Extract()
if err != nil {
panic(err)
}
*/
package siteconnections
129 changes: 129 additions & 0 deletions openstack/networking/v2/extensions/vpnaas/siteconnections/requests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package siteconnections

import (
"github.com/gophercloud/gophercloud"
)

// CreateOptsBuilder allows extensions to add additional parameters to the
// Create request.
type CreateOptsBuilder interface {
ToConnectionCreateMap() (map[string]interface{}, error)
}
type Action string
type Initiator string

const (
ActionHold Action = "hold"
ActionClear Action = "clear"
ActionRestart Action = "restart"
ActionDisabled Action = "disabled"
ActionRestartByPeer Action = "restart-by-peer"
InitiatorBiDirectional Initiator = "bi-directional"
InitiatorResponseOnly Initiator = "response-only"
)

// DPDCreateOpts contains all the values needed to create a valid configuration for Dead Peer detection protocols
type DPDCreateOpts struct {
// The dead peer detection (DPD) action.
// A valid value is clear, hold, restart, disabled, or restart-by-peer.
// Default value is hold.
Action Action `json:"action,omitempty"`

// The dead peer detection (DPD) timeout in seconds.
// A valid value is a positive integer that is greater than the DPD interval value.
// Default is 120.
Timeout int `json:"timeout,omitempty"`

// The dead peer detection (DPD) interval, in seconds.
// A valid value is a positive integer.
// Default is 30.
Interval int `json:"interval,omitempty"`
}

// CreateOpts contains all the values needed to create a new IPSec site connection
type CreateOpts struct {
// The ID of the IKE policy
IKEPolicyID string `json:"ikepolicy_id"`

// The ID of the VPN Service
VPNServiceID string `json:"vpnservice_id"`

// The ID for the endpoint group that contains private subnets for the local side of the connection.
// You must specify this parameter with the peer_ep_group_id parameter unless
// in backward- compatible mode where peer_cidrs is provided with a subnet_id for the VPN service.
LocalEPGroupID string `json:"local_ep_group_id,omitempty"`

// The ID of the IPsec policy.
IPSecPolicyID string `json:"ipsecpolicy_id"`

// The peer router identity for authentication.
// A valid value is an IPv4 address, IPv6 address, e-mail address, key ID, or FQDN.
// Typically, this value matches the peer_address value.
PeerID string `json:"peer_id"`

// The ID of the project
TenantID string `json:"tenant_id,omitempty"`

// The ID for the endpoint group that contains private CIDRs in the form < net_address > / < prefix >
// for the peer side of the connection.
// You must specify this parameter with the local_ep_group_id parameter unless in backward-compatible mode
// where peer_cidrs is provided with a subnet_id for the VPN service.
PeerEPGroupID string `json:"peer_ep_group_id,omitempty"`

// An ID to be used instead of the external IP address for a virtual router used in traffic between instances on different networks in east-west traffic.
// Most often, local ID would be domain name, email address, etc.
// If this is not configured then the external IP address will be used as the ID.
LocalID string `json:"local_id,omitempty"`

// The human readable name of the connection.
// Does not have to be unique.
// Default is an empty string
Name string `json:"name,omitempty"`

// The human readable description of the connection.
// Does not have to be unique.
// Default is an empty string
Description string `json:"description,omitempty"`

// The peer gateway public IPv4 or IPv6 address or FQDN.
PeerAddress string `json:"peer_address"`

// The pre-shared key.
// A valid value is any string.
PSK string `json:"psk"`

// Indicates whether this VPN can only respond to connections or both respond to and initiate connections.
// A valid value is response-only or bi-directional. Default is bi-directional.
Initiator Initiator `json:"initiator,omitempty"`

// Unique list of valid peer private CIDRs in the form < net_address > / < prefix > .
PeerCIDRs []string `json:"peer_cidrs,omitempty"`

// The administrative state of the resource, which is up (true) or down (false).
// Default is false
AdminStateUp *bool `json:"admin_state_up,omitempty"`

// A dictionary with dead peer detection (DPD) protocol controls.
DPD *DPDCreateOpts `json:"dpd,omitempty"`

// The maximum transmission unit (MTU) value to address fragmentation.
// Minimum value is 68 for IPv4, and 1280 for IPv6.
MTU int `json:"mtu,omitempty"`
}

// ToServiceCreateMap casts a CreateOpts struct to a map.
func (opts CreateOpts) ToConnectionCreateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "ipsec_site_connection")
}

// Create accepts a CreateOpts struct and uses the values to create a new
// IPSec site connection.
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
b, err := opts.ToConnectionCreateMap()
if err != nil {
r.Err = err
return
}
_, r.Err = c.Post(rootURL(c), b, &r.Body, nil)
return
}
Loading