Ookay, last reshuffle.
* openstack.NewClient() normalizes the identity endpoint with a trailing slash, and sets base and endpoint.
* utils.ChooseVersion() checks suffixes first to short-circuit actual version calls.
* gophercloud.ProviderClient distinguishes between the root of all identity services (IdentityBase)
and the endpoint of the requested auth service (IdentityEndpoint).
diff --git a/openstack/utils/choose_version.go b/openstack/utils/choose_version.go
index 402a870..753f8f8 100644
--- a/openstack/utils/choose_version.go
+++ b/openstack/utils/choose_version.go
@@ -2,7 +2,6 @@
import (
"fmt"
- "net/url"
"strings"
"github.com/racker/perigee"
@@ -11,6 +10,7 @@
// Version is a supported API version, corresponding to a vN package within the appropriate service.
type Version struct {
ID string
+ Suffix string
Priority int
}
@@ -23,7 +23,7 @@
// ChooseVersion queries the base endpoint of a API to choose the most recent non-experimental alternative from a service's
// published versions.
// It returns the highest-Priority Version among the alternatives that are provided, as well as its corresponding endpoint.
-func ChooseVersion(identityEndpoint string, recognized []*Version) (*Version, string, error) {
+func ChooseVersion(identityBase string, identityEndpoint string, recognized []*Version) (*Version, string, error) {
type linkResp struct {
Href string `json:"href"`
Rel string `json:"rel"`
@@ -43,16 +43,23 @@
Versions versionsResp `json:"versions"`
}
- // Normalize the identity endpoint that's provided by trimming any path, query or fragment from the URL.
- u, err := url.Parse(identityEndpoint)
- if err != nil {
- return nil, "", err
+ normalize := func(endpoint string) string {
+ if !strings.HasSuffix(endpoint, "/") {
+ return endpoint + "/"
+ }
+ return endpoint
}
- u.Path, u.RawQuery, u.Fragment = "", "", ""
- normalized := u.String()
+ identityEndpoint = normalize(identityEndpoint)
+
+ // If a full endpoint is specified, check version suffixes for a match first.
+ for _, v := range recognized {
+ if strings.HasSuffix(identityEndpoint, v.Suffix) {
+ return v, identityEndpoint, nil
+ }
+ }
var resp response
- _, err = perigee.Request("GET", normalized, perigee.Options{
+ _, err := perigee.Request("GET", identityBase, perigee.Options{
Results: &resp,
OkCodes: []int{200, 300},
})
@@ -69,14 +76,6 @@
var highest *Version
var endpoint string
- normalize := func(endpoint string) string {
- if !strings.HasSuffix(endpoint, "/") {
- return endpoint + "/"
- }
- return endpoint
- }
- normalizedGiven := normalize(identityEndpoint)
-
for _, value := range resp.Versions.Values {
href := ""
for _, link := range value.Links {
@@ -87,9 +86,9 @@
if matching, ok := byID[value.ID]; ok {
// Prefer a version that exactly matches the provided endpoint.
- if href == normalizedGiven {
+ if href == identityEndpoint {
if href == "" {
- return nil, "", fmt.Errorf("Endpoint missing in version %s response from %s", value.ID, normalized)
+ return nil, "", fmt.Errorf("Endpoint missing in version %s response from %s", value.ID, identityBase)
}
return matching, href, nil
}
@@ -105,10 +104,10 @@
}
if highest == nil {
- return nil, "", fmt.Errorf("No supported version available from endpoint %s", normalized)
+ return nil, "", fmt.Errorf("No supported version available from endpoint %s", identityBase)
}
if endpoint == "" {
- return nil, "", fmt.Errorf("Endpoint missing in version %s response from %s", highest.ID, normalized)
+ return nil, "", fmt.Errorf("Endpoint missing in version %s response from %s", highest.ID, identityBase)
}
return highest, endpoint, nil
diff --git a/openstack/utils/choose_version_test.go b/openstack/utils/choose_version_test.go
index b724ee8..9552696 100644
--- a/openstack/utils/choose_version_test.go
+++ b/openstack/utils/choose_version_test.go
@@ -40,10 +40,10 @@
defer testhelper.TeardownHTTP()
setupVersionHandler()
- v2 := &Version{ID: "v2.0", Priority: 2}
- v3 := &Version{ID: "v3.0", Priority: 3}
+ v2 := &Version{ID: "v2.0", Priority: 2, Suffix: "blarg"}
+ v3 := &Version{ID: "v3.0", Priority: 3, Suffix: "hargl"}
- v, endpoint, err := ChooseVersion(testhelper.Endpoint(), []*Version{v2, v3})
+ v, endpoint, err := ChooseVersion(testhelper.Endpoint(), "", []*Version{v2, v3})
if err != nil {
t.Fatalf("Unexpected error from ChooseVersion: %v", err)
@@ -64,10 +64,32 @@
defer testhelper.TeardownHTTP()
setupVersionHandler()
- v2 := &Version{ID: "v2.0", Priority: 2}
- v3 := &Version{ID: "v3.0", Priority: 3}
+ v2 := &Version{ID: "v2.0", Priority: 2, Suffix: "nope"}
+ v3 := &Version{ID: "v3.0", Priority: 3, Suffix: "northis"}
- v, endpoint, err := ChooseVersion(testhelper.Endpoint()+"v2.0/", []*Version{v2, v3})
+ v, endpoint, err := ChooseVersion(testhelper.Endpoint(), testhelper.Endpoint()+"v2.0/", []*Version{v2, v3})
+ if err != nil {
+ t.Fatalf("Unexpected error from ChooseVersion: %v", err)
+ }
+
+ if v != v2 {
+ t.Errorf("Expected %#v to win, but %#v did instead", v2, v)
+ }
+
+ expected := testhelper.Endpoint() + "v2.0/"
+ if endpoint != expected {
+ t.Errorf("Expected endpoint [%s], but was [%s] instead", expected, endpoint)
+ }
+}
+
+func TestChooseVersionFromSuffix(t *testing.T) {
+ testhelper.SetupHTTP()
+ defer testhelper.TeardownHTTP()
+
+ v2 := &Version{ID: "v2.0", Priority: 2, Suffix: "/v2.0/"}
+ v3 := &Version{ID: "v3.0", Priority: 3, Suffix: "/v3.0/"}
+
+ v, endpoint, err := ChooseVersion(testhelper.Endpoint(), testhelper.Endpoint()+"v2.0/", []*Version{v2, v3})
if err != nil {
t.Fatalf("Unexpected error from ChooseVersion: %v", err)
}
diff --git a/openstack/utils/client.go b/openstack/utils/client.go
index 7e3aa12..f8a6c57 100644
--- a/openstack/utils/client.go
+++ b/openstack/utils/client.go
@@ -47,7 +47,7 @@
Options: ao,
}
- c := &gophercloud.ServiceClient{Endpoint: ao.IdentityEndpoint}
+ c := &gophercloud.ServiceClient{Endpoint: ao.IdentityEndpoint + "/"}
ar, err := identity.Authenticate(c, ao)
if err != nil {
return client, err