dsl struct tags; wip
diff --git a/openstack/blockstorage/v1/apiversions/requests.go b/openstack/blockstorage/v1/apiversions/requests.go
index 0c05558..4e9df04 100644
--- a/openstack/blockstorage/v1/apiversions/requests.go
+++ b/openstack/blockstorage/v1/apiversions/requests.go
@@ -15,7 +15,7 @@
// Get will retrieve the volume type with the provided ID. To extract the volume
// type from the result, call the Extract method on the GetResult.
func Get(client *gophercloud.ServiceClient, v string) GetResult {
- var res GetResult
- _, res.Err = client.Get(getURL(client, v), &res.Body, nil)
- return res
+ var r GetResult
+ _, r.Err = client.Get(getURL(client, v), &r.Body, nil)
+ return r
}
diff --git a/openstack/blockstorage/v1/snapshots/requests.go b/openstack/blockstorage/v1/snapshots/requests.go
index 504ce6e..e8583cb 100644
--- a/openstack/blockstorage/v1/snapshots/requests.go
+++ b/openstack/blockstorage/v1/snapshots/requests.go
@@ -15,78 +15,48 @@
// the snapshots.Create function. For more information about these parameters,
// see the Snapshot object.
type CreateOpts struct {
- // OPTIONAL
- Description string
- // OPTIONAL
- Force bool
- // OPTIONAL
- Metadata map[string]interface{}
- // OPTIONAL
- Name string
- // REQUIRED
- VolumeID string
+ VolumeID string `json:"volume_id" required:"true"`
+ Description string `json:"display_description,omitempty"`
+ Force bool `json:"force,omitempty"`
+ Metadata map[string]interface{} `json:"metadata,omitempty"`
+ Name string `json:"display_name,omitempty"`
}
// ToSnapshotCreateMap assembles a request body based on the contents of a
// CreateOpts.
func (opts CreateOpts) ToSnapshotCreateMap() (map[string]interface{}, error) {
- s := make(map[string]interface{})
-
- if opts.VolumeID == "" {
- err := &gophercloud.ErrMissingInput{}
- err.Argument = "CreateOpts.VolumeID"
- err.Function = "snapshots.ToSnapshotCreateMap"
- return nil, err
- }
- s["volume_id"] = opts.VolumeID
-
- if opts.Description != "" {
- s["display_description"] = opts.Description
- }
- if opts.Force == true {
- s["force"] = opts.Force
- }
- if opts.Metadata != nil {
- s["metadata"] = opts.Metadata
- }
- if opts.Name != "" {
- s["display_name"] = opts.Name
- }
-
- return map[string]interface{}{"snapshot": s}, nil
+ return gophercloud.BuildRequestBody(opts, "snapshot")
}
// Create will create a new Snapshot based on the values in CreateOpts. To
// extract the Snapshot object from the response, call the Extract method on the
// CreateResult.
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
- var res CreateResult
-
- reqBody, err := opts.ToSnapshotCreateMap()
+ var r CreateResult
+ b, err := opts.ToSnapshotCreateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- _, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200, 201},
})
- return res
+ return r
}
// Delete will delete the existing Snapshot with the provided ID.
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
- var res DeleteResult
- _, res.Err = client.Delete(deleteURL(client, id), nil)
- return res
+ var r DeleteResult
+ _, r.Err = client.Delete(deleteURL(client, id), nil)
+ return r
}
// Get retrieves the Snapshot with the provided ID. To extract the Snapshot
// object from the response, call the Extract method on the GetResult.
func Get(client *gophercloud.ServiceClient, id string) GetResult {
- var res GetResult
- _, res.Err = client.Get(getURL(client, id), &res.Body, nil)
- return res
+ var r GetResult
+ _, r.Err = client.Get(getURL(client, id), &r.Body, nil)
+ return r
}
// ListOptsBuilder allows extensions to add additional parameters to the List
@@ -106,10 +76,7 @@
// ToSnapshotListQuery formats a ListOpts into a query string.
func (opts ListOpts) ToSnapshotListQuery() (string, error) {
q, err := gophercloud.BuildQueryString(opts)
- if err != nil {
- return "", err
- }
- return q.String(), nil
+ return q.String(), err
}
// List returns Snapshots optionally limited by the conditions provided in
@@ -123,11 +90,9 @@
}
url += query
}
-
- createPage := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
return SnapshotPage{pagination.SinglePageBase(r)}
- }
- return pagination.NewPager(client, url, createPage)
+ })
}
// UpdateMetadataOptsBuilder allows extensions to add additional parameters to
@@ -140,50 +105,35 @@
// object is passed to the snapshots.Update function. For more information
// about the parameters, see the Snapshot object.
type UpdateMetadataOpts struct {
- Metadata map[string]interface{}
+ Metadata map[string]interface{} `json:"metadata,omitempty"`
}
// ToSnapshotUpdateMetadataMap assembles a request body based on the contents of
// an UpdateMetadataOpts.
func (opts UpdateMetadataOpts) ToSnapshotUpdateMetadataMap() (map[string]interface{}, error) {
- v := make(map[string]interface{})
-
- if opts.Metadata != nil {
- v["metadata"] = opts.Metadata
- }
-
- return v, nil
+ return gophercloud.BuildRequestBody(opts, "")
}
// UpdateMetadata will update the Snapshot with provided information. To
// extract the updated Snapshot from the response, call the ExtractMetadata
// method on the UpdateMetadataResult.
func UpdateMetadata(client *gophercloud.ServiceClient, id string, opts UpdateMetadataOptsBuilder) UpdateMetadataResult {
- var res UpdateMetadataResult
-
- reqBody, err := opts.ToSnapshotUpdateMetadataMap()
+ var r UpdateMetadataResult
+ b, err := opts.ToSnapshotUpdateMetadataMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- _, res.Err = client.Put(updateMetadataURL(client, id), reqBody, &res.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Put(updateMetadataURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
- return res
+ return r
}
// IDFromName is a convienience function that returns a snapshot's ID given its name.
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
count := 0
id := ""
- if name == "" {
- err := &gophercloud.ErrMissingInput{}
- err.Function = "snapshots.IDFromName"
- err.Argument = "name"
- return "", err
- }
-
pages, err := List(client, nil).AllPages()
if err != nil {
return "", err
@@ -203,19 +153,10 @@
switch count {
case 0:
- err := &gophercloud.ErrResourceNotFound{}
- err.Name = name
- err.ResourceType = "snapshot"
- err.Function = "snapshots.IDFromName"
- return "", err
+ return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "snapshot"}
case 1:
return id, nil
default:
- err := &gophercloud.ErrMultipleResourcesFound{}
- err.Count = count
- err.Name = name
- err.ResourceType = "snapshot"
- err.Function = "snapshots.IDFromName"
- return "", err
+ return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "snapshot"}
}
}
diff --git a/openstack/blockstorage/v1/volumes/requests.go b/openstack/blockstorage/v1/volumes/requests.go
index 1c6b635..7c063b2 100644
--- a/openstack/blockstorage/v1/volumes/requests.go
+++ b/openstack/blockstorage/v1/volumes/requests.go
@@ -15,94 +15,52 @@
// the volumes.Create function. For more information about these parameters,
// see the Volume object.
type CreateOpts struct {
- // OPTIONAL
- Availability string
- // OPTIONAL
- Description string
- // OPTIONAL
- Metadata map[string]string
- // OPTIONAL
- Name string
- // REQUIRED
- Size int
- // OPTIONAL
- SnapshotID, SourceVolID, ImageID string
- // OPTIONAL
- VolumeType string
+ Size int `json:"size" required:"true"`
+ Availability string `json:"availability,omitempty"`
+ Description string `json:"description,omitempty"`
+ Metadata map[string]string `json:"metadata,omitempty"`
+ Name string `json:"name,omitempty"`
+ SnapshotID string `json:"snapshot_id,omitempty"`
+ SourceVolID string `json:"source_volid,omitempty"`
+ ImageID string `json:"imageRef,omitempty"`
+ VolumeType string `json:"volume_type,omitempty"`
}
// ToVolumeCreateMap assembles a request body based on the contents of a
// CreateOpts.
func (opts CreateOpts) ToVolumeCreateMap() (map[string]interface{}, error) {
- v := make(map[string]interface{})
-
- if opts.Size == 0 {
- err := &gophercloud.ErrMissingInput{}
- err.Argument = "CreateOpts.Size"
- err.Function = "volumes.ToVolumeCreateMap"
- return nil, err
- }
- v["size"] = opts.Size
-
- if opts.Availability != "" {
- v["availability_zone"] = opts.Availability
- }
- if opts.Description != "" {
- v["display_description"] = opts.Description
- }
- if opts.ImageID != "" {
- v["imageRef"] = opts.ImageID
- }
- if opts.Metadata != nil {
- v["metadata"] = opts.Metadata
- }
- if opts.Name != "" {
- v["display_name"] = opts.Name
- }
- if opts.SourceVolID != "" {
- v["source_volid"] = opts.SourceVolID
- }
- if opts.SnapshotID != "" {
- v["snapshot_id"] = opts.SnapshotID
- }
- if opts.VolumeType != "" {
- v["volume_type"] = opts.VolumeType
- }
-
- return map[string]interface{}{"volume": v}, nil
+ return gophercloud.BuildRequestBody(opts, "volume")
}
// Create will create a new Volume based on the values in CreateOpts. To extract
// the Volume object from the response, call the Extract method on the
// CreateResult.
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
- var res CreateResult
-
- reqBody, err := opts.ToVolumeCreateMap()
+ var r CreateResult
+ b, err := opts.ToVolumeCreateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- _, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200, 201},
})
- return res
+ return r
}
// Delete will delete the existing Volume with the provided ID.
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
- var res DeleteResult
- _, res.Err = client.Delete(deleteURL(client, id), nil)
- return res
+ var r DeleteResult
+ _, r.Err = client.Delete(deleteURL(client, id), nil)
+ return r
}
// Get retrieves the Volume with the provided ID. To extract the Volume object
// from the response, call the Extract method on the GetResult.
func Get(client *gophercloud.ServiceClient, id string) GetResult {
- var res GetResult
- _, res.Err = client.Get(getURL(client, id), &res.Body, nil)
- return res
+ var r GetResult
+ _, r.Err = client.Get(getURL(client, id), &r.Body, nil)
+ return r
}
// ListOptsBuilder allows extensions to add additional parameters to the List
@@ -127,10 +85,7 @@
// ToVolumeListQuery formats a ListOpts into a query string.
func (opts ListOpts) ToVolumeListQuery() (string, error) {
q, err := gophercloud.BuildQueryString(opts)
- if err != nil {
- return "", err
- }
- return q.String(), nil
+ return q.String(), err
}
// List returns Volumes optionally limited by the conditions provided in ListOpts.
@@ -143,11 +98,9 @@
}
url += query
}
- createPage := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
return VolumePage{pagination.SinglePageBase(r)}
- }
-
- return pagination.NewPager(client, url, createPage)
+ })
}
// UpdateOptsBuilder allows extensions to add additional parameters to the
@@ -161,59 +114,38 @@
// the Volume object.
type UpdateOpts struct {
// OPTIONAL
- Name string
+ Name string `json:"name,omitempty"`
// OPTIONAL
- Description string
+ Description string `json:"description,omitempty"`
// OPTIONAL
- Metadata map[string]string
+ Metadata map[string]string `json:"metadata,omitempty"`
}
// ToVolumeUpdateMap assembles a request body based on the contents of an
// UpdateOpts.
func (opts UpdateOpts) ToVolumeUpdateMap() (map[string]interface{}, error) {
- v := make(map[string]interface{})
-
- if opts.Description != "" {
- v["display_description"] = opts.Description
- }
- if opts.Metadata != nil {
- v["metadata"] = opts.Metadata
- }
- if opts.Name != "" {
- v["display_name"] = opts.Name
- }
-
- return map[string]interface{}{"volume": v}, nil
+ return gophercloud.BuildRequestBody(opts, "volume")
}
// Update will update the Volume with provided information. To extract the updated
// Volume from the response, call the Extract method on the UpdateResult.
func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
- var res UpdateResult
-
- reqBody, err := opts.ToVolumeUpdateMap()
+ var r UpdateResult
+ b, err := opts.ToVolumeUpdateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- _, res.Err = client.Put(updateURL(client, id), reqBody, &res.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Put(updateURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
- return res
+ return r
}
// IDFromName is a convienience function that returns a server's ID given its name.
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
count := 0
id := ""
- if name == "" {
- err := &gophercloud.ErrMissingInput{}
- err.Function = "volumes.IDFromName"
- err.Argument = "name"
- return "", err
- }
-
pages, err := List(client, nil).AllPages()
if err != nil {
return "", err
@@ -233,19 +165,10 @@
switch count {
case 0:
- err := &gophercloud.ErrResourceNotFound{}
- err.Name = name
- err.ResourceType = "volume"
- err.Function = "volumes.IDFromName"
- return "", err
+ return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "volume"}
case 1:
return id, nil
default:
- err := &gophercloud.ErrMultipleResourcesFound{}
- err.Count = count
- err.Name = name
- err.ResourceType = "volume"
- err.Function = "volumes.IDFromName"
- return "", err
+ return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "volume"}
}
}
diff --git a/openstack/blockstorage/v1/volumetypes/requests.go b/openstack/blockstorage/v1/volumetypes/requests.go
index 24e50ad..b895482 100644
--- a/openstack/blockstorage/v1/volumetypes/requests.go
+++ b/openstack/blockstorage/v1/volumetypes/requests.go
@@ -13,64 +13,50 @@
// CreateOpts are options for creating a volume type.
type CreateOpts struct {
- // OPTIONAL. See VolumeType.
- ExtraSpecs map[string]interface{}
- // OPTIONAL. See VolumeType.
- Name string
+ // See VolumeType.
+ ExtraSpecs map[string]interface{} `json:"extra_specs,omitempty"`
+ // See VolumeType.
+ Name string `json:"name,omitempty"`
}
// ToVolumeTypeCreateMap casts a CreateOpts struct to a map.
func (opts CreateOpts) ToVolumeTypeCreateMap() (map[string]interface{}, error) {
- vt := make(map[string]interface{})
-
- if opts.ExtraSpecs != nil {
- vt["extra_specs"] = opts.ExtraSpecs
- }
- if opts.Name != "" {
- vt["name"] = opts.Name
- }
-
- return map[string]interface{}{"volume_type": vt}, nil
+ return gophercloud.BuildRequestBody(opts, "volume_type")
}
// Create will create a new volume. To extract the created volume type object,
// call the Extract method on the CreateResult.
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
- var res CreateResult
-
- reqBody, err := opts.ToVolumeTypeCreateMap()
+ var r CreateResult
+ b, err := opts.ToVolumeTypeCreateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- _, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200, 201},
})
- return res
+ return r
}
// Delete will delete the volume type with the provided ID.
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
- var res DeleteResult
- _, res.Err = client.Delete(deleteURL(client, id), nil)
- return res
+ var r DeleteResult
+ _, r.Err = client.Delete(deleteURL(client, id), nil)
+ return r
}
// Get will retrieve the volume type with the provided ID. To extract the volume
// type from the result, call the Extract method on the GetResult.
func Get(client *gophercloud.ServiceClient, id string) GetResult {
- var res GetResult
- _, err := client.Get(getURL(client, id), &res.Body, nil)
- res.Err = err
- return res
+ var r GetResult
+ _, r.Err = client.Get(getURL(client, id), &r.Body, nil)
+ return r
}
// List returns all volume types.
func List(client *gophercloud.ServiceClient) pagination.Pager {
- createPage := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
return VolumeTypePage{pagination.SinglePageBase(r)}
- }
-
- return pagination.NewPager(client, listURL(client), createPage)
+ })
}
diff --git a/openstack/cdn/v1/base/requests.go b/openstack/cdn/v1/base/requests.go
index ed3e7a0..15f8346 100644
--- a/openstack/cdn/v1/base/requests.go
+++ b/openstack/cdn/v1/base/requests.go
@@ -5,17 +5,17 @@
// Get retrieves the home document, allowing the user to discover the
// entire API.
func Get(c *gophercloud.ServiceClient) GetResult {
- var res GetResult
- _, res.Err = c.Get(getURL(c), &res.Body, nil)
- return res
+ var r GetResult
+ _, r.Err = c.Get(getURL(c), &r.Body, nil)
+ return r
}
// Ping retrieves a ping to the server.
func Ping(c *gophercloud.ServiceClient) PingResult {
- var res PingResult
- _, res.Err = c.Get(pingURL(c), nil, &gophercloud.RequestOpts{
+ var r PingResult
+ _, r.Err = c.Get(pingURL(c), nil, &gophercloud.RequestOpts{
OkCodes: []int{204},
MoreHeaders: map[string]string{"Accept": ""},
})
- return res
+ return r
}
diff --git a/openstack/cdn/v1/flavors/requests.go b/openstack/cdn/v1/flavors/requests.go
index a7c0232..d42d1d7 100644
--- a/openstack/cdn/v1/flavors/requests.go
+++ b/openstack/cdn/v1/flavors/requests.go
@@ -7,16 +7,14 @@
// List returns a single page of CDN flavors.
func List(c *gophercloud.ServiceClient) pagination.Pager {
- url := listURL(c)
- createPage := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(c, listURL(c), func(r pagination.PageResult) pagination.Page {
return FlavorPage{pagination.SinglePageBase(r)}
- }
- return pagination.NewPager(c, url, createPage)
+ })
}
// Get retrieves a specific flavor based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) GetResult {
- var res GetResult
- _, res.Err = c.Get(getURL(c, id), &res.Body, nil)
- return res
+ var r GetResult
+ _, r.Err = c.Get(getURL(c, id), &r.Body, nil)
+ return r
}
diff --git a/openstack/cdn/v1/serviceassets/requests.go b/openstack/cdn/v1/serviceassets/requests.go
index 39afaff..3d0543e 100644
--- a/openstack/cdn/v1/serviceassets/requests.go
+++ b/openstack/cdn/v1/serviceassets/requests.go
@@ -24,10 +24,7 @@
// ToCDNAssetDeleteParams formats a DeleteOpts into a query string.
func (opts DeleteOpts) ToCDNAssetDeleteParams() (string, error) {
q, err := gophercloud.BuildQueryString(opts)
- if err != nil {
- return "", err
- }
- return q.String(), nil
+ return q.String(), err
}
// Delete accepts a unique service ID or URL and deletes the CDN service asset associated with
@@ -41,8 +38,15 @@
} else {
url = deleteURL(c, idOrURL)
}
-
- var res DeleteResult
- _, res.Err = c.Delete(url, nil)
- return res
+ var r DeleteResult
+ if opts != nil {
+ q, err := opts.ToCDNAssetDeleteParams()
+ if err != nil {
+ r.Err = err
+ return r
+ }
+ url += q
+ }
+ _, r.Err = c.Delete(url, nil)
+ return r
}
diff --git a/openstack/cdn/v1/services/requests.go b/openstack/cdn/v1/services/requests.go
index 89ee372..9a0f54b 100644
--- a/openstack/cdn/v1/services/requests.go
+++ b/openstack/cdn/v1/services/requests.go
@@ -24,10 +24,7 @@
// ToCDNServiceListQuery formats a ListOpts into a query string.
func (opts ListOpts) ToCDNServiceListQuery() (string, error) {
q, err := gophercloud.BuildQueryString(opts)
- if err != nil {
- return "", err
- }
- return q.String(), nil
+ return q.String(), err
}
// List returns a Pager which allows you to iterate over a collection of
@@ -42,15 +39,11 @@
}
url += query
}
-
- createPage := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
p := ServicePage{pagination.MarkerPageBase{PageResult: r}}
p.MarkerPageBase.Owner = p
return p
- }
-
- pager := pagination.NewPager(c, url, createPage)
- return pager
+ })
}
// CreateOptsBuilder is the interface options structs have to satisfy in order
@@ -64,123 +57,52 @@
// CreateOpts is the common options struct used in this package's Create
// operation.
type CreateOpts struct {
- // REQUIRED. Specifies the name of the service. The minimum length for name is
+ // Specifies the name of the service. The minimum length for name is
// 3. The maximum length is 256.
- Name string
- // REQUIRED. Specifies a list of domains used by users to access their website.
- Domains []Domain
- // REQUIRED. Specifies a list of origin domains or IP addresses where the
+ Name string `json:"name" required:"true"`
+ // Specifies a list of domains used by users to access their website.
+ Domains []Domain `json:"domains" required:"true"`
+ // Specifies a list of origin domains or IP addresses where the
// original assets are stored.
- Origins []Origin
- // REQUIRED. Specifies the CDN provider flavor ID to use. For a list of
+ Origins []Origin `json:"origins" required:"true"`
+ // Specifies the CDN provider flavor ID to use. For a list of
// flavors, see the operation to list the available flavors. The minimum
// length for flavor_id is 1. The maximum length is 256.
- FlavorID string
- // OPTIONAL. Specifies the TTL rules for the assets under this service. Supports wildcards for fine-grained control.
- Caching []CacheRule
- // OPTIONAL. Specifies the restrictions that define who can access assets (content from the CDN cache).
- Restrictions []Restriction
+ FlavorID string `json:"flavor_id" required:"true"`
+ // Specifies the TTL rules for the assets under this service. Supports wildcards for fine-grained control.
+ Caching []CacheRule `json:"caching,omitempty"`
+ // Specifies the restrictions that define who can access assets (content from the CDN cache).
+ Restrictions []Restriction `json:"restrictions,omitempty"`
}
// ToCDNServiceCreateMap casts a CreateOpts struct to a map.
func (opts CreateOpts) ToCDNServiceCreateMap() (map[string]interface{}, error) {
- s := make(map[string]interface{})
- if opts.Name == "" {
- return nil, no("Name")
- }
- s["name"] = opts.Name
-
- if opts.Domains == nil {
- return nil, no("Domains")
- }
- for _, domain := range opts.Domains {
- if domain.Domain == "" {
- return nil, no("Domains[].Domain")
- }
- }
- s["domains"] = opts.Domains
-
- if opts.Origins == nil {
- return nil, no("Origins")
- }
- for _, origin := range opts.Origins {
- if origin.Origin == "" {
- return nil, no("Origins[].Origin")
- }
- if origin.Rules == nil && len(opts.Origins) > 1 {
- return nil, no("Origins[].Rules")
- }
- for _, rule := range origin.Rules {
- if rule.Name == "" {
- return nil, no("Origins[].Rules[].Name")
- }
- if rule.RequestURL == "" {
- return nil, no("Origins[].Rules[].RequestURL")
+ /*
+ for _, origin := range opts.Origins {
+ if origin.Rules == nil && len(opts.Origins) > 1 {
+ return nil, no("Origins[].Rules")
}
}
- }
- s["origins"] = opts.Origins
+ */
- if opts.FlavorID == "" {
- return nil, no("FlavorID")
- }
- s["flavor_id"] = opts.FlavorID
-
- if opts.Caching != nil {
- for _, cache := range opts.Caching {
- if cache.Name == "" {
- return nil, no("Caching[].Name")
- }
- if cache.Rules != nil {
- for _, rule := range cache.Rules {
- if rule.Name == "" {
- return nil, no("Caching[].Rules[].Name")
- }
- if rule.RequestURL == "" {
- return nil, no("Caching[].Rules[].RequestURL")
- }
- }
- }
- }
- s["caching"] = opts.Caching
- }
-
- if opts.Restrictions != nil {
- for _, restriction := range opts.Restrictions {
- if restriction.Name == "" {
- return nil, no("Restrictions[].Name")
- }
- if restriction.Rules != nil {
- for _, rule := range restriction.Rules {
- if rule.Name == "" {
- return nil, no("Restrictions[].Rules[].Name")
- }
- }
- }
- }
- s["restrictions"] = opts.Restrictions
- }
-
- return s, nil
+ return gophercloud.BuildRequestBody(opts, "")
}
// Create accepts a CreateOpts struct and creates a new CDN service using the
// values provided.
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
- var res CreateResult
-
- reqBody, err := opts.ToCDNServiceCreateMap()
+ var r CreateResult
+ b, err := opts.ToCDNServiceCreateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
// Send request to API
- resp, err := c.Post(createURL(c), &reqBody, nil, nil)
- res.Header = resp.Header
- res.Err = err
- return res
+ resp, err := c.Post(createURL(c), &b, nil, nil)
+ r.Header = resp.Header
+ r.Err = err
+ return r
}
// Get retrieves a specific service based on its URL or its unique ID. For
@@ -195,9 +117,9 @@
url = getURL(c, idOrURL)
}
- var res GetResult
- _, res.Err = c.Get(url, &res.Body, nil)
- return res
+ var r GetResult
+ _, r.Err = c.Get(url, &r.Body, nil)
+ return r
}
// Path is a JSON pointer location that indicates which service parameter is being added, replaced,
@@ -251,11 +173,11 @@
// ToCDNServiceUpdateMap converts an Insertion into a request body fragment suitable for the
// Update call.
-func (i Insertion) ToCDNServiceUpdateMap() map[string]interface{} {
+func (opts Insertion) ToCDNServiceUpdateMap() map[string]interface{} {
return map[string]interface{}{
"op": "add",
- "path": i.Value.renderRootOr(func(p Path) string { return p.renderIndex(i.Index) }),
- "value": i.Value.toPatchValue(),
+ "path": opts.Value.renderRootOr(func(p Path) string { return p.renderIndex(opts.Index) }),
+ "value": opts.Value.toPatchValue(),
}
}
@@ -320,16 +242,17 @@
// ToCDNServiceUpdateMap converts a Removal into a request body fragment suitable for the
// Update call.
-func (r Removal) ToCDNServiceUpdateMap() map[string]interface{} {
- result := map[string]interface{}{"op": "remove"}
- if r.All {
- result["path"] = r.Path.renderRoot()
+func (opts Removal) ToCDNServiceUpdateMap() map[string]interface{} {
+ b := map[string]interface{}{"op": "remove"}
+ if opts.All {
+ b["path"] = opts.Path.renderRoot()
} else {
- result["path"] = r.Path.renderIndex(r.Index)
+ b["path"] = opts.Path.renderIndex(opts.Index)
}
- return result
+ return b
}
+// UpdateOpts is a slice of Patches used to update a CDN service
type UpdateOpts []Patch
// Update accepts a slice of Patch operations (Insertion, Append, Replacement or Removal) and
@@ -345,19 +268,19 @@
url = updateURL(c, idOrURL)
}
- reqBody := make([]map[string]interface{}, len(opts))
+ b := make([]map[string]interface{}, len(opts))
for i, patch := range opts {
- reqBody[i] = patch.ToCDNServiceUpdateMap()
+ b[i] = patch.ToCDNServiceUpdateMap()
}
resp, err := c.Request("PATCH", url, &gophercloud.RequestOpts{
- JSONBody: &reqBody,
+ JSONBody: &b,
OkCodes: []int{202},
})
- var result UpdateResult
- result.Header = resp.Header
- result.Err = err
- return result
+ var r UpdateResult
+ r.Header = resp.Header
+ r.Err = err
+ return r
}
// Delete accepts a service's ID or its URL and deletes the CDN service
@@ -372,7 +295,7 @@
url = deleteURL(c, idOrURL)
}
- var res DeleteResult
- _, res.Err = c.Delete(url, nil)
- return res
+ var r DeleteResult
+ _, r.Err = c.Delete(url, nil)
+ return r
}
diff --git a/openstack/cdn/v1/services/results.go b/openstack/cdn/v1/services/results.go
index 6de3497..f9a1caa 100644
--- a/openstack/cdn/v1/services/results.go
+++ b/openstack/cdn/v1/services/results.go
@@ -9,7 +9,7 @@
type Domain struct {
// Specifies the domain used to access the assets on their website, for which
// a CNAME is given to the CDN provider.
- Domain string `json:"domain"`
+ Domain string `json:"domain" required:"true"`
// Specifies the protocol used to access the assets on this domain. Only "http"
// or "https" are currently allowed. The default is "http".
Protocol string `json:"protocol,omitempty"`
@@ -54,17 +54,17 @@
// OriginRule represents a rule that defines when an origin should be accessed.
type OriginRule struct {
// Specifies the name of this rule.
- Name string `json:"name"`
+ Name string `json:"name" required:"true"`
// Specifies the request URL this rule should match for this origin to be used. Regex is supported.
- RequestURL string `json:"request_url"`
+ RequestURL string `json:"request_url" required:"true"`
}
// Origin specifies a list of origin domains or IP addresses where the original assets are stored.
type Origin struct {
// Specifies the URL or IP address to pull origin content from.
- Origin string `json:"origin"`
+ Origin string `json:"origin" required:"true"`
// Specifies the port used to access the origin. The default is port 80.
- Port int `json:"port"`
+ Port int `json:"port,omitempty"`
// Specifies whether or not to use HTTPS to access the origin. The default
// is false.
SSL bool `json:"ssl"`
@@ -119,17 +119,17 @@
// TTLRule specifies a rule that determines if a TTL should be applied to an asset.
type TTLRule struct {
// Specifies the name of this rule.
- Name string `json:"name"`
+ Name string `json:"name" required:"true"`
// Specifies the request URL this rule should match for this TTL to be used. Regex is supported.
- RequestURL string `json:"request_url"`
+ RequestURL string `json:"request_url" required:"true"`
}
// CacheRule specifies the TTL rules for the assets under this service.
type CacheRule struct {
// Specifies the name of this caching rule. Note: 'default' is a reserved name used for the default TTL setting.
- Name string `json:"name"`
+ Name string `json:"name" required:"true"`
// Specifies the TTL to apply.
- TTL int `json:"ttl"`
+ TTL int `json:"ttl,omitempty"`
// Specifies a collection of rules that determine if this TTL should be applied to an asset.
Rules []TTLRule `json:"rules,omitempty"`
}
@@ -177,17 +177,17 @@
// RestrictionRule specifies a rule that determines if this restriction should be applied to an asset.
type RestrictionRule struct {
// Specifies the name of this rule.
- Name string `json:"name"`
+ Name string `json:"name" required:"true"`
// Specifies the http host that requests must come from.
- Referrer string `json:"referrer"`
+ Referrer string `json:"referrer,omitempty"`
}
// Restriction specifies a restriction that defines who can access assets (content from the CDN cache).
type Restriction struct {
// Specifies the name of this restriction.
- Name string `json:"name"`
+ Name string `json:"name" required:"true"`
// Specifies a collection of rules that determine if this TTL should be applied to an asset.
- Rules []RestrictionRule `json:"rules"`
+ Rules []RestrictionRule `json:"rules,omitempty"`
}
// Error specifies an error that occurred during the previous service action.
diff --git a/openstack/common/extensions/requests.go b/openstack/common/extensions/requests.go
index f49427c..05bf35d 100755
--- a/openstack/common/extensions/requests.go
+++ b/openstack/common/extensions/requests.go
@@ -7,9 +7,9 @@
// Get retrieves information for a specific extension using its alias.
func Get(c *gophercloud.ServiceClient, alias string) GetResult {
- var res GetResult
- _, res.Err = c.Get(ExtensionURL(c, alias), &res.Body, nil)
- return res
+ var r GetResult
+ _, r.Err = c.Get(ExtensionURL(c, alias), &r.Body, nil)
+ return r
}
// List returns a Pager which allows you to iterate over the full collection of extensions.
diff --git a/openstack/compute/v2/extensions/bootfromvolume/requests.go b/openstack/compute/v2/extensions/bootfromvolume/requests.go
index 7171afa..086cc0a 100644
--- a/openstack/compute/v2/extensions/bootfromvolume/requests.go
+++ b/openstack/compute/v2/extensions/bootfromvolume/requests.go
@@ -1,9 +1,6 @@
package bootfromvolume
import (
- "fmt"
- "strconv"
-
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
)
@@ -12,37 +9,35 @@
type SourceType string
const (
- Volume SourceType = "volume"
+ // Volume SourceType
+ Volume SourceType = "volume"
+ // Snapshot SourceType
Snapshot SourceType = "snapshot"
- Image SourceType = "image"
- Blank SourceType = "blank"
+ // Image SourceType
+ Image SourceType = "image"
+ // Blank SourceType
+ Blank SourceType = "blank"
)
// BlockDevice is a structure with options for booting a server instance
// from a volume. The volume may be created from an image, snapshot, or another
// volume.
type BlockDevice struct {
- // BootIndex [optional] is the boot index. It defaults to 0.
+ // SourceType must be one of: "volume", "snapshot", "image".
+ SourceType SourceType `json:"source_type" required:"true"`
+ // UUID is the unique identifier for the volume, snapshot, or image (see above)
+ UUID string `json:"uuid,omitempty"`
+ // BootIndex is the boot index. It defaults to 0.
BootIndex int `json:"boot_index"`
-
- // DeleteOnTermination [optional] specifies whether or not to delete the attached volume
+ // DeleteOnTermination specifies whether or not to delete the attached volume
// when the server is deleted. Defaults to `false`.
DeleteOnTermination bool `json:"delete_on_termination"`
-
- // DestinationType [optional] is the type that gets created. Possible values are "volume"
+ // DestinationType is the type that gets created. Possible values are "volume"
// and "local".
- DestinationType string `json:"destination_type"`
-
- // GuestFormat [optional] specifies the format of the block device.
- GuestFormat string `json:"guest_format"`
-
- // SourceType [required] must be one of: "volume", "snapshot", "image".
- SourceType SourceType `json:"source_type"`
-
- // UUID [required] is the unique identifier for the volume, snapshot, or image (see above)
- UUID string `json:"uuid"`
-
- // VolumeSize [optional] is the size of the volume to create (in gigabytes).
+ DestinationType string `json:"destination_type,omitempty"`
+ // GuestFormat specifies the format of the block device.
+ GuestFormat string `json:"guest_format,omitempty"`
+ // VolumeSize is the size of the volume to create (in gigabytes).
VolumeSize int `json:"volume_size"`
}
@@ -63,7 +58,6 @@
if len(opts.BlockDevice) == 0 {
err := gophercloud.ErrMissingInput{}
- err.Function = "bootfromvolume.ToServerCreateMap"
err.Argument = "bootfromvolume.CreateOptsExt.BlockDevice"
return nil, err
}
@@ -73,29 +67,11 @@
blockDevice := make([]map[string]interface{}, len(opts.BlockDevice))
for i, bd := range opts.BlockDevice {
- if string(bd.SourceType) == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "bootfromvolume.ToServerCreateMap"
- err.Argument = fmt.Sprintf("bootfromvolume.CreateOptsExt.BlockDevice[%d].SourceType", i)
+ b, err := gophercloud.BuildRequestBody(bd, "")
+ if err != nil {
return nil, err
}
-
- blockDevice[i] = make(map[string]interface{})
-
- blockDevice[i]["source_type"] = bd.SourceType
- blockDevice[i]["boot_index"] = strconv.Itoa(bd.BootIndex)
- blockDevice[i]["delete_on_termination"] = strconv.FormatBool(bd.DeleteOnTermination)
- blockDevice[i]["volume_size"] = strconv.Itoa(bd.VolumeSize)
- if bd.UUID != "" {
- blockDevice[i]["uuid"] = bd.UUID
- }
- if bd.DestinationType != "" {
- blockDevice[i]["destination_type"] = bd.DestinationType
- }
- if bd.GuestFormat != "" {
- blockDevice[i]["guest_format"] = bd.GuestFormat
- }
-
+ blockDevice[i] = b
}
serverMap["block_device_mapping_v2"] = blockDevice
@@ -104,21 +80,14 @@
// Create requests the creation of a server from the given block device mapping.
func Create(client *gophercloud.ServiceClient, opts servers.CreateOptsBuilder) servers.CreateResult {
- var res servers.CreateResult
-
- reqBody, err := opts.ToServerCreateMap()
+ var r servers.CreateResult
+ b, err := opts.ToServerCreateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- // Delete imageName and flavorName that come from ToServerCreateMap().
- // As of Liberty, Boot From Volume is failing if they are passed.
- delete(reqBody["server"].(map[string]interface{}), "imageName")
- delete(reqBody["server"].(map[string]interface{}), "flavorName")
-
- _, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200, 202},
})
- return res
+ return r
}
diff --git a/openstack/compute/v2/extensions/bootfromvolume/requests_test.go b/openstack/compute/v2/extensions/bootfromvolume/requests_test.go
index 2359a77..d85070d 100644
--- a/openstack/compute/v2/extensions/bootfromvolume/requests_test.go
+++ b/openstack/compute/v2/extensions/bootfromvolume/requests_test.go
@@ -18,10 +18,11 @@
CreateOptsBuilder: base,
BlockDevice: []BlockDevice{
BlockDevice{
- UUID: "123456",
- SourceType: Image,
- DestinationType: "volume",
- VolumeSize: 10,
+ UUID: "123456",
+ SourceType: Image,
+ DestinationType: "volume",
+ VolumeSize: 10,
+ DeleteOnTermination: false,
},
},
}
@@ -37,9 +38,9 @@
"uuid":"123456",
"source_type":"image",
"destination_type":"volume",
- "boot_index": "0",
- "delete_on_termination": "false",
- "volume_size": "10"
+ "boot_index": 0,
+ "delete_on_termination": false,
+ "volume_size": 10
}
]
}
@@ -94,28 +95,28 @@
"flavorRef": "performance1-1",
"block_device_mapping_v2":[
{
- "boot_index": "0",
- "delete_on_termination": "true",
+ "boot_index": 0,
+ "delete_on_termination": true,
"destination_type":"local",
"source_type":"image",
"uuid":"123456",
- "volume_size": "0"
+ "volume_size": 0
},
{
- "boot_index": "-1",
- "delete_on_termination": "true",
+ "boot_index": -1,
+ "delete_on_termination": true,
"destination_type":"local",
"guest_format":"ext4",
"source_type":"blank",
- "volume_size": "1"
+ "volume_size": 1
},
{
- "boot_index": "-1",
- "delete_on_termination": "true",
+ "boot_index": -1,
+ "delete_on_termination": true,
"destination_type":"local",
"guest_format":"ext4",
"source_type":"blank",
- "volume_size": "1"
+ "volume_size": 1
}
]
}
diff --git a/openstack/compute/v2/extensions/defsecrules/requests.go b/openstack/compute/v2/extensions/defsecrules/requests.go
index 5e2d686..62c112e 100644
--- a/openstack/compute/v2/extensions/defsecrules/requests.go
+++ b/openstack/compute/v2/extensions/defsecrules/requests.go
@@ -7,24 +7,19 @@
// List will return a collection of default rules.
func List(client *gophercloud.ServiceClient) pagination.Pager {
- createPage := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, rootURL(client), func(r pagination.PageResult) pagination.Page {
return DefaultRulePage{pagination.SinglePageBase(r)}
- }
-
- return pagination.NewPager(client, rootURL(client), createPage)
+ })
}
// CreateOpts represents the configuration for adding a new default rule.
type CreateOpts struct {
- // Required - the lower bound of the port range that will be opened.
- FromPort int `json:"from_port"`
-
- // Required - the upper bound of the port range that will be opened.
- ToPort int `json:"to_port"`
-
- // Required - the protocol type that will be allowed, e.g. TCP.
- IPProtocol string `json:"ip_protocol"`
-
+ // The lower bound of the port range that will be opened.
+ FromPort int `json:"from_port" required:"true"`
+ // The upper bound of the port range that will be opened.
+ ToPort int `json:"to_port" required:"true"`
+ // The protocol type that will be allowed, e.g. TCP.
+ IPProtocol string `json:"ip_protocol" required:"true"`
// ONLY required if FromGroupID is blank. This represents the IP range that
// will be the source of network traffic to your security group. Use
// 0.0.0.0/0 to allow all IP addresses.
@@ -38,68 +33,33 @@
// ToRuleCreateMap builds the create rule options into a serializable format.
func (opts CreateOpts) ToRuleCreateMap() (map[string]interface{}, error) {
- if opts.FromPort == 0 {
- err := gophercloud.ErrMissingInput{}
- err.Function = "defsecrules.ToRuleCreateMap"
- err.Argument = "defsecrules.CreateOpts.FromPort"
- return nil, err
- }
- if opts.ToPort == 0 {
- err := gophercloud.ErrMissingInput{}
- err.Function = "defsecrules.ToRuleCreateMap"
- err.Argument = "defsecrules.CreateOpts.ToPort"
- return nil, err
- }
- if opts.IPProtocol == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "defsecrules.ToRuleCreateMap"
- err.Argument = "defsecrules.CreateOpts.IPProtocol"
- return nil, err
- }
- if opts.CIDR == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "defsecrules.ToRuleCreateMap"
- err.Argument = "defsecrules.CreateOpts.CIDR"
- return nil, err
- }
-
- rule := make(map[string]interface{})
-
- rule["from_port"] = opts.FromPort
- rule["to_port"] = opts.ToPort
- rule["ip_protocol"] = opts.IPProtocol
- rule["cidr"] = opts.CIDR
-
- return map[string]interface{}{"security_group_default_rule": rule}, nil
+ return gophercloud.BuildRequestBody(opts, "security_group_default_rule")
}
// Create is the operation responsible for creating a new default rule.
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
- var result CreateResult
-
- reqBody, err := opts.ToRuleCreateMap()
+ var r CreateResult
+ b, err := opts.ToRuleCreateMap()
if err != nil {
- result.Err = err
- return result
+ r.Err = err
+ return r
}
-
- _, result.Err = client.Post(rootURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Post(rootURL(client), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
-
- return result
+ return r
}
// Get will return details for a particular default rule.
func Get(client *gophercloud.ServiceClient, id string) GetResult {
- var result GetResult
- _, result.Err = client.Get(resourceURL(client, id), &result.Body, nil)
- return result
+ var r GetResult
+ _, r.Err = client.Get(resourceURL(client, id), &r.Body, nil)
+ return r
}
// Delete will permanently delete a default rule from the project.
func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
- var result gophercloud.ErrResult
- _, result.Err = client.Delete(resourceURL(client, id), nil)
- return result
+ var r gophercloud.ErrResult
+ _, r.Err = client.Delete(resourceURL(client, id), nil)
+ return r
}
diff --git a/openstack/compute/v2/extensions/diskconfig/requests.go b/openstack/compute/v2/extensions/diskconfig/requests.go
index 19798d7..41d04b9 100644
--- a/openstack/compute/v2/extensions/diskconfig/requests.go
+++ b/openstack/compute/v2/extensions/diskconfig/requests.go
@@ -50,16 +50,14 @@
// RebuildOptsExt adds a DiskConfig option to the base RebuildOpts.
type RebuildOptsExt struct {
servers.RebuildOptsBuilder
-
- // DiskConfig [optional] controls how the rebuilt server's disk is partitioned.
- DiskConfig DiskConfig
+ // DiskConfig controls how the rebuilt server's disk is partitioned.
+ DiskConfig DiskConfig `json:"OS-DCF:diskConfig,omitempty"`
}
// ToServerRebuildMap adds the diskconfig option to the base server rebuild options.
func (opts RebuildOptsExt) ToServerRebuildMap() (map[string]interface{}, error) {
if opts.DiskConfig != Auto && opts.DiskConfig != Manual {
err := gophercloud.ErrInvalidInput{}
- err.Function = "diskconfig.ToServerRebuildMap"
err.Argument = "diskconfig.RebuildOptsExt.DiskConfig"
err.Info = "Must be either diskconfig.Auto or diskconfig.Manual"
return nil, err
@@ -88,7 +86,6 @@
func (opts ResizeOptsExt) ToServerResizeMap() (map[string]interface{}, error) {
if opts.DiskConfig != Auto && opts.DiskConfig != Manual {
err := gophercloud.ErrInvalidInput{}
- err.Function = "diskconfig.ToServerResizeMap"
err.Argument = "diskconfig.ResizeOptsExt.DiskConfig"
err.Info = "Must be either diskconfig.Auto or diskconfig.Manual"
return nil, err
diff --git a/openstack/compute/v2/extensions/floatingips/requests.go b/openstack/compute/v2/extensions/floatingips/requests.go
index 00b2520..8137d76 100644
--- a/openstack/compute/v2/extensions/floatingips/requests.go
+++ b/openstack/compute/v2/extensions/floatingips/requests.go
@@ -21,158 +21,97 @@
// CreateOpts specifies a Floating IP allocation request
type CreateOpts struct {
// Pool is the pool of floating IPs to allocate one from
- Pool string
-}
-
-// AssociateOpts specifies the required information to associate or disassociate a floating IP to an instance
-type AssociateOpts struct {
- // ServerID is the UUID of the server
- ServerID string
-
- // FixedIP is an optional fixed IP address of the server
- FixedIP string
-
- // FloatingIP is the floating IP to associate with an instance
- FloatingIP string
+ Pool string `json:"pool" required:"true"`
}
// ToFloatingIPCreateMap constructs a request body from CreateOpts.
func (opts CreateOpts) ToFloatingIPCreateMap() (map[string]interface{}, error) {
- if opts.Pool == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "floatingips.ToFloatingIPCreateMap"
- err.Argument = "floatingips.CreateOpts.Pool"
- return nil, err
- }
-
- return map[string]interface{}{"pool": opts.Pool}, nil
-}
-
-// ToAssociateMap constructs a request body from AssociateOpts.
-func (opts AssociateOpts) ToAssociateMap() (map[string]interface{}, error) {
- if opts.ServerID == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "floatingips.ToAssociateMap"
- err.Argument = "floatingips.AssociateOpts.ServerID"
- return nil, err
- }
-
- if opts.FloatingIP == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "floatingips.ToAssociateMap"
- err.Argument = "floatingips.AssociateOpts.FloatingIP"
- return nil, err
- }
-
- associateInfo := map[string]interface{}{
- "serverId": opts.ServerID,
- "floatingIp": opts.FloatingIP,
- "fixedIp": opts.FixedIP,
- }
-
- return associateInfo, nil
-
+ return gophercloud.BuildRequestBody(opts, "")
}
// Create requests the creation of a new floating IP
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
- var res CreateResult
-
- reqBody, err := opts.ToFloatingIPCreateMap()
+ var r CreateResult
+ b, err := opts.ToFloatingIPCreateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- _, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
- return res
+ return r
}
// Get returns data about a previously created FloatingIP.
func Get(client *gophercloud.ServiceClient, id string) GetResult {
- var res GetResult
- _, res.Err = client.Get(getURL(client, id), &res.Body, nil)
- return res
+ var r GetResult
+ _, r.Err = client.Get(getURL(client, id), &r.Body, nil)
+ return r
}
// Delete requests the deletion of a previous allocated FloatingIP.
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
- var res DeleteResult
- _, res.Err = client.Delete(deleteURL(client, id), nil)
- return res
+ var r DeleteResult
+ _, r.Err = client.Delete(deleteURL(client, id), nil)
+ return r
}
-// association / disassociation
+// AssociateOptsBuilder is the interface types must satfisfy to be used as
+// Associate options
+type AssociateOptsBuilder interface {
+ ToFloatingIPAssociateMap() (map[string]interface{}, error)
+}
-// Associate pairs an allocated floating IP with an instance
-// Deprecated. Use AssociateInstance.
-func Associate(client *gophercloud.ServiceClient, serverId, fip string) AssociateResult {
- var res AssociateResult
+// AssociateOpts specifies the required information to associate a floating IP with an instance
+type AssociateOpts struct {
+ // FloatingIP is the floating IP to associate with an instance
+ FloatingIP string `json:"address" required:"true"`
+ // FixedIP is an optional fixed IP address of the server
+ FixedIP string `json:"fixed_address,omitempty"`
+}
- addFloatingIp := make(map[string]interface{})
- addFloatingIp["address"] = fip
- reqBody := map[string]interface{}{"addFloatingIp": addFloatingIp}
-
- _, res.Err = client.Post(associateURL(client, serverId), reqBody, nil, nil)
- return res
+// ToFloatingIPAssociateMap constructs a request body from AssociateOpts.
+func (opts AssociateOpts) ToFloatingIPAssociateMap() (map[string]interface{}, error) {
+ return gophercloud.BuildRequestBody(opts, "addFloatingIp")
}
// AssociateInstance pairs an allocated floating IP with an instance.
-func AssociateInstance(client *gophercloud.ServiceClient, opts AssociateOpts) AssociateResult {
- var res AssociateResult
-
- associateInfo, err := opts.ToAssociateMap()
+func AssociateInstance(client *gophercloud.ServiceClient, serverID string, opts AssociateOptsBuilder) AssociateResult {
+ var r AssociateResult
+ b, err := opts.ToFloatingIPAssociateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- addFloatingIp := make(map[string]interface{})
- addFloatingIp["address"] = associateInfo["floatingIp"].(string)
-
- // fixedIp is not required
- if associateInfo["fixedIp"] != "" {
- addFloatingIp["fixed_address"] = associateInfo["fixedIp"].(string)
- }
-
- serverId := associateInfo["serverId"].(string)
-
- reqBody := map[string]interface{}{"addFloatingIp": addFloatingIp}
- _, res.Err = client.Post(associateURL(client, serverId), reqBody, nil, nil)
- return res
+ _, r.Err = client.Post(associateURL(client, serverID), b, nil, nil)
+ return r
}
-// Disassociate decouples an allocated floating IP from an instance
-// Deprecated. Use DisassociateInstance.
-func Disassociate(client *gophercloud.ServiceClient, serverId, fip string) DisassociateResult {
- var res DisassociateResult
+// DisassociateOptsBuilder is the interface types must satfisfy to be used as
+// Disassociate options
+type DisassociateOptsBuilder interface {
+ ToFloatingIPDisassociateMap() (map[string]interface{}, error)
+}
- removeFloatingIp := make(map[string]interface{})
- removeFloatingIp["address"] = fip
- reqBody := map[string]interface{}{"removeFloatingIp": removeFloatingIp}
+// DisassociateOpts specifies the required information to disassociate a floating IP with an instance
+type DisassociateOpts struct {
+ FloatingIP string `json:"address" required:"true"`
+}
- _, res.Err = client.Post(disassociateURL(client, serverId), reqBody, nil, nil)
- return res
+// ToFloatingIPDisassociateMap constructs a request body from AssociateOpts.
+func (opts DisassociateOpts) ToFloatingIPDisassociateMap() (map[string]interface{}, error) {
+ return gophercloud.BuildRequestBody(opts, "removeFloatingIp")
}
// DisassociateInstance decouples an allocated floating IP from an instance
-func DisassociateInstance(client *gophercloud.ServiceClient, opts AssociateOpts) DisassociateResult {
- var res DisassociateResult
-
- associateInfo, err := opts.ToAssociateMap()
+func DisassociateInstance(client *gophercloud.ServiceClient, serverID string, opts DisassociateOptsBuilder) DisassociateResult {
+ var r DisassociateResult
+ b, err := opts.ToFloatingIPDisassociateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- removeFloatingIp := make(map[string]interface{})
- removeFloatingIp["address"] = associateInfo["floatingIp"].(string)
- reqBody := map[string]interface{}{"removeFloatingIp": removeFloatingIp}
-
- serverId := associateInfo["serverId"].(string)
-
- _, res.Err = client.Post(disassociateURL(client, serverId), reqBody, nil, nil)
- return res
+ _, r.Err = client.Post(disassociateURL(client, serverID), b, nil, nil)
+ return r
}
diff --git a/openstack/compute/v2/extensions/floatingips/requests_test.go b/openstack/compute/v2/extensions/floatingips/requests_test.go
index 705c92f..f0e9560 100644
--- a/openstack/compute/v2/extensions/floatingips/requests_test.go
+++ b/openstack/compute/v2/extensions/floatingips/requests_test.go
@@ -57,28 +57,16 @@
th.AssertNoErr(t, err)
}
-func TestAssociateDeprecated(t *testing.T) {
- th.SetupHTTP()
- defer th.TeardownHTTP()
- HandleAssociateSuccessfully(t)
- serverId := "4d8c3732-a248-40ed-bebc-539a6ffd25c0"
- fip := "10.10.10.2"
-
- err := Associate(client.ServiceClient(), serverId, fip).ExtractErr()
- th.AssertNoErr(t, err)
-}
-
func TestAssociate(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
HandleAssociateSuccessfully(t)
associateOpts := AssociateOpts{
- ServerID: "4d8c3732-a248-40ed-bebc-539a6ffd25c0",
FloatingIP: "10.10.10.2",
}
- err := AssociateInstance(client.ServiceClient(), associateOpts).ExtractErr()
+ err := AssociateInstance(client.ServiceClient(), "4d8c3732-a248-40ed-bebc-539a6ffd25c0", associateOpts).ExtractErr()
th.AssertNoErr(t, err)
}
@@ -88,23 +76,11 @@
HandleAssociateFixedSuccessfully(t)
associateOpts := AssociateOpts{
- ServerID: "4d8c3732-a248-40ed-bebc-539a6ffd25c0",
FloatingIP: "10.10.10.2",
FixedIP: "166.78.185.201",
}
- err := AssociateInstance(client.ServiceClient(), associateOpts).ExtractErr()
- th.AssertNoErr(t, err)
-}
-
-func TestDisassociateDeprecated(t *testing.T) {
- th.SetupHTTP()
- defer th.TeardownHTTP()
- HandleDisassociateSuccessfully(t)
- serverId := "4d8c3732-a248-40ed-bebc-539a6ffd25c0"
- fip := "10.10.10.2"
-
- err := Disassociate(client.ServiceClient(), serverId, fip).ExtractErr()
+ err := AssociateInstance(client.ServiceClient(), "4d8c3732-a248-40ed-bebc-539a6ffd25c0", associateOpts).ExtractErr()
th.AssertNoErr(t, err)
}
@@ -113,11 +89,10 @@
defer th.TeardownHTTP()
HandleDisassociateSuccessfully(t)
- associateOpts := AssociateOpts{
- ServerID: "4d8c3732-a248-40ed-bebc-539a6ffd25c0",
+ disassociateOpts := DisassociateOpts{
FloatingIP: "10.10.10.2",
}
- err := DisassociateInstance(client.ServiceClient(), associateOpts).ExtractErr()
+ err := DisassociateInstance(client.ServiceClient(), "4d8c3732-a248-40ed-bebc-539a6ffd25c0", disassociateOpts).ExtractErr()
th.AssertNoErr(t, err)
}
diff --git a/openstack/compute/v2/extensions/keypairs/requests.go b/openstack/compute/v2/extensions/keypairs/requests.go
index b9b32ee..2a01084 100644
--- a/openstack/compute/v2/extensions/keypairs/requests.go
+++ b/openstack/compute/v2/extensions/keypairs/requests.go
@@ -45,59 +45,43 @@
// CreateOpts specifies keypair creation or import parameters.
type CreateOpts struct {
- // Name [required] is a friendly name to refer to this KeyPair in other services.
- Name string
-
+ // Name is a friendly name to refer to this KeyPair in other services.
+ Name string `json:"name" required:"true"`
// PublicKey [optional] is a pregenerated OpenSSH-formatted public key. If provided, this key
// will be imported and no new key will be created.
- PublicKey string
+ PublicKey string `json:"public_key,omitempty"`
}
// ToKeyPairCreateMap constructs a request body from CreateOpts.
func (opts CreateOpts) ToKeyPairCreateMap() (map[string]interface{}, error) {
- if opts.Name == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "keypairs.ToKeyPairCreateMap"
- err.Argument = "keypairs.CreateOpts.Name"
- return nil, err
- }
-
- keypair := make(map[string]interface{})
- keypair["name"] = opts.Name
- if opts.PublicKey != "" {
- keypair["public_key"] = opts.PublicKey
- }
-
- return map[string]interface{}{"keypair": keypair}, nil
+ return gophercloud.BuildRequestBody(opts, "keypair")
}
// Create requests the creation of a new keypair on the server, or to import a pre-existing
// keypair.
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
- var res CreateResult
-
- reqBody, err := opts.ToKeyPairCreateMap()
+ var r CreateResult
+ b, err := opts.ToKeyPairCreateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- _, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
- return res
+ return r
}
// Get returns public data about a previously uploaded KeyPair.
func Get(client *gophercloud.ServiceClient, name string) GetResult {
- var res GetResult
- _, res.Err = client.Get(getURL(client, name), &res.Body, nil)
- return res
+ var r GetResult
+ _, r.Err = client.Get(getURL(client, name), &r.Body, nil)
+ return r
}
// Delete requests the deletion of a previous stored KeyPair from the server.
func Delete(client *gophercloud.ServiceClient, name string) DeleteResult {
- var res DeleteResult
- _, res.Err = client.Delete(deleteURL(client, name), nil)
- return res
+ var r DeleteResult
+ _, r.Err = client.Delete(deleteURL(client, name), nil)
+ return r
}
diff --git a/openstack/compute/v2/extensions/networks/requests.go b/openstack/compute/v2/extensions/networks/requests.go
index a505733..6f0f182 100644
--- a/openstack/compute/v2/extensions/networks/requests.go
+++ b/openstack/compute/v2/extensions/networks/requests.go
@@ -7,16 +7,14 @@
// List returns a Pager that allows you to iterate over a collection of Network.
func List(client *gophercloud.ServiceClient) pagination.Pager {
- url := listURL(client)
- createPage := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
return NetworkPage{pagination.SinglePageBase(r)}
- }
- return pagination.NewPager(client, url, createPage)
+ })
}
// Get returns data about a previously created Network.
func Get(client *gophercloud.ServiceClient, id string) GetResult {
- var res GetResult
- _, res.Err = client.Get(getURL(client, id), &res.Body, nil)
- return res
+ var r GetResult
+ _, r.Err = client.Get(getURL(client, id), &r.Body, nil)
+ return r
}
diff --git a/openstack/compute/v2/extensions/schedulerhints/requests.go b/openstack/compute/v2/extensions/schedulerhints/requests.go
index 5713e72..1e06b46 100644
--- a/openstack/compute/v2/extensions/schedulerhints/requests.go
+++ b/openstack/compute/v2/extensions/schedulerhints/requests.go
@@ -14,33 +14,28 @@
type SchedulerHints struct {
// Group specifies a Server Group to place the instance in.
Group string
-
// DifferentHost will place the instance on a compute node that does not
// host the given instances.
DifferentHost []string
-
// SameHost will place the instance on a compute node that hosts the given
// instances.
SameHost []string
-
// Query is a conditional statement that results in compute nodes able to
// host the instance.
Query []interface{}
-
// TargetCell specifies a cell name where the instance will be placed.
- TargetCell string
-
+ TargetCell string `json:"target_cell,omitempty"`
// BuildNearHostIP specifies a subnet of compute nodes to host the instance.
BuildNearHostIP string
}
-// SchedulerHintsBuilder builds the scheduler hints into a serializable format.
-type SchedulerHintsBuilder interface {
- ToServerSchedulerHintsMap() (map[string]interface{}, error)
+// CreateOptsBuilder builds the scheduler hints into a serializable format.
+type CreateOptsBuilder interface {
+ ToServerSchedulerHintsCreateMap() (map[string]interface{}, error)
}
// ToServerSchedulerHintsMap builds the scheduler hints into a serializable format.
-func (opts SchedulerHints) ToServerSchedulerHintsMap() (map[string]interface{}, error) {
+func (opts SchedulerHints) ToServerSchedulerHintsCreateMap() (map[string]interface{}, error) {
sh := make(map[string]interface{})
uuidRegex, _ := regexp.Compile("^[a-z0-9]{8}-[a-z0-9]{4}-[1-5][a-z0-9]{3}-[a-z0-9]{4}-[a-z0-9]{12}$")
@@ -48,7 +43,6 @@
if opts.Group != "" {
if !uuidRegex.MatchString(opts.Group) {
err := gophercloud.ErrInvalidInput{}
- err.Function = "schedulerhints.ToServerSchedulerHintsMap"
err.Argument = "schedulerhints.SchedulerHints.Group"
err.Value = opts.Group
err.Info = "Group must be a UUID"
@@ -61,7 +55,6 @@
for _, diffHost := range opts.DifferentHost {
if !uuidRegex.MatchString(diffHost) {
err := gophercloud.ErrInvalidInput{}
- err.Function = "schedulerhints.ToServerSchedulerHintsMap"
err.Argument = "schedulerhints.SchedulerHints.DifferentHost"
err.Value = opts.DifferentHost
err.Info = "The hosts must be in UUID format."
@@ -75,7 +68,6 @@
for _, sameHost := range opts.SameHost {
if !uuidRegex.MatchString(sameHost) {
err := gophercloud.ErrInvalidInput{}
- err.Function = "schedulerhints.ToServerSchedulerHintsMap"
err.Argument = "schedulerhints.SchedulerHints.SameHost"
err.Value = opts.SameHost
err.Info = "The hosts must be in UUID format."
@@ -99,7 +91,6 @@
if len(opts.Query) > 0 {
if len(opts.Query) < 3 {
err := gophercloud.ErrInvalidInput{}
- err.Function = "schedulerhints.ToServerSchedulerHintsMap"
err.Argument = "schedulerhints.SchedulerHints.Query"
err.Value = opts.Query
err.Info = "Must be a conditional statement in the format of [op,variable,value]"
@@ -115,7 +106,6 @@
if opts.BuildNearHostIP != "" {
if _, _, err := net.ParseCIDR(opts.BuildNearHostIP); err != nil {
err := gophercloud.ErrInvalidInput{}
- err.Function = "schedulerhints.ToServerSchedulerHintsMap"
err.Argument = "schedulerhints.SchedulerHints.BuildNearHostIP"
err.Value = opts.BuildNearHostIP
err.Info = "Must be a valid subnet in the form 192.168.1.1/24"
@@ -132,9 +122,8 @@
// CreateOptsExt adds a SchedulerHints option to the base CreateOpts.
type CreateOptsExt struct {
servers.CreateOptsBuilder
-
// SchedulerHints provides a set of hints to the scheduler.
- SchedulerHints SchedulerHintsBuilder
+ SchedulerHints CreateOptsBuilder
}
// ToServerCreateMap adds the SchedulerHints option to the base server creation options.
@@ -144,7 +133,7 @@
return nil, err
}
- schedulerHints, err := opts.SchedulerHints.ToServerSchedulerHintsMap()
+ schedulerHints, err := opts.SchedulerHints.ToServerSchedulerHintsCreateMap()
if err != nil {
return nil, err
}
diff --git a/openstack/compute/v2/extensions/secgroups/requests.go b/openstack/compute/v2/extensions/secgroups/requests.go
index a0bb025..48ff698 100644
--- a/openstack/compute/v2/extensions/secgroups/requests.go
+++ b/openstack/compute/v2/extensions/secgroups/requests.go
@@ -6,11 +6,9 @@
)
func commonList(client *gophercloud.ServiceClient, url string) pagination.Pager {
- createPage := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
return SecurityGroupPage{pagination.SinglePageBase(r)}
- }
-
- return pagination.NewPager(client, url, createPage)
+ })
}
// List will return a collection of all the security groups for a particular
@@ -29,11 +27,10 @@
// security groups. It therefore represents the mutable attributes of a
// security group.
type GroupOpts struct {
- // Required - the name of your security group.
- Name string `json:"name"`
-
- // Required - the description of your security group.
- Description string `json:"description"`
+ // the name of your security group.
+ Name string `json:"name" required:"true"`
+ // the description of your security group.
+ Description string `json:"description" required:"true"`
}
// CreateOpts is the struct responsible for creating a security group.
@@ -46,42 +43,21 @@
// ToSecGroupCreateMap builds the create options into a serializable format.
func (opts CreateOpts) ToSecGroupCreateMap() (map[string]interface{}, error) {
- sg := make(map[string]interface{})
-
- if opts.Name == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "secgroups.ToSecGroupCreateMap"
- err.Argument = "secgroups.CreateOpts.Name"
- return nil, err
- }
- if opts.Description == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "secgroups.ToSecGroupCreateMap"
- err.Argument = "secgroups.CreateOpts.Description"
- return nil, err
- }
-
- sg["name"] = opts.Name
- sg["description"] = opts.Description
-
- return map[string]interface{}{"security_group": sg}, nil
+ return gophercloud.BuildRequestBody(opts, "security_group")
}
// Create will create a new security group.
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
- var result CreateResult
-
- reqBody, err := opts.ToSecGroupCreateMap()
+ var r CreateResult
+ b, err := opts.ToSecGroupCreateMap()
if err != nil {
- result.Err = err
- return result
+ r.Err = err
+ return r
}
-
- _, result.Err = client.Post(rootURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Post(rootURL(client), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
-
- return result
+ return r
}
// UpdateOpts is the struct responsible for updating an existing security group.
@@ -94,79 +70,53 @@
// ToSecGroupUpdateMap builds the update options into a serializable format.
func (opts UpdateOpts) ToSecGroupUpdateMap() (map[string]interface{}, error) {
- sg := make(map[string]interface{})
-
- if opts.Name == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "secgroups.ToSecGroupUpdateMap"
- err.Argument = "secgroups.UpdateOpts.Name"
- return nil, err
- }
- if opts.Description == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "secgroups.ToSecGroupUpdateMap"
- err.Argument = "secgroups.UpdateOpts.Description"
- return nil, err
- }
-
- sg["name"] = opts.Name
- sg["description"] = opts.Description
-
- return map[string]interface{}{"security_group": sg}, nil
+ return gophercloud.BuildRequestBody(opts, "security_group")
}
// Update will modify the mutable properties of a security group, notably its
// name and description.
func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
- var result UpdateResult
-
- reqBody, err := opts.ToSecGroupUpdateMap()
+ var r UpdateResult
+ b, err := opts.ToSecGroupUpdateMap()
if err != nil {
- result.Err = err
- return result
+ r.Err = err
+ return r
}
-
- _, result.Err = client.Put(resourceURL(client, id), reqBody, &result.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Put(resourceURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
-
- return result
+ return r
}
// Get will return details for a particular security group.
func Get(client *gophercloud.ServiceClient, id string) GetResult {
- var result GetResult
- _, result.Err = client.Get(resourceURL(client, id), &result.Body, nil)
- return result
+ var r GetResult
+ _, r.Err = client.Get(resourceURL(client, id), &r.Body, nil)
+ return r
}
// Delete will permanently delete a security group from the project.
func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
- var result gophercloud.ErrResult
- _, result.Err = client.Delete(resourceURL(client, id), nil)
- return result
+ var r gophercloud.ErrResult
+ _, r.Err = client.Delete(resourceURL(client, id), nil)
+ return r
}
// CreateRuleOpts represents the configuration for adding a new rule to an
// existing security group.
type CreateRuleOpts struct {
// Required - the ID of the group that this rule will be added to.
- ParentGroupID string `json:"parent_group_id"`
-
+ ParentGroupID string `json:"parent_group_id" required:"true"`
// Required - the lower bound of the port range that will be opened.
- FromPort int `json:"from_port"`
-
+ FromPort int `json:"from_port" required:"true"`
// Required - the upper bound of the port range that will be opened.
- ToPort int `json:"to_port"`
-
+ ToPort int `json:"to_port" required:"true"`
// Required - the protocol type that will be allowed, e.g. TCP.
- IPProtocol string `json:"ip_protocol"`
-
+ IPProtocol string `json:"ip_protocol" required:"true"`
// ONLY required if FromGroupID is blank. This represents the IP range that
// will be the source of network traffic to your security group. Use
// 0.0.0.0/0 to allow all IP addresses.
CIDR string `json:"cidr,omitempty"`
-
// ONLY required if CIDR is blank. This value represents the ID of a group
// that forwards traffic to the parent group. So, instead of accepting
// network traffic from an entire IP range, you can instead refine the
@@ -181,78 +131,30 @@
// ToRuleCreateMap builds the create rule options into a serializable format.
func (opts CreateRuleOpts) ToRuleCreateMap() (map[string]interface{}, error) {
- if opts.ParentGroupID == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "secgroups.ToRuleCreateMap"
- err.Argument = "secgroups.CreateRuleOpts.ParentGroupID"
- return nil, err
- }
- if opts.FromPort == 0 {
- err := gophercloud.ErrMissingInput{}
- err.Function = "secgroups.ToRuleCreateMap"
- err.Argument = "secgroups.CreateRuleOpts.FromPort"
- return nil, err
- }
- if opts.ToPort == 0 {
- err := gophercloud.ErrMissingInput{}
- err.Function = "secgroups.ToRuleCreateMap"
- err.Argument = "secgroups.CreateRuleOpts.ToPort"
- return nil, err
- }
- if opts.IPProtocol == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "secgroups.ToRuleCreateMap"
- err.Argument = "secgroups.CreateRuleOpts.IPProtocol"
- return nil, err
- }
- if opts.CIDR == "" && opts.FromGroupID == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "secgroups.ToRuleCreateMap"
- err.Argument = "secgroups.CreateRuleOpts.CIDR/secgroups.CreateRuleOpts.FromGroupID"
- return nil, err
- }
-
- rule := make(map[string]interface{})
-
- rule["parent_group_id"] = opts.ParentGroupID
- rule["from_port"] = opts.FromPort
- rule["to_port"] = opts.ToPort
- rule["ip_protocol"] = opts.IPProtocol
-
- if opts.CIDR != "" {
- rule["cidr"] = opts.CIDR
- }
- if opts.FromGroupID != "" {
- rule["group_id"] = opts.FromGroupID
- }
-
- return map[string]interface{}{"security_group_rule": rule}, nil
+ return gophercloud.BuildRequestBody(opts, "security_group_rule")
}
// CreateRule will add a new rule to an existing security group (whose ID is
// specified in CreateRuleOpts). You have the option of controlling inbound
// traffic from either an IP range (CIDR) or from another security group.
func CreateRule(client *gophercloud.ServiceClient, opts CreateRuleOptsBuilder) CreateRuleResult {
- var result CreateRuleResult
-
- reqBody, err := opts.ToRuleCreateMap()
+ var r CreateRuleResult
+ b, err := opts.ToRuleCreateMap()
if err != nil {
- result.Err = err
- return result
+ r.Err = err
+ return r
}
-
- _, result.Err = client.Post(rootRuleURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Post(rootRuleURL(client), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
-
- return result
+ return r
}
// DeleteRule will permanently delete a rule from a security group.
func DeleteRule(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
- var result gophercloud.ErrResult
- _, result.Err = client.Delete(resourceRuleURL(client, id), nil)
- return result
+ var r gophercloud.ErrResult
+ _, r.Err = client.Delete(resourceRuleURL(client, id), nil)
+ return r
}
func actionMap(prefix, groupName string) map[string]map[string]string {
@@ -261,17 +163,17 @@
}
}
-// AddServerToGroup will associate a server and a security group, enforcing the
+// AddServer will associate a server and a security group, enforcing the
// rules of the group on the server.
-func AddServerToGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
- var result gophercloud.ErrResult
- _, result.Err = client.Post(serverActionURL(client, serverID), actionMap("add", groupName), &result.Body, nil)
- return result
+func AddServer(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
+ var r gophercloud.ErrResult
+ _, r.Err = client.Post(serverActionURL(client, serverID), actionMap("add", groupName), &r.Body, nil)
+ return r
}
-// RemoveServerFromGroup will disassociate a server from a security group.
-func RemoveServerFromGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
- var result gophercloud.ErrResult
- _, result.Err = client.Post(serverActionURL(client, serverID), actionMap("remove", groupName), &result.Body, nil)
- return result
+// RemoveServer will disassociate a server from a security group.
+func RemoveServer(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
+ var r gophercloud.ErrResult
+ _, r.Err = client.Post(serverActionURL(client, serverID), actionMap("remove", groupName), &r.Body, nil)
+ return r
}
diff --git a/openstack/compute/v2/extensions/secgroups/requests_test.go b/openstack/compute/v2/extensions/secgroups/requests_test.go
index 59a3898..9496d4a 100644
--- a/openstack/compute/v2/extensions/secgroups/requests_test.go
+++ b/openstack/compute/v2/extensions/secgroups/requests_test.go
@@ -233,7 +233,7 @@
mockAddServerToGroupResponse(t, serverID)
- err := AddServerToGroup(client.ServiceClient(), serverID, "test").ExtractErr()
+ err := AddServer(client.ServiceClient(), serverID, "test").ExtractErr()
th.AssertNoErr(t, err)
}
@@ -243,6 +243,6 @@
mockRemoveServerFromGroupResponse(t, serverID)
- err := RemoveServerFromGroup(client.ServiceClient(), serverID, "test").ExtractErr()
+ err := RemoveServer(client.ServiceClient(), serverID, "test").ExtractErr()
th.AssertNoErr(t, err)
}
diff --git a/openstack/compute/v2/extensions/servergroups/requests.go b/openstack/compute/v2/extensions/servergroups/requests.go
index 212edac..1348cfa 100644
--- a/openstack/compute/v2/extensions/servergroups/requests.go
+++ b/openstack/compute/v2/extensions/servergroups/requests.go
@@ -21,61 +21,40 @@
// CreateOpts specifies a Server Group allocation request
type CreateOpts struct {
// Name is the name of the server group
- Name string
-
+ Name string `json:"name" required:"true"`
// Policies are the server group policies
- Policies []string
+ Policies []string `json:"policies" required:"true"`
}
// ToServerGroupCreateMap constructs a request body from CreateOpts.
func (opts CreateOpts) ToServerGroupCreateMap() (map[string]interface{}, error) {
- if opts.Name == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "servergroups.ToServerGroupCreateMap"
- err.Argument = "servergroups.CreateOpts.Name"
- return nil, err
- }
-
- if len(opts.Policies) < 1 {
- err := gophercloud.ErrMissingInput{}
- err.Function = "servergroups.ToServerGroupCreateMap"
- err.Argument = "servergroups.CreateOpts.Policies"
- return nil, err
- }
-
- serverGroup := make(map[string]interface{})
- serverGroup["name"] = opts.Name
- serverGroup["policies"] = opts.Policies
-
- return map[string]interface{}{"server_group": serverGroup}, nil
+ return gophercloud.BuildRequestBody(opts, "server_group")
}
// Create requests the creation of a new Server Group
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
- var res CreateResult
-
- reqBody, err := opts.ToServerGroupCreateMap()
+ var r CreateResult
+ b, err := opts.ToServerGroupCreateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- _, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
- return res
+ return r
}
// Get returns data about a previously created ServerGroup.
func Get(client *gophercloud.ServiceClient, id string) GetResult {
- var res GetResult
- _, res.Err = client.Get(getURL(client, id), &res.Body, nil)
- return res
+ var r GetResult
+ _, r.Err = client.Get(getURL(client, id), &r.Body, nil)
+ return r
}
// Delete requests the deletion of a previously allocated ServerGroup.
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
- var res DeleteResult
- _, res.Err = client.Delete(deleteURL(client, id), nil)
- return res
+ var r DeleteResult
+ _, r.Err = client.Delete(deleteURL(client, id), nil)
+ return r
}
diff --git a/openstack/compute/v2/extensions/startstop/requests.go b/openstack/compute/v2/extensions/startstop/requests.go
index 8364487..460223a 100644
--- a/openstack/compute/v2/extensions/startstop/requests.go
+++ b/openstack/compute/v2/extensions/startstop/requests.go
@@ -8,16 +8,14 @@
// Start is the operation responsible for starting a Compute server.
func Start(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
- var res gophercloud.ErrResult
- reqBody := map[string]interface{}{"os-start": nil}
- _, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
- return res
+ var r gophercloud.ErrResult
+ _, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"os-start": nil}, nil, nil)
+ return r
}
// Stop is the operation responsible for stopping a Compute server.
func Stop(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
- var res gophercloud.ErrResult
- reqBody := map[string]interface{}{"os-stop": nil}
- _, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
- return res
+ var r gophercloud.ErrResult
+ _, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"os-stop": nil}, nil, nil)
+ return r
}
diff --git a/openstack/compute/v2/extensions/tenantnetworks/requests.go b/openstack/compute/v2/extensions/tenantnetworks/requests.go
index 68159f2..ca33c37 100644
--- a/openstack/compute/v2/extensions/tenantnetworks/requests.go
+++ b/openstack/compute/v2/extensions/tenantnetworks/requests.go
@@ -7,16 +7,14 @@
// List returns a Pager that allows you to iterate over a collection of Network.
func List(client *gophercloud.ServiceClient) pagination.Pager {
- url := listURL(client)
- createPage := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
return NetworkPage{pagination.SinglePageBase(r)}
- }
- return pagination.NewPager(client, url, createPage)
+ })
}
// Get returns data about a previously created Network.
func Get(client *gophercloud.ServiceClient, id string) GetResult {
- var res GetResult
- _, res.Err = client.Get(getURL(client, id), &res.Body, nil)
- return res
+ var r GetResult
+ _, r.Err = client.Get(getURL(client, id), &r.Body, nil)
+ return r
}
diff --git a/openstack/compute/v2/extensions/volumeattach/requests.go b/openstack/compute/v2/extensions/volumeattach/requests.go
index c2bc2ee..c8ef930 100644
--- a/openstack/compute/v2/extensions/volumeattach/requests.go
+++ b/openstack/compute/v2/extensions/volumeattach/requests.go
@@ -6,8 +6,8 @@
)
// List returns a Pager that allows you to iterate over a collection of VolumeAttachments.
-func List(client *gophercloud.ServiceClient, serverId string) pagination.Pager {
- return pagination.NewPager(client, listURL(client, serverId), func(r pagination.PageResult) pagination.Page {
+func List(client *gophercloud.ServiceClient, serverID string) pagination.Pager {
+ return pagination.NewPager(client, listURL(client, serverID), func(r pagination.PageResult) pagination.Page {
return VolumeAttachmentPage{pagination.SinglePageBase(r)}
})
}
@@ -21,56 +21,40 @@
// CreateOpts specifies volume attachment creation or import parameters.
type CreateOpts struct {
// Device is the device that the volume will attach to the instance as. Omit for "auto"
- Device string
-
+ Device string `json:"device,omitempty"`
// VolumeID is the ID of the volume to attach to the instance
- VolumeID string
+ VolumeID string `json:"volumeId" required:"true"`
}
// ToVolumeAttachmentCreateMap constructs a request body from CreateOpts.
func (opts CreateOpts) ToVolumeAttachmentCreateMap() (map[string]interface{}, error) {
- if opts.VolumeID == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "volumeattach.ToVolumeAttachmentCreateMap"
- err.Argument = "volumeattach.CreateOpts.VolumeID"
- return nil, err
- }
-
- volumeAttachment := make(map[string]interface{})
- volumeAttachment["volumeId"] = opts.VolumeID
- if opts.Device != "" {
- volumeAttachment["device"] = opts.Device
- }
-
- return map[string]interface{}{"volumeAttachment": volumeAttachment}, nil
+ return gophercloud.BuildRequestBody(opts, "volumeAttachment")
}
// Create requests the creation of a new volume attachment on the server
-func Create(client *gophercloud.ServiceClient, serverId string, opts CreateOptsBuilder) CreateResult {
- var res CreateResult
-
- reqBody, err := opts.ToVolumeAttachmentCreateMap()
+func Create(client *gophercloud.ServiceClient, serverID string, opts CreateOptsBuilder) CreateResult {
+ var r CreateResult
+ b, err := opts.ToVolumeAttachmentCreateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- _, res.Err = client.Post(createURL(client, serverId), reqBody, &res.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Post(createURL(client, serverID), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
- return res
+ return r
}
// Get returns public data about a previously created VolumeAttachment.
-func Get(client *gophercloud.ServiceClient, serverId, aId string) GetResult {
- var res GetResult
- _, res.Err = client.Get(getURL(client, serverId, aId), &res.Body, nil)
- return res
+func Get(client *gophercloud.ServiceClient, serverID, attachmentID string) GetResult {
+ var r GetResult
+ _, r.Err = client.Get(getURL(client, serverID, attachmentID), &r.Body, nil)
+ return r
}
// Delete requests the deletion of a previous stored VolumeAttachment from the server.
-func Delete(client *gophercloud.ServiceClient, serverId, aId string) DeleteResult {
- var res DeleteResult
- _, res.Err = client.Delete(deleteURL(client, serverId, aId), nil)
- return res
+func Delete(client *gophercloud.ServiceClient, serverID, attachmentID string) DeleteResult {
+ var r DeleteResult
+ _, r.Err = client.Delete(deleteURL(client, serverID, attachmentID), nil)
+ return r
}
diff --git a/openstack/compute/v2/flavors/requests.go b/openstack/compute/v2/flavors/requests.go
index 6e8f003..4f3fc46 100644
--- a/openstack/compute/v2/flavors/requests.go
+++ b/openstack/compute/v2/flavors/requests.go
@@ -34,10 +34,7 @@
// ToFlavorListQuery formats a ListOpts into a query string.
func (opts ListOpts) ToFlavorListQuery() (string, error) {
q, err := gophercloud.BuildQueryString(opts)
- if err != nil {
- return "", err
- }
- return q.String(), nil
+ return q.String(), err
}
// ListDetail instructs OpenStack to provide a list of flavors.
@@ -52,32 +49,23 @@
}
url += query
}
- createPage := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
return FlavorPage{pagination.LinkedPageBase{PageResult: r}}
- }
-
- return pagination.NewPager(client, url, createPage)
+ })
}
// Get instructs OpenStack to provide details on a single flavor, identified by its ID.
// Use ExtractFlavor to convert its result into a Flavor.
func Get(client *gophercloud.ServiceClient, id string) GetResult {
- var res GetResult
- _, res.Err = client.Get(getURL(client, id), &res.Body, nil)
- return res
+ var r GetResult
+ _, r.Err = client.Get(getURL(client, id), &r.Body, nil)
+ return r
}
// IDFromName is a convienience function that returns a flavor's ID given its name.
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
count := 0
id := ""
- if name == "" {
- err := &gophercloud.ErrMissingInput{}
- err.Function = "flavors.IDFromName"
- err.Argument = "name"
- return "", err
- }
-
allPages, err := ListDetail(client, nil).AllPages()
if err != nil {
return "", err
@@ -98,7 +86,6 @@
switch count {
case 0:
err := &gophercloud.ErrResourceNotFound{}
- err.Function = "flavors.IDFromName"
err.ResourceType = "flavor"
err.Name = name
return "", err
@@ -106,7 +93,6 @@
return id, nil
default:
err := &gophercloud.ErrMultipleResourcesFound{}
- err.Function = "flavors.IDFromName"
err.ResourceType = "flavor"
err.Name = name
err.Count = count
diff --git a/openstack/compute/v2/images/requests.go b/openstack/compute/v2/images/requests.go
index 88db657..00461f8 100644
--- a/openstack/compute/v2/images/requests.go
+++ b/openstack/compute/v2/images/requests.go
@@ -32,10 +32,7 @@
// ToImageListQuery formats a ListOpts into a query string.
func (opts ListOpts) ToImageListQuery() (string, error) {
q, err := gophercloud.BuildQueryString(opts)
- if err != nil {
- return "", err
- }
- return q.String(), nil
+ return q.String(), err
}
// ListDetail enumerates the available images.
@@ -48,40 +45,30 @@
}
url += query
}
-
- createPage := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
return ImagePage{pagination.LinkedPageBase{PageResult: r}}
- }
-
- return pagination.NewPager(client, url, createPage)
+ })
}
// Get acquires additional detail about a specific image by ID.
// Use ExtractImage() to interpret the result as an openstack Image.
func Get(client *gophercloud.ServiceClient, id string) GetResult {
- var result GetResult
- _, result.Err = client.Get(getURL(client, id), &result.Body, nil)
- return result
+ var r GetResult
+ _, r.Err = client.Get(getURL(client, id), &r.Body, nil)
+ return r
}
// Delete deletes the specified image ID.
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
- var result DeleteResult
- _, result.Err = client.Delete(deleteURL(client, id), nil)
- return result
+ var r DeleteResult
+ _, r.Err = client.Delete(deleteURL(client, id), nil)
+ return r
}
// IDFromName is a convienience function that returns an image's ID given its name.
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
count := 0
id := ""
- if name == "" {
- err := &gophercloud.ErrMissingInput{}
- err.Function = "images.IDFromName"
- err.Argument = "name"
- return "", err
- }
-
allPages, err := ListDetail(client, nil).AllPages()
if err != nil {
return "", err
@@ -102,7 +89,6 @@
switch count {
case 0:
err := &gophercloud.ErrResourceNotFound{}
- err.Function = "images.IDFromName"
err.ResourceType = "image"
err.Name = name
return "", err
@@ -110,7 +96,6 @@
return id, nil
default:
err := &gophercloud.ErrMultipleResourcesFound{}
- err.Function = "images.IDFromName"
err.ResourceType = "image"
err.Name = name
err.Count = count
diff --git a/openstack/compute/v2/servers/fixtures.go b/openstack/compute/v2/servers/fixtures.go
index 2c22b45..224b996 100644
--- a/openstack/compute/v2/servers/fixtures.go
+++ b/openstack/compute/v2/servers/fixtures.go
@@ -7,6 +7,7 @@
"net/http"
"testing"
+ "github.com/gophercloud/gophercloud"
th "github.com/gophercloud/gophercloud/testhelper"
"github.com/gophercloud/gophercloud/testhelper/client"
)
@@ -349,6 +350,15 @@
}
)
+type CreateOptsWithCustomField struct {
+ CreateOpts
+ Foo string `json:"foo,omitempty"`
+}
+
+func (opts CreateOptsWithCustomField) ToServerCreateMap() (map[string]interface{}, error) {
+ return gophercloud.BuildRequestBody(opts, "server")
+}
+
// HandleServerCreationSuccessfully sets up the test server to respond to a server creation request
// with a given response.
func HandleServerCreationSuccessfully(t *testing.T, response string) {
@@ -369,6 +379,27 @@
})
}
+// HandleServerCreationWithCustomFieldSuccessfully sets up the test server to respond to a server creation request
+// with a given response.
+func HandleServerCreationWithCustomFieldSuccessfully(t *testing.T, response string) {
+ th.Mux.HandleFunc("/servers", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "POST")
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+ th.TestJSONRequest(t, r, `{
+ "server": {
+ "name": "derp",
+ "imageRef": "f90f6034-2570-4974-8351-6b49732ef2eb",
+ "flavorRef": "1",
+ "foo": "bar"
+ }
+ }`)
+
+ w.WriteHeader(http.StatusAccepted)
+ w.Header().Add("Content-Type", "application/json")
+ fmt.Fprintf(w, response)
+ })
+}
+
// HandleServerListSuccessfully sets up the test server to respond to a server List request.
func HandleServerListSuccessfully(t *testing.T) {
th.Mux.HandleFunc("/servers/detail", func(w http.ResponseWriter, r *http.Request) {
@@ -399,7 +430,7 @@
})
}
-// HandleAdminPasswordChangeSuccessfully sets up the test server to respond to a server password
+// HandleServerForceDeletionSuccessfully sets up the test server to respond to a server password
// change request.
func HandleServerForceDeletionSuccessfully(t *testing.T) {
th.Mux.HandleFunc("/servers/asdfasdfasdf/action", func(w http.ResponseWriter, r *http.Request) {
@@ -673,4 +704,3 @@
w.WriteHeader(http.StatusAccepted)
})
}
-
diff --git a/openstack/compute/v2/servers/requests.go b/openstack/compute/v2/servers/requests.go
index 4129471..4257a4a 100644
--- a/openstack/compute/v2/servers/requests.go
+++ b/openstack/compute/v2/servers/requests.go
@@ -55,16 +55,12 @@
// ToServerListQuery formats a ListOpts into a query string.
func (opts ListOpts) ToServerListQuery() (string, error) {
q, err := gophercloud.BuildQueryString(opts)
- if err != nil {
- return "", err
- }
- return q.String(), nil
+ return q.String(), err
}
// List makes a request against the API to list servers accessible to you.
func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
url := listDetailURL(client)
-
if opts != nil {
query, err := opts.ToServerListQuery()
if err != nil {
@@ -72,12 +68,9 @@
}
url += query
}
-
- createPageFn := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
return ServerPage{pagination.LinkedPageBase{PageResult: r}}
- }
-
- return pagination.NewPager(client, url, createPageFn)
+ })
}
// CreateOptsBuilder describes struct types that can be accepted by the Create call.
@@ -189,7 +182,7 @@
// ToServerCreateMap assembles a request body based on the contents of a CreateOpts.
func (opts CreateOpts) ToServerCreateMap() (map[string]interface{}, error) {
- b, err := gophercloud.BuildRequestBody(opts)
+ b, err := gophercloud.BuildRequestBody(opts, "")
if err != nil {
return nil, err
}
@@ -228,13 +221,11 @@
if opts.ImageRef == "" {
if opts.ImageName == "" {
err := ErrNeitherImageIDNorImageNameProvided{}
- err.Function = "servers.CreateOpts.ToServerCreateMap"
err.Argument = "ImageRef/ImageName"
return nil, err
}
if opts.ServiceClient == nil {
err := ErrNoClientProvidedForIDByName{}
- err.Function = "servers.CreateOpts.ToServerCreateMap"
err.Argument = "ServiceClient"
return nil, err
}
@@ -249,14 +240,12 @@
if opts.FlavorRef == "" {
if opts.FlavorName == "" {
err := ErrNeitherFlavorIDNorFlavorNameProvided{}
- err.Function = "servers.CreateOpts.ToServerCreateMap"
err.Argument = "FlavorRef/FlavorName"
return nil, err
}
if opts.ServiceClient == nil {
err := ErrNoClientProvidedForIDByName{}
err.Argument = "ServiceClient"
- err.Function = "servers.CreateOpts.ToServerCreateMap"
return nil, err
}
flavorID, err := flavors.IDFromName(opts.ServiceClient, opts.FlavorName)
@@ -272,13 +261,11 @@
// Create requests a server to be provisioned to the user in the current tenant.
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
var r CreateResult
-
reqBody, err := opts.ToServerCreateMap()
if err != nil {
r.Err = err
return r
}
-
_, r.Err = client.Post(listURL(client), reqBody, &r.Body, nil)
return r
}
@@ -308,42 +295,36 @@
// UpdateOptsBuilder allows extensions to add additional attributes to the Update request.
type UpdateOptsBuilder interface {
- ToServerUpdateMap() map[string]interface{}
+ ToServerUpdateMap() (map[string]interface{}, error)
}
// UpdateOpts specifies the base attributes that may be updated on an existing server.
type UpdateOpts struct {
- // Name [optional] changes the displayed name of the server.
+ // Name changes the displayed name of the server.
// The server host name will *not* change.
// Server names are not constrained to be unique, even within the same tenant.
- Name string
+ Name string `json:"name,omitempty"`
- // AccessIPv4 [optional] provides a new IPv4 address for the instance.
- AccessIPv4 string
+ // AccessIPv4 provides a new IPv4 address for the instance.
+ AccessIPv4 string `json:"accessIPv4,omitempty"`
- // AccessIPv6 [optional] provides a new IPv6 address for the instance.
- AccessIPv6 string
+ // AccessIPv6 provides a new IPv6 address for the instance.
+ AccessIPv6 string `json:"accessIPv6,omitempty"`
}
// ToServerUpdateMap formats an UpdateOpts structure into a request body.
-func (opts UpdateOpts) ToServerUpdateMap() map[string]interface{} {
- server := make(map[string]string)
- if opts.Name != "" {
- server["name"] = opts.Name
- }
- if opts.AccessIPv4 != "" {
- server["accessIPv4"] = opts.AccessIPv4
- }
- if opts.AccessIPv6 != "" {
- server["accessIPv6"] = opts.AccessIPv6
- }
- return map[string]interface{}{"server": server}
+func (opts UpdateOpts) ToServerUpdateMap() (map[string]interface{}, error) {
+ return gophercloud.BuildRequestBody(opts, "server")
}
// Update requests that various attributes of the indicated server be changed.
func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
var r UpdateResult
- b := opts.ToServerUpdateMap()
+ b, err := opts.ToServerUpdateMap()
+ if err != nil {
+ r.Err = err
+ return r
+ }
_, r.Err = client.Put(updateURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
@@ -352,16 +333,13 @@
// ChangeAdminPassword alters the administrator or root password for a specified server.
func ChangeAdminPassword(client *gophercloud.ServiceClient, id, newPassword string) ActionResult {
- var req struct {
- ChangePassword struct {
- AdminPass string `json:"adminPass"`
- } `json:"changePassword"`
- }
-
- req.ChangePassword.AdminPass = newPassword
-
var r ActionResult
- _, r.Err = client.Post(actionURL(client, id), req, nil, nil)
+ b := map[string]interface{}{
+ "changePassword": map[string]string{
+ "adminPass": newPassword,
+ },
+ }
+ _, r.Err = client.Post(actionURL(client, id), b, nil, nil)
return r
}
@@ -377,36 +355,27 @@
PowerCycle = HardReboot
)
+// RebootOptsBuilder is an interface that options must satisfy in order to be
+// used when rebooting a server instance
type RebootOptsBuilder interface {
ToServerRebootMap() (map[string]interface{}, error)
}
+// RebootOpts satisfies the RebootOptsBuilder interface
type RebootOpts struct {
- Type RebootMethod
+ Type RebootMethod `json:"type" required:"true"`
}
+// ToServerRebootMap allows RebootOpts to satisfiy the RebootOptsBuilder
+// interface
func (opts *RebootOpts) ToServerRebootMap() (map[string]interface{}, error) {
- if (opts.Type != SoftReboot) && (opts.Type != HardReboot) {
- err := &gophercloud.ErrInvalidInput{}
- err.Argument = "servers.RebootOpts.Type"
- err.Value = opts.Type
- err.Function = "servers.Reboot"
- return nil, err
- }
-
- reqBody := map[string]interface{}{
- "reboot": map[string]interface{}{
- "type": string(opts.Type),
- },
- }
-
- return reqBody, nil
+ return gophercloud.BuildRequestBody(opts, "reboot")
}
// Reboot requests that a given server reboot.
// Two methods exist for rebooting a server:
//
-// HardReboot (aka PowerCycle) rtarts the server instance by physically cutting power to the machine, or if a VM,
+// HardReboot (aka PowerCycle) starts the server instance by physically cutting power to the machine, or if a VM,
// terminating it at the hypervisor level.
// It's done. Caput. Full stop.
// Then, after a brief while, power is rtored or the VM instance rtarted.
@@ -415,14 +384,12 @@
// E.g., in Linux, asking it to enter runlevel 6, or executing "sudo shutdown -r now", or by asking Windows to rtart the machine.
func Reboot(client *gophercloud.ServiceClient, id string, opts RebootOptsBuilder) ActionResult {
var r ActionResult
-
- reqBody, err := opts.ToServerRebootMap()
+ b, err := opts.ToServerRebootMap()
if err != nil {
r.Err = err
return r
}
-
- _, r.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
+ _, r.Err = client.Post(actionURL(client, id), b, nil, nil)
return r
}
@@ -435,97 +402,64 @@
// RebuildOpts represents the configuration options used in a server rebuild
// operation
type RebuildOpts struct {
- // Required. The ID of the image you want your server to be provisioned on
- ImageID string
-
+ // The server's admin password
+ AdminPass string `json:"adminPass" required:"true"`
+ // The ID of the image you want your server to be provisioned on
+ ImageID string `json:"imageRef"`
+ ImageName string `json:"-"`
+ //ImageName string `json:"-"`
// Name to set the server to
- Name string
-
- // Required. The server's admin password
- AdminPass string
-
+ Name string `json:"name,omitempty"`
// AccessIPv4 [optional] provides a new IPv4 address for the instance.
- AccessIPv4 string
-
+ AccessIPv4 string `json:"accessIPv4,omitempty"`
// AccessIPv6 [optional] provides a new IPv6 address for the instance.
- AccessIPv6 string
-
+ AccessIPv6 string `json:"accessIPv6,omitempty"`
// Metadata [optional] contains key-value pairs (up to 255 bytes each) to attach to the server.
- Metadata map[string]string
-
+ Metadata map[string]string `json:"metadata,omitempty"`
// Personality [optional] includes files to inject into the server at launch.
// Rebuild will base64-encode file contents for you.
- Personality Personality
+ Personality Personality `json:"personality,omitempty"`
+ ServiceClient *gophercloud.ServiceClient `json:"-"`
}
// ToServerRebuildMap formats a RebuildOpts struct into a map for use in JSON
func (opts RebuildOpts) ToServerRebuildMap() (map[string]interface{}, error) {
- var err error
- server := make(map[string]interface{})
-
- if opts.AdminPass == "" {
- err := ErrNoAdminPassProvided{}
- err.Function = "servers.ToServerRebuildMap"
- err.Argument = "AdminPass"
- return nil, err
- }
-
- if opts.ImageID == "" {
- err := ErrNoImageIDProvided{}
- err.Function = "servers.ToServerRebuildMap"
- err.Argument = "ImageID"
- return nil, err
- }
-
+ b, err := gophercloud.BuildRequestBody(opts, "")
if err != nil {
- return server, err
+ return nil, err
}
- server["adminPass"] = opts.AdminPass
- server["imageRef"] = opts.ImageID
-
- if opts.Name != "" {
- server["name"] = opts.Name
+ // If ImageRef isn't provided, use ImageName to ascertain the image ID.
+ if opts.ImageID == "" {
+ if opts.ImageName == "" {
+ err := ErrNeitherImageIDNorImageNameProvided{}
+ err.Argument = "ImageRef/ImageName"
+ return nil, err
+ }
+ if opts.ServiceClient == nil {
+ err := ErrNoClientProvidedForIDByName{}
+ err.Argument = "ServiceClient"
+ return nil, err
+ }
+ imageID, err := images.IDFromName(opts.ServiceClient, opts.ImageName)
+ if err != nil {
+ return nil, err
+ }
+ b["imageRef"] = imageID
}
- if opts.AccessIPv4 != "" {
- server["accessIPv4"] = opts.AccessIPv4
- }
-
- if opts.AccessIPv6 != "" {
- server["accessIPv6"] = opts.AccessIPv6
- }
-
- if opts.Metadata != nil {
- server["metadata"] = opts.Metadata
- }
-
- if len(opts.Personality) > 0 {
- server["personality"] = opts.Personality
- }
-
- return map[string]interface{}{"rebuild": server}, nil
+ return map[string]interface{}{"rebuild": b}, nil
}
// Rebuild will reprovision the server according to the configuration options
// provided in the RebuildOpts struct.
func Rebuild(client *gophercloud.ServiceClient, id string, opts RebuildOptsBuilder) RebuildResult {
var r RebuildResult
-
- if id == "" {
- err := ErrNoIDProvided{}
- err.Function = "servers.Rebuild"
- err.Argument = "id"
- r.Err = err
- return r
- }
-
b, err := opts.ToServerRebuildMap()
if err != nil {
r.Err = err
return r
}
-
_, r.Err = client.Post(actionURL(client, id), b, &r.Body, nil)
return r
}
@@ -539,17 +473,13 @@
// ResizeOpts represents the configuration options used to control a Resize operation.
type ResizeOpts struct {
// FlavorRef is the ID of the flavor you wish your server to become.
- FlavorRef string
+ FlavorRef string `json:"flavorRef" required:"true"`
}
// ToServerResizeMap formats a ResizeOpts as a map that can be used as a JSON request body for the
// Resize request.
func (opts ResizeOpts) ToServerResizeMap() (map[string]interface{}, error) {
- resize := map[string]interface{}{
- "flavorRef": opts.FlavorRef,
- }
-
- return map[string]interface{}{"resize": resize}, nil
+ return gophercloud.BuildRequestBody(opts, "resize")
}
// Resize instructs the provider to change the flavor of the server.
@@ -561,21 +491,11 @@
// Otherwise, call RevertResize() to rtore the old configuration.
func Resize(client *gophercloud.ServiceClient, id string, opts ResizeOptsBuilder) ActionResult {
var r ActionResult
-
- if id == "" {
- err := ErrNoIDProvided{}
- err.Function = "servers.Resize"
- err.Argument = "id"
- r.Err = err
- return r
- }
-
b, err := opts.ToServerResizeMap()
if err != nil {
r.Err = err
return r
}
-
_, r.Err = client.Post(actionURL(client, id), b, nil, nil)
return r
}
@@ -584,17 +504,7 @@
// See Resize() for more details.
func ConfirmResize(client *gophercloud.ServiceClient, id string) ActionResult {
var r ActionResult
-
- if id == "" {
- err := ErrNoIDProvided{}
- err.Function = "servers.ConfirmResize"
- err.Argument = "id"
- r.Err = err
- return r
- }
-
- b := map[string]interface{}{"confirmResize": nil}
- _, r.Err = client.Post(actionURL(client, id), b, nil, &gophercloud.RequestOpts{
+ _, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"confirmResize": nil}, nil, &gophercloud.RequestOpts{
OkCodes: []int{201, 202, 204},
})
return r
@@ -604,17 +514,7 @@
// See Resize() for more details.
func RevertResize(client *gophercloud.ServiceClient, id string) ActionResult {
var r ActionResult
-
- if id == "" {
- err := ErrNoIDProvided{}
- err.Function = "servers.RevertResize"
- err.Argument = "id"
- r.Err = err
- return r
- }
-
- b := map[string]interface{}{"revertResize": nil}
- _, r.Err = client.Post(actionURL(client, id), b, nil, nil)
+ _, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"revertResize": nil}, nil, nil)
return r
}
@@ -629,41 +529,26 @@
type RescueOpts struct {
// AdminPass is the desired administrative password for the instance in
// RESCUE mode. If it's left blank, the server will generate a password.
- AdminPass string
+ AdminPass string `json:"adminPass,omitempty"`
}
// ToServerRescueMap formats a RescueOpts as a map that can be used as a JSON
// request body for the Rescue request.
func (opts RescueOpts) ToServerRescueMap() (map[string]interface{}, error) {
- server := make(map[string]interface{})
- if opts.AdminPass != "" {
- server["adminPass"] = opts.AdminPass
- }
- return map[string]interface{}{"rescue": server}, nil
+ return gophercloud.BuildRequestBody(opts, "rescue")
}
// Rescue instructs the provider to place the server into RESCUE mode.
func Rescue(client *gophercloud.ServiceClient, id string, opts RescueOptsBuilder) RescueResult {
var r RescueResult
-
- if id == "" {
- err := ErrNoIDProvided{}
- err.Function = "servers.Rebuild"
- err.Argument = "id"
- r.Err = err
- return r
- }
-
b, err := opts.ToServerRescueMap()
if err != nil {
r.Err = err
return r
}
-
_, r.Err = client.Post(actionURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
-
return r
}
@@ -692,12 +577,12 @@
// UpdateMetadatas or UpdateMetadata function.
func ResetMetadata(client *gophercloud.ServiceClient, id string, opts ResetMetadataOptsBuilder) ResetMetadataResult {
var r ResetMetadataResult
- metadata, err := opts.ToMetadataResetMap()
+ b, err := opts.ToMetadataResetMap()
if err != nil {
r.Err = err
return r
}
- _, r.Err = client.Put(metadataURL(client, id), metadata, &r.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Put(metadataURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
return r
@@ -721,12 +606,12 @@
// by opts.
func UpdateMetadata(client *gophercloud.ServiceClient, id string, opts UpdateMetadataOptsBuilder) UpdateMetadataResult {
var r UpdateMetadataResult
- metadata, err := opts.ToMetadataUpdateMap()
+ b, err := opts.ToMetadataUpdateMap()
if err != nil {
r.Err = err
return r
}
- _, r.Err = client.Post(metadataURL(client, id), metadata, &r.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Post(metadataURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
return r
@@ -760,13 +645,12 @@
// CreateMetadatum will create or update the key-value pair with the given key for the given server ID.
func CreateMetadatum(client *gophercloud.ServiceClient, id string, opts MetadatumOptsBuilder) CreateMetadatumResult {
var r CreateMetadatumResult
- metadatum, key, err := opts.ToMetadatumCreateMap()
+ b, key, err := opts.ToMetadatumCreateMap()
if err != nil {
r.Err = err
return r
}
-
- _, r.Err = client.Put(metadatumURL(client, id, key), metadatum, &r.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Put(metadatumURL(client, id, key), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
return r
@@ -775,9 +659,7 @@
// Metadatum requests the key-value pair with the given key for the given server ID.
func Metadatum(client *gophercloud.ServiceClient, id, key string) GetMetadatumResult {
var r GetMetadatumResult
- _, r.Err = client.Request("GET", metadatumURL(client, id, key), &gophercloud.RequestOpts{
- JSONResponse: &r.Body,
- })
+ _, r.Err = client.Get(metadatumURL(client, id, key), &r.Body, nil)
return r
}
@@ -790,60 +672,47 @@
// ListAddresses makes a request against the API to list the servers IP addresses.
func ListAddresses(client *gophercloud.ServiceClient, id string) pagination.Pager {
- createPageFn := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, listAddressesURL(client, id), func(r pagination.PageResult) pagination.Page {
return AddressPage{pagination.SinglePageBase(r)}
- }
- return pagination.NewPager(client, listAddressesURL(client, id), createPageFn)
+ })
}
// ListAddressesByNetwork makes a request against the API to list the servers IP addresses
// for the given network.
func ListAddressesByNetwork(client *gophercloud.ServiceClient, id, network string) pagination.Pager {
- createPageFn := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, listAddressesByNetworkURL(client, id, network), func(r pagination.PageResult) pagination.Page {
return NetworkAddressPage{pagination.SinglePageBase(r)}
- }
- return pagination.NewPager(client, listAddressesByNetworkURL(client, id, network), createPageFn)
+ })
}
-type CreateImageOpts struct {
- // Name [required] of the image/snapshot
- Name string
- // Metadata [optional] contains key-value pairs (up to 255 bytes each) to attach to the created image.
- Metadata map[string]string
-}
-
+// CreateImageOptsBuilder is the interface types must satisfy in order to be
+// used as CreateImage options
type CreateImageOptsBuilder interface {
ToServerCreateImageMap() (map[string]interface{}, error)
}
+// CreateImageOpts satisfies the CreateImageOptsBuilder
+type CreateImageOpts struct {
+ // Name of the image/snapshot
+ Name string `json:"name" required:"true"`
+ // Metadata contains key-value pairs (up to 255 bytes each) to attach to the created image.
+ Metadata map[string]string `json:"metadata,omitempty"`
+}
+
// ToServerCreateImageMap formats a CreateImageOpts structure into a request body.
func (opts CreateImageOpts) ToServerCreateImageMap() (map[string]interface{}, error) {
- var err error
- img := make(map[string]interface{})
- if opts.Name == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "servers.CreateImageOpts.ToServerCreateImageMap"
- err.Argument = "CreateImageOpts.Name"
- return nil, err
- }
- img["name"] = opts.Name
- if opts.Metadata != nil {
- img["metadata"] = opts.Metadata
- }
- createImage := make(map[string]interface{})
- createImage["createImage"] = img
- return createImage, err
+ return gophercloud.BuildRequestBody(opts, "createImage")
}
// CreateImage makes a request against the nova API to schedule an image to be created of the server
-func CreateImage(client *gophercloud.ServiceClient, serverID string, opts CreateImageOptsBuilder) CreateImageResult {
+func CreateImage(client *gophercloud.ServiceClient, id string, opts CreateImageOptsBuilder) CreateImageResult {
var r CreateImageResult
b, err := opts.ToServerCreateImageMap()
if err != nil {
r.Err = err
return r
}
- resp, err := client.Post(actionURL(client, serverID), b, nil, &gophercloud.RequestOpts{
+ resp, err := client.Post(actionURL(client, id), b, nil, &gophercloud.RequestOpts{
OkCodes: []int{202},
})
r.Err = err
@@ -855,13 +724,6 @@
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
count := 0
id := ""
- if name == "" {
- err := &gophercloud.ErrMissingInput{}
- err.Function = "servers.IDFromName"
- err.Argument = "name"
- return "", err
- }
-
allPages, err := List(client, nil).AllPages()
if err != nil {
return "", err
@@ -881,19 +743,10 @@
switch count {
case 0:
- err := &gophercloud.ErrResourceNotFound{}
- err.Function = "servers.IDFromName"
- err.ResourceType = "server"
- err.Name = name
- return "", err
+ return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "server"}
case 1:
return id, nil
default:
- err := &gophercloud.ErrMultipleResourcesFound{}
- err.Function = "servers.IDFromName"
- err.ResourceType = "server"
- err.Name = name
- err.Count = count
- return "", err
+ return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "server"}
}
}
diff --git a/openstack/compute/v2/servers/requests_test.go b/openstack/compute/v2/servers/requests_test.go
index 73d1375..931ab36 100644
--- a/openstack/compute/v2/servers/requests_test.go
+++ b/openstack/compute/v2/servers/requests_test.go
@@ -69,6 +69,24 @@
th.CheckDeepEquals(t, ServerDerp, *actual)
}
+func TestCreateServerWithCustomField(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+ HandleServerCreationWithCustomFieldSuccessfully(t, SingleServerBody)
+
+ actual, err := Create(client.ServiceClient(), CreateOptsWithCustomField{
+ CreateOpts: CreateOpts{
+ Name: "derp",
+ ImageRef: "f90f6034-2570-4974-8351-6b49732ef2eb",
+ FlavorRef: "1",
+ },
+ Foo: "bar",
+ }).Extract()
+ th.AssertNoErr(t, err)
+
+ th.CheckDeepEquals(t, ServerDerp, *actual)
+}
+
func TestDeleteServer(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
diff --git a/openstack/db/v1/configurations/requests.go b/openstack/db/v1/configurations/requests.go
index abb0013..eb59cc2 100644
--- a/openstack/db/v1/configurations/requests.go
+++ b/openstack/db/v1/configurations/requests.go
@@ -8,11 +8,9 @@
// List will list all of the available configurations.
func List(client *gophercloud.ServiceClient) pagination.Pager {
- pageFn := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, baseURL(client), func(r pagination.PageResult) pagination.Page {
return ConfigPage{pagination.SinglePageBase(r)}
- }
-
- return pagination.NewPager(client, baseURL(client), pageFn)
+ })
}
// CreateOptsBuilder is a top-level interface which renders a JSON map.
@@ -23,109 +21,51 @@
// DatastoreOpts is the primary options struct for creating and modifying
// how configuration resources are associated with datastores.
type DatastoreOpts struct {
- // [OPTIONAL] The type of datastore. Defaults to "MySQL".
- Type string
-
- // [OPTIONAL] The specific version of a datastore. Defaults to "5.6".
- Version string
-}
-
-// ToMap renders a JSON map for a datastore setting.
-func (opts DatastoreOpts) ToMap() (map[string]string, error) {
- datastore := map[string]string{}
-
- if opts.Type != "" {
- datastore["type"] = opts.Type
- }
-
- if opts.Version != "" {
- datastore["version"] = opts.Version
- }
-
- return datastore, nil
+ // The type of datastore. Defaults to "MySQL".
+ Type string `json:"type,omitempty"`
+ // The specific version of a datastore. Defaults to "5.6".
+ Version string `json:"version,omitempty"`
}
// CreateOpts is the struct responsible for configuring new configurations.
type CreateOpts struct {
// [REQUIRED] The configuration group name
- Name string
+ Name string `json:"name" required:"true"`
// [REQUIRED] A map of user-defined configuration settings that will define
// how each associated datastore works. Each key/value pair is specific to a
// datastore type.
- Values map[string]interface{}
+ Values map[string]interface{} `json:"values" required:"true"`
- // [OPTIONAL] Associates the configuration group with a particular datastore.
- Datastore *DatastoreOpts
+ // Associates the configuration group with a particular datastore.
+ Datastore *DatastoreOpts `json:"datastore,omitempty"`
- // [OPTIONAL] A human-readable explanation for the group.
- Description string
+ // A human-readable explanation for the group.
+ Description string `json:"description,omitempty"`
}
// ToConfigCreateMap casts a CreateOpts struct into a JSON map.
func (opts CreateOpts) ToConfigCreateMap() (map[string]interface{}, error) {
- if opts.Name == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "configurations.ToConfigCreateMap"
- err.Argument = "configurations.CreateOpts.Name"
- return nil, err
- }
- if len(opts.Values) == 0 {
- err := gophercloud.ErrMissingInput{}
- err.Function = "configurations.ToConfigCreateMap"
- err.Argument = "configurations.CreateOpts.Values"
- return nil, err
- }
-
- config := map[string]interface{}{
- "name": opts.Name,
- "values": opts.Values,
- }
-
- if opts.Datastore != nil {
- ds, err := opts.Datastore.ToMap()
- if err != nil {
- return config, err
- }
- config["datastore"] = ds
- }
-
- if opts.Description != "" {
- config["description"] = opts.Description
- }
-
- return map[string]interface{}{"configuration": config}, nil
+ return gophercloud.BuildRequestBody(opts, "configuration")
}
// Create will create a new configuration group.
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
- var res CreateResult
-
- reqBody, err := opts.ToConfigCreateMap()
+ var r CreateResult
+ b, err := opts.ToConfigCreateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- _, res.Err = client.Request("POST", baseURL(client), &gophercloud.RequestOpts{
- OkCodes: []int{200},
- JSONBody: &reqBody,
- JSONResponse: &res.Body,
- })
-
- return res
+ _, r.Err = client.Post(baseURL(client), &b, &r.Body, &gophercloud.RequestOpts{OkCodes: []int{200}})
+ return r
}
// Get will retrieve the details for a specified configuration group.
func Get(client *gophercloud.ServiceClient, configID string) GetResult {
- var res GetResult
-
- _, res.Err = client.Request("GET", resourceURL(client, configID), &gophercloud.RequestOpts{
- OkCodes: []int{200},
- JSONResponse: &res.Body,
- })
-
- return res
+ var r GetResult
+ _, r.Err = client.Get(resourceURL(client, configID), &r.Body, nil)
+ return r
}
// UpdateOptsBuilder is the top-level interface for casting update options into
@@ -136,108 +76,66 @@
// UpdateOpts is the struct responsible for modifying existing configurations.
type UpdateOpts struct {
- // [OPTIONAL] The configuration group name
- Name string
-
- // [OPTIONAL] A map of user-defined configuration settings that will define
+ // The configuration group name
+ Name string `json:"name,omitempty"`
+ // A map of user-defined configuration settings that will define
// how each associated datastore works. Each key/value pair is specific to a
// datastore type.
- Values map[string]interface{}
-
- // [OPTIONAL] Associates the configuration group with a particular datastore.
- Datastore *DatastoreOpts
-
- // [OPTIONAL] A human-readable explanation for the group.
- Description string
+ Values map[string]interface{} `json:"values,omitempty"`
+ // Associates the configuration group with a particular datastore.
+ Datastore *DatastoreOpts `json:"datastore,omitempty"`
+ // A human-readable explanation for the group.
+ Description string `json:"description,omitempty"`
}
// ToConfigUpdateMap will cast an UpdateOpts struct into a JSON map.
func (opts UpdateOpts) ToConfigUpdateMap() (map[string]interface{}, error) {
- config := map[string]interface{}{}
-
- if opts.Name != "" {
- config["name"] = opts.Name
- }
-
- if opts.Description != "" {
- config["description"] = opts.Description
- }
-
- if opts.Datastore != nil {
- ds, err := opts.Datastore.ToMap()
- if err != nil {
- return config, err
- }
- config["datastore"] = ds
- }
-
- if len(opts.Values) > 0 {
- config["values"] = opts.Values
- }
-
- return map[string]interface{}{"configuration": config}, nil
+ return gophercloud.BuildRequestBody(opts, "configuration")
}
// Update will modify an existing configuration group by performing a merge
// between new and existing values. If the key already exists, the new value
// will overwrite. All other keys will remain unaffected.
func Update(client *gophercloud.ServiceClient, configID string, opts UpdateOptsBuilder) UpdateResult {
- var res UpdateResult
-
- reqBody, err := opts.ToConfigUpdateMap()
+ var r UpdateResult
+ b, err := opts.ToConfigUpdateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- _, res.Err = client.Request("PATCH", resourceURL(client, configID), &gophercloud.RequestOpts{
- OkCodes: []int{200},
- JSONBody: &reqBody,
- })
-
- return res
+ _, r.Err = client.Patch(resourceURL(client, configID), &b, nil, nil)
+ return r
}
// Replace will modify an existing configuration group by overwriting the
// entire parameter group with the new values provided. Any existing keys not
// included in UpdateOptsBuilder will be deleted.
func Replace(client *gophercloud.ServiceClient, configID string, opts UpdateOptsBuilder) ReplaceResult {
- var res ReplaceResult
-
- reqBody, err := opts.ToConfigUpdateMap()
+ var r ReplaceResult
+ b, err := opts.ToConfigUpdateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- _, res.Err = client.Request("PUT", resourceURL(client, configID), &gophercloud.RequestOpts{
- OkCodes: []int{202},
- JSONBody: &reqBody,
- })
-
- return res
+ _, r.Err = client.Put(resourceURL(client, configID), &b, nil, nil)
+ return r
}
// Delete will permanently delete a configuration group. Please note that
// config groups cannot be deleted whilst still attached to running instances -
// you must detach and then delete them.
func Delete(client *gophercloud.ServiceClient, configID string) DeleteResult {
- var res DeleteResult
-
- _, res.Err = client.Request("DELETE", resourceURL(client, configID), &gophercloud.RequestOpts{
- OkCodes: []int{202},
- })
-
- return res
+ var r DeleteResult
+ _, r.Err = client.Delete(resourceURL(client, configID), nil)
+ return r
}
// ListInstances will list all the instances associated with a particular
// configuration group.
func ListInstances(client *gophercloud.ServiceClient, configID string) pagination.Pager {
- pageFn := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, instancesURL(client, configID), func(r pagination.PageResult) pagination.Page {
return instances.InstancePage{pagination.LinkedPageBase{PageResult: r}}
- }
- return pagination.NewPager(client, instancesURL(client, configID), pageFn)
+ })
}
// ListDatastoreParams will list all the available and supported parameters
@@ -246,10 +144,9 @@
// you can use this operation (you will need to retrieve the MySQL datastore ID
// by using the datastores API).
func ListDatastoreParams(client *gophercloud.ServiceClient, datastoreID, versionID string) pagination.Pager {
- pageFn := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, listDSParamsURL(client, datastoreID, versionID), func(r pagination.PageResult) pagination.Page {
return ParamPage{pagination.SinglePageBase(r)}
- }
- return pagination.NewPager(client, listDSParamsURL(client, datastoreID, versionID), pageFn)
+ })
}
// GetDatastoreParam will retrieve information about a specific configuration
@@ -258,34 +155,23 @@
// need the param's ID first, which can be attained by using the ListDatastoreParams
// operation.
func GetDatastoreParam(client *gophercloud.ServiceClient, datastoreID, versionID, paramID string) ParamResult {
- var res ParamResult
-
- _, res.Err = client.Request("GET", getDSParamURL(client, datastoreID, versionID, paramID), &gophercloud.RequestOpts{
- OkCodes: []int{200},
- JSONResponse: &res.Body,
- })
-
- return res
+ var r ParamResult
+ _, r.Err = client.Get(getDSParamURL(client, datastoreID, versionID, paramID), &r.Body, nil)
+ return r
}
// ListGlobalParams is similar to ListDatastoreParams but does not require a
// DatastoreID.
func ListGlobalParams(client *gophercloud.ServiceClient, versionID string) pagination.Pager {
- pageFn := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, listGlobalParamsURL(client, versionID), func(r pagination.PageResult) pagination.Page {
return ParamPage{pagination.SinglePageBase(r)}
- }
- return pagination.NewPager(client, listGlobalParamsURL(client, versionID), pageFn)
+ })
}
// GetGlobalParam is similar to GetDatastoreParam but does not require a
// DatastoreID.
func GetGlobalParam(client *gophercloud.ServiceClient, versionID, paramID string) ParamResult {
- var res ParamResult
-
- _, res.Err = client.Request("GET", getGlobalParamURL(client, versionID, paramID), &gophercloud.RequestOpts{
- OkCodes: []int{200},
- JSONResponse: &res.Body,
- })
-
- return res
+ var r ParamResult
+ _, r.Err = client.Get(getGlobalParamURL(client, versionID, paramID), &r.Body, nil)
+ return r
}
diff --git a/openstack/db/v1/databases/requests.go b/openstack/db/v1/databases/requests.go
index 18e1af5..7338112 100644
--- a/openstack/db/v1/databases/requests.go
+++ b/openstack/db/v1/databases/requests.go
@@ -13,52 +13,35 @@
// CreateOpts is the struct responsible for configuring a database; often in
// the context of an instance.
type CreateOpts struct {
- // [REQUIRED] Specifies the name of the database. Valid names can be composed
+ // Specifies the name of the database. Valid names can be composed
// of the following characters: letters (either case); numbers; these
// characters '@', '?', '#', ' ' but NEVER beginning a name string; '_' is
// permitted anywhere. Prohibited characters that are forbidden include:
// single quotes, double quotes, back quotes, semicolons, commas, backslashes,
// and forward slashes.
- Name string
-
- // [OPTIONAL] Set of symbols and encodings. The default character set is
+ Name string `json:"name" required:"true"`
+ // Set of symbols and encodings. The default character set is
// "utf8". See http://dev.mysql.com/doc/refman/5.1/en/charset-mysql.html for
// supported character sets.
- CharSet string
-
- // [OPTIONAL] Set of rules for comparing characters in a character set. The
+ CharSet string `json:"character_set,omitempty"`
+ // Set of rules for comparing characters in a character set. The
// default value for collate is "utf8_general_ci". See
// http://dev.mysql.com/doc/refman/5.1/en/charset-mysql.html for supported
// collations.
- Collate string
+ Collate string `json:"collate,omitempty"`
}
// ToMap is a helper function to convert individual DB create opt structures
// into sub-maps.
-func (opts CreateOpts) ToMap() (map[string]string, error) {
- if opts.Name == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "databases.ToMap"
- err.Argument = "databases.CreateOpts.Name"
- }
+func (opts CreateOpts) ToMap() (map[string]interface{}, error) {
if len(opts.Name) > 64 {
err := gophercloud.ErrInvalidInput{}
- err.Function = "databases.ToMap"
err.Argument = "databases.CreateOpts.Name"
err.Value = opts.Name
err.Info = "Must be less than 64 chars long"
return nil, err
}
-
- db := map[string]string{"name": opts.Name}
-
- if opts.CharSet != "" {
- db["character_set"] = opts.CharSet
- }
- if opts.Collate != "" {
- db["collate"] = opts.Collate
- }
- return db, nil
+ return gophercloud.BuildRequestBody(opts, "")
}
// BatchCreateOpts allows for multiple databases to created and modified.
@@ -66,7 +49,7 @@
// ToDBCreateMap renders a JSON map for creating DBs.
func (opts BatchCreateOpts) ToDBCreateMap() (map[string]interface{}, error) {
- dbs := make([]map[string]string, len(opts))
+ dbs := make([]map[string]interface{}, len(opts))
for i, db := range opts {
dbMap, err := db.ToMap()
if err != nil {
@@ -80,41 +63,29 @@
// Create will create a new database within the specified instance. If the
// specified instance does not exist, a 404 error will be returned.
func Create(client *gophercloud.ServiceClient, instanceID string, opts CreateOptsBuilder) CreateResult {
- var res CreateResult
-
- reqBody, err := opts.ToDBCreateMap()
+ var r CreateResult
+ b, err := opts.ToDBCreateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- _, res.Err = client.Request("POST", baseURL(client, instanceID), &gophercloud.RequestOpts{
- JSONBody: &reqBody,
- OkCodes: []int{202},
- })
-
- return res
+ _, r.Err = client.Post(baseURL(client, instanceID), &b, nil, nil)
+ return r
}
// List will list all of the databases for a specified instance. Note: this
// operation will only return user-defined databases; it will exclude system
// databases like "mysql", "information_schema", "lost+found" etc.
func List(client *gophercloud.ServiceClient, instanceID string) pagination.Pager {
- createPageFn := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, baseURL(client, instanceID), func(r pagination.PageResult) pagination.Page {
return DBPage{pagination.LinkedPageBase{PageResult: r}}
- }
-
- return pagination.NewPager(client, baseURL(client, instanceID), createPageFn)
+ })
}
// Delete will permanently delete the database within a specified instance.
// All contained data inside the database will also be permanently deleted.
func Delete(client *gophercloud.ServiceClient, instanceID, dbName string) DeleteResult {
- var res DeleteResult
-
- _, res.Err = client.Request("DELETE", dbURL(client, instanceID, dbName), &gophercloud.RequestOpts{
- OkCodes: []int{202},
- })
-
- return res
+ var r DeleteResult
+ _, r.Err = client.Delete(dbURL(client, instanceID, dbName), nil)
+ return r
}
diff --git a/openstack/db/v1/datastores/requests.go b/openstack/db/v1/datastores/requests.go
index 277c797..d820915 100644
--- a/openstack/db/v1/datastores/requests.go
+++ b/openstack/db/v1/datastores/requests.go
@@ -7,41 +7,29 @@
// List will list all available datastore types that instances can use.
func List(client *gophercloud.ServiceClient) pagination.Pager {
- pageFn := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, baseURL(client), func(r pagination.PageResult) pagination.Page {
return DatastorePage{pagination.SinglePageBase(r)}
- }
- return pagination.NewPager(client, baseURL(client), pageFn)
+ })
}
// Get will retrieve the details of a specified datastore type.
func Get(client *gophercloud.ServiceClient, datastoreID string) GetResult {
- var res GetResult
-
- _, res.Err = client.Request("GET", resourceURL(client, datastoreID), &gophercloud.RequestOpts{
- OkCodes: []int{200},
- JSONResponse: &res.Body,
- })
-
- return res
+ var r GetResult
+ _, r.Err = client.Get(resourceURL(client, datastoreID), &r.Body, nil)
+ return r
}
// ListVersions will list all of the available versions for a specified
// datastore type.
func ListVersions(client *gophercloud.ServiceClient, datastoreID string) pagination.Pager {
- pageFn := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, versionsURL(client, datastoreID), func(r pagination.PageResult) pagination.Page {
return VersionPage{pagination.SinglePageBase(r)}
- }
- return pagination.NewPager(client, versionsURL(client, datastoreID), pageFn)
+ })
}
// GetVersion will retrieve the details of a specified datastore version.
func GetVersion(client *gophercloud.ServiceClient, datastoreID, versionID string) GetVersionResult {
- var res GetVersionResult
-
- _, res.Err = client.Request("GET", versionURL(client, datastoreID, versionID), &gophercloud.RequestOpts{
- OkCodes: []int{200},
- JSONResponse: &res.Body,
- })
-
- return res
+ var r GetVersionResult
+ _, r.Err = client.Get(versionURL(client, datastoreID, versionID), &r.Body, nil)
+ return r
}
diff --git a/openstack/db/v1/flavors/requests.go b/openstack/db/v1/flavors/requests.go
index c767606..8b7797f 100644
--- a/openstack/db/v1/flavors/requests.go
+++ b/openstack/db/v1/flavors/requests.go
@@ -9,21 +9,14 @@
// operation is identical to the one supported by the Nova API, but without the
// "disk" property.
func List(client *gophercloud.ServiceClient) pagination.Pager {
- createPage := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
return FlavorPage{pagination.LinkedPageBase{PageResult: r}}
- }
-
- return pagination.NewPager(client, listURL(client), createPage)
+ })
}
// Get will retrieve information for a specified hardware flavor.
func Get(client *gophercloud.ServiceClient, id string) GetResult {
- var gr GetResult
-
- _, gr.Err = client.Request("GET", getURL(client, id), &gophercloud.RequestOpts{
- JSONResponse: &gr.Body,
- OkCodes: []int{200},
- })
-
- return gr
+ var r GetResult
+ _, r.Err = client.Get(getURL(client, id), &r.Body, nil)
+ return r
}
diff --git a/openstack/db/v1/instances/requests.go b/openstack/db/v1/instances/requests.go
index 8e33dfe..b8cae03 100644
--- a/openstack/db/v1/instances/requests.go
+++ b/openstack/db/v1/instances/requests.go
@@ -14,16 +14,13 @@
// DatastoreOpts represents the configuration for how an instance stores data.
type DatastoreOpts struct {
- Version string
- Type string
+ Version string `json:"version"`
+ Type string `json:"type"`
}
// ToMap converts a DatastoreOpts to a map[string]string (for a request body)
-func (opts DatastoreOpts) ToMap() (map[string]string, error) {
- return map[string]string{
- "version": opts.Version,
- "type": opts.Type,
- }, nil
+func (opts DatastoreOpts) ToMap() (map[string]interface{}, error) {
+ return gophercloud.BuildRequestBody(opts, "")
}
// CreateOpts is the struct responsible for configuring a new database instance.
@@ -31,21 +28,16 @@
// Either the integer UUID (in string form) of the flavor, or its URI
// reference as specified in the response from the List() call. Required.
FlavorRef string
-
// Specifies the volume size in gigabytes (GB). The value must be between 1
// and 300. Required.
Size int
-
// Name of the instance to create. The length of the name is limited to
// 255 characters and any characters are permitted. Optional.
Name string
-
// A slice of database information options.
Databases db.CreateOptsBuilder
-
// A slice of user information options.
Users users.CreateOptsBuilder
-
// Options to configure the type of datastore the instance will use. This is
// optional, and if excluded will default to MySQL.
Datastore *DatastoreOpts
@@ -55,17 +47,14 @@
func (opts CreateOpts) ToInstanceCreateMap() (map[string]interface{}, error) {
if opts.Size > 300 || opts.Size < 1 {
err := gophercloud.ErrInvalidInput{}
- err.Function = "instances.ToInstanceCreateMap"
err.Argument = "instances.CreateOpts.Size"
err.Value = opts.Size
err.Info = "Size (GB) must be between 1-300"
return nil, err
}
+
if opts.FlavorRef == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "instances.ToInstanceCreateMap"
- err.Argument = "instances.CreateOpts.FlavorRef"
- return nil, err
+ return nil, gophercloud.ErrMissingInput{Argument: "instances.CreateOpts.FlavorRef"}
}
instance := map[string]interface{}{
@@ -110,143 +99,79 @@
// can create an instance with multiple databases and users. The default
// binding for a MySQL instance is port 3306.
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
- var res CreateResult
-
- reqBody, err := opts.ToInstanceCreateMap()
+ var r CreateResult
+ b, err := opts.ToInstanceCreateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- _, res.Err = client.Request("POST", baseURL(client), &gophercloud.RequestOpts{
- JSONBody: &reqBody,
- JSONResponse: &res.Body,
- OkCodes: []int{200},
- })
-
- return res
+ _, r.Err = client.Post(baseURL(client), &b, &r.Body, &gophercloud.RequestOpts{OkCodes: []int{200}})
+ return r
}
// List retrieves the status and information for all database instances.
func List(client *gophercloud.ServiceClient) pagination.Pager {
- createPageFn := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, baseURL(client), func(r pagination.PageResult) pagination.Page {
return InstancePage{pagination.LinkedPageBase{PageResult: r}}
- }
-
- return pagination.NewPager(client, baseURL(client), createPageFn)
+ })
}
// Get retrieves the status and information for a specified database instance.
func Get(client *gophercloud.ServiceClient, id string) GetResult {
- var res GetResult
-
- _, res.Err = client.Request("GET", resourceURL(client, id), &gophercloud.RequestOpts{
- JSONResponse: &res.Body,
- OkCodes: []int{200},
- })
-
- return res
+ var r GetResult
+ _, r.Err = client.Get(resourceURL(client, id), &r.Body, nil)
+ return r
}
// Delete permanently destroys the database instance.
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
- var res DeleteResult
-
- _, res.Err = client.Request("DELETE", resourceURL(client, id), &gophercloud.RequestOpts{
- OkCodes: []int{202},
- })
-
- return res
+ var r DeleteResult
+ _, r.Err = client.Delete(resourceURL(client, id), nil)
+ return r
}
// EnableRootUser enables the login from any host for the root user and
// provides the user with a generated root password.
-func EnableRootUser(client *gophercloud.ServiceClient, id string) UserRootResult {
- var res UserRootResult
-
- _, res.Err = client.Request("POST", userRootURL(client, id), &gophercloud.RequestOpts{
- JSONResponse: &res.Body,
- OkCodes: []int{200},
- })
-
- return res
+func EnableRootUser(client *gophercloud.ServiceClient, id string) EnableRootUserResult {
+ var r EnableRootUserResult
+ _, r.Err = client.Post(userRootURL(client, id), nil, &r.Body, &gophercloud.RequestOpts{OkCodes: []int{200}})
+ return r
}
// IsRootEnabled checks an instance to see if root access is enabled. It returns
// True if root user is enabled for the specified database instance or False
// otherwise.
-func IsRootEnabled(client *gophercloud.ServiceClient, id string) (bool, error) {
- var res gophercloud.Result
-
- _, err := client.Request("GET", userRootURL(client, id), &gophercloud.RequestOpts{
- JSONResponse: &res.Body,
- OkCodes: []int{200},
- })
-
- return res.Body.(map[string]interface{})["rootEnabled"] == true, err
+func IsRootEnabled(client *gophercloud.ServiceClient, id string) IsRootEnabledResult {
+ var r IsRootEnabledResult
+ _, r.Err = client.Get(userRootURL(client, id), &r.Body, nil)
+ return r
}
// Restart will restart only the MySQL Instance. Restarting MySQL will
// erase any dynamic configuration settings that you have made within MySQL.
// The MySQL service will be unavailable until the instance restarts.
func Restart(client *gophercloud.ServiceClient, id string) ActionResult {
- var res ActionResult
-
- _, res.Err = client.Request("POST", actionURL(client, id), &gophercloud.RequestOpts{
- JSONBody: map[string]interface{}{"restart": struct{}{}},
- OkCodes: []int{202},
- })
-
- return res
+ var r ActionResult
+ b := map[string]interface{}{"restart": struct{}{}}
+ _, r.Err = client.Post(actionURL(client, id), &b, nil, nil)
+ return r
}
// Resize changes the memory size of the instance, assuming a valid
// flavorRef is provided. It will also restart the MySQL service.
func Resize(client *gophercloud.ServiceClient, id, flavorRef string) ActionResult {
- var res ActionResult
-
- type resize struct {
- FlavorRef string `json:"flavorRef"`
- }
-
- type req struct {
- Resize resize `json:"resize"`
- }
-
- reqBody := req{Resize: resize{FlavorRef: flavorRef}}
-
- _, res.Err = client.Request("POST", actionURL(client, id), &gophercloud.RequestOpts{
- JSONBody: reqBody,
- OkCodes: []int{202},
- })
-
- return res
+ var r ActionResult
+ b := map[string]interface{}{"resize": map[string]string{"flavorRef": flavorRef}}
+ _, r.Err = client.Post(actionURL(client, id), &b, nil, nil)
+ return r
}
// ResizeVolume will resize the attached volume for an instance. It supports
// only increasing the volume size and does not support decreasing the size.
// The volume size is in gigabytes (GB) and must be an integer.
func ResizeVolume(client *gophercloud.ServiceClient, id string, size int) ActionResult {
- var res ActionResult
-
- type volume struct {
- Size int `json:"size"`
- }
-
- type resize struct {
- Volume volume `json:"volume"`
- }
-
- type req struct {
- Resize resize `json:"resize"`
- }
-
- reqBody := req{Resize: resize{Volume: volume{Size: size}}}
-
- _, res.Err = client.Request("POST", actionURL(client, id), &gophercloud.RequestOpts{
- JSONBody: reqBody,
- OkCodes: []int{202},
- })
-
- return res
+ var r ActionResult
+ b := map[string]interface{}{"resize": map[string]interface{}{"volume": map[string]int{"size": size}}}
+ _, r.Err = client.Post(actionURL(client, id), &b, nil, nil)
+ return r
}
diff --git a/openstack/db/v1/instances/requests_test.go b/openstack/db/v1/instances/requests_test.go
index b56165a..3caac23 100644
--- a/openstack/db/v1/instances/requests_test.go
+++ b/openstack/db/v1/instances/requests_test.go
@@ -99,7 +99,7 @@
defer th.TeardownHTTP()
HandleIsRootEnabled(t)
- isEnabled, err := IsRootEnabled(fake.ServiceClient(), instanceID)
+ isEnabled, err := IsRootEnabled(fake.ServiceClient(), instanceID).Extract()
th.AssertNoErr(t, err)
th.AssertEquals(t, true, isEnabled)
diff --git a/openstack/db/v1/instances/results.go b/openstack/db/v1/instances/results.go
index f32632c..21900d7 100644
--- a/openstack/db/v1/instances/results.go
+++ b/openstack/db/v1/instances/results.go
@@ -117,13 +117,13 @@
return s.Instances, err
}
-// UserRootResult represents the result of an operation to enable the root user.
-type UserRootResult struct {
+// EnableRootUserResult represents the result of an operation to enable the root user.
+type EnableRootUserResult struct {
gophercloud.Result
}
// Extract will extract root user information from a UserRootResult.
-func (r UserRootResult) Extract() (*users.User, error) {
+func (r EnableRootUserResult) Extract() (*users.User, error) {
var s struct {
User *users.User `json:"user"`
}
@@ -137,3 +137,14 @@
type ActionResult struct {
gophercloud.ErrResult
}
+
+// IsRootEnabledResult is the result of a call to IsRootEnabled. To see if
+// root is enabled, call the type's Extract method.
+type IsRootEnabledResult struct {
+ gophercloud.Result
+}
+
+// Extract is used to extract the data from a IsRootEnabledResult.
+func (r IsRootEnabledResult) Extract() (bool, error) {
+ return r.Body.(map[string]interface{})["rootEnabled"] == true, r.Err
+}
diff --git a/openstack/db/v1/users/requests.go b/openstack/db/v1/users/requests.go
index 6815c1c..910a615 100644
--- a/openstack/db/v1/users/requests.go
+++ b/openstack/db/v1/users/requests.go
@@ -14,71 +14,35 @@
// CreateOpts is the struct responsible for configuring a new user; often in the
// context of an instance.
type CreateOpts struct {
- // [REQUIRED] Specifies a name for the user. Valid names can be composed
+ // Specifies a name for the user. Valid names can be composed
// of the following characters: letters (either case); numbers; these
// characters '@', '?', '#', ' ' but NEVER beginning a name string; '_' is
// permitted anywhere. Prohibited characters that are forbidden include:
// single quotes, double quotes, back quotes, semicolons, commas, backslashes,
// and forward slashes. Spaces at the front or end of a user name are also
// not permitted.
- Name string
-
- // [REQUIRED] Specifies a password for the user.
- Password string
-
- // [OPTIONAL] An array of databases that this user will connect to. The
+ Name string `json:"name" required:"true"`
+ // Specifies a password for the user.
+ Password string `json:"password" required:"true"`
+ // An array of databases that this user will connect to. The
// "name" field is the only requirement for each option.
- Databases db.BatchCreateOpts
-
- // [OPTIONAL] Specifies the host from which a user is allowed to connect to
+ Databases db.BatchCreateOpts `json:"databases,omitempty"`
+ // Specifies the host from which a user is allowed to connect to
// the database. Possible values are a string containing an IPv4 address or
// "%" to allow connecting from any host. Optional; the default is "%".
- Host string
+ Host string `json:"host,omitempty"`
}
// ToMap is a convenience function for creating sub-maps for individual users.
func (opts CreateOpts) ToMap() (map[string]interface{}, error) {
-
if opts.Name == "root" {
err := gophercloud.ErrInvalidInput{}
- err.Function = "users.ToUserCreateMap"
err.Argument = "users.CreateOpts.Name"
err.Value = "root"
err.Info = "root is a reserved user name and cannot be used"
return nil, err
}
- if opts.Name == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "users.ToUserCreateMap"
- err.Argument = "users.CreateOpts.Name"
- return nil, err
- }
- if opts.Password == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "users.ToUserCreateMap"
- err.Argument = "users.CreateOpts.Password"
- return nil, err
- }
-
- user := map[string]interface{}{
- "name": opts.Name,
- "password": opts.Password,
- }
-
- if opts.Host != "" {
- user["host"] = opts.Host
- }
-
- dbs := make([]map[string]string, len(opts.Databases))
- for i, db := range opts.Databases {
- dbs[i] = map[string]string{"name": db.Name}
- }
-
- if len(dbs) > 0 {
- user["databases"] = dbs
- }
-
- return user, nil
+ return gophercloud.BuildRequestBody(opts, "")
}
// BatchCreateOpts allows multiple users to be created at once.
@@ -102,40 +66,28 @@
// assigned for a particular user, the user will be granted all privileges
// for those specified databases. "root" is a reserved name and cannot be used.
func Create(client *gophercloud.ServiceClient, instanceID string, opts CreateOptsBuilder) CreateResult {
- var res CreateResult
-
- reqBody, err := opts.ToUserCreateMap()
+ var r CreateResult
+ b, err := opts.ToUserCreateMap()
if err != nil {
- res.Err = err
- return res
+ r.Err = err
+ return r
}
-
- _, res.Err = client.Request("POST", baseURL(client, instanceID), &gophercloud.RequestOpts{
- JSONBody: &reqBody,
- OkCodes: []int{202},
- })
-
- return res
+ _, r.Err = client.Post(baseURL(client, instanceID), &b, nil, nil)
+ return r
}
// List will list all the users associated with a specified database instance,
// along with their associated databases. This operation will not return any
// system users or administrators for a database.
func List(client *gophercloud.ServiceClient, instanceID string) pagination.Pager {
- createPageFn := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, baseURL(client, instanceID), func(r pagination.PageResult) pagination.Page {
return UserPage{pagination.LinkedPageBase{PageResult: r}}
- }
-
- return pagination.NewPager(client, baseURL(client, instanceID), createPageFn)
+ })
}
// Delete will permanently delete a user from a specified database instance.
func Delete(client *gophercloud.ServiceClient, instanceID, userName string) DeleteResult {
- var res DeleteResult
-
- _, res.Err = client.Request("DELETE", userURL(client, instanceID, userName), &gophercloud.RequestOpts{
- OkCodes: []int{202},
- })
-
- return res
+ var r DeleteResult
+ _, r.Err = client.Delete(userURL(client, instanceID, userName), nil)
+ return r
}
diff --git a/openstack/endpoint_location.go b/openstack/endpoint_location.go
index a14f989..fb6b84a 100644
--- a/openstack/endpoint_location.go
+++ b/openstack/endpoint_location.go
@@ -29,7 +29,6 @@
if len(endpoints) > 1 {
err := &ErrMultipleMatchingEndpointsV2{}
err.Endpoints = endpoints
- err.Function = "openstack.V2EndpointURL"
return "", err
}
@@ -44,7 +43,6 @@
return gophercloud.NormalizeURL(endpoint.AdminURL), nil
default:
err := &ErrInvalidAvailabilityProvided{}
- err.Function = "openstack.V2EndpointURL"
err.Argument = "Availability"
err.Value = opts.Availability
return "", err
@@ -74,7 +72,6 @@
opts.Availability != gophercloud.AvailabilityPublic &&
opts.Availability != gophercloud.AvailabilityInternal {
err := &ErrInvalidAvailabilityProvided{}
- err.Function = "openstack.V3EndpointURL"
err.Argument = "Availability"
err.Value = opts.Availability
return "", err
@@ -89,10 +86,7 @@
// Report an error if the options were ambiguous.
if len(endpoints) > 1 {
- err := &ErrMultipleMatchingEndpointsV3{}
- err.Endpoints = endpoints
- err.Function = "openstack.V3EndpointURL"
- return "", err
+ return "", ErrMultipleMatchingEndpointsV3{Endpoints: endpoints}
}
// Extract the URL from the matching Endpoint.
@@ -102,6 +96,5 @@
// Report an error if there were no matching endpoints.
err := &gophercloud.ErrEndpointNotFound{}
- err.Function = "openstack.V3EndpointURL"
return "", err
}
diff --git a/openstack/identity/v2/extensions/admin/roles/requests.go b/openstack/identity/v2/extensions/admin/roles/requests.go
index 891ab62..d80c53f 100644
--- a/openstack/identity/v2/extensions/admin/roles/requests.go
+++ b/openstack/identity/v2/extensions/admin/roles/requests.go
@@ -8,26 +8,25 @@
// List is the operation responsible for listing all available global roles
// that a user can adopt.
func List(client *gophercloud.ServiceClient) pagination.Pager {
- createPage := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, rootURL(client), func(r pagination.PageResult) pagination.Page {
return RolePage{pagination.SinglePageBase(r)}
- }
- return pagination.NewPager(client, rootURL(client), createPage)
+ })
}
-// AddUserRole is the operation responsible for assigning a particular role to
+// AddUser is the operation responsible for assigning a particular role to
// a user. This is confined to the scope of the user's tenant - so the tenant
// ID is a required argument.
-func AddUserRole(client *gophercloud.ServiceClient, tenantID, userID, roleID string) UserRoleResult {
- var result UserRoleResult
- _, result.Err = client.Put(userRoleURL(client, tenantID, userID, roleID), nil, nil, nil)
- return result
+func AddUser(client *gophercloud.ServiceClient, tenantID, userID, roleID string) UserRoleResult {
+ var r UserRoleResult
+ _, r.Err = client.Put(userRoleURL(client, tenantID, userID, roleID), nil, nil, nil)
+ return r
}
-// DeleteUserRole is the operation responsible for deleting a particular role
+// DeleteUser is the operation responsible for deleting a particular role
// from a user. This is confined to the scope of the user's tenant - so the
// tenant ID is a required argument.
-func DeleteUserRole(client *gophercloud.ServiceClient, tenantID, userID, roleID string) UserRoleResult {
- var result UserRoleResult
- _, result.Err = client.Delete(userRoleURL(client, tenantID, userID, roleID), nil)
- return result
+func DeleteUser(client *gophercloud.ServiceClient, tenantID, userID, roleID string) UserRoleResult {
+ var r UserRoleResult
+ _, r.Err = client.Delete(userRoleURL(client, tenantID, userID, roleID), nil)
+ return r
}
diff --git a/openstack/identity/v2/extensions/admin/roles/requests_test.go b/openstack/identity/v2/extensions/admin/roles/requests_test.go
index af809a5..cf3402d 100644
--- a/openstack/identity/v2/extensions/admin/roles/requests_test.go
+++ b/openstack/identity/v2/extensions/admin/roles/requests_test.go
@@ -41,24 +41,24 @@
th.AssertEquals(t, 1, count)
}
-func TestAddUserRole(t *testing.T) {
+func TestAddUser(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
MockAddUserRoleResponse(t)
- err := AddUserRole(client.ServiceClient(), "{tenant_id}", "{user_id}", "{role_id}").ExtractErr()
+ err := AddUser(client.ServiceClient(), "{tenant_id}", "{user_id}", "{role_id}").ExtractErr()
th.AssertNoErr(t, err)
}
-func TestDeleteUserRole(t *testing.T) {
+func TestDeleteUser(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
MockDeleteUserRoleResponse(t)
- err := DeleteUserRole(client.ServiceClient(), "{tenant_id}", "{user_id}", "{role_id}").ExtractErr()
+ err := DeleteUser(client.ServiceClient(), "{tenant_id}", "{user_id}", "{role_id}").ExtractErr()
th.AssertNoErr(t, err)
}
diff --git a/openstack/identity/v2/extensions/delegate.go b/openstack/identity/v2/extensions/delegate.go
index 4b2c6a7..cf6cc81 100644
--- a/openstack/identity/v2/extensions/delegate.go
+++ b/openstack/identity/v2/extensions/delegate.go
@@ -14,23 +14,19 @@
// IsEmpty returns true if the current page contains at least one Extension.
func (page ExtensionPage) IsEmpty() (bool, error) {
is, err := ExtractExtensions(page)
- if err != nil {
- return true, err
- }
- return len(is) == 0, nil
+ return len(is) == 0, err
}
// ExtractExtensions accepts a Page struct, specifically an ExtensionPage struct, and extracts the
// elements into a slice of Extension structs.
func ExtractExtensions(page pagination.Page) ([]common.Extension, error) {
- r := page.(ExtensionPage)
// Identity v2 adds an intermediate "values" object.
var s struct {
Extensions struct {
Values []common.Extension `json:"values"`
} `json:"extensions"`
}
- err := r.ExtractInto(&s)
+ err := page.(ExtensionPage).ExtractInto(&s)
return s.Extensions.Values, err
}
diff --git a/openstack/identity/v2/tenants/requests.go b/openstack/identity/v2/tenants/requests.go
index d4ea632..b9d7de6 100644
--- a/openstack/identity/v2/tenants/requests.go
+++ b/openstack/identity/v2/tenants/requests.go
@@ -9,17 +9,12 @@
type ListOpts struct {
// Marker is the ID of the last Tenant on the previous page.
Marker string `q:"marker"`
-
// Limit specifies the page size.
Limit int `q:"limit"`
}
// List enumerates the Tenants to which the current token has access.
func List(client *gophercloud.ServiceClient, opts *ListOpts) pagination.Pager {
- createPage := func(r pagination.PageResult) pagination.Page {
- return TenantPage{pagination.LinkedPageBase{PageResult: r}}
- }
-
url := listURL(client)
if opts != nil {
q, err := gophercloud.BuildQueryString(opts)
@@ -28,6 +23,7 @@
}
url += q.String()
}
-
- return pagination.NewPager(client, url, createPage)
+ return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
+ return TenantPage{pagination.LinkedPageBase{PageResult: r}}
+ })
}
diff --git a/openstack/identity/v2/tokens/errors.go b/openstack/identity/v2/tokens/errors.go
deleted file mode 100644
index 12570f5..0000000
--- a/openstack/identity/v2/tokens/errors.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package tokens
-
-import "fmt"
-
-var (
- // ErrUserIDProvided is returned if you attempt to authenticate with a UserID.
- ErrUserIDProvided = unacceptedAttributeErr("UserID")
-
- // ErrAPIKeyProvided is returned if you attempt to authenticate with an APIKey.
- ErrAPIKeyProvided = unacceptedAttributeErr("APIKey")
-
- // ErrDomainIDProvided is returned if you attempt to authenticate with a DomainID.
- ErrDomainIDProvided = unacceptedAttributeErr("DomainID")
-
- // ErrDomainNameProvided is returned if you attempt to authenticate with a DomainName.
- ErrDomainNameProvided = unacceptedAttributeErr("DomainName")
-)
-
-func unacceptedAttributeErr(attribute string) error {
- return fmt.Errorf("The base Identity V2 API does not accept authentication by %s", attribute)
-}
diff --git a/openstack/identity/v2/tokens/requests.go b/openstack/identity/v2/tokens/requests.go
index 6064bc7..a2a0685 100644
--- a/openstack/identity/v2/tokens/requests.go
+++ b/openstack/identity/v2/tokens/requests.go
@@ -4,74 +4,9 @@
// AuthOptionsBuilder describes any argument that may be passed to the Create call.
type AuthOptionsBuilder interface {
-
// 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
-}
-
-// WrapOptions embeds a root AuthOptions struct in a package-specific one.
-func WrapOptions(original gophercloud.AuthOptions) AuthOptions {
- return AuthOptions{AuthOptions: original}
-}
-
-// 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 nil, ErrUserIDProvided
- }
- if auth.APIKey != "" {
- return nil, ErrAPIKeyProvided
- }
- if auth.DomainID != "" {
- return nil, ErrDomainIDProvided
- }
- if auth.DomainName != "" {
- return nil, ErrDomainNameProvided
- }
-
- // Populate the request map.
- authMap := make(map[string]interface{})
-
- if auth.Username != "" {
- if auth.Password == "" {
- err := gophercloud.ErrMissingInput{}
- err.Function = "tokens.ToTokenCreateMap"
- err.Argument = "tokens.AuthOptions.Password"
- return nil, err
- }
- authMap["passwordCredentials"] = map[string]interface{}{
- "username": auth.Username,
- "password": auth.Password,
- }
- } else if auth.TokenID != "" {
- authMap["token"] = map[string]interface{}{
- "id": auth.TokenID,
- }
- } else {
- err := gophercloud.ErrMissingInput{}
- err.Function = "tokens.ToTokenCreateMap"
- err.Argument = "tokens.AuthOptions.Username/tokens.AuthOptions.TokenID"
- err.Info = "You must provide either username/password or tenantID/token values."
- return nil, err
- }
-
- if auth.TenantID != "" {
- authMap["tenantId"] = auth.TenantID
- }
- if auth.TenantName != "" {
- authMap["tenantName"] = auth.TenantName
- }
-
- return map[string]interface{}{"auth": authMap}, nil
+ ToTokenV2CreateMap() (map[string]interface{}, error)
}
// Create authenticates to the identity service and attempts to acquire a Token.
@@ -79,23 +14,23 @@
// 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()
+ var r CreateResult
+ b, err := auth.ToTokenV2CreateMap()
if err != nil {
- return CreateResult{gophercloud.Result{Err: err}}
+ r.Err = err
+ return r
}
-
- var result CreateResult
- _, result.Err = client.Post(CreateURL(client), request, &result.Body, &gophercloud.RequestOpts{
+ _, r.Err = client.Post(CreateURL(client), b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200, 203},
})
- return result
+ return r
}
// Get validates and retrieves information for user's token.
func Get(client *gophercloud.ServiceClient, token string) GetResult {
- var result GetResult
- _, result.Err = client.Get(GetURL(client, token), &result.Body, &gophercloud.RequestOpts{
+ var r GetResult
+ _, r.Err = client.Get(GetURL(client, token), &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200, 203},
})
- return result
+ return r
}
diff --git a/openstack/identity/v2/tokens/requests_test.go b/openstack/identity/v2/tokens/requests_test.go
index 9b3273e..d25c2d7 100644
--- a/openstack/identity/v2/tokens/requests_test.go
+++ b/openstack/identity/v2/tokens/requests_test.go
@@ -1,6 +1,7 @@
package tokens
import (
+ "reflect"
"testing"
"github.com/gophercloud/gophercloud"
@@ -12,8 +13,7 @@
th.SetupHTTP()
defer th.TeardownHTTP()
HandleTokenPost(t, requestJSON)
-
- return Create(client.ServiceClient(), AuthOptions{options})
+ return Create(client.ServiceClient(), options)
}
func tokenPostErr(t *testing.T, options gophercloud.AuthOptions, expectedErr error) {
@@ -21,15 +21,30 @@
defer th.TeardownHTTP()
HandleTokenPost(t, "")
- actualErr := Create(client.ServiceClient(), AuthOptions{options}).Err
- th.CheckDeepEquals(t, expectedErr, actualErr)
+ actualErr := Create(client.ServiceClient(), options).Err
+ th.CheckDeepEquals(t, reflect.TypeOf(expectedErr), reflect.TypeOf(actualErr))
+}
+
+func TestCreateWithToken(t *testing.T) {
+ options := gophercloud.AuthOptions{
+ TokenID: "cbc36478b0bd8e67e89469c7749d4127",
+ }
+
+ IsSuccessful(t, tokenPost(t, options, `
+ {
+ "auth": {
+ "token": {
+ "id": "cbc36478b0bd8e67e89469c7749d4127"
+ }
+ }
+ }
+ `))
}
func TestCreateWithPassword(t *testing.T) {
- options := gophercloud.AuthOptions{
- Username: "me",
- Password: "swordfish",
- }
+ options := gophercloud.AuthOptions{}
+ options.Username = "me"
+ options.Password = "swordfish"
IsSuccessful(t, tokenPost(t, options, `
{
@@ -44,11 +59,10 @@
}
func TestCreateTokenWithTenantID(t *testing.T) {
- options := gophercloud.AuthOptions{
- Username: "me",
- Password: "opensesame",
- TenantID: "fc394f2ab2df4114bde39905f800dc57",
- }
+ options := gophercloud.AuthOptions{}
+ options.Username = "me"
+ options.Password = "opensesame"
+ options.TenantID = "fc394f2ab2df4114bde39905f800dc57"
IsSuccessful(t, tokenPost(t, options, `
{
@@ -64,11 +78,10 @@
}
func TestCreateTokenWithTenantName(t *testing.T) {
- options := gophercloud.AuthOptions{
- Username: "me",
- Password: "opensesame",
- TenantName: "demo",
- }
+ options := gophercloud.AuthOptions{}
+ options.Username = "me"
+ options.Password = "opensesame"
+ options.TenantName = "demo"
IsSuccessful(t, tokenPost(t, options, `
{
@@ -83,63 +96,21 @@
`))
}
-func TestProhibitUserID(t *testing.T) {
- options := 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",
- }
-
- tokenPostErr(t, options, ErrAPIKeyProvided)
-}
-
-func TestProhibitDomainID(t *testing.T) {
- options := 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",
- }
-
- tokenPostErr(t, options, ErrDomainNameProvided)
-}
-
func TestRequireUsername(t *testing.T) {
- options := gophercloud.AuthOptions{
- Password: "thing",
- }
+ options := gophercloud.AuthOptions{}
+ options.Password = "thing"
+
expected := gophercloud.ErrMissingInput{}
- expected.Function = "tokens.ToTokenCreateMap"
expected.Argument = "tokens.AuthOptions.Username/tokens.AuthOptions.TokenID"
expected.Info = "You must provide either username/password or tenantID/token values."
tokenPostErr(t, options, expected)
}
func TestRequirePassword(t *testing.T) {
- options := gophercloud.AuthOptions{
- Username: "me",
- }
+ options := gophercloud.AuthOptions{}
+ options.Username = "me"
+
expected := gophercloud.ErrMissingInput{}
- expected.Function = "tokens.ToTokenCreateMap"
expected.Argument = "tokens.AuthOptions.Password"
tokenPostErr(t, options, expected)
}
diff --git a/openstack/identity/v2/users/requests.go b/openstack/identity/v2/users/requests.go
index 7fa5fc3..f62f979 100644
--- a/openstack/identity/v2/users/requests.go
+++ b/openstack/identity/v2/users/requests.go
@@ -7,41 +7,25 @@
// List lists the existing users.
func List(client *gophercloud.ServiceClient) pagination.Pager {
- createPage := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, rootURL(client), func(r pagination.PageResult) pagination.Page {
return UserPage{pagination.SinglePageBase(r)}
- }
-
- return pagination.NewPager(client, rootURL(client), createPage)
+ })
}
-// EnabledState represents whether the user is enabled or not.
-type EnabledState *bool
-
-// Useful variables to use when creating or updating users.
-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 {
// Either a name or username is required. When provided, the value must be
// unique or a 409 conflict error will be returned. If you provide a name but
// omit a username, the latter will be set to the former; and vice versa.
- Name, Username string
-
+ Name string `json:"name,omitempty"`
+ Username string `json:"username,omitempty"`
// The ID of the tenant to which you want to assign this user.
- TenantID string
-
+ TenantID string `json:"tenant_id,omitempty"`
// Indicates whether this user is enabled or not.
- Enabled EnabledState
-
+ Enabled *bool `json:"enabled,omitempty"`
// The email address of this user.
- Email string
+ Email string `json:"email,omitempty"`
}
// CreateOpts represents the options needed when creating new users.
@@ -54,33 +38,13 @@
// ToUserCreateMap assembles a request body based on the contents of a CreateOpts.
func (opts CreateOpts) ToUserCreateMap() (map[string]interface{}, error) {
- m := make(map[string]interface{})
-
if opts.Name == "" && opts.Username == "" {
err := gophercloud.ErrMissingInput{}
- err.Function = "users.ToUserCreateMap"
err.Argument = "users.CreateOpts.Name/users.CreateOpts.Username"
err.Info = "Either a Name or Username must be provided"
- return m, err
+ return nil, err
}
-
- if opts.Name != "" {
- m["name"] = opts.Name
- }
- if opts.Username != "" {
- m["username"] = opts.Username
- }
- if opts.Enabled != nil {
- m["enabled"] = &opts.Enabled
- }
- if opts.Email != "" {
- m["email"] = opts.Email
- }
- if opts.TenantID != "" {
- m["tenant_id"] = opts.TenantID
- }
-
- return map[string]interface{}{"user": m}, nil
+ return gophercloud.BuildRequestBody(opts, "user")
}
// Create is the operation responsible for creating new users.
@@ -109,57 +73,41 @@
// UpdateOptsBuilder allows extensions to add additional attributes to the Update request.
type UpdateOptsBuilder interface {
- ToUserUpdateMap() map[string]interface{}
+ ToUserUpdateMap() (map[string]interface{}, error)
}
// UpdateOpts specifies the base attributes that may be updated on an existing server.
type UpdateOpts CommonOpts
// ToUserUpdateMap formats an UpdateOpts structure into a request body.
-func (opts UpdateOpts) ToUserUpdateMap() map[string]interface{} {
- m := make(map[string]interface{})
-
- if opts.Name != "" {
- m["name"] = opts.Name
- }
- if opts.Username != "" {
- m["username"] = opts.Username
- }
- if opts.Enabled != nil {
- m["enabled"] = &opts.Enabled
- }
- if opts.Email != "" {
- m["email"] = opts.Email
- }
- if opts.TenantID != "" {
- m["tenant_id"] = opts.TenantID
- }
-
- return map[string]interface{}{"user": m}
+func (opts UpdateOpts) ToUserUpdateMap() (map[string]interface{}, error) {
+ return gophercloud.BuildRequestBody(opts, "user")
}
// 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.ToUserUpdateMap()
- _, result.Err = client.Put(ResourceURL(client, id), reqBody, &result.Body, &gophercloud.RequestOpts{
+ var r UpdateResult
+ b, err := opts.ToUserUpdateMap()
+ if err != nil {
+ r.Err = err
+ return r
+ }
+ _, r.Err = client.Put(ResourceURL(client, id), &b, &r.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
- return result
+ return r
}
// 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
+ var r DeleteResult
+ _, r.Err = client.Delete(ResourceURL(client, id), nil)
+ return r
}
// ListRoles lists the existing roles that can be assigned to users.
func ListRoles(client *gophercloud.ServiceClient, tenantID, userID string) pagination.Pager {
- createPage := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, listRolesURL(client, tenantID, userID), func(r pagination.PageResult) pagination.Page {
return RolePage{pagination.SinglePageBase(r)}
- }
-
- return pagination.NewPager(client, listRolesURL(client, tenantID, userID), createPage)
+ })
}
diff --git a/openstack/identity/v2/users/requests_test.go b/openstack/identity/v2/users/requests_test.go
index 8604ab1..0e03653 100644
--- a/openstack/identity/v2/users/requests_test.go
+++ b/openstack/identity/v2/users/requests_test.go
@@ -6,6 +6,7 @@
"github.com/gophercloud/gophercloud/pagination"
th "github.com/gophercloud/gophercloud/testhelper"
"github.com/gophercloud/gophercloud/testhelper/client"
+ "github.com/jrperritt/gophercloud"
)
func TestList(t *testing.T) {
@@ -19,10 +20,7 @@
err := List(client.ServiceClient()).EachPage(func(page pagination.Page) (bool, error) {
count++
actual, err := ExtractUsers(page)
- if err != nil {
- t.Errorf("Failed to extract users: %v", err)
- return false, err
- }
+ th.AssertNoErr(t, err)
expected := []User{
User{
@@ -42,12 +40,9 @@
TenantID: "12345",
},
}
-
th.CheckDeepEquals(t, expected, actual)
-
return true, nil
})
-
th.AssertNoErr(t, err)
th.AssertEquals(t, 1, count)
}
@@ -61,7 +56,7 @@
opts := CreateOpts{
Name: "new_user",
TenantID: "12345",
- Enabled: Disabled,
+ Enabled: gophercloud.Disabled,
Email: "new_user@foo.com",
}
@@ -109,7 +104,7 @@
id := "c39e3de9be2d4c779f1dfd6abacc176d"
opts := UpdateOpts{
Name: "new_name",
- Enabled: Enabled,
+ Enabled: gophercloud.Enabled,
Email: "new_email@foo.com",
}
diff --git a/openstack/identity/v3/endpoints/errors.go b/openstack/identity/v3/endpoints/errors.go
deleted file mode 100644
index 854957f..0000000
--- a/openstack/identity/v3/endpoints/errors.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package endpoints
-
-import "fmt"
-
-func requiredAttribute(attribute string) error {
- return fmt.Errorf("You must specify %s for this endpoint.", attribute)
-}
-
-var (
- // ErrAvailabilityRequired is reported if an Endpoint is created without an Availability.
- ErrAvailabilityRequired = requiredAttribute("an availability")
-
- // ErrNameRequired is reported if an Endpoint is created without a Name.
- ErrNameRequired = requiredAttribute("a name")
-
- // ErrURLRequired is reported if an Endpoint is created without a URL.
- ErrURLRequired = requiredAttribute("a URL")
-
- // ErrServiceIDRequired is reported if an Endpoint is created without a ServiceID.
- ErrServiceIDRequired = requiredAttribute("a serviceID")
-)
diff --git a/openstack/identity/v3/endpoints/requests.go b/openstack/identity/v3/endpoints/requests.go
index c9b8cf5..7165fb4 100644
--- a/openstack/identity/v3/endpoints/requests.go
+++ b/openstack/identity/v3/endpoints/requests.go
@@ -5,59 +5,38 @@
"github.com/gophercloud/gophercloud/pagination"
)
-// EndpointOpts contains the subset of Endpoint attributes that should be used to create or update an Endpoint.
-type EndpointOpts struct {
- Availability gophercloud.Availability
- Name string
- Region string
- URL string
- ServiceID string
+type CreateOptsBuilder interface {
+ ToEndpointCreateMap() (map[string]interface{}, error)
+}
+
+// CreateOpts contains the subset of Endpoint attributes that should be used to create an Endpoint.
+type CreateOpts struct {
+ Availability gophercloud.Availability `json:"interface" required:"true"`
+ Name string `json:"name" required:"true"`
+ Region string `json:"region,omitempty"`
+ URL string `json:"url" required:"true"`
+ ServiceID string `json:"service_id" required:"true"`
+}
+
+func (opts CreateOpts) ToEndpointCreateMap() (map[string]interface{}, error) {
+ return gophercloud.BuildRequestBody(opts, "endpoint")
}
// Create inserts a new Endpoint into the service catalog.
// Within EndpointOpts, Region may be omitted by being left as "", but all other fields are required.
-func Create(client *gophercloud.ServiceClient, opts EndpointOpts) CreateResult {
- // Redefined so that Region can be re-typed as a *string, which can be omitted from the JSON output.
- type endpoint struct {
- Interface string `json:"interface"`
- Name string `json:"name"`
- Region *string `json:"region,omitempty"`
- URL string `json:"url"`
- ServiceID string `json:"service_id"`
+func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
+ var r CreateResult
+ b, err := opts.ToEndpointCreateMap()
+ if err != nil {
+ r.Err = err
+ return r
}
+ _, r.Err = client.Post(listURL(client), &b, &r.Body, nil)
+ return r
+}
- type request struct {
- Endpoint endpoint `json:"endpoint"`
- }
-
- // Ensure that EndpointOpts is fully populated.
- if opts.Availability == "" {
- return createErr(ErrAvailabilityRequired)
- }
- if opts.Name == "" {
- return createErr(ErrNameRequired)
- }
- if opts.URL == "" {
- return createErr(ErrURLRequired)
- }
- if opts.ServiceID == "" {
- return createErr(ErrServiceIDRequired)
- }
-
- // Populate the request body.
- reqBody := request{
- Endpoint: endpoint{
- Interface: string(opts.Availability),
- Name: opts.Name,
- URL: opts.URL,
- ServiceID: opts.ServiceID,
- },
- }
- reqBody.Endpoint.Region = gophercloud.MaybeString(opts.Region)
-
- var result CreateResult
- _, result.Err = client.Post(listURL(client), reqBody, &result.Body, nil)
- return result
+type ListOptsBuilder interface {
+ ToEndpointListParams() (string, error)
}
// ListOpts allows finer control over the endpoints returned by a List call.
@@ -69,55 +48,58 @@
PerPage int `q:"per_page"`
}
-// List enumerates endpoints in a paginated collection, optionally filtered by ListOpts criteria.
-func List(client *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
- u := listURL(client)
+func (opts ListOpts) ToEndpointListParams() (string, error) {
q, err := gophercloud.BuildQueryString(opts)
- if err != nil {
- return pagination.Pager{Err: err}
- }
- u += q.String()
- createPage := func(r pagination.PageResult) pagination.Page {
- return EndpointPage{pagination.LinkedPageBase{PageResult: r}}
- }
+ return q.String(), err
+}
- return pagination.NewPager(client, u, createPage)
+// List enumerates endpoints in a paginated collection, optionally filtered by ListOpts criteria.
+func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
+ u := listURL(client)
+ if opts != nil {
+ q, err := gophercloud.BuildQueryString(opts)
+ if err != nil {
+ return pagination.Pager{Err: err}
+ }
+ u += q.String()
+ }
+ return pagination.NewPager(client, u, func(r pagination.PageResult) pagination.Page {
+ return EndpointPage{pagination.LinkedPageBase{PageResult: r}}
+ })
+}
+
+type UpdateOptsBuilder interface {
+ ToEndpointUpdateMap() (map[string]interface{}, error)
+}
+
+// UpdateOpts contains the subset of Endpoint attributes that should be used to update an Endpoint.
+type UpdateOpts struct {
+ Availability gophercloud.Availability `json:"interface,omitempty"`
+ Name string `json:"name,omitempty"`
+ Region string `json:"region,omitempty"`
+ URL string `json:"url,omitempty"`
+ ServiceID string `json:"service_id,omitempty"`
+}
+
+func (opts UpdateOpts) ToEndpointUpdateMap() (map[string]interface{}, error) {
+ return gophercloud.BuildRequestBody(opts, "endpoint")
}
// Update changes an existing endpoint with new data.
-// All fields are optional in the provided EndpointOpts.
-func Update(client *gophercloud.ServiceClient, endpointID string, opts EndpointOpts) UpdateResult {
- type endpoint struct {
- Interface *string `json:"interface,omitempty"`
- Name *string `json:"name,omitempty"`
- Region *string `json:"region,omitempty"`
- URL *string `json:"url,omitempty"`
- ServiceID *string `json:"service_id,omitempty"`
+func Update(client *gophercloud.ServiceClient, endpointID string, opts UpdateOptsBuilder) UpdateResult {
+ var r UpdateResult
+ b, err := opts.ToEndpointUpdateMap()
+ if err != nil {
+ r.Err = err
+ return r
}
-
- type request struct {
- Endpoint endpoint `json:"endpoint"`
- }
-
- reqBody := request{Endpoint: endpoint{}}
- reqBody.Endpoint.Interface = gophercloud.MaybeString(string(opts.Availability))
- reqBody.Endpoint.Name = gophercloud.MaybeString(opts.Name)
- reqBody.Endpoint.Region = gophercloud.MaybeString(opts.Region)
- reqBody.Endpoint.URL = gophercloud.MaybeString(opts.URL)
- reqBody.Endpoint.ServiceID = gophercloud.MaybeString(opts.ServiceID)
-
- var result UpdateResult
- _, result.Err = client.Request("PATCH", endpointURL(client, endpointID), &gophercloud.RequestOpts{
- JSONBody: &reqBody,
- JSONResponse: &result.Body,
- OkCodes: []int{200},
- })
- return result
+ _, r.Err = client.Patch(endpointURL(client, endpointID), &b, &r.Body, nil)
+ return r
}
// Delete removes an endpoint from the service catalog.
func Delete(client *gophercloud.ServiceClient, endpointID string) DeleteResult {
- var res DeleteResult
- _, res.Err = client.Delete(endpointURL(client, endpointID), nil)
- return res
+ var r DeleteResult
+ _, r.Err = client.Delete(endpointURL(client, endpointID), nil)
+ return r
}
diff --git a/openstack/identity/v3/endpoints/requests_test.go b/openstack/identity/v3/endpoints/requests_test.go
index ec17d17..14bbe6a 100644
--- a/openstack/identity/v3/endpoints/requests_test.go
+++ b/openstack/identity/v3/endpoints/requests_test.go
@@ -3,23 +3,22 @@
import (
"fmt"
"net/http"
- "reflect"
"testing"
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/pagination"
- "github.com/gophercloud/gophercloud/testhelper"
+ th "github.com/gophercloud/gophercloud/testhelper"
"github.com/gophercloud/gophercloud/testhelper/client"
)
func TestCreateSuccessful(t *testing.T) {
- testhelper.SetupHTTP()
- defer testhelper.TeardownHTTP()
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
- testhelper.Mux.HandleFunc("/endpoints", 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, `
+ th.Mux.HandleFunc("/endpoints", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "POST")
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+ th.TestJSONRequest(t, r, `
{
"endpoint": {
"interface": "public",
@@ -49,16 +48,14 @@
`)
})
- actual, err := Create(client.ServiceClient(), EndpointOpts{
+ actual, err := Create(client.ServiceClient(), CreateOpts{
Availability: gophercloud.AvailabilityPublic,
Name: "the-endiest-of-points",
Region: "underground",
URL: "https://1.2.3.4:9000/",
ServiceID: "asdfasdfasdfasdf",
}).Extract()
- if err != nil {
- t.Fatalf("Unable to create an endpoint: %v", err)
- }
+ th.AssertNoErr(t, err)
expected := &Endpoint{
ID: "12",
@@ -69,18 +66,16 @@
URL: "https://1.2.3.4:9000/",
}
- if !reflect.DeepEqual(actual, expected) {
- t.Errorf("Expected %#v, was %#v", expected, actual)
- }
+ th.AssertDeepEquals(t, expected, actual)
}
func TestListEndpoints(t *testing.T) {
- testhelper.SetupHTTP()
- defer testhelper.TeardownHTTP()
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
- testhelper.Mux.HandleFunc("/endpoints", func(w http.ResponseWriter, r *http.Request) {
- testhelper.TestMethod(t, r, "GET")
- testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+ th.Mux.HandleFunc("/endpoints", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
w.Header().Add("Content-Type", "application/json")
fmt.Fprintf(w, `
@@ -144,26 +139,20 @@
URL: "https://1.2.3.4:9001/",
},
}
-
- if !reflect.DeepEqual(expected, actual) {
- t.Errorf("Expected %#v, got %#v", expected, actual)
- }
-
+ th.AssertDeepEquals(t, expected, actual)
return true, nil
})
- if count != 1 {
- t.Errorf("Expected 1 page, got %d", count)
- }
+ th.AssertEquals(t, 1, count)
}
func TestUpdateEndpoint(t *testing.T) {
- testhelper.SetupHTTP()
- defer testhelper.TeardownHTTP()
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
- testhelper.Mux.HandleFunc("/endpoints/12", func(w http.ResponseWriter, r *http.Request) {
- testhelper.TestMethod(t, r, "PATCH")
- testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
- testhelper.TestJSONRequest(t, r, `
+ th.Mux.HandleFunc("/endpoints/12", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "PATCH")
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+ th.TestJSONRequest(t, r, `
{
"endpoint": {
"name": "renamed",
@@ -189,7 +178,7 @@
`)
})
- actual, err := Update(client.ServiceClient(), "12", EndpointOpts{
+ actual, err := Update(client.ServiceClient(), "12", UpdateOpts{
Name: "renamed",
Region: "somewhere-else",
}).Extract()
@@ -205,22 +194,20 @@
ServiceID: "asdfasdfasdfasdf",
URL: "https://1.2.3.4:9000/",
}
- if !reflect.DeepEqual(expected, actual) {
- t.Errorf("Expected %#v, was %#v", expected, actual)
- }
+ th.AssertDeepEquals(t, expected, actual)
}
func TestDeleteEndpoint(t *testing.T) {
- testhelper.SetupHTTP()
- defer testhelper.TeardownHTTP()
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
- testhelper.Mux.HandleFunc("/endpoints/34", func(w http.ResponseWriter, r *http.Request) {
- testhelper.TestMethod(t, r, "DELETE")
- testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+ th.Mux.HandleFunc("/endpoints/34", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "DELETE")
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
w.WriteHeader(http.StatusNoContent)
})
res := Delete(client.ServiceClient(), "34")
- testhelper.AssertNoErr(t, res.Err)
+ th.AssertNoErr(t, res.Err)
}
diff --git a/openstack/identity/v3/roles/requests.go b/openstack/identity/v3/roles/requests.go
index 0264347..de65c51 100644
--- a/openstack/identity/v3/roles/requests.go
+++ b/openstack/identity/v3/roles/requests.go
@@ -17,34 +17,31 @@
// Effective lists effective assignments at the user, project, and domain level,
// allowing for the effects of group membership.
type ListAssignmentsOpts struct {
- GroupId string `q:"group.id"`
- RoleId string `q:"role.id"`
- ScopeDomainId string `q:"scope.domain.id"`
- ScopeProjectId string `q:"scope.project.id"`
- UserId string `q:"user.id"`
- Effective bool `q:"effective"`
+ GroupID string `q:"group.id"`
+ RoleID string `q:"role.id"`
+ ScopeDomainID string `q:"scope.domain.id"`
+ ScopeProjectID string `q:"scope.project.id"`
+ UserID string `q:"user.id"`
+ Effective *bool `q:"effective"`
}
// ToRolesListAssignmentsQuery formats a ListAssignmentsOpts into a query string.
func (opts ListAssignmentsOpts) ToRolesListAssignmentsQuery() (string, error) {
q, err := gophercloud.BuildQueryString(opts)
- if err != nil {
- return "", err
- }
- return q.String(), nil
+ return q.String(), err
}
// ListAssignments enumerates the roles assigned to a specified resource.
func ListAssignments(client *gophercloud.ServiceClient, opts ListAssignmentsOptsBuilder) pagination.Pager {
url := listAssignmentsURL(client)
- query, err := opts.ToRolesListAssignmentsQuery()
- if err != nil {
- return pagination.Pager{Err: err}
+ if opts != nil {
+ query, err := opts.ToRolesListAssignmentsQuery()
+ if err != nil {
+ return pagination.Pager{Err: err}
+ }
+ url += query
}
- url += query
- createPage := func(r pagination.PageResult) pagination.Page {
+ return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
return RoleAssignmentPage{pagination.LinkedPageBase{PageResult: r}}
- }
-
- return pagination.NewPager(client, url, createPage)
+ })
}
diff --git a/openstack/identity/v3/services/requests.go b/openstack/identity/v3/services/requests.go
index 484afab..34bf979 100644
--- a/openstack/identity/v3/services/requests.go
+++ b/openstack/identity/v3/services/requests.go
@@ -5,21 +5,16 @@
"github.com/gophercloud/gophercloud/pagination"
)
-type response struct {
- Service Service `json:"service"`
-}
-
// Create adds a new service of the requested type to the catalog.
func Create(client *gophercloud.ServiceClient, serviceType string) CreateResult {
- type request struct {
- Type string `json:"type"`
- }
+ var r CreateResult
+ b := map[string]string{"type": serviceType}
+ _, r.Err = client.Post(listURL(client), b, &r.Body, nil)
+ return r
+}
- req := request{Type: serviceType}
-
- var result CreateResult
- _, result.Err = client.Post(listURL(client), req, &result.Body, nil)
- return result
+type ListOptsBuilder interface {
+ ToServiceListMap() (string, error)
}
// ListOpts allows you to query the List method.
@@ -29,49 +24,45 @@
Page int `q:"page"`
}
-// List enumerates the services available to a specific user.
-func List(client *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
- u := listURL(client)
+func (opts ListOpts) ToServiceListMap() (string, error) {
q, err := gophercloud.BuildQueryString(opts)
- if err != nil {
- return pagination.Pager{Err: err}
- }
- u += q.String()
- createPage := func(r pagination.PageResult) pagination.Page {
- return ServicePage{pagination.LinkedPageBase{PageResult: r}}
- }
+ return q.String(), err
+}
- return pagination.NewPager(client, u, createPage)
+// List enumerates the services available to a specific user.
+func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
+ u := listURL(client)
+ if opts != nil {
+ q, err := opts.ToServiceListMap()
+ if err != nil {
+ return pagination.Pager{Err: err}
+ }
+ u += q
+ }
+ return pagination.NewPager(client, u, func(r pagination.PageResult) pagination.Page {
+ return ServicePage{pagination.LinkedPageBase{PageResult: r}}
+ })
}
// Get returns additional information about a service, given its ID.
func Get(client *gophercloud.ServiceClient, serviceID string) GetResult {
- var result GetResult
- _, result.Err = client.Get(serviceURL(client, serviceID), &result.Body, nil)
- return result
+ var r GetResult
+ _, r.Err = client.Get(serviceURL(client, serviceID), &r.Body, nil)
+ return r
}
// Update changes the service type of an existing service.
func Update(client *gophercloud.ServiceClient, serviceID string, serviceType string) UpdateResult {
- type request struct {
- Type string `json:"type"`
- }
-
- req := request{Type: serviceType}
-
- var result UpdateResult
- _, result.Err = client.Request("PATCH", serviceURL(client, serviceID), &gophercloud.RequestOpts{
- JSONBody: &req,
- JSONResponse: &result.Body,
- OkCodes: []int{200},
- })
- return result
+ var r UpdateResult
+ b := map[string]string{"type": serviceType}
+ _, r.Err = client.Patch(serviceURL(client, serviceID), &b, &r.Body, nil)
+ return r
}
// Delete removes an existing service.
// It either deletes all associated endpoints, or fails until all endpoints are deleted.
func Delete(client *gophercloud.ServiceClient, serviceID string) DeleteResult {
- var res DeleteResult
- _, res.Err = client.Delete(serviceURL(client, serviceID), nil)
- return res
+ var r DeleteResult
+ _, r.Err = client.Delete(serviceURL(client, serviceID), nil)
+ return r
}
diff --git a/openstack/identity/v3/services/requests_test.go b/openstack/identity/v3/services/requests_test.go
index ebe9e0f..aa19bcc 100644
--- a/openstack/identity/v3/services/requests_test.go
+++ b/openstack/identity/v3/services/requests_test.go
@@ -3,22 +3,21 @@
import (
"fmt"
"net/http"
- "reflect"
"testing"
"github.com/gophercloud/gophercloud/pagination"
- "github.com/gophercloud/gophercloud/testhelper"
+ th "github.com/gophercloud/gophercloud/testhelper"
"github.com/gophercloud/gophercloud/testhelper/client"
)
func TestCreateSuccessful(t *testing.T) {
- testhelper.SetupHTTP()
- defer testhelper.TeardownHTTP()
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
- testhelper.Mux.HandleFunc("/services", 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, `{ "type": "compute" }`)
+ th.Mux.HandleFunc("/services", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "POST")
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+ th.TestJSONRequest(t, r, `{ "type": "compute" }`)
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
@@ -32,32 +31,27 @@
}`)
})
- result, err := Create(client.ServiceClient(), "compute").Extract()
+ expected := &Service{
+ Description: "Here's your service",
+ ID: "1234",
+ Name: "InscrutableOpenStackProjectName",
+ Type: "compute",
+ }
+
+ actual, err := Create(client.ServiceClient(), "compute").Extract()
if err != nil {
t.Fatalf("Unexpected error from Create: %v", err)
}
-
- if result.Description == nil || *result.Description != "Here's your service" {
- t.Errorf("Service description was unexpected [%s]", *result.Description)
- }
- if result.ID != "1234" {
- t.Errorf("Service ID was unexpected [%s]", result.ID)
- }
- if result.Name != "InscrutableOpenStackProjectName" {
- t.Errorf("Service name was unexpected [%s]", result.Name)
- }
- if result.Type != "compute" {
- t.Errorf("Service type was unexpected [%s]", result.Type)
- }
+ th.AssertDeepEquals(t, expected, actual)
}
func TestListSinglePage(t *testing.T) {
- testhelper.SetupHTTP()
- defer testhelper.TeardownHTTP()
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
- testhelper.Mux.HandleFunc("/services", func(w http.ResponseWriter, r *http.Request) {
- testhelper.TestMethod(t, r, "GET")
- testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+ th.Mux.HandleFunc("/services", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
w.Header().Add("Content-Type", "application/json")
fmt.Fprintf(w, `
@@ -92,44 +86,34 @@
return false, err
}
- desc0 := "Service One"
- desc1 := "Service Two"
expected := []Service{
Service{
- Description: &desc0,
+ Description: "Service One",
ID: "1234",
Name: "service-one",
Type: "identity",
},
Service{
- Description: &desc1,
+ Description: "Service Two",
ID: "9876",
Name: "service-two",
Type: "compute",
},
}
-
- if !reflect.DeepEqual(expected, actual) {
- t.Errorf("Expected %#v, got %#v", expected, actual)
- }
-
+ th.AssertDeepEquals(t, expected, actual)
return true, nil
})
- if err != nil {
- t.Errorf("Unexpected error while paging: %v", err)
- }
- if count != 1 {
- t.Errorf("Expected 1 page, got %d", count)
- }
+ th.AssertNoErr(t, err)
+ th.AssertEquals(t, 1, count)
}
func TestGetSuccessful(t *testing.T) {
- testhelper.SetupHTTP()
- defer testhelper.TeardownHTTP()
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
- testhelper.Mux.HandleFunc("/services/12345", func(w http.ResponseWriter, r *http.Request) {
- testhelper.TestMethod(t, r, "GET")
- testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+ th.Mux.HandleFunc("/services/12345", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
w.Header().Add("Content-Type", "application/json")
fmt.Fprintf(w, `
@@ -144,33 +128,27 @@
`)
})
- result, err := Get(client.ServiceClient(), "12345").Extract()
- if err != nil {
- t.Fatalf("Error fetching service information: %v", err)
+ actual, err := Get(client.ServiceClient(), "12345").Extract()
+ th.AssertNoErr(t, err)
+
+ expected := &Service{
+ ID: "12345",
+ Description: "Service One",
+ Name: "service-one",
+ Type: "identity",
}
- if result.ID != "12345" {
- t.Errorf("Unexpected service ID: %s", result.ID)
- }
- if *result.Description != "Service One" {
- t.Errorf("Unexpected service description: [%s]", *result.Description)
- }
- if result.Name != "service-one" {
- t.Errorf("Unexpected service name: [%s]", result.Name)
- }
- if result.Type != "identity" {
- t.Errorf("Unexpected service type: [%s]", result.Type)
- }
+ th.AssertDeepEquals(t, expected, actual)
}
func TestUpdateSuccessful(t *testing.T) {
- testhelper.SetupHTTP()
- defer testhelper.TeardownHTTP()
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
- testhelper.Mux.HandleFunc("/services/12345", func(w http.ResponseWriter, r *http.Request) {
- testhelper.TestMethod(t, r, "PATCH")
- testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
- testhelper.TestJSONRequest(t, r, `{ "type": "lasermagic" }`)
+ th.Mux.HandleFunc("/services/12345", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "PATCH")
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+ th.TestJSONRequest(t, r, `{ "type": "lasermagic" }`)
w.Header().Add("Content-Type", "application/json")
fmt.Fprintf(w, `
@@ -183,27 +161,26 @@
`)
})
- result, err := Update(client.ServiceClient(), "12345", "lasermagic").Extract()
- if err != nil {
- t.Fatalf("Unable to update service: %v", err)
+ expected := &Service{
+ ID: "12345",
+ Type: "lasermagic",
}
- if result.ID != "12345" {
- t.Fatalf("Expected ID 12345, was %s", result.ID)
- }
+ actual, err := Update(client.ServiceClient(), "12345", "lasermagic").Extract()
+ th.AssertNoErr(t, err)
+ th.AssertDeepEquals(t, expected, actual)
}
func TestDeleteSuccessful(t *testing.T) {
- testhelper.SetupHTTP()
- defer testhelper.TeardownHTTP()
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
- testhelper.Mux.HandleFunc("/services/12345", func(w http.ResponseWriter, r *http.Request) {
- testhelper.TestMethod(t, r, "DELETE")
- testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID)
-
+ th.Mux.HandleFunc("/services/12345", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "DELETE")
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
w.WriteHeader(http.StatusNoContent)
})
res := Delete(client.ServiceClient(), "12345")
- testhelper.AssertNoErr(t, res.Err)
+ th.AssertNoErr(t, res.Err)
}
diff --git a/openstack/identity/v3/services/results.go b/openstack/identity/v3/services/results.go
index b0d36fb..9ebcc20 100644
--- a/openstack/identity/v3/services/results.go
+++ b/openstack/identity/v3/services/results.go
@@ -41,10 +41,10 @@
// Service is the result of a list or information query.
type Service struct {
- Description *string `json:"description,omitempty"`
- ID string `json:"id"`
- Name string `json:"name"`
- Type string `json:"type"`
+ Description string `json:"description`
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Type string `json:"type"`
}
// ServicePage is a single page of Service results.
diff --git a/openstack/identity/v3/tokens/requests.go b/openstack/identity/v3/tokens/requests.go
index 4b87311..e7320fd 100644
--- a/openstack/identity/v3/tokens/requests.go
+++ b/openstack/identity/v3/tokens/requests.go
@@ -6,12 +6,11 @@
"github.com/gophercloud/gophercloud"
)
-// Scope allows a created token to be limited to a specific domain or project.
-type Scope struct {
- ProjectID string
- ProjectName string
- DomainID string
- DomainName string
+// AuthOptionsBuilder describes any argument that may be passed to the Create call.
+type AuthOptionsBuilder interface {
+ // ToTokenV3CreateMap assembles the Create request body, returning an error if parameters are
+ // missing or inconsistent.
+ ToTokenV3CreateMap(*gophercloud.ScopeOptsV3) (map[string]interface{}, error)
}
func subjectTokenHeaders(c *gophercloud.ServiceClient, subjectToken string) map[string]string {
@@ -21,241 +20,33 @@
}
// Create authenticates and either generates a new token, or changes the Scope of an existing token.
-func Create(c *gophercloud.ServiceClient, options gophercloud.AuthOptions, scope *Scope) CreateResult {
- type domainReq struct {
- ID *string `json:"id,omitempty"`
- Name *string `json:"name,omitempty"`
+func Create(c *gophercloud.ServiceClient, opts AuthOptionsBuilder, scopeOpts *gophercloud.ScopeOptsV3) CreateResult {
+ var r CreateResult
+ b, err := opts.ToTokenV3CreateMap(scopeOpts)
+ if err != nil {
+ r.Err = err
+ return r
}
-
- type projectReq struct {
- Domain *domainReq `json:"domain,omitempty"`
- Name *string `json:"name,omitempty"`
- ID *string `json:"id,omitempty"`
+ var resp *http.Response
+ resp, r.Err = c.Post(tokenURL(c), b, &r.Body, nil)
+ if resp != nil {
+ r.Header = resp.Header
}
-
- type userReq struct {
- ID *string `json:"id,omitempty"`
- Name *string `json:"name,omitempty"`
- Password string `json:"password"`
- Domain *domainReq `json:"domain,omitempty"`
- }
-
- type passwordReq struct {
- User userReq `json:"user"`
- }
-
- type tokenReq struct {
- ID string `json:"id"`
- }
-
- type identityReq struct {
- Methods []string `json:"methods"`
- Password *passwordReq `json:"password,omitempty"`
- Token *tokenReq `json:"token,omitempty"`
- }
-
- type scopeReq struct {
- Domain *domainReq `json:"domain,omitempty"`
- Project *projectReq `json:"project,omitempty"`
- }
-
- type authReq struct {
- Identity identityReq `json:"identity"`
- Scope *scopeReq `json:"scope,omitempty"`
- }
-
- type request struct {
- Auth authReq `json:"auth"`
- }
-
- // Populate the request structure based on the provided arguments. Create and return an error
- // if insufficient or incompatible information is present.
- var req request
-
- // Test first for unrecognized arguments.
- if options.APIKey != "" {
- return createErr(ErrAPIKeyProvided)
- }
- if options.TenantID != "" {
- return createErr(ErrTenantIDProvided)
- }
- if options.TenantName != "" {
- return createErr(ErrTenantNameProvided)
- }
-
- if options.Password == "" {
- if c.TokenID != "" {
- // Because we aren't using password authentication, it's an error to also provide any of the user-based authentication
- // parameters.
- if options.Username != "" {
- return createErr(ErrUsernameWithToken)
- }
- if options.UserID != "" {
- return createErr(ErrUserIDWithToken)
- }
- if options.DomainID != "" {
- return createErr(ErrDomainIDWithToken)
- }
- if options.DomainName != "" {
- return createErr(ErrDomainNameWithToken)
- }
-
- // Configure the request for Token authentication.
- req.Auth.Identity.Methods = []string{"token"}
- req.Auth.Identity.Token = &tokenReq{
- ID: c.TokenID,
- }
- } else {
- // If no password or token ID are available, authentication can't continue.
- return createErr(ErrMissingPassword)
- }
- } else {
- // Password authentication.
- req.Auth.Identity.Methods = []string{"password"}
-
- // At least one of Username and UserID must be specified.
- if options.Username == "" && options.UserID == "" {
- return createErr(ErrUsernameOrUserID)
- }
-
- if options.Username != "" {
- // If Username is provided, UserID may not be provided.
- if options.UserID != "" {
- return createErr(ErrUsernameOrUserID)
- }
-
- // Either DomainID or DomainName must also be specified.
- if options.DomainID == "" && options.DomainName == "" {
- return createErr(ErrDomainIDOrDomainName)
- }
-
- if options.DomainID != "" {
- if options.DomainName != "" {
- return createErr(ErrDomainIDOrDomainName)
- }
-
- // Configure the request for Username and Password authentication with a DomainID.
- req.Auth.Identity.Password = &passwordReq{
- User: userReq{
- Name: &options.Username,
- Password: options.Password,
- Domain: &domainReq{ID: &options.DomainID},
- },
- }
- }
-
- if options.DomainName != "" {
- // Configure the request for Username and Password authentication with a DomainName.
- req.Auth.Identity.Password = &passwordReq{
- User: userReq{
- Name: &options.Username,
- Password: options.Password,
- Domain: &domainReq{Name: &options.DomainName},
- },
- }
- }
- }
-
- if options.UserID != "" {
- // If UserID is specified, neither DomainID nor DomainName may be.
- if options.DomainID != "" {
- return createErr(ErrDomainIDWithUserID)
- }
- if options.DomainName != "" {
- return createErr(ErrDomainNameWithUserID)
- }
-
- // Configure the request for UserID and Password authentication.
- req.Auth.Identity.Password = &passwordReq{
- User: userReq{ID: &options.UserID, Password: options.Password},
- }
- }
- }
-
- // Add a "scope" element if a Scope has been provided.
- if scope != nil {
- if scope.ProjectName != "" {
- // ProjectName provided: either DomainID or DomainName must also be supplied.
- // ProjectID may not be supplied.
- if scope.DomainID == "" && scope.DomainName == "" {
- return createErr(ErrScopeDomainIDOrDomainName)
- }
- if scope.ProjectID != "" {
- return createErr(ErrScopeProjectIDOrProjectName)
- }
-
- if scope.DomainID != "" {
- // ProjectName + DomainID
- req.Auth.Scope = &scopeReq{
- Project: &projectReq{
- Name: &scope.ProjectName,
- Domain: &domainReq{ID: &scope.DomainID},
- },
- }
- }
-
- if scope.DomainName != "" {
- // ProjectName + DomainName
- req.Auth.Scope = &scopeReq{
- Project: &projectReq{
- Name: &scope.ProjectName,
- Domain: &domainReq{Name: &scope.DomainName},
- },
- }
- }
- } else if scope.ProjectID != "" {
- // ProjectID provided. ProjectName, DomainID, and DomainName may not be provided.
- if scope.DomainID != "" {
- return createErr(ErrScopeProjectIDAlone)
- }
- if scope.DomainName != "" {
- return createErr(ErrScopeProjectIDAlone)
- }
-
- // ProjectID
- req.Auth.Scope = &scopeReq{
- Project: &projectReq{ID: &scope.ProjectID},
- }
- } else if scope.DomainID != "" {
- // DomainID provided. ProjectID, ProjectName, and DomainName may not be provided.
- if scope.DomainName != "" {
- return createErr(ErrScopeDomainIDOrDomainName)
- }
-
- // DomainID
- req.Auth.Scope = &scopeReq{
- Domain: &domainReq{ID: &scope.DomainID},
- }
- } else if scope.DomainName != "" {
- return createErr(ErrScopeDomainName)
- } else {
- return createErr(ErrScopeEmpty)
- }
- }
-
- var result CreateResult
- var response *http.Response
- response, result.Err = c.Post(tokenURL(c), req, &result.Body, nil)
- if result.Err != nil {
- return result
- }
- result.Header = response.Header
- return result
+ return r
}
// Get validates and retrieves information about another token.
func Get(c *gophercloud.ServiceClient, token string) GetResult {
- var result GetResult
- var response *http.Response
- response, result.Err = c.Get(tokenURL(c), &result.Body, &gophercloud.RequestOpts{
+ var r GetResult
+ var resp *http.Response
+ resp, r.Err = c.Get(tokenURL(c), &r.Body, &gophercloud.RequestOpts{
MoreHeaders: subjectTokenHeaders(c, token),
OkCodes: []int{200, 203},
})
- if result.Err != nil {
- return result
+ if resp != nil {
+ r.Header = resp.Header
}
- result.Header = response.Header
- return result
+ return r
}
// Validate determines if a specified token is valid or not.
@@ -273,9 +64,9 @@
// Revoke immediately makes specified token invalid.
func Revoke(c *gophercloud.ServiceClient, token string) RevokeResult {
- var res RevokeResult
- _, res.Err = c.Delete(tokenURL(c), &gophercloud.RequestOpts{
+ var r RevokeResult
+ _, r.Err = c.Delete(tokenURL(c), &gophercloud.RequestOpts{
MoreHeaders: subjectTokenHeaders(c, token),
})
- return res
+ return r
}
diff --git a/openstack/identity/v3/tokens/requests_test.go b/openstack/identity/v3/tokens/requests_test.go
index 89d3b51..a39a6f4 100644
--- a/openstack/identity/v3/tokens/requests_test.go
+++ b/openstack/identity/v3/tokens/requests_test.go
@@ -11,7 +11,7 @@
)
// authTokenPost verifies that providing certain AuthOptions and Scope results in an expected JSON structure.
-func authTokenPost(t *testing.T, options gophercloud.AuthOptions, scope *Scope, requestJSON string) {
+func authTokenPost(t *testing.T, options AuthOptionsBuilder, scope *gophercloud.ScopeOptsV3, requestJSON string) {
testhelper.SetupHTTP()
defer testhelper.TeardownHTTP()
@@ -42,7 +42,7 @@
}
}
-func authTokenPostErr(t *testing.T, options gophercloud.AuthOptions, scope *Scope, includeToken bool, expectedErr error) {
+func authTokenPostErr(t *testing.T, options AuthOptionsBuilder, scope *gophercloud.ScopeOptsV3, includeToken bool, expectedErr error) {
testhelper.SetupHTTP()
defer testhelper.TeardownHTTP()
@@ -64,7 +64,10 @@
}
func TestCreateUserIDAndPassword(t *testing.T) {
- authTokenPost(t, gophercloud.AuthOptions{UserID: "me", Password: "squirrel!"}, nil, `
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "me"
+ ao.Password = "squirrel!"
+ authTokenPost(t, ao, nil, `
{
"auth": {
"identity": {
@@ -79,7 +82,10 @@
}
func TestCreateUsernameDomainIDPassword(t *testing.T) {
- authTokenPost(t, gophercloud.AuthOptions{Username: "fakey", Password: "notpassword", DomainID: "abc123"}, nil, `
+ ao := gophercloud.AuthOptions{DomainID: "abc123"}
+ ao.Username = "fakey"
+ ao.Password = "notpassword"
+ authTokenPost(t, ao, nil, `
{
"auth": {
"identity": {
@@ -100,7 +106,10 @@
}
func TestCreateUsernameDomainNamePassword(t *testing.T) {
- authTokenPost(t, gophercloud.AuthOptions{Username: "frank", Password: "swordfish", DomainName: "spork.net"}, nil, `
+ ao := gophercloud.AuthOptions{DomainName: "spork.net"}
+ ao.Username = "frank"
+ ao.Password = "swordfish"
+ authTokenPost(t, ao, nil, `
{
"auth": {
"identity": {
@@ -121,7 +130,7 @@
}
func TestCreateTokenID(t *testing.T) {
- authTokenPost(t, gophercloud.AuthOptions{}, nil, `
+ authTokenPost(t, gophercloud.AuthOptions{TokenID: "12345abcdef"}, nil, `
{
"auth": {
"identity": {
@@ -136,9 +145,11 @@
}
func TestCreateProjectIDScope(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
- scope := &Scope{ProjectID: "123456"}
- authTokenPost(t, options, scope, `
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "fenris"
+ ao.Password = "g0t0h311"
+ scope := &gophercloud.ScopeOptsV3{ProjectID: "123456"}
+ authTokenPost(t, ao, scope, `
{
"auth": {
"identity": {
@@ -161,9 +172,11 @@
}
func TestCreateDomainIDScope(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
- scope := &Scope{DomainID: "1000"}
- authTokenPost(t, options, scope, `
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "fenris"
+ ao.Password = "g0t0h311"
+ scope := &gophercloud.ScopeOptsV3{DomainID: "1000"}
+ authTokenPost(t, ao, scope, `
{
"auth": {
"identity": {
@@ -186,9 +199,11 @@
}
func TestCreateProjectNameAndDomainIDScope(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
- scope := &Scope{ProjectName: "world-domination", DomainID: "1000"}
- authTokenPost(t, options, scope, `
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "fenris"
+ ao.Password = "g0t0h311"
+ scope := &gophercloud.ScopeOptsV3{ProjectName: "world-domination", DomainID: "1000"}
+ authTokenPost(t, ao, scope, `
{
"auth": {
"identity": {
@@ -214,9 +229,11 @@
}
func TestCreateProjectNameAndDomainNameScope(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
- scope := &Scope{ProjectName: "world-domination", DomainName: "evil-plans"}
- authTokenPost(t, options, scope, `
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "fenris"
+ ao.Password = "g0t0h311"
+ scope := &gophercloud.ScopeOptsV3{ProjectName: "world-domination", DomainName: "evil-plans"}
+ authTokenPost(t, ao, scope, `
{
"auth": {
"identity": {
@@ -261,8 +278,10 @@
}`)
})
- options := gophercloud.AuthOptions{UserID: "me", Password: "shhh"}
- token, err := Create(&client, options, nil).Extract()
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "me"
+ ao.Password = "shhh"
+ token, err := Create(&client, ao, nil).Extract()
if err != nil {
t.Fatalf("Create returned an error: %v", err)
}
@@ -276,20 +295,10 @@
authTokenPostErr(t, gophercloud.AuthOptions{}, nil, false, ErrMissingPassword)
}
-func TestCreateFailureAPIKey(t *testing.T) {
- authTokenPostErr(t, gophercloud.AuthOptions{APIKey: "something"}, nil, false, ErrAPIKeyProvided)
-}
-
-func TestCreateFailureTenantID(t *testing.T) {
- authTokenPostErr(t, gophercloud.AuthOptions{TenantID: "something"}, nil, false, ErrTenantIDProvided)
-}
-
-func TestCreateFailureTenantName(t *testing.T) {
- authTokenPostErr(t, gophercloud.AuthOptions{TenantName: "something"}, nil, false, ErrTenantNameProvided)
-}
-
func TestCreateFailureTokenIDUsername(t *testing.T) {
- authTokenPostErr(t, gophercloud.AuthOptions{Username: "something"}, nil, true, ErrUsernameWithToken)
+ ao := gophercloud.AuthOptions{}
+ ao.Username = "somthing"
+ authTokenPostErr(t, ao, nil, true, ErrUsernameWithToken)
}
func TestCreateFailureTokenIDUserID(t *testing.T) {
@@ -305,95 +314,105 @@
}
func TestCreateFailureMissingUser(t *testing.T) {
- options := gophercloud.AuthOptions{Password: "supersecure"}
- authTokenPostErr(t, options, nil, false, ErrUsernameOrUserID)
+ ao := gophercloud.AuthOptions{}
+ ao.Password = "supersecure"
+ authTokenPostErr(t, ao, nil, false, ErrUsernameOrUserID)
}
func TestCreateFailureBothUser(t *testing.T) {
- options := gophercloud.AuthOptions{
- Password: "supersecure",
- Username: "oops",
- UserID: "redundancy",
- }
- authTokenPostErr(t, options, nil, false, ErrUsernameOrUserID)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "redundancy"
+ ao.Username = "oops"
+ ao.Password = "supersecure"
+ authTokenPostErr(t, ao, nil, false, ErrUsernameOrUserID)
}
func TestCreateFailureMissingDomain(t *testing.T) {
- options := gophercloud.AuthOptions{
- Password: "supersecure",
- Username: "notuniqueenough",
- }
- authTokenPostErr(t, options, nil, false, ErrDomainIDOrDomainName)
+ ao := gophercloud.AuthOptions{}
+ ao.Username = "notuniqueenough"
+ ao.Password = "supersecure"
+ authTokenPostErr(t, ao, nil, false, ErrDomainIDOrDomainName)
}
func TestCreateFailureBothDomain(t *testing.T) {
- options := gophercloud.AuthOptions{
- Password: "supersecure",
- Username: "someone",
- DomainID: "hurf",
- DomainName: "durf",
- }
- authTokenPostErr(t, options, nil, false, ErrDomainIDOrDomainName)
+ ao := gophercloud.AuthOptions{}
+ ao.Username = "someone"
+ ao.Password = "supersecure"
+ ao.DomainID = "hurf"
+ ao.DomainName = "durf"
+ authTokenPostErr(t, ao, nil, false, ErrDomainIDOrDomainName)
}
func TestCreateFailureUserIDDomainID(t *testing.T) {
- options := gophercloud.AuthOptions{
- UserID: "100",
- Password: "stuff",
- DomainID: "oops",
- }
- authTokenPostErr(t, options, nil, false, ErrDomainIDWithUserID)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "100"
+ ao.Password = "stuff"
+ ao.DomainID = "oops"
+ authTokenPostErr(t, ao, nil, false, ErrDomainIDWithUserID)
}
func TestCreateFailureUserIDDomainName(t *testing.T) {
- options := gophercloud.AuthOptions{
- UserID: "100",
- Password: "sssh",
- DomainName: "oops",
- }
- authTokenPostErr(t, options, nil, false, ErrDomainNameWithUserID)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "100"
+ ao.Password = "sssh"
+ ao.DomainName = "oops"
+ authTokenPostErr(t, ao, nil, false, ErrDomainNameWithUserID)
}
func TestCreateFailureScopeProjectNameAlone(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
- scope := &Scope{ProjectName: "notenough"}
- authTokenPostErr(t, options, scope, false, ErrScopeDomainIDOrDomainName)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "myself"
+ ao.Password = "swordfish"
+ scope := &gophercloud.ScopeOptsV3{ProjectName: "notenough"}
+ authTokenPostErr(t, ao, scope, false, ErrScopeDomainIDOrDomainName)
}
func TestCreateFailureScopeProjectNameAndID(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
- scope := &Scope{ProjectName: "whoops", ProjectID: "toomuch", DomainID: "1234"}
- authTokenPostErr(t, options, scope, false, ErrScopeProjectIDOrProjectName)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "myself"
+ ao.Password = "swordfish"
+ scope := &gophercloud.ScopeOptsV3{ProjectName: "whoops", ProjectID: "toomuch", DomainID: "1234"}
+ authTokenPostErr(t, ao, scope, false, ErrScopeProjectIDOrProjectName)
}
func TestCreateFailureScopeProjectIDAndDomainID(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
- scope := &Scope{ProjectID: "toomuch", DomainID: "notneeded"}
- authTokenPostErr(t, options, scope, false, ErrScopeProjectIDAlone)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "myself"
+ ao.Password = "swordfish"
+ scope := &gophercloud.ScopeOptsV3{ProjectID: "toomuch", DomainID: "notneeded"}
+ authTokenPostErr(t, ao, scope, false, ErrScopeProjectIDAlone)
}
func TestCreateFailureScopeProjectIDAndDomainNAme(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
- scope := &Scope{ProjectID: "toomuch", DomainName: "notneeded"}
- authTokenPostErr(t, options, scope, false, ErrScopeProjectIDAlone)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "myself"
+ ao.Password = "swordfish"
+ scope := &gophercloud.ScopeOptsV3{ProjectID: "toomuch", DomainName: "notneeded"}
+ authTokenPostErr(t, ao, scope, false, ErrScopeProjectIDAlone)
}
func TestCreateFailureScopeDomainIDAndDomainName(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
- scope := &Scope{DomainID: "toomuch", DomainName: "notneeded"}
- authTokenPostErr(t, options, scope, false, ErrScopeDomainIDOrDomainName)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "myself"
+ ao.Password = "swordfish"
+ scope := &gophercloud.ScopeOptsV3{DomainID: "toomuch", DomainName: "notneeded"}
+ authTokenPostErr(t, ao, scope, false, ErrScopeDomainIDOrDomainName)
}
func TestCreateFailureScopeDomainNameAlone(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
- scope := &Scope{DomainName: "notenough"}
- authTokenPostErr(t, options, scope, false, ErrScopeDomainName)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "myself"
+ ao.Password = "swordfish"
+ scope := &gophercloud.ScopeOptsV3{DomainName: "notenough"}
+ authTokenPostErr(t, ao, scope, false, ErrScopeDomainName)
}
func TestCreateFailureEmptyScope(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
- scope := &Scope{}
- authTokenPostErr(t, options, scope, false, ErrScopeEmpty)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "myself"
+ ao.Password = "swordfish"
+ scope := &gophercloud.ScopeOptsV3{}
+ authTokenPostErr(t, ao, scope, false, ErrScopeEmpty)
}
func TestGetRequest(t *testing.T) {