dsl struct tags; wip
diff --git a/openstack/identity/v3/endpoints/errors.go b/openstack/identity/v3/endpoints/errors.go
deleted file mode 100644
index 854957f..0000000
--- a/openstack/identity/v3/endpoints/errors.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package endpoints
-
-import "fmt"
-
-func requiredAttribute(attribute string) error {
- return fmt.Errorf("You must specify %s for this endpoint.", attribute)
-}
-
-var (
- // ErrAvailabilityRequired is reported if an Endpoint is created without an Availability.
- ErrAvailabilityRequired = requiredAttribute("an availability")
-
- // ErrNameRequired is reported if an Endpoint is created without a Name.
- ErrNameRequired = requiredAttribute("a name")
-
- // ErrURLRequired is reported if an Endpoint is created without a URL.
- ErrURLRequired = requiredAttribute("a URL")
-
- // ErrServiceIDRequired is reported if an Endpoint is created without a ServiceID.
- ErrServiceIDRequired = requiredAttribute("a serviceID")
-)
diff --git a/openstack/identity/v3/endpoints/requests.go b/openstack/identity/v3/endpoints/requests.go
index c9b8cf5..7165fb4 100644
--- a/openstack/identity/v3/endpoints/requests.go
+++ b/openstack/identity/v3/endpoints/requests.go
@@ -5,59 +5,38 @@
"github.com/gophercloud/gophercloud/pagination"
)
-// EndpointOpts contains the subset of Endpoint attributes that should be used to create or update an Endpoint.
-type EndpointOpts struct {
- Availability gophercloud.Availability
- Name string
- Region string
- URL string
- ServiceID string
+type CreateOptsBuilder interface {
+ ToEndpointCreateMap() (map[string]interface{}, error)
+}
+
+// CreateOpts contains the subset of Endpoint attributes that should be used to create an Endpoint.
+type CreateOpts struct {
+ Availability gophercloud.Availability `json:"interface" required:"true"`
+ Name string `json:"name" required:"true"`
+ Region string `json:"region,omitempty"`
+ URL string `json:"url" required:"true"`
+ ServiceID string `json:"service_id" required:"true"`
+}
+
+func (opts CreateOpts) ToEndpointCreateMap() (map[string]interface{}, error) {
+ return gophercloud.BuildRequestBody(opts, "endpoint")
}
// Create inserts a new Endpoint into the service catalog.
// Within EndpointOpts, Region may be omitted by being left as "", but all other fields are required.
-func Create(client *gophercloud.ServiceClient, opts EndpointOpts) CreateResult {
- // Redefined so that Region can be re-typed as a *string, which can be omitted from the JSON output.
- type endpoint struct {
- Interface string `json:"interface"`
- Name string `json:"name"`
- Region *string `json:"region,omitempty"`
- URL string `json:"url"`
- ServiceID string `json:"service_id"`
+func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
+ var r CreateResult
+ b, err := opts.ToEndpointCreateMap()
+ if err != nil {
+ r.Err = err
+ return r
}
+ _, r.Err = client.Post(listURL(client), &b, &r.Body, nil)
+ return r
+}
- type request struct {
- Endpoint endpoint `json:"endpoint"`
- }
-
- // Ensure that EndpointOpts is fully populated.
- if opts.Availability == "" {
- return createErr(ErrAvailabilityRequired)
- }
- if opts.Name == "" {
- return createErr(ErrNameRequired)
- }
- if opts.URL == "" {
- return createErr(ErrURLRequired)
- }
- if opts.ServiceID == "" {
- return createErr(ErrServiceIDRequired)
- }
-
- // Populate the request body.
- reqBody := request{
- Endpoint: endpoint{
- Interface: string(opts.Availability),
- Name: opts.Name,
- URL: opts.URL,
- ServiceID: opts.ServiceID,
- },
- }
- reqBody.Endpoint.Region = gophercloud.MaybeString(opts.Region)
-
- var result CreateResult
- _, result.Err = client.Post(listURL(client), reqBody, &result.Body, nil)
- return result
+type ListOptsBuilder interface {
+ ToEndpointListParams() (string, error)
}
// ListOpts allows finer control over the endpoints returned by a List call.
@@ -69,55 +48,58 @@
PerPage int `q:"per_page"`
}
-// List enumerates endpoints in a paginated collection, optionally filtered by ListOpts criteria.
-func List(client *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
- u := listURL(client)
+func (opts ListOpts) ToEndpointListParams() (string, error) {
q, err := gophercloud.BuildQueryString(opts)
- if err != nil {
- return pagination.Pager{Err: err}
- }
- u += q.String()
- createPage := func(r pagination.PageResult) pagination.Page {
- return EndpointPage{pagination.LinkedPageBase{PageResult: r}}
- }
+ return q.String(), err
+}
- return pagination.NewPager(client, u, createPage)
+// List enumerates endpoints in a paginated collection, optionally filtered by ListOpts criteria.
+func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
+ u := listURL(client)
+ if opts != nil {
+ q, err := gophercloud.BuildQueryString(opts)
+ if err != nil {
+ return pagination.Pager{Err: err}
+ }
+ u += q.String()
+ }
+ return pagination.NewPager(client, u, func(r pagination.PageResult) pagination.Page {
+ return EndpointPage{pagination.LinkedPageBase{PageResult: r}}
+ })
+}
+
+type UpdateOptsBuilder interface {
+ ToEndpointUpdateMap() (map[string]interface{}, error)
+}
+
+// UpdateOpts contains the subset of Endpoint attributes that should be used to update an Endpoint.
+type UpdateOpts struct {
+ Availability gophercloud.Availability `json:"interface,omitempty"`
+ Name string `json:"name,omitempty"`
+ Region string `json:"region,omitempty"`
+ URL string `json:"url,omitempty"`
+ ServiceID string `json:"service_id,omitempty"`
+}
+
+func (opts UpdateOpts) ToEndpointUpdateMap() (map[string]interface{}, error) {
+ return gophercloud.BuildRequestBody(opts, "endpoint")
}
// Update changes an existing endpoint with new data.
-// All fields are optional in the provided EndpointOpts.
-func Update(client *gophercloud.ServiceClient, endpointID string, opts EndpointOpts) UpdateResult {
- type endpoint struct {
- Interface *string `json:"interface,omitempty"`
- Name *string `json:"name,omitempty"`
- Region *string `json:"region,omitempty"`
- URL *string `json:"url,omitempty"`
- ServiceID *string `json:"service_id,omitempty"`
+func Update(client *gophercloud.ServiceClient, endpointID string, opts UpdateOptsBuilder) UpdateResult {
+ var r UpdateResult
+ b, err := opts.ToEndpointUpdateMap()
+ if err != nil {
+ r.Err = err
+ return r
}
-
- type request struct {
- Endpoint endpoint `json:"endpoint"`
- }
-
- reqBody := request{Endpoint: endpoint{}}
- reqBody.Endpoint.Interface = gophercloud.MaybeString(string(opts.Availability))
- reqBody.Endpoint.Name = gophercloud.MaybeString(opts.Name)
- reqBody.Endpoint.Region = gophercloud.MaybeString(opts.Region)
- reqBody.Endpoint.URL = gophercloud.MaybeString(opts.URL)
- reqBody.Endpoint.ServiceID = gophercloud.MaybeString(opts.ServiceID)
-
- var result UpdateResult
- _, result.Err = client.Request("PATCH", endpointURL(client, endpointID), &gophercloud.RequestOpts{
- JSONBody: &reqBody,
- JSONResponse: &result.Body,
- OkCodes: []int{200},
- })
- return result
+ _, r.Err = client.Patch(endpointURL(client, endpointID), &b, &r.Body, nil)
+ return r
}
// Delete removes an endpoint from the service catalog.
func Delete(client *gophercloud.ServiceClient, endpointID string) DeleteResult {
- var res DeleteResult
- _, res.Err = client.Delete(endpointURL(client, endpointID), nil)
- return res
+ var r DeleteResult
+ _, r.Err = client.Delete(endpointURL(client, endpointID), nil)
+ return r
}
diff --git a/openstack/identity/v3/endpoints/requests_test.go b/openstack/identity/v3/endpoints/requests_test.go
index ec17d17..14bbe6a 100644
--- a/openstack/identity/v3/endpoints/requests_test.go
+++ b/openstack/identity/v3/endpoints/requests_test.go
@@ -3,23 +3,22 @@
import (
"fmt"
"net/http"
- "reflect"
"testing"
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/pagination"
- "github.com/gophercloud/gophercloud/testhelper"
+ th "github.com/gophercloud/gophercloud/testhelper"
"github.com/gophercloud/gophercloud/testhelper/client"
)
func TestCreateSuccessful(t *testing.T) {
- testhelper.SetupHTTP()
- defer testhelper.TeardownHTTP()
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
- testhelper.Mux.HandleFunc("/endpoints", func(w http.ResponseWriter, r *http.Request) {
- testhelper.TestMethod(t, r, "POST")
- testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
- testhelper.TestJSONRequest(t, r, `
+ th.Mux.HandleFunc("/endpoints", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "POST")
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+ th.TestJSONRequest(t, r, `
{
"endpoint": {
"interface": "public",
@@ -49,16 +48,14 @@
`)
})
- actual, err := Create(client.ServiceClient(), EndpointOpts{
+ actual, err := Create(client.ServiceClient(), CreateOpts{
Availability: gophercloud.AvailabilityPublic,
Name: "the-endiest-of-points",
Region: "underground",
URL: "https://1.2.3.4:9000/",
ServiceID: "asdfasdfasdfasdf",
}).Extract()
- if err != nil {
- t.Fatalf("Unable to create an endpoint: %v", err)
- }
+ th.AssertNoErr(t, err)
expected := &Endpoint{
ID: "12",
@@ -69,18 +66,16 @@
URL: "https://1.2.3.4:9000/",
}
- if !reflect.DeepEqual(actual, expected) {
- t.Errorf("Expected %#v, was %#v", expected, actual)
- }
+ th.AssertDeepEquals(t, expected, actual)
}
func TestListEndpoints(t *testing.T) {
- testhelper.SetupHTTP()
- defer testhelper.TeardownHTTP()
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
- testhelper.Mux.HandleFunc("/endpoints", func(w http.ResponseWriter, r *http.Request) {
- testhelper.TestMethod(t, r, "GET")
- testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+ th.Mux.HandleFunc("/endpoints", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
w.Header().Add("Content-Type", "application/json")
fmt.Fprintf(w, `
@@ -144,26 +139,20 @@
URL: "https://1.2.3.4:9001/",
},
}
-
- if !reflect.DeepEqual(expected, actual) {
- t.Errorf("Expected %#v, got %#v", expected, actual)
- }
-
+ th.AssertDeepEquals(t, expected, actual)
return true, nil
})
- if count != 1 {
- t.Errorf("Expected 1 page, got %d", count)
- }
+ th.AssertEquals(t, 1, count)
}
func TestUpdateEndpoint(t *testing.T) {
- testhelper.SetupHTTP()
- defer testhelper.TeardownHTTP()
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
- testhelper.Mux.HandleFunc("/endpoints/12", func(w http.ResponseWriter, r *http.Request) {
- testhelper.TestMethod(t, r, "PATCH")
- testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
- testhelper.TestJSONRequest(t, r, `
+ th.Mux.HandleFunc("/endpoints/12", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "PATCH")
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+ th.TestJSONRequest(t, r, `
{
"endpoint": {
"name": "renamed",
@@ -189,7 +178,7 @@
`)
})
- actual, err := Update(client.ServiceClient(), "12", EndpointOpts{
+ actual, err := Update(client.ServiceClient(), "12", UpdateOpts{
Name: "renamed",
Region: "somewhere-else",
}).Extract()
@@ -205,22 +194,20 @@
ServiceID: "asdfasdfasdfasdf",
URL: "https://1.2.3.4:9000/",
}
- if !reflect.DeepEqual(expected, actual) {
- t.Errorf("Expected %#v, was %#v", expected, actual)
- }
+ th.AssertDeepEquals(t, expected, actual)
}
func TestDeleteEndpoint(t *testing.T) {
- testhelper.SetupHTTP()
- defer testhelper.TeardownHTTP()
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
- testhelper.Mux.HandleFunc("/endpoints/34", func(w http.ResponseWriter, r *http.Request) {
- testhelper.TestMethod(t, r, "DELETE")
- testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+ th.Mux.HandleFunc("/endpoints/34", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "DELETE")
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
w.WriteHeader(http.StatusNoContent)
})
res := Delete(client.ServiceClient(), "34")
- testhelper.AssertNoErr(t, res.Err)
+ th.AssertNoErr(t, res.Err)
}