| # 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 primary storage limits | |
| Test Plan: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Limit+Resources+to+domain+or+accounts | |
| Issue Link: https://issues.apache.org/jira/browse/CLOUDSTACK-1466 | |
| Feature Specifications: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Limit+Resources+to+domains+and+accounts | |
| """ | |
| import unittest | |
| from ddt import ddt, data | |
| from marvin.cloudstackTestCase import cloudstackTestCase | |
| from marvin.codes import ( | |
| PASS, | |
| FAIL, | |
| RESOURCE_PRIMARY_STORAGE, | |
| CHILD_DOMAIN_ADMIN, | |
| ROOT_DOMAIN_ADMIN) | |
| from marvin.lib.base import ( | |
| Account, | |
| ServiceOffering, | |
| VirtualMachine, | |
| Domain, | |
| Volume, | |
| DiskOffering) | |
| from marvin.lib.common import ( | |
| get_domain, | |
| get_zone, | |
| get_template, | |
| matchResourceCount, | |
| createSnapshotFromVirtualMachineVolume, | |
| isVmExpunged, | |
| find_storage_pool_type) | |
| from marvin.lib.utils import (cleanup_resources, | |
| validateList) | |
| # Import Local Modules | |
| from nose.plugins.attrib import attr | |
| @ddt | |
| class TestVolumeLimits(cloudstackTestCase): | |
| @classmethod | |
| def setUpClass(cls): | |
| cloudstackTestClient = super(TestVolumeLimits, | |
| cls).getClsTestClient() | |
| cls.api_client = cloudstackTestClient.getApiClient() | |
| cls.hypervisor = cloudstackTestClient.getHypervisorInfo() | |
| # Fill services from the external config file | |
| cls.services = cloudstackTestClient.getParsedTestDataConfig() | |
| # Get Zone, Domain and templates | |
| cls.domain = get_domain(cls.api_client) | |
| cls.zone = get_zone(cls.api_client, cloudstackTestClient.getZoneForTests()) | |
| cls.services["mode"] = cls.zone.networktype | |
| cls._cleanup = [] | |
| cls.unsupportedStorageType = False | |
| if cls.hypervisor.lower() == 'lxc': | |
| if not find_storage_pool_type(cls.api_client, storagetype='rbd'): | |
| cls.unsupportedStorageType = True | |
| return | |
| cls.template = get_template( | |
| cls.api_client, | |
| cls.zone.id, | |
| cls.services["ostype"] | |
| ) | |
| cls.services["virtual_machine"]["zoneid"] = cls.zone.id | |
| cls.services["virtual_machine"]["template"] = cls.template.id | |
| cls.services["volume"]["zoneid"] = cls.zone.id | |
| try: | |
| cls.service_offering = ServiceOffering.create(cls.api_client, cls.services["service_offering"]) | |
| cls._cleanup.append(cls.service_offering) | |
| except Exception as e: | |
| cls.tearDownClass() | |
| raise unittest.SkipTest("Exception in setUpClass: %s" % e) | |
| return | |
| @classmethod | |
| def tearDownClass(cls): | |
| super(TestVolumeLimits, cls).tearDownClass() | |
| def setUp(self): | |
| if self.unsupportedStorageType: | |
| self.skipTest( | |
| "unsupported storage type") | |
| self.apiclient = self.testClient.getApiClient() | |
| self.dbclient = self.testClient.getDbConnection() | |
| self.cleanup = [] | |
| try: | |
| self.services["disk_offering"]["disksize"] = 2 | |
| self.disk_offering = DiskOffering.create(self.apiclient, self.services["disk_offering"]) | |
| self.cleanup.append(self.disk_offering) | |
| self.assertNotEqual(self.disk_offering, None, \ | |
| "Disk offering is None") | |
| except Exception as e: | |
| self.tearDown() | |
| self.skipTest("Failure in setup: %s" % e) | |
| return | |
| def tearDown(self): | |
| super(TestVolumeLimits, self).tearDown() | |
| def setupAccount(self, accountType): | |
| """Setup the account required for the test""" | |
| try: | |
| if accountType == CHILD_DOMAIN_ADMIN: | |
| self.domain = Domain.create(self.apiclient, | |
| services=self.services["domain"], | |
| parentdomainid=self.domain.id) | |
| self.cleanup.append(self.domain) | |
| self.account = Account.create(self.apiclient, self.services["account"], | |
| domainid=self.domain.id, admin=True) | |
| self.cleanup.append(self.account) | |
| self.virtualMachine = VirtualMachine.create(self.api_client, self.services["virtual_machine"], | |
| accountid=self.account.name, domainid=self.account.domainid, | |
| diskofferingid=self.disk_offering.id, | |
| serviceofferingid=self.service_offering.id, | |
| startvm=False) | |
| self.cleanup.append(self.virtualMachine) | |
| accounts = Account.list(self.apiclient, id=self.account.id) | |
| self.assertEqual(validateList(accounts)[0], PASS, | |
| "accounts list validation failed") | |
| self.initialResourceCount = int(accounts[0].primarystoragetotal) | |
| except Exception as e: | |
| return [FAIL, e] | |
| return [PASS, None] | |
| @data(ROOT_DOMAIN_ADMIN, CHILD_DOMAIN_ADMIN) | |
| @attr(tags=["advanced", "basic"], required_hardware="false") | |
| def test_stop_start_vm(self, value): | |
| """Test Deploy VM with 5 GB volume & verify the usage | |
| # Validate the following | |
| # 1. Create a VM with custom disk offering and check the primary storage count | |
| # 2. Stop VM and verify the resource count remains same | |
| # 3. Start VM and verify resource count remains same""" | |
| response = self.setupAccount(value) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| expectedCount = self.initialResourceCount | |
| # Stopping instance | |
| try: | |
| self.virtualMachine.stop(self.apiclient) | |
| except Exception as e: | |
| self.fail("Failed to stop instance: %s" % e) | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| # Starting instance | |
| try: | |
| self.virtualMachine.start(self.apiclient) | |
| except Exception as e: | |
| self.fail("Failed to start instance: %s" % e) | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| return | |
| @unittest.skip("skip") | |
| @data(ROOT_DOMAIN_ADMIN, CHILD_DOMAIN_ADMIN) | |
| @attr(tags=["advanced", "basic"], required_hardware="false") | |
| def test_destroy_recover_vm(self, value): | |
| """Test delete and recover instance | |
| # Validate the following | |
| # 1. Create a VM with custom disk offering and check the primary storage count | |
| # 2. Destroy VM and verify the resource count remains same | |
| # 3. Recover VM and verify resource count remains same""" | |
| response = self.setupAccount(value) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| expectedCount = self.initialResourceCount | |
| # Stopping instance | |
| try: | |
| self.virtualMachine.delete(self.apiclient, expunge=False) | |
| self.cleanup.remove(self.virtualMachine) | |
| except Exception as e: | |
| self.fail("Failed to destroy instance: %s" % e) | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| # Recovering instance | |
| try: | |
| self.virtualMachine.recover(self.apiclient) | |
| self.cleanup.append(self.virtualMachine) | |
| except Exception as e: | |
| self.fail("Failed to start instance: %s" % e) | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| return | |
| @data(ROOT_DOMAIN_ADMIN, CHILD_DOMAIN_ADMIN) | |
| @attr(tags=["advanced", "basic"], required_hardware="false") | |
| def test_attach_detach_volume(self, value): | |
| """Stop attach and detach volume from VM | |
| # Validate the following | |
| # 1. Create a VM with custom disk offering and check the primary storage count | |
| # of account | |
| # 2. Create custom volume in account | |
| # 3. Verify that primary storage count increases by same amount | |
| # 4. Attach volume to VM and verify resource count remains the same | |
| # 5. Detach volume and verify resource count remains the same""" | |
| response = self.setupAccount(value) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| apiclient = self.apiclient | |
| if value == CHILD_DOMAIN_ADMIN: | |
| apiclient = self.testClient.getUserApiClient( | |
| UserName=self.account.name, | |
| DomainName=self.account.domain | |
| ) | |
| self.assertNotEqual(apiclient, FAIL, "Failure while getting\ | |
| api client of account: %s" % self.account.name) | |
| try: | |
| self.services["disk_offering"]["disksize"] = 4 | |
| expectedCount = self.initialResourceCount + int(self.services["disk_offering"]["disksize"]) | |
| disk_offering = DiskOffering.create(self.apiclient, | |
| services=self.services["disk_offering"]) | |
| self.cleanup.append(disk_offering) | |
| volume = Volume.create( | |
| apiclient, self.services["volume"], zoneid=self.zone.id, | |
| account=self.account.name, domainid=self.account.domainid, | |
| diskofferingid=disk_offering.id) | |
| self.cleanup.append(volume) | |
| except Exception as e: | |
| self.fail("Failure: %s" % e) | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| try: | |
| self.virtualMachine.attach_volume(apiclient, volume=volume) | |
| self.cleanup.remove(volume) | |
| except Exception as e: | |
| self.fail("Failed while attaching volume to VM: %s" % e) | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| try: | |
| self.virtualMachine.detach_volume(apiclient, volume=volume) | |
| self.cleanup.append(volume) | |
| except Exception as e: | |
| self.fail("Failure while detaching volume: %s" % e) | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| return | |
| @data(ROOT_DOMAIN_ADMIN, CHILD_DOMAIN_ADMIN) | |
| @attr(tags=["advanced", "basic"], required_hardware="false") | |
| def test_create_multiple_volumes(self, value): | |
| """Test create multiple volumes | |
| # Validate the following | |
| # 1. Create a VM with custom disk offering and check the primary storage count | |
| # of account | |
| # 2. Create multiple volumes in account | |
| # 3. Verify that primary storage count increases by same amount | |
| # 4. Attach volumes to VM and verify resource count remains the same | |
| # 5. Detach and delete both volumes one by one and verify resource count decreases | |
| # proportionately""" | |
| # Creating service offering with 10 GB volume | |
| response = self.setupAccount(value) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| apiclient = self.apiclient | |
| if value == CHILD_DOMAIN_ADMIN: | |
| apiclient = self.testClient.getUserApiClient( | |
| UserName=self.account.name, | |
| DomainName=self.account.domain | |
| ) | |
| self.assertNotEqual(apiclient, FAIL, "Failure while getting\ | |
| api client of account %s" % self.account.name) | |
| try: | |
| self.services["disk_offering"]["disksize"] = 5 | |
| disk_offering_5_GB = DiskOffering.create(self.apiclient, | |
| services=self.services["disk_offering"]) | |
| self.cleanup.append(disk_offering_5_GB) | |
| self.services["disk_offering"]["disksize"] = 10 | |
| disk_offering_10_GB = DiskOffering.create(self.apiclient, | |
| services=self.services["disk_offering"]) | |
| self.cleanup.append(disk_offering_10_GB) | |
| volume_1 = Volume.create( | |
| apiclient, self.services["volume"], zoneid=self.zone.id, | |
| account=self.account.name, domainid=self.account.domainid, | |
| diskofferingid=disk_offering_5_GB.id) | |
| self.debug("Attaching volume %s to vm %s" % (volume_1.name, self.virtualMachine.name)) | |
| self.virtualMachine.attach_volume(apiclient, volume=volume_1) | |
| volume_2 = Volume.create( | |
| apiclient, self.services["volume"], zoneid=self.zone.id, | |
| account=self.account.name, domainid=self.account.domainid, | |
| diskofferingid=disk_offering_10_GB.id) | |
| self.debug("Attaching volume %s to vm %s" % (volume_2.name, self.virtualMachine.name)) | |
| self.virtualMachine.attach_volume(apiclient, volume=volume_2) | |
| except Exception as e: | |
| self.fail("Failure: %s" % e) | |
| expectedCount = self.initialResourceCount + 15 # (5 + 10) | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| try: | |
| # Detaching and deleting volume 1 | |
| self.virtualMachine.detach_volume(apiclient, volume=volume_1) | |
| volume_1.delete(apiclient) | |
| except Exception as e: | |
| self.fail("Failure while volume operation: %s" % e) | |
| expectedCount -= 5 # After deleting first volume | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| try: | |
| # Detaching and deleting volume 2 | |
| self.virtualMachine.detach_volume(apiclient, volume=volume_2) | |
| volume_2.delete(apiclient) | |
| except Exception as e: | |
| self.fail("Failure while volume operation: %s" % e) | |
| expectedCount -= 10 | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| return | |
| @data(ROOT_DOMAIN_ADMIN, CHILD_DOMAIN_ADMIN) | |
| @attr(tags=["advanced", "basic"], required_hardware="false") | |
| def test_deploy_multiple_vm(self, value): | |
| """Test Deploy multiple VMs with & verify the usage | |
| # Validate the following | |
| # 1. Deploy multiple VMs with this service offering | |
| # 2. Update Resource count for the root admin Primary Storage usage | |
| # 3. Primary Storage usage should list properly | |
| # 4. Destroy one VM among multiple VM's and verify that primary storage count | |
| # decreases by equivalent amount | |
| """ | |
| response = self.setupAccount(value) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| self.virtualMachine_2 = VirtualMachine.create(self.api_client, self.services["virtual_machine"], | |
| accountid=self.account.name, domainid=self.account.domainid, | |
| diskofferingid=self.disk_offering.id, | |
| serviceofferingid=self.service_offering.id) | |
| self.cleanup.append(self.virtualMachine_2) | |
| expectedCount = (self.initialResourceCount * 2) # Total 2 vms | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| self.virtualMachine_3 = VirtualMachine.create(self.api_client, self.services["virtual_machine"], | |
| accountid=self.account.name, domainid=self.account.domainid, | |
| diskofferingid=self.disk_offering.id, | |
| serviceofferingid=self.service_offering.id) | |
| self.cleanup.append(self.virtualMachine_3) | |
| expectedCount = (self.initialResourceCount * 3) # Total 3 vms | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| self.debug("Destroying instance: %s" % self.virtualMachine_2.name) | |
| try: | |
| self.virtualMachine_2.delete(self.apiclient) | |
| self.cleanup.remove(self.virtualMachine_2) | |
| except Exception as e: | |
| self.fail("Failed to delete instance: %s" % e) | |
| self.assertTrue(isVmExpunged(self.apiclient, self.virtualMachine_2.id), "VM not expunged \ | |
| in allotted time") | |
| expectedCount -= (self.template.size / (1024 ** 3)) | |
| response = matchResourceCount( | |
| self.apiclient, int(expectedCount), | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| return | |
| @data(ROOT_DOMAIN_ADMIN, CHILD_DOMAIN_ADMIN) | |
| @attr(tags=["advanced", "basic", "selfservice"]) | |
| def test_assign_vm_different_account(self, value): | |
| """Test assign Vm to different account | |
| # Validate the following | |
| # 1. Deploy VM in account and check the primary storage resource count | |
| # 2. Assign VM to another account | |
| # 3. Resource count for first account should now equal to 0 | |
| # 4. Resource count for the account to which VM is assigned should | |
| # increase to that of initial resource count of first account | |
| """ | |
| response = self.setupAccount(value) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| try: | |
| account_2 = Account.create(self.apiclient, self.services["account"], | |
| domainid=self.domain.id, admin=True) | |
| self.cleanup.append(account_2) | |
| except Exception as e: | |
| self.fail("Failed to create account: %s" % e) | |
| expectedCount = self.initialResourceCount | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| try: | |
| self.virtualMachine.stop(self.apiclient) | |
| self.virtualMachine.assign_virtual_machine(self.apiclient, | |
| account_2.name, account_2.domainid) | |
| self.cleanup.remove(self.virtualMachine) # should now be cleaned with account_2 | |
| self.cleanup.append(self.virtualMachine) # or before to be neat | |
| except Exception as e: | |
| self.fail("Failed to assign virtual machine to account %s: %s" % | |
| (account_2.name, e)) | |
| # Checking resource count for account 2 | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=account_2.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| expectedCount = 0 | |
| # Checking resource count for original account | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| return | |
| @data(ROOT_DOMAIN_ADMIN, CHILD_DOMAIN_ADMIN) | |
| # @attr(tags=["advanced", "basic"], required_hardware="true") | |
| @attr(tags=["TODO"], required_hardware="true") | |
| def test_create_template_snapshot(self, value): | |
| """Test create snapshot and templates from volume | |
| # Validate the following | |
| # 1. Deploy VM with custoom disk offering and check the | |
| # primary storage resource count | |
| # 2. Stop the VM and create Snapshot from VM's volume | |
| # 3. Create volume againt from this snapshto and attach to VM | |
| # 4. Verify that primary storage count increases by the volume size | |
| # 5. Detach and delete volume, verify primary storage count decreaes by volume size""" | |
| if self.hypervisor.lower() in ['hyperv']: | |
| self.skipTest("Snapshots feature is not supported on Hyper-V") | |
| response = self.setupAccount(value) | |
| self.debug(response[0]) | |
| self.debug(response[1]) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| apiclient = self.apiclient | |
| try: | |
| self.virtualMachine.start(apiclient) | |
| except Exception as e: | |
| self.fail("Failed to start instance: %s" % e) | |
| if value == CHILD_DOMAIN_ADMIN: | |
| apiclient = self.testClient.getUserApiClient( | |
| UserName=self.account.name, | |
| DomainName=self.account.domain | |
| ) | |
| self.assertNotEqual(apiclient, FAIL, "Failure while getting api\ | |
| client of account: %s" % self.account.name) | |
| try: | |
| self.virtualMachine.stop(apiclient) | |
| except Exception as e: | |
| self.fail("Failed to stop instance: %s" % e) | |
| expectedCount = self.initialResourceCount | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| self.debug("Creating snapshot from ROOT volume: %s" % self.virtualMachine.name) | |
| snapshot = None | |
| response = createSnapshotFromVirtualMachineVolume(apiclient, self.account, self.virtualMachine.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| snapshot = response[1] | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| try: | |
| self.services["volume"]["size"] = self.services["disk_offering"]["disksize"] | |
| volume = Volume.create_from_snapshot(apiclient, | |
| snapshot_id=snapshot.id, | |
| services=self.services["volume"], | |
| account=self.account.name, | |
| domainid=self.account.domainid) | |
| self.debug("Attaching the volume to vm: %s" % self.virtualMachine.name) | |
| self.virtualMachine.attach_volume(apiclient, volume) | |
| except Exception as e: | |
| self.fail("Failure in volume operation: %s" % e) | |
| expectedCount += int(self.services["volume"]["size"]) | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| try: | |
| self.virtualMachine.detach_volume(apiclient, volume) | |
| self.cleanup.append(volume) | |
| except Exception as e: | |
| self.fail("Failure in detach volume operation: %s" % e) | |
| try: | |
| self.debug("deleting the volume: %s" % volume.name) | |
| volume.delete(apiclient) | |
| self.cleanup.remove(volume) | |
| except Exception as e: | |
| self.fail("Failure while deleting volume: %s" % e) | |
| expectedCount -= int(self.services["volume"]["size"]) | |
| response = matchResourceCount( | |
| self.apiclient, expectedCount, | |
| RESOURCE_PRIMARY_STORAGE, | |
| accountid=self.account.id) | |
| self.assertEqual(response[0], PASS, response[1]) | |
| return |