diff --git a/openstack/identity/v2/tenants/requests.go b/openstack/identity/v2/tenants/requests.go index 5a359f5c..daee4330 100644 --- a/openstack/identity/v2/tenants/requests.go +++ b/openstack/identity/v2/tenants/requests.go @@ -31,3 +31,120 @@ func List(client *gophercloud.ServiceClient, opts *ListOpts) pagination.Pager { return pagination.NewPager(client, url, createPage) } + +// EnabledState represents whether the tenant is enabled or not. +type EnabledState *bool + +// Useful variables to use when creating or updating tenants. +var ( + iTrue = true + iFalse = false + + Enabled EnabledState = &iTrue + Disabled EnabledState = &iFalse +) + +// CommonOpts are the parameters that are shared between CreateOpts and +// UpdateOpts +type CommonOpts struct { + // A name is required. When provided, the value must be + // unique or a 409 conflict error will be returned. + Name string + + // Indicates whether this user is enabled or not. + Enabled EnabledState + + // The description of this tenant. + Description string +} + +// CreateOpts represents the options needed when creating new tenants. +type CreateOpts CommonOpts + +// CreateOptsBuilder describes struct types that can be accepted by the Create call. +type CreateOptsBuilder interface { + ToTenantCreateMap() (map[string]interface{}, error) +} + +// ToTenantCreateMap assembles a request body based on the contents of a CreateOpts. +func (opts CreateOpts) ToTenantCreateMap() (map[string]interface{}, error) { + m := make(map[string]interface{}) + + if opts.Name != "" { + m["name"] = opts.Name + } + if opts.Description != "" { + m["description"] = opts.Description + } + if opts.Enabled != nil { + m["enabled"] = &opts.Enabled + } + + return map[string]interface{}{"tenant": m}, nil +} + +// Create is the operation responsible for creating new tenants. +func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult { + var res CreateResult + + reqBody, err := opts.ToTenantCreateMap() + if err != nil { + res.Err = err + return res + } + + _, res.Err = client.Post(rootURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200, 201}, + }) + + return res +} + +// Get requests details on a single tenant, either by ID. +func Get(client *gophercloud.ServiceClient, id string) GetResult { + var result GetResult + _, result.Err = client.Get(ResourceURL(client, id), &result.Body, nil) + return result +} + +// UpdateOptsBuilder allows extensions to add additional attributes to the Update request. +type UpdateOptsBuilder interface { + ToTenantUpdateMap() map[string]interface{} +} + +// UpdateOpts specifies the base attributes that may be updated on an existing tenant. +type UpdateOpts CommonOpts + +// ToUserUpdateMap formats an UpdateOpts structure into a request body. +func (opts UpdateOpts) ToTenantUpdateMap() map[string]interface{} { + m := make(map[string]interface{}) + + if opts.Name != "" { + m["name"] = opts.Name + } + if opts.Description != "" { + m["description"] = opts.Description + } + if opts.Enabled != nil { + m["enabled"] = &opts.Enabled + } + + return map[string]interface{}{"tenant": m} +} + +// Update is the operation responsible for updating exist users by their UUID. +func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult { + var result UpdateResult + reqBody := opts.ToTenantUpdateMap() + _, result.Err = client.Put(ResourceURL(client, id), reqBody, &result.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200}, + }) + return result +} + +// Delete is the operation responsible for permanently deleting an API user. +func Delete(client *gophercloud.ServiceClient, id string) DeleteResult { + var result DeleteResult + _, result.Err = client.Delete(ResourceURL(client, id), nil) + return result +} diff --git a/openstack/identity/v2/tenants/results.go b/openstack/identity/v2/tenants/results.go index c1220c38..51584c7b 100644 --- a/openstack/identity/v2/tenants/results.go +++ b/openstack/identity/v2/tenants/results.go @@ -60,3 +60,42 @@ func ExtractTenants(page pagination.Page) ([]Tenant, error) { err := mapstructure.Decode(casted, &response) return response.Tenants, err } + +type commonResult struct { + gophercloud.Result +} + +// Extract interprets any commonResult as a Tenant, if possible. +func (r commonResult) Extract() (*Tenant, error) { + if r.Err != nil { + return nil, r.Err + } + + var response struct { + Tenant Tenant `mapstructure:"tenant"` + } + + err := mapstructure.Decode(r.Body, &response) + + return &response.Tenant, err +} + +// CreateResult represents the result of a Create operation +type CreateResult struct { + commonResult +} + +// GetResult represents the result of a Get operation +type GetResult struct { + commonResult +} + +// UpdateResult represents the result of an Update operation +type UpdateResult struct { + commonResult +} + +// DeleteResult represents the result of a Delete operation +type DeleteResult struct { + commonResult +} diff --git a/openstack/identity/v2/tenants/urls.go b/openstack/identity/v2/tenants/urls.go index 1dd6ce02..0a694866 100644 --- a/openstack/identity/v2/tenants/urls.go +++ b/openstack/identity/v2/tenants/urls.go @@ -2,6 +2,14 @@ package tenants import "github.com/rackspace/gophercloud" +func ResourceURL(c *gophercloud.ServiceClient, id string) string { + return c.ServiceURL("tenants", id) +} + +func rootURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL("tenants") +} + func listURL(client *gophercloud.ServiceClient) string { return client.ServiceURL("tenants") }