create map from 'CreateOptsBuilder'; rackspace boot from volume; untested acceptance test
diff --git a/openstack/compute/v2/extensions/bootfromvolume/requests.go b/openstack/compute/v2/extensions/bootfromvolume/requests.go
index bbef496..d5b361b 100644
--- a/openstack/compute/v2/extensions/bootfromvolume/requests.go
+++ b/openstack/compute/v2/extensions/bootfromvolume/requests.go
@@ -2,24 +2,54 @@
import (
"errors"
+ "strconv"
+ "github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
+
+ "github.com/racker/perigee"
)
+// 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.
+ BootIndex int
+
+ // DeleteOnTermination [optional] specifies whether or not to delete the attached volume
+ // when the server is deleted. Defaults to `false`.
+ DeleteOnTermination bool
+
+ // DestinationType [optional] is the type that gets created. Possible values are "volume"
+ // and "local".
+ DestinationType string
+
+ // SourceType [optional] must be one of: "volume", "snapshot", "image".
+ SourceType string
+
+ // UUID [optional] is the unique identifier for the volume, snapshot, or image (see above)
+ UUID string
+
+ // VolumeSize [optional] is the size of the volume to create (in gigabytes).
+ VolumeSize int
+}
+
+// CreateOptsExt is a structure that extends the server `CreateOpts` structure
+// by allowing for a block device mapping.
type CreateOptsExt struct {
servers.CreateOptsBuilder
- BDM BlockDeviceMapping
+ BlockDevice BlockDevice
}
// ToServerCreateMap adds the block device mapping option to the base server
// creation options.
func (opts CreateOptsExt) ToServerCreateMap() (map[string]interface{}, error) {
- if opts.BDM.SourceType != "volume" && opts.BDM.SourceType != "image" && opts.BDM.SourceType != "snapshot" {
- return nil, errors.New("SourceType must be one of: volume, image, snapshot.")
- }
-
- if opts.BDM.UUID == "" {
- return nil, errors.New("Required field UUID not set.")
+ if opts.BlockDevice.SourceType != "volume" &&
+ opts.BlockDevice.SourceType != "image" &&
+ opts.BlockDevice.SourceType != "snapshot" &&
+ opts.BlockDevice.SourceType != "" {
+ return nil, errors.New("SourceType must be one of: volume, image, snapshot, [blank].")
}
base, err := opts.CreateOptsBuilder.ToServerCreateMap()
@@ -28,7 +58,39 @@
}
serverMap := base["server"].(map[string]interface{})
- serverMap["block_device_mapping_v2"] = opts.BDM
+
+ bd := make(map[string]interface{})
+ bd["source_type"] = opts.BlockDevice.SourceType
+ bd["boot_index"] = strconv.Itoa(opts.BlockDevice.BootIndex)
+ bd["delete_on_termination"] = strconv.FormatBool(opts.BlockDevice.DeleteOnTermination)
+ bd["volume_size"] = strconv.Itoa(opts.BlockDevice.VolumeSize)
+ if opts.BlockDevice.UUID != "" {
+ bd["uuid"] = opts.BlockDevice.UUID
+ }
+ if opts.BlockDevice.DestinationType != "" {
+ bd["destination_type"] = opts.BlockDevice.DestinationType
+ }
+
+ serverMap["block_device_mapping_v2"] = []map[string]interface{}{bd}
return base, nil
}
+
+// 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()
+ if err != nil {
+ res.Err = err
+ return res
+ }
+
+ _, res.Err = perigee.Request("POST", createURL(client), perigee.Options{
+ MoreHeaders: client.AuthenticatedHeaders(),
+ ReqBody: reqBody,
+ Results: &res.Body,
+ OkCodes: []int{200},
+ })
+ return res
+}
diff --git a/openstack/compute/v2/extensions/bootfromvolume/requests_test.go b/openstack/compute/v2/extensions/bootfromvolume/requests_test.go
index a564982..bad6c03 100644
--- a/openstack/compute/v2/extensions/bootfromvolume/requests_test.go
+++ b/openstack/compute/v2/extensions/bootfromvolume/requests_test.go
@@ -1 +1,49 @@
package bootfromvolume
+
+import (
+ "testing"
+
+ "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
+ th "github.com/rackspace/gophercloud/testhelper"
+)
+
+func TestCreateOpts(t *testing.T) {
+ base := servers.CreateOpts{
+ Name: "createdserver",
+ ImageRef: "asdfasdfasdf",
+ FlavorRef: "performance1-1",
+ }
+
+ ext := CreateOptsExt{
+ CreateOptsBuilder: base,
+ BlockDevice: BlockDevice{
+ UUID: "123456",
+ SourceType: "image",
+ DestinationType: "volume",
+ VolumeSize: 10,
+ },
+ }
+
+ expected := `
+ {
+ "server": {
+ "name": "createdserver",
+ "imageRef": "asdfasdfasdf",
+ "flavorRef": "performance1-1",
+ "block_device_mapping_v2":[
+ {
+ "uuid":"123456",
+ "source_type":"image",
+ "destination_type":"volume",
+ "boot_index": "0",
+ "delete_on_termination": "false",
+ "volume_size": "10"
+ }
+ ]
+ }
+ }
+ `
+ actual, err := ext.ToServerCreateMap()
+ th.AssertNoErr(t, err)
+ th.CheckJSONEquals(t, expected, actual)
+}
diff --git a/openstack/compute/v2/extensions/bootfromvolume/results.go b/openstack/compute/v2/extensions/bootfromvolume/results.go
deleted file mode 100644
index 9d33728..0000000
--- a/openstack/compute/v2/extensions/bootfromvolume/results.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package bootfromvolume
-
-type BlockDeviceMapping struct {
- BootIndex int `json:"boot_index"`
- DeleteOnTermination bool `json:"delete_on_termination"`
- DestinationType string `json:"destination_type"`
- SourceType string `json:"source_type"`
- UUID string `json:"uuid"`
- VolumeSize int `json:"volume_size"`
-}
diff --git a/openstack/compute/v2/extensions/bootfromvolume/urls.go b/openstack/compute/v2/extensions/bootfromvolume/urls.go
new file mode 100644
index 0000000..0cffe25
--- /dev/null
+++ b/openstack/compute/v2/extensions/bootfromvolume/urls.go
@@ -0,0 +1,7 @@
+package bootfromvolume
+
+import "github.com/rackspace/gophercloud"
+
+func createURL(c *gophercloud.ServiceClient) string {
+ return c.ServiceURL("os-volumes_boot")
+}
diff --git a/openstack/compute/v2/extensions/bootfromvolume/urls_test.go b/openstack/compute/v2/extensions/bootfromvolume/urls_test.go
new file mode 100644
index 0000000..6ee6477
--- /dev/null
+++ b/openstack/compute/v2/extensions/bootfromvolume/urls_test.go
@@ -0,0 +1,16 @@
+package bootfromvolume
+
+import (
+ "testing"
+
+ th "github.com/rackspace/gophercloud/testhelper"
+ "github.com/rackspace/gophercloud/testhelper/client"
+)
+
+func TestCreateURL(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+ c := client.ServiceClient()
+
+ th.CheckEquals(t, c.Endpoint+"os-volumes_boot", createURL(c))
+}