allow EndpointOpts to search catalog for Identity clients
diff --git a/openstack/client.go b/openstack/client.go
index 680a782..fdaee49 100644
--- a/openstack/client.go
+++ b/openstack/client.go
@@ -3,6 +3,7 @@
import (
"fmt"
"net/url"
+ "reflect"
"github.com/gophercloud/gophercloud"
tokens2 "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens"
@@ -215,37 +216,37 @@
// NewIdentityV2 creates a ServiceClient that may be used to interact with the v2 identity service.
func NewIdentityV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
- v2Endpoint := client.IdentityBase + "v2.0/"
- /*
+ endpoint := client.IdentityBase + "v2.0/"
+ var err error
+ if !reflect.DeepEqual(eo, gophercloud.EndpointOpts{}) {
eo.ApplyDefaults("identity")
- url, err := client.EndpointLocator(eo)
+ endpoint, err = client.EndpointLocator(eo)
if err != nil {
return nil, err
}
- */
+ }
return &gophercloud.ServiceClient{
ProviderClient: client,
- Endpoint: v2Endpoint,
- //Endpoint: url,
+ Endpoint: endpoint,
}, nil
}
// NewIdentityV3 creates a ServiceClient that may be used to access the v3 identity service.
func NewIdentityV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
- v3Endpoint := client.IdentityBase + "v3/"
- /*
+ endpoint := client.IdentityBase + "v3/"
+ var err error
+ if !reflect.DeepEqual(eo, gophercloud.EndpointOpts{}) {
eo.ApplyDefaults("identity")
- url, err := client.EndpointLocator(eo)
+ endpoint, err = client.EndpointLocator(eo)
if err != nil {
return nil, err
}
- */
+ }
return &gophercloud.ServiceClient{
ProviderClient: client,
- Endpoint: v3Endpoint,
- //Endpoint: url,
+ Endpoint: endpoint,
}, nil
}
diff --git a/openstack/identity/v3/tokens/results.go b/openstack/identity/v3/tokens/results.go
index 7dd2c0b..d6917f9 100644
--- a/openstack/identity/v3/tokens/results.go
+++ b/openstack/identity/v3/tokens/results.go
@@ -24,17 +24,13 @@
// Note: when looking for the desired service, try, whenever possible, to key off the type field.
// Otherwise, you'll tie the representation of the service to a specific provider.
type CatalogEntry struct {
-
// Service ID
ID string `json:"id"`
-
// Name will contain the provider-specified name for the service.
Name string `json:"name"`
-
// Type will contain a type string if OpenStack defines a type for the service.
// Otherwise, for provider-specific services, the provider may assign their own type strings.
Type string `json:"type"`
-
// Endpoints will let the caller iterate over all the different endpoints that may exist for
// the service.
Endpoints []Endpoint `json:"endpoints"`
@@ -60,7 +56,7 @@
func (r commonResult) ExtractToken() (*Token, error) {
var s struct {
Token struct {
- ExpiresAt string `json:"expires_at"`
+ ExpiresAt gophercloud.JSONRFC3339Milli `json:"expires_at"`
} `json:"token"`
}
@@ -74,8 +70,7 @@
return nil, err
}
- // Attempt to parse the timestamp.
- token.ExpiresAt, err = time.Parse(gophercloud.RFC3339Milli, s.Token.ExpiresAt)
+ token.ExpiresAt = time.Time(s.Token.ExpiresAt)
return &token, err
}
diff --git a/openstack/testing/client_test.go b/openstack/testing/client_test.go
index 37e63c1..93f4d7c 100644
--- a/openstack/testing/client_test.go
+++ b/openstack/testing/client_test.go
@@ -10,12 +10,12 @@
th "github.com/gophercloud/gophercloud/testhelper"
)
+const ID = "0123456789"
+
func TestAuthenticatedClientV3(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
- const ID = "0123456789"
-
th.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `
{
@@ -160,3 +160,132 @@
th.AssertNoErr(t, err)
th.CheckEquals(t, "01234567890", client.TokenID)
}
+
+func TestIdentityAdminV3Client(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, `
+ {
+ "versions": {
+ "values": [
+ {
+ "status": "stable",
+ "id": "v3.0",
+ "links": [
+ { "href": "%s", "rel": "self" }
+ ]
+ },
+ {
+ "status": "stable",
+ "id": "v2.0",
+ "links": [
+ { "href": "%s", "rel": "self" }
+ ]
+ }
+ ]
+ }
+ }
+ `, th.Endpoint()+"v3/", th.Endpoint()+"v2.0/")
+ })
+
+ th.Mux.HandleFunc("/v3/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Add("X-Subject-Token", ID)
+
+ w.WriteHeader(http.StatusCreated)
+ fmt.Fprintf(w, `
+ {
+ "token": {
+ "audit_ids": ["VcxU2JYqT8OzfUVvrjEITQ", "qNUTIJntTzO1-XUk5STybw"],
+ "catalog": [
+ {
+ "endpoints": [
+ {
+ "id": "39dc322ce86c4111b4f06c2eeae0841b",
+ "interface": "public",
+ "region": "RegionOne",
+ "url": "http://localhost:5000"
+ },
+ {
+ "id": "ec642f27474842e78bf059f6c48f4e99",
+ "interface": "internal",
+ "region": "RegionOne",
+ "url": "http://localhost:5000"
+ },
+ {
+ "id": "c609fc430175452290b62a4242e8a7e8",
+ "interface": "admin",
+ "region": "RegionOne",
+ "url": "http://localhost:35357"
+ }
+ ],
+ "id": "4363ae44bdf34a3981fde3b823cb9aa2",
+ "type": "identity",
+ "name": "keystone"
+ }
+ ],
+ "expires_at": "2013-02-27T18:30:59.999999Z",
+ "is_domain": false,
+ "issued_at": "2013-02-27T16:30:59.999999Z",
+ "methods": [
+ "password"
+ ],
+ "project": {
+ "domain": {
+ "id": "1789d1",
+ "name": "example.com"
+ },
+ "id": "263fd9",
+ "name": "project-x"
+ },
+ "roles": [
+ {
+ "id": "76e72a",
+ "name": "admin"
+ },
+ {
+ "id": "f4f392",
+ "name": "member"
+ }
+ ],
+ "service_providers": [
+ {
+ "auth_url":"https://example.com:5000/v3/OS-FEDERATION/identity_providers/acme/protocols/saml2/auth",
+ "id": "sp1",
+ "sp_url": "https://example.com:5000/Shibboleth.sso/SAML2/ECP"
+ },
+ {
+ "auth_url":"https://other.example.com:5000/v3/OS-FEDERATION/identity_providers/acme/protocols/saml2/auth",
+ "id": "sp2",
+ "sp_url": "https://other.example.com:5000/Shibboleth.sso/SAML2/ECP"
+ }
+ ],
+ "user": {
+ "domain": {
+ "id": "1789d1",
+ "name": "example.com"
+ },
+ "id": "0ca8f6",
+ "name": "Joe",
+ "password_expires_at": "2016-11-06T15:32:17.000000"
+ }
+ }
+}
+ `)
+ })
+
+ options := gophercloud.AuthOptions{
+ Username: "me",
+ Password: "secret",
+ DomainID: "12345",
+ IdentityEndpoint: th.Endpoint(),
+ }
+ pc, err := openstack.AuthenticatedClient(options)
+ th.AssertNoErr(t, err)
+ sc, err := openstack.NewIdentityV3(pc, gophercloud.EndpointOpts{
+ Availability: gophercloud.AvailabilityAdmin,
+ })
+ th.AssertNoErr(t, err)
+ th.CheckEquals(t, "http://localhost:35357/", sc.Endpoint)
+}