Merge pull request #1500 from myENA/KVM_root_detach

CLOUDSTACK-9349: Enable root disk detach for KVM with new Marvin testsThis PR addresses the KVM detach/attach ROOT disks from VMs (CLOUDSTACK-9349).  In short, this allows the KVM Hypervisor, and I added the Simulator as a valid hypervisor for ease of development and testing of marvin, to detach a root volume and the reattach a root volume using the deviceid=0 flag to the attachVolume API.  I have also written a marvin integration test that verifies this feature works for both KVM and the Simulator.

Below is the marvin results files of the full marvin test_volumes.py.  All tests pass, including the new root detach/attach, on our KVM lab running with the patches in this PR.

[test_volumes_KIR4G3.zip](https://github.com/apache/cloudstack/files/223799/test_volumes_KIR4G3.zip)

* pr/1500:
  Removed sleeps and used validateList as requested.
  Added required_hardware="false" attr above test_02_root_volume_attach_detach
  Modified test_volumes.py to include a hypervisor test for root attach/detach testing
  Let hypervisor type KVM and Simulator detach root volumes. Updated test_volumes.py to include a test for detaching and reattaching a root volume from a vm. I also had to update base.py to allow attach_volume to have the parameter deviceid to be passed as needed.

Signed-off-by: Will Stevens <williamstevens@gmail.com>
This commit is contained in:
Will Stevens 2016-04-28 16:02:53 -04:00
commit 1979f42b2d
3 changed files with 141 additions and 4 deletions

View File

@ -1744,8 +1744,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
}
private void validateRootVolumeDetachAttach(VolumeVO volume, UserVmVO vm) {
if (!(vm.getHypervisorType() == HypervisorType.XenServer || vm.getHypervisorType() == HypervisorType.VMware)) {
throw new InvalidParameterValueException("Root volume detach is allowed for hypervisor type " + HypervisorType.XenServer + " only");
if (!(vm.getHypervisorType() == HypervisorType.XenServer || vm.getHypervisorType() == HypervisorType.VMware || vm.getHypervisorType() == HypervisorType.KVM || vm.getHypervisorType() == HypervisorType.Simulator)) {
throw new InvalidParameterValueException("Root volume detach is not supported for hypervisor type " + vm.getHypervisorType() );
}
if (!(vm.getState() == State.Stopped) || (vm.getState() == State.Destroyed)) {
throw new InvalidParameterValueException("Root volume detach can happen only when vm is in states: " + State.Stopped.toString() + " or " + State.Destroyed.toString());

View File

@ -603,7 +603,140 @@ class TestAttachDetachVolume(cloudstackTestCase):
"Check the state of VM"
)
except Exception as e:
self.fail("Exception occuered: %s" % e)
self.fail("Exception occurred: %s" % e)
return
@attr(tags=["advanced", "advancedns"], required_hardware="false")
def test_02_root_volume_attach_detach(self):
"""Test Root Volume attach/detach to VM
"""
# Validate the following
# 1. Deploy a VM
# 2. Verify that we are testing a supported hypervisor
# 3. Check for root volume
# 4. Stop VM
# 5. Detach root volume
# 6. Verify root volume detached
# 7. Attach root volume
# 8. Start VM
# Verify we are using a supported hypervisor
if (self.hypervisor.lower() == 'vmware'
or self.hypervisor.lower() == 'kvm'
or self.hypervisor.lower() == 'simulator'
or self.hypervisor.lower() == 'xenserver'):
try:
# Check for root volume
root_volume_response = Volume.list(
self.apiclient,
virtualmachineid=self.virtual_machine.id,
type='ROOT',
listall=True
)
self.assertEqual(
validateList(root_volume_response)[0],
PASS,
"Invalid response returned for root volume list"
)
# Grab the root volume for later use
root_volume = root_volume_response[0]
# Stop VM
self.debug("Stopping the VM: %s" % self.virtual_machine.id)
self.virtual_machine.stop(self.apiclient)
vm_response = VirtualMachine.list(
self.apiclient,
id=self.virtual_machine.id,
)
# Ensure that vm_response is a valid list
self.assertEqual(
validateList(vm_response)[0],
PASS,
"Invalid response returned for vm_response list"
)
vm = vm_response[0]
self.assertEqual(
vm.state,
'Stopped',
"Check the state of VM"
)
# Detach root volume from VM
self.virtual_machine.detach_volume(
self.apiclient,
root_volume
)
# Verify that root disk is gone
no_root_volume_response = Volume.list(
self.apiclient,
virtualmachineid=self.virtual_machine.id,
type='ROOT',
listall=True
)
self.assertEqual(
no_root_volume_response,
None,
"Check if root volume exists in ListVolumes"
)
# Attach root volume to VM
self.virtual_machine.attach_volume(
self.apiclient,
root_volume,
0
)
# Check for root volume
new_root_volume_response = Volume.list(
self.apiclient,
virtualmachineid=self.virtual_machine.id,
type='ROOT',
listall=True
)
# Ensure that new_root_volume_response is a valid list
self.assertEqual(
validateList(new_root_volume_response)[0],
PASS,
"Invalid response returned for new_root_volume_response list"
)
# Start VM
self.virtual_machine.start(self.apiclient)
vm_response = VirtualMachine.list(
self.apiclient,
id=self.virtual_machine.id,
)
# Verify VM response to check whether VM deployment was successful
self.assertEqual(
validateList(vm_response)[0],
PASS,
"Invalid response returned for vm_response list during VM start up"
)
vm = vm_response[0]
self.assertEqual(
vm.state,
'Running',
"Ensure the state of VM is running"
)
except Exception as e:
self.fail("Exception occurred: %s" % e)
else:
self.skipTest("Root Volume attach/detach is not supported on %s " % self.hypervisor)
return

View File

@ -667,11 +667,15 @@ class VirtualMachine:
})
apiclient.migrateVirtualMachineWithVolume(cmd)
def attach_volume(self, apiclient, volume):
def attach_volume(self, apiclient, volume, deviceid=None):
"""Attach volume to instance"""
cmd = attachVolume.attachVolumeCmd()
cmd.id = volume.id
cmd.virtualmachineid = self.id
if deviceid is not None:
cmd.deviceid = deviceid
return apiclient.attachVolume(cmd)
def detach_volume(self, apiclient, volume):