Merge pull request #234 from jamiehannaford/object-store-accounts
Making account files more consistent
diff --git a/acceptance/openstack/networking/v2/extensions/layer3_test.go b/acceptance/openstack/networking/v2/extensions/layer3_test.go
index 1289113..63e0be3 100644
--- a/acceptance/openstack/networking/v2/extensions/layer3_test.go
+++ b/acceptance/openstack/networking/v2/extensions/layer3_test.go
@@ -219,7 +219,7 @@
}
func updateRouter(t *testing.T, routerID string) {
- r, err := routers.Update(base.Client, routerID, routers.UpdateOpts{
+ _, err := routers.Update(base.Client, routerID, routers.UpdateOpts{
Name: "another_name",
}).Extract()
diff --git a/acceptance/openstack/networking/v2/extensions/provider_test.go b/acceptance/openstack/networking/v2/extensions/provider_test.go
index dc21ae5..f10c9d9 100644
--- a/acceptance/openstack/networking/v2/extensions/provider_test.go
+++ b/acceptance/openstack/networking/v2/extensions/provider_test.go
@@ -6,24 +6,25 @@
"strconv"
"testing"
+ base "github.com/rackspace/gophercloud/acceptance/openstack/networking/v2"
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
"github.com/rackspace/gophercloud/pagination"
th "github.com/rackspace/gophercloud/testhelper"
)
func TestNetworkCRUDOperations(t *testing.T) {
- Setup(t)
- defer Teardown()
+ base.Setup(t)
+ defer base.Teardown()
// Create a network
- n, err := networks.Create(Client, networks.CreateOpts{Name: "sample_network", AdminStateUp: true}).Extract()
+ n, err := networks.Create(base.Client, networks.CreateOpts{Name: "sample_network", AdminStateUp: networks.Up}).Extract()
th.AssertNoErr(t, err)
th.AssertEquals(t, n.Name, "sample_network")
th.AssertEquals(t, n.AdminStateUp, true)
networkID := n.ID
// List networks
- pager := networks.List(Client, networks.ListOpts{Limit: 2})
+ pager := networks.List(base.Client, networks.ListOpts{Limit: 2})
err = pager.EachPage(func(page pagination.Page) (bool, error) {
t.Logf("--- Page ---")
@@ -43,7 +44,7 @@
if networkID == "" {
t.Fatalf("In order to retrieve a network, the NetworkID must be set")
}
- n, err = networks.Get(Client, networkID).Extract()
+ n, err = networks.Get(base.Client, networkID).Extract()
th.AssertNoErr(t, err)
th.AssertEquals(t, n.Status, "ACTIVE")
th.AssertDeepEquals(t, n.Subnets, []string{})
@@ -53,12 +54,12 @@
th.AssertEquals(t, n.ID, networkID)
// Update network
- n, err = networks.Update(Client, networkID, networks.UpdateOpts{Name: "new_network_name"}).Extract()
+ n, err = networks.Update(base.Client, networkID, networks.UpdateOpts{Name: "new_network_name"}).Extract()
th.AssertNoErr(t, err)
th.AssertEquals(t, n.Name, "new_network_name")
// Delete network
- res := networks.Delete(Client, networkID)
+ res := networks.Delete(base.Client, networkID)
th.AssertNoErr(t, res.Err)
}
diff --git a/acceptance/openstack/networking/v2/extensions/security_test.go b/acceptance/openstack/networking/v2/extensions/security_test.go
index 522219a..16ecca4 100644
--- a/acceptance/openstack/networking/v2/extensions/security_test.go
+++ b/acceptance/openstack/networking/v2/extensions/security_test.go
@@ -120,18 +120,6 @@
t.Logf("Deleted security group %s", groupID)
}
-func deletePort(t *testing.T, portID string) {
- res := ports.Delete(base.Client, portID)
- th.AssertNoErr(t, res.Err)
- t.Logf("Deleted port %s", portID)
-}
-
-func deleteNetwork(t *testing.T, networkID string) {
- res := networks.Delete(base.Client, networkID)
- th.AssertNoErr(t, res.Err)
- t.Logf("Deleted network %s", networkID)
-}
-
func createSecRule(t *testing.T, groupID string) string {
r, err := rules.Create(base.Client, rules.CreateOpts{
Direction: "ingress",
diff --git a/acceptance/openstack/networking/v2/network_test.go b/acceptance/openstack/networking/v2/network_test.go
index f00edba..be8a3a1 100644
--- a/acceptance/openstack/networking/v2/network_test.go
+++ b/acceptance/openstack/networking/v2/network_test.go
@@ -16,7 +16,7 @@
defer Teardown()
// Create a network
- n, err := networks.Create(Client, networks.CreateOpts{Name: "sample_network", AdminStateUp: true}).Extract()
+ n, err := networks.Create(Client, networks.CreateOpts{Name: "sample_network", AdminStateUp: networks.Up}).Extract()
th.AssertNoErr(t, err)
defer networks.Delete(Client, n.ID)
th.AssertEquals(t, n.Name, "sample_network")
diff --git a/acceptance/openstack/networking/v2/port_test.go b/acceptance/openstack/networking/v2/port_test.go
index 363a7fe..7f22dbd 100644
--- a/acceptance/openstack/networking/v2/port_test.go
+++ b/acceptance/openstack/networking/v2/port_test.go
@@ -97,18 +97,17 @@
}
func createNetwork() (string, error) {
- res, err := networks.Create(Client, networks.CreateOpts{Name: "tmp_network", AdminStateUp: true}).Extract()
+ res, err := networks.Create(Client, networks.CreateOpts{Name: "tmp_network", AdminStateUp: networks.Up}).Extract()
return res.ID, err
}
func createSubnet(networkID string) (string, error) {
- enable := false
s, err := subnets.Create(Client, subnets.CreateOpts{
NetworkID: networkID,
CIDR: "192.168.199.0/24",
IPVersion: subnets.IPv4,
Name: "my_subnet",
- EnableDHCP: &enable,
+ EnableDHCP: subnets.Down,
}).Extract()
return s.ID, err
}
diff --git a/acceptance/openstack/networking/v2/subnet_test.go b/acceptance/openstack/networking/v2/subnet_test.go
index 2758e2a..097a303 100644
--- a/acceptance/openstack/networking/v2/subnet_test.go
+++ b/acceptance/openstack/networking/v2/subnet_test.go
@@ -38,7 +38,7 @@
// Setup network
t.Log("Setting up network")
- n, err := networks.Create(Client, networks.CreateOpts{Name: "tmp_network", AdminStateUp: true}).Extract()
+ n, err := networks.Create(Client, networks.CreateOpts{Name: "tmp_network", AdminStateUp: networks.Up}).Extract()
th.AssertNoErr(t, err)
networkID := n.ID
defer networks.Delete(Client, networkID)
diff --git a/openstack/blockstorage/v1/apiversions/results.go b/openstack/blockstorage/v1/apiversions/results.go
index c4ac157..ea2f7f5 100644
--- a/openstack/blockstorage/v1/apiversions/results.go
+++ b/openstack/blockstorage/v1/apiversions/results.go
@@ -37,11 +37,8 @@
}
err := mapstructure.Decode(page.(APIVersionPage).Body, &resp)
- if err != nil {
- return nil, err
- }
- return resp.Versions, nil
+ return resp.Versions, err
}
// GetResult represents the result of a get operation.
@@ -56,9 +53,6 @@
}
err := mapstructure.Decode(r.Resp, &resp)
- if err != nil {
- return nil, err
- }
- return resp.Version, nil
+ return resp.Version, err
}
diff --git a/openstack/blockstorage/v1/snapshots/results.go b/openstack/blockstorage/v1/snapshots/results.go
index 9509bca..d23090d 100644
--- a/openstack/blockstorage/v1/snapshots/results.go
+++ b/openstack/blockstorage/v1/snapshots/results.go
@@ -1,8 +1,6 @@
package snapshots
import (
- "fmt"
-
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
@@ -91,8 +89,6 @@
}
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("snapshots: Error decoding snapshots.commonResult: %v", err)
- }
- return res.Snapshot, nil
+
+ return res.Snapshot, err
}
diff --git a/openstack/blockstorage/v1/volumes/results.go b/openstack/blockstorage/v1/volumes/results.go
index 78c863f..78eb6c1 100644
--- a/openstack/blockstorage/v1/volumes/results.go
+++ b/openstack/blockstorage/v1/volumes/results.go
@@ -1,8 +1,6 @@
package volumes
import (
- "fmt"
-
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
@@ -80,8 +78,6 @@
}
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("volumes: Error decoding volumes.commonResult: %v", err)
- }
- return res.Volume, nil
+
+ return res.Volume, err
}
diff --git a/openstack/blockstorage/v1/volumetypes/results.go b/openstack/blockstorage/v1/volumetypes/results.go
index 8e5932a..77cc1f5 100644
--- a/openstack/blockstorage/v1/volumetypes/results.go
+++ b/openstack/blockstorage/v1/volumetypes/results.go
@@ -1,8 +1,6 @@
package volumetypes
import (
- "fmt"
-
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
@@ -64,9 +62,6 @@
}
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Volume Type: %v", err)
- }
- return res.VolumeType, nil
+ return res.VolumeType, err
}
diff --git a/openstack/common/extensions/results.go b/openstack/common/extensions/results.go
index 9319018..e98e5d6 100755
--- a/openstack/common/extensions/results.go
+++ b/openstack/common/extensions/results.go
@@ -1,8 +1,6 @@
package extensions
import (
- "fmt"
-
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
@@ -25,11 +23,8 @@
}
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding OpenStack extension: %v", err)
- }
- return res.Extension, nil
+ return res.Extension, err
}
// Extension is a struct that represents an OpenStack extension.
@@ -65,9 +60,6 @@
}
err := mapstructure.Decode(page.(ExtensionPage).Body, &resp)
- if err != nil {
- return nil, err
- }
- return resp.Extensions, nil
+ return resp.Extensions, err
}
diff --git a/openstack/compute/v2/flavors/results.go b/openstack/compute/v2/flavors/results.go
index 68c8f58..1e274e3 100644
--- a/openstack/compute/v2/flavors/results.go
+++ b/openstack/compute/v2/flavors/results.go
@@ -78,12 +78,8 @@
// NextPageURL uses the response's embedded link reference to navigate to the next page of results.
func (p FlavorPage) NextPageURL() (string, error) {
- type link struct {
- Href string `mapstructure:"href"`
- Rel string `mapstructure:"rel"`
- }
type resp struct {
- Links []link `mapstructure:"flavors_links"`
+ Links []gophercloud.Link `mapstructure:"flavors_links"`
}
var r resp
@@ -92,17 +88,7 @@
return "", err
}
- var url string
- for _, l := range r.Links {
- if l.Rel == "next" {
- url = l.Href
- }
- }
- if url == "" {
- return "", nil
- }
-
- return url, nil
+ return gophercloud.ExtractNextURL(r.Links)
}
func defaulter(from, to reflect.Kind, v interface{}) (interface{}, error) {
diff --git a/openstack/compute/v2/images/results.go b/openstack/compute/v2/images/results.go
index f93c90c..3c22eeb 100644
--- a/openstack/compute/v2/images/results.go
+++ b/openstack/compute/v2/images/results.go
@@ -65,12 +65,8 @@
// NextPageURL uses the response's embedded link reference to navigate to the next page of results.
func (page ImagePage) NextPageURL() (string, error) {
- type link struct {
- Href string `mapstructure:"href"`
- Rel string `mapstructure:"rel"`
- }
type resp struct {
- Links []link `mapstructure:"images_links"`
+ Links []gophercloud.Link `mapstructure:"images_links"`
}
var r resp
@@ -79,17 +75,7 @@
return "", err
}
- var url string
- for _, l := range r.Links {
- if l.Rel == "next" {
- url = l.Href
- }
- }
- if url == "" {
- return "", nil
- }
-
- return url, nil
+ return gophercloud.ExtractNextURL(r.Links)
}
// ExtractImages converts a page of List results into a slice of usable Image structs.
diff --git a/openstack/compute/v2/servers/results.go b/openstack/compute/v2/servers/results.go
index dd2e651..d284ed8 100644
--- a/openstack/compute/v2/servers/results.go
+++ b/openstack/compute/v2/servers/results.go
@@ -116,12 +116,8 @@
// NextPageURL uses the response's embedded link reference to navigate to the next page of results.
func (page ServerPage) NextPageURL() (string, error) {
- type link struct {
- Href string `mapstructure:"href"`
- Rel string `mapstructure:"rel"`
- }
type resp struct {
- Links []link `mapstructure:"servers_links"`
+ Links []gophercloud.Link `mapstructure:"servers_links"`
}
var r resp
@@ -130,17 +126,7 @@
return "", err
}
- var url string
- for _, l := range r.Links {
- if l.Rel == "next" {
- url = l.Href
- }
- }
- if url == "" {
- return "", nil
- }
-
- return url, nil
+ return gophercloud.ExtractNextURL(r.Links)
}
// ExtractServers interprets the results of a single page from a List() call, producing a slice of Server entities.
diff --git a/openstack/identity/v2/tenants/results.go b/openstack/identity/v2/tenants/results.go
index e4e3f47..c1220c3 100644
--- a/openstack/identity/v2/tenants/results.go
+++ b/openstack/identity/v2/tenants/results.go
@@ -2,6 +2,7 @@
import (
"github.com/mitchellh/mapstructure"
+ "github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
)
@@ -36,12 +37,8 @@
// NextPageURL extracts the "next" link from the tenants_links section of the result.
func (page TenantPage) NextPageURL() (string, error) {
- type link struct {
- Href string `mapstructure:"href"`
- Rel string `mapstructure:"rel"`
- }
type resp struct {
- Links []link `mapstructure:"tenants_links"`
+ Links []gophercloud.Link `mapstructure:"tenants_links"`
}
var r resp
@@ -50,17 +47,7 @@
return "", err
}
- var url string
- for _, l := range r.Links {
- if l.Rel == "next" {
- url = l.Href
- }
- }
- if url == "" {
- return "", nil
- }
-
- return url, nil
+ return gophercloud.ExtractNextURL(r.Links)
}
// ExtractTenants returns a slice of Tenants contained in a single page of results.
diff --git a/openstack/identity/v3/endpoints/results.go b/openstack/identity/v3/endpoints/results.go
index 2dd2357..d1c2472 100644
--- a/openstack/identity/v3/endpoints/results.go
+++ b/openstack/identity/v3/endpoints/results.go
@@ -1,8 +1,6 @@
package endpoints
import (
- "fmt"
-
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
@@ -24,11 +22,8 @@
}
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Endpoint: %v", err)
- }
- return &res.Endpoint, nil
+ return &res.Endpoint, err
}
// CreateResult is the deferred result of a Create call.
@@ -77,8 +72,6 @@
}
err := mapstructure.Decode(page.(EndpointPage).Body, &response)
- if err != nil {
- return nil, err
- }
- return response.Endpoints, nil
+
+ return response.Endpoints, err
}
diff --git a/openstack/identity/v3/services/results.go b/openstack/identity/v3/services/results.go
index b4e7bd2..e4e068b 100644
--- a/openstack/identity/v3/services/results.go
+++ b/openstack/identity/v3/services/results.go
@@ -1,8 +1,6 @@
package services
import (
- "fmt"
-
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
@@ -25,11 +23,8 @@
}
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Service: %v", err)
- }
- return &res.Service, nil
+ return &res.Service, err
}
// CreateResult is the deferred result of a Create call.
diff --git a/openstack/identity/v3/tokens/results.go b/openstack/identity/v3/tokens/results.go
index e96da51..1be98cb 100644
--- a/openstack/identity/v3/tokens/results.go
+++ b/openstack/identity/v3/tokens/results.go
@@ -40,11 +40,8 @@
// Attempt to parse the timestamp.
token.ExpiresAt, err = time.Parse(gophercloud.RFC3339Milli, response.Token.ExpiresAt)
- if err != nil {
- return nil, err
- }
- return &token, nil
+ return &token, err
}
// CreateResult is the deferred response from a Create call.
diff --git a/openstack/networking/v2/apiversions/requests_test.go b/openstack/networking/v2/apiversions/requests_test.go
index c49b509..d35af9f 100644
--- a/openstack/networking/v2/apiversions/requests_test.go
+++ b/openstack/networking/v2/apiversions/requests_test.go
@@ -65,6 +65,22 @@
}
}
+func TestNonJSONCannotBeExtractedIntoAPIVersions(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ })
+
+ ListVersions(fake.ServiceClient()).EachPage(func(page pagination.Page) (bool, error) {
+ if _, err := ExtractAPIVersions(page); err == nil {
+ t.Fatalf("Expected error, got nil")
+ }
+ return true, nil
+ })
+}
+
func TestAPIInfo(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
@@ -148,3 +164,19 @@
t.Errorf("Expected 1 page, got %d", count)
}
}
+
+func TestNonJSONCannotBeExtractedIntoAPIVersionResources(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ })
+
+ ListVersionResources(fake.ServiceClient(), "v2.0").EachPage(func(page pagination.Page) (bool, error) {
+ if _, err := ExtractVersionResources(page); err == nil {
+ t.Fatalf("Expected error, got nil")
+ }
+ return true, nil
+ })
+}
diff --git a/openstack/networking/v2/apiversions/results.go b/openstack/networking/v2/apiversions/results.go
index e13998d..9715934 100644
--- a/openstack/networking/v2/apiversions/results.go
+++ b/openstack/networking/v2/apiversions/results.go
@@ -35,11 +35,8 @@
}
err := mapstructure.Decode(page.(APIVersionPage).Body, &resp)
- if err != nil {
- return nil, err
- }
- return resp.Versions, nil
+ return resp.Versions, err
}
// APIVersionResource represents a generic API resource. It contains the name
@@ -75,9 +72,6 @@
}
err := mapstructure.Decode(page.(APIVersionResourcePage).Body, &resp)
- if err != nil {
- return nil, err
- }
- return resp.APIVersionResources, nil
+ return resp.APIVersionResources, err
}
diff --git a/openstack/networking/v2/apiversions/urls.go b/openstack/networking/v2/apiversions/urls.go
index c43f991..58aa2b6 100644
--- a/openstack/networking/v2/apiversions/urls.go
+++ b/openstack/networking/v2/apiversions/urls.go
@@ -7,9 +7,9 @@
)
func apiVersionsURL(c *gophercloud.ServiceClient) string {
- return c.ServiceURL("")
+ return c.Endpoint
}
func apiInfoURL(c *gophercloud.ServiceClient, version string) string {
- return c.ServiceURL(strings.TrimRight(version, "/") + "/")
+ return c.Endpoint + strings.TrimRight(version, "/") + "/"
}
diff --git a/openstack/networking/v2/common/common_tests.go b/openstack/networking/v2/common/common_tests.go
new file mode 100644
index 0000000..4160351
--- /dev/null
+++ b/openstack/networking/v2/common/common_tests.go
@@ -0,0 +1,14 @@
+package common
+
+import (
+ "github.com/rackspace/gophercloud"
+ "github.com/rackspace/gophercloud/testhelper/client"
+)
+
+const TokenID = client.TokenID
+
+func ServiceClient() *gophercloud.ServiceClient {
+ sc := client.ServiceClient()
+ sc.ResourceBase = sc.Endpoint + "v2.0/"
+ return sc
+}
diff --git a/openstack/networking/v2/extensions/delegate_test.go b/openstack/networking/v2/extensions/delegate_test.go
index 8de8906..3d2ac78 100755
--- a/openstack/networking/v2/extensions/delegate_test.go
+++ b/openstack/networking/v2/extensions/delegate_test.go
@@ -6,16 +6,16 @@
"testing"
common "github.com/rackspace/gophercloud/openstack/common/extensions"
+ fake "github.com/rackspace/gophercloud/openstack/networking/v2/common"
"github.com/rackspace/gophercloud/pagination"
th "github.com/rackspace/gophercloud/testhelper"
- fake "github.com/rackspace/gophercloud/testhelper/client"
)
func TestList(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/extensions", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/extensions", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
@@ -73,7 +73,7 @@
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/extensions/agent", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/extensions/agent", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
@@ -92,14 +92,14 @@
}
}
`)
-
- ext, err := Get(fake.ServiceClient(), "agent").Extract()
- th.AssertNoErr(t, err)
-
- th.AssertEquals(t, ext.Updated, "2013-02-03T10:00:00-00:00")
- th.AssertEquals(t, ext.Name, "agent")
- th.AssertEquals(t, ext.Namespace, "http://docs.openstack.org/ext/agent/api/v2.0")
- th.AssertEquals(t, ext.Alias, "agent")
- th.AssertEquals(t, ext.Description, "The agent management extension.")
})
+
+ ext, err := Get(fake.ServiceClient(), "agent").Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, ext.Updated, "2013-02-03T10:00:00-00:00")
+ th.AssertEquals(t, ext.Name, "agent")
+ th.AssertEquals(t, ext.Namespace, "http://docs.openstack.org/ext/agent/api/v2.0")
+ th.AssertEquals(t, ext.Alias, "agent")
+ th.AssertEquals(t, ext.Description, "The agent management extension.")
}
diff --git a/openstack/networking/v2/extensions/external/results.go b/openstack/networking/v2/extensions/external/results.go
index 4cd2133..47f7258 100644
--- a/openstack/networking/v2/extensions/external/results.go
+++ b/openstack/networking/v2/extensions/external/results.go
@@ -1,8 +1,6 @@
package external
import (
- "fmt"
-
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
"github.com/rackspace/gophercloud/pagination"
@@ -37,52 +35,36 @@
External bool `mapstructure:"router:external" json:"router:external"`
}
-// ExtractGet decorates a GetResult struct returned from a networks.Get()
-// function with extended attributes.
-func ExtractGet(r networks.GetResult) (*NetworkExternal, error) {
- if r.Err != nil {
- return nil, r.Err
+func commonExtract(e error, response map[string]interface{}) (*NetworkExternal, error) {
+ if e != nil {
+ return nil, e
}
+
var res struct {
Network *NetworkExternal `json:"network"`
}
- err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Neutron network: %v", err)
- }
- return res.Network, nil
+
+ err := mapstructure.Decode(response, &res)
+
+ return res.Network, err
+}
+
+// ExtractGet decorates a GetResult struct returned from a networks.Get()
+// function with extended attributes.
+func ExtractGet(r networks.GetResult) (*NetworkExternal, error) {
+ return commonExtract(r.Err, r.Resp)
}
// ExtractCreate decorates a CreateResult struct returned from a networks.Create()
// function with extended attributes.
func ExtractCreate(r networks.CreateResult) (*NetworkExternal, error) {
- if r.Err != nil {
- return nil, r.Err
- }
- var res struct {
- Network *NetworkExternal `json:"network"`
- }
- err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Neutron network: %v", err)
- }
- return res.Network, nil
+ return commonExtract(r.Err, r.Resp)
}
// ExtractUpdate decorates a UpdateResult struct returned from a
// networks.Update() function with extended attributes.
func ExtractUpdate(r networks.UpdateResult) (*NetworkExternal, error) {
- if r.Err != nil {
- return nil, r.Err
- }
- var res struct {
- Network *NetworkExternal `json:"network"`
- }
- err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Neutron network: %v", err)
- }
- return res.Network, nil
+ return commonExtract(r.Err, r.Resp)
}
// ExtractList accepts a Page struct, specifically a NetworkPage struct, and
@@ -94,9 +76,6 @@
}
err := mapstructure.Decode(page.(networks.NetworkPage).Body, &resp)
- if err != nil {
- return nil, err
- }
- return resp.Networks, nil
+ return resp.Networks, err
}
diff --git a/openstack/networking/v2/extensions/external/results_test.go b/openstack/networking/v2/extensions/external/results_test.go
index 6bed126..916cd2c 100644
--- a/openstack/networking/v2/extensions/external/results_test.go
+++ b/openstack/networking/v2/extensions/external/results_test.go
@@ -1,6 +1,7 @@
package external
import (
+ "errors"
"fmt"
"net/http"
"testing"
@@ -228,3 +229,26 @@
th.AssertNoErr(t, err)
th.AssertEquals(t, true, n.External)
}
+
+func TestExtractFnsReturnsErrWhenResultContainsErr(t *testing.T) {
+ gr := networks.GetResult{}
+ gr.Err = errors.New("")
+
+ if _, err := ExtractGet(gr); err == nil {
+ t.Fatalf("Expected error, got one")
+ }
+
+ ur := networks.UpdateResult{}
+ ur.Err = errors.New("")
+
+ if _, err := ExtractUpdate(ur); err == nil {
+ t.Fatalf("Expected error, got one")
+ }
+
+ cr := networks.CreateResult{}
+ cr.Err = errors.New("")
+
+ if _, err := ExtractCreate(cr); err == nil {
+ t.Fatalf("Expected error, got one")
+ }
+}
diff --git a/openstack/networking/v2/extensions/layer3/floatingips/requests_test.go b/openstack/networking/v2/extensions/layer3/floatingips/requests_test.go
index b9153fc..19614be 100644
--- a/openstack/networking/v2/extensions/layer3/floatingips/requests_test.go
+++ b/openstack/networking/v2/extensions/layer3/floatingips/requests_test.go
@@ -5,9 +5,9 @@
"net/http"
"testing"
+ fake "github.com/rackspace/gophercloud/openstack/networking/v2/common"
"github.com/rackspace/gophercloud/pagination"
th "github.com/rackspace/gophercloud/testhelper"
- fake "github.com/rackspace/gophercloud/testhelper/client"
)
func TestList(t *testing.T) {
@@ -90,6 +90,34 @@
}
}
+func TestInvalidNextPageURLs(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/v2.0/floatingips", func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ fmt.Fprintf(w, `{"floatingips": [{}], "floatingips_links": {}}`)
+ })
+
+ List(fake.ServiceClient(), ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
+ ExtractFloatingIPs(page)
+ return true, nil
+ })
+}
+
+func TestRequiredFieldsForCreate(t *testing.T) {
+ res1 := Create(fake.ServiceClient(), CreateOpts{FloatingNetworkID: ""})
+ if res1.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+
+ res2 := Create(fake.ServiceClient(), CreateOpts{FloatingNetworkID: "foo", PortID: ""})
+ if res2.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+}
+
func TestCreate(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
diff --git a/openstack/networking/v2/extensions/layer3/floatingips/results.go b/openstack/networking/v2/extensions/layer3/floatingips/results.go
index 4857c92..43892f0 100644
--- a/openstack/networking/v2/extensions/layer3/floatingips/results.go
+++ b/openstack/networking/v2/extensions/layer3/floatingips/results.go
@@ -89,12 +89,8 @@
// the end of a page and the pager seeks to traverse over a new one. In order
// to do this, it needs to construct the next page's URL.
func (p FloatingIPPage) NextPageURL() (string, error) {
- type link struct {
- Href string `mapstructure:"href"`
- Rel string `mapstructure:"rel"`
- }
type resp struct {
- Links []link `mapstructure:"floatingips_links"`
+ Links []gophercloud.Link `mapstructure:"floatingips_links"`
}
var r resp
@@ -103,17 +99,7 @@
return "", err
}
- var url string
- for _, l := range r.Links {
- if l.Rel == "next" {
- url = l.Href
- }
- }
- if url == "" {
- return "", nil
- }
-
- return url, nil
+ return gophercloud.ExtractNextURL(r.Links)
}
// IsEmpty checks whether a NetworkPage struct is empty.
@@ -134,9 +120,6 @@
}
err := mapstructure.Decode(page.(FloatingIPPage).Body, &resp)
- if err != nil {
- return nil, err
- }
- return resp.FloatingIPs, nil
+ return resp.FloatingIPs, err
}
diff --git a/openstack/networking/v2/extensions/layer3/floatingips/urls.go b/openstack/networking/v2/extensions/layer3/floatingips/urls.go
index dbe3f9f..355f20d 100644
--- a/openstack/networking/v2/extensions/layer3/floatingips/urls.go
+++ b/openstack/networking/v2/extensions/layer3/floatingips/urls.go
@@ -2,15 +2,12 @@
import "github.com/rackspace/gophercloud"
-const (
- version = "v2.0"
- resourcePath = "floatingips"
-)
+const resourcePath = "floatingips"
func rootURL(c *gophercloud.ServiceClient) string {
- return c.ServiceURL(version, resourcePath)
+ return c.ServiceURL(resourcePath)
}
func resourceURL(c *gophercloud.ServiceClient, id string) string {
- return c.ServiceURL(version, resourcePath, id)
+ return c.ServiceURL(resourcePath, id)
}
diff --git a/openstack/networking/v2/extensions/layer3/routers/requests_test.go b/openstack/networking/v2/extensions/layer3/routers/requests_test.go
index 56a0d74..c34264d 100755
--- a/openstack/networking/v2/extensions/layer3/routers/requests_test.go
+++ b/openstack/networking/v2/extensions/layer3/routers/requests_test.go
@@ -5,9 +5,9 @@
"net/http"
"testing"
+ fake "github.com/rackspace/gophercloud/openstack/networking/v2/common"
"github.com/rackspace/gophercloud/pagination"
th "github.com/rackspace/gophercloud/testhelper"
- fake "github.com/rackspace/gophercloud/testhelper/client"
)
func TestURLs(t *testing.T) {
@@ -288,6 +288,17 @@
th.AssertEquals(t, "9a83fa11-8da5-436e-9afe-3d3ac5ce7770", res.ID)
}
+func TestAddInterfaceRequiredOpts(t *testing.T) {
+ _, err := AddInterface(fake.ServiceClient(), "foo", InterfaceOpts{}).Extract()
+ if err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+ _, err = AddInterface(fake.ServiceClient(), "foo", InterfaceOpts{SubnetID: "bar", PortID: "baz"}).Extract()
+ if err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+}
+
func TestRemoveInterface(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
diff --git a/openstack/networking/v2/extensions/layer3/routers/results.go b/openstack/networking/v2/extensions/layer3/routers/results.go
index d14578c..eae647f 100755
--- a/openstack/networking/v2/extensions/layer3/routers/results.go
+++ b/openstack/networking/v2/extensions/layer3/routers/results.go
@@ -1,8 +1,6 @@
package routers
import (
- "fmt"
-
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
@@ -53,12 +51,8 @@
// the end of a page and the pager seeks to traverse over a new one. In order
// to do this, it needs to construct the next page's URL.
func (p RouterPage) NextPageURL() (string, error) {
- type link struct {
- Href string `mapstructure:"href"`
- Rel string `mapstructure:"rel"`
- }
type resp struct {
- Links []link `mapstructure:"routers_links"`
+ Links []gophercloud.Link `mapstructure:"routers_links"`
}
var r resp
@@ -67,17 +61,7 @@
return "", err
}
- var url string
- for _, l := range r.Links {
- if l.Rel == "next" {
- url = l.Href
- }
- }
- if url == "" {
- return "", nil
- }
-
- return url, nil
+ return gophercloud.ExtractNextURL(r.Links)
}
// IsEmpty checks whether a RouterPage struct is empty.
@@ -98,11 +82,8 @@
}
err := mapstructure.Decode(page.(RouterPage).Body, &resp)
- if err != nil {
- return nil, err
- }
- return resp.Routers, nil
+ return resp.Routers, err
}
type commonResult struct {
@@ -120,11 +101,8 @@
}
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Neutron router: %v", err)
- }
- return res.Router, nil
+ return res.Router, err
}
// CreateResult represents the result of a create operation.
@@ -176,9 +154,6 @@
var res *InterfaceInfo
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Neutron router interface: %v", err)
- }
- return res, nil
+ return res, err
}
diff --git a/openstack/networking/v2/extensions/layer3/routers/urls.go b/openstack/networking/v2/extensions/layer3/routers/urls.go
index 512c8a4..bc22c2a 100644
--- a/openstack/networking/v2/extensions/layer3/routers/urls.go
+++ b/openstack/networking/v2/extensions/layer3/routers/urls.go
@@ -2,23 +2,20 @@
import "github.com/rackspace/gophercloud"
-const (
- version = "v2.0"
- resourcePath = "routers"
-)
+const resourcePath = "routers"
func rootURL(c *gophercloud.ServiceClient) string {
- return c.ServiceURL(version, resourcePath)
+ return c.ServiceURL(resourcePath)
}
func resourceURL(c *gophercloud.ServiceClient, id string) string {
- return c.ServiceURL(version, resourcePath, id)
+ return c.ServiceURL(resourcePath, id)
}
func addInterfaceURL(c *gophercloud.ServiceClient, id string) string {
- return c.ServiceURL(version, resourcePath, id, "add_router_interface")
+ return c.ServiceURL(resourcePath, id, "add_router_interface")
}
func removeInterfaceURL(c *gophercloud.ServiceClient, id string) string {
- return c.ServiceURL(version, resourcePath, id, "remove_router_interface")
+ return c.ServiceURL(resourcePath, id, "remove_router_interface")
}
diff --git a/openstack/networking/v2/extensions/lbaas/members/requests_test.go b/openstack/networking/v2/extensions/lbaas/members/requests_test.go
index cae3524..dc1ece3 100644
--- a/openstack/networking/v2/extensions/lbaas/members/requests_test.go
+++ b/openstack/networking/v2/extensions/lbaas/members/requests_test.go
@@ -5,9 +5,9 @@
"net/http"
"testing"
+ fake "github.com/rackspace/gophercloud/openstack/networking/v2/common"
"github.com/rackspace/gophercloud/pagination"
th "github.com/rackspace/gophercloud/testhelper"
- fake "github.com/rackspace/gophercloud/testhelper/client"
)
func TestURLs(t *testing.T) {
diff --git a/openstack/networking/v2/extensions/lbaas/members/results.go b/openstack/networking/v2/extensions/lbaas/members/results.go
index 9466fee..b006551 100644
--- a/openstack/networking/v2/extensions/lbaas/members/results.go
+++ b/openstack/networking/v2/extensions/lbaas/members/results.go
@@ -1,8 +1,6 @@
package members
import (
- "fmt"
-
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
@@ -46,12 +44,8 @@
// the end of a page and the pager seeks to traverse over a new one. In order
// to do this, it needs to construct the next page's URL.
func (p MemberPage) NextPageURL() (string, error) {
- type link struct {
- Href string `mapstructure:"href"`
- Rel string `mapstructure:"rel"`
- }
type resp struct {
- Links []link `mapstructure:"members_links"`
+ Links []gophercloud.Link `mapstructure:"members_links"`
}
var r resp
@@ -60,17 +54,7 @@
return "", err
}
- var url string
- for _, l := range r.Links {
- if l.Rel == "next" {
- url = l.Href
- }
- }
- if url == "" {
- return "", nil
- }
-
- return url, nil
+ return gophercloud.ExtractNextURL(r.Links)
}
// IsEmpty checks whether a MemberPage struct is empty.
@@ -113,11 +97,8 @@
}
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Neutron member: %v", err)
- }
- return res.Member, nil
+ return res.Member, err
}
// CreateResult represents the result of a create operation.
diff --git a/openstack/networking/v2/extensions/lbaas/members/urls.go b/openstack/networking/v2/extensions/lbaas/members/urls.go
index 9d5ecec..94b57e4 100644
--- a/openstack/networking/v2/extensions/lbaas/members/urls.go
+++ b/openstack/networking/v2/extensions/lbaas/members/urls.go
@@ -3,15 +3,14 @@
import "github.com/rackspace/gophercloud"
const (
- version = "v2.0"
rootPath = "lb"
resourcePath = "members"
)
func rootURL(c *gophercloud.ServiceClient) string {
- return c.ServiceURL(version, rootPath, resourcePath)
+ return c.ServiceURL(rootPath, resourcePath)
}
func resourceURL(c *gophercloud.ServiceClient, id string) string {
- return c.ServiceURL(version, rootPath, resourcePath, id)
+ return c.ServiceURL(rootPath, resourcePath, id)
}
diff --git a/openstack/networking/v2/extensions/lbaas/monitors/requests_test.go b/openstack/networking/v2/extensions/lbaas/monitors/requests_test.go
index 68a3288..5c5a1d2 100644
--- a/openstack/networking/v2/extensions/lbaas/monitors/requests_test.go
+++ b/openstack/networking/v2/extensions/lbaas/monitors/requests_test.go
@@ -5,9 +5,9 @@
"net/http"
"testing"
+ fake "github.com/rackspace/gophercloud/openstack/networking/v2/common"
"github.com/rackspace/gophercloud/pagination"
th "github.com/rackspace/gophercloud/testhelper"
- fake "github.com/rackspace/gophercloud/testhelper/client"
)
func TestURLs(t *testing.T) {
@@ -158,6 +158,17 @@
th.AssertNoErr(t, err)
}
+func TestRequiredCreateOpts(t *testing.T) {
+ res := Create(fake.ServiceClient(), CreateOpts{})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+ res = Create(fake.ServiceClient(), CreateOpts{Type: TypeHTTP})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+}
+
func TestGet(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
diff --git a/openstack/networking/v2/extensions/lbaas/monitors/results.go b/openstack/networking/v2/extensions/lbaas/monitors/results.go
index a41f20e..656ab1d 100644
--- a/openstack/networking/v2/extensions/lbaas/monitors/results.go
+++ b/openstack/networking/v2/extensions/lbaas/monitors/results.go
@@ -1,8 +1,6 @@
package monitors
import (
- "fmt"
-
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
@@ -74,12 +72,8 @@
// the end of a page and the pager seeks to traverse over a new one. In order
// to do this, it needs to construct the next page's URL.
func (p MonitorPage) NextPageURL() (string, error) {
- type link struct {
- Href string `mapstructure:"href"`
- Rel string `mapstructure:"rel"`
- }
type resp struct {
- Links []link `mapstructure:"health_monitors_links"`
+ Links []gophercloud.Link `mapstructure:"health_monitors_links"`
}
var r resp
@@ -88,17 +82,7 @@
return "", err
}
- var url string
- for _, l := range r.Links {
- if l.Rel == "next" {
- url = l.Href
- }
- }
- if url == "" {
- return "", nil
- }
-
- return url, nil
+ return gophercloud.ExtractNextURL(r.Links)
}
// IsEmpty checks whether a PoolPage struct is empty.
@@ -119,11 +103,8 @@
}
err := mapstructure.Decode(page.(MonitorPage).Body, &resp)
- if err != nil {
- return nil, err
- }
- return resp.Monitors, nil
+ return resp.Monitors, err
}
type commonResult struct {
@@ -141,11 +122,8 @@
}
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Neutron monitor: %v", err)
- }
- return res.Monitor, nil
+ return res.Monitor, err
}
// CreateResult represents the result of a create operation.
diff --git a/openstack/networking/v2/extensions/lbaas/monitors/urls.go b/openstack/networking/v2/extensions/lbaas/monitors/urls.go
index e4b2afc..46e84bb 100644
--- a/openstack/networking/v2/extensions/lbaas/monitors/urls.go
+++ b/openstack/networking/v2/extensions/lbaas/monitors/urls.go
@@ -3,15 +3,14 @@
import "github.com/rackspace/gophercloud"
const (
- version = "v2.0"
rootPath = "lb"
resourcePath = "health_monitors"
)
func rootURL(c *gophercloud.ServiceClient) string {
- return c.ServiceURL(version, rootPath, resourcePath)
+ return c.ServiceURL(rootPath, resourcePath)
}
func resourceURL(c *gophercloud.ServiceClient, id string) string {
- return c.ServiceURL(version, rootPath, resourcePath, id)
+ return c.ServiceURL(rootPath, resourcePath, id)
}
diff --git a/openstack/networking/v2/extensions/lbaas/pools/requests_test.go b/openstack/networking/v2/extensions/lbaas/pools/requests_test.go
index 6af47a1..6da29a6 100644
--- a/openstack/networking/v2/extensions/lbaas/pools/requests_test.go
+++ b/openstack/networking/v2/extensions/lbaas/pools/requests_test.go
@@ -5,9 +5,9 @@
"net/http"
"testing"
+ fake "github.com/rackspace/gophercloud/openstack/networking/v2/common"
"github.com/rackspace/gophercloud/pagination"
th "github.com/rackspace/gophercloud/testhelper"
- fake "github.com/rackspace/gophercloud/testhelper/client"
)
func TestURLs(t *testing.T) {
diff --git a/openstack/networking/v2/extensions/lbaas/pools/results.go b/openstack/networking/v2/extensions/lbaas/pools/results.go
index 5b2adde..4233176 100644
--- a/openstack/networking/v2/extensions/lbaas/pools/results.go
+++ b/openstack/networking/v2/extensions/lbaas/pools/results.go
@@ -1,8 +1,6 @@
package pools
import (
- "fmt"
-
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
@@ -68,12 +66,8 @@
// the end of a page and the pager seeks to traverse over a new one. In order
// to do this, it needs to construct the next page's URL.
func (p PoolPage) NextPageURL() (string, error) {
- type link struct {
- Href string `mapstructure:"href"`
- Rel string `mapstructure:"rel"`
- }
type resp struct {
- Links []link `mapstructure:"pools_links"`
+ Links []gophercloud.Link `mapstructure:"pools_links"`
}
var r resp
@@ -82,17 +76,7 @@
return "", err
}
- var url string
- for _, l := range r.Links {
- if l.Rel == "next" {
- url = l.Href
- }
- }
- if url == "" {
- return "", nil
- }
-
- return url, nil
+ return gophercloud.ExtractNextURL(r.Links)
}
// IsEmpty checks whether a PoolPage struct is empty.
@@ -113,11 +97,8 @@
}
err := mapstructure.Decode(page.(PoolPage).Body, &resp)
- if err != nil {
- return nil, err
- }
- return resp.Pools, nil
+ return resp.Pools, err
}
type commonResult struct {
@@ -135,11 +116,8 @@
}
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Neutron pool: %v", err)
- }
- return res.Pool, nil
+ return res.Pool, err
}
// CreateResult represents the result of a create operation.
diff --git a/openstack/networking/v2/extensions/lbaas/pools/urls.go b/openstack/networking/v2/extensions/lbaas/pools/urls.go
index 124ef5d..6cd15b0 100644
--- a/openstack/networking/v2/extensions/lbaas/pools/urls.go
+++ b/openstack/networking/v2/extensions/lbaas/pools/urls.go
@@ -3,24 +3,23 @@
import "github.com/rackspace/gophercloud"
const (
- version = "v2.0"
rootPath = "lb"
resourcePath = "pools"
monitorPath = "health_monitors"
)
func rootURL(c *gophercloud.ServiceClient) string {
- return c.ServiceURL(version, rootPath, resourcePath)
+ return c.ServiceURL(rootPath, resourcePath)
}
func resourceURL(c *gophercloud.ServiceClient, id string) string {
- return c.ServiceURL(version, rootPath, resourcePath, id)
+ return c.ServiceURL(rootPath, resourcePath, id)
}
func associateURL(c *gophercloud.ServiceClient, id string) string {
- return c.ServiceURL(version, rootPath, resourcePath, id, monitorPath)
+ return c.ServiceURL(rootPath, resourcePath, id, monitorPath)
}
func disassociateURL(c *gophercloud.ServiceClient, poolID, monitorID string) string {
- return c.ServiceURL(version, rootPath, resourcePath, poolID, monitorPath, monitorID)
+ return c.ServiceURL(rootPath, resourcePath, poolID, monitorPath, monitorID)
}
diff --git a/openstack/networking/v2/extensions/lbaas/vips/requests_test.go b/openstack/networking/v2/extensions/lbaas/vips/requests_test.go
index f4e90c7..430f1a1 100644
--- a/openstack/networking/v2/extensions/lbaas/vips/requests_test.go
+++ b/openstack/networking/v2/extensions/lbaas/vips/requests_test.go
@@ -5,9 +5,9 @@
"net/http"
"testing"
+ fake "github.com/rackspace/gophercloud/openstack/networking/v2/common"
"github.com/rackspace/gophercloud/pagination"
th "github.com/rackspace/gophercloud/testhelper"
- fake "github.com/rackspace/gophercloud/testhelper/client"
)
func TestURLs(t *testing.T) {
@@ -139,7 +139,8 @@
"admin_state_up": true,
"subnet_id": "8032909d-47a1-4715-90af-5153ffe39861",
"pool_id": "61b1f87a-7a21-4ad3-9dda-7f81d249944f",
- "protocol_port": 80
+ "protocol_port": 80,
+ "session_persistence": {"type": "SOURCE_IP"}
}
}
`)
@@ -175,6 +176,7 @@
SubnetID: "8032909d-47a1-4715-90af-5153ffe39861",
PoolID: "61b1f87a-7a21-4ad3-9dda-7f81d249944f",
ProtocolPort: 80,
+ Persistence: &SessionPersistence{Type: "SOURCE_IP"},
}
r, err := Create(fake.ServiceClient(), opts).Extract()
@@ -195,6 +197,29 @@
th.AssertEquals(t, "NewVip", r.Name)
}
+func TestRequiredCreateOpts(t *testing.T) {
+ res := Create(fake.ServiceClient(), CreateOpts{})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+ res = Create(fake.ServiceClient(), CreateOpts{Name: "foo"})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+ res = Create(fake.ServiceClient(), CreateOpts{Name: "foo", SubnetID: "bar"})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+ res = Create(fake.ServiceClient(), CreateOpts{Name: "foo", SubnetID: "bar", Protocol: "bar"})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+ res = Create(fake.ServiceClient(), CreateOpts{Name: "foo", SubnetID: "bar", Protocol: "bar", ProtocolPort: 80})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+}
+
func TestGet(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
@@ -254,7 +279,8 @@
th.TestJSONRequest(t, r, `
{
"vip": {
- "connection_limit": 1000
+ "connection_limit": 1000,
+ "session_persistence": {"type": "SOURCE_IP"}
}
}
`)
@@ -284,7 +310,10 @@
})
i1000 := 1000
- options := UpdateOpts{ConnLimit: &i1000}
+ options := UpdateOpts{
+ ConnLimit: &i1000,
+ Persistence: &SessionPersistence{Type: "SOURCE_IP"},
+ }
vip, err := Update(fake.ServiceClient(), "4ec89087-d057-4e2c-911f-60a3b47ee304", options).Extract()
th.AssertNoErr(t, err)
diff --git a/openstack/networking/v2/extensions/lbaas/vips/results.go b/openstack/networking/v2/extensions/lbaas/vips/results.go
index 62efe09..5925adc 100644
--- a/openstack/networking/v2/extensions/lbaas/vips/results.go
+++ b/openstack/networking/v2/extensions/lbaas/vips/results.go
@@ -1,8 +1,6 @@
package vips
import (
- "fmt"
-
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
@@ -28,7 +26,7 @@
Type string `mapstructure:"type" json:"type"`
// Name of cookie if persistence mode is set appropriately
- CookieName string `mapstructure:"cookie_name" json:"cookie_name"`
+ CookieName string `mapstructure:"cookie_name" json:"cookie_name,omitempty"`
}
// VirtualIP is the primary load balancing configuration object that specifies
@@ -93,12 +91,8 @@
// the end of a page and the pager seeks to traverse over a new one. In order
// to do this, it needs to construct the next page's URL.
func (p VIPPage) NextPageURL() (string, error) {
- type link struct {
- Href string `mapstructure:"href"`
- Rel string `mapstructure:"rel"`
- }
type resp struct {
- Links []link `mapstructure:"vips_links"`
+ Links []gophercloud.Link `mapstructure:"vips_links"`
}
var r resp
@@ -107,17 +101,7 @@
return "", err
}
- var url string
- for _, l := range r.Links {
- if l.Rel == "next" {
- url = l.Href
- }
- }
- if url == "" {
- return "", nil
- }
-
- return url, nil
+ return gophercloud.ExtractNextURL(r.Links)
}
// IsEmpty checks whether a RouterPage struct is empty.
@@ -138,11 +122,8 @@
}
err := mapstructure.Decode(page.(VIPPage).Body, &resp)
- if err != nil {
- return nil, err
- }
- return resp.VIPs, nil
+ return resp.VIPs, err
}
type commonResult struct {
@@ -160,11 +141,8 @@
}
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Neutron Virtual IP: %v", err)
- }
- return res.VirtualIP, nil
+ return res.VirtualIP, err
}
// CreateResult represents the result of a create operation.
diff --git a/openstack/networking/v2/extensions/lbaas/vips/urls.go b/openstack/networking/v2/extensions/lbaas/vips/urls.go
index 570db6d..2b6f67e 100644
--- a/openstack/networking/v2/extensions/lbaas/vips/urls.go
+++ b/openstack/networking/v2/extensions/lbaas/vips/urls.go
@@ -3,15 +3,14 @@
import "github.com/rackspace/gophercloud"
const (
- version = "v2.0"
rootPath = "lb"
resourcePath = "vips"
)
func rootURL(c *gophercloud.ServiceClient) string {
- return c.ServiceURL(version, rootPath, resourcePath)
+ return c.ServiceURL(rootPath, resourcePath)
}
func resourceURL(c *gophercloud.ServiceClient, id string) string {
- return c.ServiceURL(version, rootPath, resourcePath, id)
+ return c.ServiceURL(rootPath, resourcePath, id)
}
diff --git a/openstack/networking/v2/extensions/provider/results.go b/openstack/networking/v2/extensions/provider/results.go
index a20b259..8fc21b4 100755
--- a/openstack/networking/v2/extensions/provider/results.go
+++ b/openstack/networking/v2/extensions/provider/results.go
@@ -1,8 +1,6 @@
package provider
import (
- "fmt"
-
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
"github.com/rackspace/gophercloud/pagination"
@@ -70,14 +68,14 @@
if r.Err != nil {
return nil, r.Err
}
+
var res struct {
Network *NetworkExtAttrs `json:"network"`
}
+
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Neutron network: %v", err)
- }
- return res.Network, nil
+
+ return res.Network, err
}
// ExtractCreate decorates a CreateResult struct returned from a networks.Create()
@@ -86,14 +84,14 @@
if r.Err != nil {
return nil, r.Err
}
+
var res struct {
Network *NetworkExtAttrs `json:"network"`
}
+
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Neutron network: %v", err)
- }
- return res.Network, nil
+
+ return res.Network, err
}
// ExtractUpdate decorates a UpdateResult struct returned from a
@@ -102,14 +100,14 @@
if r.Err != nil {
return nil, r.Err
}
+
var res struct {
Network *NetworkExtAttrs `json:"network"`
}
+
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Neutron network: %v", err)
- }
- return res.Network, nil
+
+ return res.Network, err
}
// ExtractList accepts a Page struct, specifically a NetworkPage struct, and
@@ -121,9 +119,6 @@
}
err := mapstructure.Decode(page.(networks.NetworkPage).Body, &resp)
- if err != nil {
- return nil, err
- }
- return resp.Networks, nil
+ return resp.Networks, err
}
diff --git a/openstack/networking/v2/extensions/provider/results_test.go b/openstack/networking/v2/extensions/provider/results_test.go
index 74951d9..9801b2e 100644
--- a/openstack/networking/v2/extensions/provider/results_test.go
+++ b/openstack/networking/v2/extensions/provider/results_test.go
@@ -5,17 +5,17 @@
"net/http"
"testing"
+ fake "github.com/rackspace/gophercloud/openstack/networking/v2/common"
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
"github.com/rackspace/gophercloud/pagination"
th "github.com/rackspace/gophercloud/testhelper"
- fake "github.com/rackspace/gophercloud/testhelper/client"
)
func TestList(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/networks", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/networks", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
@@ -109,7 +109,7 @@
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/networks/d32019d3-bc6e-4319-9c1d-6722fc136a22", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/networks/d32019d3-bc6e-4319-9c1d-6722fc136a22", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
@@ -150,7 +150,7 @@
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/networks", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/networks", 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")
@@ -202,7 +202,7 @@
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/networks/4e8e5957-649f-477b-9e5b-f1f75b21c03c", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/networks/4e8e5957-649f-477b-9e5b-f1f75b21c03c", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "PUT")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
th.TestHeader(t, r, "Content-Type", "application/json")
diff --git a/openstack/networking/v2/extensions/security/groups/requests_test.go b/openstack/networking/v2/extensions/security/groups/requests_test.go
index 857bdc6..5f074c7 100644
--- a/openstack/networking/v2/extensions/security/groups/requests_test.go
+++ b/openstack/networking/v2/extensions/security/groups/requests_test.go
@@ -5,10 +5,10 @@
"net/http"
"testing"
+ fake "github.com/rackspace/gophercloud/openstack/networking/v2/common"
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/rules"
"github.com/rackspace/gophercloud/pagination"
th "github.com/rackspace/gophercloud/testhelper"
- fake "github.com/rackspace/gophercloud/testhelper/client"
)
func TestURLs(t *testing.T) {
diff --git a/openstack/networking/v2/extensions/security/groups/results.go b/openstack/networking/v2/extensions/security/groups/results.go
index 6db613e..617d690 100644
--- a/openstack/networking/v2/extensions/security/groups/results.go
+++ b/openstack/networking/v2/extensions/security/groups/results.go
@@ -1,8 +1,6 @@
package groups
import (
- "fmt"
-
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/rules"
@@ -40,12 +38,8 @@
// reached the end of a page and the pager seeks to traverse over a new one. In
// order to do this, it needs to construct the next page's URL.
func (p SecGroupPage) NextPageURL() (string, error) {
- type link struct {
- Href string `mapstructure:"href"`
- Rel string `mapstructure:"rel"`
- }
type resp struct {
- Links []link `mapstructure:"security_groups_links"`
+ Links []gophercloud.Link `mapstructure:"security_groups_links"`
}
var r resp
@@ -54,17 +48,7 @@
return "", err
}
- var url string
- for _, l := range r.Links {
- if l.Rel == "next" {
- url = l.Href
- }
- }
- if url == "" {
- return "", nil
- }
-
- return url, nil
+ return gophercloud.ExtractNextURL(r.Links)
}
// IsEmpty checks whether a SecGroupPage struct is empty.
@@ -85,11 +69,8 @@
}
err := mapstructure.Decode(page.(SecGroupPage).Body, &resp)
- if err != nil {
- return nil, err
- }
- return resp.SecGroups, nil
+ return resp.SecGroups, err
}
type commonResult struct {
@@ -107,11 +88,8 @@
}
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Neutron secgroup: %v", err)
- }
- return res.SecGroup, nil
+ return res.SecGroup, err
}
// CreateResult represents the result of a create operation.
diff --git a/openstack/networking/v2/extensions/security/groups/urls.go b/openstack/networking/v2/extensions/security/groups/urls.go
index 2f2bbdd..84f7324 100644
--- a/openstack/networking/v2/extensions/security/groups/urls.go
+++ b/openstack/networking/v2/extensions/security/groups/urls.go
@@ -2,15 +2,12 @@
import "github.com/rackspace/gophercloud"
-const (
- version = "v2.0"
- rootPath = "security-groups"
-)
+const rootPath = "security-groups"
func rootURL(c *gophercloud.ServiceClient) string {
- return c.ServiceURL(version, rootPath)
+ return c.ServiceURL(rootPath)
}
func resourceURL(c *gophercloud.ServiceClient, id string) string {
- return c.ServiceURL(version, rootPath, id)
+ return c.ServiceURL(rootPath, id)
}
diff --git a/openstack/networking/v2/extensions/security/rules/requests_test.go b/openstack/networking/v2/extensions/security/rules/requests_test.go
index a2c7fbb..b5afef3 100644
--- a/openstack/networking/v2/extensions/security/rules/requests_test.go
+++ b/openstack/networking/v2/extensions/security/rules/requests_test.go
@@ -5,9 +5,9 @@
"net/http"
"testing"
+ fake "github.com/rackspace/gophercloud/openstack/networking/v2/common"
"github.com/rackspace/gophercloud/pagination"
th "github.com/rackspace/gophercloud/testhelper"
- fake "github.com/rackspace/gophercloud/testhelper/client"
)
func TestURLs(t *testing.T) {
@@ -165,6 +165,25 @@
th.AssertNoErr(t, err)
}
+func TestRequiredCreateOpts(t *testing.T) {
+ res := Create(fake.ServiceClient(), CreateOpts{Direction: "something"})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+ res = Create(fake.ServiceClient(), CreateOpts{Direction: DirIngress, EtherType: "something"})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+ res = Create(fake.ServiceClient(), CreateOpts{Direction: DirIngress, EtherType: Ether4})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+ res = Create(fake.ServiceClient(), CreateOpts{Direction: DirIngress, EtherType: Ether4, SecGroupID: "something", Protocol: "foo"})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+}
+
func TestGet(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
diff --git a/openstack/networking/v2/extensions/security/rules/results.go b/openstack/networking/v2/extensions/security/rules/results.go
index 13d5c7d..ca8435e 100644
--- a/openstack/networking/v2/extensions/security/rules/results.go
+++ b/openstack/networking/v2/extensions/security/rules/results.go
@@ -1,8 +1,6 @@
package rules
import (
- "fmt"
-
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
@@ -65,12 +63,8 @@
// reached the end of a page and the pager seeks to traverse over a new one. In
// order to do this, it needs to construct the next page's URL.
func (p SecGroupRulePage) NextPageURL() (string, error) {
- type link struct {
- Href string `mapstructure:"href"`
- Rel string `mapstructure:"rel"`
- }
type resp struct {
- Links []link `mapstructure:"security_group_rules_links"`
+ Links []gophercloud.Link `mapstructure:"security_group_rules_links"`
}
var r resp
@@ -79,17 +73,7 @@
return "", err
}
- var url string
- for _, l := range r.Links {
- if l.Rel == "next" {
- url = l.Href
- }
- }
- if url == "" {
- return "", nil
- }
-
- return url, nil
+ return gophercloud.ExtractNextURL(r.Links)
}
// IsEmpty checks whether a SecGroupRulePage struct is empty.
@@ -110,11 +94,8 @@
}
err := mapstructure.Decode(page.(SecGroupRulePage).Body, &resp)
- if err != nil {
- return nil, err
- }
- return resp.SecGroupRules, nil
+ return resp.SecGroupRules, err
}
type commonResult struct {
@@ -132,11 +113,8 @@
}
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Neutron SecGroupRule: %v", err)
- }
- return res.SecGroupRule, nil
+ return res.SecGroupRule, err
}
// CreateResult represents the result of a create operation.
diff --git a/openstack/networking/v2/extensions/security/rules/urls.go b/openstack/networking/v2/extensions/security/rules/urls.go
index 2ffbf37..8e2b2bb 100644
--- a/openstack/networking/v2/extensions/security/rules/urls.go
+++ b/openstack/networking/v2/extensions/security/rules/urls.go
@@ -2,15 +2,12 @@
import "github.com/rackspace/gophercloud"
-const (
- version = "v2.0"
- rootPath = "security-group-rules"
-)
+const rootPath = "security-group-rules"
func rootURL(c *gophercloud.ServiceClient) string {
- return c.ServiceURL(version, rootPath)
+ return c.ServiceURL(rootPath)
}
func resourceURL(c *gophercloud.ServiceClient, id string) string {
- return c.ServiceURL(version, rootPath, id)
+ return c.ServiceURL(rootPath, id)
}
diff --git a/openstack/networking/v2/networks/requests.go b/openstack/networking/v2/networks/requests.go
index 81b1545..39a151a 100644
--- a/openstack/networking/v2/networks/requests.go
+++ b/openstack/networking/v2/networks/requests.go
@@ -6,6 +6,19 @@
"github.com/rackspace/gophercloud/pagination"
)
+// AdminState gives users a solid type to work with for create and update
+// operations. It is recommended that users use the `Up` and `Down` enums.
+type AdminState *bool
+
+// Convenience vars for AdminStateUp values.
+var (
+ iTrue = true
+ iFalse = false
+
+ Up AdminState = &iTrue
+ Down AdminState = &iFalse
+)
+
type networkOpts struct {
AdminStateUp *bool
Name string
diff --git a/openstack/networking/v2/networks/requests_test.go b/openstack/networking/v2/networks/requests_test.go
index 6b22acd..a263b7b 100644
--- a/openstack/networking/v2/networks/requests_test.go
+++ b/openstack/networking/v2/networks/requests_test.go
@@ -5,16 +5,16 @@
"net/http"
"testing"
+ fake "github.com/rackspace/gophercloud/openstack/networking/v2/common"
"github.com/rackspace/gophercloud/pagination"
th "github.com/rackspace/gophercloud/testhelper"
- fake "github.com/rackspace/gophercloud/testhelper/client"
)
func TestList(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/networks", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/networks", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
@@ -97,7 +97,7 @@
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/networks/d32019d3-bc6e-4319-9c1d-6722fc136a22", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/networks/d32019d3-bc6e-4319-9c1d-6722fc136a22", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
@@ -137,7 +137,7 @@
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/networks", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/networks", 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")
@@ -187,7 +187,7 @@
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/networks", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/networks", 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")
@@ -216,7 +216,7 @@
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/networks/4e8e5957-649f-477b-9e5b-f1f75b21c03c", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/networks/4e8e5957-649f-477b-9e5b-f1f75b21c03c", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "PUT")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
th.TestHeader(t, r, "Content-Type", "application/json")
@@ -264,7 +264,7 @@
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/networks/4e8e5957-649f-477b-9e5b-f1f75b21c03c", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/networks/4e8e5957-649f-477b-9e5b-f1f75b21c03c", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "DELETE")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
w.WriteHeader(http.StatusNoContent)
diff --git a/openstack/networking/v2/networks/results.go b/openstack/networking/v2/networks/results.go
index 2dbd55f..e605fcf 100644
--- a/openstack/networking/v2/networks/results.go
+++ b/openstack/networking/v2/networks/results.go
@@ -1,8 +1,6 @@
package networks
import (
- "fmt"
-
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
@@ -23,11 +21,8 @@
}
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Neutron network: %v", err)
- }
- return res.Network, nil
+ return res.Network, err
}
// CreateResult represents the result of a create operation.
@@ -83,12 +78,8 @@
// the end of a page and the pager seeks to traverse over a new one. In order
// to do this, it needs to construct the next page's URL.
func (p NetworkPage) NextPageURL() (string, error) {
- type link struct {
- Href string `mapstructure:"href"`
- Rel string `mapstructure:"rel"`
- }
type resp struct {
- Links []link `mapstructure:"networks_links"`
+ Links []gophercloud.Link `mapstructure:"networks_links"`
}
var r resp
@@ -97,17 +88,7 @@
return "", err
}
- var url string
- for _, l := range r.Links {
- if l.Rel == "next" {
- url = l.Href
- }
- }
- if url == "" {
- return "", nil
- }
-
- return url, nil
+ return gophercloud.ExtractNextURL(r.Links)
}
// IsEmpty checks whether a NetworkPage struct is empty.
@@ -128,9 +109,6 @@
}
err := mapstructure.Decode(page.(NetworkPage).Body, &resp)
- if err != nil {
- return nil, err
- }
- return resp.Networks, nil
+ return resp.Networks, err
}
diff --git a/openstack/networking/v2/ports/requests.go b/openstack/networking/v2/ports/requests.go
index 6928d8f..0fbb9f2 100644
--- a/openstack/networking/v2/ports/requests.go
+++ b/openstack/networking/v2/ports/requests.go
@@ -6,6 +6,19 @@
"github.com/rackspace/gophercloud/pagination"
)
+// AdminState gives users a solid type to work with for create and update
+// operations. It is recommended that users use the `Up` and `Down` enums.
+type AdminState *bool
+
+// Convenience vars for AdminStateUp values.
+var (
+ iTrue = true
+ iFalse = false
+
+ Up AdminState = &iTrue
+ Down AdminState = &iFalse
+)
+
// ListOpts allows the filtering and sorting of paginated collections through
// the API. Filtering is achieved by passing in struct field values that map to
// the port attributes you want to see returned. SortKey allows you to sort
diff --git a/openstack/networking/v2/ports/requests_test.go b/openstack/networking/v2/ports/requests_test.go
index 7576341..9e323ef 100644
--- a/openstack/networking/v2/ports/requests_test.go
+++ b/openstack/networking/v2/ports/requests_test.go
@@ -5,16 +5,16 @@
"net/http"
"testing"
+ fake "github.com/rackspace/gophercloud/openstack/networking/v2/common"
"github.com/rackspace/gophercloud/pagination"
th "github.com/rackspace/gophercloud/testhelper"
- fake "github.com/rackspace/gophercloud/testhelper/client"
)
func TestList(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/ports", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/ports", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
@@ -93,7 +93,7 @@
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/ports/46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/ports/46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
@@ -147,7 +147,7 @@
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/ports", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/ports", 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")
@@ -157,7 +157,14 @@
"port": {
"network_id": "a87cc70a-3e15-4acf-8205-9b711a3531b7",
"name": "private-port",
- "admin_state_up": true
+ "admin_state_up": true,
+ "fixed_ips": [
+ {
+ "subnet_id": "a0304c3a-4f08-4c43-88af-d796509c97d2",
+ "ip_address": "10.0.0.2"
+ }
+ ],
+ "security_groups": ["foo"]
}
}
`)
@@ -193,7 +200,15 @@
})
asu := true
- options := CreateOpts{Name: "private-port", AdminStateUp: &asu, NetworkID: "a87cc70a-3e15-4acf-8205-9b711a3531b7"}
+ options := CreateOpts{
+ Name: "private-port",
+ AdminStateUp: &asu,
+ NetworkID: "a87cc70a-3e15-4acf-8205-9b711a3531b7",
+ FixedIPs: []IP{
+ IP{SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.2"},
+ },
+ SecurityGroups: []string{"foo"},
+ }
n, err := Create(fake.ServiceClient(), options).Extract()
th.AssertNoErr(t, err)
@@ -211,11 +226,18 @@
th.AssertDeepEquals(t, n.SecurityGroups, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"})
}
+func TestRequiredCreateOpts(t *testing.T) {
+ res := Create(fake.ServiceClient(), CreateOpts{})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+}
+
func TestUpdate(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/ports/65c0ee9f-d634-4522-8954-51021b570b0d", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/ports/65c0ee9f-d634-4522-8954-51021b570b0d", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "PUT")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
th.TestHeader(t, r, "Content-Type", "application/json")
@@ -288,7 +310,7 @@
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/ports/65c0ee9f-d634-4522-8954-51021b570b0d", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/ports/65c0ee9f-d634-4522-8954-51021b570b0d", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "DELETE")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
w.WriteHeader(http.StatusNoContent)
diff --git a/openstack/networking/v2/ports/results.go b/openstack/networking/v2/ports/results.go
index 91118a4..cedd658 100644
--- a/openstack/networking/v2/ports/results.go
+++ b/openstack/networking/v2/ports/results.go
@@ -1,8 +1,6 @@
package ports
import (
- "fmt"
-
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
@@ -23,11 +21,8 @@
}
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Neutron port: %v", err)
- }
- return res.Port, nil
+ return res.Port, err
}
// CreateResult represents the result of a create operation.
@@ -94,10 +89,7 @@
// to do this, it needs to construct the next page's URL.
func (p PortPage) NextPageURL() (string, error) {
type resp struct {
- Links []struct {
- Href string `mapstructure:"href"`
- Rel string `mapstructure:"rel"`
- } `mapstructure:"ports_links"`
+ Links []gophercloud.Link `mapstructure:"ports_links"`
}
var r resp
@@ -106,17 +98,7 @@
return "", err
}
- var url string
- for _, l := range r.Links {
- if l.Rel == "next" {
- url = l.Href
- }
- }
- if url == "" {
- return "", nil
- }
-
- return url, nil
+ return gophercloud.ExtractNextURL(r.Links)
}
// IsEmpty checks whether a PortPage struct is empty.
@@ -137,9 +119,6 @@
}
err := mapstructure.Decode(page.(PortPage).Body, &resp)
- if err != nil {
- return nil, err
- }
- return resp.Ports, nil
+ return resp.Ports, err
}
diff --git a/openstack/networking/v2/subnets/requests.go b/openstack/networking/v2/subnets/requests.go
index 092c914..a7e6b53 100644
--- a/openstack/networking/v2/subnets/requests.go
+++ b/openstack/networking/v2/subnets/requests.go
@@ -6,6 +6,19 @@
"github.com/rackspace/gophercloud/pagination"
)
+// AdminState gives users a solid type to work with for create and update
+// operations. It is recommended that users use the `Up` and `Down` enums.
+type AdminState *bool
+
+// Convenience vars for AdminStateUp values.
+var (
+ iTrue = true
+ iFalse = false
+
+ Up AdminState = &iTrue
+ Down AdminState = &iFalse
+)
+
// ListOpts allows the filtering and sorting of paginated collections through
// the API. Filtering is achieved by passing in struct field values that map to
// the subnet attributes you want to see returned. SortKey allows you to sort
@@ -76,7 +89,7 @@
IPVersion int
EnableDHCP *bool
DNSNameservers []string
- HostRoutes []interface{}
+ HostRoutes []HostRoute
}
// Create accepts a CreateOpts struct and creates a new subnet using the values
@@ -108,7 +121,7 @@
IPVersion int `json:"ip_version,omitempty"`
EnableDHCP *bool `json:"enable_dhcp,omitempty"`
DNSNameservers []string `json:"dns_nameservers,omitempty"`
- HostRoutes []interface{} `json:"host_routes,omitempty"`
+ HostRoutes []HostRoute `json:"host_routes,omitempty"`
}
type request struct {
Subnet subnet `json:"subnet"`
@@ -151,7 +164,7 @@
Name string
GatewayIP string
DNSNameservers []string
- HostRoutes []interface{}
+ HostRoutes []HostRoute
EnableDHCP *bool
}
@@ -159,11 +172,11 @@
// values provided.
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResult {
type subnet struct {
- Name *string `json:"name,omitempty"`
- GatewayIP *string `json:"gateway_ip,omitempty"`
- DNSNameservers []string `json:"dns_nameservers,omitempty"`
- HostRoutes []interface{} `json:"host_routes,omitempty"`
- EnableDHCP *bool `json:"enable_dhcp,omitempty"`
+ Name *string `json:"name,omitempty"`
+ GatewayIP *string `json:"gateway_ip,omitempty"`
+ DNSNameservers []string `json:"dns_nameservers,omitempty"`
+ HostRoutes []HostRoute `json:"host_routes,omitempty"`
+ EnableDHCP *bool `json:"enable_dhcp,omitempty"`
}
type request struct {
Subnet subnet `json:"subnet"`
diff --git a/openstack/networking/v2/subnets/requests_test.go b/openstack/networking/v2/subnets/requests_test.go
index 9f3e8df..987064a 100644
--- a/openstack/networking/v2/subnets/requests_test.go
+++ b/openstack/networking/v2/subnets/requests_test.go
@@ -5,16 +5,16 @@
"net/http"
"testing"
+ fake "github.com/rackspace/gophercloud/openstack/networking/v2/common"
"github.com/rackspace/gophercloud/pagination"
th "github.com/rackspace/gophercloud/testhelper"
- fake "github.com/rackspace/gophercloud/testhelper/client"
)
func TestList(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/subnets", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/subnets", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
@@ -128,7 +128,7 @@
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/subnets/54d6f61d-db07-451c-9ab3-b9609b6b6f0b", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/subnets/54d6f61d-db07-451c-9ab3-b9609b6b6f0b", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
@@ -184,7 +184,7 @@
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/subnets", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/subnets", 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")
@@ -194,7 +194,15 @@
"subnet": {
"network_id": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
"ip_version": 4,
- "cidr": "192.168.199.0/24"
+ "cidr": "192.168.199.0/24",
+ "dns_nameservers": ["foo"],
+ "allocation_pools": [
+ {
+ "start": "192.168.199.2",
+ "end": "192.168.199.254"
+ }
+ ],
+ "host_routes": [{"destination":"","nexthop": "bar"}]
}
}
`)
@@ -226,7 +234,21 @@
`)
})
- opts := CreateOpts{NetworkID: "d32019d3-bc6e-4319-9c1d-6722fc136a22", IPVersion: 4, CIDR: "192.168.199.0/24"}
+ opts := CreateOpts{
+ NetworkID: "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+ IPVersion: 4,
+ CIDR: "192.168.199.0/24",
+ AllocationPools: []AllocationPool{
+ AllocationPool{
+ Start: "192.168.199.2",
+ End: "192.168.199.254",
+ },
+ },
+ DNSNameservers: []string{"foo"},
+ HostRoutes: []HostRoute{
+ HostRoute{NextHop: "bar"},
+ },
+ }
s, err := Create(fake.ServiceClient(), opts).Extract()
th.AssertNoErr(t, err)
@@ -248,11 +270,28 @@
th.AssertEquals(t, s.ID, "3b80198d-4f7b-4f77-9ef5-774d54e17126")
}
+func TestRequiredCreateOpts(t *testing.T) {
+ res := Create(fake.ServiceClient(), CreateOpts{})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+
+ res = Create(fake.ServiceClient(), CreateOpts{NetworkID: "foo"})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+
+ res = Create(fake.ServiceClient(), CreateOpts{NetworkID: "foo", CIDR: "bar", IPVersion: 40})
+ if res.Err == nil {
+ t.Fatalf("Expected error, got none")
+ }
+}
+
func TestUpdate(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/subnets/08eae331-0402-425a-923c-34f7cfe39c1b", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/subnets/08eae331-0402-425a-923c-34f7cfe39c1b", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "PUT")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
th.TestHeader(t, r, "Content-Type", "application/json")
@@ -260,7 +299,9 @@
th.TestJSONRequest(t, r, `
{
"subnet": {
- "name": "my_new_subnet"
+ "name": "my_new_subnet",
+ "dns_nameservers": ["foo"],
+ "host_routes": [{"destination":"","nexthop": "bar"}]
}
}
`)
@@ -292,7 +333,13 @@
`)
})
- opts := UpdateOpts{Name: "my_new_subnet"}
+ opts := UpdateOpts{
+ Name: "my_new_subnet",
+ DNSNameservers: []string{"foo"},
+ HostRoutes: []HostRoute{
+ HostRoute{NextHop: "bar"},
+ },
+ }
s, err := Update(fake.ServiceClient(), "08eae331-0402-425a-923c-34f7cfe39c1b", opts).Extract()
th.AssertNoErr(t, err)
@@ -304,7 +351,7 @@
th.SetupHTTP()
defer th.TeardownHTTP()
- th.Mux.HandleFunc("/subnets/08eae331-0402-425a-923c-34f7cfe39c1b", func(w http.ResponseWriter, r *http.Request) {
+ th.Mux.HandleFunc("/v2.0/subnets/08eae331-0402-425a-923c-34f7cfe39c1b", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "DELETE")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
w.WriteHeader(http.StatusNoContent)
diff --git a/openstack/networking/v2/subnets/results.go b/openstack/networking/v2/subnets/results.go
index 5c5744c..3c9ef71 100644
--- a/openstack/networking/v2/subnets/results.go
+++ b/openstack/networking/v2/subnets/results.go
@@ -1,8 +1,6 @@
package subnets
import (
- "fmt"
-
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
@@ -23,11 +21,8 @@
}
err := mapstructure.Decode(r.Resp, &res)
- if err != nil {
- return nil, fmt.Errorf("Error decoding Neutron subnet: %v", err)
- }
- return res.Subnet, nil
+ return res.Subnet, err
}
// CreateResult represents the result of a create operation.
@@ -99,12 +94,8 @@
// the end of a page and the pager seeks to traverse over a new one. In order
// to do this, it needs to construct the next page's URL.
func (p SubnetPage) NextPageURL() (string, error) {
- type link struct {
- Href string `mapstructure:"href"`
- Rel string `mapstructure:"rel"`
- }
type resp struct {
- Links []link `mapstructure:"subnets_links"`
+ Links []gophercloud.Link `mapstructure:"subnets_links"`
}
var r resp
@@ -113,17 +104,7 @@
return "", err
}
- var url string
- for _, l := range r.Links {
- if l.Rel == "next" {
- url = l.Href
- }
- }
- if url == "" {
- return "", nil
- }
-
- return url, nil
+ return gophercloud.ExtractNextURL(r.Links)
}
// IsEmpty checks whether a SubnetPage struct is empty.
@@ -144,9 +125,6 @@
}
err := mapstructure.Decode(page.(SubnetPage).Body, &resp)
- if err != nil {
- return nil, err
- }
- return resp.Subnets, nil
+ return resp.Subnets, err
}
diff --git a/results.go b/results.go
index f7d526c..647ba46 100644
--- a/results.go
+++ b/results.go
@@ -10,3 +10,28 @@
// RFC3339Milli describes a time format used by API responses.
const RFC3339Milli = "2006-01-02T15:04:05.999999Z"
+
+// Link represents a structure that enables paginated collections how to
+// traverse backward or forward. The "Rel" field is usually either "next".
+type Link struct {
+ Href string `mapstructure:"href"`
+ Rel string `mapstructure:"rel"`
+}
+
+// ExtractNextURL attempts to extract the next URL from a JSON structure. It
+// follows the common structure of nesting back and next links.
+func ExtractNextURL(links []Link) (string, error) {
+ var url string
+
+ for _, l := range links {
+ if l.Rel == "next" {
+ url = l.Href
+ }
+ }
+
+ if url == "" {
+ return "", nil
+ }
+
+ return url, nil
+}