diff --git a/test/integration/component/test_ss_domain_limits.py b/test/integration/component/test_ss_domain_limits.py new file mode 100644 index 00000000000..998bb8ba360 --- /dev/null +++ b/test/integration/component/test_ss_domain_limits.py @@ -0,0 +1,580 @@ +# 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 secondary 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 +from marvin.lib.base import (Account, + Resources, + Domain, + Template) +from marvin.lib.common import (get_domain, + get_zone, + get_template, + get_builtin_template_info, + list_zones, + isDomainResourceCountEqualToExpectedCount) +from marvin.lib.utils import (cleanup_resources, validateList) +from marvin.codes import (PASS, + FAIL, + RESOURCE_SECONDARY_STORAGE) + +class TestMultipleChildDomain(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cloudstackTestClient = super(TestMultipleChildDomain, + cls).getClsTestClient() + cls.api_client = cloudstackTestClient.getApiClient() + # 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._cleanup = [] + return + + @classmethod + def tearDownClass(cls): + try: + # Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + return + + def tearDown(self): + try: + # Clean up, terminate the created instance, volumes and snapshots + cleanup_resources(self.apiclient, self.cleanup) + pass + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def updateDomainResourceLimits(self, parentdomainlimit, subdomainlimit): + """Update secondary storage limits of the parent domain and its + child domains""" + + try: + #Update resource limit for domain + Resources.updateLimit(self.apiclient, resourcetype=11, + max=parentdomainlimit, + domainid=self.parent_domain.id) + + # Update Resource limit for sub-domains + Resources.updateLimit(self.apiclient, resourcetype=11, + max=subdomainlimit, + domainid=self.cadmin_1.domainid) + + Resources.updateLimit(self.apiclient, resourcetype=11, + 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.parentd_admin = Account.create(self.apiclient, self.services["account"], + admin=True, domainid=self.parent_domain.id) + + # Create sub-domains and their admin accounts + self.cdomain_1 = Domain.create(self.apiclient, + services=self.services["domain"], + parentdomainid=self.parent_domain.id) + self.cdomain_2 = Domain.create(self.apiclient, + services=self.services["domain"], + parentdomainid=self.parent_domain.id) + + self.cadmin_1 = Account.create(self.apiclient, self.services["account"], + admin=True, domainid=self.cdomain_1.id) + + self.cadmin_2 = Account.create(self.apiclient, self.services["account"], + admin=True, domainid=self.cdomain_2.id) + + # Cleanup the resources created at end of test + self.cleanup.append(self.cadmin_1) + self.cleanup.append(self.cadmin_2) + self.cleanup.append(self.cdomain_1) + self.cleanup.append(self.cdomain_2) + self.cleanup.append(self.parentd_admin) + self.cleanup.append(self.parent_domain) + + 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"], required_hardware="false") + def test_01_multiple_domains_secondary_storage_limits(self): + """Test secondary 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. Register template in child domain 1 so that total secondary storage + is less than the limit of child domain + 3. Set the child domain limit equal to template size and parent domain + domain limit as double of the template size + 4. Repeat step 2 for child domain 2 + 5. Try to register template in parent domain now so that the total secondary storage in + parent domain (including that in sub-domains is more than the secondary + 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 template in account 2 and check secondary storage count + of parent domain + + # Validations: + 1. Step 2 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""" + + # Setting up account and domain hierarchy + result = self.setupAccounts() + self.assertEqual(result[0], PASS, result[1]) + + try: + builtin_info = get_builtin_template_info(self.apiclient, self.zone.id) + self.services["template_2"]["url"] = builtin_info[0] + self.services["template_2"]["hypervisor"] = builtin_info[1] + self.services["template_2"]["format"] = builtin_info[2] + + templateChildAccount1 = Template.register(self.apiclient, + self.services["template_2"], + zoneid=self.zone.id, + account=self.cadmin_1.name, + domainid=self.cadmin_1.domainid) + + templateChildAccount1.download(self.apiclient) + + templates = Template.list(self.apiclient, + templatefilter=\ + self.services["template_2"]["templatefilter"], + id=templateChildAccount1.id) + if validateList(templates)[0] == FAIL: + raise Exception("templates list validation failed") + + self.templateSize = int(int(templates[0].size) / (1024**3)) + except Exception as e: + self.fail("Failed with exception as ee: %s" % e) + + subdomainlimit = (self.templateSize) + + result = self.updateDomainResourceLimits(((subdomainlimit*2)), subdomainlimit) + self.assertEqual(result[0], PASS, result[1]) + + # Checking Primary Storage count of Parent domain admin before deleting child domain user account + result = isDomainResourceCountEqualToExpectedCount( + self.apiclient, self.cadmin_1.domainid, + self.templateSize, RESOURCE_SECONDARY_STORAGE) + self.assertFalse(result[0], result[1]) + self.assertTrue(result[2], "Resource count does not match") + + try: + templateChildAccount2 = Template.register(self.apiclient, + self.services["template_2"], + zoneid=self.zone.id, + account=self.cadmin_2.name, + domainid=self.cadmin_2.domainid) + + templateChildAccount2.download(self.apiclient) + except Exception as e: + self.fail("Failed while registering/downloading template: %s" % e) + + result = isDomainResourceCountEqualToExpectedCount( + self.apiclient, self.cadmin_2.domainid, + self.templateSize, RESOURCE_SECONDARY_STORAGE) + self.assertFalse(result[0], result[1]) + self.assertTrue(result[2], "Resource count does not match") + + with self.assertRaises(Exception): + Template.register(self.apiclient, + self.services["template_2"], + zoneid=self.zone.id, + account=self.parentd_admin.name, + domainid=self.parentd_admin.domainid) + + self.cadmin_1.delete(self.apiclient) + self.cleanup.remove(self.cadmin_1) + + result = isDomainResourceCountEqualToExpectedCount( + self.apiclient, self.parent_domain.id, + self.templateSize, RESOURCE_SECONDARY_STORAGE) + self.assertFalse(result[0], result[1]) + self.assertTrue(result[2], "Resource count does not match") + + try: + templateChildAccount2.delete(self.apiclient) + except Exception as e: + self.fail("Failed to delete template: %s" % e) + + result = isDomainResourceCountEqualToExpectedCount( + self.apiclient, self.parent_domain.id, + 0, RESOURCE_SECONDARY_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_secondary_storage_counts(self): + """Test secondary 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. Register template in child domain + 3. Check if the resource count for domain is updated correctly + 4. Delete the template + 5. Verify that the resource count for the domain is 0 + + """ + users = None + # Setting up account and domain hierarchy + result = self.setupAccounts() + self.assertEqual(result[0], PASS, result[1]) + users = result[2] + + for domain, admin in users.items(): + self.account = admin + self.domain = domain + + try: + builtin_info = get_builtin_template_info(self.apiclient, self.zone.id) + self.services["template_2"]["url"] = builtin_info[0] + self.services["template_2"]["hypervisor"] = builtin_info[1] + self.services["template_2"]["format"] = builtin_info[2] + + template = Template.register(self.apiclient, + self.services["template_2"], + zoneid=self.zone.id, + account=self.account.name, + domainid=self.account.domainid) + + template.download(self.apiclient) + + templates = Template.list(self.apiclient, + templatefilter=\ + self.services["template_2"]["templatefilter"], + id=template.id) + if validateList(templates)[0] == FAIL: + raise Exception("templates list validation failed") + + templateSize = int(int(templates[0].size) / (1024**3)) + expectedCount = templateSize + result = isDomainResourceCountEqualToExpectedCount( + self.apiclient, self.domain.id, + expectedCount, RESOURCE_SECONDARY_STORAGE) + self.assertFalse(result[0], result[1]) + self.assertTrue(result[2], "Resource count does not match") + + template.delete(self.apiclient) + + expectedCount = 0 + result = isDomainResourceCountEqualToExpectedCount( + self.apiclient, self.domain.id, + expectedCount, RESOURCE_SECONDARY_STORAGE) + self.assertFalse(result[0], result[1]) + self.assertTrue(result[2], "Resource count does not match") + except Exception as e: + self.fail("Failed to get zone list: %s" % e) + return + + @attr(tags=["advanced"], required_hardware="false") + def test_03_copy_template(self): + """Test secondary 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. Register template in child domain + 3. Check if the resource count for domain is updated correctly + 4. Copy template to other zone + 5. Verify that secondary storage count for the domain is doubled + as there are two templates now + """ + + zones = list_zones(self.apiclient) + self.assertEqual(validateList(zones)[0], PASS, "zones list validation faield") + + if len(zones) < 2: + self.skipTest("At least 2 zones should be present for this test case") + + users = None + # Setting up account and domain hierarchy + result = self.setupAccounts() + self.assertEqual(result[0], PASS, result[1]) + users = result[2] + + for domain, admin in users.items(): + self.account = admin + self.domain = domain + + try: + builtin_info = get_builtin_template_info(self.apiclient, self.zone.id) + self.services["template_2"]["url"] = builtin_info[0] + self.services["template_2"]["hypervisor"] = builtin_info[1] + self.services["template_2"]["format"] = builtin_info[2] + + template = Template.register(self.apiclient, + self.services["template_2"], + zoneid=self.zone.id, + account=self.account.name, + domainid=self.account.domainid) + + template.download(self.apiclient) + + templates = Template.list(self.apiclient, + templatefilter=\ + self.services["template_2"]["templatefilter"], + id=template.id) + if validateList(templates)[0] == FAIL: + raise Exception("templates list validation failed") + + templateSize = int(int(templates[0].size) / (1024**3)) + expectedCount = templateSize + result = isDomainResourceCountEqualToExpectedCount( + self.apiclient, self.domain.id, + expectedCount, RESOURCE_SECONDARY_STORAGE) + self.assertFalse(result[0], result[1]) + self.assertTrue(result[2], "Resource count does not match") + + templateDestinationZoneId = None + for zone in zones: + if template.zoneid != zone.id : + templateDestinationZoneId = zone.id + break + + template.copy(self.apiclient, destzoneid=templateDestinationZoneId, + sourcezoneid = template.zoneid) + + expectedCount *= 2 + result = isDomainResourceCountEqualToExpectedCount( + self.apiclient, self.domain.id, + expectedCount, RESOURCE_SECONDARY_STORAGE) + self.assertFalse(result[0], result[1]) + self.assertTrue(result[2], "Resource count does not match") + except Exception as e: + self.fail("Failed to get zone list: %s" % e) + return + +class TestDeleteAccount(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cloudstackTestClient = super(TestDeleteAccount, + cls).getClsTestClient() + cls.api_client = cloudstackTestClient.getApiClient() + # 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) + cls.services["mode"] = cls.zone.networktype + cls.template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostype"] + ) + cls._cleanup = [] + return + + @classmethod + def tearDownClass(cls): + try: + # Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + return + + def tearDown(self): + try: + # Clean up, terminate the created instance, volumes and snapshots + cleanup_resources(self.apiclient, self.cleanup) + pass + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setupAccounts(self): + try: + self.parent_domain = Domain.create(self.apiclient, + services=self.services["domain"], + parentdomainid=self.domain.id) + self.parentd_admin = Account.create(self.apiclient, self.services["account"], + admin=True, domainid=self.parent_domain.id) + + # Create sub-domains and their admin accounts + self.cdomain_1 = Domain.create(self.apiclient, + services=self.services["domain"], + parentdomainid=self.parent_domain.id) + self.cdomain_2 = Domain.create(self.apiclient, + services=self.services["domain"], + parentdomainid=self.parent_domain.id) + + self.cadmin_1 = Account.create(self.apiclient, self.services["account"], + admin=True, domainid=self.cdomain_1.id) + + self.cadmin_2 = Account.create(self.apiclient, self.services["account"], + admin=True, domainid=self.cdomain_2.id) + + # Cleanup the resources created at end of test + self.cleanup.append(self.cadmin_2) + self.cleanup.append(self.cdomain_1) + self.cleanup.append(self.cdomain_2) + self.cleanup.append(self.parentd_admin) + self.cleanup.append(self.parent_domain) + + 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"], required_hardware="false") + def test_04_create_template_delete_account(self): + """Test secondary 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. Register template in child domain 1 + 3. Verify that the secondary storage count for child domain 1 equals + the template size + 4. Register template in child domain 2 + 5. Vreify that the seconday storage count for child domain 2 equals + the template size + 6. Verify that the secondary storage count for parent domain equals + double of template size + 7. Delete child domain 1 admin account + 8. Verify that secondary storage count for parent domain now equals + to only 1 template size + """ + + # Setting up account and domain hierarchy + result = self.setupAccounts() + self.assertEqual(result[0], PASS, result[1]) + + try: + builtin_info = get_builtin_template_info(self.apiclient, self.zone.id) + self.services["template_2"]["url"] = builtin_info[0] + self.services["template_2"]["hypervisor"] = builtin_info[1] + self.services["template_2"]["format"] = builtin_info[2] + + template = Template.register(self.apiclient, + self.services["template_2"], + zoneid=self.zone.id, + account=self.cadmin_1.name, + domainid=self.cadmin_1.domainid) + + template.download(self.apiclient) + + templates = Template.list(self.apiclient, + templatefilter=\ + self.services["template_2"]["templatefilter"], + id=template.id) + if validateList(templates)[0] == FAIL: + raise Exception("templates list validation failed") + + self.templateSize = int(int(templates[0].size) / (1024**3)) + except Exception as e: + self.fail("Failed with exception as ee: %s" % e) + + # Checking Primary Storage count of Parent domain admin before deleting child domain user account + expectedCount = self.templateSize + result = isDomainResourceCountEqualToExpectedCount( + self.apiclient, self.cadmin_1.domainid, + expectedCount, RESOURCE_SECONDARY_STORAGE) + self.assertFalse(result[0], result[1]) + self.assertTrue(result[2], "Resource count does not match") + + try: + template = Template.register(self.apiclient, + self.services["template_2"], + zoneid=self.zone.id, + account=self.cadmin_2.name, + domainid=self.cadmin_2.domainid) + + template.download(self.apiclient) + except Exception as e: + self.fail("Failed while registering/downloading template: %s" % e) + + result = isDomainResourceCountEqualToExpectedCount( + self.apiclient, self.cadmin_2.domainid, + expectedCount, RESOURCE_SECONDARY_STORAGE) + self.assertFalse(result[0], result[1]) + self.assertTrue(result[2], "Resource count does not match") + + expectedCount *= 2 + result = isDomainResourceCountEqualToExpectedCount( + self.apiclient, self.parent_domain.id, + expectedCount, RESOURCE_SECONDARY_STORAGE) + self.assertFalse(result[0], result[1]) + self.assertTrue(result[2], "Resource count does not match") + + try: + self.cadmin_1.delete(self.apiclient) + except Exception as e: + self.fail("Failed to delete account: %s" % e) + + expectedCount /= 2 + result = isDomainResourceCountEqualToExpectedCount( + self.apiclient, self.parent_domain.id, + expectedCount, RESOURCE_SECONDARY_STORAGE) + self.assertFalse(result[0], result[1]) + self.assertTrue(result[2], "Resource count does not match") + return diff --git a/test/integration/component/test_ss_limits.py b/test/integration/component/test_ss_limits.py new file mode 100644 index 00000000000..4d6efc4eb33 --- /dev/null +++ b/test/integration/component/test_ss_limits.py @@ -0,0 +1,377 @@ +# 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 secondary 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 Local Modules +from nose.plugins.attrib import attr +from marvin.cloudstackTestCase import cloudstackTestCase, unittest +from marvin.lib.base import (Account, + ServiceOffering, + VirtualMachine, + Domain, + Template, + Iso) +from marvin.lib.common import (get_domain, + get_zone, + get_template, + matchResourceCount, + createSnapshotFromVirtualMachineVolume, + list_zones, + get_builtin_template_info) +from marvin.lib.utils import (cleanup_resources, + validateList) +from marvin.codes import (PASS, + FAIL, + FAILED, + RESOURCE_SECONDARY_STORAGE, + CHILD_DOMAIN_ADMIN, + ROOT_DOMAIN_ADMIN) +from ddt import ddt, data +import time + +@ddt +class TestSecondaryStorageLimits(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cloudstackTestClient = super(TestSecondaryStorageLimits, + cls).getClsTestClient() + cls.api_client = cloudstackTestClient.getApiClient() + # 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.hypervisor = cloudstackTestClient.getHypervisorInfo() + + 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"]) + if cls.service_offering == FAILED: + raise Exception("Creating service offering failed") + except Exception as e: + cls.tearDownClass() + raise unittest.SkipTest("Exception in setup class: %s" % e) + return + + @classmethod + def tearDownClass(cls): + try: + # Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + return + + def tearDown(self): + try: + # Clean up, terminate the created instance, volumes and snapshots + cleanup_resources(self.apiclient, self.cleanup) + pass + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + 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.account = Account.create(self.apiclient, self.services["account"], + domainid=self.domain.id, admin=True) + self.cleanup.append(self.account) + if accountType == CHILD_DOMAIN_ADMIN: + self.cleanup.append(self.domain) + except Exception as e: + return [FAIL, e] + return [PASS, None] + + @data(ROOT_DOMAIN_ADMIN, CHILD_DOMAIN_ADMIN) + @attr(tags = ["advanced"], required_hardware="false") + def test_01_register_template(self, value): + """Test register template + # Validate the following: + 1. Create a root domain admin/ child domain admin account + 2. Register and download a template according to hypervisor type + 3. Verify that the template is listed + 4. Verify that the secondary storage count for the account equals the size + of the template + 5. Delete the template + 6. Verify that the secondary storage resource count of the account equals 0 + """ + response = self.setupAccount(value) + self.assertEqual(response[0], PASS, response[1]) + + builtin_info = get_builtin_template_info(self.apiclient, self.zone.id) + self.services["template_2"]["url"] = builtin_info[0] + self.services["template_2"]["hypervisor"] = builtin_info[1] + self.services["template_2"]["format"] = builtin_info[2] + + try: + template = Template.register(self.apiclient, + self.services["template_2"], + zoneid=self.zone.id, + account=self.account.name, + domainid=self.account.domainid, + hypervisor=self.hypervisor) + + template.download(self.apiclient) + except Exception as e: + self.fail("Failed to register template: %s" % e) + + templates = Template.list(self.apiclient, + templatefilter=\ + self.services["template_2"]["templatefilter"], + id=template.id) + self.assertEqual(validateList(templates)[0],PASS,\ + "templates list validation failed") + + templateSize = (templates[0].size / (1024**3)) + expectedCount = templateSize + response = matchResourceCount( + self.apiclient, expectedCount, + RESOURCE_SECONDARY_STORAGE, + accountid=self.account.id) + self.assertEqual(response[0], PASS, response[1]) + + try: + template.delete(self.apiclient) + except Exception as e: + self.fail("Failed to delete template: %s" % e) + + expectedCount = 0 + response = matchResourceCount( + self.apiclient, expectedCount, + RESOURCE_SECONDARY_STORAGE, + accountid=self.account.id) + self.assertEqual(response[0], PASS, response[1]) + return + + @data(ROOT_DOMAIN_ADMIN, CHILD_DOMAIN_ADMIN) + @attr(tags=["advanced"], required_hardware="false") + def test_02_create_template_snapshot(self, value): + """Test create snapshot and templates from volume + + # Validate the following + 1. Create root domain/child domain admin account + 2. Deploy VM in the account + 3. Create snapshot from the virtual machine root volume + 4. Create template from the snapshot + 5. Verify that the secondary storage count of the account equals + the size of the template""" + + response = self.setupAccount(value) + self.assertEqual(response[0], PASS, response[1]) + + self.virtualMachine = VirtualMachine.create(self.api_client, self.services["virtual_machine"], + accountid=self.account.name, domainid=self.account.domainid, + serviceofferingid=self.service_offering.id) + + self.assertNotEqual(self.virtualMachine, FAILED, "VM deployment failed") + + 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: + self.virtualMachine.stop(apiclient) + except Exception as e: + self.fail("Failed to stop instance: %s" % e) + + self.debug("Creating snapshot from ROOT volume: %s" % self.virtualMachine.name) + response = createSnapshotFromVirtualMachineVolume(apiclient, self.account, self.virtualMachine.id) + self.assertEqual(response[0], PASS, response[1]) + snapshot = response[1] + + try: + template = Template.create_from_snapshot(apiclient, + snapshot=snapshot, + services=self.services["template_2"]) + except Exception as e: + self.fail("Failed to create template: %s" % e) + + templateSize = (template.size / (1024**3)) + response = matchResourceCount(self.apiclient, templateSize, + resourceType=RESOURCE_SECONDARY_STORAGE, + accountid=self.account.id) + self.assertEqual(response[0], PASS, response[1]) + return + + @data(ROOT_DOMAIN_ADMIN, CHILD_DOMAIN_ADMIN) + @attr(tags = ["advanced"], required_hardware="false") + def test_03_register_iso(self, value): + """Test register iso + Steps and validations: + 1. Create a root domain/child domain admin account + 2. Register a test iso in the account + 3. Wait till the iso is downloaded and is in ready state + 3. Verify that secondary storage resource count of the account equals the + iso size + 4. Delete the iso + 5. Verify that the secondary storage count of the account equals 0 + """ + response = self.setupAccount(value) + self.assertEqual(response[0], PASS, response[1]) + + self.services["iso"]["zoneid"] = self.zone.id + try: + iso = Iso.create( + self.apiclient, + self.services["iso"], + account=self.account.name, + domainid=self.account.domainid + ) + except Exception as e: + self.fail("Failed to create Iso: %s" % e) + + timeout = 600 + isoList = None + while timeout >= 0: + isoList = Iso.list(self.apiclient, + isofilter="self", + id=iso.id) + self.assertEqual(validateList(isoList)[0],PASS,\ + "iso list validation failed") + if isoList[0].isready: + break + time.sleep(60) + timeout -= 60 + + self.assertNotEqual(timeout, 0,\ + "template not downloaded completely") + + isoSize = (isoList[0].size / (1024**3)) + expectedCount = isoSize + response = matchResourceCount(self.apiclient, expectedCount, + resourceType=RESOURCE_SECONDARY_STORAGE, + accountid=self.account.id) + self.assertEqual(response[0], PASS, response[1]) + + try: + iso.delete(self.apiclient) + except Exception as e: + self.fail("Failed to delete Iso") + + expectedCount = 0 + response = matchResourceCount(self.apiclient, expectedCount, + resourceType=RESOURCE_SECONDARY_STORAGE, + accountid=self.account.id) + self.assertEqual(response[0], PASS, response[1]) + return + + @data(ROOT_DOMAIN_ADMIN, CHILD_DOMAIN_ADMIN) + @attr(tags = ["advanced"], required_hardware="false") + def test_04_copy_template(self, value): + """Test copy template between zones + + Steps and validations: + This test requires at least two zones present in the setup + 1. Create a root domain/child domain admin account + 2. Register and download a template in the account + 3. Verify the secondary storage resource count of the account + equals the size of the template + 4. Copy this template to other zone + 5. Verify that the secondary storage resource count is now doubled + as there are two templates now in two zones under the admin account + """ + + zones = list_zones(self.apiclient) + self.assertEqual(validateList(zones)[0], PASS, "zones list validation faield") + + if len(zones) < 2: + self.skipTest("At least 2 zones should be present for this test case") + + response = self.setupAccount(value) + self.assertEqual(response[0], PASS, response[1]) + + builtin_info = get_builtin_template_info(self.apiclient, self.zone.id) + self.services["template_2"]["url"] = builtin_info[0] + self.services["template_2"]["hypervisor"] = builtin_info[1] + self.services["template_2"]["format"] = builtin_info[2] + + try: + template = Template.register(self.apiclient, + self.services["template_2"], + zoneid=self.zone.id, + account=self.account.name, + domainid=self.account.domainid, + hypervisor=self.hypervisor) + + template.download(self.apiclient) + except Exception as e: + self.fail("Failed to register template: %s" % e) + + templates = Template.list(self.apiclient, + templatefilter=\ + self.services["template_2"]["templatefilter"], + id=template.id) + self.assertEqual(validateList(templates)[0],PASS,\ + "templates list validation failed") + + templateSize = (templates[0].size / (1024**3)) + expectedCount = templateSize + response = matchResourceCount( + self.apiclient, expectedCount, + RESOURCE_SECONDARY_STORAGE, + accountid=self.account.id) + self.assertEqual(response[0], PASS, response[1]) + + templateDestinationZoneId = None + for zone in zones: + if template.zoneid != zone.id : + templateDestinationZoneId = zone.id + break + + template.copy(self.apiclient, destzoneid=templateDestinationZoneId, + sourcezoneid = template.zoneid) + + expectedCount = (templateSize * 2) + response = matchResourceCount( + self.apiclient, expectedCount, + RESOURCE_SECONDARY_STORAGE, + accountid=self.account.id) + self.assertEqual(response[0], PASS, response[1]) + return diff --git a/test/integration/component/test_ss_max_limits.py b/test/integration/component/test_ss_max_limits.py new file mode 100644 index 00000000000..ba886e89075 --- /dev/null +++ b/test/integration/component/test_ss_max_limits.py @@ -0,0 +1,279 @@ +# 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. + +""" Tests for secondary storage - Maximum 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 +from marvin.lib.base import (Account, + ServiceOffering, + Resources, + Domain, + Project, + Template) +from marvin.lib.common import (get_domain, + get_zone, + get_template, + get_builtin_template_info, + matchResourceCount) +from marvin.lib.utils import (cleanup_resources, + validateList) +from marvin.codes import PASS, FAIL, RESOURCE_SECONDARY_STORAGE + +class TestMaxSecondaryStorageLimits(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cloudstackTestClient = super(TestMaxSecondaryStorageLimits, + cls).getClsTestClient() + cls.api_client = cloudstackTestClient.getApiClient() + # 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.service_offering = ServiceOffering.create(cls.api_client, cls.services["service_offering"]) + cls._cleanup = [cls.service_offering] + return + + @classmethod + def tearDownClass(cls): + try: + # Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + return + + def tearDown(self): + try: + # Clean up, terminate the created instance, volumes and snapshots + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def registerTemplate(self, inProject=False): + """Register and download template by default in the account/domain, + in project if stated so""" + + try: + builtin_info = get_builtin_template_info(self.apiclient, self.zone.id) + self.services["template_2"]["url"] = builtin_info[0] + self.services["template_2"]["hypervisor"] = builtin_info[1] + self.services["template_2"]["format"] = builtin_info[2] + + template = Template.register(self.apiclient, + self.services["template_2"], + zoneid=self.zone.id, + account=self.child_do_admin.name if not inProject else None, + domainid=self.child_do_admin.domainid if not inProject else None, + projectid=self.project.id if inProject else None) + + template.download(self.apiclient) + + templates = Template.list(self.apiclient, + templatefilter=\ + self.services["template_2"]["templatefilter"], + id=template.id) + self.assertEqual(validateList(templates)[0], PASS,\ + "templates list validation failed") + + self.templateSize = (templates[0].size / (1024**3)) + except Exception as e: + return [FAIL, e] + return [PASS, None] + + def setupAccounts(self): + + try: + self.child_domain = Domain.create(self.apiclient,services=self.services["domain"], + parentdomainid=self.domain.id) + + self.child_do_admin = Account.create(self.apiclient, self.services["account"], admin=True, + domainid=self.child_domain.id) + + # Create project as a domain admin + self.project = Project.create(self.apiclient, self.services["project"], + account=self.child_do_admin.name, + domainid=self.child_do_admin.domainid) + + # Cleanup created project at end of test + self.cleanup.append(self.project) + + # Cleanup accounts created + self.cleanup.append(self.child_do_admin) + self.cleanup.append(self.child_domain) + except Exception as e: + return [FAIL, e] + return [PASS, None] + + def updateSecondaryStorageLimits(self, accountLimit=None, domainLimit=None, projectLimit=None): + + try: + # Update resource limits for account + if accountLimit: + Resources.updateLimit(self.apiclient, resourcetype=11, + max=accountLimit, account=self.child_do_admin.name, + domainid=self.child_do_admin.domainid) + + if projectLimit: + Resources.updateLimit(self.apiclient, resourcetype=11, + max=projectLimit, projectid=self.project.id) + + if domainLimit: + Resources.updateLimit(self.apiclient, resourcetype=11, + max=domainLimit, domainid=self.child_domain.id) + except Exception as e: + return [FAIL, e] + return [PASS, None] + + @attr(tags=["advanced"], required_hardware="false") + def test_01_deploy_vm_domain_limit_reached(self): + """Test Try to deploy VM with admin account where account has not used + the resources but @ domain they are not available + + # Validate the following + # 1. Try to register template with admin account where account has not used the + # resources but @ domain they are not available + # 2. Template registration should fail""" + + response = self.setupAccounts() + self.assertEqual(response[0], PASS, response[1]) + + response = self.registerTemplate() + self.assertEqual(response[0], PASS, response[1]) + + expectedCount = self.templateSize + response = matchResourceCount( + self.apiclient, expectedCount, + RESOURCE_SECONDARY_STORAGE, + accountid=self.child_do_admin.id) + self.assertEqual(response[0], PASS, response[1]) + + domainLimit = self.templateSize + + response = self.updateSecondaryStorageLimits(domainLimit=domainLimit) + self.assertEqual(response[0], PASS, response[1]) + + with self.assertRaises(Exception): + template = Template.register(self.apiclient, + self.services["template_2"], + zoneid=self.zone.id, + account=self.child_do_admin.name, + domainid=self.child_do_admin.domainid) + return + + @attr(tags=["advanced"], required_hardware="false") + def test_02_deploy_vm_account_limit_reached(self): + """Test Try to deploy VM with admin account where account has used + the resources but @ domain they are available + + # Validate the following + # 1. Try to register template with admin account where account has used the + # resources but @ domain they are available + # 2. Template registration should fail""" + + response = self.setupAccounts() + self.assertEqual(response[0], PASS, response[1]) + + response = self.registerTemplate() + self.assertEqual(response[0], PASS, response[1]) + + expectedCount = self.templateSize + response = matchResourceCount( + self.apiclient, expectedCount, + RESOURCE_SECONDARY_STORAGE, + accountid=self.child_do_admin.id) + self.assertEqual(response[0], PASS, response[1]) + + accountLimit = self.templateSize + + response = self.updateSecondaryStorageLimits(accountLimit=accountLimit) + self.assertEqual(response[0], PASS, response[1]) + + with self.assertRaises(Exception): + template = Template.register(self.apiclient, + self.services["template_2"], + zoneid=self.zone.id, + account=self.child_do_admin.name, + domainid=self.child_do_admin.domainid) + return + + @attr(tags=["advanced"], required_hardware="false") + def test_03_deploy_vm_project_limit_reached(self): + """Test TTry to deploy VM with admin account where account has not used + the resources but @ project they are not available + + # Validate the following + # 1. Try to register template with admin account where account has not used the + # resources but @ project they are not available + # 2. Template registration should error out saying ResourceAllocationException + # with "resource limit exceeds""" + + response = self.setupAccounts() + self.assertEqual(response[0], PASS, response[1]) + + response = self.registerTemplate(inProject=True) + self.assertEqual(response[0], PASS, response[1]) + + try: + projects = Project.list(self.apiclient, id=self.project.id, listall=True) + except Exception as e: + self.fail("failed to get projects list: %s" % e) + + self.assertEqual(validateList(projects)[0], PASS, + "projects list validation failed") + self.assertEqual(self.templateSize, projects[0].secondarystoragetotal, "Resource count %s\ + not matching with the expcted count: %s" % + (projects[0].secondarystoragetotal, self.templateSize)) + + projectLimit = self.templateSize + + response = self.updateSecondaryStorageLimits(projectLimit=projectLimit) + self.assertEqual(response[0], PASS, response[1]) + + with self.assertRaises(Exception): + template = Template.register(self.apiclient, + self.services["template_2"], + zoneid=self.zone.id, + projectid=self.project.id) + return diff --git a/test/integration/component/test_ss_project_limits.py b/test/integration/component/test_ss_project_limits.py new file mode 100644 index 00000000000..0668f07cb26 --- /dev/null +++ b/test/integration/component/test_ss_project_limits.py @@ -0,0 +1,262 @@ +# 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 secondary storage Project 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, unittest +from marvin.lib.base import (Account, + ServiceOffering, + VirtualMachine, + Domain, + Project, + Template, + Iso, + Resources) +from marvin.lib.common import (get_domain, + get_zone, + get_template, + matchResourceCount, + get_builtin_template_info, + createSnapshotFromVirtualMachineVolume) +from marvin.lib.utils import (cleanup_resources, + validateList) +from marvin.codes import (PASS, + FAIL, + FAILED, + RESOURCE_SECONDARY_STORAGE) +import time + +class TestProjectsVolumeLimits(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cloudstackTestClient = super(TestProjectsVolumeLimits, + cls).getClsTestClient() + cls.api_client = cloudstackTestClient.getApiClient() + # 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) + 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): + try: + # Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + + self.cleanup = [] + response = self.setupProjectAccounts() + self.assertEqual(response[0], PASS, response[1]) + return + + def tearDown(self): + try: + # Clean up, terminate the created instance, volumes and snapshots + cleanup_resources(self.apiclient, self.cleanup) + pass + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setupProjectAccounts(self): + + try: + self.parentDomain = Domain.create(self.apiclient, + services=self.services["domain"], + parentdomainid=self.domain.id) + self.domainAdmin = Account.create( + self.apiclient, self.services["account"], + admin=True, domainid=self.parentDomain.id) + + # Create project as a domain admin + self.project = Project.create( + self.apiclient,self.services["project"], + account=self.domainAdmin.name,domainid=self.parentDomain.id) + # Cleanup created project at end of test + self.cleanup.append(self.project) + self.cleanup.append(self.domainAdmin) + self.cleanup.append(self.parentDomain) + except Exception as e: + return [FAIL, e] + return [PASS, None] + + @attr(tags=["advanced"], required_hardware="false") + def test_01_register_template_with_project(self): + """Test register template + # Validate the following: + 1. Create a project + 2. Register and download a template according to hypervisor type in the project + 3. Verify that the template is listed + 4. Verify that the secondary storage count for the project equals the size + of the template + 5. Delete the template + 6. Verify that the secondary storage resource count of the project equals 0 + """ + + builtin_info = get_builtin_template_info(self.apiclient, self.zone.id) + self.services["template_2"]["url"] = builtin_info[0] + self.services["template_2"]["hypervisor"] = builtin_info[1] + self.services["template_2"]["format"] = builtin_info[2] + + try: + template = Template.register(self.apiclient, + self.services["template_2"], + zoneid=self.zone.id, + projectid=self.project.id) + + template.download(self.apiclient) + except Exception as e: + self.fail("Failed to register template: %s" % e) + + templates = Template.list(self.apiclient, + templatefilter=\ + self.services["template_2"]["templatefilter"], + id=template.id, + ) + self.assertEqual(validateList(templates)[0],PASS,\ + "templates list validation failed") + + templates = Template.list(self.apiclient, + templatefilter=\ + self.services["template_2"]["templatefilter"], + id=template.id, + ) + self.assertEqual(validateList(templates)[0],PASS,\ + "templates list validation failed") + + templateSize = (templates[0].size / (1024**3)) + expectedCount = templateSize + response = matchResourceCount( + self.apiclient, expectedCount, + RESOURCE_SECONDARY_STORAGE, + projectid=self.project.id) + self.assertEqual(response[0], PASS, response[1]) + + try: + template.delete(self.apiclient) + except Exception as e: + self.fail("Failed to delete template: %s" % e) + + expectedCount = 0 + response = matchResourceCount( + self.apiclient, expectedCount, + RESOURCE_SECONDARY_STORAGE, + projectid=self.project.id) + self.assertEqual(response[0], PASS, response[1]) + return + + @attr(tags = ["advanced"], required_hardware="false") + def test_02_register_iso(self): + """Test register iso + Steps and validations: + 1. Create a root domain/child domain admin account + 2. Register a test iso in the account + 3. Wait till the iso is downloaded and is in ready state + 3. Verify that secondary storage resource count of the account equals the + iso size + 4. Delete the iso + 5. Verify that the secondary storage count of the account equals 0 + """ + try: + self.projectMember = Account.create( + self.apiclient, self.services["account"], + domainid=self.parentDomain.id) + self.cleanup.insert(0, self.projectMember) + self.project.addAccount(self.apiclient, account=self.projectMember.name) + except Exception as e: + self.fail("Exception occured: %s" % e) + + self.services["iso"]["zoneid"] = self.zone.id + try: + iso = Iso.create( + self.apiclient, + self.services["iso"], + account=self.projectMember.name, + domainid=self.projectMember.domainid + ) + except Exception as e: + self.fail("Failed to create Iso: %s" % e) + + timeout = 600 + isoList = None + while timeout >= 0: + isoList = Iso.list(self.apiclient, + isofilter="self", + id=iso.id) + self.assertEqual(validateList(isoList)[0],PASS,\ + "iso list validation failed") + if isoList[0].isready: + break + time.sleep(60) + timeout -= 60 + + self.assertNotEqual(timeout, 0,\ + "template not downloaded completely") + + isoSize = (isoList[0].size / (1024**3)) + expectedCount = isoSize + response = matchResourceCount(self.apiclient, expectedCount, + resourceType=RESOURCE_SECONDARY_STORAGE, + projectid=self.project.id) + self.assertEqual(response[0], PASS, response[1]) + + try: + iso.delete(self.apiclient) + except Exception as e: + self.fail("Failed to delete Iso") + + expectedCount = 0 + response = matchResourceCount(self.apiclient, expectedCount, + resourceType=RESOURCE_SECONDARY_STORAGE, + projectid=self.project.id) + self.assertEqual(response[0], PASS, response[1]) + return diff --git a/tools/marvin/marvin/config/test_data.py b/tools/marvin/marvin/config/test_data.py index ade8657cabb..fca24425eac 100644 --- a/tools/marvin/marvin/config/test_data.py +++ b/tools/marvin/marvin/config/test_data.py @@ -770,6 +770,7 @@ test_data = { "ispublic": True, "isextractable": True, "mode": "HTTP_DOWNLOAD", + "templatefilter": "self" }, "templatefilter": 'self', diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py index a43ec5e1c3e..982986bcf9c 100755 --- a/tools/marvin/marvin/lib/base.py +++ b/tools/marvin/marvin/lib/base.py @@ -1076,7 +1076,8 @@ class Template: @classmethod def register(cls, apiclient, services, zoneid=None, - account=None, domainid=None, hypervisor=None): + account=None, domainid=None, hypervisor=None, + projectid=None): """Create template from URL""" # Create template from Virtual machine and Volume ID @@ -1125,6 +1126,11 @@ class Template: if domainid: cmd.domainid = domainid + if projectid: + cmd.projectid = projectid + elif "projectid" in services: + cmd.projectid = services["projectid"] + # Register Template template = apiclient.registerTemplate(cmd)