# 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 domain 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 Local Modules from nose.plugins.attrib import attr from marvin.cloudstackTestCase import cloudstackTestCase import unittest from marvin.lib.base import (Account, ServiceOffering, VirtualMachine, Resources, Domain, Volume, DiskOffering, Snapshot) from marvin.lib.common import (get_domain, get_zone, get_template, createSnapshotFromVirtualMachineVolume, isVmExpunged, isDomainResourceCountEqualToExpectedCount, find_storage_pool_type) from marvin.lib.utils import (cleanup_resources) from marvin.codes import (PASS, FAIL, FAILED, RESOURCE_PRIMARY_STORAGE) class TestMultipleChildDomain(cloudstackTestCase): @classmethod def setUpClass(cls): cloudstackTestClient = super(TestMultipleChildDomain, 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.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 cls._cleanup = [] 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(TestMultipleChildDomain, cls).tearDownClass() def setUp(self): self.apiclient = self.testClient.getApiClient() self.dbclient = self.testClient.getDbConnection() self.cleanup = [] self.services["disk_offering"]["disksize"] = 5 try: 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 while creating disk offering: %s" % e) return def tearDown(self): super(TestMultipleChildDomain, self).tearDown() def updateDomainResourceLimits(self, parentdomainlimit, subdomainlimit): """Update primary storage limits of the parent domain and its child domains""" try: # Update resource limit for domain Resources.updateLimit(self.apiclient, resourcetype=10, max=parentdomainlimit, domainid=self.parent_domain.id) # Update Resource limit for sub-domains Resources.updateLimit(self.apiclient, resourcetype=10, max=subdomainlimit, domainid=self.cadmin_1.domainid) Resources.updateLimit(self.apiclient, resourcetype=10, max=subdomainlimit, domainid=self.cadmin_2.domainid) except Exception as e: return [FAIL, e] return [PASS, None] def setupAccounts(self): try: self.parent_domain = Domain.create( self.apiclient, services=self.services["domain"], parentdomainid=self.domain.id) self.cleanup.append(self.parent_domain) self.parentd_admin = Account.create( self.apiclient, self.services["account"], admin=True, domainid=self.parent_domain.id) self.cleanup.append(self.parentd_admin) # Create sub-domains and their admin accounts self.cdomain_1 = Domain.create( self.apiclient, services=self.services["domain"], parentdomainid=self.parent_domain.id) self.cleanup.append(self.cdomain_1) self.cdomain_2 = Domain.create( self.apiclient, services=self.services["domain"], parentdomainid=self.parent_domain.id) self.cleanup.append(self.cdomain_2) self.cadmin_1 = Account.create( self.apiclient, self.services["account"], admin=True, domainid=self.cdomain_1.id) self.cleanup.append(self.cadmin_1) self.cadmin_2 = Account.create( self.apiclient, self.services["account"], admin=True, domainid=self.cdomain_2.id) self.cleanup.append(self.cadmin_2) users = { self.cdomain_1: self.cadmin_1, self.cdomain_2: self.cadmin_2 } except Exception as e: return [FAIL, e, None] return [PASS, None, users] @attr(tags=["advanced", "selfservice"], required_hardware="false") def test_01_multiple_domains_primary_storage_limits(self): """Test primary storage limit of domain and its sub-domains # Steps 1. Create a parent domain and two sub-domains in it (also admin accounts of each domain) 2. Update primary storage limits of the parent domain and child domains 3. Deploy VM in child domain 1 so that total primary storage is less than the limit of child domain 4. Repeat step 3 for child domain 2 5. Try to deploy VM in parent domain now so that the total primary storage in parent domain (including that in sub-domains is more than the primary storage limit of the parent domain 6. Delete the admin account of child domain 1 and check resource count of the parent domain 7. Delete VM deployed in account 2 and check primary storage count of parent domain # Validations: 1. Step 3 and 4 should succeed 2. Step 5 should fail as the resource limit exceeds in parent domain 3. After step 6, resource count in parent domain should decrease by equivalent quantity 4. After step 7, resource count in parent domain should be 0""" result = self.setupAccounts() self.assertEqual( result[0], PASS, "Failure while setting up accounts and domains: %s" % result[1]) templatesize = (self.template.size / (1024 ** 3)) disksize = 10 subdomainlimit = (templatesize + disksize) maxlimit = subdomainlimit * 3 - 1 result = self.updateDomainResourceLimits( int(maxlimit), int(subdomainlimit)) self.assertEqual( result[0], PASS, "Failure while updating resource limits: %s" % result[1]) try: self.services["disk_offering"]["disksize"] = disksize disk_offering_custom = DiskOffering.create( self.apiclient, services=self.services["disk_offering"]) self.cleanup.append(disk_offering_custom) except Exception as e: self.fail("Failed to create disk offering") # Get API clients of parent and child domain admin accounts api_client_admin = self.testClient.getUserApiClient( UserName=self.parentd_admin.name, DomainName=self.parentd_admin.domain) self.assertNotEqual( api_client_admin, FAILED, "Failed to create api client for account: %s" % self.parentd_admin.name) api_client_cadmin_1 = self.testClient.getUserApiClient( UserName=self.cadmin_1.name, DomainName=self.cadmin_1.domain) self.assertNotEqual( api_client_cadmin_1, FAILED, "Failed to create api client for account: %s" % self.cadmin_1.name) api_client_cadmin_2 = self.testClient.getUserApiClient( UserName=self.cadmin_2.name, DomainName=self.cadmin_2.domain) self.assertNotEqual( api_client_cadmin_2, FAILED, "Failed to create api client for account: %s" % self.cadmin_2.name) vm_1 = VirtualMachine.create( api_client_cadmin_1, self.services["virtual_machine"], accountid=self.cadmin_1.name, domainid=self.cadmin_1.domainid, diskofferingid=disk_offering_custom.id, serviceofferingid=self.service_offering.id) self.cleanup.append(vm_1) self.initialResourceCount = (templatesize + disksize) result = isDomainResourceCountEqualToExpectedCount( self.apiclient, self.parent_domain.id, self.initialResourceCount, RESOURCE_PRIMARY_STORAGE) self.assertFalse(result[0], result[1]) self.assertTrue(result[2], "Resource count does not match") # Create VM in second child domain vm_2 = VirtualMachine.create( api_client_cadmin_2, self.services["virtual_machine"], accountid=self.cadmin_2.name, domainid=self.cadmin_2.domainid, diskofferingid=disk_offering_custom.id, serviceofferingid=self.service_offering.id) self.cleanup.append(vm_2) # Now the VMs in two child domains have exhausted the primary storage limit # of parent domain, hence VM creation in parent domain with custom disk offering # should fail with self.assertRaises(Exception): vm_faulty = VirtualMachine.create( api_client_admin, self.services["virtual_machine"], accountid=self.parentd_admin.name, domainid=self.parentd_admin.domainid, diskofferingid=disk_offering_custom.id, serviceofferingid=self.service_offering.id) self.cleanup.append(vm_faulty) # should not happen # Deleting user account and remove it's resources from the cleanup list self.cadmin_1.delete(self.apiclient) self.cleanup.remove(self.cadmin_1) self.cleanup.remove(vm_1) expectedCount = self.initialResourceCount result = isDomainResourceCountEqualToExpectedCount( self.apiclient, self.parent_domain.id, expectedCount, RESOURCE_PRIMARY_STORAGE) self.assertFalse(result[0], result[1]) self.assertTrue(result[2], "Resource count does not match") try: vm_2.delete(self.apiclient) self.cleanup.remove(vm_2) except Exception as e: self.fail("Failed to delete instance: %s" % e) self.assertTrue(isVmExpunged(self.apiclient, vm_2.id), "VM not expunged \ in allotted time") expectedCount -= templatesize result = isDomainResourceCountEqualToExpectedCount( self.apiclient, self.parent_domain.id, expectedCount, RESOURCE_PRIMARY_STORAGE) self.assertFalse(result[0], result[1]) self.assertTrue(result[2], "Resource count does not match") return @attr(tags=["advanced"], required_hardware="false") def test_02_multiple_domains_primary_storage_limits(self): """Test primary storage counts in multiple child domains # Steps 1. Create a parent domain and two sub-domains in it (also admin accounts of each domain) Repeat following steps for both the child domains 2. Deploy VM in child domain 3. Check if the resource count for domain is updated correctly 4. Create a volume and attach it to the VM 5. Check if the primary storage resource count is updated correctly """ # Setting up account and domain hierarchy result = self.setupAccounts() self.assertEqual( result[0], PASS, "Failure while setting up accounts and domains: %s" % result[1]) users = result[2] templatesize = (self.template.size / (1024 ** 3)) for domain, admin in list(users.items()): self.account = admin self.domain = domain apiclient = self.testClient.getUserApiClient( UserName=self.account.name, DomainName=self.account.domain) self.assertNotEqual( apiclient, FAILED, "Failed to create api client for account: %s" % self.account.name) try: vm = VirtualMachine.create( apiclient, 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(vm) expectedCount = templatesize + self.disk_offering.disksize result = isDomainResourceCountEqualToExpectedCount( self.apiclient, self.domain.id, expectedCount, RESOURCE_PRIMARY_STORAGE) self.assertFalse(result[0], result[1]) self.assertTrue(result[2], "Resource count does not match") # Creating service offering with 10 GB volume 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 = 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.cleanup.append(volume) # we get an exception in the next few lines volumeSize = (volume.size / (1024 ** 3)) expectedCount += volumeSize vm.attach_volume(apiclient, volume=volume) self.cleanup.remove(volume) # we can't cleanup an attached volume result = isDomainResourceCountEqualToExpectedCount( self.apiclient, self.domain.id, expectedCount, RESOURCE_PRIMARY_STORAGE) self.assertFalse(result[0], result[1]) self.assertTrue(result[2], "Resource count does not match") except Exception as e: self.fail("Failure: %s" % e) return @attr(tags=["advanced"], required_hardware="false") def test_03_multiple_domains_multiple_volumes(self): """Test primary storage counts in multiple child domains # Steps 1. Create a parent domain and two sub-domains in it (also admin accounts of each domain) Repeat following steps for both the child domains 2. Deploy VM in child domain 3. Check if the resource count for domain is updated correctly 4. Create multiple volumes and attach it to the VM 5. Check if the primary storage resource count is updated correctly 6. Delete one of the volumes and check if the primary storage resource count reduced by equivalent number 7. Detach other volume and check primary storage resource count remains the same """ # Setting up account and domain hierarchy if self.hypervisor.lower() == 'lxc': if not find_storage_pool_type(self.apiclient, storagetype='rbd'): self.skipTest("RBD storage type is required for data volumes for LXC") result = self.setupAccounts() if result[0] == FAIL: self.fail( "Failure while setting up accounts and domains: %s" % result[1]) else: users = result[2] templatesize = (self.template.size / (1024 ** 3)) for domain, admin in list(users.items()): self.account = admin self.domain = domain apiclient = self.testClient.getUserApiClient( UserName=self.account.name, DomainName=self.account.domain) self.assertNotEqual( apiclient, FAILED, "Failed to create api client for account: %s" % self.account.name) try: vm = VirtualMachine.create( apiclient, 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(vm) expectedCount = templatesize + self.disk_offering.disksize result = isDomainResourceCountEqualToExpectedCount( self.apiclient, self.domain.id, expectedCount, RESOURCE_PRIMARY_STORAGE) self.assertFalse(result[0], result[1]) self.assertTrue(result[2], "Resource count does not match") volume1size = self.services["disk_offering"]["disksize"] = 15 disk_offering_15_GB = DiskOffering.create( self.apiclient, services=self.services["disk_offering"]) self.cleanup.append(disk_offering_15_GB) volume2size = self.services["disk_offering"]["disksize"] = 20 disk_offering_20_GB = DiskOffering.create( self.apiclient, services=self.services["disk_offering"]) self.cleanup.append(disk_offering_20_GB) volume_1 = Volume.create( apiclient, self.services["volume"], zoneid=self.zone.id, account=self.account.name, domainid=self.account.domainid, diskofferingid=disk_offering_15_GB.id) self.cleanup.append(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_20_GB.id) self.cleanup.append(volume_2) vm.attach_volume(apiclient, volume=volume_1) self.cleanup.remove(volume_1) vm.attach_volume(apiclient, volume=volume_2) self.cleanup.remove(volume_2) expectedCount += volume1size + volume2size result = isDomainResourceCountEqualToExpectedCount( self.apiclient, self.domain.id, expectedCount, RESOURCE_PRIMARY_STORAGE) self.assertFalse(result[0], result[1]) self.assertTrue(result[2], "Resource count does not match") vm.detach_volume(apiclient, volume=volume_1) volume_1.delete(apiclient) expectedCount -= volume1size result = isDomainResourceCountEqualToExpectedCount( self.apiclient, self.domain.id, expectedCount, RESOURCE_PRIMARY_STORAGE) self.assertFalse(result[0], result[1]) self.assertTrue(result[2], "Resource count does not match") except Exception as e: self.fail("Failure: %s" % e) return # @attr(tags=["advanced"], required_hardware="true") @attr(tags=["TODO"], required_hardware="true") def test_04_create_template_snapshot(self): """Test create snapshot and templates from volume # Validate the following 1. Create parent domain with two child sub-domains (and their admin accounts) Follow these steps for both the domains # 1. Create template from snapshot and verify secondary storage resource count # 2. Create Volume from Snapshot and verify primary storage resource count # 3. Attach volume to instance which was created from snapshot and # verify primary storage resource count # 4. Detach volume from instance which was created from snapshot and # verify the primary storage resource count # 5. Delete volume which was created from snapshot and verify primary storage resource count""" if self.hypervisor.lower() in ['hyperv', 'lxc']: self.skipTest("Snapshots feature is not supported on %s" % self.hypervisor.lower()) result = self.setupAccounts() if result[0] == FAIL: self.fail( "Failure while setting up accounts and domains: %s" % result[1]) users = result[2] for domain, admin in list(users.items()): self.account = admin self.domain = domain try: apiclient = self.testClient.getUserApiClient( UserName=self.account.name, DomainName=self.account.domain) self.assertNotEqual( apiclient, FAILED, "Failed to create api client for account: %s" % self.account.name) vm = VirtualMachine.create( apiclient, 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(vm) templatesize = (self.template.size / (1024 ** 3)) initialResourceCount = expectedCount = templatesize + \ self.disk_offering.disksize result = isDomainResourceCountEqualToExpectedCount( self.apiclient, self.domain.id, initialResourceCount, RESOURCE_PRIMARY_STORAGE) self.assertFalse(result[0], result[1]) self.assertTrue(result[2], "Resource count does not match") vm.stop(self.apiclient) response = createSnapshotFromVirtualMachineVolume( apiclient, self.account, vm.id) self.assertEqual(response[0], PASS, response[1]) snapshot = response[1] self.cleanup.append(snapshot) response = snapshot.validateState( apiclient, Snapshot.BACKED_UP) self.assertEqual(response[0], PASS, response[1]) 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.cleanup.append(volume) volumeSize = (volume.size / (1024 ** 3)) vm.attach_volume(apiclient, volume) self.cleanup.remove(volume) expectedCount = initialResourceCount + (volumeSize) result = isDomainResourceCountEqualToExpectedCount( self.apiclient, self.domain.id, expectedCount, RESOURCE_PRIMARY_STORAGE) self.assertFalse(result[0], result[1]) self.assertTrue(result[2], "Resource count does not match") expectedCount -= volumeSize vm.detach_volume(apiclient, volume) volume.delete(apiclient) result = isDomainResourceCountEqualToExpectedCount( self.apiclient, self.domain.id, expectedCount, RESOURCE_PRIMARY_STORAGE) self.assertFalse(result[0], result[1]) self.assertTrue(result[2], "Resource count does not match") except Exception as e: self.fail("Failed with exception : %s" % e) return @attr(tags=["advanced"], required_hardware="false") def test_05_assign_virtual_machine_different_domain(self): """Test assign virtual machine to account belonging to different domain # Steps 1. Create a parent domain and two sub-domains in it (also admin accounts of each domain) 2. Deploy VM in child domain 1 3. Check if the resource count for domain 1 is updated correctly 4. Assign this virtual machine to account 2 in domain 2 5. Verify that primaru storage resource count of domain 1 is now 0 and primary storage resource count of domain 2 is increased by equivalent number """ # Setting up account and domain hierarchy result = self.setupAccounts() self.assertEqual(result[0], PASS, result[1]) apiclient = self.testClient.getUserApiClient( UserName=self.cadmin_1.name, DomainName=self.cadmin_1.domain) self.assertNotEqual( apiclient, FAILED, "Failed to create api client for account: %s" % self.cadmin_1.name) try: vm_1 = VirtualMachine.create( apiclient, self.services["virtual_machine"], accountid=self.cadmin_1.name, domainid=self.cadmin_1.domainid, diskofferingid=self.disk_offering.id, serviceofferingid=self.service_offering.id) self.cleanup.append(vm_1) templatesize = (self.template.size / (1024 ** 3)) expectedCount = templatesize + self.disk_offering.disksize result = isDomainResourceCountEqualToExpectedCount( self.apiclient, self.cadmin_1.domainid, expectedCount, RESOURCE_PRIMARY_STORAGE) self.assertFalse(result[0], result[1]) self.assertTrue(result[2], "Resource count does not match") vm_1.stop(apiclient) vm_1.assign_virtual_machine( self.apiclient, account=self.cadmin_2.name, domainid=self.cadmin_2.domainid) result = isDomainResourceCountEqualToExpectedCount( self.apiclient, self.cadmin_2.domainid, expectedCount, RESOURCE_PRIMARY_STORAGE) self.assertFalse(result[0], result[1]) self.assertTrue(result[2], "Resource count does not match") expectedCount = 0 result = isDomainResourceCountEqualToExpectedCount( self.apiclient, self.cadmin_1.domainid, expectedCount, RESOURCE_PRIMARY_STORAGE) self.assertFalse(result[0], result[1]) self.assertTrue(result[2], "Resource count does not match") except Exception as e: self.fail("Failed with exception: %s" % e) return @attr(tags=["advanced"], required_hardware="false") def test_06_destroy_recover_vm(self): """Test primary storage counts while destroying and recovering VM # Steps 1. Create a parent domain and two sub-domains in it (also admin accounts of each domain) Repeat following steps for both the child domains 2. Deploy VM in child domain 3. Check if the resource count for domain is updated correctly 4. Destroy the VM 5. Verify that the primary storage resource count remains the same 6. Recover the VM 7. Verify that the primary storage resource count remains the same """ # Setting up account and domain hierarchy result = self.setupAccounts() self.assertEqual(result[0], PASS, result[1]) users = result[2] for domain, admin in list(users.items()): self.account = admin self.domain = domain try: vm_1 = VirtualMachine.create( self.apiclient, 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(vm_1) templatesize = (self.template.size / (1024 ** 3)) expectedCount = templatesize + self.disk_offering.disksize result = isDomainResourceCountEqualToExpectedCount( self.apiclient, self.account.domainid, expectedCount, RESOURCE_PRIMARY_STORAGE) self.assertFalse(result[0], result[1]) self.assertTrue(result[2], "Resource count does not match") vm_1.delete(self.apiclient, expunge=False) self.cleanup.remove(vm_1) result = isDomainResourceCountEqualToExpectedCount( self.apiclient, self.account.domainid, expectedCount, RESOURCE_PRIMARY_STORAGE) self.assertFalse(result[0], result[1]) self.assertTrue(result[2], "Resource count does not match") vm_1.recover(self.apiclient) self.cleanup.append(vm_1) result = isDomainResourceCountEqualToExpectedCount( self.apiclient, self.account.domainid, expectedCount, RESOURCE_PRIMARY_STORAGE) self.assertFalse(result[0], result[1]) self.assertTrue(result[2], "Resource count does not match") except Exception as e: self.fail("Failed with exception: %s" % e) return