api versions
diff --git a/openstack/orchestration/v1/apiversions/requests.go b/openstack/orchestration/v1/apiversions/requests.go
new file mode 100644
index 0000000..f6454c8
--- /dev/null
+++ b/openstack/orchestration/v1/apiversions/requests.go
@@ -0,0 +1,13 @@
+package apiversions
+
+import (
+ "github.com/rackspace/gophercloud"
+ "github.com/rackspace/gophercloud/pagination"
+)
+
+// ListVersions lists all the Neutron API versions available to end-users
+func ListVersions(c *gophercloud.ServiceClient) pagination.Pager {
+ return pagination.NewPager(c, apiVersionsURL(c), func(r pagination.PageResult) pagination.Page {
+ return APIVersionPage{pagination.SinglePageBase(r)}
+ })
+}
diff --git a/openstack/orchestration/v1/apiversions/requests_test.go b/openstack/orchestration/v1/apiversions/requests_test.go
new file mode 100644
index 0000000..5184864
--- /dev/null
+++ b/openstack/orchestration/v1/apiversions/requests_test.go
@@ -0,0 +1,88 @@
+package apiversions
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ "github.com/rackspace/gophercloud/pagination"
+ th "github.com/rackspace/gophercloud/testhelper"
+ fake "github.com/rackspace/gophercloud/testhelper/client"
+)
+
+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", fake.TokenID)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+
+ fmt.Fprintf(w, `
+{
+ "versions": [
+ {
+ "status": "CURRENT",
+ "id": "v1.0",
+ "links": [
+ {
+ "href": "http://23.253.228.211:8000/v1",
+ "rel": "self"
+ }
+ ]
+ }
+ ]
+}`)
+ })
+
+ count := 0
+
+ ListVersions(fake.ServiceClient()).EachPage(func(page pagination.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: "v1.0",
+ Links: []Link{
+ Link{
+ HRef: "http://23.253.228.211:8000/v1",
+ Rel: "self",
+ },
+ },
+ },
+ }
+
+ th.AssertDeepEquals(t, expected, actual)
+
+ return true, nil
+ })
+
+ if count != 1 {
+ t.Errorf("Expected 1 page, got %d", count)
+ }
+}
+
+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
+ })
+}
diff --git a/openstack/orchestration/v1/apiversions/results.go b/openstack/orchestration/v1/apiversions/results.go
new file mode 100644
index 0000000..40b26ae
--- /dev/null
+++ b/openstack/orchestration/v1/apiversions/results.go
@@ -0,0 +1,47 @@
+package apiversions
+
+import (
+ "github.com/mitchellh/mapstructure"
+ "github.com/rackspace/gophercloud/pagination"
+)
+
+// Link represents the base URL for a particular version.
+type Link struct {
+ HRef string `mapstructure:"href"`
+ Rel string `mapstructure:"rel"`
+}
+
+// APIVersion represents an API version for Neutron. It contains the status of
+// the API, and its unique ID.
+type APIVersion struct {
+ Status string `mapstructure:"status"`
+ ID string `mapstructure:"id"`
+ Links []Link `mapstructure:"links"`
+}
+
+// APIVersionPage is the page returned by a pager when traversing over a
+// collection of API versions.
+type APIVersionPage struct {
+ pagination.SinglePageBase
+}
+
+// IsEmpty checks whether an APIVersionPage struct is empty.
+func (r APIVersionPage) IsEmpty() (bool, error) {
+ is, err := ExtractAPIVersions(r)
+ if err != nil {
+ return true, err
+ }
+ return len(is) == 0, nil
+}
+
+// ExtractAPIVersions takes a collection page, extracts all of the elements,
+// and returns them a slice of APIVersion structs. It is effectively a cast.
+func ExtractAPIVersions(page pagination.Page) ([]APIVersion, error) {
+ var resp struct {
+ Versions []APIVersion `mapstructure:"versions"`
+ }
+
+ err := mapstructure.Decode(page.(APIVersionPage).Body, &resp)
+
+ return resp.Versions, err
+}
diff --git a/openstack/orchestration/v1/apiversions/urls.go b/openstack/orchestration/v1/apiversions/urls.go
new file mode 100644
index 0000000..55d6e0e
--- /dev/null
+++ b/openstack/orchestration/v1/apiversions/urls.go
@@ -0,0 +1,7 @@
+package apiversions
+
+import "github.com/rackspace/gophercloud"
+
+func apiVersionsURL(c *gophercloud.ServiceClient) string {
+ return c.Endpoint
+}