Skip to content

Commit

Permalink
Identity V3: add Trust Delete function (#1644)
Browse files Browse the repository at this point in the history
* Identity V3: add Trust Create and Extract funcions

Implement Create and Extract functions for v3/extenstions/trusts package
with unit tests and docs.

This commit also adds Role struct to this package.

* Identity V3: add Trust Delete function

Implement Delete function for the v3/extensions/trusts package with
tests and docs.
  • Loading branch information
ozerovandrei committed Jul 16, 2019
1 parent 17584a2 commit 00c1d0b
Show file tree
Hide file tree
Showing 6 changed files with 268 additions and 1 deletion.
32 changes: 32 additions & 0 deletions openstack/identity/v3/extensions/trusts/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,37 @@ Example to Create a Token with Username, Password, and Trust ID
if err != nil {
panic(err)
}
Example to Create a Trust
expiresAt := time.Date(2019, 12, 1, 14, 0, 0, 999999999, time.UTC)
createOpts := trusts.CreateOpts{
ExpiresAt: &expiresAt,
Impersonation: true,
AllowRedelegation: true,
ProjectID: "9b71012f5a4a4aef9193f1995fe159b2",
Roles: []trusts.Role{
{
Name: "member",
},
},
TrusteeUserID: "ecb37e88cc86431c99d0332208cb6fbf",
TrustorUserID: "959ed913a32c4ec88c041c98e61cbbc3",
}
trust, err := trusts.Create(identityClient, createOpts).Extract()
if err != nil {
panic(err)
}
fmt.Printf("Trust: %+v\n", trust)
Example to Delete a Trust
trustID := "3422b7c113894f5d90665e1a79655e23"
err := trusts.Delete(identityClient, trustID).ExtractErr()
if err != nil {
panic(err)
}
*/
package trusts
80 changes: 79 additions & 1 deletion openstack/identity/v3/extensions/trusts/requests.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package trusts

import "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
import (
"time"

"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
)

// AuthOptsExt extends the base Identity v3 tokens AuthOpts with a TrustID.
type AuthOptsExt struct {
Expand Down Expand Up @@ -37,3 +42,76 @@ func (opts AuthOptsExt) ToTokenV3ScopeMap() (map[string]interface{}, error) {
func (opts AuthOptsExt) CanReauth() bool {
return opts.AuthOptionsBuilder.CanReauth()
}

// CreateOptsBuilder allows extensions to add additional parameters to
// the Create request.
type CreateOptsBuilder interface {
ToTrustCreateMap() (map[string]interface{}, error)
}

// CreateOpts provides options used to create a new trust.
type CreateOpts struct {
// Impersonation allows the trustee to impersonate the trustor.
Impersonation bool `json:"impersonation" required:"true"`

// TrusteeUserID is a user who is capable of consuming the trust.
TrusteeUserID string `json:"trustee_user_id" required:"true"`

// TrustorUserID is a user who created the trust.
TrustorUserID string `json:"trustor_user_id" required:"true"`

// AllowRedelegation enables redelegation of a trust.
AllowRedelegation bool `json:"allow_redelegation,omitempty"`

// ExpiresAt sets expiration time on trust.
ExpiresAt *time.Time `json:"-"`

// ProjectID identifies the project.
ProjectID string `json:"project_id,omitempty"`

// RedelegationCount specifies a depth of the redelegation chain.
RedelegationCount int `json:"redelegation_count,omitempty"`

// RemainingUses specifies how many times a trust can be used to get a token.
RemainingUses int `json:"remaining_uses,omitempty"`

// Roles specifies roles that need to be granted to trustee.
Roles []Role `json:"roles,omitempty"`
}

// ToTrustCreateMap formats a CreateOpts into a create request.
func (opts CreateOpts) ToTrustCreateMap() (map[string]interface{}, error) {
parent := "trust"

b, err := gophercloud.BuildRequestBody(opts, parent)
if err != nil {
return nil, err
}

if opts.ExpiresAt != nil {
if v, ok := b[parent].(map[string]interface{}); ok {
v["expires_at"] = opts.ExpiresAt.Format(gophercloud.RFC3339Milli)
}
}

return b, nil
}

// Create creates a new Trust.
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
b, err := opts.ToTrustCreateMap()
if err != nil {
r.Err = err
return
}
_, r.Err = client.Post(createURL(client), &b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{201},
})
return
}

// Delete deletes a trust.
func Delete(client *gophercloud.ServiceClient, trustID string) (r DeleteResult) {
_, r.Err = client.Delete(deleteURL(client, trustID), nil)
return
}
33 changes: 33 additions & 0 deletions openstack/identity/v3/extensions/trusts/results.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
package trusts

import "github.com/gophercloud/gophercloud"

type trustResult struct {
gophercloud.Result
}

// CreateResult is the response from a Create operation. Call its Extract method
// to interpret it as a Trust.
type CreateResult struct {
trustResult
}

// DeleteResult is the response from a Delete operation. Call its ExtractErr to
// determine if the request succeeded or failed.
type DeleteResult struct {
gophercloud.ErrResult
}

// Extract interprets any trust result as a Trust.
func (r trustResult) Extract() (*Trust, error) {
var s struct {
Trust *Trust `json:"trust"`
}
err := r.ExtractInto(&s)
return s.Trust, err
}

// TrusteeUser represents the trusted user ID of a trust.
type TrusteeUser struct {
ID string `json:"id"`
Expand All @@ -21,6 +48,12 @@ type Trust struct {
RedelegationCount int `json:"redelegation_count"`
}

// Role specifies a single role that is granted to a trustee.
type Role struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
}

// TokenExt represents an extension of the base token result.
type TokenExt struct {
Trust Trust `json:"OS-TRUST:trust"`
Expand Down
68 changes: 68 additions & 0 deletions openstack/identity/v3/extensions/trusts/testing/fixtures.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,51 @@ import (

"github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
"github.com/gophercloud/gophercloud/testhelper"
"github.com/gophercloud/gophercloud/testhelper/client"
)

const CreateRequest = `
{
"trust": {
"expires_at": "2019-12-01T14:00:00.999999Z",
"impersonation": true,
"allow_redelegation": true,
"project_id": "9b71012f5a4a4aef9193f1995fe159b2",
"roles": [
{
"name": "member"
}
],
"trustee_user_id": "ecb37e88cc86431c99d0332208cb6fbf",
"trustor_user_id": "959ed913a32c4ec88c041c98e61cbbc3"
}
}
`

const CreateResponse = `
{
"trust": {
"expires_at": "2019-12-01T14:00:00.999999Z",
"id": "3422b7c113894f5d90665e1a79655e23",
"impersonation": true,
"redelegation_count": 10,
"project_id": "9b71012f5a4a4aef9193f1995fe159b2",
"remaining_uses": null,
"roles": [
{
"id": "b627fca5-beb0-471a-9857-0e852b719e76",
"links": {
"self": "http://example.com/identity/v3/roles/b627fca5-beb0-471a-9857-0e852b719e76"
},
"name": "member"
}
],
"trustee_user_id": "ecb37e88cc86431c99d0332208cb6fbf",
"trustor_user_id": "959ed913a32c4ec88c041c98e61cbbc3"
}
}
`

// HandleCreateTokenWithTrustID verifies that providing certain AuthOptions and Scope results in an expected JSON structure.
func HandleCreateTokenWithTrustID(t *testing.T, options tokens.AuthOptionsBuilder, requestJSON string) {
testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -65,3 +108,28 @@ func HandleCreateTokenWithTrustID(t *testing.T, options tokens.AuthOptionsBuilde
}`)
})
}

// HandleCreateTrust creates an HTTP handler at `/OS-TRUST/trusts` on the
// test handler mux that tests trust creation.
func HandleCreateTrust(t *testing.T) {
testhelper.Mux.HandleFunc("/OS-TRUST/trusts", 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, CreateRequest)

w.WriteHeader(http.StatusCreated)
_, err := fmt.Fprintf(w, CreateResponse)
testhelper.AssertNoErr(t, err)
})
}

// HandleDeleteUserSuccessfully creates an HTTP handler at `/users` on the
// test handler mux that tests user deletion.
func HandleDeleteTrust(t *testing.T) {
testhelper.Mux.HandleFunc("/OS-TRUST/trusts/3422b7c113894f5d90665e1a79655e23", func(w http.ResponseWriter, r *http.Request) {
testhelper.TestMethod(t, r, "DELETE")
testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)

w.WriteHeader(http.StatusNoContent)
})
}
35 changes: 35 additions & 0 deletions openstack/identity/v3/extensions/trusts/testing/requests_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,38 @@ func TestCreateUserIDPasswordTrustID(t *testing.T) {

th.AssertDeepEquals(t, expected, actual)
}

func TestCreateTrust(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
HandleCreateTrust(t)

expiresAt := time.Date(2019, 12, 1, 14, 0, 0, 999999999, time.UTC)
result, err := trusts.Create(client.ServiceClient(), trusts.CreateOpts{
ExpiresAt: &expiresAt,
Impersonation: true,
AllowRedelegation: true,
ProjectID: "9b71012f5a4a4aef9193f1995fe159b2",
Roles: []trusts.Role{
{
Name: "member",
},
},
TrusteeUserID: "ecb37e88cc86431c99d0332208cb6fbf",
TrustorUserID: "959ed913a32c4ec88c041c98e61cbbc3",
}).Extract()
th.AssertNoErr(t, err)

th.AssertEquals(t, "3422b7c113894f5d90665e1a79655e23", result.ID)
th.AssertEquals(t, true, result.Impersonation)
th.AssertEquals(t, 10, result.RedelegationCount)
}

func TestDeleteTrust(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
HandleDeleteTrust(t)

res := trusts.Delete(client.ServiceClient(), "3422b7c113894f5d90665e1a79655e23")
th.AssertNoErr(t, res.Err)
}
21 changes: 21 additions & 0 deletions openstack/identity/v3/extensions/trusts/urls.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package trusts

import "github.com/gophercloud/gophercloud"

const resourcePath = "OS-TRUST/trusts"

func rootURL(c *gophercloud.ServiceClient) string {
return c.ServiceURL(resourcePath)
}

func resourceURL(c *gophercloud.ServiceClient, id string) string {
return c.ServiceURL(resourcePath, id)
}

func createURL(c *gophercloud.ServiceClient) string {
return rootURL(c)
}

func deleteURL(c *gophercloud.ServiceClient, id string) string {
return resourceURL(c, id)
}

0 comments on commit 00c1d0b

Please sign in to comment.