mirror of
https://github.com/apache/cloudstack
synced 2026-08-08 07:47:32 +00:00
This PR aligns the use of terminology, renaming VM / virtual machine references to 'Instance' and also capitalising the terms Templates, Network, Snapshot, User, Account in CloudStack APIs, error and log messages, events, tooltips, etc. Many typos, grammar and spelling mistakes were fixed, also terms like IPv4, VPN, VPC, etc. were properly capitalised. Some error messages were cleaned for better readability. The test cases, expecting some exception strings were adjusted accordingly. Here is the wiki page, describing the changes in details: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Object+Naming+and+Title+Case+Convention --------- Co-authored-by: Manoj Kumar <manojkr.itbhu@gmail.com> Co-authored-by: Harikrishna <harikrishna.patnala@gmail.com>
1623 lines
69 KiB
Python
1623 lines
69 KiB
Python
# 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.
|
|
"""Utilities functions
|
|
"""
|
|
# All tests inherit from cloudstack TestCase
|
|
|
|
from marvin.cloudstackTestCase import cloudstackTestCase
|
|
from marvin.cloudstackTestCase import cloudstackTestCase
|
|
import unittest
|
|
from marvin.codes import FAILED, PASS
|
|
from marvin.lib.base import (Account,
|
|
VirtualMachine,
|
|
ServiceOffering,
|
|
User,
|
|
DiskOffering,
|
|
Volume,
|
|
Template,
|
|
VmSnapshot,
|
|
StoragePool,
|
|
Host,
|
|
Capacities)
|
|
from marvin.lib.utils import cleanup_resources, validateList
|
|
from marvin.lib.common import (get_zone,
|
|
get_domain,
|
|
list_clusters,
|
|
get_template,
|
|
list_volumes,
|
|
list_virtual_machines)
|
|
from nose.plugins.attrib import attr
|
|
from ddt import ddt, data
|
|
|
|
|
|
def verify_vm_state(self, vmid, state):
|
|
list_vm = list_virtual_machines(self.userapiclient,
|
|
account=self.account.name,
|
|
domainid=self.account.domainid,
|
|
id=vmid)
|
|
self.assertEqual(
|
|
validateList(list_vm)[0],
|
|
PASS,
|
|
'Check List vm response for vmid: %s' %
|
|
vmid)
|
|
self.assertGreater(
|
|
len(list_vm),
|
|
0,
|
|
'Check the list vm response for vm id: %s' %
|
|
vmid)
|
|
vm = list_vm[0]
|
|
self.assertEqual(
|
|
vm.id,
|
|
str(vmid),
|
|
'Vm deployed is different from the test')
|
|
self.assertEqual(vm.state, state, 'VM is not in %s state' % state)
|
|
self.debug('VM is in is %s state' % state)
|
|
|
|
|
|
def verify_pool_state(self, poolid, state):
|
|
list_storage_pool_response = StoragePool.list(
|
|
self.userapiclient, id=poolid)
|
|
self.assertGreater(len(list_storage_pool_response), 0,
|
|
'Check list pool response is greater than 0')
|
|
self.assertEqual(
|
|
list_storage_pool_response[0].state,
|
|
state,
|
|
'Storage pool is not in %s state' %
|
|
state)
|
|
|
|
|
|
def verify_vm_storage_pool(self, vmid, storageid):
|
|
root_volume = Volume.list(
|
|
self.userapiclient,
|
|
virtualmachineid=vmid,
|
|
type='ROOT')[0]
|
|
list_volume = Volume.list(self.userapiclient, id=root_volume.id)
|
|
self.assertEqual(
|
|
list_volume[0].storageid,
|
|
storageid,
|
|
'check list volume response for Storage id: % s ' %
|
|
storageid)
|
|
|
|
|
|
@ddt
|
|
class TestPathDisableStorage_Basic(cloudstackTestCase):
|
|
"""
|
|
# Tests in this path requires to be run independently
|
|
# ( not to be run in parallel with any other tests since it involves disabling/enabling storage pools \
|
|
and may cause unexpected failures in other tests
|
|
# The test also requires to have 2 Cluster-wide and 2 zone-wide storage pools available in the setup.
|
|
# For running the tests on local storage, ensure there are 2 local storage pools set up on each host
|
|
|
|
"""
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
testClient = super(
|
|
TestPathDisableStorage_Basic,
|
|
cls).getClsTestClient()
|
|
cls.apiclient = testClient.getApiClient()
|
|
cls.testdata = testClient.getParsedTestDataConfig()
|
|
cls.domain = get_domain(cls.apiclient)
|
|
cls.zone = get_zone(cls.apiclient)
|
|
cls.testdata['mode'] = cls.zone.networktype
|
|
cls.template = get_template(
|
|
cls.apiclient,
|
|
cls.zone.id,
|
|
cls.testdata['ostype'])
|
|
cls.testdata['template']['ostypeid'] = cls.template.ostypeid
|
|
if cls.template == FAILED:
|
|
cls.fail(
|
|
'get_template() failed to return template with description %s'
|
|
% cls.testdata['ostype'])
|
|
cls._cleanup = []
|
|
cls.disabled_list = []
|
|
cls.testdata['template_2']['zoneid'] = cls.zone.id
|
|
cls.testdata['template_2']['ostypeid'] = cls.template.ostypeid
|
|
cls.hypervisor = testClient.getHypervisorInfo()
|
|
try:
|
|
cls.debug('Creating account')
|
|
cls.account = Account.create(cls.apiclient,
|
|
cls.testdata['account'],
|
|
admin=True
|
|
)
|
|
cls._cleanup.append(cls.account)
|
|
except Exception as e:
|
|
cls.tearDownClass()
|
|
raise e
|
|
|
|
# Create shared storage offerings
|
|
cls.service_offering_shared = ServiceOffering.create(
|
|
cls.apiclient, cls.testdata['service_offering'])
|
|
cls._cleanup.append(cls.service_offering_shared)
|
|
cls.disk_offering_shared = DiskOffering.create(
|
|
cls.apiclient, cls.testdata['disk_offering'])
|
|
cls.resized_disk_offering = DiskOffering.create(
|
|
cls.apiclient, cls.testdata['resized_disk_offering'])
|
|
cls._cleanup.append(cls.disk_offering_shared)
|
|
|
|
# Create offerings for local storage if local storage is enabled
|
|
if cls.zone.localstorageenabled:
|
|
cls.testdata["service_offerings"]["tiny"]["storagetype"] = 'local'
|
|
cls.service_offering_local = ServiceOffering.create(
|
|
cls.apiclient, cls.testdata["service_offerings"]["tiny"])
|
|
cls._cleanup.append(cls.service_offering_local)
|
|
cls.testdata["disk_offering"]["storagetype"] = 'local'
|
|
cls.disk_offering_local = DiskOffering.create(
|
|
cls.apiclient, cls.testdata["disk_offering"])
|
|
cls._cleanup.append(cls.disk_offering_local)
|
|
cls.testdata["disk_offering"]["storagetype"] = ' '
|
|
cls.testdata["service_offerings"]["tiny"]["storagetype"] = ' '
|
|
else:
|
|
cls.debug("No local storage found")
|
|
|
|
cls.userapiclient = testClient.getUserApiClient(
|
|
UserName=cls.account.name, DomainName=cls.account.domain)
|
|
response = User.login(cls.userapiclient,
|
|
username=cls.account.name,
|
|
password=cls.testdata['account']['password']
|
|
)
|
|
assert response.sessionkey is not None
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
try:
|
|
cleanup_resources(cls.apiclient, cls._cleanup)
|
|
except Exception as e:
|
|
raise Exception('Warning:Exception during cleanup: %s' % e)
|
|
|
|
def setUp(self):
|
|
self.apiclient = self.testClient.getApiClient()
|
|
self.cleanup = []
|
|
|
|
def tearDown(self):
|
|
if self.disabled_list:
|
|
for poolid in self.disabled_list:
|
|
if StoragePool.list(
|
|
self.userapiclient,
|
|
id=poolid)[0].state != 'Up':
|
|
try:
|
|
StoragePool.update(
|
|
self.userapiclient, id=poolid, enabled=True)
|
|
self.debug('Enabling: % s ' % poolid)
|
|
except Exception as e:
|
|
self.fail("Couldn't enable storage % s" % id)
|
|
|
|
try:
|
|
cleanup_resources(self.apiclient, self.cleanup)
|
|
except Exception as e:
|
|
self.fail('Warning: Exception during cleanup : %s' % e)
|
|
|
|
@data('host', 'CLUSTER', 'ZONE')
|
|
@attr(tags=['advanced', 'advancedsg', 'basic'], required_hardware='false')
|
|
def test_01_disable_enable_pool(self, value):
|
|
"""
|
|
|
|
Test Steps:
|
|
=========
|
|
1. Deploy 2 VMs
|
|
2. Stop VM2
|
|
3. Disable storage pool SP1
|
|
4. Try to deploy a new VM, should fail
|
|
5. Start VM2 which was stopped, should run from same pool
|
|
6. Remove disabled Storage pool SP1, should fail
|
|
7. Enable storage pool SP1
|
|
8. Deploy new VM, VM4 - should succeed
|
|
9. Create and attach new disk to VM4
|
|
10. Disable storage pool SP1 again and enable new pool
|
|
11. Deploy new VM, VM5 - should succeed
|
|
12. Stop VM1 which is running from disabled pool
|
|
13. Migrate ROOT volume of VM1 to another enabled storage pool - should succeed
|
|
14. findStoragePoolsforMigration should not list the disabled pool
|
|
"""
|
|
|
|
# Choose appropriate service offering depending on the scope the test
|
|
# is being run on
|
|
self.disabled_list = []
|
|
if value == 'CLUSTER':
|
|
other_scope = 'ZONE'
|
|
self.service_offering = self.service_offering_shared
|
|
self.disk_offering = self.disk_offering_shared
|
|
elif value == 'ZONE':
|
|
other_scope = 'CLUSTER'
|
|
self.service_offering = self.service_offering_shared
|
|
self.disk_offering = self.disk_offering_shared
|
|
elif value == 'host':
|
|
# local storage
|
|
other_scope = None
|
|
if self.zone.localstorageenabled:
|
|
self.service_offering = self.service_offering_local
|
|
self.disk_offering = self.disk_offering_local
|
|
else:
|
|
self.skipTest("Local storage not enabled")
|
|
|
|
# Keep only one pool active and disable the rest
|
|
try:
|
|
self.list_storage = StoragePool.list(
|
|
self.userapiclient, scope=value)
|
|
if self.list_storage:
|
|
count_st_pools = len(self.list_storage)
|
|
else:
|
|
count_st_pools = 0
|
|
self.disabled_pool_1 = None
|
|
if count_st_pools > 1:
|
|
self.debug(
|
|
'Found % s storage pools, keeping one and disabling rest' %
|
|
count_st_pools)
|
|
for pool in self.list_storage[1:]:
|
|
self.disabled_pool_1 = self.list_storage[1]
|
|
if pool.state == 'Up':
|
|
self.debug('Trying to disable storage %s' % pool.id)
|
|
try:
|
|
StoragePool.update(
|
|
self.userapiclient, id=pool.id, enabled=False)
|
|
self.disabled_list.append(pool.id)
|
|
self.debug(
|
|
'Appended to list of disabled pools. List is now: % s ' %
|
|
self.disabled_list)
|
|
except Exception as e:
|
|
raise e
|
|
elif count_st_pools == 1:
|
|
self.debug(
|
|
'Only one % s wide storage found - will not be able to complete all tests' %
|
|
value)
|
|
else:
|
|
self.skipTest('No % s storage pools found' % value)
|
|
except Exception as e:
|
|
raise e
|
|
|
|
# Disable the other scope shared storage pools while we are testing on
|
|
# one - applicable for only shared storage
|
|
if value != 'host':
|
|
try:
|
|
self.list_storage = StoragePool.list(
|
|
self.userapiclient, scope=other_scope)
|
|
if self.list_storage:
|
|
for pool in self.list_storage:
|
|
if pool.state == 'Up':
|
|
self.debug(
|
|
'Trying to disable storage % s' %
|
|
pool.id)
|
|
try:
|
|
StoragePool.update(
|
|
self.userapiclient, id=pool.id, enabled=False)
|
|
self.disabled_list.append(pool.id)
|
|
self.debug(
|
|
'Appended to list of disabled pools. List is now: % s ' %
|
|
self.disabled_list)
|
|
except Exception as e:
|
|
self.fail(
|
|
"Couldn't disable storage % s" % pool.id)
|
|
else:
|
|
self.debug('No % s wide storage pools found' % other_scope)
|
|
except Exception as e:
|
|
raise e
|
|
|
|
# Step 1: Deploy 2 VMs
|
|
self.virtual_machine_1 = VirtualMachine.create(
|
|
self.userapiclient,
|
|
self.testdata['small'],
|
|
templateid=self.template.id,
|
|
accountid=self.account.name,
|
|
domainid=self.account.domainid,
|
|
serviceofferingid=self.service_offering.id,
|
|
zoneid=self.zone.id)
|
|
verify_vm_state(self, self.virtual_machine_1.id, 'Running')
|
|
self.virtual_machine_2 = VirtualMachine.create(
|
|
self.userapiclient,
|
|
self.testdata['small'],
|
|
templateid=self.template.id,
|
|
accountid=self.account.name,
|
|
domainid=self.account.domainid,
|
|
serviceofferingid=self.service_offering.id,
|
|
zoneid=self.zone.id)
|
|
verify_vm_state(self, self.virtual_machine_2.id, 'Running')
|
|
|
|
# Step 2: Keep one VM in stopped state while other keeps running
|
|
try:
|
|
self.debug('Step 2: Stopping one of the VMs')
|
|
self.virtual_machine_2.stop(self.userapiclient)
|
|
verify_vm_state(self, self.virtual_machine_2.id, 'Stopped')
|
|
except Exception as e:
|
|
self.fail('Step 2: Failed to stop VM: %s' % e)
|
|
|
|
# Step 3: Disable the Storage Pool, verify VMs are in same state as
|
|
# before
|
|
self.storage_pools_list = StoragePool.list(
|
|
self.userapiclient, scope=value, state='Up')
|
|
self.storage_pool_1 = self.storage_pools_list[0]
|
|
try:
|
|
self.debug(
|
|
'Step 3: Disabling Storage Pool: %s' %
|
|
self.storage_pool_1.id)
|
|
StoragePool.update(
|
|
self.userapiclient,
|
|
id=self.storage_pool_1.id,
|
|
enabled=False)
|
|
except Exception as e:
|
|
self.debug("Step 3: Couldn't disable pool %s" % e)
|
|
|
|
verify_pool_state(self, self.storage_pool_1.id, 'Disabled')
|
|
verify_vm_state(self, self.virtual_machine_1.id, 'Running')
|
|
verify_vm_state(self, self.virtual_machine_2.id, 'Stopped')
|
|
|
|
# Step 4: Deploying new VM on disabled pool should fail
|
|
self.debug(
|
|
'Step 4: Trying to deploy VM on disabled storage - should fail')
|
|
with self.assertRaises(Exception):
|
|
VirtualMachine.create(self.userapiclient,
|
|
self.testdata['small'],
|
|
templateid=self.template.id,
|
|
accountid=self.account.name,
|
|
domainid=self.account.domainid,
|
|
serviceofferingid=self.service_offering.id,
|
|
zoneid=self.zone.id)
|
|
|
|
# Step 5: Should be able to start VM on disabled pool
|
|
try:
|
|
self.virtual_machine_2.start(self.userapiclient)
|
|
verify_vm_state(self, self.virtual_machine_2.id, 'Running')
|
|
verify_vm_storage_pool(
|
|
self,
|
|
self.virtual_machine_2.id,
|
|
self.storage_pool_1.id)
|
|
except Exception as e:
|
|
self.fail('Step 5: Failed to start VM: %s' % e)
|
|
|
|
# Step 6: Removing disabled pool should fail
|
|
self.debug('Step 6: Trying to remove disabled storage pool')
|
|
with self.assertRaises(Exception):
|
|
StoragePool.delete(self.userapiclient, self.storage_pool_1.id)
|
|
|
|
# Step 7: Enable Storage pool
|
|
try:
|
|
self.debug(
|
|
'Step 7: Enabling Storage Pool: %s' %
|
|
self.storage_pool_1.id)
|
|
StoragePool.update(
|
|
self.userapiclient,
|
|
id=self.storage_pool_1.id,
|
|
enabled=True)
|
|
except Exception as e:
|
|
self.debug("Step 7: Couldn't enable pool %s" % e)
|
|
verify_pool_state(self, self.storage_pool_1.id, 'Up')
|
|
|
|
# Step 8: Deploy a VM on the pool
|
|
self.virtual_machine_3 = VirtualMachine.create(
|
|
self.userapiclient,
|
|
self.testdata['small'],
|
|
templateid=self.template.id,
|
|
accountid=self.account.name,
|
|
domainid=self.account.domainid,
|
|
serviceofferingid=self.service_offering.id,
|
|
zoneid=self.zone.id)
|
|
verify_vm_state(self, self.virtual_machine_3.id, 'Running')
|
|
|
|
if self.hypervisor.lower() == 'lxc':
|
|
self.skipTest("Not running rest of tests in lxc")
|
|
|
|
# Step 9: Create and attach new disk to VM
|
|
self.volume = Volume.create(self.userapiclient,
|
|
services=self.testdata['volume'],
|
|
diskofferingid=self.disk_offering.id,
|
|
zoneid=self.zone.id)
|
|
list_volume = Volume.list(
|
|
self.userapiclient,
|
|
id=self.volume.id,
|
|
accountid=self.account.name,
|
|
domainid=self.account.domainid)
|
|
self.assertEqual(
|
|
validateList(list_volume)[0],
|
|
PASS,
|
|
'Step 9: Check List volume response for volume %s' %
|
|
self.volume.id)
|
|
self.assertEqual(
|
|
list_volume[0].id,
|
|
self.volume.id,
|
|
'Step 9: check list volume response for volume id: %s' %
|
|
self.volume.id)
|
|
self.debug(
|
|
'Step 9: volume id %s got created successfully' %
|
|
list_volume[0].id)
|
|
|
|
self.virtual_machine_3.attach_volume(self.userapiclient, self.volume)
|
|
list_volume = Volume.list(self.userapiclient, id=self.volume.id)
|
|
self.assertEqual(
|
|
list_volume[0].virtualmachineid,
|
|
self.virtual_machine_3.id,
|
|
'Step 9: Check if volume state (attached) is reflected')
|
|
self.debug(
|
|
'Step 9: volume id:%s successfully attached to vm id%s' %
|
|
(self.volume.id, self.virtual_machine_3.id))
|
|
if self.disabled_pool_1:
|
|
newpoolid = self.disabled_pool_1.id
|
|
else:
|
|
self.skipTest(
|
|
'Step 9: Could not find a second storage pool to complete the remaining tests')
|
|
|
|
# Step 10: Disable storage pool SP1 again and enable new pool
|
|
try:
|
|
StoragePool.update(self.userapiclient, id=newpoolid, enabled=True)
|
|
except Exception as e:
|
|
self.fail('Step 10: Enable storage pool %s' % e, 'failed')
|
|
verify_pool_state(self, newpoolid, 'Up')
|
|
try:
|
|
self.debug(
|
|
'Step 10: Disabling Storage Pool: %s' %
|
|
self.storage_pool_1.id)
|
|
StoragePool.update(
|
|
self.userapiclient,
|
|
id=self.storage_pool_1.id,
|
|
enabled=False)
|
|
self.disabled_list.append(self.storage_pool_1.id)
|
|
self.debug(
|
|
'Step 10: Appended to list of disabled pools. List is now: % s ' %
|
|
self.disabled_list)
|
|
except Exception as e:
|
|
self.debug("Step 10: Couldn't disable pool %s" % e)
|
|
verify_pool_state(self, self.storage_pool_1.id, 'Disabled')
|
|
|
|
# Step 11: Deploy new VM, VM5 - should succeed
|
|
self.virtual_machine_4 = VirtualMachine.create(
|
|
self.userapiclient,
|
|
self.testdata['small'],
|
|
templateid=self.template.id,
|
|
accountid=self.account.name,
|
|
domainid=self.account.domainid,
|
|
serviceofferingid=self.service_offering.id,
|
|
zoneid=self.zone.id)
|
|
verify_vm_state(self, self.virtual_machine_4.id, 'Running')
|
|
|
|
# Step 12: Stop VM1 which is running from disabled pool
|
|
self.virtual_machine_1.stop(self.userapiclient)
|
|
verify_vm_state(self, self.virtual_machine_1.id, 'Stopped')
|
|
|
|
# Step 13: Migrate ROOT volume of VM1 to another enabled storage pool -
|
|
# should succeed
|
|
if value != 'host':
|
|
root_volume = Volume.list(
|
|
self.userapiclient,
|
|
virtualmachineid=self.virtual_machine_1.id,
|
|
type='ROOT')
|
|
try:
|
|
Volume.migrate(
|
|
self.userapiclient,
|
|
volumeid=root_volume[0].id,
|
|
storageid=newpoolid)
|
|
except Exception as e:
|
|
raise e
|
|
list_volume = list_volumes(
|
|
self.userapiclient, id=root_volume[0].id)
|
|
self.assertEqual(
|
|
isinstance(
|
|
list_volume,
|
|
list),
|
|
True,
|
|
'Step 13: Check list volumes response for valid list')
|
|
|
|
# Step 14: findStoragePoolsforMigration should not list the disabled
|
|
# pool
|
|
if value != 'host':
|
|
pools_for_migration = StoragePool.listForMigration(
|
|
self.userapiclient, id=root_volume[0].id)
|
|
self.debug(
|
|
'Step 14: List of pools suitable for migration: % s ' %
|
|
pools_for_migration)
|
|
if pools_for_migration:
|
|
if self.storage_pool_1 in pools_for_migration:
|
|
self.fail(
|
|
'Step 14: Storage pool % s is supposed to be disabled and not suitable for migration, \
|
|
but found in the list of pools suitable for migration' %
|
|
self.storage_pool_1.id)
|
|
|
|
@data('host', 'CLUSTER', 'ZONE')
|
|
@attr(tags=['advanced', 'advancedsg', 'basic'], required_hardware='false')
|
|
def test_02_vm_operations_on_disabled_pool(self, value):
|
|
"""
|
|
Test Steps:
|
|
=========
|
|
|
|
1. Deploy an Instance and attach volume
|
|
2. Disable Storage
|
|
3. Create Template from root volume of the Instance
|
|
4. Attach a new volume - should fail
|
|
5. Resize DATA disk to a higher value
|
|
6. Take Instance Snapshot of the Instance (for supported hypervisors)
|
|
7. Destroy the VM and immediately restore the Instance
|
|
8. Enable a new storage pool
|
|
9. Re-install the Instance with same template
|
|
10. Re-install the Instance with the new template created earlier
|
|
11. Repeat tests with enabled pool, Attach new Volume to VM2
|
|
12. Resize disk to a higher value
|
|
13. Reboot the Instance
|
|
14. Take Instance Snapshot of the Instance
|
|
15. Destroy the VM and immediately restore the Instance
|
|
|
|
"""
|
|
|
|
# Choose appropriate service offering depending on the scope the test
|
|
# is being run on
|
|
self.disabled_list = []
|
|
if value == 'CLUSTER':
|
|
other_scope = 'ZONE'
|
|
self.service_offering = self.service_offering_shared
|
|
self.disk_offering = self.disk_offering_shared
|
|
elif value == 'ZONE':
|
|
other_scope = 'CLUSTER'
|
|
self.service_offering = self.service_offering_shared
|
|
self.disk_offering = self.disk_offering_shared
|
|
elif value == 'host':
|
|
# local storage
|
|
other_scope = None
|
|
if self.zone.localstorageenabled:
|
|
self.service_offering = self.service_offering_local
|
|
self.disk_offering = self.disk_offering_local
|
|
else:
|
|
self.skipTest("Local storage not enabled")
|
|
|
|
if self.hypervisor.lower() == 'lxc':
|
|
self.skipTest("Not running rest of tests in lxc")
|
|
|
|
# Keep one storage pool active and disable the rest
|
|
try:
|
|
self.list_storage = StoragePool.list(
|
|
self.userapiclient, scope=value)
|
|
if self.list_storage:
|
|
count_st_pools = len(self.list_storage)
|
|
else:
|
|
count_st_pools = 0
|
|
self.disabled_pool_1 = None
|
|
if count_st_pools > 1:
|
|
self.debug(
|
|
'Found % s storage pools, keeping one and disabling rest' %
|
|
count_st_pools)
|
|
for pool in self.list_storage[1:]:
|
|
self.disabled_pool_1 = self.list_storage[1]
|
|
if pool.state == 'Up':
|
|
self.debug('Trying to disable storage %s' % pool.id)
|
|
try:
|
|
StoragePool.update(
|
|
self.userapiclient, id=pool.id, enabled=False)
|
|
self.disabled_list.append(pool.id)
|
|
self.debug(
|
|
'Appended to list of disabled pools. List is now: % s ' %
|
|
self.disabled_list)
|
|
except Exception as e:
|
|
raise e
|
|
elif count_st_pools == 1:
|
|
self.debug(
|
|
'Only one % s wide storage found - will not be able to complete all tests' %
|
|
value)
|
|
else:
|
|
self.skipTest('No % s wide storage pools found' % value)
|
|
except Exception as e:
|
|
raise e
|
|
|
|
# Disable the other scope storage pools while we are testing on one
|
|
# scope - applicable for only shared storage
|
|
if value != 'host':
|
|
try:
|
|
self.list_storage = StoragePool.list(
|
|
self.userapiclient, scope=other_scope)
|
|
if self.list_storage:
|
|
for pool in self.list_storage:
|
|
if pool.state == 'Up':
|
|
self.debug(
|
|
'Trying to disable storage % s' %
|
|
pool.id)
|
|
try:
|
|
StoragePool.update(
|
|
self.userapiclient, id=pool.id, enabled=False)
|
|
self.disabled_list.append(pool.id)
|
|
self.debug(
|
|
'Appended to list of disabled pools. List is now: % s ' %
|
|
self.disabled_list)
|
|
except Exception as e:
|
|
self.fail(
|
|
"Couldn't disable storage % s" % pool.id)
|
|
else:
|
|
self.debug('No % s wide storage pools found' % other_scope)
|
|
except Exception as e:
|
|
raise e
|
|
|
|
# Step 1: Deploy a VM and attach data disk to one VM
|
|
self.virtual_machine_1 = VirtualMachine.create(
|
|
self.userapiclient,
|
|
self.testdata['small'],
|
|
templateid=self.template.id,
|
|
accountid=self.account.name,
|
|
domainid=self.account.domainid,
|
|
serviceofferingid=self.service_offering.id,
|
|
zoneid=self.zone.id)
|
|
verify_vm_state(self, self.virtual_machine_1.id, 'Running')
|
|
|
|
self.volume_1 = Volume.create(self.userapiclient,
|
|
services=self.testdata['volume'],
|
|
diskofferingid=self.disk_offering.id,
|
|
zoneid=self.zone.id)
|
|
self.virtual_machine_1.attach_volume(self.userapiclient, self.volume_1)
|
|
list_volume = Volume.list(self.userapiclient, id=self.volume_1.id)
|
|
self.assertEqual(
|
|
list_volume[0].virtualmachineid,
|
|
self.virtual_machine_1.id,
|
|
''
|
|
'Check if volume state (attached) is reflected')
|
|
self.debug(
|
|
'Step 1: volume id:%s successfully attached to vm id%s' %
|
|
(self.volume_1.id, self.virtual_machine_1.id))
|
|
|
|
# Step 2: Disable the storage pool
|
|
|
|
self.storage_pools_list = StoragePool.list(
|
|
self.userapiclient, scope=value, state='Up')
|
|
self.storage_pool_1 = self.storage_pools_list[0]
|
|
|
|
try:
|
|
self.debug(
|
|
'Step 2: Disabling Storage Pool: %s' %
|
|
self.storage_pool_1.id)
|
|
StoragePool.update(
|
|
self.userapiclient,
|
|
id=self.storage_pool_1.id,
|
|
enabled=False)
|
|
self.disabled_list.append(self.storage_pool_1.id)
|
|
except Exception as e:
|
|
self.debug("Step 2: Couldn't disable pool %s" % e)
|
|
verify_pool_state(self, self.storage_pool_1.id, 'Disabled')
|
|
verify_vm_state(self, self.virtual_machine_1.id, 'Running')
|
|
|
|
# Step 3: Create Template from root volume of the VM
|
|
root_volume_1 = Volume.list(
|
|
self.userapiclient,
|
|
virtualmachineid=self.virtual_machine_1.id,
|
|
type='ROOT')[0]
|
|
self.virtual_machine_1.stop(self.userapiclient)
|
|
try:
|
|
template_2 = Template.create(self.userapiclient,
|
|
self.testdata['template_2'],
|
|
volumeid=root_volume_1.id,
|
|
account=self.account.name,
|
|
domainid=self.account.domainid)
|
|
self.cleanup.append(template_2)
|
|
self.debug('Step 3: Created template with ID: %s' % template_2.id)
|
|
list_template = Template.list(
|
|
self.userapiclient,
|
|
templatefilter='self',
|
|
id=template_2.id)
|
|
except Exception as e:
|
|
self.fail('Step 3: Template from volume failed')
|
|
|
|
# Step 4: Attach a new volume - should fail
|
|
self.volume_2 = Volume.create(self.userapiclient,
|
|
services=self.testdata['volume'],
|
|
diskofferingid=self.disk_offering.id,
|
|
zoneid=self.zone.id)
|
|
self.debug(
|
|
'Step 4: Trying to attach new volume to VM on disabled storage - should fail')
|
|
with self.assertRaises(Exception):
|
|
self.virtual_machine_1.attach_volume(
|
|
self.userapiclient, self.volume_2)
|
|
|
|
# Step 5: Resize DATA disk to a higher value for attached disk
|
|
try:
|
|
self.volume_1.resize(self.userapiclient,
|
|
diskofferingid=self.resized_disk_offering.id)
|
|
list_volume_1 = Volume.list(
|
|
self.userapiclient, id=self.volume_1.id)
|
|
self.assertEqual(
|
|
list_volume_1[0].diskofferingid,
|
|
self.resized_disk_offering.id,
|
|
'check list volume response for volume id: %s' %
|
|
self.volume_1.id)
|
|
self.debug(
|
|
'Step 5: volume id %s got resized successfully' %
|
|
list_volume_1[0].id)
|
|
except Exception as e:
|
|
self.fail('Step 5: Volume resize on disabled pool failed: % s' % e)
|
|
|
|
# Step 6: Take VM Snapshot
|
|
if self.hypervisor.lower() not in ('kvm', 'hyperv', 'lxc'):
|
|
try:
|
|
self.debug(
|
|
"Step 6: Taking Instance Snapshot for Instance id % s" %
|
|
self.virtual_machine_1.id)
|
|
vm_snapshot = VmSnapshot.create(self.userapiclient,
|
|
self.virtual_machine_1.id,
|
|
'false',
|
|
'TestSnapshot',
|
|
'Display Text')
|
|
self.assertEqual(
|
|
vm_snapshot.state,
|
|
'Ready',
|
|
'Check VM snapshot is ready')
|
|
except Exception as e:
|
|
self.fail(
|
|
'Step 6: VM Snapshot on disabled pool failed: % s' %
|
|
e)
|
|
|
|
if vm_snapshot:
|
|
self.debug('Step 6: Deleting Vm Snapshot')
|
|
VmSnapshot.deleteVMSnapshot(self.userapiclient, vm_snapshot.id)
|
|
|
|
# Step 7: Destroy VM and immediately restore the VM
|
|
self.debug(
|
|
"Step 7: Deleting and restoring the VM, should continue to run from same storage pool")
|
|
self.virtual_machine_1.delete(self.userapiclient, expunge=False)
|
|
self.virtual_machine_1.recover(self.userapiclient)
|
|
verify_vm_state(self, self.virtual_machine_1.id, 'Stopped')
|
|
self.virtual_machine_1.start(self.userapiclient)
|
|
verify_vm_state(self, self.virtual_machine_1.id, 'Running')
|
|
verify_vm_storage_pool(
|
|
self,
|
|
self.virtual_machine_1.id,
|
|
self.storage_pool_1.id)
|
|
|
|
# Step 8: Enable new pool
|
|
if self.disabled_pool_1:
|
|
try:
|
|
newpoolid = self.disabled_pool_1.id
|
|
StoragePool.update(
|
|
self.userapiclient, id=newpoolid, enabled=True)
|
|
self.debug("Step 8: Enabling new pool % s " % newpoolid)
|
|
if newpoolid in self.disabled_list:
|
|
self.disabled_list.remove(newpoolid)
|
|
except Exception as e:
|
|
self.fail('Step 8: Enable storage pool %s' % e, 'failed')
|
|
else:
|
|
self.debug(
|
|
'Step 8: Could not find a second storage pool, so enabling the first storage pool and running the tests')
|
|
try:
|
|
self.debug(
|
|
'Step 8: Enabling Storage Pool: %s' %
|
|
self.storage_pool_1.id)
|
|
StoragePool.update(
|
|
self.userapiclient,
|
|
id=self.storage_pool_1.id,
|
|
enabled=True)
|
|
if self.storage_pool_1.id in self.disabled_list:
|
|
self.disabled_list.remove(self.storage_pool_1.id)
|
|
newpoolid = self.storage_pool_1.id
|
|
except Exception as e:
|
|
self.fail("Step 8: Couldn't enable pool %s" % e)
|
|
verify_pool_state(self, newpoolid, 'Up')
|
|
|
|
# Step 9: Re-install the VM with same template
|
|
|
|
if value != 'host':
|
|
self.debug("Step 9: Re-installing VM 1")
|
|
vm_restore = self.virtual_machine_1.restore(
|
|
self.userapiclient, templateid=self.template.id)
|
|
verify_vm_storage_pool(self, self.virtual_machine_1.id, newpoolid)
|
|
|
|
# Step 10 : Re-install VM with different template
|
|
self.debug("Step 10: re-installing VM with different template")
|
|
vm_restore = self.virtual_machine_1.restore(
|
|
self.userapiclient, templateid=template_2.id)
|
|
verify_vm_storage_pool(self, self.virtual_machine_1.id, newpoolid)
|
|
|
|
# Step 11: Repeat tests with enabled pool. Start with attach VM
|
|
if value != 'host':
|
|
self.debug("Step 11: Attach volume to VM")
|
|
self.virtual_machine_1.attach_volume(
|
|
self.userapiclient, self.volume_2)
|
|
list_volume_2 = Volume.list(
|
|
self.userapiclient, id=self.volume_2.id)
|
|
self.assertEqual(list_volume_2[0].virtualmachineid,
|
|
self.virtual_machine_1.id,
|
|
'Check if volume state (attached) is reflected')
|
|
self.debug(
|
|
'Step 11: volume id:% s successfully attached to vm id % s' %
|
|
(self.volume_2.id, self.virtual_machine_1.id))
|
|
|
|
# Step 12: Re-size Volume to higher disk offering
|
|
try:
|
|
self.virtual_machine_1.stop(self.userapiclient)
|
|
self.volume_2.resize(
|
|
self.userapiclient,
|
|
diskofferingid=self.resized_disk_offering.id)
|
|
list_volume_2 = Volume.list(
|
|
self.userapiclient, id=self.volume_2.id)
|
|
self.assertEqual(
|
|
list_volume_2[0].diskofferingid,
|
|
self.resized_disk_offering.id,
|
|
'check list volume response for volume id: %s' %
|
|
self.volume_2.id)
|
|
self.debug(
|
|
'Step 12: volume id %s got resized successfully' %
|
|
list_volume_2[0].id)
|
|
except Exception as e:
|
|
self.fail('Step 12: Failed to resize volume % s ' % e)
|
|
self.virtual_machine_1.start(self.userapiclient)
|
|
|
|
# Step 13: Reboot VM
|
|
self.virtual_machine_1.reboot(self.userapiclient)
|
|
verify_vm_state(self, self.virtual_machine_1.id, 'Running')
|
|
|
|
# Step 14: Take Snapshot of VM
|
|
if self.hypervisor.lower() not in ('kvm', 'hyperv', 'lxc'):
|
|
try:
|
|
vm_snapshot = VmSnapshot.create(
|
|
self.userapiclient,
|
|
self.virtual_machine_1.id,
|
|
'false',
|
|
'TestSnapshot2',
|
|
'Display Text')
|
|
self.assertEqual(
|
|
vm_snapshot.state,
|
|
'Ready',
|
|
'Check the snapshot of vm is ready!')
|
|
except Exception as e:
|
|
self.fail(
|
|
'Step 14: Snapshot failed post enabling new storage pool')
|
|
|
|
# Step 15: Delete and recover VM
|
|
self.debug("Step 15: Deleting and recovering VM")
|
|
self.virtual_machine_1.delete(self.userapiclient, expunge=False)
|
|
self.virtual_machine_1.recover(self.userapiclient)
|
|
verify_vm_state(self, self.virtual_machine_1.id, 'Stopped')
|
|
self.virtual_machine_1.start(self.userapiclient)
|
|
verify_vm_state(self, self.virtual_machine_1.id, 'Running')
|
|
|
|
|
|
@ddt
|
|
class TestPathDisableStorage_Maint_Tags(cloudstackTestCase):
|
|
"""
|
|
# Tests in this path requires to be run independently
|
|
# Not to be run in parallel with any other tests since it involves disabling/enabling storage pools \
|
|
and may cause unexpected failures in other tests
|
|
# The test also requires to have 2 Cluster-wide and 2 zone-wide storage pools available in the setup.
|
|
# For running the tests on local storage, ensure there are 2 local storage pools set up on each host or different hosts
|
|
|
|
"""
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
testClient = super(
|
|
TestPathDisableStorage_Maint_Tags,
|
|
cls).getClsTestClient()
|
|
cls.apiclient = testClient.getApiClient()
|
|
cls.testdata = testClient.getParsedTestDataConfig()
|
|
cls.domain = get_domain(cls.apiclient)
|
|
cls.zone = get_zone(cls.apiclient)
|
|
cls.testdata['mode'] = cls.zone.networktype
|
|
cls.template = get_template(
|
|
cls.apiclient,
|
|
cls.zone.id,
|
|
cls.testdata['ostype'])
|
|
cls.testdata['template']['ostypeid'] = cls.template.ostypeid
|
|
if cls.template == FAILED:
|
|
cls.fail(
|
|
'get_template() failed to return template with description %s' %
|
|
cls.testdata['ostype'])
|
|
cls._cleanup = []
|
|
cls.disabled_list = []
|
|
cls.maint_list = []
|
|
cls.testdata['template_2']['zoneid'] = cls.zone.id
|
|
cls.testdata['template_2']['ostypeid'] = cls.template.ostypeid
|
|
cls.hypervisor = testClient.getHypervisorInfo()
|
|
try:
|
|
cls.account = Account.create(cls.apiclient,
|
|
cls.testdata['account'],
|
|
admin=True)
|
|
cls.debug('Creating account')
|
|
cls._cleanup.append(cls.account)
|
|
|
|
# Create shared storage offerings
|
|
cls.service_offering_shared = ServiceOffering.create(
|
|
cls.apiclient, cls.testdata['service_offering'])
|
|
cls._cleanup.append(cls.service_offering_shared)
|
|
cls.disk_offering_shared = DiskOffering.create(
|
|
cls.apiclient, cls.testdata['disk_offering'])
|
|
cls.resized_disk_offering = DiskOffering.create(
|
|
cls.apiclient, cls.testdata['resized_disk_offering'])
|
|
cls._cleanup.append(cls.disk_offering_shared)
|
|
|
|
# Create offerings for local storage if local storage is enabled
|
|
if cls.zone.localstorageenabled:
|
|
cls.testdata["service_offerings"][
|
|
"tiny"]["storagetype"] = 'local'
|
|
cls.debug("Creating local storage offering")
|
|
cls.service_offering_local = ServiceOffering.create(
|
|
cls.apiclient, cls.testdata["service_offerings"]["tiny"])
|
|
cls._cleanup.append(cls.service_offering_local)
|
|
cls.testdata["disk_offering"]["storagetype"] = 'local'
|
|
cls.debug("Creating local storage disk offering")
|
|
cls.disk_offering_local = DiskOffering.create(
|
|
cls.apiclient, cls.testdata["disk_offering"])
|
|
cls._cleanup.append(cls.disk_offering_local)
|
|
cls.testdata["disk_offering"]["storagetype"] = ' '
|
|
cls.testdata["service_offerings"]["tiny"]["storagetype"] = ' '
|
|
else:
|
|
cls.debug("No local storage found")
|
|
|
|
cls.userapiclient = testClient.getUserApiClient(
|
|
UserName=cls.account.name, DomainName=cls.account.domain)
|
|
response = User.login(cls.userapiclient,
|
|
username=cls.account.name,
|
|
password=cls.testdata['account']['password'])
|
|
assert response.sessionkey is not None
|
|
except Exception as e:
|
|
cls.tearDownClass()
|
|
raise e
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
try:
|
|
cleanup_resources(cls.apiclient, cls._cleanup)
|
|
except Exception as e:
|
|
raise Exception('Warning:Exception during cleanup: %s' % e)
|
|
|
|
def setUp(self):
|
|
self.apiclient = self.testClient.getApiClient()
|
|
self.cleanup = []
|
|
|
|
def tearDown(self):
|
|
if self.disabled_list:
|
|
for poolid in self.disabled_list:
|
|
if StoragePool.list(self.userapiclient, id=poolid)[0].state == 'Disabled':
|
|
try:
|
|
StoragePool.update(
|
|
self.userapiclient, id=poolid, enabled=True)
|
|
self.debug('Enabling: % s ' % poolid)
|
|
except Exception as e:
|
|
self.fail("Couldn't enable storage % s" % id)
|
|
|
|
if self.maint_list:
|
|
for poolid in self.maint_list:
|
|
if StoragePool.list(self.userapiclient, id=poolid)[0].state == 'Maintenance':
|
|
try:
|
|
StoragePool.cancelMaintenance(
|
|
self.userapiclient, id=poolid)
|
|
self.debug(
|
|
'Cancelled Maintenance mode for % s' %
|
|
poolid)
|
|
except Exception as e:
|
|
self.fail(
|
|
"Couldn't cancel Maintenance mode for storage % s " %
|
|
poolid)
|
|
|
|
try:
|
|
cleanup_resources(self.apiclient, self.cleanup)
|
|
except Exception as e:
|
|
self.fail('Warning: Exception during cleanup : %s' % e)
|
|
|
|
@data('host', 'CLUSTER', 'ZONE')
|
|
@attr(tags=['advanced', 'advancedsg', 'basic'], required_hardware='false')
|
|
def test_01_maint_capacity_tags(self, value):
|
|
"""
|
|
|
|
Test Steps:
|
|
========
|
|
|
|
1. Deploy VM
|
|
2. Add storage to maintenance
|
|
3. Cancel Maintenance
|
|
4. Disable pool and then Start the VM - verify it runs off the same pool
|
|
5. Perform more VM operations - reboot
|
|
6. Add tags to pool
|
|
7. Create tagged offering with same tags
|
|
8. Enable pool
|
|
9. Deploy VM using the tagged offering
|
|
10. Disable storage pool again
|
|
11. Calculate current capacity used so far for the storage pool
|
|
12. Delete VM and check capacity is re-calculated in the disabled pool
|
|
13. Perform VM deploy - should fail since pool is disabled
|
|
14. Re-calculate Capacity, should not be altered
|
|
|
|
|
|
"""
|
|
|
|
# Choose appropriate service offering depending on the scope the test
|
|
# is being run on
|
|
self.disabled_list = []
|
|
if value == 'CLUSTER':
|
|
other_scope = 'ZONE'
|
|
self.service_offering = self.service_offering_shared
|
|
self.disk_offering = self.disk_offering_shared
|
|
elif value == 'ZONE':
|
|
other_scope = 'CLUSTER'
|
|
self.service_offering = self.service_offering_shared
|
|
self.disk_offering = self.disk_offering_shared
|
|
elif value == 'host':
|
|
# local storage
|
|
if self.zone.localstorageenabled:
|
|
other_scope = None
|
|
self.service_offering = self.service_offering_local
|
|
self.disk_offering = self.disk_offering_local
|
|
else:
|
|
self.skipTest("Local storage not enabled")
|
|
|
|
# Keep 2 storage pools active and disable the rest. If only one storage
|
|
# pool is present, then skip the test
|
|
try:
|
|
self.list_storage = StoragePool.list(
|
|
self.userapiclient, scope=value)
|
|
count_st_pools = len(self.list_storage)
|
|
if count_st_pools <= 1:
|
|
raise unittest.SkipTest(
|
|
'Found 1 or less storage pools in % s wide scope- cannot proceed' %
|
|
value)
|
|
elif count_st_pools > 2:
|
|
for pool in self.list_storage[2:]:
|
|
if pool.state == 'Up':
|
|
self.debug('Trying to disable storage %s' % pool.id)
|
|
try:
|
|
StoragePool.update(
|
|
self.userapiclient, id=pool.id, enabled=False)
|
|
self.disabled_list.append(pool.id)
|
|
self.debug(
|
|
'Appended to list of disabled pools. List is now: % s ' %
|
|
self.disabled_list)
|
|
except Exception as e:
|
|
raise e
|
|
elif count_st_pools == 2:
|
|
for pool in self.list_storage:
|
|
if pool.state != 'Up':
|
|
raise unittest.SkipTest(
|
|
'Found storage pool % s not in Up State.. cannot proceed' %
|
|
pool.id)
|
|
except Exception as e:
|
|
raise e
|
|
|
|
# Disable the other scope shared storage pools while we are testing on
|
|
# one - applicable for only shared storage
|
|
if value != 'host':
|
|
try:
|
|
self.list_storage = StoragePool.list(
|
|
self.userapiclient, scope=other_scope)
|
|
if self.list_storage:
|
|
for pool in self.list_storage:
|
|
if pool.state == 'Up':
|
|
self.debug(
|
|
'Trying to disable storage % s' %
|
|
pool.id)
|
|
try:
|
|
StoragePool.update(
|
|
self.userapiclient, id=pool.id, enabled=False)
|
|
self.disabled_list.append(pool.id)
|
|
self.debug(
|
|
'Appended to list of disabled pools. List is now: % s ' %
|
|
self.disabled_list)
|
|
except Exception as e:
|
|
self.fail(
|
|
"Couldn't disable storage % s" % pool.id)
|
|
else:
|
|
self.debug('No % s wide storage pools found' % other_scope)
|
|
except Exception as e:
|
|
raise e
|
|
|
|
self.debug("Step 1: Deploy VM")
|
|
self.virtual_machine_1 = VirtualMachine.create(
|
|
self.userapiclient,
|
|
self.testdata['small'],
|
|
templateid=self.template.id,
|
|
accountid=self.account.name,
|
|
domainid=self.account.domainid,
|
|
serviceofferingid=self.service_offering.id,
|
|
zoneid=self.zone.id)
|
|
verify_vm_state(self, self.virtual_machine_1.id, 'Running')
|
|
|
|
# Step 2: Add storage to Maintenance mode
|
|
self.debug("Step 2: Adding storage to maintenance mode ")
|
|
root_volume = Volume.list(
|
|
self.userapiclient,
|
|
virtualmachineid=self.virtual_machine_1.id,
|
|
type='ROOT')[0]
|
|
list_volume = Volume.list(self.userapiclient, id=root_volume.id)
|
|
storage_id = list_volume[0].storageid
|
|
try:
|
|
StoragePool.enableMaintenance(self.userapiclient, id=storage_id)
|
|
self.debug('Step 2: Added % s to Maintenance mode')
|
|
self.maint_list.append(storage_id)
|
|
except Exception as e:
|
|
self.fail(
|
|
'Step 2: Failed to add Storage pool % s to Maintenance mode' %
|
|
storage_id)
|
|
verify_vm_state(self, self.virtual_machine_1.id, 'Stopped')
|
|
|
|
# Step 3: Cancel maintenance mode
|
|
try:
|
|
StoragePool.cancelMaintenance(self.userapiclient, id=storage_id)
|
|
self.debug(
|
|
'Step 3: Cancelled Maintenance mode for % s' %
|
|
storage_id)
|
|
self.maint_list.remove(storage_id)
|
|
except Exception as e:
|
|
self.fail(
|
|
"Step 3: Couldn't cancel Maintenance mode for storage % s " %
|
|
storage_id)
|
|
|
|
# Step 4: Start the VM after disabling pool and verify it's running
|
|
# from same pool
|
|
try:
|
|
self.debug("Step 4: Starting VM after disabling pool")
|
|
self.list_storage = StoragePool.list(
|
|
self.userapiclient, id=storage_id)
|
|
if self.list_storage[0].state == 'Up':
|
|
StoragePool.update(
|
|
self.userapiclient,
|
|
id=storage_id,
|
|
enabled=False)
|
|
self.debug("Step 4: Disabled pool % s" % storage_id)
|
|
self.disabled_list.append(storage_id)
|
|
except Exception as e:
|
|
raise e
|
|
|
|
list_vm = list_virtual_machines(
|
|
self.userapiclient,
|
|
account=self.account.name,
|
|
domainid=self.account.domainid,
|
|
id=self.virtual_machine_1.id)
|
|
vm = list_vm[0]
|
|
if vm.state != 'Running':
|
|
self.virtual_machine_1.start(self.userapiclient)
|
|
verify_vm_state(self, self.virtual_machine_1.id, 'Running')
|
|
verify_vm_storage_pool(self, self.virtual_machine_1.id, storage_id)
|
|
|
|
# Step 5: Perform some VM operations - reboot
|
|
self.debug(
|
|
"Step 5: Performing reboot of VM % s" %
|
|
self.virtual_machine_1.id)
|
|
self.virtual_machine_1.reboot(self.userapiclient)
|
|
verify_vm_storage_pool(self, self.virtual_machine_1.id, storage_id)
|
|
|
|
# Step 6: Add tags to the storage pool
|
|
self.debug("Step 6: Adding tags to storage pool")
|
|
StoragePool.update(
|
|
self.userapiclient,
|
|
id=storage_id,
|
|
tags='disable_prov')
|
|
|
|
# Step 7: Add tagged service offering
|
|
self.testdata['service_offerings']['tiny']['tags'] = 'disable_prov'
|
|
self.testdata["service_offerings"]["tiny"]["storagetype"] = 'local'
|
|
self.tagged_so = ServiceOffering.create(
|
|
self.userapiclient, self.testdata['service_offerings'])
|
|
self.testdata['service_offerings']['tiny']['tags'] = ' '
|
|
self.testdata["service_offerings"]["tiny"]["storagetype"] = ' '
|
|
self.cleanup.append(self.tagged_so)
|
|
|
|
# Step 8: Enable the pool
|
|
try:
|
|
self.debug("Step 8: Enabling pool")
|
|
self.list_storage = StoragePool.list(
|
|
self.userapiclient, id=storage_id)
|
|
if self.list_storage[0].state == 'Disabled':
|
|
StoragePool.update(
|
|
self.userapiclient,
|
|
id=storage_id,
|
|
enabled=True)
|
|
self.disabled_list.remove(storage_id)
|
|
except Exception as e:
|
|
raise e
|
|
|
|
# Step 9: Deploy VM using the tagged offering
|
|
self.debug("Step 9: Deploying VM using tagged offering")
|
|
self.virtual_machine_2 = VirtualMachine.create(
|
|
self.userapiclient,
|
|
self.testdata['small'],
|
|
templateid=self.template.id,
|
|
accountid=self.account.name,
|
|
domainid=self.account.domainid,
|
|
serviceofferingid=self.tagged_so.id,
|
|
zoneid=self.zone.id)
|
|
verify_vm_state(self, self.virtual_machine_2.id, 'Running')
|
|
verify_vm_storage_pool(self, self.virtual_machine_2.id, storage_id)
|
|
|
|
# Step 10: Disable storage Pool
|
|
try:
|
|
self.list_storage = StoragePool.list(
|
|
self.userapiclient, id=storage_id)
|
|
if self.list_storage[0].state == 'Up':
|
|
StoragePool.update(
|
|
self.userapiclient,
|
|
id=storage_id,
|
|
enabled=False)
|
|
if storage_id not in self.disabled_list:
|
|
self.disabled_list.append(storage_id)
|
|
except Exception as e:
|
|
raise e
|
|
|
|
if value != 'host':
|
|
capacity_type = 2
|
|
else:
|
|
capacity_type = 9
|
|
|
|
# Step 11: View current capacity of storage pool
|
|
self.debug("Step 11: Getting current capacity...")
|
|
list_capacity_allocated = Capacities.list(
|
|
self.userapiclient, fetchlatest='true', type=capacity_type)
|
|
capacity_1 = list_capacity_allocated[0].capacityused
|
|
self.debug("Capacity 1: % s" % capacity_1)
|
|
|
|
# Step 12: Delete VM and check capacity is recalculated in disabled
|
|
# pool
|
|
self.debug("Step 12: Deleting Vm and re-calculating capacity")
|
|
self.virtual_machine_2.delete(self.userapiclient)
|
|
list_capacity_allocated = Capacities.list(
|
|
self.userapiclient, fetchlatest='true', type=capacity_type)
|
|
capacity_2 = list_capacity_allocated[0].capacityused
|
|
self.debug("Capacity 2: % s" % capacity_2)
|
|
self.assertGreater(
|
|
capacity_1,
|
|
capacity_2,
|
|
'Step 12: Capacity Used should be greater after VM delete although Storage is not enabled')
|
|
|
|
# Step 13: Deploy new VM with tagged offering again - should fail
|
|
with self.assertRaises(Exception):
|
|
self.virtual_machine_3 = VirtualMachine.create(
|
|
self.userapiclient,
|
|
self.testdata['small'],
|
|
templateid=self.template.id,
|
|
accountid=self.account.name,
|
|
domainid=self.account.domainid,
|
|
serviceofferingid=self.tagged_so.id,
|
|
zoneid=self.zone.id)
|
|
|
|
# Step 14: Capacity should not be altered in disabled pool since deploy
|
|
# VM failed
|
|
self.debug(
|
|
"Step 14: Checking capacity is not altered after deploy VM fails")
|
|
list_capacity_allocated = Capacities.list(
|
|
self.userapiclient, fetchlatest='true', type=capacity_type)
|
|
capacity_3 = list_capacity_allocated[0].capacityused
|
|
self.assertEqual(
|
|
capacity_2,
|
|
capacity_3,
|
|
"Step 14: Capacity Used shouldn't be altered since VM deployment failed")
|
|
|
|
|
|
class TestPathDisableStorage_Cross_Cluster(cloudstackTestCase):
|
|
"""
|
|
# Tests in this path requires to be run independently (not to be run in parallel with any other tests \
|
|
since it involves disabling/enabling storage pools and may cause unexpected failures in other tests
|
|
# This test at least 2 Clusters in the set up with suitable hosts for migration.
|
|
# For running the tests on local storage, ensure there are 2 local storage pools set up on each host
|
|
|
|
"""
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
testClient = super(
|
|
TestPathDisableStorage_Cross_Cluster,
|
|
cls).getClsTestClient()
|
|
cls.apiclient = testClient.getApiClient()
|
|
cls.testdata = testClient.getParsedTestDataConfig()
|
|
cls.domain = get_domain(cls.apiclient)
|
|
cls.zone = get_zone(cls.apiclient)
|
|
cls.testdata['mode'] = cls.zone.networktype
|
|
cls.template = get_template(
|
|
cls.apiclient,
|
|
cls.zone.id,
|
|
cls.testdata['ostype'])
|
|
cls.testdata['template']['ostypeid'] = cls.template.ostypeid
|
|
if cls.template == FAILED:
|
|
cls.fail(
|
|
'get_template() failed to return template with description %s' %
|
|
cls.testdata['ostype'])
|
|
|
|
cls._cleanup = []
|
|
cls.disabled_list = []
|
|
cls.maint_list = []
|
|
cls.testdata['template_2']['zoneid'] = cls.zone.id
|
|
cls.testdata['template_2']['ostypeid'] = cls.template.ostypeid
|
|
cls.hypervisor = testClient.getHypervisorInfo()
|
|
|
|
try:
|
|
cls.account = Account.create(
|
|
cls.apiclient, cls.testdata['account'], admin=True)
|
|
cls.debug('Creating account')
|
|
cls._cleanup.append(cls.account)
|
|
cls.service_offering = ServiceOffering.create(
|
|
cls.apiclient, cls.testdata['service_offering'])
|
|
cls._cleanup.append(cls.service_offering)
|
|
cls.disk_offering = DiskOffering.create(
|
|
cls.apiclient, cls.testdata['disk_offering'])
|
|
cls.resized_disk_offering = DiskOffering.create(
|
|
cls.apiclient, cls.testdata['resized_disk_offering'])
|
|
cls._cleanup.append(cls.disk_offering)
|
|
|
|
cls.userapiclient = testClient.getUserApiClient(
|
|
UserName=cls.account.name, DomainName=cls.account.domain)
|
|
response = User.login(cls.userapiclient,
|
|
username=cls.account.name,
|
|
password=cls.testdata['account']['password'])
|
|
assert response.sessionkey is not None
|
|
except Exception as e:
|
|
cls.tearDownClass()
|
|
raise e
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
try:
|
|
cleanup_resources(cls.apiclient, cls._cleanup)
|
|
except Exception as e:
|
|
raise Exception('Warning:Exception during cleanup: %s' % e)
|
|
|
|
def setUp(self):
|
|
self.apiclient = self.testClient.getApiClient()
|
|
self.cleanup = []
|
|
|
|
def tearDown(self):
|
|
if self.disabled_list:
|
|
for poolid in self.disabled_list:
|
|
if StoragePool.list(self.userapiclient, id=poolid)[
|
|
0].state == 'Disabled':
|
|
try:
|
|
StoragePool.update(
|
|
self.userapiclient, id=poolid, enabled=True)
|
|
self.debug('Enabling: % s ' % poolid)
|
|
except Exception as e:
|
|
self.fail("Couldn't enable storage % s" % id)
|
|
try:
|
|
cleanup_resources(self.apiclient, self.cleanup)
|
|
except Exception as e:
|
|
self.fail('Warning: Exception during cleanup : %s' % e)
|
|
|
|
@attr(tags=['advanced', 'advancedsg', 'basic'], required_hardware='false')
|
|
def test_01_cross_cluster_attach_disk(self):
|
|
"""
|
|
Test Steps:
|
|
========
|
|
|
|
1. Deploy VM in one cluster
|
|
2. Migrate to other cluster
|
|
3. Add data disk, Attach to VM
|
|
4. Disable first storage pool
|
|
5. List for migration should not list the first pool anymore
|
|
6. Stop VM and detach disk
|
|
7. Enable first Pool
|
|
8. Migrate root to first pool
|
|
9. Now disable first pool again
|
|
10. Attach the disk which is running from enabled pool - Should fail
|
|
11.Enable pool again
|
|
12. Attach disk should now pass
|
|
|
|
"""
|
|
if self.hypervisor.lower() == 'lxc':
|
|
self.skipTest("Not running rest of tests in lxc")
|
|
|
|
cluster_id_list = []
|
|
clusters = list_clusters(self.userapiclient, listall='true')
|
|
if len(clusters) == 1:
|
|
raise unittest.SkipTest('Found only one cluster... skipping test')
|
|
for cluster in clusters:
|
|
try:
|
|
self.debug('Processing for cluster % s ' % cluster.id)
|
|
self.list_storage = StoragePool.list(
|
|
self.userapiclient, clusterid=cluster.id, scope='CLUSTER')
|
|
count_st_pools = len(self.list_storage)
|
|
if count_st_pools > 1:
|
|
self.debug(
|
|
'Found % s storage pools in cluster % s, keeping one and disabling rest' %
|
|
(count_st_pools, cluster.id))
|
|
for pool in self.list_storage[1:]:
|
|
self.disabled_pool_1 = self.list_storage[1]
|
|
if pool.state == 'Up':
|
|
self.debug(
|
|
'Trying to disable storage %s' %
|
|
pool.id)
|
|
try:
|
|
StoragePool.update(
|
|
self.userapiclient, id=pool.id, enabled=False)
|
|
self.disabled_list.append(pool.id)
|
|
self.debug(
|
|
'Appended to list of disabled pools. List is now: % s ' %
|
|
self.disabled_list)
|
|
except Exception as e:
|
|
raise e
|
|
elif count_st_pools == 1:
|
|
self.debug('Only one cluster wide storage found')
|
|
else:
|
|
self.fail('No cluster wide storage pools found')
|
|
except Exception as e:
|
|
raise e
|
|
|
|
try:
|
|
self.list_storage = StoragePool.list(
|
|
self.userapiclient, scope='ZONE')
|
|
if self.list_storage:
|
|
for pool in self.list_storage:
|
|
if pool.state == 'Up':
|
|
self.debug('Trying to disable storage % s' % pool.id)
|
|
try:
|
|
StoragePool.update(
|
|
self.userapiclient, id=pool.id, enabled=False)
|
|
self.disabled_list.append(pool.id)
|
|
self.debug(
|
|
'Appended to list of disabled pools. List is now: % s ' %
|
|
self.disabled_list)
|
|
except Exception as e:
|
|
self.fail("Couldn't disable storage % s" % pool.id)
|
|
else:
|
|
self.debug('No zone wide storage pools found')
|
|
except Exception as e:
|
|
raise e
|
|
|
|
# Step 1: Deploy VM in a cluster
|
|
self.virtual_machine_1 = VirtualMachine.create(
|
|
self.userapiclient,
|
|
self.testdata['small'],
|
|
templateid=self.template.id,
|
|
accountid=self.account.name,
|
|
domainid=self.account.domainid,
|
|
serviceofferingid=self.service_offering.id,
|
|
zoneid=self.zone.id)
|
|
verify_vm_state(self, self.virtual_machine_1.id, 'Running')
|
|
|
|
root_vol = Volume.list(
|
|
self.userapiclient,
|
|
virtualmachineid=self.virtual_machine_1.id,
|
|
type='ROOT')[0]
|
|
storage_1 = root_vol.storageid
|
|
host_1 = self.virtual_machine_1.hostid
|
|
self.debug(
|
|
"Step 1: VM1 is running on % s host and % s storage pool" %
|
|
(host_1, storage_1))
|
|
|
|
# Step 2: Live Migrate VM to another cluster
|
|
hosts_for_migration = Host.listForMigration(
|
|
self.userapiclient, virtualmachineid=self.virtual_machine_1.id)
|
|
self.debug(
|
|
'Step 2: List of hosts suitable for migration: % s ' %
|
|
hosts_for_migration)
|
|
host_2 = None
|
|
for host in hosts_for_migration:
|
|
self.debug(
|
|
'Step 2: Host Requires storage motion is % s ' %
|
|
host.requiresStorageMotion)
|
|
if host.requiresStorageMotion:
|
|
host_2 = host.id
|
|
|
|
if host_2:
|
|
self.debug(
|
|
'Step 2: Migrating VM % s to Host % s' %
|
|
(self.virtual_machine_1.id, host_2))
|
|
self.virtual_machine_1.migrate_vm_with_volume(
|
|
self.userapiclient, hostid=host_2)
|
|
else:
|
|
self.fail('Step 2: No host found suitable for migration')
|
|
|
|
# Step 3: Add data disk and attach to VM
|
|
self.volume_1 = Volume.create(self.userapiclient,
|
|
services=self.testdata['volume'],
|
|
diskofferingid=self.disk_offering.id,
|
|
zoneid=self.zone.id)
|
|
self.virtual_machine_1.attach_volume(self.userapiclient, self.volume_1)
|
|
list_volume = Volume.list(self.userapiclient, id=self.volume_1.id)
|
|
|
|
self.assertEqual(
|
|
list_volume[0].virtualmachineid,
|
|
self.virtual_machine_1.id,
|
|
'Step 3: Check if volume state (attached) is reflected')
|
|
self.debug(
|
|
'Step 3: volume id:% s successfully attached to vm id % s' %
|
|
(self.volume_1.id, self.virtual_machine_1.id))
|
|
|
|
root_vol = Volume.list(
|
|
self.userapiclient,
|
|
virtualmachineid=self.virtual_machine_1.id,
|
|
type='ROOT')[0]
|
|
storage_2 = root_vol.storageid
|
|
data_vol = Volume.list(
|
|
self.userapiclient,
|
|
virtualmachineid=self.virtual_machine_1.id,
|
|
type='DATA')[0]
|
|
self.debug(
|
|
"Step 3: Data Volume is in storage pool: % s" %
|
|
data_vol.storageid)
|
|
self.assertEqual(
|
|
data_vol.storageid,
|
|
root_vol.storageid,
|
|
"Step 3: Root and Data disk should be running from 2nd storage pool where the VM was live migrated")
|
|
|
|
# Step 4: Disable first Storage Pool and verify it is not listed in
|
|
# hosts suitable for migration
|
|
try:
|
|
StoragePool.update(self.userapiclient, id=storage_1, enabled=False)
|
|
self.disabled_list.append(storage_1)
|
|
self.debug(
|
|
'Step 4: Appended to list of disabled pools. List is now: % s ' %
|
|
self.disabled_list)
|
|
except Exception as e:
|
|
self.fail("Step 4: Couldn't disable storage % s" % storage_1)
|
|
|
|
# Step 5: Disabled pool shouldn't be listed in hostsforMigration since
|
|
# all pools in the cluster are disabled
|
|
hosts_for_migration = Host.listForMigration(
|
|
self.userapiclient, virtualmachineid=self.virtual_machine_1.id)
|
|
self.debug(
|
|
"Step 5: List of Hosts For Migration is % s" %
|
|
hosts_for_migration)
|
|
if hosts_for_migration:
|
|
for host in hosts_for_migration:
|
|
if host_1 == host.id:
|
|
self.fail(
|
|
"Step 5: All pools in the cluster are disabled, hence host should not be listed for migration")
|
|
|
|
# Step 6: Stop VM and Detach Disk
|
|
self.virtual_machine_1.stop(self.userapiclient)
|
|
verify_vm_state(self, self.virtual_machine_1.id, 'Stopped')
|
|
verify_vm_storage_pool(self, self.virtual_machine_1.id, storage_2)
|
|
self.debug("Step 6: Stopping VM and detaching disk")
|
|
self.virtual_machine_1.detach_volume(
|
|
self.userapiclient, volume=self.volume_1)
|
|
|
|
# Step 7, 8: Enable Pool for Migrating VM and disable again
|
|
try:
|
|
StoragePool.update(self.userapiclient, id=storage_1, enabled=True)
|
|
if storage_1 in self.disabled_list:
|
|
self.disabled_list.remove(storage_1)
|
|
except Exception as e:
|
|
self.fail("Step 7: Couldn't enable storage % s" % storage_1)
|
|
|
|
self.virtual_machine_1.start(self.userapiclient)
|
|
verify_vm_state(self, self.virtual_machine_1.id, 'Running')
|
|
|
|
try:
|
|
self.debug(
|
|
'Step 8: Migrating VM % s to Host % s' %
|
|
(self.virtual_machine_1.id, host_1))
|
|
self.virtual_machine_1.migrate_vm_with_volume(
|
|
self.userapiclient, hostid=host_1)
|
|
except Exception as e:
|
|
self.fail(
|
|
"Step 8: Couldn't live migrate VM to host % s due to % s" %
|
|
(host_1, e))
|
|
|
|
# Step 9: disable pool again
|
|
try:
|
|
StoragePool.update(self.userapiclient, id=storage_1, enabled=False)
|
|
self.debug("Step 9: Disabling storage pool: % s " % storage_1)
|
|
self.disabled_list.append(storage_1)
|
|
except Exception as e:
|
|
self.fail("Step 9: Couldn't disable storage % s" % storage_1)
|
|
|
|
st_list = StoragePool.list(self.userapiclient, id=storage_1)
|
|
self.debug(
|
|
"9.5 Status of storage pool 1 % s is % s " %
|
|
(st_list[0].name, st_list[0].state))
|
|
|
|
# Step 10: Try to attach data disk running from enabled pool with Root
|
|
# running in disabled pool - this should fail
|
|
with self.assertRaises(Exception):
|
|
self.virtual_machine_1.attach_volume(
|
|
self.userapiclient, self.volume_1)
|
|
self.debug(
|
|
"Step 10: Trying to attach volume % s" %
|
|
self.volume_1.id)
|
|
|
|
# Step 11: Enable the pool and try to attach again - this should pass
|
|
try:
|
|
StoragePool.update(self.userapiclient, id=storage_1, enabled=True)
|
|
self.debug("Step 11: Enable storage pool: % s " % storage_1)
|
|
self.disabled_list.remove(storage_1)
|
|
except Exception as e:
|
|
self.fail("Step 11: Couldn't enable storage % s" % storage_1)
|
|
|
|
# Step 12: Repeat attach volume - should succeed
|
|
self.virtual_machine_1.attach_volume(self.userapiclient, self.volume_1)
|
|
self.debug("Step 12: Trying to attach volume")
|
|
list_volume = Volume.list(self.userapiclient, id=self.volume_1.id)
|
|
|
|
self.assertEqual(
|
|
list_volume[0].virtualmachineid,
|
|
self.virtual_machine_1.id,
|
|
'Step 12: Check if volume state (attached) is reflected')
|
|
self.debug(
|
|
'Step 12: volume id:%s successfully attached to vm id%s' %
|
|
(self.volume_1.id, self.virtual_machine_1.id))
|