Shuffled resources into sub-packages and upgraded to new pagination idiom
diff --git a/openstack/networking/v2/apiversions/doc.go b/openstack/networking/v2/apiversions/doc.go
new file mode 100644
index 0000000..76bdb14
--- /dev/null
+++ b/openstack/networking/v2/apiversions/doc.go
@@ -0,0 +1 @@
+package apiversions
diff --git a/openstack/networking/v2/apiversions/errors.go b/openstack/networking/v2/apiversions/errors.go
new file mode 100644
index 0000000..76bdb14
--- /dev/null
+++ b/openstack/networking/v2/apiversions/errors.go
@@ -0,0 +1 @@
+package apiversions
diff --git a/openstack/networking/v2/apiversions/requests.go b/openstack/networking/v2/apiversions/requests.go
new file mode 100644
index 0000000..8e3ff32
--- /dev/null
+++ b/openstack/networking/v2/apiversions/requests.go
@@ -0,0 +1,11 @@
+package apiversions
+
+import "github.com/rackspace/gophercloud"
+
+func ListVersions(c *gophercloud.ServiceClient) gophercloud.Pager {
+ return gophercloud.NewLinkedPager(c, APIVersionsURL(c))
+}
+
+func ListVersionResources(c *gophercloud.ServiceClient, v string) gophercloud.Pager {
+ return gophercloud.NewLinkedPager(c, APIInfoURL(c, v))
+}
diff --git a/openstack/networking/v2/apiversions/requests_test.go b/openstack/networking/v2/apiversions/requests_test.go
new file mode 100644
index 0000000..0922318
--- /dev/null
+++ b/openstack/networking/v2/apiversions/requests_test.go
@@ -0,0 +1,160 @@
+package apiversions
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ "github.com/rackspace/gophercloud"
+ th "github.com/rackspace/gophercloud/testhelper"
+)
+
+const TokenID = "123"
+
+func ServiceClient() *gophercloud.ServiceClient {
+ return &gophercloud.ServiceClient{
+ Provider: &gophercloud.ProviderClient{
+ TokenID: TokenID,
+ },
+ Endpoint: th.Endpoint(),
+ }
+}
+
+func TestListVersions(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-Token", TokenID)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+
+ fmt.Fprintf(w, `
+{
+ "versions": [
+ {
+ "status": "CURRENT",
+ "id": "v2.0",
+ "links": [
+ {
+ "href": "http://23.253.228.211:9696/v2.0",
+ "rel": "self"
+ }
+ ]
+ }
+ ]
+}`)
+ })
+
+ count := 0
+
+ ListVersions(ServiceClient()).EachPage(func(page gophercloud.Page) (bool, error) {
+ count++
+ actual, err := ExtractAPIVersions(page)
+ if err != nil {
+ t.Errorf("Failed to extract API versions: %v", err)
+ return false, err
+ }
+
+ expected := []APIVersion{
+ APIVersion{
+ Status: "CURRENT",
+ ID: "v2.0",
+ },
+ }
+
+ th.AssertDeepEquals(t, expected, actual)
+
+ return true, nil
+ })
+
+ if count != 1 {
+ t.Errorf("Expected 1 page, got %d", count)
+ }
+}
+
+func TestAPIInfo(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/v2.0/", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-Token", TokenID)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+
+ fmt.Fprintf(w, `
+{
+ "resources": [
+ {
+ "links": [
+ {
+ "href": "http://23.253.228.211:9696/v2.0/subnets",
+ "rel": "self"
+ }
+ ],
+ "name": "subnet",
+ "collection": "subnets"
+ },
+ {
+ "links": [
+ {
+ "href": "http://23.253.228.211:9696/v2.0/networks",
+ "rel": "self"
+ }
+ ],
+ "name": "network",
+ "collection": "networks"
+ },
+ {
+ "links": [
+ {
+ "href": "http://23.253.228.211:9696/v2.0/ports",
+ "rel": "self"
+ }
+ ],
+ "name": "port",
+ "collection": "ports"
+ }
+ ]
+}
+ `)
+ })
+
+ count := 0
+
+ ListVersionResources(ServiceClient(), "v2.0").EachPage(func(page gophercloud.Page) (bool, error) {
+ count++
+ actual, err := ExtractVersionResources(page)
+ if err != nil {
+ t.Errorf("Failed to extract version resources: %v", err)
+ return false, err
+ }
+
+ expected := []APIVersionResource{
+ APIVersionResource{
+ Name: "subnet",
+ Collection: "subnets",
+ },
+ APIVersionResource{
+ Name: "network",
+ Collection: "networks",
+ },
+ APIVersionResource{
+ Name: "port",
+ Collection: "ports",
+ },
+ }
+
+ th.AssertDeepEquals(t, expected, actual)
+
+ return true, nil
+ })
+
+ if count != 1 {
+ t.Errorf("Expected 1 page, got %d", count)
+ }
+}
diff --git a/openstack/networking/v2/apiversions/results.go b/openstack/networking/v2/apiversions/results.go
new file mode 100644
index 0000000..dbf40eb
--- /dev/null
+++ b/openstack/networking/v2/apiversions/results.go
@@ -0,0 +1,42 @@
+package apiversions
+
+import (
+ "github.com/mitchellh/mapstructure"
+ "github.com/rackspace/gophercloud"
+)
+
+type APIVersion struct {
+ Status string `mapstructure:"status" json:"status"`
+ ID string `mapstructure:"id" json:"id"`
+}
+
+func ExtractAPIVersions(page gophercloud.Page) ([]APIVersion, error) {
+ var resp struct {
+ Versions []APIVersion `mapstructure:"versions"`
+ }
+
+ err := mapstructure.Decode(page.(gophercloud.LinkedPage).Body, &resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return resp.Versions, nil
+}
+
+type APIVersionResource struct {
+ Name string `mapstructure:"name" json:"name"`
+ Collection string `mapstructure:"collection" json:"collection"`
+}
+
+func ExtractVersionResources(page gophercloud.Page) ([]APIVersionResource, error) {
+ var resp struct {
+ APIVersionResources []APIVersionResource `mapstructure:"resources"`
+ }
+
+ err := mapstructure.Decode(page.(gophercloud.LinkedPage).Body, &resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return resp.APIVersionResources, nil
+}
diff --git a/openstack/networking/v2/apiversions/urls.go b/openstack/networking/v2/apiversions/urls.go
new file mode 100644
index 0000000..e66434e
--- /dev/null
+++ b/openstack/networking/v2/apiversions/urls.go
@@ -0,0 +1,15 @@
+package apiversions
+
+import (
+ "strings"
+
+ "github.com/rackspace/gophercloud"
+)
+
+func APIVersionsURL(c *gophercloud.ServiceClient) string {
+ return c.ServiceURL("")
+}
+
+func APIInfoURL(c *gophercloud.ServiceClient, version string) string {
+ return c.ServiceURL(strings.TrimRight(version, "/") + "/")
+}
diff --git a/openstack/networking/v2/apiversions/urls_test.go b/openstack/networking/v2/apiversions/urls_test.go
new file mode 100644
index 0000000..383ba59
--- /dev/null
+++ b/openstack/networking/v2/apiversions/urls_test.go
@@ -0,0 +1,26 @@
+package apiversions
+
+import (
+ "testing"
+
+ "github.com/rackspace/gophercloud"
+ th "github.com/rackspace/gophercloud/testhelper"
+)
+
+const Endpoint = "http://localhost:57909/"
+
+func EndpointClient() *gophercloud.ServiceClient {
+ return &gophercloud.ServiceClient{Endpoint: Endpoint}
+}
+
+func TestAPIVersionsURL(t *testing.T) {
+ actual := APIVersionsURL(EndpointClient())
+ expected := Endpoint
+ th.AssertEquals(t, expected, actual)
+}
+
+func TestAPIInfoURL(t *testing.T) {
+ actual := APIInfoURL(EndpointClient(), "v2.0")
+ expected := Endpoint + "v2.0/"
+ th.AssertEquals(t, expected, actual)
+}