# 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 Resource limits """ #Import Local Modules import marvin from nose.plugins.attrib import attr from marvin.cloudstackTestCase import * from marvin.cloudstackAPI import * from marvin.lib.utils import * from marvin.lib.base import * from marvin.lib.common import * from marvin.codes import PASS import datetime class Services: """Test Resource Limits Services """ def __init__(self): self.services = { "domain": { "name": "Domain", }, "project": { "name": "Project", "displaytext": "Test project", }, "account": { "email": "administrator@clogeny.com", "firstname": "Test", "lastname": "User", "username": "test", # Random characters are appended for unique # username "password": "password", }, "user": { "email": "administrator@clogeny.com", "firstname": "User", "lastname": "User", "username": "User", # Random characters are appended for unique # username "password": "password", }, "service_offering": { "name": "Tiny Instance", "displaytext": "Tiny Instance", "cpunumber": 1, "cpuspeed": 100, # in MHz "memory": 128, # In MBs }, "disk_offering": { "displaytext": "Tiny Disk Offering", "name": "Tiny Disk Offering", "disksize": 1 }, "volume": { "diskname": "Test Volume", }, "server": { "displayname": "TestVM", "username": "root", "password": "password", "ssh_port": 22, "hypervisor": 'XenServer', "privateport": 22, "publicport": 22, "protocol": 'TCP', }, "template": { "displaytext": "Cent OS Template", "name": "Cent OS Template", "ostype": 'CentOS 5.3 (64-bit)', "templatefilter": 'self', }, "network_offering": { "name": 'Network offering-VR services', "displaytext": 'Network offering-VR services', "guestiptype": 'Isolated', "supportedservices": 'Dhcp,Dns,SourceNat,PortForwarding,Vpn,Firewall,Lb,UserData,StaticNat', "traffictype": 'GUEST', "availability": 'Optional', "serviceProviderList": { "Dhcp": 'VirtualRouter', "Dns": 'VirtualRouter', "SourceNat": 'VirtualRouter', "PortForwarding": 'VirtualRouter', "Vpn": 'VirtualRouter', "Firewall": 'VirtualRouter', "Lb": 'VirtualRouter', "UserData": 'VirtualRouter', "StaticNat": 'VirtualRouter', }, }, "network": { "name": "Test Network", "displaytext": "Test Network", }, "ostype": 'CentOS 5.3 (64-bit)', # Cent OS 5.3 (64 bit) "sleep": 60, "timeout": 10, } class TestProjectLimits(cloudstackTestCase): @classmethod def setUpClass(cls): cls.api_client = super( TestProjectLimits, cls ).getClsTestClient().getApiClient() cls.services = Services().services # Get Zone cls.zone = get_zone(cls.api_client, cls.services) cls.services['mode'] = cls.zone.networktype # Create domains, account etc. cls.domain = Domain.create( cls.api_client, cls.services["domain"] ) cls.admin = Account.create( cls.api_client, cls.services["account"], admin=True, domainid=cls.domain.id ) cls.user = Account.create( cls.api_client, cls.services["user"], domainid=cls.domain.id ) cls.disk_offering = DiskOffering.create( cls.api_client, cls.services["disk_offering"] ) cls._cleanup = [ cls.admin, cls.user, cls.domain, cls.disk_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 accounts, domains etc cleanup_resources(self.apiclient, self.cleanup) except Exception as e: raise Exception("Warning: Exception during cleanup : %s" % e) return @attr(tags=["advanced", "basic", "sg", "eip", "advancedns", "simulator"]) def test_01_project_limits(self): """ Test project limits for domain admin """ # Validate the following # 1. Create a Project. Verify once projects are created, they inherit # a default set of resource limits as configured by the Cloud Stack # ROOT admin. # 2. Reduce Project resources limits. Verify limits can be reduced by # the Project Owner of each project and project limit applies to # number of virtual instances, disk volumes, snapshots, IP address. # Also, verify resource limits for the project are independent of # account resource limits # 3. Increase Projects Resources limits above domains limit. Verify # project can't have more resources than domain level limit allows. # 4. Create Resource more than its set limit for the parent domain. # Verify resource allocation should fail giving proper message # Create project as a domain admin project = Project.create( self.apiclient, self.services["project"], account=self.admin.name, domainid=self.admin.domainid ) # Cleanup created project at end of test self.cleanup.append(project) self.debug("Created project with domain admin with ID: %s" % project.id) list_projects_reponse = Project.list( self.apiclient, id=project.id, listall=True ) self.assertEqual( isinstance(list_projects_reponse, list), True, "Check for a valid list projects response" ) list_project = list_projects_reponse[0] self.assertNotEqual( len(list_projects_reponse), 0, "Check list project response returns a valid project" ) self.assertEqual( project.name, list_project.name, "Check project name from list response" ) # Get the resource limits for ROOT domain resource_limits = list_resource_limits(self.apiclient) self.assertEqual( isinstance(resource_limits, list), True, "List resource API should return a valid list" ) self.assertNotEqual( len(resource_limits), 0, "List resource API response should not be empty" ) # Reduce resource limits for project # Resource: 0 - Instance. Number of instances a user can create. # Resource: 1 - IP. Number of public IP addresses a user can own. # Resource: 2 - Volume. Number of disk volumes a user can create. # Resource: 3 - Snapshot. Number of snapshots a user can create. # Resource: 4 - Template. Number of templates that a user can # register/create for resource in resource_limits: update_resource_limit( self.apiclient, resource.resourcetype, max=1, projectid=project.id ) self.debug( "Updating resource (ID: %s) limit for project: %s" % ( resource, project.id )) resource_limits = list_resource_limits( self.apiclient, projectid=project.id ) self.assertEqual( isinstance(resource_limits, list), True, "List resource API should return a valid list" ) self.assertNotEqual( len(resource_limits), 0, "List resource API response should not be empty" ) for resource in resource_limits: self.assertEqual( resource.max, 1, "Resource limit should be updated to 1" ) # Get the resource limits for domain resource_limits = list_resource_limits( self.apiclient, domainid=self.domain.id ) self.assertEqual( isinstance(resource_limits, list), True, "List resource API should return a valid list" ) self.assertNotEqual( len(resource_limits), 0, "List resource API response should not be empty" ) for resource in resource_limits: # Update domain resource limits to 2 update_resource_limit( self.apiclient, resource.resourcetype, domainid=self.domain.id, max=1 ) max_value = 2 self.debug( "Attempting to update project: %s resource limit to: %s" % ( project.id, max_value )) # Update project resource limits to 3 update_resource_limit( self.apiclient, resource.resourcetype, max=max_value, projectid=project.id ) # Verify project can't have more resources then limit set for domain by adding volumes. volume = Volume.create( self.apiclient, self.services["volume"], zoneid=self.zone.id, diskofferingid=self.disk_offering.id, projectid=project.id ) # Exception should be raised for second volume with self.assertRaises(Exception): Volume.create( self.apiclient, self.services["volume"], zoneid=self.zone.id, diskofferingid=self.disk_offering.id, projectid=project.id ) volume.delete(self.apiclient); return @attr(tags=["advanced", "basic", "sg", "eip", "advancedns", "simulator"]) def test_02_project_limits_normal_user(self): """ Test project limits for normal user """ # Validate the following # 1. Create a Project # 2. Reduce the projects limits as a domain admin. Verify resource # count is updated # 3. Reduce the projects limits as a project user owner who is not a # domain admin. Resource count should fail # Create project as a domain admin project = Project.create( self.apiclient, self.services["project"], account=self.admin.name, domainid=self.admin.domainid ) # Cleanup created project at end of test self.cleanup.append(project) self.debug("Created project with domain admin with ID: %s" % project.id) list_projects_reponse = Project.list( self.apiclient, id=project.id, listall=True ) self.assertEqual( isinstance(list_projects_reponse, list), True, "Check for a valid list projects response" ) list_project = list_projects_reponse[0] self.assertNotEqual( len(list_projects_reponse), 0, "Check list project response returns a valid project" ) self.assertEqual( project.name, list_project.name, "Check project name from list response" ) # Get the resource limits for ROOT domain resource_limits = list_resource_limits(self.apiclient) self.assertEqual( isinstance(resource_limits, list), True, "List resource API should return a valid list" ) self.assertNotEqual( len(resource_limits), 0, "List resource API response should not be empty" ) # Reduce resource limits for project # Resource: 0 - Instance. Number of instances a user can create. # Resource: 1 - IP. Number of public IP addresses a user can own. # Resource: 2 - Volume. Number of disk volumes a user can create. # Resource: 3 - Snapshot. Number of snapshots a user can create. # Resource: 4 - Template. Number of templates that a user can # register/create for resource in resource_limits: update_resource_limit( self.apiclient, resource.resourcetype, max=1, projectid=project.id ) self.debug( "Updating resource (ID: %s) limit for project: %s" % ( resource, project.id )) resource_limits = list_resource_limits( self.apiclient, projectid=project.id ) self.assertEqual( isinstance(resource_limits, list), True, "List resource API should return a valid list" ) self.assertNotEqual( len(resource_limits), 0, "List resource API response should not be empty" ) for resource in resource_limits: self.assertEqual( resource.max, 1, "Resource limit should be updated to 1" ) self.debug("Adding %s user to project: %s" % ( self.user.name, project.name )) # Add user to the project project.addAccount( self.apiclient, self.user.name, ) # Get the resource limits for domain resource_limits = list_resource_limits( self.apiclient, domainid=self.domain.id ) self.assertEqual( isinstance(resource_limits, list), True, "List resource API should return a valid list" ) self.assertNotEqual( len(resource_limits), 0, "List resource API response should not be empty" ) for resource in resource_limits: #with self.assertRaises(Exception): self.debug( "Attempting to update resource limit by user: %s" % ( self.user.name )) # Update project resource limits to 3 update_resource_limit( self.apiclient, resource.resourcetype, account=self.user.name, domainid=self.user.domainid, max=3, projectid=project.id ) return class TestResourceLimitsProject(cloudstackTestCase): @classmethod def setUpClass(cls): cls.api_client = super(TestResourceLimitsProject, cls).getClsTestClient().getApiClient() cls.services = Services().services # Get Zone, Domain and templates cls.zone = get_zone(cls.api_client, cls.services) cls.services['mode'] = cls.zone.networktype cls.template = get_template( cls.api_client, cls.zone.id, cls.services["ostype"] ) cls.services["server"]["zoneid"] = cls.zone.id # Create Domains, Account etc cls.domain = Domain.create( cls.api_client, cls.services["domain"] ) cls.account = Account.create( cls.api_client, cls.services["account"], domainid=cls.domain.id ) # Create project as a domain admin cls.project = Project.create( cls.api_client, cls.services["project"], account=cls.account.name, domainid=cls.account.domainid ) cls.services["account"] = cls.account.name # Create Service offering and disk offerings etc cls.service_offering = ServiceOffering.create( cls.api_client, cls.services["service_offering"] ) cls.disk_offering = DiskOffering.create( cls.api_client, cls.services["disk_offering"] ) cls._cleanup = [ cls.project, cls.service_offering, cls.disk_offering, cls.account, cls.domain ] 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 @attr(tags=["advanced", "basic", "sg", "eip", "advancedns", "simulator"]) def test_03_vm_per_project(self): """Test VM limit per project """ # Validate the following # 1. Set max VM per project to 2 # 2. Create account and start 2 VMs. Verify VM state is Up and Running # 3. Try to create 3rd VM instance. The appropriate error or alert # should be raised self.debug( "Updating instance resource limits for project: %s" % self.project.id) # Set usage_vm=1 for Account 1 update_resource_limit( self.apiclient, 0, # Instance max=2, projectid=self.project.id ) self.debug("Deploying VM for project: %s" % self.project.id) virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, serviceofferingid=self.service_offering.id, projectid=self.project.id ) self.cleanup.append(virtual_machine_1) # Verify VM state self.assertEqual( virtual_machine_1.state, 'Running', "Check VM state is Running or not" ) self.debug("Deploying VM for project: %s" % self.project.id) virtual_machine_2 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, serviceofferingid=self.service_offering.id, projectid=self.project.id ) self.cleanup.append(virtual_machine_2) # Verify VM state self.assertEqual( virtual_machine_2.state, 'Running', "Check VM state is Running or not" ) # Exception should be raised for second instance with self.assertRaises(Exception): VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, serviceofferingid=self.service_offering.id, projectid=self.project.id ) return @attr(tags=["advanced", "eip", "advancedns", "simulator"]) def test_04_publicip_per_project(self): """Test Public IP limit per project """ # Validate the following # 1. set max no of IPs per project to 2. # 2. Create an account in this domain # 3. Create 1 VM in this domain # 4. Acquire 1 IP in the domain. IP should be successfully acquired # 5. Try to acquire 3rd IP in this domain. It should give the user an # appropriate error and an alert should be generated. self.debug( "Updating public IP resource limits for project: %s" % self.project.id) # Set usage_vm=1 for Account 1 update_resource_limit( self.apiclient, 1, # Public Ip max=2, projectid=self.project.id ) self.debug("Deploying VM for Project: %s" % self.project.id) virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, serviceofferingid=self.service_offering.id, projectid=self.project.id ) self.cleanup.append(virtual_machine_1) # Verify VM state self.assertEqual( virtual_machine_1.state, 'Running', "Check VM state is Running or not" ) networks = Network.list( self.apiclient, projectid=self.project.id, listall=True ) self.assertEqual( isinstance(networks, list), True, "Check list networks response returns a valid response" ) self.assertNotEqual( len(networks), 0, "Check list networks response returns a valid network" ) network = networks[0] self.debug("Associating public IP for project: %s" % self.project.id) public_ip_1 = PublicIPAddress.create( self.apiclient, zoneid=virtual_machine_1.zoneid, services=self.services["server"], networkid=network.id, projectid=self.project.id ) self.cleanup.append(public_ip_1) # Verify Public IP state self.assertEqual( public_ip_1.ipaddress.state in [ 'Allocated', 'Allocating' ], True, "Check Public IP state is allocated or not" ) # Exception should be raised for second Public IP with self.assertRaises(Exception): public_ip_2 = PublicIPAddress.create( self.apiclient, zoneid=virtual_machine_1.zoneid, services=self.services["server"], networkid=network.id, projectid=self.project.id ) return @attr(tags=["advanced", "basic", "sg", "eip", "advancedns", "simulator"]) def test_05_snapshots_per_project(self): """Test Snapshot limit per project """ # Validate the following # 1. set max no of snapshots per project to 1. # 2. Create one snapshot in the project. Snapshot should be # successfully created # 5. Try to create another snapshot in this project. It should give # user an appropriate error and an alert should be generated. self.debug( "Updating snapshot resource limits for project: %s" % self.project.id) # Set usage_vm=1 for Account 1 update_resource_limit( self.apiclient, 3, # Snapshot max=1, projectid=self.project.id ) self.debug("Deploying VM for account: %s" % self.account.name) virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, serviceofferingid=self.service_offering.id, projectid=self.project.id ) self.cleanup.append(virtual_machine_1) # Verify VM state self.assertEqual( virtual_machine_1.state, 'Running', "Check VM state is Running or not" ) # Get the Root disk of VM volumes = list_volumes( self.apiclient, virtualmachineid=virtual_machine_1.id, projectid=self.project.id, type='ROOT' ) self.assertEqual( isinstance(volumes, list), True, "Check for list volume response return valid data" ) volume = volumes[0] self.debug("Creating snapshot from volume: %s" % volumes[0].id) # Create a snapshot from the ROOTDISK snapshot_1 = Snapshot.create(self.apiclient, volumes[0].id, projectid=self.project.id ) self.cleanup.append(snapshot_1) #list snapshots snapshots = list_snapshots(self.apiclient, projectid=self.project.id) self.debug("snapshots list: %s" % snapshots) self.assertEqual(validateList(snapshots)[0], PASS, "Snapshots list validation failed") self.assertEqual(len(snapshots), 1, "Snapshots list should have exactly one entity") # Exception should be raised for second snapshot with self.assertRaises(Exception): Snapshot.create(self.apiclient, volumes[0].id, projectid=self.project.id ) return @attr(tags=["advanced", "basic", "sg", "eip", "advancedns", "simulator"]) def test_06_volumes_per_project(self): """Test Volumes limit per project """ # Validate the following # 1. set max no of volume per project to 1. # 2. Create 1 VM in this project # 4. Try to Create another VM in the project. It should give the user # an appropriate error that Volume limit is exhausted and an alert # should be generated. self.project_1 = Project.create( self.api_client, self.services["project"], account=self.account.name, domainid=self.account.domainid ) self.cleanup.append(self.project_1) self.debug( "Updating volume resource limits for project: %s" % self.project_1.id) # Set usage_vm=1 for Account 1 update_resource_limit( self.apiclient, 2, # Volume max=1, projectid=self.project_1.id ) self.debug("Deploying VM for project: %s" % self.project_1.id) virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, serviceofferingid=self.service_offering.id, projectid=self.project_1.id ) # Verify VM state self.assertEqual( virtual_machine_1.state, 'Running', "Check VM state is Running or not" ) # Exception should be raised for second volume with self.assertRaises(Exception): Volume.create( self.apiclient, self.services["volume"], zoneid=self.zone.id, diskofferingid=self.disk_offering.id, projectid=self.project_1.id ) return @attr(tags=["advanced", "basic", "sg", "eip", "advancedns"]) def test_07_templates_per_project(self): """Test Templates limit per project """ # 1. set max no of templates per project to 1. # 2. Create a template in this project. Both template should be in # ready state # 3. Try create 2nd template in the project. It should give the user # appropriate error and an alert should be generated. # Reset the volume limits update_resource_limit( self.apiclient, 2, # Volume max=5, projectid=self.project.id ) self.debug( "Updating template resource limits for domain: %s" % self.account.domainid) # Set usage_vm=1 for Account 1 update_resource_limit( self.apiclient, 4, # Template max=1, projectid=self.project.id ) self.debug("Deploying VM for account: %s" % self.account.name) virtual_machine_1 = VirtualMachine.create( self.apiclient, self.services["server"], templateid=self.template.id, serviceofferingid=self.service_offering.id, projectid=self.project.id ) self.cleanup.append(virtual_machine_1) # Verify VM state self.assertEqual( virtual_machine_1.state, 'Running', "Check VM state is Running or not" ) virtual_machine_1.stop(self.apiclient) # Get the Root disk of VM volumes = list_volumes( self.apiclient, virtualmachineid=virtual_machine_1.id, projectid=self.project.id, type='ROOT' ) self.assertEqual( isinstance(volumes, list), True, "Check for list volume response return valid data" ) volume = volumes[0] self.debug("Creating template from volume: %s" % volume.id) # Create a template from the ROOTDISK template_1 = Template.create( self.apiclient, self.services["template"], volumeid=volume.id, projectid=self.project.id ) self.cleanup.append(template_1) # Verify Template state self.assertEqual( template_1.isready, True, "Check Template is in ready state or not" ) # Exception should be raised for second template with self.assertRaises(Exception): Template.create( self.apiclient, self.services["template"], volumeid=volume.id, projectid=self.project.id ) return class TestMaxProjectNetworks(cloudstackTestCase): @classmethod def setUpClass(cls): cls.api_client = super( TestMaxProjectNetworks, cls ).getClsTestClient().getApiClient() cls.services = Services().services # Get Zone, Domain and templates cls.domain = get_domain(cls.api_client, cls.services) cls.zone = get_zone(cls.api_client, cls.services) cls.services['mode'] = cls.zone.networktype cls.template = get_template( cls.api_client, cls.zone.id, cls.services["ostype"] ) cls.service_offering = ServiceOffering.create( cls.api_client, cls.services["service_offering"] ) cls.network_offering = NetworkOffering.create( cls.api_client, cls.services["network_offering"], conservemode=True ) # Enable Network offering cls.network_offering.update(cls.api_client, state='Enabled') cls._cleanup = [ cls.service_offering, cls.network_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.account = Account.create( self.apiclient, self.services["account"], admin=True, domainid=self.domain.id ) self.cleanup = [] return def tearDown(self): try: #Clean up, terminate the created network offerings cleanup_resources(self.apiclient, self.cleanup) self.account.delete(self.apiclient) interval = list_configurations( self.apiclient, name='account.cleanup.interval' ) # Sleep to ensure that all resources are deleted time.sleep(int(interval[0].value) * 2) except Exception as e: raise Exception("Warning: Exception during cleanup : %s" % e) return @attr(tags=["advanced", "advancedns", "simulator", "api", "eip"]) def test_maxAccountNetworks(self): """Test Limit number of guest account specific networks """ # Steps for validation # 1. Fetch max.account.networks from configurations # 2. Create an account. Create account more that max.accout.network # 3. Create network should fail self.debug("Creating project with '%s' as admin" % self.account.name) # Create project as a domain admin project = Project.create( self.apiclient, self.services["project"], account=self.account.name, domainid=self.account.domainid ) # Cleanup created project at end of test self.cleanup.append(project) self.debug("Created project with domain admin with ID: %s" % project.id) config = Configurations.list( self.apiclient, name='max.project.networks', listall=True ) self.assertEqual( isinstance(config, list), True, "List configurations hsould have max.project.networks" ) config_value = int(config[0].value) self.debug("max.project.networks: %s" % config_value) for ctr in range(config_value): # Creating network using the network offering created self.debug("Creating network with network offering: %s" % self.network_offering.id) network = Network.create( self.apiclient, self.services["network"], projectid=project.id, networkofferingid=self.network_offering.id, zoneid=self.zone.id ) self.debug("Created network with ID: %s" % network.id) self.debug( "Creating network in account already having networks : %s" % config_value) with self.assertRaises(Exception): Network.create( self.apiclient, self.services["network"], projectid=project.id, networkofferingid=self.network_offering.id, zoneid=self.zone.id ) self.debug('Create network failed (as expected)') return