dsl struct tags; wip
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()