This is an automated email from the ASF dual-hosted git repository.

rohit pushed a commit to branch 4.11
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/4.11 by this push:
     new f6e600e  CLOUDSTACK-3009: Fix resource calculation CPU, RAM for 
accounts. (#3012)
f6e600e is described below

commit f6e600e4d8134dd317ec8444ccf259285932dd50
Author: Bitworks LLC <[email protected]>
AuthorDate: Mon Nov 12 19:59:08 2018 -0500

    CLOUDSTACK-3009: Fix resource calculation CPU, RAM for accounts. (#3012)
    
    The view "service_offering_view" doesn't include removed SOs, as a result 
when SO is removed, the bug happens. The PR introduces a change for resource 
calculation changing "service_offering_view" to "service_offering" table which 
has all service offerings.
    
    Must be fixed in:
    
    4.12
    4.11
    Fixes: #3009
---
 .dockerignore                                      |  22 ++
 .gitignore                                         |   1 +
 .travis.yml                                        |   1 +
 .../configuration/dao/ResourceCountDaoImpl.java    |   2 +-
 .../integration/component/test_browse_templates.py |  10 +-
 test/integration/smoke/test_resource_accounting.py | 243 +++++++++++++++++++++
 6 files changed, 273 insertions(+), 6 deletions(-)

diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..6ca3ad4
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,22 @@
+# 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.
+
+cloudstack/tools/docker/Dockerfile
+.dockerignore
+.idea
+.git
+venv
diff --git a/.gitignore b/.gitignore
index 1a73724..2f5c516 100644
--- a/.gitignore
+++ b/.gitignore
@@ -99,3 +99,4 @@ plugins/hypervisors/kvm/.pydevproject
 scripts/.pydevproject
 *.qcow2
 *.raw
+venv
diff --git a/.travis.yml b/.travis.yml
index d5fd173..43f2bb2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -78,6 +78,7 @@ env:
              smoke/test_pvlan
              smoke/test_regions
              smoke/test_reset_vm_on_reboot
+             smoke/test_resource_accounting
              smoke/test_resource_detail
              smoke/test_router_dhcphosts
              smoke/test_router_dns
diff --git 
a/engine/schema/src/com/cloud/configuration/dao/ResourceCountDaoImpl.java 
b/engine/schema/src/com/cloud/configuration/dao/ResourceCountDaoImpl.java
index 9cc8913..1de2b65 100644
--- a/engine/schema/src/com/cloud/configuration/dao/ResourceCountDaoImpl.java
+++ b/engine/schema/src/com/cloud/configuration/dao/ResourceCountDaoImpl.java
@@ -258,7 +258,7 @@ public class ResourceCountDaoImpl extends 
GenericDaoBase<ResourceCountVO, Long>
             + "        ELSE CONVERT(vmd.value, UNSIGNED INTEGER) "
             + "    END)) as total "
             + " from vm_instance vm "
-            + " join service_offering_view so on so.id = 
vm.service_offering_id "
+            + " join service_offering so on so.id = vm.service_offering_id "
             + " left join user_vm_details vmd on vmd.vm_id = vm.id and 
vmd.name = '%s' "
             + " where vm.type = 'User' and state not in ('Destroyed', 'Error', 
'Expunging') and display_vm = true and account_id = ? ";
 
diff --git a/test/integration/component/test_browse_templates.py 
b/test/integration/component/test_browse_templates.py
index 80e9a13..4340092 100644
--- a/test/integration/component/test_browse_templates.py
+++ b/test/integration/component/test_browse_templates.py
@@ -230,7 +230,7 @@ class TestBrowseUploadVolume(cloudstackTestCase):
 
         return(totaltemplates)
 
-    def getstoragelimts(self,rtype):
+    def getstoragelimits(self, rtype):
 
         cmd=updateResourceCount.updateResourceCountCmd()
         cmd.account=self.account.name
@@ -1652,7 +1652,7 @@ class TestBrowseUploadVolume(cloudstackTestCase):
 
             self.debug("========================= Test 22 Upload template and 
verify secondary storage limits========================")
 
-            initialsecondarystoragelimit=self.getstoragelimts(11)
+            initialsecondarystoragelimit=self.getstoragelimits(11)
             browseup_template1=self.browse_upload_template()
 
             tmpldetails=Template.list(
@@ -1662,7 +1662,7 @@ class TestBrowseUploadVolume(cloudstackTestCase):
                                      zoneid=self.zone.id)
 
 
-            afteruploadsecondarystoragelimit=self.getstoragelimts(11)
+            afteruploadsecondarystoragelimit=self.getstoragelimits(11)
 
             if 
afteruploadsecondarystoragelimit!=(initialsecondarystoragelimit+tmpldetails[0].size):
                 self.fail("Secondary Storage Resouce Count is not updated")
@@ -1709,10 +1709,10 @@ class TestBrowseUploadVolume(cloudstackTestCase):
                                      templatefilter="all",
                                      zoneid=self.zone.id)
 
-            initialuploadprimarystoragelimit=self.getstoragelimts(11)
+            initialuploadprimarystoragelimit=self.getstoragelimits(11)
             self.delete_template(browseup_template1)
 
-            afteruploadprimarystoragelimit=self.getstoragelimts(11)
+            afteruploadprimarystoragelimit=self.getstoragelimits(11)
 
             if 
afteruploadprimarystoragelimit!=(initialuploadprimarystoragelimit-tmpldetails[0].size):
                 self.fail("Secondary Storage Resource Count is not updated 
after deletion")
diff --git a/test/integration/smoke/test_resource_accounting.py 
b/test/integration/smoke/test_resource_accounting.py
new file mode 100644
index 0000000..043a7af
--- /dev/null
+++ b/test/integration/smoke/test_resource_accounting.py
@@ -0,0 +1,243 @@
+# 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.
+
+from nose.plugins.attrib import attr
+
+# Import Local Modules
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.lib.base import (Domain,
+                             Account,
+                             ServiceOffering,
+                             VirtualMachine, updateResourceCount)
+from marvin.lib.common import (get_zone,
+                               get_test_template)
+from marvin.lib.utils import (cleanup_resources)
+
+
+class Services:
+    """Test Account Services
+    """
+
+    def __init__(self):
+        self.services = {
+            "domain": {
+                "name": "Domain",
+            },
+            "account": {
+                "email": "[email protected]",
+                "firstname": "Test",
+                "lastname": "User",
+                "username": "test",
+                # Random characters are appended for unique
+                # username
+                "password": "fr3sca",
+            },
+            "user": {
+                "email": "[email protected]",
+                "firstname": "User",
+                "lastname": "User",
+                "username": "User",
+                # Random characters are appended for unique
+                # username
+                "password": "fr3sca",
+            },
+            "service_offering_it_1": {
+                "name": "InstanceType-1",
+                "displaytext": "Tiny Instance",
+                "cpunumber": 1,
+                "cpuspeed": 100,
+                "memory": 128,
+            },
+            "service_offering_it_2": {
+                "name": "InstanceType-2",
+                "displaytext": "Tiny Instance",
+                "cpunumber": 2,
+                "cpuspeed": 100,
+                "memory": 512,
+            },
+            "virtual_machine_1": {
+                "displayname": "Test VM1",
+                "username": "root",
+                "password": "password",
+                "ssh_port": 22,
+                "hypervisor": 'XenServer',
+                "privateport": 22,
+                "publicport": 22,
+                "protocol": 'TCP',
+            },
+            "virtual_machine_2": {
+                "displayname": "Test VM2",
+                "username": "root",
+                "password": "password",
+                "ssh_port": 22,
+                "hypervisor": 'XenServer',
+                "privateport": 22,
+                "publicport": 22,
+                "protocol": 'TCP',
+            },
+            "template": {
+                "displaytext": "Public Template",
+                "name": "Public template",
+                "ostype": 'CentOS 5.6 (64-bit)',
+                "url": "",
+                "hypervisor": '',
+                "format": '',
+                "isfeatured": True,
+                "ispublic": True,
+                "isextractable": True,
+                "templatefilter": "self"
+            },
+            "natrule": {
+                "publicport": 22,
+                "privateport": 22,
+                "protocol": 'TCP',
+            },
+            "ostype": 'CentOS 5.6 (64-bit)',
+            "sleep": 60,
+            "timeout": 10,
+        }
+
+
+class TestRAMCPUResourceAccounting(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        cls.testClient = super(
+            TestRAMCPUResourceAccounting,
+            cls).getClsTestClient()
+        cls.api_client = cls.testClient.getApiClient()
+
+        cls.services = Services().services
+        cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls.hypervisor = cls.testClient.getHypervisorInfo()
+        # Create an account, domain etc
+        cls.domain = Domain.create(
+            cls.api_client,
+            cls.services["domain"],
+        )
+        cls.account = Account.create(
+            cls.api_client,
+            cls.services["account"],
+            admin=True,
+            domainid=cls.domain.id
+        )
+
+        cls.template = get_test_template(
+            cls.api_client,
+            cls.zone.id,
+            cls.hypervisor)
+
+        cls.services["virtual_machine_1"]["zoneid"] = cls.zone.id
+        cls.services["virtual_machine_1"]["template"] = cls.template.id
+
+        cls.services["virtual_machine_2"]["zoneid"] = cls.zone.id
+        cls.services["virtual_machine_2"]["template"] = cls.template.id
+
+        cls._cleanup = [
+            cls.account,
+            cls.domain
+        ]
+
+    @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)
+
+    def setUp(self):
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+
+    def tearDown(self):
+        try:
+            # Clean up, terminate the created accounts
+            cleanup_resources(self.apiclient, self.cleanup)
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+
+    def get_resource_amount(self, resource_type):
+        cmd = updateResourceCount.updateResourceCountCmd()
+        cmd.account = self.account.name
+        cmd.domainid = self.domain.id
+        cmd.resourcetype = resource_type
+        response = self.apiclient.updateResourceCount(cmd)
+        amount = response[0].resourcecount
+        return amount
+
+    @attr(tags=["advanced", "basic"], required_hardware="false")
+    def test_01_so_removal_resource_update(self):
+
+        self.service_offering_it_1 = ServiceOffering.create(
+            self.api_client,
+            self.services["service_offering_it_1"],
+            domainid=self.domain.id
+        )
+
+        self.cleanup.append(self.service_offering_it_1)
+
+        self.service_offering_it_2 = ServiceOffering.create(
+            self.api_client,
+            self.services["service_offering_it_2"],
+            domainid=self.domain.id
+        )
+
+        self.cleanup.append(self.service_offering_it_2)
+
+        vm_1 = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine_1"],
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            serviceofferingid=self.service_offering_it_1.id
+        )
+
+        self.debug("Deployed VM in account: %s, ID: %s" % (self.account.name, 
vm_1.id))
+        self.cleanup.append(vm_1)
+
+        vm_2 = VirtualMachine.create(
+            self.apiclient,
+            self.services["virtual_machine_2"],
+            accountid=self.account.name,
+            domainid=self.account.domainid,
+            serviceofferingid=self.service_offering_it_2.id
+        )
+
+        self.debug("Deployed VM in account: %s, ID: %s" % (self.account.name, 
vm_2.id))
+        self.cleanup.append(vm_2)
+
+        CPU_RESOURCE_ID = 8
+        RAM_RESOURCE_ID = 9
+
+        cores = int(self.get_resource_amount(CPU_RESOURCE_ID))
+        ram = int(self.get_resource_amount(RAM_RESOURCE_ID))
+
+        self.assertEqual(cores, 
self.services['service_offering_it_1']['cpunumber'] + 
self.services['service_offering_it_2']['cpunumber'])
+        self.assertEqual(ram, self.services['service_offering_it_1']['memory'] 
+ self.services['service_offering_it_2']['memory'])
+
+        self.service_offering_it_2.delete(self.apiclient)
+
+        self.cleanup = self.cleanup[0:-1]
+
+        cores = int(self.get_resource_amount(CPU_RESOURCE_ID))
+        ram = int(self.get_resource_amount(RAM_RESOURCE_ID))
+
+        self.assertEqual(cores, 
self.services['service_offering_it_1']['cpunumber'] + 
self.services['service_offering_it_2']['cpunumber'])
+        self.assertEqual(ram, self.services['service_offering_it_1']['memory'] 
+ self.services['service_offering_it_2']['memory'])

Reply via email to