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 VPN service #760

Merged
merged 23 commits into from
Feb 18, 2018
Merged
Show file tree
Hide file tree
Changes from 10 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
41 changes: 41 additions & 0 deletions openstack/networking/v2/extensions/vpnaas/services/requests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package services

import "github.com/gophercloud/gophercloud"

// CreateOptsBuilder allows extensions to add additional parameters to the
// Create request.
type CreateOptsBuilder interface {
ToVPNServiceCreateMap() (map[string]interface{}, error)
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be ToServiceCreateMap.

}

// CreateOpts contains all the values needed to create a new VPN service
type CreateOpts struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

doc nit: all fields should have a descriptive comment even if it's something simple like:

Name is the human-readable name of the VPN Service.

// TenantID specifies a tenant to own the VPN service. The caller must have
// an admin role in order to set this. Otherwise, this field is left unset
// and the caller will be the owner.
TenantID string `json:"tenant_id,omitempty"`
SubnetID string `json:"subnet_id,omitempty"`
RouterID string `json:"router_id" required:"true"`
Description string `json:"description,omitempty"`
AdminStateUp *bool `json:"admin_state_up"`
ProjectID string `json:"project_id"`
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see project_id defined anywhere here, so maybe it's an internal neutron field? What happens if TenantID and ProjectID are different UUIDs?

Name string `json:"name,omitempty"`
FlavorID string `json:"flavor_id,omitempty"`
}

// ToVPNServiceCreateMap casts a CreateOpts struct to a map.
func (opts CreateOpts) ToVPNServiceCreateMap() (map[string]interface{}, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

ToServiceCreateMap

return gophercloud.BuildRequestBody(opts, "vpnservice")
}

// Create accepts a CreateOpts struct and uses the values to create a new
// VPN service
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
b, err := opts.ToVPNServiceCreateMap()
if err != nil {
r.Err = err
return
}
_, r.Err = c.Post(rootURL(c), b, &r.Body, nil)
return
}
40 changes: 40 additions & 0 deletions openstack/networking/v2/extensions/vpnaas/services/results.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package services

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

// Service is a VPN Service
type Service struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

doc nit: these fields should have comments to describe what they are.

TenantID string `json:"tenant_id"`
SubnetID string `json:"subnet_id,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

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

omitempty isn't valid for results. it can safely be removed.

RouterID string `json:"router_id"`
Description string `json:"description,omitempty"`
AdminStateUp *bool `json:"admin_state_up"`
ProjectID string `json:"project_id"`
Name string `json:"name,omitempty"`
Status string `json:"status"`
ID string `json:"id"`
ExternalV6IP string `json:"external_v6_ip"`
ExternalV4IP string `json:"external_v4_ip"`
FlavorID string `json:"flavor_id"`
}

type commonResult struct {
gophercloud.Result
}

// Extract is a function that accepts a result and extracts a VPN service.
func (r commonResult) Extract() (*Service, error) {
var s struct {
Service *Service `json:"vpnservice"`
}
err := r.ExtractInto(&s)
return s.Service, err
}

// CreateResult represents the result of a create operation. Call its Extract
// method to interpret it as a Service.
type CreateResult struct {
commonResult
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package testing

import (
"fmt"
"net/http"
"testing"

"github.com/gophercloud/gophercloud"
fake "github.com/gophercloud/gophercloud/openstack/networking/v2/common"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/vpnaas/services"
th "github.com/gophercloud/gophercloud/testhelper"
)

func TestCreate(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()

th.Mux.HandleFunc("/v2.0/vpn/vpnservices", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "POST")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
th.TestHeader(t, r, "Content-Type", "application/json")
th.TestHeader(t, r, "Accept", "application/json")
th.TestJSONRequest(t, r, `
{
"vpnservice": {
"router_id": "66e3b16c-8ce5-40fb-bb49-ab6d8dc3f2aa",
"name": "vpn",
"admin_state_up": true,
"description": "OpenStack VPN service",
"tenant_id": "10039663455a446d8ba2cbb058b0f578",
"project_id": "10039663455a446d8ba2cbb058b0f578"
}
} `)

w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)

fmt.Fprintf(w, `
{
"vpnservice": {
"router_id": "66e3b16c-8ce5-40fb-bb49-ab6d8dc3f2aa",
"status": "PENDING_CREATE",
"name": "vpn",
"external_v6_ip": "2001:db8::1",
"admin_state_up": true,
"subnet_id": null,
"project_id": "10039663455a446d8ba2cbb058b0f578",
"tenant_id": "10039663455a446d8ba2cbb058b0f578",
"external_v4_ip": "172.32.1.11",
"id": "5c561d9d-eaea-45f6-ae3e-08d1a7080828",
"description": "OpenStack VPN service"
}
}
`)
})

options := services.CreateOpts{
TenantID: "10039663455a446d8ba2cbb058b0f578",
Name: "vpn",
Description: "OpenStack VPN service",
AdminStateUp: gophercloud.Enabled,
RouterID: "66e3b16c-8ce5-40fb-bb49-ab6d8dc3f2aa",
ProjectID: "10039663455a446d8ba2cbb058b0f578",
}
_, err := services.Create(fake.ServiceClient(), options).Extract()
th.AssertNoErr(t, err)
}
16 changes: 16 additions & 0 deletions openstack/networking/v2/extensions/vpnaas/services/urls.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package services

import "github.com/gophercloud/gophercloud"

const (
rootPath = "vpn"
resourcePath = "vpnservices"
)

func rootURL(c *gophercloud.ServiceClient) string {
return c.ServiceURL(rootPath, resourcePath)
}

func resourceURL(c *gophercloud.ServiceClient, id string) string {
return c.ServiceURL(rootPath, resourcePath, id)
}