List the services available from an endpoint.
diff --git a/openstack/identity/v3/services/requests.go b/openstack/identity/v3/services/requests.go
index e9384e1..899b91c 100644
--- a/openstack/identity/v3/services/requests.go
+++ b/openstack/identity/v3/services/requests.go
@@ -1,8 +1,11 @@
package services
import (
+ "strconv"
+
"github.com/racker/perigee"
"github.com/rackspace/gophercloud"
+ "github.com/rackspace/gophercloud/openstack/utils"
)
// Create adds a new service of the requested type to the catalog.
@@ -30,3 +33,37 @@
return &resp.Service, nil
}
+
+// ListOpts allows you to query the List method.
+type ListOpts struct {
+ ServiceType string
+ PerPage int
+ Page int
+}
+
+// List enumerates the services available to a specific user.
+func List(client *gophercloud.ServiceClient, opts ListOpts) (*ServiceListResult, error) {
+ q := make(map[string]string)
+ if opts.ServiceType != "" {
+ q["type"] = opts.ServiceType
+ }
+ if opts.Page != 0 {
+ q["page"] = strconv.Itoa(opts.Page)
+ }
+ if opts.PerPage != 0 {
+ q["perPage"] = strconv.Itoa(opts.PerPage)
+ }
+ u := getListURL(client) + utils.BuildQuery(q)
+
+ var resp ServiceListResult
+ _, err := perigee.Request("GET", u, perigee.Options{
+ MoreHeaders: client.Provider.AuthenticatedHeaders(),
+ Results: &resp,
+ OkCodes: []int{200},
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return &resp, nil
+}
diff --git a/openstack/identity/v3/services/requests_test.go b/openstack/identity/v3/services/requests_test.go
index 6592fc6..cd96daf 100644
--- a/openstack/identity/v3/services/requests_test.go
+++ b/openstack/identity/v3/services/requests_test.go
@@ -55,3 +55,65 @@
t.Errorf("Service type was unexpected [%s]", result.Type)
}
}
+
+func TestListSinglePage(t *testing.T) {
+ testhelper.SetupHTTP()
+ defer testhelper.TeardownHTTP()
+
+ testhelper.Mux.HandleFunc("/services", func(w http.ResponseWriter, r *http.Request) {
+ testhelper.TestMethod(t, r, "GET")
+ testhelper.TestHeader(t, r, "X-Auth-Token", "1111")
+
+ w.Header().Add("Content-Type", "application/json")
+ fmt.Fprintf(w, `
+ {
+ "links": {
+ "next": null,
+ "previous": null
+ },
+ "services": [
+ {
+ "description": "Service One",
+ "id": "1234",
+ "name": "service-one",
+ "type": "identity"
+ },
+ {
+ "description": "Service Two",
+ "id": "9876",
+ "name": "service-two",
+ "type": "compute"
+ }
+ ]
+ }
+ `)
+ })
+
+ client := gophercloud.ServiceClient{
+ Provider: &gophercloud.ProviderClient{
+ TokenID: "1111",
+ },
+ Endpoint: testhelper.Endpoint(),
+ }
+
+ result, err := List(&client, ListOpts{})
+ if err != nil {
+ t.Fatalf("Error listing services: %v", err)
+ }
+
+ if result.Pagination.Next != nil {
+ t.Errorf("Unexpected next link: %s", result.Pagination.Next)
+ }
+ if result.Pagination.Previous != nil {
+ t.Errorf("Unexpected previous link: %s", result.Pagination.Previous)
+ }
+ if len(result.Services) != 2 {
+ t.Errorf("Unexpected number of services: %s", len(result.Services))
+ }
+ if result.Services[0].ID != "1234" {
+ t.Errorf("Unexpected service: %#v", result.Services[0])
+ }
+ if result.Services[0].ID == "9876" {
+ t.Errorf("Unexpected service: %#v", result.Services[1])
+ }
+}
diff --git a/openstack/identity/v3/services/results.go b/openstack/identity/v3/services/results.go
index baf8d6b..aba3aa1 100644
--- a/openstack/identity/v3/services/results.go
+++ b/openstack/identity/v3/services/results.go
@@ -1,5 +1,7 @@
package services
+import "github.com/rackspace/gophercloud"
+
// ServiceResult is the result of a list or information query.
type ServiceResult struct {
Description *string `json:"description,omitempty"`
@@ -7,3 +9,10 @@
Name string `json:"name"`
Type string `json:"type"`
}
+
+// ServiceListResult is a paged collection of Services.
+type ServiceListResult struct {
+ gophercloud.Pagination
+
+ Services []ServiceResult `json:"services"`
+}
diff --git a/openstack/utils/utils.go b/openstack/utils/utils.go
index f97f3d1..1d09d9e 100644
--- a/openstack/utils/utils.go
+++ b/openstack/utils/utils.go
@@ -60,6 +60,10 @@
// BuildQuery constructs the query section of a URI from a map.
func BuildQuery(params map[string]string) string {
+ if len(params) == 0 {
+ return ""
+ }
+
query := "?"
for k, v := range params {
query += k + "=" + v + "&"
diff --git a/pagination.go b/pagination.go
new file mode 100644
index 0000000..f100651
--- /dev/null
+++ b/pagination.go
@@ -0,0 +1,11 @@
+package gophercloud
+
+// Pagination stores information that's necessary to enumerate through pages of results.
+type Pagination struct {
+
+ // Next is the full URL to the next page of results, or nil if this is the last page.
+ Next *string `json:"next,omitempty"`
+
+ // Previous is the full URL to the previous page of results, or nil if this is the first page.s
+ Previous *string `json:"previous,omitempty"`
+}