# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """ P1 tests for Volumes """ # Import Local Modules from nose.plugins.attrib import attr from marvin.cloudstackTestCase import cloudstackTestCase from marvin.cloudstackAPI import (listHypervisorCapabilities, attachIso, deleteVolume ) from marvin.lib.utils import cleanup_resources, validateList from marvin.lib.base import (Account, ServiceOffering, VirtualMachine, Volume, Host, Iso, Configurations, DiskOffering, Domain, StoragePool) from marvin.lib.common import (get_domain, get_zone, get_template, get_pod, find_storage_pool_type, update_resource_limit) from marvin.codes import PASS # Import System modules import time class TestAttachVolume(cloudstackTestCase): @classmethod def setUpClass(cls): cls.testClient = super(TestAttachVolume, cls).getClsTestClient() cls.api_client = cls.testClient.getApiClient() cls.testdata = cls.testClient.getParsedTestDataConfig() # Get Zone, Domain and templates cls.domain = get_domain(cls.api_client) cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) cls.pod = get_pod(cls.api_client, cls.zone.id) cls.testdata['mode'] = cls.zone.networktype cls._cleanup = [] cls.unsupportedStorageType = False cls.hypervisor = cls.testClient.getHypervisorInfo() if cls.hypervisor.lower() == 'lxc': if not find_storage_pool_type(cls.api_client, storagetype='rbd'): cls.unsupportedStorageType = True return cls.disk_offering = DiskOffering.create( cls.api_client, cls.testdata["disk_offering"] ) cls._cleanup.append(cls.disk_offering) cls.template = get_template( cls.api_client, cls.zone.id, cls.testdata["ostype"] ) # get max data volumes limit based on the hypervisor type and version listHost = Host.list( cls.api_client, type='Routing', zoneid=cls.zone.id, podid=cls.pod.id, ) ver = listHost[0].hypervisorversion hv = listHost[0].hypervisor cmd = listHypervisorCapabilities.listHypervisorCapabilitiesCmd() cmd.hypervisor = hv res = cls.api_client.listHypervisorCapabilities(cmd) cls.debug('Hypervisor Capabilities: {}'.format(res)) for i in range(len(res)): if res[i].hypervisorversion == ver: break cls.max_data_volumes = int(res[i].maxdatavolumeslimit) if 'kvm' in cls.hypervisor: cls.max_data_volumes = 24 cls.debug('max data volumes:{}'.format(cls.max_data_volumes)) cls.testdata["volume"]["max"] = cls.max_data_volumes # Create VMs, NAT Rules etc cls.account = Account.create( cls.api_client, cls.testdata["account"], domainid=cls.domain.id ) cls._cleanup.append(cls.account) update_resource_limit( cls.api_client, 2, # Instance account=cls.account.name, domainid=cls.account.domainid, max=cls.max_data_volumes + 1 ) cls.debug('max data volumes:{}'.format(cls.max_data_volumes)) cls.service_offering = ServiceOffering.create( cls.api_client, cls.testdata["service_offering"] ) cls._cleanup.append(cls.service_offering) cls.virtual_machine = VirtualMachine.create( cls.api_client, cls.testdata["virtual_machine"], accountid=cls.account.name, domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, templateid=cls.template.id, zoneid=cls.zone.id ) cls._cleanup.append(cls.virtual_machine) def setUp(self): self.apiclient = self.testClient.getApiClient() self.dbclient = self.testClient.getDbConnection() self.cleanup = [] if self.unsupportedStorageType: self.skipTest("Skipping because of unsupported storage type") def tearDown(self): super(TestAttachVolume, self).tearDown() @classmethod def tearDownClass(cls): super(TestAttachVolume, cls).tearDownClass() @attr(tags=["advanced", "advancedns", "needle"]) def test_01_volume_attach(self): """Test Attach volumes (max capacity) """ # Validate the following # 1. Deploy a vm and create 5 data disk # 2. Attach all the created Volume to the vm. # 3. Reboot the VM. VM should be successfully rebooted # 4. Stop the VM. Stop VM should be successful # 5. Start The VM. Start VM should be successful # Create 5 volumes and attach to VM for i in range(self.max_data_volumes): volume = Volume.create( self.apiclient, self.testdata["volume"], zoneid=self.zone.id, account=self.account.name, domainid=self.account.domainid, diskofferingid=self.disk_offering.id ) # Check List Volume response for newly created volume list_volume_response = Volume.list( self.apiclient, id=volume.id ) self.assertNotEqual( list_volume_response, None, "Check if volume exists in ListVolumes" ) # Attach volume to VM self.virtual_machine.attach_volume( self.apiclient, volume ) # Check all volumes attached to same VM list_volume_response = Volume.list( self.apiclient, virtualmachineid=self.virtual_machine.id, type='DATADISK', listall=True ) self.assertNotEqual( list_volume_response, None, "Check if volume exists in ListVolumes") self.assertEqual( isinstance(list_volume_response, list), True, "Check list volumes response for valid list") self.assertEqual( len(list_volume_response), self.max_data_volumes, "Volumes attached to the VM %s. Expected %s" % (len(list_volume_response), self.max_data_volumes)) self.debug("Rebooting the VM: %s" % self.virtual_machine.id) # Reboot VM self.virtual_machine.reboot(self.apiclient) vm_response = VirtualMachine.list( self.apiclient, id=self.virtual_machine.id, ) # Verify VM response to check whether VM deployment was successful self.assertNotEqual( len(vm_response), 0, "Check VMs available in List VMs response" ) self.assertEqual( isinstance(vm_response, list), True, "Check list VM response for valid list" ) vm = vm_response[0] self.assertEqual( vm.state, 'Running', "Check the state of VM" ) # Stop VM self.virtual_machine.stop(self.apiclient) # Start VM self.virtual_machine.start(self.apiclient) # Sleep to ensure that VM is in ready state time.sleep(self.testdata["sleep"]) vm_response = VirtualMachine.list( self.apiclient, id=self.virtual_machine.id, ) self.assertEqual( isinstance(vm_response, list), True, "Check list VM response for valid list" ) # Verify VM response to check whether VM deployment was successful self.assertNotEqual( len(vm_response), 0, "Check VMs available in List VMs response" ) vm = vm_response[0] self.assertEqual( vm.state, 'Running', "Check the state of VM" ) return @attr(tags=["advanced", "advancedns"]) def test_02_volume_attach_max(self): """Test attach volumes (more than max) to an instance # Validate the following # 1. Attach one more data volume to VM (Already 5 attached) # 2. Attach volume should fail """ # Create a volume and attach to VM # Update limit so that account could create one more volume if 'kvm' in self.hypervisor: update_resource_limit( self.api_client, 2, # Instance account=self.account.name, domainid=self.account.domainid, max=32 ) # Attach volume to VM with self.assertRaises(Exception): for i in range(self.max_data_volumes): volume = Volume.create( self.apiclient, self.testdata["volume"], zoneid=self.zone.id, account=self.account.name, domainid=self.account.domainid, diskofferingid=self.disk_offering.id ) # Check List Volume response for newly created volume list_volume_response = Volume.list( self.apiclient, id=volume.id ) self.assertNotEqual( list_volume_response, None, "Check if volume exists in ListVolumes" ) # Attach volume to VM self.virtual_machine.attach_volume( self.apiclient, volume ) return class TestAttachDetachVolume(cloudstackTestCase): @classmethod def setUpClass(cls): cls.testClient = super(TestAttachDetachVolume, cls).getClsTestClient() cls.api_client = cls.testClient.getApiClient() cls.testdata = cls.testClient.getParsedTestDataConfig() # Get Zone, Domain and templates cls.domain = get_domain(cls.api_client) cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) cls.pod = get_pod(cls.api_client, cls.zone.id) cls.testdata['mode'] = cls.zone.networktype cls._cleanup = [] cls.unsupportedStorageType = False cls.hypervisor = cls.testClient.getHypervisorInfo() if cls.hypervisor.lower() == 'lxc': if not find_storage_pool_type(cls.api_client, storagetype='rbd'): cls.unsupportedStorageType = True return cls.disk_offering = DiskOffering.create( cls.api_client, cls.testdata["disk_offering"] ) cls._cleanup.append(cls.disk_offering) template = get_template( cls.api_client, cls.zone.id, cls.testdata["ostype"] ) cls.testdata["zoneid"] = cls.zone.id cls.testdata["virtual_machine"]["zoneid"] = cls.zone.id cls.testdata["virtual_machine"]["template"] = template.id # get max data volumes limit based on the hypervisor type and version listHost = Host.list( cls.api_client, type='Routing', zoneid=cls.zone.id, podid=cls.pod.id, ) ver = listHost[0].hypervisorversion hv = listHost[0].hypervisor cmd = listHypervisorCapabilities.listHypervisorCapabilitiesCmd() cmd.hypervisor = hv # cls.services["virtual_machine"]["hypervisor"] res = cls.api_client.listHypervisorCapabilities(cmd) cls.debug('Hypervisor Capabilities: {}'.format(res)) for i in range(len(res)): if res[i].hypervisorversion == ver: break cls.max_data_volumes = int(res[i].maxdatavolumeslimit) if 'kvm' in cls.hypervisor: cls.max_data_volumes = 24 cls.debug('max data volumes:{}'.format(cls.max_data_volumes)) cls.testdata["volume"]["max"] = cls.max_data_volumes # Create VMs, NAT Rules etc cls.account = Account.create( cls.api_client, cls.testdata["account"], domainid=cls.domain.id ) cls._cleanup.append(cls.account) update_resource_limit( cls.api_client, 2, # Instance account=cls.account.name, domainid=cls.account.domainid, max=cls.max_data_volumes + 1 ) cls.service_offering = ServiceOffering.create( cls.api_client, cls.testdata["service_offering"] ) cls._cleanup.append(cls.service_offering) cls.virtual_machine = VirtualMachine.create( cls.api_client, cls.testdata["virtual_machine"], accountid=cls.account.name, domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, ) cls._cleanup.append(cls.virtual_machine) def setUp(self): self.apiclient = self.testClient.getApiClient() self.dbclient = self.testClient.getDbConnection() self.cleanup = [] if self.unsupportedStorageType: self.skipTest("RBD storage type is required for data volumes for LXC") def tearDown(self): super(TestAttachDetachVolume, self).tearDown() @classmethod def tearDownClass(cls): super(TestAttachDetachVolume, cls).tearDownClass() @attr(tags=["advanced", "advancedns"]) def test_01_volume_attach_detach(self): """Test Volume attach/detach to VM (5 data volumes) """ # Validate the following # 1. Deploy a vm and create 5 data disk # 2. Attach all the created Volume to the vm. # 3. Detach all the volumes attached. # 4. Reboot the VM. VM should be successfully rebooted # 5. Stop the VM. Stop VM should be successful # 6. Start The VM. Start VM should be successful volumes = [] # Create 5 volumes and attach to VM for i in range(self.max_data_volumes): volume = Volume.create( self.apiclient, self.testdata["volume"], zoneid=self.zone.id, account=self.account.name, domainid=self.account.domainid, diskofferingid=self.disk_offering.id ) self.cleanup.append(volume) volumes.append(volume) # Check List Volume response for newly created volume list_volume_response = Volume.list( self.apiclient, id=volume.id ) self.assertNotEqual( list_volume_response, None, "Check if volume exists in ListVolumes") self.assertEqual( isinstance(list_volume_response, list), True, "Check list volumes response for valid list") # Attach volume to VM self.virtual_machine.attach_volume( self.apiclient, volume ) # Check all volumes attached to same VM list_volume_response = Volume.list( self.apiclient, virtualmachineid=self.virtual_machine.id, type='DATADISK', listall=True ) self.assertNotEqual( list_volume_response, None, "Check if volume exists in ListVolumes" ) self.assertEqual( isinstance(list_volume_response, list), True, "Check list volumes response for valid list" ) self.assertEqual( len(list_volume_response), self.max_data_volumes, "Volumes attached to the VM %s. Expected %s" % (len(list_volume_response), self.max_data_volumes)) # Detach all volumes from VM for volume in volumes: self.virtual_machine.detach_volume( self.apiclient, volume ) # Reboot VM self.debug("Rebooting the VM: %s" % self.virtual_machine.id) self.virtual_machine.reboot(self.apiclient) # Sleep to ensure that VM is in ready state time.sleep(self.testdata["sleep"]) vm_response = VirtualMachine.list( self.apiclient, id=self.virtual_machine.id, ) # Verify VM response to check whether VM deployment was successful self.assertEqual( isinstance(vm_response, list), True, "Check list VM response for valid list" ) self.assertNotEqual( len(vm_response), 0, "Check VMs available in List VMs response" ) vm = vm_response[0] self.assertEqual( vm.state, 'Running', "Check the state of VM" ) # Stop VM self.virtual_machine.stop(self.apiclient) # Start VM self.virtual_machine.start(self.apiclient) # Sleep to ensure that VM is in ready state time.sleep(self.testdata["sleep"]) vm_response = VirtualMachine.list( self.apiclient, id=self.virtual_machine.id, ) # Verify VM response to check whether VM deployment was successful self.assertEqual( isinstance(vm_response, list), True, "Check list VM response for valid list" ) self.assertNotEqual( len(vm_response), 0, "Check VMs available in List VMs response" ) vm = vm_response[0] self.assertEqual( vm.state, 'Running', "Check the state of VM" ) 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 """ if (self.hypervisor.lower() == 'vmware' or self.hypervisor.lower() == 'kvm' or self.hypervisor.lower() == 'simulator' or self.hypervisor.lower() == 'xenserver'): 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" ) else: self.skipTest("Root Volume attach/detach is not supported on %s " % self.hypervisor) return class TestAttachVolumeISO(cloudstackTestCase): @classmethod def setUpClass(cls): cls.testClient = super(TestAttachVolumeISO, cls).getClsTestClient() cls.api_client = cls.testClient.getApiClient() cls.testdata = cls.testClient.getParsedTestDataConfig() # Get Zone, Domain and templates cls.domain = get_domain(cls.api_client) cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) cls.pod = get_pod(cls.api_client, cls.zone.id) cls.testdata['mode'] = cls.zone.networktype cls._cleanup = [] cls.unsupportedStorageType = False cls.hypervisor = cls.testClient.getHypervisorInfo() if cls.hypervisor.lower() == 'lxc': if not find_storage_pool_type(cls.api_client, storagetype='rbd'): cls.unsupportedStorageType = True return cls.disk_offering = DiskOffering.create( cls.api_client, cls.testdata["disk_offering"] ) cls._cleanup.append(cls.disk_offering) template = get_template( cls.api_client, cls.zone.id, cls.testdata["ostype"] ) cls.testdata["zoneid"] = cls.zone.id cls.testdata["virtual_machine"]["zoneid"] = cls.zone.id cls.testdata["iso"]["zoneid"] = cls.zone.id cls.testdata["virtual_machine"]["template"] = template.id # get max data volumes limit based on the hypervisor type and version listHost = Host.list( cls.api_client, type='Routing', zoneid=cls.zone.id, podid=cls.pod.id, ) ver = listHost[0].hypervisorversion hv = listHost[0].hypervisor cmd = listHypervisorCapabilities.listHypervisorCapabilitiesCmd() cmd.hypervisor = hv res = cls.api_client.listHypervisorCapabilities(cmd) cls.debug('Hypervisor Capabilities: {}'.format(res)) for i in range(len(res)): if res[i].hypervisorversion == ver: break cls.max_data_volumes = int(res[i].maxdatavolumeslimit) if 'kvm' in cls.hypervisor: cls.max_data_volumes = 24 cls.debug('max data volumes:{}'.format(cls.max_data_volumes)) cls.testdata["volume"]["max"] = cls.max_data_volumes # Create VMs, NAT Rules etc cls.account = Account.create( cls.api_client, cls.testdata["account"], domainid=cls.domain.id ) cls._cleanup.append(cls.account) update_resource_limit( cls.api_client, 2, # Instance account=cls.account.name, domainid=cls.account.domainid, max=cls.max_data_volumes + 1 ) cls.debug('max data volumes:{}'.format(cls.max_data_volumes)) cls.testdata["volume"]["max"] = cls.max_data_volumes # Create VMs, NAT Rules etc cls.service_offering = ServiceOffering.create( cls.api_client, cls.testdata["service_offering"] ) cls._cleanup.append(cls.service_offering) cls.virtual_machine = VirtualMachine.create( cls.api_client, cls.testdata["virtual_machine"], accountid=cls.account.name, domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, ) cls._cleanup.append(cls.virtual_machine) @classmethod def tearDownClass(cls): super(TestAttachVolumeISO, cls).tearDownClass() def setUp(self): self.apiclient = self.testClient.getApiClient() self.dbclient = self.testClient.getDbConnection() self.cleanup = [] if self.unsupportedStorageType: self.skipTest("RBD storage type is required for data volumes for LXC") def tearDown(self): super(TestAttachVolumeISO, self).tearDown() @attr(tags=["advanced", "advancedns"], required_hardware="true") def test_01_volume_iso_attach(self): """Test Volumes and ISO attach # Validate the following # 1. Create and attach 5 data volumes to VM # 2. Create an ISO. Attach it to VM instance # 3. Verify that attach ISO is successful """ # Create 5 volumes and attach to VM if self.hypervisor.lower() in ["lxc"]: self.skipTest("attach ISO is not supported on LXC") for i in range(self.max_data_volumes): volume = Volume.create( self.apiclient, self.testdata["volume"], zoneid=self.zone.id, account=self.account.name, domainid=self.account.domainid, diskofferingid=self.disk_offering.id ) self.cleanup.append(volume) self.debug("Created volume: %s for account: %s" % ( volume.id, self.account.name )) # Check List Volume response for newly created volume list_volume_response = Volume.list( self.apiclient, id=volume.id ) self.assertNotEqual( list_volume_response, None, "Check if volume exists in ListVolumes" ) self.assertEqual( isinstance(list_volume_response, list), True, "Check list volumes response for valid list" ) # Attach volume to VM self.virtual_machine.attach_volume( self.apiclient, volume ) self.cleanup.remove(volume) # Check all volumes attached to same VM list_volume_response = Volume.list( self.apiclient, virtualmachineid=self.virtual_machine.id, type='DATADISK', listall=True ) self.assertNotEqual( list_volume_response, None, "Check if volume exists in ListVolumes" ) self.assertEqual( isinstance(list_volume_response, list), True, "Check list volumes response for valid list" ) self.assertEqual( len(list_volume_response), self.max_data_volumes, "Volumes attached to the VM %s. Expected %s" % (len(list_volume_response), self.max_data_volumes)) # Create an ISO and attach it to VM iso = Iso.create( self.apiclient, self.testdata["iso"], account=self.account.name, domainid=self.account.domainid, ) self.cleanup.append(iso) self.debug("Created ISO with ID: %s for account: %s" % ( iso.id, self.account.name )) try: self.debug("Downloading ISO with ID: %s" % iso.id) iso.download(self.apiclient) except Exception as e: self.fail("Exception while downloading ISO %s: %s" % (iso.id, e)) # Attach ISO to virtual machine self.debug("Attach ISO ID: %s to VM: %s" % ( iso.id, self.virtual_machine.id )) cmd = attachIso.attachIsoCmd() cmd.id = iso.id cmd.virtualmachineid = self.virtual_machine.id self.apiclient.attachIso(cmd) self.cleanup.remove(iso) # Verify ISO is attached to VM vm_response = VirtualMachine.list( self.apiclient, id=self.virtual_machine.id, ) # Verify VM response to check whether VM deployment was successful self.assertEqual( isinstance(vm_response, list), True, "Check list VM response for valid list" ) self.assertNotEqual( len(vm_response), 0, "Check VMs available in List VMs response" ) vm = vm_response[0] self.assertEqual( vm.isoid, iso.id, "Check ISO is attached to VM or not" ) return class TestVolumes(cloudstackTestCase): @classmethod def setUpClass(cls): cls.testClient = super(TestVolumes, cls).getClsTestClient() cls.api_client = cls.testClient.getApiClient() cls.testdata = cls.testClient.getParsedTestDataConfig() # Get Zone, Domain and templates cls.domain = get_domain(cls.api_client) cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) cls.testdata['mode'] = cls.zone.networktype cls._cleanup = [] cls.unsupportedStorageType = False cls.hypervisor = cls.testClient.getHypervisorInfo() if cls.hypervisor.lower() == 'lxc': if not find_storage_pool_type(cls.api_client, storagetype='rbd'): cls.unsupportedStorageType = True return cls.disk_offering = DiskOffering.create( cls.api_client, cls.testdata["disk_offering"] ) cls._cleanup.append(cls.disk_offering) template = get_template( cls.api_client, cls.zone.id, cls.testdata["ostype"] ) cls.testdata["zoneid"] = cls.zone.id cls.testdata["virtual_machine"]["zoneid"] = cls.zone.id cls.testdata["virtual_machine"]["template"] = template.id cls.testdata["virtual_machine"][ "diskofferingid"] = cls.disk_offering.id # Create VMs, VMs etc cls.account = Account.create( cls.api_client, cls.testdata["account"], domainid=cls.domain.id ) cls._cleanup.append(cls.account) cls.service_offering = ServiceOffering.create( cls.api_client, cls.testdata["service_offering"] ) cls._cleanup.append(cls.service_offering) cls.virtual_machine = VirtualMachine.create( cls.api_client, cls.testdata["virtual_machine"], accountid=cls.account.name, domainid=cls.account.domainid, serviceofferingid=cls.service_offering.id, startvm=False ) cls._cleanup.append(cls.virtual_machine) cls.volume = Volume.create( cls.api_client, cls.testdata["volume"], zoneid=cls.zone.id, account=cls.account.name, domainid=cls.account.domainid, diskofferingid=cls.disk_offering.id ) cls._cleanup.append(cls.volume) @classmethod def tearDownClass(cls): super(TestVolumes, cls).tearDownClass() def setUp(self): self.apiclient = self.testClient.getApiClient() self.dbclient = self.testClient.getDbConnection() self.cleanup = [] if self.unsupportedStorageType: self.skipTest("RBD storage type is required for data volumes for LXC") def tearDown(self): super(TestVolumes, self).tearDown() @attr(tags=["advanced", "advancedns"], required_hardware="false") def test_01_attach_volume(self): """Attach a created Volume to a Running VM # Validate the following # Create a data volume. (this is being done in setup) # 2. List Volumes should not have vmname and virtualmachineid fields in # response before volume attach (to VM) # 3. Attch volume to VM. Attach volume should be successful. # 4. List Volumes should have vmname and virtualmachineid fields in # response before volume attach (to VM) FIXME: This test (method) creates a precondition for `test_02_detach_volume()`: an attached `self.volume` to `self.virtual_machine` """ # Check the list volumes response for vmname and virtualmachineid list_volume_response = Volume.list( self.apiclient, id=self.volume.id ) self.assertNotEqual( list_volume_response, None, "Check if volume exists in ListVolumes" ) self.assertEqual( isinstance(list_volume_response, list), True, "Check list volumes response for valid list" ) volume = list_volume_response[0] self.assertEqual( volume.type, 'DATADISK', "Check volume type from list volume response" ) self.assertEqual( hasattr(volume, 'vmname'), True, "Check whether volume has vmname field" ) self.assertEqual( hasattr(volume, 'virtualmachineid'), True, "Check whether volume has virtualmachineid field" ) # Attach volume to VM self.debug("Attach volume: %s to VM: %s" % ( self.volume.id, self.virtual_machine.id )) self.virtual_machine.attach_volume(self.apiclient, self.volume) self._cleanup.remove(self.volume) # Check all volumes attached to same VM list_volume_response = Volume.list( self.apiclient, virtualmachineid=self.virtual_machine.id, type='DATADISK', listall=True ) self.assertNotEqual( list_volume_response, None, "Check if volume exists in ListVolumes" ) self.assertEqual( isinstance(list_volume_response, list), True, "Check list volumes response for valid list" ) volume = list_volume_response[0] self.assertEqual( volume.vmname, self.virtual_machine.name, "Check virtual machine name in list volumes response" ) self.assertEqual( volume.virtualmachineid, self.virtual_machine.id, "Check VM ID in list Volume response" ) return @attr(tags=["advanced", "advancedns"], required_hardware="false") def test_02_detach_volume(self): """Detach a Volume attached to a VM FIXME: this test method assumes a precondition set in `self.test_01_atttach_volume()`: there is expected to be a VM with a disk attached # Validate the following # 1. Data disk should be detached from instance # 2. Listvolumes should not have vmname and virtualmachineid fields for # that volume. FIXME: this test (method) leaves a precondition for `self.test_03_delete_detached_volume()`: """ self.debug("Detach volume: %s to VM: %s" % ( self.volume.id, self.virtual_machine.id )) self.virtual_machine.detach_volume(self.apiclient, self.volume) self._cleanup.append(self.volume) # Sleep to ensure the current state will reflected in other calls time.sleep(self.testdata["sleep"]) list_volume_response = Volume.list( self.apiclient, id=self.volume.id ) self.assertNotEqual( list_volume_response, None, "Check if volume exists in ListVolumes" ) self.assertEqual( isinstance(list_volume_response, list), True, "Check list volumes response for valid list" ) volume = list_volume_response[0] self.assertEqual( volume.virtualmachineid, None, "Check if volume state (detached) is reflected" ) self.assertEqual( volume.vmname, None, "Check if volume state (detached) is reflected" ) return @attr(tags=["advanced", "advancedns"], required_hardware="false") def test_03_delete_detached_volume(self): """Delete a Volume unattached to an VM FIXME: this expects `test_02_detach_volume()` to leave `self.volume` free and ready to delete # Validate the following # 1. volume should be deleted successfully and listVolume should not # contain the deleted volume details. """ self.debug("Deleting volume: %s" % self.volume.id) cmd = deleteVolume.deleteVolumeCmd() cmd.id = self.volume.id self.apiclient.deleteVolume(cmd) self._cleanup.remove(self.volume) # Sleep to ensure the current state will reflected in other calls time.sleep(self.testdata["sleep"]) list_volume_response = Volume.list( self.apiclient, id=self.volume.id, ) self.assertEqual( list_volume_response, None, "Volume %s was not deleted" % self.volume.id ) return @attr( tags=[ "advanced", "advancedns", "simulator", "basic", "eip", "sg"], required_hardware="false") def test_create_volume_under_domain(self): """Create a volume under a non-root domain as non-root-domain user 1. Create a domain under ROOT 2. Create a user within this domain 3. As user in step 2. create a volume with standard disk offering 4. Ensure the volume is created in the domain and available to the user in their listVolumes call """ dom = Domain.create( self.apiclient, services={}, name="NROOT", parentdomainid=self.domain.id ) self.cleanup.append(dom) self.assertTrue(dom is not None, msg="Domain creation failed") domuser = Account.create( apiclient=self.apiclient, services=self.testdata["account"], admin=False, domainid=dom.id ) self.cleanup.append(domuser) self.assertTrue(domuser is not None) domapiclient = self.testClient.getUserApiClient( UserName=domuser.name, DomainName=dom.name) diskoffering = DiskOffering.list(self.apiclient) self.assertTrue( isinstance( diskoffering, list), msg="DiskOffering list is not a list?") self.assertTrue( len(diskoffering) > 0, "no disk offerings in the deployment") vol = Volume.create( domapiclient, services=self.testdata["volume"], zoneid=self.zone.id, account=domuser.name, domainid=dom.id, diskofferingid=[x for x in diskoffering if not x.iscustomized][0].id ) self.cleanup.append(vol) self.assertTrue( vol is not None, "volume creation fails in domain %s as user %s" % (dom.name, domuser.name)) listed_vol = Volume.list(domapiclient, id=vol.id) self.assertTrue( listed_vol is not None and isinstance( listed_vol, list), "invalid response from listVolumes for volume %s" % vol.id) self.assertTrue( listed_vol[0].id == vol.id, "Volume returned by list volumes %s not matching with queried\ volume %s in domain %s" % (listed_vol[0].id, vol.id, dom.name)) class TestDeployVmWithCustomDisk(cloudstackTestCase): @classmethod def setUpClass(cls): cls.testClient = super( TestDeployVmWithCustomDisk, cls).getClsTestClient() cls.api_client = cls.testClient.getApiClient() cls.testdata = cls.testClient.getParsedTestDataConfig() # Get Zone, Domain and templates cls.domain = get_domain(cls.api_client) cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) cls.testdata['mode'] = cls.zone.networktype cls._cleanup = [] cls.unsupportedStorageType = False cls.hypervisor = cls.testClient.getHypervisorInfo() if cls.hypervisor.lower() == 'lxc': if not find_storage_pool_type(cls.api_client, storagetype='rbd'): cls.unsupportedStorageType = True return cls.disk_offering = DiskOffering.create( cls.api_client, cls.testdata["disk_offering"], custom=True ) cls._cleanup.append(cls.disk_offering) template = get_template( cls.api_client, cls.zone.id, cls.testdata["ostype"] ) cls.testdata["zoneid"] = cls.zone.id cls.testdata["virtual_machine"]["zoneid"] = cls.zone.id cls.testdata["virtual_machine"]["template"] = template.id # Create VMs, NAT Rules etc cls.account = Account.create( cls.api_client, cls.testdata["account"], domainid=cls.domain.id ) cls._cleanup.append(cls.account) cls.service_offering = ServiceOffering.create( cls.api_client, cls.testdata["service_offering"] ) cls._cleanup.append(cls.service_offering) def setUp(self): self.apiclient = self.testClient.getApiClient() self.dbclient = self.testClient.getDbConnection() self.cleanup = [] if self.unsupportedStorageType: self.skipTest("RBD storage type is required for data volumes for LXC") @classmethod def tearDownClass(cls): super(TestDeployVmWithCustomDisk, cls).tearDownClass() def tearDown(self): super(TestDeployVmWithCustomDisk, self).tearDown() @attr(tags=["advanced", "configuration", "advancedns", "simulator", "api", "basic", "eip", "sg"]) def test_deployVmWithCustomDisk(self): """Test custom disk sizes beyond range # Steps for validation # 1. listConfigurations - custom.diskoffering.size.min # and custom.diskoffering.size.max # 2. deployVm with custom disk offering size < min # 3. deployVm with custom disk offering min< size < max # 4. deployVm with custom disk offering size > max # Validate the following # 2. and 4. of deploy VM should fail. # Only case 3. should succeed. # cleanup all created data disks from the account """ config = Configurations.list( self.apiclient, name="custom.diskoffering.size.min" ) self.assertEqual( isinstance(config, list), True, "custom.diskoffering.size.min should be present in global config" ) # minimum size of custom disk (in GBs) min_size = int(config[0].value) self.debug("custom.diskoffering.size.min: %s" % min_size) config = Configurations.list( self.apiclient, name="custom.diskoffering.size.max" ) self.assertEqual( isinstance(config, list), True, "custom.diskoffering.size.min should be present in global config" ) # maximum size of custom disk (in GBs) max_size = int(config[0].value) self.debug("custom.diskoffering.size.max: %s" % max_size) self.debug("Creating a volume with size less than min cust disk size") self.testdata["custom_volume"]["customdisksize"] = (min_size - 1) self.testdata["custom_volume"]["zoneid"] = self.zone.id with self.assertRaises(Exception): vol = Volume.create_custom_disk( self.apiclient, self.testdata["custom_volume"], account=self.account.name, domainid=self.account.domainid, diskofferingid=self.disk_offering.id ) self.cleanup.append(vol) self.debug("Create volume failed!") self.debug("Creating a volume with size more than max cust disk size") self.testdata["custom_volume"]["customdisksize"] = (max_size + 1) with self.assertRaises(Exception): vol = Volume.create_custom_disk( self.apiclient, self.testdata["custom_volume"], account=self.account.name, domainid=self.account.domainid, diskofferingid=self.disk_offering.id ) self.cleanup.append(vol) self.debug("Create volume failed!") self.debug("Creating a volume with size more than min cust disk " + "but less than max cust disk size" ) self.testdata["custom_volume"]["customdisksize"] = (min_size + 1) vol = Volume.create_custom_disk( self.apiclient, self.testdata["custom_volume"], account=self.account.name, domainid=self.account.domainid, diskofferingid=self.disk_offering.id ) self.cleanup.append(vol) self.debug("Create volume of cust disk size succeeded") return class TestMigrateVolume(cloudstackTestCase): @classmethod def setUpClass(cls): cls.testClient = super(TestMigrateVolume, cls).getClsTestClient() cls.api_client = cls.testClient.getApiClient() cls.testdata = cls.testClient.getParsedTestDataConfig() # Get Zone, Domain and templates cls.domain = get_domain(cls.api_client) cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) cls.testdata['mode'] = cls.zone.networktype cls._cleanup = [] cls.unsupportedStorageType = False cls.hypervisor = cls.testClient.getHypervisorInfo() if cls.hypervisor.lower() == 'lxc': if not find_storage_pool_type(cls.api_client, storagetype='rbd'): cls.unsupportedStorageType = True return cls.disk_offering = DiskOffering.create( cls.api_client, cls.testdata["disk_offering"] ) cls._cleanup.append(cls.disk_offering) template = get_template( cls.api_client, cls.zone.id, cls.testdata["ostype"] ) cls.testdata["zoneid"] = cls.zone.id cls.testdata["virtual_machine"]["zoneid"] = cls.zone.id cls.testdata["virtual_machine"]["template"] = template.id cls.testdata["virtual_machine"][ "diskofferingid"] = cls.disk_offering.id # Create VMs, VMs etc cls.account = Account.create( cls.api_client, cls.testdata["account"], domainid=cls.domain.id ) cls._cleanup.append(cls.account) cls.small_offering = ServiceOffering.create( cls.api_client, cls.testdata["service_offering"] ) cls._cleanup.append(cls.small_offering) cls.virtual_machine = VirtualMachine.create( cls.api_client, cls.testdata["virtual_machine"], accountid=cls.account.name, domainid=cls.account.domainid, serviceofferingid=cls.small_offering.id, mode=cls.testdata["mode"] ) cls._cleanup.append(cls.virtual_machine) return @classmethod def tearDownClass(cls): super(TestMigrateVolume, cls).tearDownClass() def setUp(self): self.apiclient = self.testClient.getApiClient() self.dbclient = self.testClient.getDbConnection() self.cleanup = [] if self.unsupportedStorageType: self.skipTest("RBD storage type is required for data volumes for LXC") return def tearDown(self): super(TestMigrateVolume, self).tearDown() @attr(tags=["advanced", "sg", "advancedsg"], required_hardware='true') def test_01_migrateVolume(self): """ @Desc:Volume is not retaining same uuid when migrating from one storage to another. Step1:Create a volume/data disk Step2:Verify UUID of the volume Step3:Migrate the volume to another primary storage within the cluster Step4:Migrating volume to new primary storage should succeed Step5:volume UUID should not change even after migration """ if self.hypervisor.lower() in ["kvm"]: self.skipTest("KVM cannot migrate an attached volume without the VM") vol = Volume.create( self.apiclient, self.testdata["volume"], diskofferingid=self.disk_offering.id, zoneid=self.zone.id, account=self.account.name, domainid=self.account.domainid, ) self.cleanup.append(vol) self.assertIsNotNone(vol, "Failed to create volume") vol_res = Volume.list( self.apiclient, id=vol.id ) self.assertEqual( validateList(vol_res)[0], PASS, "Invalid response returned for list volumes") vol_uuid = vol_res[0].id self.virtual_machine.attach_volume( self.apiclient, vol ) self.cleanup.remove(vol) pools = StoragePool.listForMigration( self.apiclient, id=vol.id ) if not pools: self.skipTest( "No suitable storage pools found for volume migration.\ Skipping") self.assertEqual( validateList(pools)[0], PASS, "invalid pool response from findStoragePoolsForMigration") pool = pools[0] self.debug("Migrating Volume-ID: %s to Pool: %s" % (vol.id, pool.id)) Volume.migrate( self.apiclient, volumeid=vol.id, storageid=pool.id, livemigrate='true' ) migrated_vols = Volume.list( self.apiclient, virtualmachineid=self.virtual_machine.id, listall='true', type='DATADISK' ) self.assertEqual( validateList(migrated_vols)[0], PASS, "invalid volumes response after migration") migrated_vol_uuid = migrated_vols[0].id self.assertEqual( vol_uuid, migrated_vol_uuid, "Volume is not retaining same uuid when migrating from one\ storage to another" ) self.virtual_machine.detach_volume( self.apiclient, vol ) self.cleanup.append(vol) return