Update capacity check API 40/83840/1
authorBin Yang <bin.yang@windriver.com>
Mon, 1 Apr 2019 09:46:31 +0000 (09:46 +0000)
committerBin Yang <bin.yang@windriver.com>
Mon, 1 Apr 2019 09:46:31 +0000 (09:46 +0000)
Query the AZinfo from the cache
Relay on the background thread of AZcap Auditing

Change-Id: I064dbc22c71ef25683145ef1c96274ce6ac74c3b
Issue-ID: MULTICLOUD-542
Signed-off-by: Bin Yang <bin.yang@windriver.com>
share/newton_base/resource/capacity.py
share/starlingx_base/registration/registration.py
share/starlingx_base/resource/__init__.py [new file with mode: 0644]
share/starlingx_base/resource/capacity.py [new file with mode: 0644]

index 1a08b9a..c2fee36 100644 (file)
@@ -35,112 +35,113 @@ class CapacityCheck(APIView):
         self._logger.info("vimid, data> %s, %s" % (vimid, request.data))
         self._logger.debug("META> %s" % request.META)
 
-        hasEnoughResource = False
         try:
-            resource_demand = request.data
-
-            tenant_name = None
-            vim = VimDriverUtils.get_vim_info(vimid)
-            sess = VimDriverUtils.get_session(vim, tenant_name)
-
-            # get token:
-            cloud_owner, regionid = extsys.decode_vim_id(vimid)
-            interface = 'public'
-            service = {'service_type': 'compute',
-                       'interface': interface,
-                       'region_name': vim['openstack_region_id']
-                       if vim.get('openstack_region_id')
-                       else vim['cloud_region_id']
-                       }
-
-            # get limit for this tenant
-            req_resouce = "/limits"
-            self._logger.info("check limits> URI:%s" % req_resouce)
-            resp = sess.get(req_resouce, endpoint_filter=service)
-            self._logger.info("check limits> status:%s" % resp.status_code)
-            content = resp.json()
-            compute_limits = content['limits']['absolute']
-            self._logger.debug("check limits> resp data:%s" % content)
-
-            # get total resource of this cloud region
-            try:
-                req_resouce = "/os-hypervisors/statistics"
-                self._logger.info("check os-hypervisors statistics> URI:%s" % req_resouce)
-                resp = sess.get(req_resouce, endpoint_filter=service)
-                self._logger.info("check os-hypervisors statistics> status:%s" % resp.status_code)
-                content = resp.json()
-                hypervisor_statistics = content['hypervisor_statistics']
-                self._logger.debug("check os-hypervisors statistics> resp data:%s" % content)
-            except HttpError as e:
-                if e.http_status == status.HTTP_403_FORBIDDEN:
-                    # Due to non administrator account cannot get hypervisor data,
-                    # so construct enough resource data
-                    conVCPUS = int(resource_demand['vCPU'])
-                    conFreeRamMB = int(resource_demand['Memory'])
-                    conFreeDiskGB = int(resource_demand['Storage'])
-                    self._logger.info("Non administator forbidden to access hypervisor statistics data")
-                    hypervisor_statistics = {'vcpus_used': 0,
-                                             'vcpus': conVCPUS,
-                                             'free_ram_mb': conFreeRamMB,
-                                             'free_disk_gb': conFreeDiskGB}
-                else:
-                    # non forbiden exeption will be redirected
-                    raise e
-
-            # get storage limit for this tenant
-            service['service_type'] = 'volumev2'
-            req_resouce = "/limits"
-            self._logger.info("check volumev2 limits> URI:%s" % req_resouce)
-            resp = sess.get(req_resouce, endpoint_filter=service)
-            self._logger.info("check volumev2> status:%s" % resp.status_code)
-            content = resp.json()
-            storage_limits = content['limits']['absolute']
-            self._logger.debug("check volumev2> resp data:%s" % content)
-
-            # compute actual available resource for this tenant
-            remainVCPU = compute_limits['maxTotalCores'] - compute_limits['totalCoresUsed']
-            remainHypervisorVCPU = hypervisor_statistics['vcpus'] - hypervisor_statistics['vcpus_used']
-
-            if (remainVCPU > remainHypervisorVCPU):
-                remainVCPU = remainHypervisorVCPU
-
-            remainMEM = compute_limits['maxTotalRAMSize'] - compute_limits['totalRAMUsed']
-            remainHypervisorMEM = hypervisor_statistics['free_ram_mb']
-            if remainMEM > remainHypervisorMEM:
-                remainMEM = remainHypervisorMEM
-
-            remainStorage = storage_limits['maxTotalVolumeGigabytes'] - storage_limits['totalGigabytesUsed']
-            remainHypervisorStorage = hypervisor_statistics['free_disk_gb']
-            if (remainStorage > remainHypervisorStorage):
-                remainStorage = remainHypervisorStorage
-
-            # compare resource demanded with available
-            if (int(resource_demand['vCPU']) > remainVCPU):
-                hasEnoughResource = False
-            elif (int(resource_demand['Memory']) > remainMEM):
-                hasEnoughResource = False
-            elif (int(resource_demand['Storage']) > remainStorage):
-                hasEnoughResource = False
-            else:
-                hasEnoughResource = True
-
+            hasEnoughResource = self.get_tenant_cap_info(vimid, request.data)
             self._logger.info("RESP with data> result:%s" % hasEnoughResource)
             return Response(data={'result': hasEnoughResource}, status=status.HTTP_200_OK)
         except VimDriverNewtonException as e:
             self._logger.error("Plugin exception> status:%s,error:%s"
                                % (e.status_code, e.content))
