http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ada8cdce/test/integration/testpaths/testpath_usage.py ---------------------------------------------------------------------- diff --git a/test/integration/testpaths/testpath_usage.py b/test/integration/testpaths/testpath_usage.py new file mode 100644 index 0000000..17d56cc --- /dev/null +++ b/test/integration/testpaths/testpath_usage.py @@ -0,0 +1,3327 @@ +# 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. +""" Test cases for Usage Test Path +""" +from nose.plugins.attrib import attr +from marvin.cloudstackTestCase import cloudstackTestCase, unittest +from marvin.lib.utils import (cleanup_resources, + validateList, + verifyRouterState, + get_process_status) +from marvin.lib.base import (Account, + ServiceOffering, + VirtualMachine, + Template, + Iso, + DiskOffering, + Volume, + Snapshot, + PublicIPAddress, + LoadBalancerRule, + EgressFireWallRule, + Router, + VmSnapshot, + Usage, + Configurations, + FireWallRule, + NATRule, + StaticNATRule, + Network, + Vpn, + VpnUser, + VpcOffering, + VPC, + NetworkACL) +from marvin.lib.common import (get_domain, + get_zone, + get_template, + createEnabledNetworkOffering, + get_builtin_template_info, + findSuitableHostForMigration, + list_hosts, + list_routers) +from marvin.codes import (PASS, FAIL, ERROR_NO_HOST_FOR_MIGRATION) +from marvin.sshClient import SshClient +import time + + +def CreateEnabledNetworkOffering(apiclient, networkServices): + """Create network offering of given services and enable it""" + + result = createEnabledNetworkOffering(apiclient, networkServices) + assert result[0] == PASS,\ + "Network offering creation/enabling failed due to %s" % result[2] + return result[1] + + +class TestUsage(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + testClient = super(TestUsage, cls).getClsTestClient() + cls.hypervisor = testClient.getHypervisorInfo() + cls.apiclient = testClient.getApiClient() + cls.testdata = testClient.getParsedTestDataConfig() + + # Get Zone, Domain and templates + cls.domain = get_domain(cls.apiclient) + cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) + + cls.mgtSvrDetails = cls.config.__dict__["mgtSvr"][0].__dict__ + + isUsageJobRunning = cls.IsUsageJobRunning() + if not isUsageJobRunning: + raise unittest.SkipTest("Skipping, usage job is not running") + + if cls.testdata["configurableData"][ + "setUsageConfigurationThroughTestCase"]: + cls.setUsageConfiguration() + cls.RestartServers() + + cls.hypervisor = testClient.getHypervisorInfo() + + cls.template = get_template( + cls.apiclient, + cls.zone.id, + cls.testdata["ostype"]) + cls._cleanup = [] + + try: + # If local storage is enabled, alter the offerings to use + # localstorage + if cls.zone.localstorageenable: + cls.testdata["service_offering"]["storagetype"] = 'local' + + # Create 2 service offerings with different values for + # for cpunumber, cpuspeed, and memory + + cls.testdata["service_offering"]["cpunumber"] = "1" + cls.testdata["service_offering"]["cpuspeed"] = "128" + cls.testdata["service_offering"]["memory"] = "256" + + cls.service_offering = ServiceOffering.create( + cls.apiclient, + cls.testdata["service_offering"] + ) + cls._cleanup.append(cls.service_offering) + + cls.testdata["service_offering"]["cpunumber"] = "2" + cls.testdata["service_offering"]["cpuspeed"] = "256" + cls.testdata["service_offering"]["memory"] = "512" + + cls.service_offering_2 = ServiceOffering.create( + cls.apiclient, + cls.testdata["service_offering"] + ) + cls._cleanup.append(cls.service_offering_2) + + # Create isolated network offering + cls.isolated_network_offering = CreateEnabledNetworkOffering( + cls.apiclient, + cls.testdata["isolated_network_offering"] + ) + cls._cleanup.append(cls.isolated_network_offering) + + cls.isolated_network_offering_2 = CreateEnabledNetworkOffering( + cls.apiclient, + cls.testdata["isolated_network_offering"] + ) + cls._cleanup.append(cls.isolated_network_offering_2) + + cls.isolated_network_offering_vpc = CreateEnabledNetworkOffering( + cls.apiclient, + cls.testdata["nw_offering_isolated_vpc"] + ) + cls._cleanup.append(cls.isolated_network_offering_vpc) + + cls.testdata["shared_network_offering_all_services"][ + "specifyVlan"] = "True" + cls.testdata["shared_network_offering_all_services"][ + "specifyIpRanges"] = "True" + + cls.shared_network_offering = CreateEnabledNetworkOffering( + cls.apiclient, + cls.testdata["shared_network_offering_all_services"] + ) + cls._cleanup.append(cls.shared_network_offering) + + configs = Configurations.list( + cls.apiclient, + name='usage.stats.job.aggregation.range' + ) + + # Set the value for one more minute than + # actual range to be on safer side + cls.usageJobAggregationRange = ( + int(configs[0].value) + 1) * 60 # in seconds + except Exception as e: + cls.tearDownClass() + raise e + return + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.apiclient, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + # Create an account + self.account = Account.create( + self.apiclient, + self.testdata["account"], + domainid=self.domain.id + ) + self.cleanup.append(self.account) + # Create user api client of the account + self.userapiclient = self.testClient.getUserApiClient( + UserName=self.account.name, + DomainName=self.account.domain + ) + + def tearDown(self): + try: + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @classmethod + def setUsageConfiguration(cls): + """ Set the configuration parameters so that usage job runs + every 10 miuntes """ + + Configurations.update( + cls.apiclient, + name="enable.usage.server", + value="true" + ) + + Configurations.update( + cls.apiclient, + name="usage.aggregation.timezone", + value="GMT" + ) + + Configurations.update( + cls.apiclient, + name="usage.execution.timezone", + value="GMT" + ) + + Configurations.update( + cls.apiclient, + name="usage.stats.job.aggregation.range", + value="10" + ) + + currentMgtSvrTime = cls.getCurrentMgtSvrTime() + dateTimeSplit = currentMgtSvrTime.split("/") + cls.curDate = dateTimeSplit[0] + timeSplit = dateTimeSplit[1].split(":") + minutes = int(timeSplit[1]) + minutes += 5 + usageJobExecTime = timeSplit[0] + ":" + str(minutes) + + Configurations.update( + cls.apiclient, + name="usage.stats.job.exec.time", + value=usageJobExecTime + ) + + return + + @classmethod + def getCurrentMgtSvrTime(cls, format='%Y-%m-%d/%H:%M'): + """ Get the current time from Management Server """ + + sshClient = SshClient( + cls.mgtSvrDetails["mgtSvrIp"], + 22, + cls.mgtSvrDetails["user"], + cls.mgtSvrDetails["passwd"] + ) + command = "date +%s" % format + return sshClient.execute(command)[0] + + @classmethod + def RestartServers(cls): + """ Restart management server and usage server """ + + sshClient = SshClient( + cls.mgtSvrDetails["mgtSvrIp"], + 22, + cls.mgtSvrDetails["user"], + cls.mgtSvrDetails["passwd"] + ) + command = "service cloudstack-management restart" + sshClient.execute(command) + + command = "service cloudstack-usage restart" + sshClient.execute(command) + return + + @classmethod + def IsUsageJobRunning(cls): + """ Check that usage job is running on Management server or not""" + + sshClient = SshClient( + cls.mgtSvrDetails["mgtSvrIp"], + 22, + cls.mgtSvrDetails["user"], + cls.mgtSvrDetails["passwd"] + ) + + command = "service cloudstack-usage status" + response = str(sshClient.execute(command)).lower() + if "running" not in response: + return False + return True + + def getLatestUsageJobExecutionTime(self): + """ Get the end time of latest usage job that has run successfully""" + + try: + qresultset = self.dbclient.execute( + "SELECT max(end_date) FROM usage_job WHERE success=1;", + db="cloud_usage") + + self.assertNotEqual( + len(qresultset), + 0, + "Check DB Query result set" + ) + + lastUsageJobExecutionTime = qresultset[0][0] + self.debug( + "last usage job exec time: %s" % + lastUsageJobExecutionTime) + return [PASS, lastUsageJobExecutionTime] + except Exception as e: + return [FAIL, e] + + def getEventCreatedDateTime(self, resourceName): + """ Get the created date/time of particular entity + from cloud_usage.usage_event table """ + + try: + # Checking exact entity creation time + qresultset = self.dbclient.execute( + "select created from usage_event where resource_name = '%s';" % + str(resourceName), db="cloud_usage") + self.assertNotEqual( + len(qresultset), + 0, + "Check DB Query result set" + ) + eventCreatedDateTime = qresultset[0][0] + except Exception as e: + return [FAIL, e] + return [PASS, eventCreatedDateTime] + + def listUsageRecords(self, usagetype, apiclient=None, startdate=None, + enddate=None, account=None, sleep=True): + """List and return the usage record for given account + and given usage type""" + + if sleep: + # Sleep till usage job has run at least once after the operation + self.debug( + "Sleeping for %s seconds" % + self.usageJobAggregationRange) + time.sleep(self.usageJobAggregationRange) + + if not startdate: + startdate = self.curDate + if not enddate: + enddate = self.curDate + if not account: + account = self.account + if not apiclient: + self.apiclient + + Usage.generateRecords( + self.apiclient, + startdate=startdate, + enddate=enddate) + + try: + usageRecords = Usage.listRecords( + self.apiclient, + startdate=startdate, + enddate=enddate, + account=account.name, + domainid=account.domainid, + type=usagetype) + + self.assertEqual( + validateList(usageRecords)[0], + PASS, + "usage records list validation failed") + + return [PASS, usageRecords] + except Exception as e: + return [FAIL, e] + return + + def getCommandResultFromRouter(self, router, command): + """Run given command on router and return the result""" + + if (self.hypervisor.lower() == 'vmware' + or self.hypervisor.lower() == 'hyperv'): + result = get_process_status( + self.apiclient.connection.mgtSvr, + 22, + self.apiclient.connection.user, + self.apiclient.connection.passwd, + router.linklocalip, + command, + hypervisor=self.hypervisor + ) + else: + hosts = list_hosts( + self.apiclient, + id=router.hostid, + ) + self.assertEqual( + isinstance(hosts, list), + True, + "Check for list hosts response return valid data" + ) + host = hosts[0] + host.user = self.testdata["configurableData"]["host"]["username"] + host.passwd = self.testdata["configurableData"]["host"]["password"] + + result = get_process_status( + host.ipaddress, + 22, + host.user, + host.passwd, + router.linklocalip, + command + ) + return result + + @attr(tags=["advanced"], required_hardware="true") + def test_01_positive_tests_usage(self): + """ Positive test for usage test path + + # 1. Register a template and verify that usage usage is generated + for correct size of template + # 2. Register an ISO, verify usage is generate for the correct size + of ISO + # 3. Deploy a VM from the template and verify usage is generated + for the VM with correct Service Offering and template id + # 4. Delete template and iso + # 5. Stop and start the VM + # 6. Verify that allocated VM usage should be greater than + running VM usage + # 7. Destroy the Vm and recover it + # 8. Verify that the running VM usage stays the same after delete and + and after recover operation + # 9. Verify that allocated VM usage should be greater after recover + operation than after destroy operation + # 10. Change service offering of the VM + # 11. Verify that VM usage is generated for the VM with correct + service offering + # 12. Start the VM + # 13. Verify that the running VM usage after start operation is less + than the allocated VM usage + # 14. Verify that the running VM usage after start vm opearation + is greater running VM usage after recover VM operation + """ + + # Step 1 + # Register a private template in the account + builtin_info = get_builtin_template_info( + self.apiclient, + self.zone.id + ) + + self.testdata["privatetemplate"]["url"] = builtin_info[0] + self.testdata["privatetemplate"]["hypervisor"] = builtin_info[1] + self.testdata["privatetemplate"]["format"] = builtin_info[2] + + # Register new template + template = Template.register( + self.userapiclient, + self.testdata["privatetemplate"], + zoneid=self.zone.id, + account=self.account.name, + domainid=self.account.domainid + ) + self.cleanup.append(template) + template.download(self.userapiclient) + + templates = Template.list( + self.userapiclient, + listall=True, + id=template.id, + templatefilter="self") + + self.assertEqual( + validateList(templates)[0], + PASS, + "Templates list validation failed") + + # Checking template usage + response = self.listUsageRecords(usagetype=7) + self.assertEqual(response[0], PASS, response[1]) + templateUsageRecords = [record for record in response[1] + if template.id == record.usageid] + + self.assertEqual(templateUsageRecords[0].virtualsize, + templates[0].size, + "The template size in the usage record and \ + does not match with the created template size") + + # Getting last usage job execution time + response = self.getLatestUsageJobExecutionTime() + self.assertEqual(response[0], PASS, response[1]) + lastUsageJobExecTime = response[1] + + # Checking exact template creation time + response = self.getEventCreatedDateTime(template.name) + self.assertEqual(response[0], PASS, response[1]) + templateCreatedDateTime = response[1] + self.debug("Template creation date: %s" % templateCreatedDateTime) + + # We have to get the expected usage count in hours as the rawusage returned by listUsageRecords + # is also in hours + expectedUsage = format( + ((lastUsageJobExecTime - templateCreatedDateTime).total_seconds() / 3600), + ".2f") + + actualUsage = format(sum(float(record.rawusage) + for record in templateUsageRecords), ".2f") + + self.assertEqual( + expectedUsage, + actualUsage, + "expected usage %s and actual usage %s not matching" % + (expectedUsage, + actualUsage)) + + # step 2 + iso = Iso.create( + self.userapiclient, + self.testdata["iso"], + account=self.account.name, + domainid=self.account.domainid, + zoneid=self.zone.id + ) + self.cleanup.append(iso) + + iso.download(self.apiclient) + + isos = Iso.list( + self.userapiclient, + id=iso.id, + listall=True) + + self.assertEqual( + validateList(isos)[0], + PASS, + "Iso list validation failed" + ) + + # Checking usage for Iso + response = self.listUsageRecords(usagetype=8) + self.assertEqual(response[0], PASS, response[1]) + isoUsageRecords = [record for record in response[1] + if iso.id == record.usageid] + + self.assertEqual(isoUsageRecords[0].size, + isos[0].size, + "The iso size in the usage record and \ + does not match with the created iso size") + + # Getting last usage job execution time + response = self.getLatestUsageJobExecutionTime() + self.assertEqual(response[0], PASS, response[1]) + lastUsageJobExecTime = response[1] + + # Checking exact Iso creation time + response = self.getEventCreatedDateTime(iso.name) + self.assertEqual(response[0], PASS, response[1]) + isoCreatedDateTime = response[1] + self.debug("Iso creation date: %s" % isoCreatedDateTime) + + # We have to get the expected usage count in hours as the rawusage returned by listUsageRecords + # is also in hours + expectedUsage = format( + ((lastUsageJobExecTime - isoCreatedDateTime).total_seconds() / 3600), + ".2f") + + actualUsage = format(sum(float(record.rawusage) + for record in isoUsageRecords), ".2f") + + self.assertEqual( + expectedUsage, + actualUsage, + "expected usage %s and actual usage %s not matching" % + (expectedUsage, + actualUsage)) + + # step 3 + # Create VM in account + vm = VirtualMachine.create( + self.userapiclient, + self.testdata["small"], + templateid=template.id, + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id, + zoneid=self.zone.id + ) + + # Checking running VM usage + response = self.listUsageRecords(usagetype=1) + self.assertEqual(response[0], PASS, response[1]) + vmRunningUsageRecords = [record for record in response[1] + if record.virtualmachineid == vm.id] + + vmRunningRawUsage = sum(float(record.rawusage) + for record in vmRunningUsageRecords) + + self.assertEqual(vmRunningUsageRecords[0].offeringid, + self.service_offering.id, + "The service offering id in the usage record\ + does not match with id of service offering\ + with which the VM was created") + + self.assertEqual(vmRunningUsageRecords[0].templateid, + template.id, + "The template id in the usage record\ + does not match with id of template\ + with which the VM was created") + + response = self.listUsageRecords(usagetype=2, sleep=False) + self.assertEqual(response[0], PASS, response[1]) + vmAllocatedUsageRecords = [record for record in response[1] + if record.virtualmachineid == vm.id] + + vmAllocatedRawUsage = sum(float(record.rawusage) + for record in vmAllocatedUsageRecords) + + self.debug("running vm usage: %s" % vmRunningRawUsage) + self.debug("allocated vm usage: %s" % vmAllocatedRawUsage) + + self.assertTrue( + vmRunningRawUsage < vmAllocatedRawUsage, + "Allocated VM usage should be greater than Running VM usage") + + # Getting last usage job execution time + response = self.getLatestUsageJobExecutionTime() + self.assertEqual(response[0], PASS, response[1]) + lastUsageJobExecTime = response[1] + + # Checking exact VM creation time + response = self.getEventCreatedDateTime(vm.name) + self.assertEqual(response[0], PASS, response[1]) + vmCreatedDateTime = response[1] + self.debug("Vm creation date: %s" % vmCreatedDateTime) + + # We have to get the expected usage count in hours as the rawusage returned by listUsageRecords + # is also in hours + expectedUsage = format( + ((lastUsageJobExecTime - vmCreatedDateTime).total_seconds() / 3600), + ".2f") + self.debug("VM expected usage: %s" % expectedUsage) + + actualUsage = format(vmAllocatedRawUsage, ".2f") + + self.assertEqual( + expectedUsage, + actualUsage, + "expected usage %s and actual usage %s not matching" % + (expectedUsage, + actualUsage)) + + # Step 4 - Deleting template and ISO + template.delete(self.userapiclient) + self.cleanup.remove(template) + + iso.delete(self.userapiclient) + self.cleanup.remove(iso) + + # Verifying that usage for template and ISO is stopped + response = self.listUsageRecords(usagetype=7) + self.assertEqual(response[0], PASS, response[1]) + templateUsageRecords = response[1] + + usageForTemplateAfterDeletion_1 = sum( + float( + record.rawusage) for record in [ + record for record in templateUsageRecords + if template.id == record.usageid]) + + response = self.listUsageRecords(usagetype=8, sleep=False) + self.assertEqual(response[0], PASS, response[1]) + isoUsageRecords = response[1] + + usageForIsoAfterDeletion_1 = sum( + float( + record.rawusage) for record in [ + record for record in isoUsageRecords + if iso.id == record.usageid]) + + response = self.listUsageRecords(usagetype=7) + self.assertEqual(response[0], PASS, response[1]) + templateUsageRecords = response[1] + + usageForTemplateAfterDeletion_2 = sum( + float( + record.rawusage) for record in [ + record for record in templateUsageRecords + if template.id == record.usageid]) + + response = self.listUsageRecords(usagetype=8, sleep=False) + self.assertEqual(response[0], PASS, response[1]) + isoUsageRecords = response[1] + + usageForIsoAfterDeletion_2 = sum( + float( + record.rawusage) for record in [ + record for record in isoUsageRecords + if iso.id == record.usageid]) + + self.assertTrue(usageForTemplateAfterDeletion_1 == + usageForTemplateAfterDeletion_2, + "usage for template after deletion should remain the same\ + after specific intervals of time") + + self.assertTrue(usageForIsoAfterDeletion_1 == + usageForIsoAfterDeletion_2, + "usage for iso after deletion should remain the same\ + after specific intervals of time") + + # Step 5 + vm.stop(self.userapiclient) + + # Sleep to get difference between allocated and running usage + time.sleep(120) + + vm.start(self.userapiclient) + + # Step 6: Verifying allocated usage is greater than running usage + response = self.listUsageRecords(usagetype=1) + self.assertEqual(response[0], PASS, response[1]) + vmRunningUsageRecords = [record for record in response[1] + if record.virtualmachineid == vm.id] + + vmRunningRawUsage = sum(float(record.rawusage) + for record in vmRunningUsageRecords) + + response = self.listUsageRecords(usagetype=2, sleep=False) + self.assertEqual(response[0], PASS, response[1]) + vmAllocatedUsageRecords = [record for record in response[1] + if record.virtualmachineid == vm.id] + + vmAllocatedRawUsage = sum(float(record.rawusage) + for record in vmAllocatedUsageRecords) + + self.debug("running vm usage: %s" % vmRunningRawUsage) + self.debug("allocated vm usage: %s" % vmAllocatedRawUsage) + + self.assertTrue( + vmRunningRawUsage < vmAllocatedRawUsage, + "Allocated VM usage should be greater than Running VM usage") + + # Step 7 + vm.delete(self.userapiclient, expunge=False) + + response = self.listUsageRecords(usagetype=1, sleep=False) + self.assertEqual(response[0], PASS, response[1]) + vmRunningUsageRecordAfterDestroy = sum( + float( + record.rawusage) for record in response[1] if + record.virtualmachineid == vm.id) + + response = self.listUsageRecords(usagetype=2, sleep=False) + self.assertEqual(response[0], PASS, response[1]) + vmAllocatedUsageRecordAfterDestroy = sum( + float( + record.rawusage) for record in response[1] if record.virtualmachineid == vm.id) + + vm.recover(self.apiclient) + + # Step 8 + response = self.listUsageRecords(usagetype=1) + self.assertEqual(response[0], PASS, response[1]) + vmRunningUsageRecordAfterRecover = sum( + float( + record.rawusage) for record in response[1] if + record.virtualmachineid == vm.id) + + response = self.listUsageRecords(usagetype=2, sleep=False) + self.assertEqual(response[0], PASS, response[1]) + vmAllocatedUsageRecordAfterRecover = sum( + float( + record.rawusage) for record in response[1] if + record.virtualmachineid == vm.id) + + self.debug( + "running vm usage T1: %s" % + vmRunningUsageRecordAfterDestroy) + self.debug( + "allocated vm usage T1: %s" % + vmRunningUsageRecordAfterRecover) + + self.assertEqual( + format(vmRunningUsageRecordAfterDestroy, ".1f"), + format(vmRunningUsageRecordAfterRecover, ".1f"), + "Running usage should remain the same") + + self.debug( + "allocated vm usage T2: %s" % + vmAllocatedUsageRecordAfterDestroy) + self.debug( + "allocated vm usage T2: %s" % + vmAllocatedUsageRecordAfterRecover) + + # Step 9 + self.assertTrue( + vmAllocatedUsageRecordAfterDestroy < + vmAllocatedUsageRecordAfterRecover, + "Allocated VM usage after recover should be greater than\ + before") + + # Step 10 + # Change service offering of VM and verify that it is changed + vm.change_service_offering( + self.userapiclient, + serviceOfferingId=self.service_offering_2.id + ) + + response = self.listUsageRecords(usagetype=2) + self.assertEqual(response[0], PASS, response[1]) + vmAllocatedUsageRecord = response[1][-1] + + # Step 11: Veriying vm usage for new service offering + self.assertEqual(vmAllocatedUsageRecord.offeringid, + self.service_offering_2.id, + "The service offering id in the usage record\ + does not match with id of new service offering") + + # Step 12 + vm.start(self.userapiclient) + + response = self.listUsageRecords(usagetype=1) + self.assertEqual(response[0], PASS, response[1]) + vmRunningUsageRecordAfterStart = sum( + float( + record.rawusage) for record in response[1] if + record.virtualmachineid == vm.id) + + response = self.listUsageRecords(usagetype=2, sleep=False) + self.assertEqual(response[0], PASS, response[1]) + vmAllocatedUsageRecordAfterStart = sum( + float( + record.rawusage) for record in response[1] if + record.virtualmachineid == vm.id) + + self.debug("running vm usage T3: %s" % vmRunningUsageRecordAfterStart) + self.debug( + "allocated vm usage T3: %s" % + vmAllocatedUsageRecordAfterStart) + + # Step 13 + self.assertTrue( + vmRunningUsageRecordAfterStart < + vmAllocatedUsageRecordAfterStart, + "Allocated VM usage should be greater than Running usage") + + # Step 14 + self.assertTrue( + vmRunningUsageRecordAfterRecover < + vmRunningUsageRecordAfterStart, + "Running VM usage after start VM should be greater than\ + that after recover operation") + return + + @attr(tags=["advanced"], required_hardware="true") + def test_02_positive_tests_usage(self): + """ Positive test for usage test path + + # 1. Scale up VM and check that usage is generated for + new cpu and ram value (Check in usage_vm_instance table) + # 2. Scale down VM and check that usage is generated for + new cpu and ram value (Check in usage_vm_instance table) + # 3. Attach disk to VM and check that volume usage is + generated for correct disk offering + # 4. Detach volume from and verify that usage for volue remains + the same there afterwards + # 5. Create snapshot of the root disk and verify correct usage is + generated for snapshot with correct size + # 6. Create template from root disk and check correct usage is + generated for template with correct size + # 7. Delete the template and verify that usage is stopped for + template + # 8. Create volume from snaopshot and verify correct disk usage + is generated + # 9. Delete the volume and verify that the usage is stopped + # 10. Create template from snapshot and verify correct usage + is generated for the template with correct size + """ + + # Step 1 + # Create dynamic and static service offering + self.testdata["service_offering"]["cpunumber"] = "" + self.testdata["service_offering"]["cpuspeed"] = "" + self.testdata["service_offering"]["memory"] = "" + + serviceOffering_dynamic = ServiceOffering.create( + self.apiclient, + self.testdata["service_offering"] + ) + self.cleanup.append(serviceOffering_dynamic) + + customcpunumber = 1 + customcpuspeed = 256 + custommemory = 128 + + # Deploy VM with dynamic service offering + virtualMachine = VirtualMachine.create( + self.userapiclient, + self.testdata["virtual_machine"], + serviceofferingid=serviceOffering_dynamic.id, + templateid=self.template.id, + zoneid=self.zone.id, + accountid=self.account.name, + domainid=self.account.domainid, + customcpunumber=customcpunumber, + customcpuspeed=customcpuspeed, + custommemory=custommemory + ) + + # Stop VM and verify that it is in stopped state + virtualMachine.stop(self.userapiclient) + + scaledcpunumber = 2 + scaledcpuspeed = 512 + scaledmemory = 256 + + # Scale up VM + virtualMachine.scale( + self.userapiclient, + serviceOfferingId=serviceOffering_dynamic.id, + customcpunumber=scaledcpunumber, + customcpuspeed=scaledcpuspeed, + custommemory=scaledmemory + ) + + self.listUsageRecords(usagetype=1) + + qresultset = self.dbclient.execute( + "select cpu_cores, memory, cpu_speed from usage_vm_instance where vm_name = '%s';" % + str(virtualMachine.name), db="cloud_usage") + self.assertNotEqual( + len(qresultset), + 0, + "Check DB Query result set" + ) + dbcpucores = qresultset[-1][0] + dbmemory = qresultset[-1][1] + dbcpuspeed = qresultset[-1][2] + + self.assertEqual(int(dbcpucores), scaledcpunumber, + "scaled cpu number not matching with db record") + + self.assertEqual(int(dbmemory), scaledmemory, + "scaled memory not matching with db record") + + self.assertEqual(int(dbcpuspeed), scaledcpuspeed, + "scaled cpu speed not matching with db record") + + scaledcpunumber = 1 + scaledcpuspeed = 512 + scaledmemory = 256 + + # Step 2 + # Scale down VM + virtualMachine.scale( + self.userapiclient, + serviceOfferingId=serviceOffering_dynamic.id, + customcpunumber=scaledcpunumber, + customcpuspeed=scaledcpuspeed, + custommemory=scaledmemory + ) + + self.listUsageRecords(usagetype=1) + + qresultset = self.dbclient.execute( + "select cpu_cores, memory, cpu_speed from usage_vm_instance where vm_name = '%s';" % + str(virtualMachine.name), db="cloud_usage") + self.assertNotEqual( + len(qresultset), + 0, + "Check DB Query result set" + ) + dbcpucores = qresultset[-1][0] + dbmemory = qresultset[-1][1] + dbcpuspeed = qresultset[-1][2] + + self.assertEqual(int(dbcpucores), scaledcpunumber, + "scaled cpu number not matching with db record") + + self.assertEqual(int(dbmemory), scaledmemory, + "scaled memory not matching with db record") + + self.assertEqual(int(dbcpuspeed), scaledcpuspeed, + "scaled cpu speed not matching with db record") + + disk_offering = DiskOffering.create( + self.apiclient, + self.testdata["disk_offering"] + ) + self.cleanup.append(disk_offering) + + # Step 3 + volume = Volume.create( + self.userapiclient, self.testdata["volume"], + zoneid=self.zone.id, account=self.account.name, + domainid=self.account.domainid, diskofferingid=disk_offering.id + ) + + # Create VM in account + virtual_machine = VirtualMachine.create( + self.userapiclient, + self.testdata["small"], + templateid=self.template.id, + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id, + zoneid=self.zone.id + ) + + virtual_machine.attach_volume(self.userapiclient, volume=volume) + + # Verifying usage for Volume - START + response = self.listUsageRecords(usagetype=6) + self.assertEqual(response[0], PASS, response[1]) + volumeUsageRecords = [record for record in response[1] + if volume.id == record.usageid] + + self.assertTrue( + len(volumeUsageRecords) >= 1, + "Volume usage record for attached volume is not generated") + + volumeRawUsageBeforeDetach = sum(float(record.rawusage) for + record in [ + record for record in volumeUsageRecords + if volume.id == record.usageid]) + + # Getting last usage job execution time + response = self.getLatestUsageJobExecutionTime() + self.assertEqual(response[0], PASS, response[1]) + lastUsageJobExecTime = response[1] + + # Checking exact Volume creation time + response = self.getEventCreatedDateTime(volume.name) + self.assertEqual(response[0], PASS, response[1]) + volumeCreatedDateTime = response[1] + self.debug("Volume creation date: %s" % volumeCreatedDateTime) + + # We have to get the expected usage count in hours as the rawusage returned by listUsageRecords + # is also in hours + expectedUsage = format( + ((lastUsageJobExecTime - volumeCreatedDateTime).total_seconds() / 3600), + ".2f") + self.debug("Volume expected usage: %s" % expectedUsage) + + actualUsage = format(volumeRawUsageBeforeDetach, ".2f") + + self.assertEqual( + expectedUsage, + actualUsage, + "expected usage %s and actual usage %s not matching" % + (expectedUsage, + actualUsage)) + + # Verifying usage for Volume - END + + # Step 4 + virtual_machine.detach_volume(self.userapiclient, volume=volume) + + # Verifying usage for Volume after detaching - START + response = self.listUsageRecords(usagetype=6) + self.assertEqual(response[0], PASS, response[1]) + volumeUsageRecords = response[1] + + volumeRawUsageAfterDetach_time_1 = sum(float(record.rawusage) for + record in [ + record for record in volumeUsageRecords + if volume.id == record.usageid]) + + response = self.listUsageRecords(usagetype=6) + self.assertEqual(response[0], PASS, response[1]) + volumeUsageRecords = response[1] + + volumeRawUsageAfterDetach_time_2 = sum(float(record.rawusage) for + record in [ + record for record in volumeUsageRecords + if volume.id == record.usageid]) + + self.debug(volumeRawUsageAfterDetach_time_1) + self.debug(volumeRawUsageAfterDetach_time_2) + + self.assertTrue( + volumeRawUsageAfterDetach_time_1 < + volumeRawUsageAfterDetach_time_2, + "Raw volume usage should continue running after detach operation" + ) + + # Verifying usage for Volume after detaching - END + + volumes = Volume.list( + self.userapiclient, + virtualmachineid=virtual_machine.id, + type='ROOT', + listall=True + ) + self.assertEqual( + validateList(volumes)[0], + PASS, + "Volumes list validation failed" + ) + + rootVolume = volumes[0] + + # Step 5 + # Create a snapshot from the ROOTDISK + snapshotFromRootVolume = Snapshot.create( + self.userapiclient, + rootVolume.id) + + + # Verifying usage for Snapshot - START + response = self.listUsageRecords(usagetype=9) + self.assertEqual(response[0], PASS, response[1]) + snapshotUsageRecords = [record for record in response[1] + if snapshotFromRootVolume.id == record.usageid] + + self.assertEqual(snapshotUsageRecords[0].size, + snapshotFromRootVolume.physicalsize, + "The snapshot size in the usage record and \ + does not match with the created snapshot size") + + # Getting last usage job execution time + response = self.getLatestUsageJobExecutionTime() + self.assertEqual(response[0], PASS, response[1]) + lastUsageJobExecTime = response[1] + + # Checking exact snapshot creation time + response = self.getEventCreatedDateTime(snapshotFromRootVolume.name) + self.assertEqual(response[0], PASS, response[1]) + snapshotCreatedDateTime = response[1] + self.debug("Snapshot creation date: %s" % snapshotCreatedDateTime) + + # We have to get the expected usage count in hours as the rawusage returned by listUsageRecords + # is also in hours + expectedUsage = format( + ((lastUsageJobExecTime - snapshotCreatedDateTime).total_seconds() / 3600), + ".2f") + + actualUsage = format(sum(float(record.rawusage) + for record in snapshotUsageRecords), ".2f") + + self.assertEqual( + expectedUsage, + actualUsage, + "expected usage %s and actual usage %s not matching" % + (expectedUsage, + actualUsage)) + + # Verifying usage for Snapshot - END + + virtual_machine.stop(self.userapiclient) + + # Step 6 + templateFromVolume = Template.create( + self.userapiclient, + self.testdata["templates"], + rootVolume.id, + self.account.name, + self.account.domainid + ) + + templates = Template.list( + self.userapiclient, + listall=True, + id=templateFromVolume.id, + templatefilter="self" + ) + + self.assertEqual( + validateList(templates)[0], + PASS, + "templates list validation failed" + ) + + # Verifying usage for Template - START + response = self.listUsageRecords(usagetype=7) + self.assertEqual(response[0], PASS, response[1]) + templateUsageRecords = [record for record in response[1] + if templateFromVolume.id == record.usageid] + + self.assertEqual(templateUsageRecords[0].virtualsize, + templates[-1].size, + "The template size in the usage record and \ + does not match with the created template size") + + templateRawUsage = sum(float(record.rawusage) + for record in templateUsageRecords) + + # Getting last usage job execution time + response = self.getLatestUsageJobExecutionTime() + self.assertEqual(response[0], PASS, response[1]) + lastUsageJobExecTime = response[1] + + # Checking exact Template creation time + response = self.getEventCreatedDateTime(templateFromVolume.name) + self.assertEqual(response[0], PASS, response[1]) + templateCreatedDateTime = response[1] + self.debug("Template creation date: %s" % templateCreatedDateTime) + + # We have to get the expected usage count in hours as the rawusage returned by listUsageRecords + # is also in hours + expectedUsage = format( + ((lastUsageJobExecTime - templateCreatedDateTime).total_seconds() / 3600), + ".2f") + self.debug("Template expected usage: %s" % expectedUsage) + + actualUsage = format(templateRawUsage, ".2f") + + self.assertEqual( + expectedUsage, + actualUsage, + "expected usage %s and actual usage %s not matching" % + (expectedUsage, + actualUsage)) + + # Verifying usage for Template - END + + # Step 7 + templateFromVolume.delete(self.userapiclient) + + + # Verifying usage for Template is stoppd after deleting it - START + response = self.listUsageRecords(usagetype=7) + self.assertEqual(response[0], PASS, response[1]) + templateUsageRecords = response[1] + + usageForTemplateFromVolumeAfterDeletion_1 = sum( + float( + record.rawusage) for record in [ + record for record in templateUsageRecords + if templateFromVolume.id == record.usageid]) + + response = self.listUsageRecords(usagetype=7) + self.assertEqual(response[0], PASS, response[1]) + templateUsageRecords = response[1] + + usageForTemplateFromVolumeAfterDeletion_2 = sum( + float( + record.rawusage) for record in [ + record for record in templateUsageRecords + if templateFromVolume.id == record.usageid]) + + self.assertTrue(usageForTemplateFromVolumeAfterDeletion_1 == + usageForTemplateFromVolumeAfterDeletion_2, + "usage for template after deletion should remain the same\ + after specific intervals of time") + + # Verifying usage for Template is stoppd after deleting it - END + + # Step 8 + self.testdata["volume_from_snapshot"]["zoneid"] = self.zone.id + + volumeFromSnapshot = Volume.create_from_snapshot( + self.userapiclient, + snapshot_id=snapshotFromRootVolume.id, + services=self.testdata["volume_from_snapshot"], + account=self.account.name, + domainid=self.account.domainid + ) + + # Verifying usage for Volume from Snapshot - START + response = self.listUsageRecords(usagetype=6) + self.assertEqual(response[0], PASS, response[1]) + volumeUsageRecords = response[1] + + usageForVolumeFromSnapshotBeforeDeletion = sum( + float( + record.rawusage) for record in [ + record for record in volumeUsageRecords + if volumeFromSnapshot.id == record.usageid]) + + self.debug(usageForVolumeFromSnapshotBeforeDeletion) + + # Getting last usage job execution time + response = self.getLatestUsageJobExecutionTime() + self.assertEqual(response[0], PASS, response[1]) + lastUsageJobExecTime = response[1] + + # Checking exact Volume creation time + response = self.getEventCreatedDateTime(volumeFromSnapshot.name) + self.assertEqual(response[0], PASS, response[1]) + volumeCreatedDateTime = response[1] + self.debug("Volume creation date: %s" % volumeCreatedDateTime) + + # We have to get the expected usage count in hours as the rawusage returned by listUsageRecords + # is also in hours + expectedUsage = format( + ((lastUsageJobExecTime - volumeCreatedDateTime).total_seconds() / 3600), + ".2f") + self.debug("Volume expected usage: %s" % expectedUsage) + + actualUsage = format(usageForVolumeFromSnapshotBeforeDeletion, ".2f") + + self.assertEqual( + expectedUsage, + actualUsage, + "expected usage %s and actual usage %s not matching" % + (expectedUsage, + actualUsage)) + + # Verifying usage for Volume from Snapshot - END + + # Step 9 + volumeFromSnapshot.delete(self.userapiclient) + + + # Verifying usage for Volume from Snapshot is stopped after delete - START + response = self.listUsageRecords(usagetype=6) + self.assertEqual(response[0], PASS, response[1]) + volumeUsageRecords = response[1] + + usageForVolumeFromSnapshotAfterDeletion_1 = sum( + float( + record.rawusage) for record in [ + record for record in volumeUsageRecords + if volumeFromSnapshot.id == record.usageid]) + + response = self.listUsageRecords(usagetype=6) + self.assertEqual(response[0], PASS, response[1]) + volumeUsageRecords = response[1] + + usageForVolumeFromSnapshotAfterDeletion_2 = sum( + float( + record.rawusage) for record in [ + record for record in volumeUsageRecords + if volumeFromSnapshot.id == record.usageid]) + + self.debug(usageForVolumeFromSnapshotAfterDeletion_1) + self.debug(usageForVolumeFromSnapshotAfterDeletion_2) + + self.assertTrue(usageForVolumeFromSnapshotAfterDeletion_1 == + usageForVolumeFromSnapshotAfterDeletion_2, + "usage for volume after deletion should remain the same\ + after specific intervals of time") + + # Verifying usage for Volume from Snapshot is stopped after delete - END + + # Step 10 + templateFromSnapshot = Template.create_from_snapshot( + self.userapiclient, + snapshotFromRootVolume, + self.testdata["privatetemplate"] + ) + + templates = Template.list( + self.userapiclient, + listall=True, + id=templateFromSnapshot.id, + templatefilter="self" + ) + + self.assertEqual( + validateList(templates)[0], + PASS, + "templates list validation failed" + ) + + # Verifying usage for Template from Snapshot - START + response = self.listUsageRecords(usagetype=7) + self.assertEqual(response[0], PASS, response[1]) + usageRecords = response[1] + + templateUsageRecords = [record for record in usageRecords + if templateFromSnapshot.id == record.usageid] + + self.assertTrue(len(templateUsageRecords) >= 1, + "template usage record list is empty") + + self.assertEqual(templateUsageRecords[-1].virtualsize, + templates[0].size, + "The template size in the usage record and \ + does not match with the created template size") + + templateRawUsage = sum(float(record.rawusage) + for record in templateUsageRecords) + + # Getting last usage job execution time + response = self.getLatestUsageJobExecutionTime() + self.assertEqual(response[0], PASS, response[1]) + lastUsageJobExecTime = response[1] + + # Checking exact Template creation time + response = self.getEventCreatedDateTime(templateFromSnapshot.name) + self.assertEqual(response[0], PASS, response[1]) + templateCreatedDateTime = response[1] + self.debug("Template creation date: %s" % templateCreatedDateTime) + + # We have to get the expected usage count in hours as the rawusage returned by listUsageRecords + # is also in hours + expectedUsage = format( + ((lastUsageJobExecTime - templateCreatedDateTime).total_seconds() / 3600), + ".2f") + self.debug("Template expected usage: %s" % expectedUsage) + + actualUsage = format(templateRawUsage, ".2f") + + self.assertEqual( + expectedUsage, + actualUsage, + "expected usage %s and actual usage %s not matching" % + (expectedUsage, + actualUsage)) + + # Verifying usage for Template from Snapshot - END + + templateFromSnapshot.delete(self.userapiclient) + + # Verifying usage for Template from Snapshot is stopped after delete - START + response = self.listUsageRecords(usagetype=7) + self.assertEqual(response[0], PASS, response[1]) + templateUsageRecords = response[1] + + usageForTemplateAfterDeletion_1 = sum( + float( + record.rawusage) for record in [ + record for record in templateUsageRecords + if templateFromSnapshot.id == record.usageid]) + + response = self.listUsageRecords(usagetype=7) + self.assertEqual(response[0], PASS, response[1]) + templateUsageRecords = response[1] + + usageForTemplateAfterDeletion_2 = sum( + float( + record.rawusage) for record in [ + record for record in templateUsageRecords + if templateFromSnapshot.id == record.usageid]) + + self.assertTrue(usageForTemplateAfterDeletion_1 == + usageForTemplateAfterDeletion_2, + "usage for volume after deletion should remain the same\ + after specific intervals of time") + + # Verifying usage for Template from Snapshot is stopped after delete - END + + snapshotFromRootVolume.delete(self.userapiclient) + + # Verifying usage for Snapshot from volume is stopped after delete - START + response = self.listUsageRecords(usagetype=9) + self.assertEqual(response[0], PASS, response[1]) + templateUsageRecords = response[1] + + usageForSnapshotAfterDeletion_1 = sum( + float( + record.rawusage) for record in [ + record for record in templateUsageRecords + if snapshotFromRootVolume.id == record.usageid]) + + response = self.listUsageRecords(usagetype=9) + self.assertEqual(response[0], PASS, response[1]) + templateUsageRecords = response[1] + + usageForSnapshotAfterDeletion_2 = sum( + float( + record.rawusage) for record in [ + record for record in templateUsageRecords + if snapshotFromRootVolume.id == record.usageid]) + + self.assertTrue(usageForSnapshotAfterDeletion_1 == + usageForSnapshotAfterDeletion_2, + "usage for volume after deletion should remain the same\ + after specific intervals of time") + + # Verifying usage for Snapshot from volume is stopped after delete - END + return + + @attr(tags=["advanced"], required_hardware="true") + def test_03_positive_tests_usage(self): + """ Positive test for usage test path T28 - T35 + + Steps: + # 1. Add an isolated network to VM and verify that network offering + usage is generated for account + Also verify that IP usage is generated for source NAT IP of + network + # 2. Enabled VPN on source nat IP of default network of VM + # 3. Add two VPN users and check that usage is generated for VPN users + # 4. Acquire public IP in the network and verify that IP usage + is generated for the acquired IP + # 5. Create two PF rules on this IP and verify that PF rules usage + is generated for the account + # 6. Acquire another IP and enabled static NAT on it and create + egress firewall rule on it + # 7. Verify IP usage is generated for above acquired IP + # 8. SSH to VM with above IP and ping to google.com + # 9. Verify that Network bytes usage is generated for account + and it matches with the actual number of bytes + # 10. Repeat the same for other acquired IP + # 11. Delete one of the PF rules and verify that usage is stopped for the PF rule + # 12. Also verify that usage is not stopped for other PF rule which + # is still present + """ + + # Step 1 + # Create VM in account + virtual_machine = VirtualMachine.create( + self.userapiclient, + self.testdata["small"], + templateid=self.template.id, + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id, + zoneid=self.zone.id + ) + + self.testdata["isolated_network"]["zoneid"] = self.zone.id + isolated_network = Network.create( + self.userapiclient, + self.testdata["isolated_network"], + self.account.name, + self.account.domainid, + networkofferingid=self.isolated_network_offering_2.id) + + virtual_machine.add_nic(self.userapiclient, isolated_network.id) + + # Usages for steps are checked together in batch after the operations are done + # to avoid waiting for usage job to run for each operation separately + + # Listing source nat ip of newly added network + ipAddresses = PublicIPAddress.list( + self.apiclient, + associatednetworkid=isolated_network.id, + listall=True) + + sourceNatIP = ipAddresses[0] + + ipAddressesDefaultNetwork = PublicIPAddress.list( + self.apiclient, + associatednetworkid=virtual_machine.nic[0].networkid, + listall=True) + + sourceNatIPDefaultNetwork = ipAddressesDefaultNetwork[0] + + # Step 2 + # Create VPN for source NAT ip + Vpn.create(self.apiclient, + sourceNatIPDefaultNetwork.id, + account=self.account.name, + domainid=self.account.domainid) + + self.debug("Verifying the remote VPN access") + vpns = Vpn.list(self.apiclient, + publicipid=sourceNatIPDefaultNetwork.id, + listall=True) + self.assertEqual( + isinstance(vpns, list), + True, + "List VPNs shall return a valid response" + ) + + # Step 3: + vpnuser_1 = VpnUser.create( + self.apiclient, + self.testdata["vpn_user"]["username"], + self.testdata["vpn_user"]["password"], + account=self.account.name, + domainid=self.account.domainid, + rand_name=True + ) + + vpnuser_2 = VpnUser.create( + self.apiclient, + self.testdata["vpn_user"]["username"], + self.testdata["vpn_user"]["password"], + account=self.account.name, + domainid=self.account.domainid, + rand_name=True + ) + + # Step 4 + public_ip_1 = PublicIPAddress.create( + self.userapiclient, + accountid=virtual_machine.account, + zoneid=virtual_machine.zoneid, + domainid=virtual_machine.domainid, + services=self.testdata["server"], + networkid=virtual_machine.nic[0].networkid + ) + + FireWallRule.create( + self.userapiclient, + ipaddressid=public_ip_1.ipaddress.id, + protocol=self.testdata["fwrule"]["protocol"], + cidrlist=[self.testdata["fwrule"]["cidr"]], + startport=self.testdata["fwrule"]["startport"], + endport=self.testdata["fwrule"]["endport"] + ) + + # Step 5 + self.testdata["natrule"]["startport"] = 22 + self.testdata["natrule"]["endport"] = 22 + + nat_rule_1 = NATRule.create( + self.userapiclient, + virtual_machine, + self.testdata["natrule"], + public_ip_1.ipaddress.id + ) + + self.testdata["natrule"]["privateport"] = 23 + self.testdata["natrule"]["publicport"] = 23 + + nat_rule_2 = NATRule.create( + self.userapiclient, + virtual_machine, + self.testdata["natrule"], + public_ip_1.ipaddress.id + ) + + # Usages for above operations are checked here together + + # Checking usage for source nat IP of added network + response = self.listUsageRecords(usagetype=13) + self.assertEqual(response[0], PASS, response[1]) + usageRecords = response[1] + + nwOfferingUsageRecords = [ + record for record in usageRecords if self.isolated_network_offering_2.id == record.offeringid] + + self.assertTrue(validateList(nwOfferingUsageRecords)[0] == PASS, + "IP usage record list validation failed") + + self.assertTrue(float(nwOfferingUsageRecords[0].rawusage) > 0, + "Raw usage not started for source NAT ip") + + # Checking usage for source nat IP of default VM network + response = self.listUsageRecords(usagetype=3, sleep=False) + self.assertEqual(response[0], PASS, response[1]) + usageRecords = response[1] + + ipUsageRecords = [record for record in usageRecords + if sourceNatIP.id == record.usageid] + + self.assertTrue(validateList(ipUsageRecords)[0] == PASS, + "IP usage record list validation failed") + + self.assertTrue(float(ipUsageRecords[0].rawusage) > 0, + "Raw usage not started for source NAT ip") + + # Checking usage for acquired public IP + response = self.listUsageRecords(usagetype=3, sleep=False) + self.assertEqual(response[0], PASS, response[1]) + usageRecords = response[1] + + ipUsageRecords = [record for record + in usageRecords + if public_ip_1.ipaddress.id == record.usageid + ] + + self.assertTrue(validateList(ipUsageRecords)[0] == PASS, + "IP usage record list validation failed") + + self.assertTrue(float(ipUsageRecords[0].rawusage) > 0, + "Raw usage not started for acquired public ip") + + # Checking usage for NAT rules + response = self.listUsageRecords(usagetype=12, sleep=False) + self.assertEqual(response[0], PASS, response[1]) + usageRecords = response[1] + + natRuleUsageRecords = [record for record in usageRecords + if nat_rule_1.id == record.usageid] + + self.assertTrue(validateList(natRuleUsageRecords)[0] == PASS, + "NAT rule usage record list validation failed") + + self.assertTrue(float(natRuleUsageRecords[0].rawusage) > 0, + "Raw usage not started for nat rule") + + natRuleUsageRecords = [record for record in usageRecords + if nat_rule_2.id == record.usageid] + + self.assertTrue(validateList(natRuleUsageRecords)[0] == PASS, + "NAT rule usage record list validation failed") + + self.assertTrue(float(natRuleUsageRecords[0].rawusage) > 0, + "Raw usage not started for nat rule") + + # Checking VPN usage + response = self.listUsageRecords(usagetype=14, sleep=False) + self.assertEqual(response[0], PASS, response[1]) + usageRecords = response[1] + + vpnUserUsageRecords_1 = [record for record in usageRecords + if vpnuser_1.id == record.usageid] + + self.assertTrue(validateList(vpnUserUsageRecords_1)[0] == PASS, + "VPN user usage record list validation failed") + + vpnuser1_rawusage = sum(float(record.rawusage) + for record in vpnUserUsageRecords_1) + + # Getting last usage job execution time + response = self.getLatestUsageJobExecutionTime() + self.assertEqual(response[0], PASS, response[1]) + lastUsageJobExecTime = response[1] + + # Checking exact VPN user creation time + response = self.getEventCreatedDateTime(vpnuser_1.username) + self.assertEqual(response[0], PASS, response[1]) + vpnUserCreatedDateTime = response[1] + self.debug("VPN creation date: %s" % vpnUserCreatedDateTime) + + # We have to get the expected usage count in hours as the rawusage returned by listUsageRecords + # is also in hours + expectedUsage = format( + ((lastUsageJobExecTime - vpnUserCreatedDateTime).total_seconds() / 3600), + ".2f") + self.debug("VPN user expected usage: %s" % expectedUsage) + + actualUsage = format(vpnuser1_rawusage, ".2f") + + self.assertEqual( + expectedUsage, + actualUsage, + "expected usage %s and actual usage %s not matching" % + (expectedUsage, + actualUsage)) + + vpnUserUsageRecords_2 = [record for record in usageRecords + if vpnuser_2.id == record.usageid] + + self.assertTrue(validateList(vpnUserUsageRecords_2)[0] == PASS, + "VPN user usage record list validation failed") + + vpnuser2_rawusage = sum(float(record.rawusage) + for record in vpnUserUsageRecords_2) + + # Checking exact VPN user creation time + response = self.getEventCreatedDateTime(vpnuser_2.username) + self.assertEqual(response[0], PASS, response[1]) + vpnUserCreatedDateTime = response[1] + self.debug("VPN creation date: %s" % vpnUserCreatedDateTime) + + # We have to get the expected usage count in hours as the rawusage returned by listUsageRecords + # is also in hours + expectedUsage = format( + ((lastUsageJobExecTime - vpnUserCreatedDateTime).total_seconds() / 3600), + ".2f") + self.debug("VPN user expected usage: %s" % expectedUsage) + + actualUsage = format(vpnuser2_rawusage, ".2f") + + self.assertEqual( + expectedUsage, + actualUsage, + "expected usage %s and actual usage %s not matching" % + (expectedUsage, + actualUsage)) + + # Acquire another public IP and check usage + public_ip_2 = PublicIPAddress.create( + self.userapiclient, + accountid=virtual_machine.account, + zoneid=virtual_machine.zoneid, + domainid=virtual_machine.domainid, + services=self.testdata["server"], + networkid=virtual_machine.nic[0].networkid + ) + + # Step 6 + # Enabling static Nat for Ip Address associated + StaticNATRule.enable( + self.userapiclient, + ipaddressid=public_ip_2.ipaddress.id, + virtualmachineid=virtual_machine.id, + ) + + # Step 7 + response = self.listUsageRecords(usagetype=3) + self.assertEqual(response[0], PASS, response[1]) + usageRecords = response[1] + + ipUsageRecords = [record for record + in usageRecords + if public_ip_2.ipaddress.id == record.usageid + ] + + self.assertTrue(validateList(ipUsageRecords)[0] == PASS, + "IP usage record list validation failed") + + self.assertTrue(float(ipUsageRecords[0].rawusage) > 0, + "Raw usage not started for public ip") + + FireWallRule.create( + self.userapiclient, + ipaddressid=public_ip_2.ipaddress.id, + protocol=self.testdata["fwrule"]["protocol"], + cidrlist=[self.testdata["fwrule"]["cidr"]], + startport=self.testdata["fwrule"]["startport"], + endport=self.testdata["fwrule"]["endport"] + ) + + EgressFireWallRule.create( + self.userapiclient, + networkid=virtual_machine.nic[0].networkid, + protocol=self.testdata["icmprule"]["protocol"], + type=self.testdata["icmprule"]["icmptype"], + code=self.testdata["icmprule"]["icmpcode"], + cidrlist=self.testdata["icmprule"]["cidrlist"]) + + # Step 8: + ssh_client = virtual_machine.get_ssh_client( + ipaddress=public_ip_1.ipaddress.ipaddress + ) + + # Ping Internet and check the bytes received + res = ssh_client.execute("ping -c 1 www.google.com") + self.assertEqual( + str(res).count("1 received"), + 1, + "Ping to outside world from VM should be successful" + ) + + routers = list_routers( + self.apiclient, + networkid=virtual_machine.nic[0].networkid, + listall=True + ) + self.assertEqual( + validateList(routers)[0], + PASS, + "Routers list validation failed") + router = routers[0] + + result = self.getCommandResultFromRouter( + router, + "iptables -L NETWORK_STATS -n -v -x") + + self.debug("iptables -L NETWORK_STATS -n -v -x: %s" % result) + + bytesReceivedIptableRows = [record for record in result if + "eth2 eth0" in record] + self.debug("bytes received rows: %s" % bytesReceivedIptableRows) + bytesReceivedOnRouter = sum( + int(record[1]) for record in [x.split() for x in bytesReceivedIptableRows]) + + self.debug( + "Bytes received extracted from router: %s" % + bytesReceivedOnRouter) + + # Step 9: + # Verify that bytes received in usage are equal to + # as shown on router + response = self.listUsageRecords(usagetype=5) + self.assertEqual(response[0], PASS, response[1]) + bytesReceivedUsage = sum( + int(record.rawusage) for record in response[1]) + + self.assertTrue(bytesReceivedUsage == + bytesReceivedOnRouter, + "Total bytes received usage should be \ + equal to bytes received on router") + + # Step 10: + # Repeat the same for other public IP + ssh_client = virtual_machine.get_ssh_client( + ipaddress=public_ip_2.ipaddress.ipaddress + ) + + res = ssh_client.execute("ping -c 1 www.google.com") + self.assertEqual( + str(res).count("1 received"), + 1, + "Ping to outside world from VM should be successful" + ) + result = self.getCommandResultFromRouter( + router, + "iptables -L NETWORK_STATS -n -v -x") + + self.debug("iptables -L NETWORK_STATS -n -v -x: %s" % result) + + bytesReceivedIptableRows = [record for record in result if + "eth2 eth0" in record] + self.debug("bytes received rows: %s" % bytesReceivedIptableRows) + bytesReceivedOnRouter = sum( + int(record[1]) for record in [x.split() for x in bytesReceivedIptableRows]) + + self.debug( + "Bytes received extracted from router: %s" % + bytesReceivedOnRouter) + + # Step 9: + # Verify that bytes received in usage are equal to + # as shown on router + response = self.listUsageRecords(usagetype=5) + self.assertEqual(response[0], PASS, response[1]) + bytesReceivedUsage = sum( + int(record.rawusage) for record in response[1]) + + self.assertTrue(bytesReceivedUsage == + bytesReceivedOnRouter, + "Total bytes received usage should be \ + equal to bytes received on router") + + # Step 11: + # Delete NAT rule and verify that usage is stopped for the NAT rule + nat_rule_1.delete(self.userapiclient) + + response = self.listUsageRecords(usagetype=12, sleep=True) + self.assertEqual(response[0], PASS, response[1]) + usageRecords = response[1] + + natRule_1_Usage_t1 = sum(float(record.rawusage) for record + in [record for record in usageRecords + if nat_rule_1.id == record.usageid]) + + response = self.listUsageRecords(usagetype=12) + self.assertEqual(response[0], PASS, response[1]) + usageRecords = response[1] + + natRule_1_Usage_t2 = sum(float(record.rawusage) for record + in [record for record in usageRecords + if nat_rule_1.id == record.usageid]) + + self.assertTrue( + natRule_1_Usage_t1 == natRule_1_Usage_t2, + "NAT rule usage should be stopped once the rule is deleted") + + # Also verify that usage for other nat rule is running + natRule_2_Usage_t1 = sum(float(record.rawusage) for record + in [record for record in usageRecords + if nat_rule_2.id == record.usageid]) + + # Step 12: + response = self.listUsageRecords(usagetype=12) + self.assertEqual(response[0], PASS, response[1]) + usageRecords = response[1] + + natRule_2_Usage_t2 = sum(float(record.rawusage) for record + in [record for record in usageRecords + if nat_rule_1.id == record.usageid]) + + self.assertTrue(natRule_2_Usage_t1 > natRule_2_Usage_t2, + "NAT rule usage for second rule should be running") + return + + @attr(tags=["advanced"], required_hardware="true") + def test_04_positive_tests_usage(self): + """ Positive test for usage test path + Steps: + # 1. Create a VM in the account + # 2. Acquire public IP in VM network and verify correct usage + is generated for IP + # 3. Create LB rule for the IP address and verify LB rule usage + is generated for the account + # 4. Create another LB rule with different ports and verify + seperate usage is generated for new LB rule + + # 5. Create egress firewall rule for VM and SSH to VM + # 6. Ping external network from the VM and verify that + network byte usage is genrated correctly + # 7. Delete one LB rule and verify that the usage + is stopped for the LB rule + # 8. Stop the network router and + # Verify iptables counters are reset when domR stops + # Verify current_bytes in user_statistics table are moved to + net_bytes + # Verify currnt_bytes becomes zero + # 9. Start the router and + # Verify iptables counters are reset when domR starts + # Verify a diff of total (current_bytes + net_bytes) in previous + aggregation period and current period will give the network usage + + """ + + # Step 1 + # Create VM in account + virtual_machine = VirtualMachine.create( + self.userapiclient, + self.testdata["small"], + templateid=self.template.id, + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id, + zoneid=self.zone.id + ) + + # Step 2 + public_ip_1 = PublicIPAddress.create( + self.userapiclient, + accountid=virtual_machine.account, + zoneid=virtual_machine.zoneid, + domainid=virtual_machine.domainid, + services=self.testdata["server"] + ) + + self.testdata["lbrule"]["privateport"] = 22 + self.testdata["lbrule"]["publicport"] = 2222 + publicport = self.testdata["lbrule"]["publicport"] + + # Step 3 + # Create LB Rule + lbrule_1 = LoadBalancerRule.create( + self.apiclient, + self.testdata["lbrule"], + ipaddressid=public_ip_1.ipaddress.id, + accountid=self.account.name, + networkid=virtual_machine.nic[0].networkid, + domainid=self.account.domainid) + + self.testdata["lbrule"]["privateport"] = 23 + self.testdata["lbrule"]["publicport"] = 2223 + + # Step 4 + # Create another LB Rule + lbrule_2 = LoadBalancerRule.create( + self.apiclient, + self.testdata["lbrule"], + ipaddressid=public_ip_1.ipaddress.id, + accountid=self.account.name, + networkid=virtual_machine.nic[0].networkid, + domainid=self.account.domainid) + + response = self.listUsageRecords(usagetype=3) + self.assertEqual(response[0], PASS, response[1]) + usageRecords = response[1] + + ipUsageRecords = [record for record in usageRecords + if public_ip_1.ipaddress.id == record.usageid + ] + + self.assertTrue(validateList(ipUsageRecords)[0] == PASS, + "IP usage record list validation failed") + + self.assertTrue(float(ipUsageRecords[0].rawusage) > 0, + "Raw usage not started for ip address") + + response = self.listUsageRecords(usagetype=11, sleep=False) + self.assertEqual(response[0], PASS, response[1]) + usageRecords = response[1] + + lbRule_1_UsageRecords = [record for record in usageRecords + if lbrule_1.id == record.usageid] + + self.assertTrue(validateList(lbRule_1_UsageRecords)[0] == PASS, + "LB rule usage record list validation failed") + + self.assertTrue(float(lbRule_1_UsageRecords[0].rawusage) > 0, + "LB usage not started for nat rule") + + lbRule_2_UsageRecords = [record for record in usageRecords + if lbrule_2.id == record.usageid] + + self.assertTrue(validateList(lbRule_2_UsageRecords)[0] == PASS, + "LB rule usage record list validation failed") + + self.assertTrue(float(lbRule_2_UsageRecords[0].rawusage) > 0, + "LB usage not started for nat rule") + + # Step 5 + EgressFireWallRule.create( + self.userapiclient, + networkid=virtual_machine.nic[0].networkid, + protocol=self.testdata["icmprule"]["protocol"], + type=self.testdata["icmprule"]["icmptype"], + code=self.testdata["icmprule"]["icmpcode"], + cidrlist=self.testdata["icmprule"]["cidrlist"]) + + lbrule_1.assign(self.userapiclient, [virtual_machine]) + + ssh_client = virtual_machine.get_ssh_client( + ipaddress=public_ip_1.ipaddress.ipaddress, + port=publicport + ) + + # Step 6 + res = ssh_client.execute("ping -c 1 www.google.com") + self.assertEqual( + str(res).count("1 received"), + 1, + "Ping to outside world from VM should be successful" + ) + + # Verifying usage for bytes received - START + routers = list_routers( + self.apiclient, + networkid=virtual_machine.nic[0].networkid, + listall=True + ) + self.assertEqual( + validateList(routers)[0], + PASS, + "Routers list validation failed") + router = routers[0] + result = self.getCommandResultFromRouter( + router, + "iptables -L NETWORK_STATS -n -v -x") + + self.debug("iptables -L NETWORK_STATS -n -v -x: %s" % result) + + bytesReceivedIptableRows = [record for record in result if + "eth2 eth0" in record] + self.debug("bytes received rows: %s" % bytesReceivedIptableRows) + bytesReceivedOnRouter = sum( + int(record[1]) for record in [x.split() for x in bytesReceivedIptableRows]) + + self.debug( + "Bytes received extracted from router: %s" % + bytesReceivedOnRouter) + + # Verify that bytes received in usage are equal to + # as shown on router + response = self.listUsageRecords(usagetype=5) + self.assertEqual(response[0], PASS, response[1]) + bytesReceivedUsage = sum( + int(record.rawusage) for record in response[1]) + + self.assertTrue(bytesReceivedUsage == + bytesReceivedOnRouter, + "Total bytes received usage should be \ + equal to bytes received on router") + + # Verifying usage for bytes received - END + + lbrule_1.delete(self.userapiclient) + # Step 7 Verify that usage is stopped for the LB rule + + response = self.listUsageRecords(usagetype=11) + self.assertEqual(response[0], PASS, response[1]) + lbUsageRecords = response[1] + + usageForLbRuleAfterDeletion_t1 = sum( + float( + record.rawusage) for record in [ + record for record in lbUsageRecords + if lbrule_1.id == record.usageid]) + + response = self.listUsageRecords(usagetype=11) + self.assertEqual(response[0], PASS, response[1]) + lbUsageRecords = response[1] + + usageForLbRuleAfterDeletion_t2 = sum( + float( + record.rawusage) for record in [ + record for record in lbUsageRecords + if lbrule_1.id == record.usageid]) + + self.assertTrue(usageForLbRuleAfterDeletion_t1 == + usageForLbRuleAfterDeletion_t2, + "usage for LB rule after deletion should remain the same\ + after specific intervals of time") + + qresultset = self.dbclient.execute( + "select id from account where account_name = '%s';" + % self.account.name + ) + accountid = qresultset[0][0] + self.debug("accountid: %s" % accountid) + + qresultset = self.dbclient.execute( + "select current_bytes_sent, current_bytes_received from user_statistics where account_id = '%s';" % + accountid, + db="cloud_usage")[0] + + currentBytesSentBeforeRouterStop = qresultset[0] + currentBytesReceivedBeforeRouterStop = qresultset[1] + + self.debug(currentBytesSentBeforeRouterStop) + self.debug(currentBytesReceivedBeforeRouterStop) + + # Step 8 + routers = Router.list( + self.apiclient, + account=self.account.name, + domainid=self.account.domainid, + ) + + self.assertEqual( + validateList(routers)[0], + PASS, + "Check for list routers response return valid data" + ) + router = routers[0] + + # Stop the router + Router.stop( + self.apiclient, + id=router.id + ) + + response = verifyRouterState( + self.apiclient, + router.id, + "stopped") + self.assertEqual(response[0], PASS, response[1]) + + qresultset = self.dbclient.execute( + "select current_bytes_sent, current_bytes_received, net_bytes_sent, net_bytes_received from user_statistics where account_id = '%s';" % + accountid, + db="cloud_usage")[0] + + currentBytesSentAfterRouterStop = int(qresultset[0]) + currentBytesReceivedAfterRouterStop = int(qresultset[1]) + netBytesSentAfterRouterStop = int(qresultset[0]) + netBytesReceivedAfterRouterStop = int(qresultset[1]) + + self.debug(currentBytesSentAfterRouterStop) + self.debug(currentBytesReceivedAfterRouterStop) + self.debug(netBytesSentAfterRouterStop) + self.debug(netBytesReceivedAfterRouterStop) + + self.assertTrue( + (currentBytesSentAfterRouterStop + + currentBytesReceivedAfterRouterStop) == 0, + "Current bytes should be 0") + + self.assertTrue( + (currentBytesSentBeforeRouterStop + + currentBytesReceivedBeforeRouterStop) == ( + netBytesSentAfterRouterStop + + netBytesReceivedAfterRouterStop), + "current bytes should be moved to net bytes") + + # TODO: Verify iptables counters are reset when domR starts + + # Step 9 + # Start the router + Router.start( + self.apiclient, + id=router.id + ) + + response = verifyRouterState( + self.apiclient, + router.id, + "running") + self.assertEqual(response[0], PASS, response[1]) + + # TODO: Verify iptables counters are reset when domR starts + # Verify a diff of total (current_bytes + net_bytes) in previous + # aggregation period and current period will give the network usage + return + + @attr(tags=["advanced"], required_hardware="true") + def test_05_positive_tests_usage(self): + """ Positive test for usage test path T61 - T62 + Steps: + # 1. Deploy a VM + # 2. Take Vm snapshot and verify usage is generated for VM snapshot + # 3. Delete VM snapshot and verify that usage stops + """ + + time.sleep(180) + + if self.hypervisor.lower() in ['kvm', 'hyperv']: + self.skipTest("This feature is not supported on %s" % + self.hypervisor) + + # Step 1 + # Create VM in account + virtual_machine = VirtualMachine.create( + self.userapiclient, + self.testdata["small"], + templateid=self.template.id, + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id, + zoneid=self.zone.id + ) + + # Step 2 + vmsnapshot = VmSnapshot.create( + self.userapiclient, + virtual_machine.id) + + response = self.listUsageRecords(usagetype=25) + self.assertEqual(response[0], PASS, response[1]) + + # Step 3 + VmSnapshot.deleteVMSnapshot( + self.userapiclient, + vmsnapshot.id + ) + + response = self.listUsageRecords(usagetype=25) + self.assertEqual(response[0], PASS, response[1]) + vmSnapshotUsageRecords_t1 = response[1] + + vmSnapshotUsage_t1 = sum(float(record.rawusage) + for record in vmSnapshotUsageRecords_t1) + + response = self.listUsageRecords(usagetype=25) + self.assertEqual(response[0], PASS, response[1]) + vmSnapshotUsageRecords_t2 = response[1] + + vmSnapshotUsage_t2 = sum(float(record.rawusage) + for record in vmSnapshotUsageRecords_t2) + + self.debug(vmSnapshotUsage_t1) + self.debug(vmSnapshotUsage_t2) + + self.assertEqual( + vmSnapshotUsage_t1, + vmSnapshotUsage_t2, + "VmSnapshot usage should remain the same\ +
<TRUNCATED>