bfv updates (#100)
This commit creates a DestinationType for the possible block device
destination types.
It allows VolumeSize to be omitted.
Finally, it adds both unit and acceptance tests for all possible ways
that the bootfromvolume extension can be used.
* Renaming and reordering source and destination types
* Erroneous rename
diff --git a/acceptance/openstack/blockstorage/v2/blockstorage.go b/acceptance/openstack/blockstorage/v2/blockstorage.go
index e007c2a..555bdcd 100644
--- a/acceptance/openstack/blockstorage/v2/blockstorage.go
+++ b/acceptance/openstack/blockstorage/v2/blockstorage.go
@@ -7,6 +7,7 @@
"testing"
"github.com/gophercloud/gophercloud"
+ "github.com/gophercloud/gophercloud/acceptance/clients"
"github.com/gophercloud/gophercloud/acceptance/tools"
"github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes"
)
@@ -39,6 +40,35 @@
return volume, nil
}
+// CreateVolumeFromImage will create a volume from with a random name and size of
+// 1GB. An error will be returned if the volume was unable to be created.
+func CreateVolumeFromImage(t *testing.T, client *gophercloud.ServiceClient, choices *clients.AcceptanceTestChoices) (*volumes.Volume, error) {
+ if testing.Short() {
+ t.Skip("Skipping test that requires volume creation in short mode.")
+ }
+
+ volumeName := tools.RandomString("ACPTTEST", 16)
+ t.Logf("Attempting to create volume: %s", volumeName)
+
+ createOpts := volumes.CreateOpts{
+ Size: 1,
+ Name: volumeName,
+ ImageID: choices.ImageID,
+ }
+
+ volume, err := volumes.Create(client, createOpts).Extract()
+ if err != nil {
+ return volume, err
+ }
+
+ err = volumes.WaitForStatus(client, volume.ID, "available", 60)
+ if err != nil {
+ return volume, err
+ }
+
+ return volume, nil
+}
+
// DeleteVolume will delete a volume. A fatal error will occur if the volume
// failed to be deleted. This works best when used as a deferred function.
func DeleteVolume(t *testing.T, client *gophercloud.ServiceClient, volume *volumes.Volume) {
diff --git a/acceptance/openstack/compute/v2/bootfromvolume_test.go b/acceptance/openstack/compute/v2/bootfromvolume_test.go
index 844a7cb..54719d0 100644
--- a/acceptance/openstack/compute/v2/bootfromvolume_test.go
+++ b/acceptance/openstack/compute/v2/bootfromvolume_test.go
@@ -6,10 +6,11 @@
"testing"
"github.com/gophercloud/gophercloud/acceptance/clients"
+ blockstorage "github.com/gophercloud/gophercloud/acceptance/openstack/blockstorage/v2"
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume"
)
-func TestBootFromVolumeSingleVolume(t *testing.T) {
+func TestBootFromImage(t *testing.T) {
if testing.Short() {
t.Skip("Skipping test that requires server creation in short mode.")
}
@@ -26,10 +27,44 @@
blockDevices := []bootfromvolume.BlockDevice{
bootfromvolume.BlockDevice{
- UUID: choices.ImageID,
- SourceType: bootfromvolume.Image,
+ BootIndex: 0,
DeleteOnTermination: true,
- DestinationType: "volume",
+ DestinationType: bootfromvolume.DestinationLocal,
+ SourceType: bootfromvolume.SourceImage,
+ UUID: choices.ImageID,
+ },
+ }
+
+ server, err := CreateBootableVolumeServer(t, client, blockDevices, choices)
+ if err != nil {
+ t.Fatalf("Unable to create server: %v", err)
+ }
+ defer DeleteServer(t, client, server)
+
+ PrintServer(t, server)
+}
+
+func TestBootFromNewVolume(t *testing.T) {
+ if testing.Short() {
+ t.Skip("Skipping test that requires server creation in short mode.")
+ }
+
+ client, err := clients.NewComputeV2Client()
+ if err != nil {
+ t.Fatalf("Unable to create a compute client: %v", err)
+ }
+
+ choices, err := clients.AcceptanceTestChoicesFromEnv()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ blockDevices := []bootfromvolume.BlockDevice{
+ bootfromvolume.BlockDevice{
+ DeleteOnTermination: true,
+ DestinationType: bootfromvolume.DestinationVolume,
+ SourceType: bootfromvolume.SourceImage,
+ UUID: choices.ImageID,
VolumeSize: 2,
},
}
@@ -43,6 +78,49 @@
PrintServer(t, server)
}
+func TestBootFromExistingVolume(t *testing.T) {
+ if testing.Short() {
+ t.Skip("Skipping test that requires server creation in short mode.")
+ }
+
+ computeClient, err := clients.NewComputeV2Client()
+ if err != nil {
+ t.Fatalf("Unable to create a compute client: %v", err)
+ }
+
+ blockStorageClient, err := clients.NewBlockStorageV2Client()
+ if err != nil {
+ t.Fatalf("Unable to create a block storage client: %v", err)
+ }
+
+ choices, err := clients.AcceptanceTestChoicesFromEnv()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ volume, err := blockstorage.CreateVolumeFromImage(t, blockStorageClient, choices)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ blockDevices := []bootfromvolume.BlockDevice{
+ bootfromvolume.BlockDevice{
+ DeleteOnTermination: true,
+ DestinationType: bootfromvolume.DestinationVolume,
+ SourceType: bootfromvolume.SourceVolume,
+ UUID: volume.ID,
+ },
+ }
+
+ server, err := CreateBootableVolumeServer(t, computeClient, blockDevices, choices)
+ if err != nil {
+ t.Fatalf("Unable to create server: %v", err)
+ }
+ defer DeleteServer(t, computeClient, server)
+
+ PrintServer(t, server)
+}
+
func TestBootFromMultiEphemeralServer(t *testing.T) {
if testing.Short() {
t.Skip("Skipping test that requires server creation in short mode.")
@@ -61,26 +139,26 @@
blockDevices := []bootfromvolume.BlockDevice{
bootfromvolume.BlockDevice{
BootIndex: 0,
- UUID: choices.ImageID,
- SourceType: bootfromvolume.Image,
- DestinationType: "local",
+ DestinationType: bootfromvolume.DestinationLocal,
DeleteOnTermination: true,
+ SourceType: bootfromvolume.SourceImage,
+ UUID: choices.ImageID,
VolumeSize: 5,
},
bootfromvolume.BlockDevice{
BootIndex: -1,
- SourceType: bootfromvolume.Blank,
- DestinationType: "local",
+ DestinationType: bootfromvolume.DestinationLocal,
DeleteOnTermination: true,
GuestFormat: "ext4",
+ SourceType: bootfromvolume.SourceBlank,
VolumeSize: 1,
},
bootfromvolume.BlockDevice{
BootIndex: -1,
- SourceType: bootfromvolume.Blank,
- DestinationType: "local",
+ DestinationType: bootfromvolume.DestinationLocal,
DeleteOnTermination: true,
GuestFormat: "ext4",
+ SourceType: bootfromvolume.SourceBlank,
VolumeSize: 1,
},
}
@@ -93,3 +171,95 @@
PrintServer(t, server)
}
+
+func TestAttachNewVolume(t *testing.T) {
+ if testing.Short() {
+ t.Skip("Skipping test that requires server creation in short mode.")
+ }
+
+ client, err := clients.NewComputeV2Client()
+ if err != nil {
+ t.Fatalf("Unable to create a compute client: %v", err)
+ }
+
+ choices, err := clients.AcceptanceTestChoicesFromEnv()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ blockDevices := []bootfromvolume.BlockDevice{
+ bootfromvolume.BlockDevice{
+ BootIndex: 0,
+ DeleteOnTermination: true,
+ DestinationType: bootfromvolume.DestinationLocal,
+ SourceType: bootfromvolume.SourceImage,
+ UUID: choices.ImageID,
+ },
+ bootfromvolume.BlockDevice{
+ BootIndex: 1,
+ DeleteOnTermination: true,
+ DestinationType: bootfromvolume.DestinationVolume,
+ SourceType: bootfromvolume.SourceBlank,
+ VolumeSize: 2,
+ },
+ }
+
+ server, err := CreateBootableVolumeServer(t, client, blockDevices, choices)
+ if err != nil {
+ t.Fatalf("Unable to create server: %v", err)
+ }
+ defer DeleteServer(t, client, server)
+
+ PrintServer(t, server)
+}
+
+func TestAttachExistingVolume(t *testing.T) {
+ if testing.Short() {
+ t.Skip("Skipping test that requires server creation in short mode.")
+ }
+
+ computeClient, err := clients.NewComputeV2Client()
+ if err != nil {
+ t.Fatalf("Unable to create a compute client: %v", err)
+ }
+
+ blockStorageClient, err := clients.NewBlockStorageV2Client()
+ if err != nil {
+ t.Fatalf("Unable to create a block storage client: %v", err)
+ }
+
+ choices, err := clients.AcceptanceTestChoicesFromEnv()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ volume, err := blockstorage.CreateVolume(t, blockStorageClient)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ blockDevices := []bootfromvolume.BlockDevice{
+ bootfromvolume.BlockDevice{
+ BootIndex: 0,
+ DeleteOnTermination: true,
+ DestinationType: bootfromvolume.DestinationLocal,
+ SourceType: bootfromvolume.SourceImage,
+ UUID: choices.ImageID,
+ },
+ bootfromvolume.BlockDevice{
+ BootIndex: 1,
+ DeleteOnTermination: true,
+ DestinationType: bootfromvolume.DestinationVolume,
+ SourceType: bootfromvolume.SourceVolume,
+ UUID: volume.ID,
+ },
+ }
+
+ server, err := CreateBootableVolumeServer(t, computeClient, blockDevices, choices)
+ if err != nil {
+ t.Fatalf("Unable to create server: %v", err)
+ }
+ defer DeleteServer(t, computeClient, server)
+
+ PrintServer(t, server)
+}
diff --git a/acceptance/openstack/compute/v2/compute.go b/acceptance/openstack/compute/v2/compute.go
index 9b284c3..3392c2e 100644
--- a/acceptance/openstack/compute/v2/compute.go
+++ b/acceptance/openstack/compute/v2/compute.go
@@ -90,6 +90,10 @@
},
}
+ if blockDevices[0].SourceType == bootfromvolume.SourceImage && blockDevices[0].DestinationType == bootfromvolume.DestinationLocal {
+ serverCreateOpts.ImageRef = blockDevices[0].UUID
+ }
+
server, err = bootfromvolume.Create(client, bootfromvolume.CreateOptsExt{
serverCreateOpts,
blockDevices,