-            return Response(data={'result': hasEnoughResource,
+            return Response(data={'result': False,
                                   'error': e.content}, status=e.status_code)
         except HttpError as e:
             self._logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json()))
             resp = e.response.json()
-            resp.update({'result': hasEnoughResource})
+            resp.update({'result': False})
             return Response(data=e.response.json(), status=e.http_status)
         except Exception as e:
             self._logger.error(traceback.format_exc())
-            return Response(data={'result': hasEnoughResource, 'error': str(e)},
+            return Response(data={'result': False, 'error': str(e)},
                             status=status.HTTP_500_INTERNAL_SERVER_ERROR)
 
+    def get_tenant_cap_info(self, vimid, resource_demand):
+        hasEnoughResource = False
+        tenant_name = None
+        vim = VimDriverUtils.get_vim_info(vimid)
+        sess = VimDriverUtils.get_session(vim, tenant_name)
+
+        # get token:
+        # cloud_owner, regionid = extsys.decode_vim_id(vimid)
+        interface = 'public'
+        service = {'service_type': 'compute',
+                   'interface': interface,
+                   'region_name': vim['openstack_region_id']
+                   if vim.get('openstack_region_id')
+                   else vim['cloud_region_id']
+                   }
+
+        # get limit for this tenant
+        req_resouce = "/limits"
+        self._logger.info("check limits> URI:%s" % req_resouce)
+        resp = sess.get(req_resouce, endpoint_filter=service)
+        self._logger.info("check limits> status:%s" % resp.status_code)
+        content = resp.json()
+        compute_limits = content['limits']['absolute']
+        self._logger.debug("check limits> resp data:%s" % content)
+
+        # get total resource of this cloud region
+        try:
+            req_resouce = "/os-hypervisors/statistics"
+            self._logger.info("check os-hypervisors statistics> URI:%s" % req_resouce)
+            resp = sess.get(req_resouce, endpoint_filter=service)
+            self._logger.info("check os-hypervisors statistics> status:%s" % resp.status_code)
+            content = resp.json()
+            hypervisor_statistics = content['hypervisor_statistics']
+            self._logger.debug("check os-hypervisors statistics> resp data:%s" % content)
+        except HttpError as e:
+            if e.http_status == status.HTTP_403_FORBIDDEN:
+                # Due to non administrator account cannot get hypervisor data,
+                # so construct enough resource data
+                conVCPUS = int(resource_demand['vCPU'])
+                conFreeRamMB = int(resource_demand['Memory'])
+                conFreeDiskGB = int(resource_demand['Storage'])
+                self._logger.info("Non administator forbidden to access hypervisor statistics data")
+                hypervisor_statistics = {'vcpus_used': 0,
+                                         'vcpus': conVCPUS,
+                                         'free_ram_mb': conFreeRamMB,
+                                         'free_disk_gb': conFreeDiskGB}
+            else:
+                # non forbiden exeption will be redirected
+                raise e
+
+        # get storage limit for this tenant
+        service['service_type'] = 'volumev2'
+        req_resouce = "/limits"
+        self._logger.info("check volumev2 limits> URI:%s" % req_resouce)
+        resp = sess.get(req_resouce, endpoint_filter=service)
+        self._logger.info("check volumev2> status:%s" % resp.status_code)
+        content = resp.json()
+        storage_limits = content['limits']['absolute']
+        self._logger.debug("check volumev2> resp data:%s" % content)
+
+        # compute actual available resource for this tenant
+        remainVCPU = compute_limits['maxTotalCores'] - compute_limits['totalCoresUsed']
+        remainHypervisorVCPU = hypervisor_statistics['vcpus'] - hypervisor_statistics['vcpus_used']
+
+        if (remainVCPU > remainHypervisorVCPU):
+            remainVCPU = remainHypervisorVCPU
+
+        remainMEM = compute_limits['maxTotalRAMSize'] - compute_limits['totalRAMUsed']
+        remainHypervisorMEM = hypervisor_statistics['free_ram_mb']
+        if remainMEM > remainHypervisorMEM:
+            remainMEM = remainHypervisorMEM
+
+        remainStorage = storage_limits['maxTotalVolumeGigabytes'] - storage_limits['totalGigabytesUsed']
+        remainHypervisorStorage = hypervisor_statistics['free_disk_gb']
+        if (remainStorage > remainHypervisorStorage):
+            remainStorage = remainHypervisorStorage
+
+        # compare resource demanded with available
+        if (int(resource_demand['vCPU']) > remainVCPU):
+            hasEnoughResource = False
+        elif (int(resource_demand['Memory']) > remainMEM):
+            hasEnoughResource = False
+        elif (int(resource_demand['Storage']) > remainStorage):
+            hasEnoughResource = False
+        else:
+            hasEnoughResource = True
+
+        return hasEnoughResource
 
 class APIv1CapacityCheck(CapacityCheck):
     def __init__(self):
index 7a85b29..5907456 100644 (file)
@@ -373,7 +373,8 @@ class InfraResourceAuditor(newton_registration.RegistryHelper):
                     continue
                 hypervisors_dict[h["hypervisor_hostname"]] = h
 
-            az_pserver_info = {}
+            vimAzCacheKey = "cap_azlist_" + vimid
+            vimAzList = []
             # cloud_owner, cloud_region_id = extsys.decode_vim_id(vimid)
             for az in self._get_list_resources(
                     "/os-availability-zone/detail", "compute", session,
@@ -393,6 +394,8 @@ class InfraResourceAuditor(newton_registration.RegistryHelper):
                 if azName == 'internal':
                     continue
 
+                vimAzList.append(azName)
+
                 # get list of host names
                 pservers_info = [k for (k, v) in az['hosts'].items()]
                 # set the association between az and pservers
@@ -456,6 +459,7 @@ class InfraResourceAuditor(newton_registration.RegistryHelper):
 
                 # update the cache
                 cache.set(azCapCacheKey, json.dumps(azCapInfoCache), 3600 * 24)
+                cache.set(vimAzCacheKey, vimAzList, 3600 * 24)
         except Exception as e:
             self._logger.error("azcap_audit raise exception: %s" % e)
             pass
diff --git a/share/starlingx_base/resource/__init__.py b/share/starlingx_base/resource/__init__.py
new file mode 100644 (file)
index 0000000..825091f
--- /dev/null
@@ -0,0 +1,10 @@
+# Copyright (c) 2017-2019 Wind River Systems, Inc.
+#
+# Licensed 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.
diff --git a/share/starlingx_base/resource/capacity.py b/share/starlingx_base/resource/capacity.py
new file mode 100644 (file)
index 0000000..fc926d0
--- /dev/null
@@ -0,0 +1,97 @@
+# Copyright (c) 2017-2019 Wind River Systems, Inc.
+#
+# Licensed 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.
+
+import logging
+import traceback
+import json
+
+from django.core.cache import cache
+
+from newton_base.resource import capacity as newton_capacity
+from common.exceptions import VimDriverNewtonException
+from newton_base.util import VimDriverUtils
+
+from keystoneauth1.exceptions import HttpError
+from rest_framework import status
+from rest_framework.response import Response
+from rest_framework.views import APIView
+from common.msapi import extsys
+
+logger = logging.getLogger(__name__)
+
+
+class CapacityCheck(newton_capacity.CapacityCheck):
+    def __init__(self):
+        super(CapacityCheck, self).__init__()
+        self._logger = logger
+
+    def post(self, request, vimid=""):
+        self._logger.info("vimid, data> %s, %s" % (vimid, request.data))
+        self._logger.debug("META> %s" % request.META)
+
+        try:
+            hasEnoughResource = self.get_tenant_cap_info(vimid, request.data)
+            azCapInfo = self.get_az_cap_info(vimid)
+            self._logger.info("RESP with data> result:%s" % hasEnoughResource)
+            return Response(data={'result': hasEnoughResource, 'AZs': azCapInfo}, status=status.HTTP_200_OK)
+        except Exception as e:
+            self._logger.error(traceback.format_exc())
+            return Response(data={'result': False, 'error': str(e)},
+                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+    def get_az_cap_info(self, vimid):
+        azCapInfo = []
+        viminfo = VimDriverUtils.get_vim_info(vimid)
+        if not viminfo:
+            self._logger.warn("azcap_audit no valid vimid: %s" % vimid)
+            return
+
+        session = VimDriverUtils.get_session(
+            viminfo,
+            tenant_name=viminfo['tenant']
+        )
+        try:
+            # get list of AZ
+            vimAzCacheKey = "cap_azlist_" + vimid
+            vimAzListCacheStr = cache.get(vimAzCacheKey)
+            vimAzListCache = json.loads(vimAzListCacheStr) if vimAzListCacheStr else []
+            for azName in vimAzListCache:
+                azCapCacheKey = "cap_" + vimid + "_" + azName
+                azCapInfoCacheStr = cache.get(azCapCacheKey)
+                azCapInfoCache = json.loads(azCapInfoCacheStr) if azCapInfoCacheStr else None
+
+                azCapInfo["availability-zone-name"] = azName
+                azCapInfo["vCPUAvail"] = azCapInfoCache.get("vcpus", 0) + azCapInfoCache.get("vcpus_used", 0)
+                azCapInfo["vCPUTotal"] = azCapInfoCache.get("vcpus", 0)
+                azCapInfo["MemoryAvail"] = azCapInfoCache.get("vcpus", 0)
+                azCapInfo["MemoryTotal"] = azCapInfoCache.get("vcpus", 0)
+                azCapInfo["StorageAvail"] = azCapInfoCache.get("vcpus", 0)
+                azCapInfo["StorageTotal"] = azCapInfoCache.get("vcpus", 0)
+
+            return azCapInfo
+        except Exception as e:
+            return azCapInfo
+            pass
+
+class APIv1CapacityCheck(CapacityCheck):
+    def __init__(self):
+        super(APIv1CapacityCheck, self).__init__()
+        # self._logger = logger
+
+    def post(self, request, cloud_owner="", cloud_region_id=""):
+        self._logger.info("vimid, data> %s,%s, %s" % (cloud_owner, cloud_region_id, request.data))
+        self._logger.debug("META> %s" % request.META)
+
+        vimid = extsys.encode_vim_id(cloud_owner, cloud_region_id)
+        return super(APIv1CapacityCheck, self).post(request, vimid)