Apply the OptsBuilder interface to tokens.Create()
diff --git a/openstack/client.go b/openstack/client.go
index d7bf646..bd82690 100644
--- a/openstack/client.go
+++ b/openstack/client.go
@@ -95,7 +95,7 @@
v2Client.Endpoint = endpoint
}
- result := tokens2.Create(v2Client, options)
+ result := tokens2.Create(v2Client, tokens2.AuthOptions{AuthOptions: options})
token, err := result.ExtractToken()
if err != nil {
diff --git a/openstack/identity/v2/tokens/requests.go b/openstack/identity/v2/tokens/requests.go
index 346a149..96c28cf 100644
--- a/openstack/identity/v2/tokens/requests.go
+++ b/openstack/identity/v2/tokens/requests.go
@@ -5,53 +5,72 @@
"github.com/rackspace/gophercloud"
)
-// Create authenticates to the identity service and attempts to acquire a Token.
-// If successful, the CreateResult
-// Generally, rather than interact with this call directly, end users should call openstack.AuthenticatedClient(),
-// which abstracts all of the gory details about navigating service catalogs and such.
-func Create(client *gophercloud.ServiceClient, auth gophercloud.AuthOptions) CreateResult {
- type passwordCredentials struct {
- Username string `json:"username"`
- Password string `json:"password"`
- }
+// AuthOptionsBuilder describes any argument that may be passed to the Create call.
+type AuthOptionsBuilder interface {
- var request struct {
- Auth struct {
- PasswordCredentials *passwordCredentials `json:"passwordCredentials"`
- TenantID string `json:"tenantId,omitempty"`
- TenantName string `json:"tenantName,omitempty"`
- } `json:"auth"`
- }
+ // ToTokenCreateMap assembles the Create request body, returning an error if parameters are
+ // missing or inconsistent.
+ ToTokenCreateMap() (map[string]interface{}, error)
+}
+// AuthOptions wraps a gophercloud AuthOptions in order to adhere to the AuthOptionsBuilder
+// interface.
+type AuthOptions struct {
+ gophercloud.AuthOptions
+}
+
+// ToTokenCreateMap converts AuthOptions into nested maps that can be serialized into a JSON
+// request.
+func (auth AuthOptions) ToTokenCreateMap() (map[string]interface{}, error) {
// Error out if an unsupported auth option is present.
if auth.UserID != "" {
- return createErr(ErrUserIDProvided)
+ return nil, ErrUserIDProvided
}
if auth.APIKey != "" {
- return createErr(ErrAPIKeyProvided)
+ return nil, ErrAPIKeyProvided
}
if auth.DomainID != "" {
- return createErr(ErrDomainIDProvided)
+ return nil, ErrDomainIDProvided
}
if auth.DomainName != "" {
- return createErr(ErrDomainNameProvided)
+ return nil, ErrDomainNameProvided
}
// Username and Password are always required.
if auth.Username == "" {
- return createErr(ErrUsernameRequired)
+ return nil, ErrUsernameRequired
}
if auth.Password == "" {
- return createErr(ErrPasswordRequired)
+ return nil, ErrPasswordRequired
}
- // Populate the request.
- request.Auth.PasswordCredentials = &passwordCredentials{
- Username: auth.Username,
- Password: auth.Password,
+ // Populate the request map.
+ authMap := make(map[string]interface{})
+
+ authMap["passwordCredentials"] = map[string]interface{}{
+ "username": auth.Username,
+ "password": auth.Password,
}
- request.Auth.TenantID = auth.TenantID
- request.Auth.TenantName = auth.TenantName
+
+ if auth.TenantID != "" {
+ authMap["tenantId"] = auth.TenantID
+ }
+ if auth.TenantName != "" {
+ authMap["tenantName"] = auth.TenantName
+ }
+
+ return map[string]interface{}{"auth": authMap}, nil
+}
+
+// Create authenticates to the identity service and attempts to acquire a Token.
+// If successful, the CreateResult
+// Generally, rather than interact with this call directly, end users should call openstack.AuthenticatedClient(),
+// which abstracts all of the gory details about navigating service catalogs and such.
+func Create(client *gophercloud.ServiceClient, auth AuthOptionsBuilder) CreateResult {
+ request, err := auth.ToTokenCreateMap()
+ if err != nil {
+ return CreateResult{gophercloud.CommonResult{Err: err}}
+ }
var result CreateResult
_, result.Err = perigee.Request("POST", CreateURL(client), perigee.Options{
diff --git a/openstack/identity/v2/tokens/requests_test.go b/openstack/identity/v2/tokens/requests_test.go
index 3b8e643..b6476df 100644
--- a/openstack/identity/v2/tokens/requests_test.go
+++ b/openstack/identity/v2/tokens/requests_test.go
@@ -51,7 +51,7 @@
},
}
-func tokenPost(t *testing.T, options gophercloud.AuthOptions, requestJSON string) CreateResult {
+func tokenPost(t *testing.T, options AuthOptions, requestJSON string) CreateResult {
th.SetupHTTP()
defer th.TeardownHTTP()
@@ -112,7 +112,7 @@
return Create(&client, options)
}
-func tokenPostErr(t *testing.T, options gophercloud.AuthOptions, expectedErr error) {
+func tokenPostErr(t *testing.T, options AuthOptions, expectedErr error) {
th.SetupHTTP()
defer th.TeardownHTTP()
@@ -142,9 +142,11 @@
}
func TestCreateWithPassword(t *testing.T) {
- options := gophercloud.AuthOptions{
- Username: "me",
- Password: "swordfish",
+ options := AuthOptions{
+ gophercloud.AuthOptions{
+ Username: "me",
+ Password: "swordfish",
+ },
}
isSuccessful(t, tokenPost(t, options, `
@@ -160,10 +162,12 @@
}
func TestCreateTokenWithTenantID(t *testing.T) {
- options := gophercloud.AuthOptions{
- Username: "me",
- Password: "opensesame",
- TenantID: "fc394f2ab2df4114bde39905f800dc57",
+ options := AuthOptions{
+ gophercloud.AuthOptions{
+ Username: "me",
+ Password: "opensesame",
+ TenantID: "fc394f2ab2df4114bde39905f800dc57",
+ },
}
isSuccessful(t, tokenPost(t, options, `
@@ -180,10 +184,12 @@
}
func TestCreateTokenWithTenantName(t *testing.T) {
- options := gophercloud.AuthOptions{
- Username: "me",
- Password: "opensesame",
- TenantName: "demo",
+ options := AuthOptions{
+ gophercloud.AuthOptions{
+ Username: "me",
+ Password: "opensesame",
+ TenantName: "demo",
+ },
}
isSuccessful(t, tokenPost(t, options, `
@@ -200,51 +206,63 @@
}
func TestProhibitUserID(t *testing.T) {
- options := gophercloud.AuthOptions{
- Username: "me",
- UserID: "1234",
- Password: "thing",
+ options := AuthOptions{
+ gophercloud.AuthOptions{
+ Username: "me",
+ UserID: "1234",
+ Password: "thing",
+ },
}
tokenPostErr(t, options, ErrUserIDProvided)
}
func TestProhibitAPIKey(t *testing.T) {
- options := gophercloud.AuthOptions{
- Username: "me",
- Password: "thing",
- APIKey: "123412341234",
+ options := AuthOptions{
+ gophercloud.AuthOptions{
+ Username: "me",
+ Password: "thing",
+ APIKey: "123412341234",
+ },
}
tokenPostErr(t, options, ErrAPIKeyProvided)
}
func TestProhibitDomainID(t *testing.T) {
- options := gophercloud.AuthOptions{
- Username: "me",
- Password: "thing",
- DomainID: "1234",
+ options := AuthOptions{
+ gophercloud.AuthOptions{
+ Username: "me",
+ Password: "thing",
+ DomainID: "1234",
+ },
}
tokenPostErr(t, options, ErrDomainIDProvided)
}
func TestProhibitDomainName(t *testing.T) {
- options := gophercloud.AuthOptions{
- Username: "me",
- Password: "thing",
- DomainName: "wat",
+ options := AuthOptions{
+ gophercloud.AuthOptions{
+ Username: "me",
+ Password: "thing",
+ DomainName: "wat",
+ },
}
tokenPostErr(t, options, ErrDomainNameProvided)
}
func TestRequireUsername(t *testing.T) {
- options := gophercloud.AuthOptions{
- Password: "thing",
+ options := AuthOptions{
+ gophercloud.AuthOptions{
+ Password: "thing",
+ },
}
tokenPostErr(t, options, ErrUsernameRequired)
}
func TestRequirePassword(t *testing.T) {
- options := gophercloud.AuthOptions{
- Username: "me",
+ options := AuthOptions{
+ gophercloud.AuthOptions{
+ Username: "me",
+ },
}
tokenPostErr(t, options, ErrPasswordRequired)
}