From d8db2570c5955cf45f058e638253576820b543e5 Mon Sep 17 00:00:00 2001 From: Ethan Lynn Date: Wed, 3 Apr 2019 15:57:21 +0800 Subject: Add AZ info in capacity_check Add AZ info in capacity_check Change-Id: Icb8d6be7034d7ac6cdda324b1e445f027e4fdd39 Issue-ID: MULTICLOUD-564 Signed-off-by: Ethan Lynn --- vio/vio/pub/vim/drivers/vimsdk/compute.py | 4 ++ vio/vio/pub/vim/vimapi/nova/OperateNova.py | 6 +++ vio/vio/swagger/views/capacity/views.py | 85 +++++++++++++++++++++++------- vio/vio/tests/test_capacity_view.py | 12 ++++- 4 files changed, 87 insertions(+), 20 deletions(-) diff --git a/vio/vio/pub/vim/drivers/vimsdk/compute.py b/vio/vio/pub/vim/drivers/vimsdk/compute.py index e415573..9dccd2a 100644 --- a/vio/vio/pub/vim/drivers/vimsdk/compute.py +++ b/vio/vio/pub/vim/drivers/vimsdk/compute.py @@ -142,3 +142,7 @@ class ComputeClient(base.DriverBase): @sdk.translate_exception def list_hypervisors(self, **query): return self.conn.compute.hypervisors(**query) + + @sdk.translate_exception + def availability_zones(self, **query): + return self.conn.compute.availability_zones(**query) diff --git a/vio/vio/pub/vim/vimapi/nova/OperateNova.py b/vio/vio/pub/vim/vimapi/nova/OperateNova.py index 262da57..76dae71 100644 --- a/vio/vio/pub/vim/vimapi/nova/OperateNova.py +++ b/vio/vio/pub/vim/vimapi/nova/OperateNova.py @@ -37,3 +37,9 @@ class OperateNova(baseclient): compute = self.compute(param) func = getattr(compute, op) return func(**kwargs) + + +class OperateAZ(OperateNova): + + def list_availability_zones(self, data, **kwargs): + return self.request('availability_zones', data, **kwargs) diff --git a/vio/vio/swagger/views/capacity/views.py b/vio/vio/swagger/views/capacity/views.py index f679931..5cbd38e 100644 --- a/vio/vio/swagger/views/capacity/views.py +++ b/vio/vio/swagger/views/capacity/views.py @@ -21,6 +21,7 @@ from vio.pub.exceptions import VimDriverVioException from vio.pub.msapi import extsys from vio.pub.vim.vimapi.nova import OperateHypervisor from vio.pub.vim.vimapi.nova import OperateLimits +from vio.pub.vim.vimapi.nova import OperateNova from cinderclient import client @@ -69,16 +70,16 @@ class CapacityCheck(APIView): return False return True - def post(self, request, vimid): + def _post_handler(self, request, vimid): try: requirement = json.loads(request.body) except ValueError as ex: - return Response(data={'error': str(ex)}, - status=status.HTTP_400_BAD_REQUEST) + return {'error': str(ex), + "status_code": status.HTTP_400_BAD_REQUEST} try: vim_info = extsys.get_vim_by_id(vimid) except VimDriverVioException as e: - return Response(data={'error': str(e)}, status=e.status_code) + return {'error': str(e), "status_code": e.status_code} auth_info = { "username": vim_info['userName'], "password": vim_info['password'], @@ -92,38 +93,86 @@ class CapacityCheck(APIView): nova_limits = servers_op.get_limits(auth_info, None) except Exception as e: logger.exception("get nova limits error %(e)s", {"e": e}) - return Response(data={'error': str(e)}, status=e.status_code) + return {'error': str(e), "status_code": e.status_code} if not self._check_nova_limits(nova_limits, requirement): - return Response( - data={'result': False}, status=status.HTTP_200_OK) + return {'result': False, "status_code": status.HTTP_200_OK} # check cinder limits cinder = client.Client( - "2", auth_info['username'], auth_info['password'], + "3", auth_info['username'], auth_info['password'], auth_info['project_name'], auth_info['url'], insecure=True) try: limits = cinder.limits.get().to_dict() except Exception as e: logger.exception("get cinder limits error %(e)s", {"e": e}) - return Response(data={'error': str(e)}, status=e.status_code) + return {'error': str(e), "status_code": e.status_code} if not self._check_cinder_limits(limits, requirement): - return Response( - data={'result': False}, status=status.HTTP_200_OK) + return {'result': False, "status_code": status.HTTP_200_OK} + # Get Availability zones info + nova_op = OperateNova.OperateAZ() + try: + azs = nova_op.list_availability_zones(auth_info, details=True) + except Exception as e: + logger.exception("get availability_zones error %(e)s", {"e": e}) + return {'error': str(e), "status_code": e.status_code} + availability_zones = [] + for az in azs: + if az.name == "internal": + continue + availability_zones.append({ + "availability-zone-name": az.name, + "hosts": az.hosts, + "vCPUTotal": 0, + "vCPUAvail": 0, + "MemoryTotal": 0, + "MemoryAvail": 0, + "StorageTotal": 0, + "StorageAvail": 0, + }) # check hypervisor resources hypervisor_op = OperateHypervisor.OperateHypervisor() try: hypervisors = hypervisor_op.list_hypervisors(auth_info) except Exception as e: logger.exception("get hypervisors error %(e)s", {"e": e}) - return Response(data={'error': str(e)}, status=e.status_code) + return {'error': str(e), "status_code": e.status_code} + ret = {'result': False, "status_code": status.HTTP_200_OK} + # import ipdb; ipdb.set_trace() for hypervisor in hypervisors: + if hypervisor.status != "enabled": + continue hyper = hypervisor_op.get_hypervisor(auth_info, hypervisor.id) - if self._check_capacity(hyper.to_dict(), requirement): - return Response(data={'result': True}, - status=status.HTTP_200_OK) - return Response(data={'result': False}, status=status.HTTP_200_OK) + hyper_dict = hyper.to_dict() + for az in availability_zones: + if az['hosts'].get(hyper_dict["service_details"]['host']): + az['vCPUTotal'] += hyper_dict["vcpus"] + az['vCPUAvail'] += hyper_dict["vcpus"] - hyper_dict[ + "vcpus_used"] + az['MemoryTotal'] += hyper_dict["memory_size"] + az['MemoryAvail'] += hyper_dict["memory_free"] + az['StorageTotal'] += hyper_dict["local_disk_size"] + az['StorageAvail'] += hyper_dict["local_disk_free"] + if self._check_capacity(hyper_dict, requirement): + ret["result"] = True + if ret["result"]: + for az in availability_zones: + del az["hosts"] + ret["AZs"] = availability_zones + return ret + + def post(self, request, vimid): + ret = self._post_handler(request, vimid) + status_code = ret["status_code"] + del ret["status_code"] + if ret.get("AZs"): + del ret["AZs"] + return Response(data=ret, status=status_code) class CapacityCheckV1(CapacityCheck): def post(self, request, cloud_owner, cloud_region): - return super(CapacityCheckV1, self).post( - request, cloud_owner + "_" + cloud_region) + # import ipdb; ipdb.set_trace() + vimid = cloud_owner + "_" + cloud_region + ret = self._post_handler(request, vimid) + status_code = ret["status_code"] + del ret["status_code"] + return Response(data=ret, status=status_code) diff --git a/vio/vio/tests/test_capacity_view.py b/vio/vio/tests/test_capacity_view.py index d27efba..3079bac 100644 --- a/vio/vio/tests/test_capacity_view.py +++ b/vio/vio/tests/test_capacity_view.py @@ -18,6 +18,7 @@ from rest_framework import status from vio.pub.msapi import extsys from vio.pub.vim.vimapi.nova import OperateHypervisor from vio.pub.vim.vimapi.nova import OperateLimits +from vio.pub.vim.vimapi.nova import OperateNova from vio.swagger.views.capacity.views import CapacityCheck from cinderclient import client @@ -32,12 +33,13 @@ class CapacityCheckTest(unittest.TestCase): def setUp(self): self.view = CapacityCheck() + @mock.patch.object(OperateNova, "OperateAZ") @mock.patch.object(OperateHypervisor, "OperateHypervisor") @mock.patch.object(OperateLimits, "OperateLimits") @mock.patch.object(client, "Client") @mock.patch.object(extsys, "get_vim_by_id") def test_check_capacity_success(self, mock_get_vim, mock_cinder, - mock_limit, mock_hypervisor): + mock_limit, mock_hypervisor, mock_az): mock_get_vim.return_value = VIM_INFO req = mock.Mock() req.body = """{ @@ -63,11 +65,17 @@ class CapacityCheckTest(unittest.TestCase): cclient.limits.get.return_value = climits mock_cinder.return_value = cclient + nazs = [mock.Mock(name="nova", hosts={"compute01": {}})] + nclient = mock.Mock() + nclient.list_availability_zones.return_value = nazs + mock_az.return_value = nclient + ophypervisor = mock.Mock() ophypervisor.list_hypervisors.return_value = [ - mock.Mock(id="compute01")] + mock.Mock(id="compute01", status="enabled")] hyper = mock.Mock() hyper.to_dict.return_value = { + "service_details": {"host": "compute01"}, "vcpus": 20, "vcpus_used": 1, "memory_size": 128*1024, -- cgit 1.2.3-korg