Allow ImageRef to be empty when block device is present (#97)
This commit removes the requirement for ImageRef to be set when creating
a server. This is to enable booting from a volume to work properly.
A unit test was added to verify this is possible.
Acceptance tests were also modified to handle this.
diff --git a/openstack/compute/v2/extensions/bootfromvolume/testing/requests_test.go b/openstack/compute/v2/extensions/bootfromvolume/testing/requests_test.go
index dca1105..6724dab 100644
--- a/openstack/compute/v2/extensions/bootfromvolume/testing/requests_test.go
+++ b/openstack/compute/v2/extensions/bootfromvolume/testing/requests_test.go
@@ -52,6 +52,49 @@
th.CheckJSONEquals(t, expected, actual)
}
+func TestCreateOptsWithoutImageRef(t *testing.T) {
+ base := servers.CreateOpts{
+ Name: "createdserver",
+ FlavorRef: "performance1-1",
+ }
+
+ ext := bootfromvolume.CreateOptsExt{
+ CreateOptsBuilder: base,
+ BlockDevice: []bootfromvolume.BlockDevice{
+ {
+ UUID: "123456",
+ SourceType: bootfromvolume.Image,
+ DestinationType: "volume",
+ VolumeSize: 10,
+ DeleteOnTermination: false,
+ },
+ },
+ }
+
+ expected := `
+ {
+ "server": {
+ "name": "createdserver",
+ "imageRef": "",
+ "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)
+}
+
func TestCreateMultiEphemeralOpts(t *testing.T) {
base := servers.CreateOpts{
Name: "createdserver",
diff --git a/openstack/compute/v2/servers/requests.go b/openstack/compute/v2/servers/requests.go
index fcc8b2e..4ec2cf0 100644
--- a/openstack/compute/v2/servers/requests.go
+++ b/openstack/compute/v2/servers/requests.go
@@ -219,23 +219,21 @@
b["networks"] = networks
}
- // If ImageRef isn't provided, use ImageName to ascertain the image ID.
+ // If ImageRef isn't provided, check if ImageName was provided to ascertain
+ // the image ID.
if opts.ImageRef == "" {
- if opts.ImageName == "" {
- err := ErrNeitherImageIDNorImageNameProvided{}
- err.Argument = "ImageRef/ImageName"
- return nil, err
+ if opts.ImageName != "" {
+ if sc == nil {
+ err := ErrNoClientProvidedForIDByName{}
+ err.Argument = "ServiceClient"
+ return nil, err
+ }
+ imageID, err := images.IDFromName(sc, opts.ImageName)
+ if err != nil {
+ return nil, err
+ }
+ b["imageRef"] = imageID
}
- if sc == nil {
- err := ErrNoClientProvidedForIDByName{}
- err.Argument = "ServiceClient"
- return nil, err
- }
- imageID, err := images.IDFromName(sc, opts.ImageName)
- if err != nil {
- return nil, err
- }
- b["imageRef"] = imageID
}
// If FlavorRef isn't provided, use FlavorName to ascertain the flavor ID.
@@ -424,23 +422,21 @@
return nil, err
}
- // If ImageRef isn't provided, use ImageName to ascertain the image ID.
+ // If ImageRef isn't provided, check if ImageName was provided to ascertain
+ // the image ID.
if opts.ImageID == "" {
- if opts.ImageName == "" {
- err := ErrNeitherImageIDNorImageNameProvided{}
- err.Argument = "ImageRef/ImageName"
- return nil, err
+ if opts.ImageName != "" {
+ 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.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
}
return map[string]interface{}{"rebuild": b}, nil