Skip to content
This repository was archived by the owner on Aug 1, 2023. It is now read-only.

Commit 8ec9886

Browse files
authored
Merge pull request #582 from suonto/fix-identity-base
Fix openstack NewClient to not remove relative paths from IdentityBase
2 parents d47105c + e481b2e commit 8ec9886

File tree

3 files changed

+140
-10
lines changed

3 files changed

+140
-10
lines changed

openstack/client.go

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package openstack
33
import (
44
"fmt"
55
"net/url"
6+
"strconv"
67
"strings"
78

89
"github.com/rackspace/gophercloud"
@@ -25,18 +26,40 @@ func NewClient(endpoint string) (*gophercloud.ProviderClient, error) {
2526
if err != nil {
2627
return nil, err
2728
}
28-
hadPath := u.Path != ""
29-
u.Path, u.RawQuery, u.Fragment = "", "", ""
30-
base := u.String()
3129

32-
endpoint = gophercloud.NormalizeURL(endpoint)
33-
base = gophercloud.NormalizeURL(base)
30+
u.RawQuery, u.Fragment = "", ""
3431

35-
if hadPath {
36-
return &gophercloud.ProviderClient{
37-
IdentityBase: base,
38-
IdentityEndpoint: endpoint,
39-
}, nil
32+
// Base is url with path
33+
endpoint = gophercloud.NormalizeURL(endpoint)
34+
base := gophercloud.NormalizeURL(u.String())
35+
36+
path := u.Path
37+
if !strings.HasSuffix(path, "/") {
38+
path = path + "/"
39+
}
40+
41+
parts := strings.Split(path[0:len(path)-1], "/")
42+
for index,version := range(parts) {
43+
if 2 <= len(version) && len(version) <= 4 && strings.HasPrefix(version, "v") {
44+
_, err := strconv.ParseFloat(version[1:], 64)
45+
if err == nil {
46+
// post version suffixes in path are not supported
47+
// version must be on the last index
48+
if index < len(parts) - 1 {
49+
return nil, fmt.Errorf("Path suffixes (after version) are not supported.")
50+
}
51+
switch version {
52+
case "v2.0", "v3":
53+
// valid version found, strip from base
54+
return &gophercloud.ProviderClient{
55+
IdentityBase: base[0:len(base)-len(version)-1],
56+
IdentityEndpoint: endpoint,
57+
}, nil
58+
default:
59+
return nil, fmt.Errorf("Invalid identity endpoint version %v. Supported versions: v2.0, v3", version)
60+
}
61+
}
62+
}
4063
}
4164

4265
return &gophercloud.ProviderClient{

openstack/client_test.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,3 +159,95 @@ func TestAuthenticatedClientV2(t *testing.T) {
159159
th.AssertNoErr(t, err)
160160
th.CheckEquals(t, "01234567890", client.TokenID)
161161
}
162+
163+
func TestNewClient(t *testing.T) {
164+
client, err := NewClient("https://example.com")
165+
th.AssertNoErr(t, err)
166+
th.AssertEquals(t, "", client.IdentityEndpoint)
167+
th.AssertEquals(t, "https://example.com/", client.IdentityBase)
168+
169+
client, err = NewClient("https://example.com/")
170+
th.AssertNoErr(t, err)
171+
th.AssertEquals(t, "", client.IdentityEndpoint)
172+
th.AssertEquals(t, "https://example.com/", client.IdentityBase)
173+
174+
client, err = NewClient("https://example.com/v2.0")
175+
th.AssertNoErr(t, err)
176+
th.AssertEquals(t, "https://example.com/v2.0/", client.IdentityEndpoint)
177+
th.AssertEquals(t, "https://example.com/", client.IdentityBase)
178+
179+
client, err = NewClient("https://example.com/v2.0/")
180+
th.AssertNoErr(t, err)
181+
th.AssertEquals(t, "https://example.com/v2.0/", client.IdentityEndpoint)
182+
th.AssertEquals(t, "https://example.com/", client.IdentityBase)
183+
184+
client, err = NewClient("https://example.com/foo/bar")
185+
th.AssertNoErr(t, err)
186+
th.AssertEquals(t, "", client.IdentityEndpoint)
187+
th.AssertEquals(t, "https://example.com/foo/bar/", client.IdentityBase)
188+
189+
client, err = NewClient("https://example.com/foo/bar/")
190+
th.AssertNoErr(t, err)
191+
th.AssertEquals(t, "", client.IdentityEndpoint)
192+
th.AssertEquals(t, "https://example.com/foo/bar/", client.IdentityBase)
193+
194+
client, err = NewClient("https://example.com/foo/bar/v2.0")
195+
th.AssertNoErr(t, err)
196+
th.AssertEquals(t, "https://example.com/foo/bar/v2.0/", client.IdentityEndpoint)
197+
th.AssertEquals(t, "https://example.com/foo/bar/", client.IdentityBase)
198+
199+
client, err = NewClient("https://example.com/foo/bar/v2.0/")
200+
th.AssertNoErr(t, err)
201+
th.AssertEquals(t, "https://example.com/foo/bar/v2.0/", client.IdentityEndpoint)
202+
th.AssertEquals(t, "https://example.com/foo/bar/", client.IdentityBase)
203+
204+
client, err = NewClient("https://example.com/foo/bar/v3/")
205+
th.AssertNoErr(t, err)
206+
th.AssertEquals(t, "https://example.com/foo/bar/v3/", client.IdentityEndpoint)
207+
th.AssertEquals(t, "https://example.com/foo/bar/", client.IdentityBase)
208+
209+
client, err = NewClient("https://example.com/v3")
210+
th.AssertNoErr(t, err)
211+
th.AssertEquals(t, "https://example.com/v3/", client.IdentityEndpoint)
212+
th.AssertEquals(t, "https://example.com/", client.IdentityBase)
213+
214+
client, err = NewClient("https://example.com/v3/")
215+
th.AssertNoErr(t, err)
216+
th.AssertEquals(t, "https://example.com/v3/", client.IdentityEndpoint)
217+
th.AssertEquals(t, "https://example.com/", client.IdentityBase)
218+
219+
_, err = NewClient("https://example.com/v2.3/")
220+
th.AssertErr(t, err)
221+
expected := fmt.Errorf("Invalid identity endpoint version %v. Supported versions: v2.0, v3", "v2.3")
222+
th.AssertEquals(t, expected.Error(), err.Error())
223+
224+
_, err = NewClient("https://example.com/v2.0/foo")
225+
th.AssertErr(t, err)
226+
expected = fmt.Errorf("Path suffixes (after version) are not supported.")
227+
th.AssertEquals(t, expected.Error(), err.Error())
228+
229+
// Does not match regexp, include to base
230+
client, err = NewClient("https://example.com/v2a0/")
231+
th.AssertNoErr(t, err)
232+
th.AssertEquals(t, "", client.IdentityEndpoint)
233+
th.AssertEquals(t, "https://example.com/v2a0/", client.IdentityBase)
234+
235+
// Does not match regexp, include to base
236+
client, err = NewClient("https://example.com/v3api")
237+
th.AssertNoErr(t, err)
238+
th.AssertEquals(t, "", client.IdentityEndpoint)
239+
th.AssertEquals(t, "https://example.com/v3api/", client.IdentityBase)
240+
241+
// Matches regexp, invalid version v20.
242+
_, err = NewClient("https://example.com/v20./")
243+
th.AssertErr(t, err)
244+
expected = fmt.Errorf("Invalid identity endpoint version %v. Supported versions: v2.0, v3", "v20.")
245+
th.AssertEquals(t, expected.Error(), err.Error())
246+
247+
// domain contains version
248+
client, err = NewClient("https://v3.v2.0example.com/v3/")
249+
th.AssertNoErr(t, err)
250+
th.AssertEquals(t, "https://v3.v2.0example.com/v3/", client.IdentityEndpoint)
251+
th.AssertEquals(t, "https://v3.v2.0example.com/", client.IdentityBase)
252+
253+
}

testhelper/convenience.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,21 @@ func CheckEquals(t *testing.T, expected, actual interface{}) {
224224
}
225225
}
226226

227+
// AssertErr is a convenience function for checking that an error occurred
228+
func AssertErr(t *testing.T, e error) {
229+
if e == nil {
230+
logFatal(t, fmt.Sprintf("expected an error but none occurred"))
231+
}
232+
}
233+
234+
// CheckErr is a convenience function for checking that an error occurred,
235+
// except with a non-fatal error
236+
func CheckErr(t *testing.T, e error) {
237+
if e == nil {
238+
logError(t, fmt.Sprintf("expected an error but none occurred"))
239+
}
240+
}
241+
227242
// AssertDeepEquals - like Equals - performs a comparison - but on more complex
228243
// structures that requires deeper inspection
229244
func AssertDeepEquals(t *testing.T, expected, actual interface{}) {

0 commit comments

Comments
 (0)