From: SudhakarReddy Date: Thu, 6 Sep 2018 09:37:26 +0000 (+0300) Subject: Added V0 Registry API X-Git-Tag: 1.2.0~6^2 X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=e212f4fcb3d6f7d2853c6a80144f193b6cc266bf;p=multicloud%2Fazure.git Added V0 Registry API Change-Id: Iac61b136485ddb06b76d8b701ab51e8e18439e94 Issue-ID: MULTICLOUD-354 Signed-off-by: SudhakarReddy --- diff --git a/azure/assembly.xml b/azure/assembly.xml index 61a4883..48255fd 100644 --- a/azure/assembly.xml +++ b/azure/assembly.xml @@ -20,8 +20,8 @@ - azure - /azure + multicloud_azure + /multicloud_azure **/*.py **/*.json @@ -61,6 +61,6 @@ - azure + multicloud_azure diff --git a/azure/azure/swagger/views/registry/views.py b/azure/azure/swagger/views/registry/views.py deleted file mode 100644 index b5db805..0000000 --- a/azure/azure/swagger/views/registry/views.py +++ /dev/null @@ -1,167 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# 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. - - -import logging - -from rest_framework import status -from rest_framework.response import Response -from rest_framework.views import APIView - -from azure.pub.exceptions import VimDriverAzureException -from azure.pub.msapi import extsys -from azure.pub.utils.restcall import AAIClient - - -logger = logging.getLogger(__name__) - - -class Registry(APIView): - # def _get_tenants(self, auth_info): - # tenant_instance = OperateTenant.OperateTenant() - # try: - # projects = tenant_instance.get_projects(auth_info) - # except Exception as e: - # logger.exception("get tenants error %(e)s", {"e": e}) - # raise e - # - # rsp = {"tenants": []} - # for project in projects: - # rsp['tenants'].append(project.to_dict()) - # return rsp - # - # def _get_images(self, auth_info): - # image_instance = OperateImage.OperateImage(auth_info) - # try: - # images = image_instance.get_vim_images() - # except Exception as e: - # logger.exception("get images error %(e)s", {"e": e}) - # raise e - # - # rsp = {"images": []} - # for image in images: - # rsp['images'].append(image.to_dict()) - # return rsp - # - # def _get_flavors(self, auth_info): - # flavors_op = OperateFlavors.OperateFlavors() - # try: - # flavors = flavors_op.list_flavors( - # auth_info, auth_info['tenant']) - # except Exception as e: - # logger.exception("get flavors error %(e)s", {"e": e}) - # raise e - # - # rsp = {"flavors": []} - # for flavor in flavors: - # flavor_info = flavor[0].to_dict() - # flavor_info['extra_specs'] = flavor[1].extra_specs - # rsp['flavors'].append(flavor_info) - # return rsp - # - # def _get_networks(self, auth_info): - # net_op = OperateNetwork.OperateNetwork() - # try: - # resp = net_op.list_networks( - # auth_info['vimId'], auth_info['tenant']) - # except Exception as e: - # logger.exception("get networks error %(e)s", {"e": e}) - # raise e - # - # rsp = {'networks': resp['networks']} - # return rsp - # - # def _get_hypervisors(self, auth_info): - # 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}) - # raise e - # - # rsp = {"hypervisors": []} - # for hypervisor in hypervisors: - # rsp['hypervisors'].append(hypervisor.to_dict()) - # return rsp - - def _find_tenant_id(self, name, tenants): - for tenant in tenants['tenants']: - if tenant['name'] == name: - return tenant['id'] - - def post(self, request, vimid): - try: - vim_info = extsys.get_vim_by_id(vimid) - except VimDriverAzureException as e: - return Response(data={'error': str(e)}, status=e.status_code) - data = {} - data['vimId'] = vim_info['vimId'] - data['username'] = vim_info['userName'] - data['userName'] = vim_info['userName'] - data['password'] = vim_info['password'] - data['url'] = vim_info['url'] - data['project_name'] = vim_info['tenant'] - - rsp = {} - # get tenants - try: - logger.debug('Getting tenants') - tenants = self._get_tenants(data) - rsp.update(tenants) - data['tenant'] = self._find_tenant_id( - data['project_name'], tenants) - data['project_id'] = data['tenant'] - # set default tenant - # get images - logger.debug('Getting images') - images = self._get_images(data) - rsp.update(images) - # get flavors - logger.debug('Getting flavors') - flavors = self._get_flavors(data) - rsp.update(flavors) - # get networks - logger.debug('Getting networks') - networks = self._get_networks(data) - rsp.update(networks) - # get hypervisors - logger.debug('Getting hypervisors') - hypervisors = self._get_hypervisors(data) - rsp.update(hypervisors) - # update A&AI - logger.debug('Put data into A&AI') - cloud_owner, cloud_region = extsys.split_vim_to_owner_region( - vimid) - aai_adapter = AAIClient(cloud_owner, cloud_region) - aai_adapter.update_vim(rsp) - except Exception as e: - if hasattr(e, "http_status"): - return Response(data={'error': str(e)}, status=e.http_status) - else: - return Response(data={'error': str(e)}, - status=status.HTTP_500_INTERNAL_SERVER_ERROR) - - return Response(data="", status=status.HTTP_200_OK) - - -class UnRegistry(APIView): - - def delete(self, request, vimid): - try: - cloud_owner, cloud_region = extsys.split_vim_to_owner_region( - vimid) - aai_adapter = AAIClient(cloud_owner, cloud_region) - aai_adapter.delete_vim() - except Exception as e: - return Response(data=e.message, - status=status.HTTP_500_INTERNAL_SERVER_ERROR) - return Response(data="", status=status.HTTP_204_NO_CONTENT) diff --git a/azure/azure/tests/test_aai_client.py b/azure/azure/tests/test_aai_client.py deleted file mode 100644 index 31ff37d..0000000 --- a/azure/azure/tests/test_aai_client.py +++ /dev/null @@ -1,378 +0,0 @@ -# Copyright (c) 2018 Amdocs -# -# 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. - -import json -import mock -import unittest - -from azure.pub.exceptions import VimDriverAzureException -from azure.pub.utils import restcall - - -class TestAAIClient(unittest.TestCase): - - def setUp(self): - self.view = restcall.AAIClient("vmware", "4.0") - - @mock.patch.object(restcall, "call_req") - def test_get_vim(self, mock_call): - mock_call.return_value = [0, '{"cloudOwner": "vmware"}'] - ret = self.view.get_vim(get_all=True) - expect_ret = {"cloudOwner": "vmware"} - self.assertEqual(expect_ret, ret) - - @mock.patch.object(restcall.AAIClient, "get_vim") - @mock.patch.object(restcall, "call_req") - def test_update_identity_url(self, mock_call, mock_getvim): - mock_getvim.return_value = {} - self.view.update_identity_url() - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_add_tenants(self, mock_call): - tenants = {"tenants": [{"name": "admin", "id": "admin-id"}]} - self.view.add_tenants(tenants) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_add_flavors(self, mock_call): - flavors = { - "flavors": [{ - "name": "m1.small", - "id": "1", - "vcpus": 1, - "ram": 512, - "disk": 10, - "ephemeral": 0, - "swap": 0, - "is_public": True, - "links": [{"href": "http://fake-url"}], - "is_disabled": False - }] - } - self.view.add_flavors(flavors) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_add_flavors_with_hpa(self, mock_call): - flavors = { - "flavors": [{ - "name": "onap.small", - "id": "1", - "vcpus": 1, - "ram": 512, - "disk": 10, - "ephemeral": 0, - "swap": 0, - "is_public": True, - "links": [{"href": "http://fake-url"}], - "is_disabled": False, - "extra_specs": {}, - }] - } - self.view._get_ovsdpdk_capabilities = mock.MagicMock() - self.view._get_ovsdpdk_capabilities.return_value = {} - self.view.add_flavors(flavors) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_add_images(self, mock_call): - images = { - "images": [{ - "name": "ubuntu-16.04", - "id": "image-id" - }] - } - self.view.add_images(images) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_add_networks(self, mock_call): - networks = { - "networks": [{ - "name": "net-1", - "id": "net-id", - "segmentationId": 144 - }] - } - self.view.add_networks(networks) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_add_pservers(self, mock_call): - pservers = { - "hypervisors": [{ - "name": "compute-1", - "vcpus": 100, - "local_disk_size": 1000, - "memory_size": 10240, - "host_ip": "10.0.0.7", - "id": "compute-1-id" - }] - } - self.view.add_pservers(pservers) - self.assertEqual(mock_call.call_count, 2) - - @mock.patch.object(restcall, "call_req") - def test_del_tenants(self, mock_call): - mock_call.return_value = [0] - rsp = { - "tenants": { - "tenant": [{ - "tenant-id": "tenant-id", - "resource-version": "version-1" - }] - } - } - self.view._del_tenants(rsp) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_del_flavors(self, mock_call): - mock_call.return_value = [0] - rsp = { - "flavors": { - "flavor": [{ - "flavor-id": "fake-id", - "resource-version": "fake-version" - }] - } - } - self.view._del_flavors(rsp) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_del_images(self, mock_call): - mock_call.return_value = [0] - rsp = { - "images": { - "image": [{ - "image-id": "fake-id", - "resource-version": "fake-version" - }] - } - } - self.view._del_images(rsp) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_del_networks(self, mock_call): - mock_call.return_value = [0] - rsp = { - "oam-networks": { - "oam-network": [{ - "network-uuid": "fake-id", - "resource-version": "fake-version" - }] - } - } - self.view._del_networks(rsp) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_del_azs(self, mock_call): - mock_call.return_value = [0] - rsp = { - "availability-zones": { - "availability-zone": [{ - "availability-zone-name": "fake-name", - "resource-version": "fake-version" - }] - } - } - self.view._del_azs(rsp) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_del_hpa(self, mock_call): - mock_call.return_value = [0] - rsp = { - "flavor-id": "id1", - "hpa-capabilities": { - "hpa-capability": [{ - "resource-version": "v1", - "hpa-capability-id": "id2" - }] - } - } - self.view._del_hpa(rsp) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_del_vim(self, mock_call): - resp = { - "resource-version": "1" - } - self.view.get_vim = mock.MagicMock() - self.view.get_vim.return_value = resp - mock_call.return_value = [0, "", "", ""] - self.view.delete_vim() - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_del_vim_fail(self, mock_call): - resp = { - "resource-version": "1" - } - self.view.get_vim = mock.MagicMock() - self.view.get_vim.return_value = resp - mock_call.return_value = [1, "", "", ""] - self.assertRaises(VimDriverAzureException, self.view.delete_vim) - - @mock.patch.object(restcall, "call_req") - def test_update_vim(self, mock_call): - resp = { - "resource-version": "1" - } - self.view.get_vim = mock.MagicMock() - self.view.get_vim.return_value = resp - content = { - "tenants": [], - "images": [], - "flavors": [], - "networks": [], - "hypervisors": [] - } - self.view.update_vim(content) - mock_call.assert_called_once() - - @mock.patch.object(restcall, "call_req") - def test_get_hpa(self, mock_call): - self.view._get_hpa_basic_capabilities = mock.MagicMock() - self.view._get_hpa_basic_capabilities.return_value = {"hpa": "basic"} - self.view._get_cpupinning_capabilities = mock.MagicMock() - self.view._get_cpupinning_capabilities.return_value = {"hpa": "basic"} - self.view._get_cputopology_capabilities = mock.MagicMock() - self.view._get_cputopology_capabilities.return_value = {"hpa": "basic"} - self.view._get_hugepages_capabilities = mock.MagicMock() - self.view._get_hugepages_capabilities.return_value = {"hpa": "basic"} - self.view._get_numa_capabilities = mock.MagicMock() - self.view._get_numa_capabilities.return_value = {"hpa": "basic"} - self.view._get_storage_capabilities = mock.MagicMock() - self.view._get_storage_capabilities.return_value = {"hpa": "basic"} - self.view._get_instruction_set_capabilities = mock.MagicMock() - self.view._get_instruction_set_capabilities.return_value = { - "hpa": "basic"} - self.view._get_pci_passthrough_capabilities = mock.MagicMock() - self.view._get_pci_passthrough_capabilities.return_value = { - "hpa": "basic"} - self.view._get_ovsdpdk_capabilities = mock.MagicMock() - self.view._get_ovsdpdk_capabilities.return_value = {"hpa": "basic"} - ret = self.view._get_hpa_capabilities({"extra_specs": {}}) - self.assertEqual([{"hpa": "basic"}]*9, ret) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_basic(self, mock_call): - flavor = { - "vcpus": 1, - "ram": 1024 - } - ret = self.view._get_hpa_basic_capabilities(flavor) - self.assertEqual(len(ret["hpa-feature-attributes"]), 2) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_cpupin(self, mock_call): - extra = { - "hw:cpu_policy": "cpu_policy", - "hw:cpu_thread_policy": "thread_policy" - } - ret = self.view._get_cpupinning_capabilities(extra) - self.assertEqual(len(ret["hpa-feature-attributes"]), 2) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_cputopo(self, mock_call): - extra = { - "hw:cpu_sockets": 2, - "hw:cpu_cores": 2, - "hw:cpu_threads": 4 - } - ret = self.view._get_cputopology_capabilities(extra) - self.assertEqual(len(ret["hpa-feature-attributes"]), 3) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_hugepage_large(self, mock_call): - extra = { - "hw:mem_page_size": "large" - } - ret = self.view._get_hugepages_capabilities(extra) - self.assertIn( - "2", ret["hpa-feature-attributes"][0]["hpa-attribute-value"]) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_hugepage_small(self, mock_call): - extra = { - "hw:mem_page_size": "small" - } - ret = self.view._get_hugepages_capabilities(extra) - self.assertIn( - "4", ret["hpa-feature-attributes"][0]["hpa-attribute-value"]) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_hugepage_int(self, mock_call): - extra = { - "hw:mem_page_size": 8, - } - ret = self.view._get_hugepages_capabilities(extra) - self.assertIn( - "8", ret["hpa-feature-attributes"][0]["hpa-attribute-value"]) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_hugepage_any(self, mock_call): - extra = { - "hw:mem_page_size": "any", - } - ret = self.view._get_hugepages_capabilities(extra) - self.assertEqual(0, len(ret["hpa-feature-attributes"])) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_numa(self, mock_call): - extra = { - "hw:numa_nodes": 1, - "hw:numa_cpus.0": 1, - "hw:numa_mem.0": 1024, - } - ret = self.view._get_numa_capabilities(extra) - self.assertEqual(3, len(ret["hpa-feature-attributes"])) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_storage(self, mock_call): - extra = { - "disk": 10, - } - ret = self.view._get_storage_capabilities(extra) - self.assertEqual(3, len(ret["hpa-feature-attributes"])) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_instru(self, mock_call): - extra = { - "hw:capabilities:cpu_info:features": "avx", - } - ret = self.view._get_instruction_set_capabilities(extra) - self.assertEqual(1, len(ret["hpa-feature-attributes"])) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_pci(self, mock_call): - extra = { - "pci_passthrough:alias": "gpu-nvidia-x86-0011-0022:1", - } - ret = self.view._get_pci_passthrough_capabilities(extra) - self.assertEqual(3, len(ret["hpa-feature-attributes"])) - - @mock.patch.object(restcall, "call_req") - def test_get_hpa_dpdk(self, mock_call): - self.view.get_vim = mock.MagicMock() - self.view.get_vim.return_value = { - "cloud-extra-info": json.dumps({'ovsDpdk': { - 'libname': 'generic', 'libversion': '17.04'}}) - } - ret = self.view._get_ovsdpdk_capabilities() - self.assertEqual(1, len(ret["hpa-feature-attributes"])) diff --git a/azure/manage.py b/azure/manage.py index 4a98417..9b219de 100644 --- a/azure/manage.py +++ b/azure/manage.py @@ -13,7 +13,7 @@ import os import sys -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "azure.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "multicloud_azure.settings") if __name__ == "__main__": from django.core.management import execute_from_command_line diff --git a/azure/azure/__init__.py b/azure/multicloud_azure/__init__.py similarity index 100% rename from azure/azure/__init__.py rename to azure/multicloud_azure/__init__.py diff --git a/azure/azure/api_v2/__init__.py b/azure/multicloud_azure/api_v2/__init__.py similarity index 100% rename from azure/azure/api_v2/__init__.py rename to azure/multicloud_azure/api_v2/__init__.py diff --git a/azure/azure/api_v2/api_definition/__init__.py b/azure/multicloud_azure/api_v2/api_definition/__init__.py similarity index 100% rename from azure/azure/api_v2/api_definition/__init__.py rename to azure/multicloud_azure/api_v2/api_definition/__init__.py diff --git a/azure/azure/api_v2/api_definition/hosts.yaml b/azure/multicloud_azure/api_v2/api_definition/hosts.yaml similarity index 100% rename from azure/azure/api_v2/api_definition/hosts.yaml rename to azure/multicloud_azure/api_v2/api_definition/hosts.yaml diff --git a/azure/azure/api_v2/api_definition/images.yaml b/azure/multicloud_azure/api_v2/api_definition/images.yaml similarity index 100% rename from azure/azure/api_v2/api_definition/images.yaml rename to azure/multicloud_azure/api_v2/api_definition/images.yaml diff --git a/azure/azure/api_v2/api_definition/networks.yaml b/azure/multicloud_azure/api_v2/api_definition/networks.yaml similarity index 100% rename from azure/azure/api_v2/api_definition/networks.yaml rename to azure/multicloud_azure/api_v2/api_definition/networks.yaml diff --git a/azure/azure/api_v2/api_definition/ports.yaml b/azure/multicloud_azure/api_v2/api_definition/ports.yaml similarity index 100% rename from azure/azure/api_v2/api_definition/ports.yaml rename to azure/multicloud_azure/api_v2/api_definition/ports.yaml diff --git a/azure/azure/api_v2/api_definition/subnets.yaml b/azure/multicloud_azure/api_v2/api_definition/subnets.yaml similarity index 100% rename from azure/azure/api_v2/api_definition/subnets.yaml rename to azure/multicloud_azure/api_v2/api_definition/subnets.yaml diff --git a/azure/azure/api_v2/api_definition/utils.py b/azure/multicloud_azure/api_v2/api_definition/utils.py similarity index 100% rename from azure/azure/api_v2/api_definition/utils.py rename to azure/multicloud_azure/api_v2/api_definition/utils.py diff --git a/azure/azure/api_v2/api_router/__init__.py b/azure/multicloud_azure/api_v2/api_router/__init__.py similarity index 100% rename from azure/azure/api_v2/api_router/__init__.py rename to azure/multicloud_azure/api_v2/api_router/__init__.py diff --git a/azure/azure/api_v2/api_router/root.py b/azure/multicloud_azure/api_v2/api_router/root.py similarity index 93% rename from azure/azure/api_v2/api_router/root.py rename to azure/multicloud_azure/api_v2/api_router/root.py index 0b6f995..76c42fd 100644 --- a/azure/azure/api_v2/api_router/root.py +++ b/azure/multicloud_azure/api_v2/api_router/root.py @@ -15,7 +15,7 @@ import pecan from pecan import rest -from azure.api_v2.api_router import v0_controller +from multicloud_azure.api_v2.api_router import v0_controller class AzureController(rest.RestController): diff --git a/azure/azure/api_v2/api_router/swagger_json.py b/azure/multicloud_azure/api_v2/api_router/swagger_json.py similarity index 94% rename from azure/azure/api_v2/api_router/swagger_json.py rename to azure/multicloud_azure/api_v2/api_router/swagger_json.py index 8573a46..ca6aa0b 100644 --- a/azure/azure/api_v2/api_router/swagger_json.py +++ b/azure/multicloud_azure/api_v2/api_router/swagger_json.py @@ -15,7 +15,7 @@ import pecan from pecan import rest -from azure.swagger import utils +from multicloud_azure.swagger import utils class SwaggerJson(rest.RestController): diff --git a/azure/azure/api_v2/api_router/v0_controller.py b/azure/multicloud_azure/api_v2/api_router/v0_controller.py similarity index 95% rename from azure/azure/api_v2/api_router/v0_controller.py rename to azure/multicloud_azure/api_v2/api_router/v0_controller.py index 68aac1b..8d7e697 100644 --- a/azure/azure/api_v2/api_router/v0_controller.py +++ b/azure/multicloud_azure/api_v2/api_router/v0_controller.py @@ -15,7 +15,7 @@ import pecan from pecan import rest -from azure.api_v2.api_router import swagger_json +from multicloud_azure.api_v2.api_router import swagger_json class V0_Controller(rest.RestController): diff --git a/azure/azure/api_v2/app.py b/azure/multicloud_azure/api_v2/app.py similarity index 100% rename from azure/azure/api_v2/app.py rename to azure/multicloud_azure/api_v2/app.py diff --git a/azure/azure/api_v2/service.py b/azure/multicloud_azure/api_v2/service.py similarity index 93% rename from azure/azure/api_v2/service.py rename to azure/multicloud_azure/api_v2/service.py index 2b73c15..d6e3923 100644 --- a/azure/azure/api_v2/service.py +++ b/azure/multicloud_azure/api_v2/service.py @@ -17,8 +17,8 @@ from oslo_config import cfg from oslo_service import service from oslo_service import wsgi -from azure.api_v2 import app -from azure.pub.config import config as mc_cfg +from multicloud_azure.api_v2 import app +from multicloud_azure.pub.config import config as mc_cfg CONF = cfg.CONF diff --git a/azure/azure/event_listener/__init__.py b/azure/multicloud_azure/event_listener/__init__.py similarity index 100% rename from azure/azure/event_listener/__init__.py rename to azure/multicloud_azure/event_listener/__init__.py diff --git a/azure/azure/event_listener/i18n.py b/azure/multicloud_azure/event_listener/i18n.py similarity index 100% rename from azure/azure/event_listener/i18n.py rename to azure/multicloud_azure/event_listener/i18n.py diff --git a/azure/azure/event_listener/listener.conf b/azure/multicloud_azure/event_listener/listener.conf similarity index 100% rename from azure/azure/event_listener/listener.conf rename to azure/multicloud_azure/event_listener/listener.conf diff --git a/azure/azure/event_listener/server.py b/azure/multicloud_azure/event_listener/server.py similarity index 96% rename from azure/azure/event_listener/server.py rename to azure/multicloud_azure/event_listener/server.py index 7f1f830..90e3461 100644 --- a/azure/azure/event_listener/server.py +++ b/azure/multicloud_azure/event_listener/server.py @@ -21,8 +21,8 @@ import ConfigParser import json import os import requests -from azure.pub.config.config import MR_ADDR -from azure.pub.config.config import MR_PORT +from multicloud_azure.pub.config.config import MR_ADDR +from multicloud_azure.pub.config.config import MR_PORT LOG = logging.getLogger(__name__) diff --git a/azure/azure/middleware.py b/azure/multicloud_azure/middleware.py similarity index 93% rename from azure/azure/middleware.py rename to azure/multicloud_azure/middleware.py index 1edc44b..5b99e9a 100644 --- a/azure/azure/middleware.py +++ b/azure/multicloud_azure/middleware.py @@ -13,8 +13,8 @@ import uuid from onaplogging.mdcContext import MDC -from azure.pub.config.config import SERVICE_NAME -from azure.pub.config.config import FORWARDED_FOR_FIELDS +from multicloud_azure.pub.config.config import SERVICE_NAME +from multicloud_azure.pub.config.config import FORWARDED_FOR_FIELDS class LogContextMiddleware(object): diff --git a/azure/azure/pub/__init__.py b/azure/multicloud_azure/pub/__init__.py similarity index 100% rename from azure/azure/pub/__init__.py rename to azure/multicloud_azure/pub/__init__.py diff --git a/azure/azure/pub/config/__init__.py b/azure/multicloud_azure/pub/config/__init__.py similarity index 100% rename from azure/azure/pub/config/__init__.py rename to azure/multicloud_azure/pub/config/__init__.py diff --git a/azure/azure/pub/config/config.py b/azure/multicloud_azure/pub/config/config.py similarity index 100% rename from azure/azure/pub/config/config.py rename to azure/multicloud_azure/pub/config/config.py diff --git a/azure/azure/pub/config/log.yml b/azure/multicloud_azure/pub/config/log.yml similarity index 100% rename from azure/azure/pub/config/log.yml rename to azure/multicloud_azure/pub/config/log.yml diff --git a/azure/azure/pub/database/__init__.py b/azure/multicloud_azure/pub/database/__init__.py similarity index 100% rename from azure/azure/pub/database/__init__.py rename to azure/multicloud_azure/pub/database/__init__.py diff --git a/azure/azure/pub/database/models.py b/azure/multicloud_azure/pub/database/models.py similarity index 100% rename from azure/azure/pub/database/models.py rename to azure/multicloud_azure/pub/database/models.py diff --git a/azure/azure/pub/exceptions.py b/azure/multicloud_azure/pub/exceptions.py similarity index 100% rename from azure/azure/pub/exceptions.py rename to azure/multicloud_azure/pub/exceptions.py diff --git a/azure/azure/pub/msapi/__init__.py b/azure/multicloud_azure/pub/msapi/__init__.py similarity index 100% rename from azure/azure/pub/msapi/__init__.py rename to azure/multicloud_azure/pub/msapi/__init__.py diff --git a/azure/azure/pub/msapi/extsys.py b/azure/multicloud_azure/pub/msapi/extsys.py similarity index 84% rename from azure/azure/pub/msapi/extsys.py rename to azure/multicloud_azure/pub/msapi/extsys.py index f0b9dcc..4d78337 100644 --- a/azure/azure/pub/msapi/extsys.py +++ b/azure/multicloud_azure/pub/msapi/extsys.py @@ -12,7 +12,7 @@ import logging -from azure.pub.utils.restcall import AAIClient +from multicloud_azure.pub.utils.restcall import AAIClient logger = logging.getLogger(__name__) @@ -32,11 +32,12 @@ def get_vim_by_id(vim_id): data = { 'type': ret['cloud-type'], 'version': ret['cloud-region-version'], - 'vimId': vim_id, + 'cloud_extra_info': ret['cloud-extra-info'], + 'cloud_region_id': ret['cloud-region-id'], 'name': vim_id, - 'userName': esrInfo['user-name'], + 'username': esrInfo['user-name'], 'password': esrInfo['password'], - 'tenant': esrInfo['default-tenant'], + 'default_tenant': esrInfo['default-tenant'], 'url': esrInfo['service-url'], 'domain': esrInfo['cloud-domain'], 'cacert': esrInfo.get('ssl-cacert', ""), diff --git a/azure/azure/pub/utils/__init__.py b/azure/multicloud_azure/pub/utils/__init__.py similarity index 100% rename from azure/azure/pub/utils/__init__.py rename to azure/multicloud_azure/pub/utils/__init__.py diff --git a/azure/azure/pub/utils/enumutil.py b/azure/multicloud_azure/pub/utils/enumutil.py similarity index 100% rename from azure/azure/pub/utils/enumutil.py rename to azure/multicloud_azure/pub/utils/enumutil.py diff --git a/azure/azure/pub/utils/fileutil.py b/azure/multicloud_azure/pub/utils/fileutil.py similarity index 100% rename from azure/azure/pub/utils/fileutil.py rename to azure/multicloud_azure/pub/utils/fileutil.py diff --git a/azure/azure/pub/utils/idutil.py b/azure/multicloud_azure/pub/utils/idutil.py similarity index 100% rename from azure/azure/pub/utils/idutil.py rename to azure/multicloud_azure/pub/utils/idutil.py diff --git a/azure/azure/pub/utils/restcall.py b/azure/multicloud_azure/pub/utils/restcall.py similarity index 64% rename from azure/azure/pub/utils/restcall.py rename to azure/multicloud_azure/pub/utils/restcall.py index 4b28098..984c425 100644 --- a/azure/azure/pub/utils/restcall.py +++ b/azure/multicloud_azure/pub/utils/restcall.py @@ -18,13 +18,13 @@ import uuid import httplib2 import json -from azure.pub.config.config import AAI_SCHEMA_VERSION -from azure.pub.config.config import AAI_SERVICE_URL -from azure.pub.config.config import AAI_USERNAME -from azure.pub.config.config import AAI_PASSWORD -from azure.pub.config.config import MSB_SERVICE_IP, MSB_SERVICE_PORT +from multicloud_azure.pub.config.config import AAI_SCHEMA_VERSION +from multicloud_azure.pub.config.config import AAI_SERVICE_URL +from multicloud_azure.pub.config.config import AAI_USERNAME +from multicloud_azure.pub.config.config import AAI_PASSWORD +from multicloud_azure.pub.config.config import MSB_SERVICE_IP, MSB_SERVICE_PORT -from azure.pub.exceptions import VimDriverAzureException +from multicloud_azure.pub.exceptions import VimDriverAzureException rest_no_auth, rest_oneway_auth, rest_bothway_auth = 0, 1, 2 HTTP_200_OK, HTTP_201_CREATED = '200', '201' @@ -133,7 +133,7 @@ class AAIClient(object): self.username = AAI_USERNAME self.password = AAI_PASSWORD self.default_headers = { - 'X-FromAppId': 'multicloud-openstack-vmware', + 'X-FromAppId': 'multicloud-azure', 'X-TransactionId': '9004', 'content-type': 'application/json', 'accept': 'application/json' @@ -159,16 +159,6 @@ class AAIClient(object): def delete_vim(self): resp = self.get_vim(get_all=True) - logger.debug('Delete tenants') - self._del_tenants(resp) - logger.debug('Delete images') - self._del_images(resp) - logger.debug('Delete flavors') - self._del_flavors(resp) - logger.debug('Delete networks') - self._del_networks(resp) - logger.debug('Delete availability zones') - self._del_azs(resp) logger.debug('Delete cloud region') resource = ("/cloud-infrastructure/cloud-regions/cloud-region" "/%s/%s?resource-version=%s" % @@ -184,18 +174,7 @@ class AAIClient(object): self.cloud_owner, self.cloud_region, resp[1])) def update_vim(self, content): - # update identity url - self.update_identity_url() - # update tenants - self.add_tenants(content) - # update flavors - self.add_images(content) - # update images self.add_flavors(content) - # update networks - self.add_networks(content) - # update pservers - self.add_pservers(content) def update_identity_url(self): vim = self.get_vim() @@ -210,33 +189,18 @@ class AAIClient(object): content=json.dumps(vim), headers=self.default_headers) - def add_tenants(self, content): - for tenant in content['tenants']: - resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/tenants/tenant/%s" % ( - self.cloud_owner, self.cloud_region, tenant['id'])) - body = {'tenant-name': tenant['name']} - logger.debug("Adding tenants to cloud region") - call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "PUT", - content=json.dumps(body), - headers=self.default_headers) - def add_flavors(self, content): for flavor in content['flavors']: resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" "%s/%s/flavors/flavor/%s" % ( - self.cloud_owner, self.cloud_region, flavor['id'])) + self.cloud_owner, self.cloud_region, + flavor['name'])) body = { 'flavor-name': flavor['name'], 'flavor-vcpus': flavor['vcpus'], 'flavor-ram': flavor['ram'], 'flavor-disk': flavor['disk'], - 'flavor-ephemeral': flavor['ephemeral'], - 'flavor-swap': flavor['swap'], - 'flavor-is-public': flavor['is_public'], - 'flavor-selflink': flavor['links'][0]['href'], - 'flavor-disabled': flavor['is_disabled'] + 'flavor-selflink': "" } # Handle extra specs if flavor['name'].startswith("onap."): @@ -251,222 +215,6 @@ class AAIClient(object): content=json.dumps(body), headers=self.default_headers) - def add_images(self, content): - for image in content['images']: - resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/images/image/%s" % ( - self.cloud_owner, self.cloud_region, image['id'])) - split_image_name = image['name'].split("-") - os_distro = split_image_name[0] - os_version = split_image_name[1] if \ - len(split_image_name) > 1 else "" - body = { - 'image-name': image['name'], - # 'image-architecture': image[''], - 'image-os-distro': os_distro, - 'image-os-version': os_version, - # 'application': image[''], - # 'application-vendor': image[''], - # 'application-version': image[''], - # TODO replace this with image proxy endpoint - 'image-selflink': "", - } - logger.debug("Adding images to cloud region") - call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "PUT", - content=json.dumps(body), - headers=self.default_headers) - - def add_networks(self, content): - for network in content['networks']: - resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/oam-networks/oam-network/%s" % ( - self.cloud_owner, self.cloud_region, - network['id'])) - body = { - 'network-uuid': network['id'], - 'network-name': network['name'], - 'cvlan-tag': network['segmentationId'] or 0, - } - logger.debug("Adding networks to cloud region") - call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "PUT", - content=json.dumps(body), - headers=self.default_headers) - - def add_pservers(self, content): - for hypervisor in content['hypervisors']: - resource = ("/cloud-infrastructure/pservers/pserver/%s" % ( - hypervisor['name'])) - body = { - # 'ptnii-equip-name' - 'number-of-cpus': hypervisor['vcpus'], - 'disk-in-gigabytes': hypervisor['local_disk_size'], - 'ram-in-megabytes': hypervisor['memory_size'], - # 'equip-type' - # 'equip-vendor' - # 'equip-model' - # 'fqdn' - # 'pserver-selflink' - 'ipv4-oam-address': hypervisor['host_ip'], - # 'serial-number' - # 'ipaddress-v4-loopback-0' - # 'ipaddress-v6-loopback-0' - # 'ipaddress-v4-aim' - # 'ipaddress-v6-aim' - # 'ipaddress-v6-oam' - # 'inv-status' - 'pserver-id': hypervisor['id'], - # 'internet-topology' - } - logger.debug("Adding pservers") - call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "PUT", - content=json.dumps(body), - headers=self.default_headers) - # update relationship - resource = ("/cloud-infrastructure/pservers/pserver/%s/" - "relationship-list/relationship" % - hypervisor['name']) - related_link = ("%s/cloud-infrastructure/cloud-regions/" - "cloud-region/%s/%s" % ( - self.base_url, self.cloud_owner, - self.cloud_region)) - body = { - 'related-to': 'cloud-region', - 'related-link': related_link, - 'relationship-data': [ - { - 'relationship-key': 'cloud-region.cloud-owner', - 'relationship-value': self.cloud_owner - }, - { - 'relationship-key': 'cloud-region.cloud-region-id', - 'relationship-value': self.cloud_region - } - ] - } - logger.debug("Connecting pservers and cloud region") - call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "PUT", - content=json.dumps(body), - headers=self.default_headers) - - def _del_tenants(self, rsp): - tenants = rsp.get("tenants", []) - if not tenants: - return - for tenant in tenants["tenant"]: - resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/tenants/tenant/%s?resource-version=%s" % ( - self.cloud_owner, self.cloud_region, - tenant['tenant-id'], tenant['resource-version'])) - resp = call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "DELETE", - headers=self.default_headers) - if resp[0] != 0: - raise VimDriverAzureException( - status_code=400, - content="Failed to delete tenant %s: %s." % ( - tenant['tenant-id'], resp[1])) - - def _del_hpa(self, flavor): - hpas = flavor.get("hpa-capabilities", {}).get("hpa-capability", []) - for hpa in hpas: - resource = ( - "/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/flavors/flavor/%s/hpa-capabilities/hpa-capability/%s" - "?resource-version=%s" % ( - self.cloud_owner, self.cloud_region, - flavor['flavor-id'], hpa['hpa-capability-id'], - hpa['resource-version'])) - resp = call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "DELETE", - headers=self.default_headers) - if resp[0] != 0: - raise VimDriverAzureException( - status_code=400, - content="Failed to delete flavor %s on hpa %s: %s." % ( - flavor['flavor-id'], hpa['hpa-capability-id'], - resp[1])) - - def _del_flavors(self, rsp): - flavors = rsp.get("flavors", []) - if not flavors: - return - for flavor in flavors["flavor"]: - self._del_hpa(flavor) - resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/flavors/flavor/%s?resource-version=%s" % ( - self.cloud_owner, self.cloud_region, - flavor['flavor-id'], flavor['resource-version'])) - resp = call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "DELETE", - headers=self.default_headers) - if resp[0] != 0: - raise VimDriverAzureException( - status_code=400, - content="Failed to delete flavor %s: %s." % ( - flavor['flavor-id'], resp[1])) - - def _del_images(self, rsp): - tenants = rsp.get("images", []) - if not tenants: - return - for tenant in tenants["image"]: - resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/images/image/%s?resource-version=%s" % ( - self.cloud_owner, self.cloud_region, - tenant['image-id'], tenant['resource-version'])) - resp = call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "DELETE", - headers=self.default_headers) - if resp[0] != 0: - raise VimDriverAzureException( - status_code=400, - content="Failed to delete image %s: %s." % ( - tenant['image-id'], resp[1])) - - def _del_networks(self, rsp): - networks = rsp.get("oam-networks", []) - if not networks: - return - for network in networks["oam-network"]: - resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/oam-networks/oam-network/%s?" - "resource-version=%s" % ( - self.cloud_owner, self.cloud_region, - network['network-uuid'], - network['resource-version'])) - resp = call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "DELETE", - headers=self.default_headers) - if resp[0] != 0: - raise VimDriverAzureException( - status_code=400, - content="Failed to delete network %s: %s." % ( - network['network-uuid'], resp[1])) - - def _del_azs(self, rsp): - azs = rsp.get("availability-zones", []) - if not azs: - return - for az in azs["availability-zone"]: - resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" - "%s/%s/availability-zones/availability-zone/%s?" - "resource-version=%s" % ( - self.cloud_owner, self.cloud_region, - az['availability-zone-name'], - az['resource-version'])) - resp = call_req(self.base_url, self.username, self.password, - rest_no_auth, resource, "DELETE", - headers=self.default_headers) - if resp[0] != 0: - raise VimDriverAzureException( - status_code=400, - content="Failed to delete availability zone %s: %s." % ( - az['availability-zone-name'], resp[1])) - def _get_hpa_capabilities(self, flavor): hpa_caps = [] @@ -545,7 +293,7 @@ class AAIClient(object): basic_capability['hpa-feature-attributes'].append({ 'hpa-attribute-key': 'virtualMemSize', 'hpa-attribute-value': json.dumps({'value': str( - flavor['ram']), 'unit': 'MB'})}) + flavor['ram']), 'unit': 'GB'})}) return basic_capability @@ -689,7 +437,7 @@ class AAIClient(object): storage_capability['hpa-feature-attributes'].append({ 'hpa-attribute-key': 'diskSize', 'hpa-attribute-value': json.dumps({'value': str( - flavor['disk']), 'unit': 'GB'}) + flavor['disk']), 'unit': 'MB'}) }) storage_capability['hpa-feature-attributes'].append({ 'hpa-attribute-key': 'swapMemSize', diff --git a/azure/azure/pub/utils/syscomm.py b/azure/multicloud_azure/pub/utils/syscomm.py similarity index 100% rename from azure/azure/pub/utils/syscomm.py rename to azure/multicloud_azure/pub/utils/syscomm.py diff --git a/azure/azure/pub/utils/timeutil.py b/azure/multicloud_azure/pub/utils/timeutil.py similarity index 100% rename from azure/azure/pub/utils/timeutil.py rename to azure/multicloud_azure/pub/utils/timeutil.py diff --git a/azure/azure/pub/utils/values.py b/azure/multicloud_azure/pub/utils/values.py similarity index 100% rename from azure/azure/pub/utils/values.py rename to azure/multicloud_azure/pub/utils/values.py diff --git a/azure/azure/pub/vim/__init__.py b/azure/multicloud_azure/pub/vim/__init__.py similarity index 100% rename from azure/azure/pub/vim/__init__.py rename to azure/multicloud_azure/pub/vim/__init__.py diff --git a/azure/azure/pub/vim/const.py b/azure/multicloud_azure/pub/vim/const.py similarity index 100% rename from azure/azure/pub/vim/const.py rename to azure/multicloud_azure/pub/vim/const.py diff --git a/azure/azure/samples/__init__.py b/azure/multicloud_azure/pub/vim/vimapi/__init__.py similarity index 100% rename from azure/azure/samples/__init__.py rename to azure/multicloud_azure/pub/vim/vimapi/__init__.py diff --git a/azure/multicloud_azure/pub/vim/vimapi/baseclient.py b/azure/multicloud_azure/pub/vim/vimapi/baseclient.py new file mode 100644 index 0000000..4a9844b --- /dev/null +++ b/azure/multicloud_azure/pub/vim/vimapi/baseclient.py @@ -0,0 +1,42 @@ +# Copyright (c) 2018 Amdocs +# +# 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. + +import logging + +from multicloud_azure.pub.vim.vimsdk.azure_credentials import ClientObj +from azure.mgmt.compute import ComputeManagementClient +from azure.mgmt.resource import ResourceManagementClient + +LOG = logging.getLogger(__name__) + + +class baseclient(object): + + def __init__(self, **kwargs): + self._compute = None + self._resource = None + + def get_compute_client(self, params): + if self._compute is not None: + return self._compute + credentials = ClientObj().get_client_obj(params) + self._compute = ComputeManagementClient( + credentials, params['subscription_id']) + return self._compute + + def get_resource_client(self, params): + if self._resource is not None: + return self._resource + credentials = ClientObj.get_client_obj(params) + self._resource = ResourceManagementClient( + credentials, params['subscription_id']) + return self._resource diff --git a/azure/multicloud_azure/pub/vim/vimapi/compute/OperateCompute.py b/azure/multicloud_azure/pub/vim/vimapi/compute/OperateCompute.py new file mode 100644 index 0000000..799a0d1 --- /dev/null +++ b/azure/multicloud_azure/pub/vim/vimapi/compute/OperateCompute.py @@ -0,0 +1,29 @@ +# Copyright (c) 2018 Amdocs +# +# 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. + +import logging + +from multicloud_azure.pub.vim.vimapi.baseclient import baseclient + + +logger = logging.getLogger(__name__) + + +class OperateCompute(baseclient): + + def __init__(self, **kwargs): + super(OperateCompute, self).__init__(**kwargs) + + def request(self, op, data, **kwargs): + compute = self.get_compute_client(data) + func = getattr(compute, op) + return func diff --git a/azure/multicloud_azure/pub/vim/vimapi/compute/OperateFlavors.py b/azure/multicloud_azure/pub/vim/vimapi/compute/OperateFlavors.py new file mode 100644 index 0000000..827366b --- /dev/null +++ b/azure/multicloud_azure/pub/vim/vimapi/compute/OperateFlavors.py @@ -0,0 +1,33 @@ +# Copyright (c) 2018 Amdocs +# +# 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. + +import logging + +from OperateCompute import OperateCompute +from multicloud_azure.swagger import compute_utils +logger = logging.getLogger(__name__) + + +class OperateFlavors(OperateCompute): + + def __init__(self, **kwargs): + super(OperateFlavors, self).__init__(**kwargs) + + def list_flavors(self, data, **query): + logger.info("Inside OperateFlavors.list_flavors ") + flavors = self.request('virtual_machine_sizes', data, **query) + flavors = flavors.list(data['region_id']) + vmSizes = [] + for flavor in flavors: + result = compute_utils.convert_vmsize_aai(flavor) + vmSizes.append(result) + return vmSizes diff --git a/azure/azure/scripts/__init__.py b/azure/multicloud_azure/pub/vim/vimapi/compute/__init__.py similarity index 100% rename from azure/azure/scripts/__init__.py rename to azure/multicloud_azure/pub/vim/vimapi/compute/__init__.py diff --git a/azure/azure/swagger/__init__.py b/azure/multicloud_azure/pub/vim/vimsdk/__init__.py similarity index 100% rename from azure/azure/swagger/__init__.py rename to azure/multicloud_azure/pub/vim/vimsdk/__init__.py diff --git a/azure/multicloud_azure/pub/vim/vimsdk/azure_credentials.py b/azure/multicloud_azure/pub/vim/vimsdk/azure_credentials.py new file mode 100644 index 0000000..e66ac7b --- /dev/null +++ b/azure/multicloud_azure/pub/vim/vimsdk/azure_credentials.py @@ -0,0 +1,28 @@ +# Copyright (c) 2018 Amdocs +# +# 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. + +from azure.common.credentials import ServicePrincipalCredentials + + +class ClientObj(object): + + def get_client_obj(self, params): + if params is None: + params = {} + TENANT_ID = params['tenant_id'] + CLIENT = params['username'] + KEY = params['password'] + + credentials = ServicePrincipalCredentials(client_id=CLIENT, + secret=KEY, tenant=TENANT_ID) + + return credentials diff --git a/azure/multicloud_azure/pub/vim/vimsdk/sdk.py b/azure/multicloud_azure/pub/vim/vimsdk/sdk.py new file mode 100644 index 0000000..c716620 --- /dev/null +++ b/azure/multicloud_azure/pub/vim/vimsdk/sdk.py @@ -0,0 +1,20 @@ +# Copyright (c) 2018 Amdocs +# +# 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. + +from multicloud_azure.pub.vim.vimapi.baseclient import baseclient + + +def create_connection(params): + if params is None: + params = {} + client = baseclient.get_compute_client(params) + return client diff --git a/azure/azure/swagger/views/__init__.py b/azure/multicloud_azure/samples/__init__.py similarity index 100% rename from azure/azure/swagger/views/__init__.py rename to azure/multicloud_azure/samples/__init__.py diff --git a/azure/azure/samples/tests.py b/azure/multicloud_azure/samples/tests.py similarity index 100% rename from azure/azure/samples/tests.py rename to azure/multicloud_azure/samples/tests.py diff --git a/azure/azure/samples/urls.py b/azure/multicloud_azure/samples/urls.py similarity index 93% rename from azure/azure/samples/urls.py rename to azure/multicloud_azure/samples/urls.py index 39da376..3c10ace 100644 --- a/azure/azure/samples/urls.py +++ b/azure/multicloud_azure/samples/urls.py @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. from django.conf.urls import url -from azure.samples import views +from multicloud_azure.samples import views urlpatterns = [ url(r'^samples/$', views.SampleList.as_view()), ] diff --git a/azure/azure/samples/views.py b/azure/multicloud_azure/samples/views.py similarity index 100% rename from azure/azure/samples/views.py rename to azure/multicloud_azure/samples/views.py diff --git a/azure/azure/swagger/views/registry/__init__.py b/azure/multicloud_azure/scripts/__init__.py similarity index 100% rename from azure/azure/swagger/views/registry/__init__.py rename to azure/multicloud_azure/scripts/__init__.py diff --git a/azure/azure/scripts/api.py b/azure/multicloud_azure/scripts/api.py similarity index 95% rename from azure/azure/scripts/api.py rename to azure/multicloud_azure/scripts/api.py index 792fd5d..b516ca8 100644 --- a/azure/azure/scripts/api.py +++ b/azure/multicloud_azure/scripts/api.py @@ -22,7 +22,7 @@ import sys # noqa # python here. sys.path.append(os.path.abspath('.')) -from azure.api_v2 import service as api_service # noqa +from multicloud_azure.api_v2 import service as api_service # noqa def main(): diff --git a/azure/azure/settings-cover.py b/azure/multicloud_azure/settings-cover.py similarity index 80% rename from azure/azure/settings-cover.py rename to azure/multicloud_azure/settings-cover.py index b4fecdd..0c1316a 100644 --- a/azure/azure/settings-cover.py +++ b/azure/multicloud_azure/settings-cover.py @@ -9,8 +9,8 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -from azure.settings import * # noqa -from azure.settings import INSTALLED_APPS +from multicloud_azure.settings import * # noqa +from multicloud_azure.settings import INSTALLED_APPS INSTALLED_APPS.append('django_nose') @@ -18,5 +18,5 @@ TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' NOSE_ARGS = [ '--with-coverage', - '--cover-package=azure', + '--cover-package=multicloud_azure', ] diff --git a/azure/azure/settings.py b/azure/multicloud_azure/settings.py similarity index 89% rename from azure/azure/settings.py rename to azure/multicloud_azure/settings.py index ace6e8f..5078754 100644 --- a/azure/azure/settings.py +++ b/azure/multicloud_azure/settings.py @@ -39,7 +39,7 @@ INSTALLED_APPS = [ 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', - 'azure.pub.database', + 'multicloud_azure.pub.database', ] MIDDLEWARE_CLASSES = [ @@ -51,12 +51,12 @@ MIDDLEWARE_CLASSES = [ 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'azure.middleware.LogContextMiddleware', + 'multicloud_azure.middleware.LogContextMiddleware', ] -ROOT_URLCONF = 'azure.urls' +ROOT_URLCONF = 'multicloud_azure.urls' -WSGI_APPLICATION = 'azure.wsgi.application' +WSGI_APPLICATION = 'multicloud_azure.wsgi.application' REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': ( @@ -82,12 +82,12 @@ STATIC_URL = '/static/' LOGGING_CONFIG = None # yaml configuration of logging -LOGGING_FILE = os.path.join(BASE_DIR, 'azure/pub/config/log.yml') +LOGGING_FILE = os.path.join(BASE_DIR, 'multicloud_azure/pub/config/log.yml') config.yamlConfig(filepath=LOGGING_FILE, watchDog=True) if 'test' in sys.argv: - from azure.pub.config import config + from multicloud_azure.pub.config import config REST_FRAMEWORK = {} import platform diff --git a/azure/azure/tests/__init__.py b/azure/multicloud_azure/swagger/__init__.py similarity index 100% rename from azure/azure/tests/__init__.py rename to azure/multicloud_azure/swagger/__init__.py diff --git a/azure/multicloud_azure/swagger/compute_utils.py b/azure/multicloud_azure/swagger/compute_utils.py new file mode 100644 index 0000000..53bd587 --- /dev/null +++ b/azure/multicloud_azure/swagger/compute_utils.py @@ -0,0 +1,29 @@ +# Copyright (c) 2018 Amdocs +# +# 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. + +import six + + +def extra_specs_formatter(extra_specs): + return [{"keyName": k, "value": v} + for k, v in six.iteritems(extra_specs.extra_specs)] + + +def convert_vmsize_aai(vmsize): + + body = { + 'name': vmsize.name, + 'vcpus': vmsize.number_of_cores, + 'disk': vmsize.os_disk_size_in_mb, + 'ram': vmsize.memory_in_mb + } + return body diff --git a/azure/azure/swagger/image_utils.py b/azure/multicloud_azure/swagger/image_utils.py similarity index 100% rename from azure/azure/swagger/image_utils.py rename to azure/multicloud_azure/swagger/image_utils.py diff --git a/azure/multicloud_azure/swagger/multivim.flavor.swagger.json b/azure/multicloud_azure/swagger/multivim.flavor.swagger.json new file mode 100644 index 0000000..76e53f4 --- /dev/null +++ b/azure/multicloud_azure/swagger/multivim.flavor.swagger.json @@ -0,0 +1,365 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "MultiVIM Service rest API" + }, + "basePath": "/api/multicloud_azure/v0/", + "tags": [ + { + "name": "MultiVIM Azure services" + } + ], + "paths": { + "/{vimid}/flavors": { + "post": { + "tags": [ + "vim flavors" + ], + "summary": "create a flavor", + "description": "create a flavor", + "operationId": "create_vim_flavor", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "vimid", + "in": "path", + "description": "vim instance id", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "description": "create vim flavor request param", + "required": true, + "schema": { + "$ref": "#/definitions/CreateVimFlavor" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/VimFlavorInfo" + } + }, + "404": { + "description": "the vim id or tenant UUID is wrong" + }, + "500": { + "description": "the vim flavor is not accessable" + } + } + }, + "get": { + "tags": [ + "vim flavors" + ], + "summary": "query vim flavors list", + "description": "query vim flavors list", + "operationId": "query_vim_flavors", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "vimid", + "in": "path", + "description": "vim instance id", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "description": "get a list of vim flavors request param", + "required": false, + "schema": { + "$ref": "#/definitions/ListVimFlavors" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/VimFlavorsInfo" + } + }, + "404": { + "description": "the vim id or tenant UUID is wrong" + }, + "500": { + "description": "the vim flavor is not accessable" + } + } + } + }, + "/{vimid}/flavors/{flavorid}": { + "delete": { + "tags": [ + "vim flavors" + ], + "summary": "delete specific vim flavor", + "description": "delete specific vim flavor", + "operationId": "delete_vim_flavor", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "vimid", + "in": "path", + "description": "vim instance id", + "required": true, + "type": "string" + }, + { + "name": "flavorid", + "in": "path", + "description": "vim flavor id", + "required": true, + "type": "string" + } + ], + "responses": { + "204": { + "description": "successful operation" + }, + "404": { + "description": "the vim id or tenant UUID is wrong" + }, + "500": { + "description": "the vim flavor is not accessable" + } + } + }, + "get": { + "tags": [ + "vim flavors" + ], + "summary": "query specific vim flavor", + "description": "query specific vim flavor", + "operationId": "query_vim_flavor", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "vimid", + "in": "path", + "description": "vim instance id", + "required": true, + "type": "string" + }, + { + "name": "flavorid", + "in": "path", + "description": "vim flavor id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/VimFlavorInfo" + } + }, + "404": { + "description": "the vim id or tenant UUID is wrong" + }, + "500": { + "description": "the vim flavor is not accessable" + } + } + } + } + }, + "definitions": { + "CreateVimFlavor": { + "type": "object", + "required": [ + "vcpu", + "name", + "memory", + "disk" + ], + "properties": { + "name": { + "type": "string", + "description": "flavor name" + }, + "vcpu": { + "type": "integer", + "description": "virtual cpu number" + }, + "memory": { + "type": "integer", + "description": "memory size" + }, + "disk": { + "type": "integer", + "description": "The size of the root disk" + }, + "ephemeral": { + "type": "integer", + "description": "The size of the ephemeral disk" + }, + "swap": { + "type": "integer", + "description": "The size of the swap disk" + }, + "isPublic": { + "type": "boolean", + "description": "whether the flavor is public" + }, + "extraSpecs": { + "type": "array", + "description": "list of extra specs", + "items": { + "$ref": "#/definitions/VimFlavorExtraSpecInfo" + } + } + } + }, + "VimFlavorExtraSpecInfo": { + "type": "object", + "properties": { + "keyName": { + "type": "string", + "description": "extra spec key" + }, + "value": { + "type": "string", + "description": "extra spec value" + } + } + }, + "ListVimFlavors": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "flavor name to filter flavor list" + }, + "limit": { + "type": "integer", + "description": "Requests a page size of items" + }, + "marker": { + "type": "string", + "description": "flavor ID of the last-seen item" + } + } + }, + "VimFlavorsInfo": { + "type": "object", + "required": [ + "vimId", + "tenantId", + "flavors" + ], + "properties": { + "vimId": { + "type": "string" + }, + "vimName": { + "type": "string" + }, + "flavors": { + "type": "array", + "description": "flavor list information", + "items": { + "$ref": "#/definitions/VimFlavorInfo" + } + } + } + }, + "VimFlavorInfo": { + "type": "object", + "required": [ + "name", + "id", + "vcpu", + "memory", + "disk", + "ephemeral", + "swap", + "isPublic" + ], + "properties": { + "name": { + "type": "string", + "description": "flavor name" + }, + "id": { + "type": "string", + "description": "flavor UUID" + }, + "vcpu": { + "type": "integer", + "description": "virtual cpu number" + }, + "memory": { + "type": "integer", + "description": "memory size" + }, + "disk": { + "type": "integer", + "description": "The size of the root disk" + }, + "ephemeral": { + "type": "integer", + "description": "The size of the ephemeral disk" + }, + "swap": { + "type": "integer", + "description": "The size of the swap disk" + }, + "isPublic": { + "type": "boolean", + "description": "whether the flavor is public" + }, + "extraSpecs": { + "type": "array", + "description": "list of extra specs", + "items": { + "$ref": "#/definitions/VimFlavorExtraSpecInfo" + } + }, + "vimId": { + "type": "string" + }, + "vimName": { + "type": "string" + }, + "tenantId": { + "type": "string", + "description": "tenant UUID" + }, + "returnCode": { + "type": "integer", + "description": "0: Already exist 1: Newly created" + } + } + } + } +} diff --git a/azure/azure/swagger/tests.py b/azure/multicloud_azure/swagger/tests.py similarity index 100% rename from azure/azure/swagger/tests.py rename to azure/multicloud_azure/swagger/tests.py diff --git a/azure/azure/swagger/urls.py b/azure/multicloud_azure/swagger/urls.py similarity index 82% rename from azure/azure/swagger/urls.py rename to azure/multicloud_azure/swagger/urls.py index f80fa26..6acd327 100644 --- a/azure/azure/swagger/urls.py +++ b/azure/multicloud_azure/swagger/urls.py @@ -14,12 +14,12 @@ from django.conf.urls import url from rest_framework.urlpatterns import format_suffix_patterns -from azure.swagger.views.swagger_json import SwaggerJsonView +from multicloud_azure.swagger.views.swagger_json import SwaggerJsonView # Registry -from azure.swagger.views.registry.views import Registry -from azure.swagger.views.registry.views import UnRegistry +from multicloud_azure.swagger.views.registry.views import Registry +from multicloud_azure.swagger.views.registry.views import UnRegistry urlpatterns = [ diff --git a/azure/azure/swagger/utils.py b/azure/multicloud_azure/swagger/utils.py similarity index 100% rename from azure/azure/swagger/utils.py rename to azure/multicloud_azure/swagger/utils.py diff --git a/azure/azure/swagger/views.py b/azure/multicloud_azure/swagger/views.py similarity index 87% rename from azure/azure/swagger/views.py rename to azure/multicloud_azure/swagger/views.py index f0b7028..d6ea65c 100644 --- a/azure/azure/swagger/views.py +++ b/azure/multicloud_azure/swagger/views.py @@ -17,8 +17,8 @@ import logging from rest_framework.response import Response from rest_framework.views import APIView -# from azure.pub.exceptions import VimDriverAzureException -from azure.swagger import utils +# from multicloud_azure.pub.exceptions import VimDriverAzureException +from multicloud_azure.swagger import utils logger = logging.getLogger(__name__) diff --git a/azure/multicloud_azure/swagger/views/__init__.py b/azure/multicloud_azure/swagger/views/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/swagger/views/flavor/__init__.py b/azure/multicloud_azure/swagger/views/flavor/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/swagger/views/flavor/views.py b/azure/multicloud_azure/swagger/views/flavor/views.py new file mode 100644 index 0000000..c4eb060 --- /dev/null +++ b/azure/multicloud_azure/swagger/views/flavor/views.py @@ -0,0 +1,98 @@ +# Copyright (c) 2018 Amdocs +# +# 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. + +import json + +from rest_framework import status +from rest_framework.response import Response +from rest_framework.views import APIView + +from multicloud_azure.pub.msapi import extsys +from multicloud_azure.pub.vim.vimapi.compute import OperateFlavors +from multicloud_azure.swagger import compute_utils +from multicloud_azure.pub.exceptions import VimDriverAzureException + + +class FlavorsView(APIView): + + def post(self, request, vimid): + try: + create_req = json.loads(request.body) + except Exception as e: + return Response(data={'error': 'Fail to decode request body.'}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + try: + vim_info = extsys.get_vim_by_id(vimid) + except VimDriverAzureException as e: + return Response(data={'error': str(e)}, status=e.status_code) + + data = {'subscription_id': vim_info['cloud_extra_info'], + 'username': vim_info['username'], + 'password': vim_info['password'], + 'tenant_id': vim_info['default_tenant'], + 'region_id': vim_info['cloud_region']} + rsp = {'vimId': vim_info['cloud_extra_info'], + 'vimName': vim_info['name']} + flavor_name = create_req.get('name', None) + flavor_id = create_req.get('id', None) + flavors_op = OperateFlavors.OperateFlavors() + try: + target = flavor_id or flavor_name + flavor = flavors_op.find_flavor(data, target) + if flavor: + flavor, extra_specs = flavors_op.get_flavor( + data, flavor.id) + rsp['returnCode'] = 0 + else: + rsp['returnCode'] = 1 + flavor, extra_specs = flavors_op.create_flavor( + data, create_req) + flavor_dict = compute_utils.flavor_formatter(flavor, extra_specs) + except Exception as e: + if hasattr(e, "http_status"): + return Response(data={'error': str(e)}, status=e.http_status) + else: + return Response(data={'error': str(e)}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + rsp.update(flavor_dict) + return Response(data=rsp, status=status.HTTP_200_OK) + + def get(self, request, vimid): + try: + vim_info = extsys.get_vim_by_id(vimid) + except VimDriverAzureException as e: + return Response(data={'error': str(e)}, status=e.status_code) + + data = {'subscription_id': vim_info['cloud_extra_info'], + 'username': vim_info['username'], + 'password': vim_info['password'], + 'tenant_id': vim_info['default_tenant'], + 'region_id': vim_info['cloud_region_id']} + query = dict(request.query_params) + flavors_op = OperateFlavors.OperateFlavors() + try: + flavors_result = flavors_op.list_flavors(data, **query) + flavors_dict = [compute_utils.flavor_formatter(flavor, extra) + for flavor, extra in flavors_result] + except Exception as e: + if hasattr(e, "http_status"): + return Response(data={'error': str(e)}, status=e.http_status) + else: + return Response(data={'error': str(e)}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + rsp = {'vimId': vim_info['cloud_extra_info'], + 'vimName': vim_info['name'], + 'flavors': flavors_dict} + + return Response(data=rsp, status=status.HTTP_200_OK) diff --git a/azure/multicloud_azure/swagger/views/multivim.flavor.swagger.json b/azure/multicloud_azure/swagger/views/multivim.flavor.swagger.json new file mode 100644 index 0000000..76e53f4 --- /dev/null +++ b/azure/multicloud_azure/swagger/views/multivim.flavor.swagger.json @@ -0,0 +1,365 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "MultiVIM Service rest API" + }, + "basePath": "/api/multicloud_azure/v0/", + "tags": [ + { + "name": "MultiVIM Azure services" + } + ], + "paths": { + "/{vimid}/flavors": { + "post": { + "tags": [ + "vim flavors" + ], + "summary": "create a flavor", + "description": "create a flavor", + "operationId": "create_vim_flavor", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "vimid", + "in": "path", + "description": "vim instance id", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "description": "create vim flavor request param", + "required": true, + "schema": { + "$ref": "#/definitions/CreateVimFlavor" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/VimFlavorInfo" + } + }, + "404": { + "description": "the vim id or tenant UUID is wrong" + }, + "500": { + "description": "the vim flavor is not accessable" + } + } + }, + "get": { + "tags": [ + "vim flavors" + ], + "summary": "query vim flavors list", + "description": "query vim flavors list", + "operationId": "query_vim_flavors", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "vimid", + "in": "path", + "description": "vim instance id", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "description": "get a list of vim flavors request param", + "required": false, + "schema": { + "$ref": "#/definitions/ListVimFlavors" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/VimFlavorsInfo" + } + }, + "404": { + "description": "the vim id or tenant UUID is wrong" + }, + "500": { + "description": "the vim flavor is not accessable" + } + } + } + }, + "/{vimid}/flavors/{flavorid}": { + "delete": { + "tags": [ + "vim flavors" + ], + "summary": "delete specific vim flavor", + "description": "delete specific vim flavor", + "operationId": "delete_vim_flavor", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "vimid", + "in": "path", + "description": "vim instance id", + "required": true, + "type": "string" + }, + { + "name": "flavorid", + "in": "path", + "description": "vim flavor id", + "required": true, + "type": "string" + } + ], + "responses": { + "204": { + "description": "successful operation" + }, + "404": { + "description": "the vim id or tenant UUID is wrong" + }, + "500": { + "description": "the vim flavor is not accessable" + } + } + }, + "get": { + "tags": [ + "vim flavors" + ], + "summary": "query specific vim flavor", + "description": "query specific vim flavor", + "operationId": "query_vim_flavor", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "vimid", + "in": "path", + "description": "vim instance id", + "required": true, + "type": "string" + }, + { + "name": "flavorid", + "in": "path", + "description": "vim flavor id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/VimFlavorInfo" + } + }, + "404": { + "description": "the vim id or tenant UUID is wrong" + }, + "500": { + "description": "the vim flavor is not accessable" + } + } + } + } + }, + "definitions": { + "CreateVimFlavor": { + "type": "object", + "required": [ + "vcpu", + "name", + "memory", + "disk" + ], + "properties": { + "name": { + "type": "string", + "description": "flavor name" + }, + "vcpu": { + "type": "integer", + "description": "virtual cpu number" + }, + "memory": { + "type": "integer", + "description": "memory size" + }, + "disk": { + "type": "integer", + "description": "The size of the root disk" + }, + "ephemeral": { + "type": "integer", + "description": "The size of the ephemeral disk" + }, + "swap": { + "type": "integer", + "description": "The size of the swap disk" + }, + "isPublic": { + "type": "boolean", + "description": "whether the flavor is public" + }, + "extraSpecs": { + "type": "array", + "description": "list of extra specs", + "items": { + "$ref": "#/definitions/VimFlavorExtraSpecInfo" + } + } + } + }, + "VimFlavorExtraSpecInfo": { + "type": "object", + "properties": { + "keyName": { + "type": "string", + "description": "extra spec key" + }, + "value": { + "type": "string", + "description": "extra spec value" + } + } + }, + "ListVimFlavors": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "flavor name to filter flavor list" + }, + "limit": { + "type": "integer", + "description": "Requests a page size of items" + }, + "marker": { + "type": "string", + "description": "flavor ID of the last-seen item" + } + } + }, + "VimFlavorsInfo": { + "type": "object", + "required": [ + "vimId", + "tenantId", + "flavors" + ], + "properties": { + "vimId": { + "type": "string" + }, + "vimName": { + "type": "string" + }, + "flavors": { + "type": "array", + "description": "flavor list information", + "items": { + "$ref": "#/definitions/VimFlavorInfo" + } + } + } + }, + "VimFlavorInfo": { + "type": "object", + "required": [ + "name", + "id", + "vcpu", + "memory", + "disk", + "ephemeral", + "swap", + "isPublic" + ], + "properties": { + "name": { + "type": "string", + "description": "flavor name" + }, + "id": { + "type": "string", + "description": "flavor UUID" + }, + "vcpu": { + "type": "integer", + "description": "virtual cpu number" + }, + "memory": { + "type": "integer", + "description": "memory size" + }, + "disk": { + "type": "integer", + "description": "The size of the root disk" + }, + "ephemeral": { + "type": "integer", + "description": "The size of the ephemeral disk" + }, + "swap": { + "type": "integer", + "description": "The size of the swap disk" + }, + "isPublic": { + "type": "boolean", + "description": "whether the flavor is public" + }, + "extraSpecs": { + "type": "array", + "description": "list of extra specs", + "items": { + "$ref": "#/definitions/VimFlavorExtraSpecInfo" + } + }, + "vimId": { + "type": "string" + }, + "vimName": { + "type": "string" + }, + "tenantId": { + "type": "string", + "description": "tenant UUID" + }, + "returnCode": { + "type": "integer", + "description": "0: Already exist 1: Newly created" + } + } + } + } +} diff --git a/azure/azure/swagger/views/multivim.swagger.json b/azure/multicloud_azure/swagger/views/multivim.swagger.json similarity index 100% rename from azure/azure/swagger/views/multivim.swagger.json rename to azure/multicloud_azure/swagger/views/multivim.swagger.json diff --git a/azure/multicloud_azure/swagger/views/registry/__init__.py b/azure/multicloud_azure/swagger/views/registry/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/swagger/views/registry/views.py b/azure/multicloud_azure/swagger/views/registry/views.py new file mode 100644 index 0000000..8464ce4 --- /dev/null +++ b/azure/multicloud_azure/swagger/views/registry/views.py @@ -0,0 +1,87 @@ +# Copyright (c) 2018 Amdocs +# +# 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. + + +import logging +import json + +from rest_framework import status +from rest_framework.response import Response +from rest_framework.views import APIView + +from multicloud_azure.pub.exceptions import VimDriverAzureException +from multicloud_azure.pub.msapi import extsys +from multicloud_azure.pub.utils.restcall import AAIClient +from multicloud_azure.pub.vim.vimapi.compute import OperateFlavors + + +logger = logging.getLogger(__name__) + + +class Registry(APIView): + def _get_flavors(self, auth_info): + flavors_op = OperateFlavors.OperateFlavors() + try: + flavors = flavors_op.list_flavors(auth_info) + except Exception as e: + logger.exception("get flavors error %(e)s", {"e": e}) + raise e + + rsp = {"flavors": flavors} + return rsp + + def post(self, request, vimid): + try: + vim_info = extsys.get_vim_by_id(vimid) + except VimDriverAzureException as e: + return Response(data={'error': str(e)}, status=e.status_code) + cloud_extra_info = json.loads(vim_info['cloud_extra_info']) + data = { + 'subscription_id': cloud_extra_info['subscription_id'], + 'username': vim_info['username'], + 'password': vim_info['password'], + 'tenant_id': vim_info['default_tenant'], + 'region_id': vim_info['cloud-region-id'] + } + rsp = {} + try: + logger.debug('Getting flavors') + flavors = self._get_flavors(data) + rsp.update(flavors) + # update A&AI + logger.debug('Put data into A&AI') + cloud_owner, cloud_region = extsys.split_vim_to_owner_region( + vimid) + aai_adapter = AAIClient(cloud_owner, cloud_region) + aai_adapter.update_vim(rsp) + except Exception as e: + if hasattr(e, "http_status"): + return Response(data={'error': str(e)}, status=e.http_status) + else: + return Response(data={'error': str(e)}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + return Response(data="", status=status.HTTP_200_OK) + + +class UnRegistry(APIView): + + def delete(self, request, vimid): + try: + cloud_owner, cloud_region = extsys.split_vim_to_owner_region( + vimid) + aai_adapter = AAIClient(cloud_owner, cloud_region) + aai_adapter.delete_vim() + except Exception as e: + return Response(data=e.message, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + return Response(data="", status=status.HTTP_204_NO_CONTENT) diff --git a/azure/azure/swagger/views/swagger_json.py b/azure/multicloud_azure/swagger/views/swagger_json.py similarity index 100% rename from azure/azure/swagger/views/swagger_json.py rename to azure/multicloud_azure/swagger/views/swagger_json.py diff --git a/azure/azure/swagger/volume_utils.py b/azure/multicloud_azure/swagger/volume_utils.py similarity index 100% rename from azure/azure/swagger/volume_utils.py rename to azure/multicloud_azure/swagger/volume_utils.py diff --git a/azure/multicloud_azure/tests/__init__.py b/azure/multicloud_azure/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/azure/multicloud_azure/tests/test_aai_client.py b/azure/multicloud_azure/tests/test_aai_client.py new file mode 100644 index 0000000..c782bd9 --- /dev/null +++ b/azure/multicloud_azure/tests/test_aai_client.py @@ -0,0 +1,77 @@ +# Copyright (c) 2018 Amdocs +# +# 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. + +import mock +import unittest + +from multicloud_azure.pub.utils import restcall + + +class TestAAIClient(unittest.TestCase): + + def setUp(self): + self.view = restcall.AAIClient("vmware", "4.0") + + @mock.patch.object(restcall, "call_req") + def test_get_vim(self, mock_call): + mock_call.return_value = [0, '{"cloudOwner": "vmware"}'] + ret = self.view.get_vim(get_all=True) + expect_ret = {"cloudOwner": "vmware"} + self.assertEqual(expect_ret, ret) + + @mock.patch.object(restcall.AAIClient, "get_vim") + @mock.patch.object(restcall, "call_req") + def test_update_identity_url(self, mock_call, mock_getvim): + mock_getvim.return_value = {} + self.view.update_identity_url() + mock_call.assert_called_once() + + @mock.patch.object(restcall, "call_req") + def test_add_flavors(self, mock_call): + flavors = { + "flavors": [{ + "name": "m1.small", + "id": "1", + "vcpus": 1, + "ram": 512, + "disk": 10, + "ephemeral": 0, + "swap": 0, + "is_public": True, + "links": [{"href": "http://fake-url"}], + "is_disabled": False + }] + } + self.view.add_flavors(flavors) + mock_call.assert_called_once() + + @mock.patch.object(restcall, "call_req") + def test_add_flavors_with_hpa(self, mock_call): + flavors = { + "flavors": [{ + "name": "onap.small", + "id": "1", + "vcpus": 1, + "ram": 512, + "disk": 10, + "ephemeral": 0, + "swap": 0, + "is_public": True, + "links": [{"href": "http://fake-url"}], + "is_disabled": False, + "extra_specs": {}, + }] + } + self.view._get_ovsdpdk_capabilities = mock.MagicMock() + self.view._get_ovsdpdk_capabilities.return_value = {} + self.view.add_flavors(flavors) + mock_call.assert_called_once() diff --git a/azure/multicloud_azure/tests/test_flavor_view.py b/azure/multicloud_azure/tests/test_flavor_view.py new file mode 100644 index 0000000..d946ece --- /dev/null +++ b/azure/multicloud_azure/tests/test_flavor_view.py @@ -0,0 +1,76 @@ +# Copyright (c) 2018 Amdocs +# +# 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. + +import unittest + +import mock +from multicloud_azure.pub.msapi import extsys +from multicloud_azure.pub.vim.vimapi.compute import OperateFlavors +from multicloud_azure.swagger import compute_utils +from multicloud_azure.swagger.views.flavor.views import FlavorsView +from rest_framework import status + +VIM_INFO = {'cloud_extra_info': 1, 'username': 'user1', + 'password': '1234', 'default_tenant': 't1', + 'cloud_region_id': 'r1'} + + +class FlavorViewTest(unittest.TestCase): + + def setUp(self): + self.fsv = FlavorsView() + + def tearDown(self): + pass + + @mock.patch.object(compute_utils, 'convert_vmsize_aai') + @mock.patch.object(OperateFlavors.OperateFlavors, 'list_flavors') + @mock.patch.object(extsys, 'get_vim_by_id') + def test_flavors_get_fail(self, mock_vim_info, + mock_flavors, mock_formatter): + mock_vim_info.return_value = VIM_INFO + + class Flavor: + def __init__(self, id, name): + self.id = id + self.name = name + f1 = Flavor(1, "f1") + f2 = Flavor(2, "f2") + flavors = [f1, f2] + mock_flavors.return_value = flavors + mock_formatter.return_value = flavors + + class Request: + def __init__(self, query_params): + self.query_params = query_params + req = Request({'k': 'v'}) + self.assertEqual( + status.HTTP_500_INTERNAL_SERVER_ERROR, + self.fsv.get(req, "vimid").status_code) + + def test_vmsize_aai(self): + expected = { + 'name': "abc", + 'vcpus': 1, + 'ram': 123, + 'disk': 1234 + } + + class VmSize: + def __init__(self, name, number_of_cores, memory_in_mb, + os_disk_size_in_mb): + self.name = name + self.number_of_cores = number_of_cores + self.memory_in_mb = memory_in_mb + self.os_disk_size_in_mb = os_disk_size_in_mb + v1 = VmSize("abc", 1, 123, 1234) + self.assertEquals(expected, compute_utils.convert_vmsize_aai(v1)) diff --git a/azure/azure/tests/test_restcall.py b/azure/multicloud_azure/tests/test_restcall.py similarity index 98% rename from azure/azure/tests/test_restcall.py rename to azure/multicloud_azure/tests/test_restcall.py index bf45ccf..9f60317 100644 --- a/azure/azure/tests/test_restcall.py +++ b/azure/multicloud_azure/tests/test_restcall.py @@ -12,7 +12,7 @@ import mock import unittest import urllib2 -from azure.pub.utils import restcall +from multicloud_azure.pub.utils import restcall class TestRestCall(unittest.TestCase): diff --git a/azure/azure/tests/test_syscomm.py b/azure/multicloud_azure/tests/test_syscomm.py similarity index 96% rename from azure/azure/tests/test_syscomm.py rename to azure/multicloud_azure/tests/test_syscomm.py index d700ed7..12507a4 100644 --- a/azure/azure/tests/test_syscomm.py +++ b/azure/multicloud_azure/tests/test_syscomm.py @@ -12,7 +12,7 @@ import unittest -from azure.pub.utils import syscomm +from multicloud_azure.pub.utils import syscomm class SyscommTest(unittest.TestCase): diff --git a/azure/azure/urls.py b/azure/multicloud_azure/urls.py similarity index 82% rename from azure/azure/urls.py rename to azure/multicloud_azure/urls.py index 028f008..bcc63b1 100644 --- a/azure/azure/urls.py +++ b/azure/multicloud_azure/urls.py @@ -13,6 +13,6 @@ from django.conf.urls import include, url urlpatterns = [ - url(r'^', include('azure.swagger.urls')), - url(r'^', include('azure.samples.urls')), + url(r'^', include('multicloud_azure.swagger.urls')), + url(r'^', include('multicloud_azure.samples.urls')), ] diff --git a/azure/azure/wsgi.py b/azure/multicloud_azure/wsgi.py similarity index 88% rename from azure/azure/wsgi.py rename to azure/multicloud_azure/wsgi.py index 355b604..f6f77d6 100644 --- a/azure/azure/wsgi.py +++ b/azure/multicloud_azure/wsgi.py @@ -15,6 +15,6 @@ import os from django.core.wsgi import get_wsgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "azure.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "multicloud_azure.settings") application = get_wsgi_application() diff --git a/azure/requirements.txt b/azure/requirements.txt index aa98578..f7225e9 100644 --- a/azure/requirements.txt +++ b/azure/requirements.txt @@ -37,3 +37,9 @@ oslo.config>=4.11.0 oslo.service>=1.25.0 eventlet>=0.20.0 PyYAML>=3.1.0 + +#azure +azure-mgmt-resource==2.0.0 +azure-mgmt-compute==4.0.1 +azure-mgmt-authorization==0.50.0 +azure-common==1.1.14 diff --git a/azure/run.sh b/azure/run.sh index 6883739..5ec19e2 100644 --- a/azure/run.sh +++ b/azure/run.sh @@ -31,8 +31,8 @@ then python multivimbroker/scripts/api.py else # nohup python manage.py runserver 0.0.0.0:9008 2>&1 & - nohup uwsgi --http :9008 --module azure.wsgi --master --processes 4 & - nohup python -m azure.event_listener.server 2>&1 & + nohup uwsgi --http :9008 --module multicloud_azure.wsgi --master --processes 4 & + nohup python -m multicloud_azure.event_listener.server 2>&1 & while [ ! -f $logDir/azure.log ]; do sleep 1 diff --git a/azure/setup.py b/azure/setup.py index c81e04f..92167ca 100644 --- a/azure/setup.py +++ b/azure/setup.py @@ -15,7 +15,7 @@ import setuptools setuptools.setup( - name="azure", + name="azure-plugin", version="1.0", packages=setuptools.find_packages(), include_package_data=True, diff --git a/azure/stop.sh b/azure/stop.sh index 04e822a..3c367de 100644 --- a/azure/stop.sh +++ b/azure/stop.sh @@ -12,4 +12,4 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # ps auxww | grep 'manage.py runserver 0.0.0.0:9004' | awk '{print $2}' | xargs kill -9 -ps auxww |grep 'uwsgi --http :9004 --module azure.wsgi --master' |awk '{print $2}' |xargs kill -9 +ps auxww |grep 'uwsgi --http :9004 --module multicloud_azure.wsgi --master' |awk '{print $2}' |xargs kill -9 diff --git a/azure/tox.ini b/azure/tox.ini index d6559ab..4c2c67e 100644 --- a/azure/tox.ini +++ b/azure/tox.ini @@ -9,7 +9,7 @@ downloadcache = ~/cache/pip deps = -r{toxinidir}/requirements.txt commands = /usr/bin/find . -type f -name "*.py[c|o]" -delete - python manage.py test azure + python manage.py test multicloud_azure [testenv:pep8] deps=flake8 @@ -21,7 +21,7 @@ commands = [testenv:cover] setenv= - DJANGO_SETTINGS_MODULE = azure.settings-cover + DJANGO_SETTINGS_MODULE = multicloud_azure.settings-cover commands = coverage erase {[testenv]commands} diff --git a/sonar.sh b/sonar.sh index 25cc44c..eee6415 100755 --- a/sonar.sh +++ b/sonar.sh @@ -58,7 +58,7 @@ run_tox_test() pip install --upgrade pip pip install --upgrade tox argparse pip freeze - cd azure + cd multicloud_azure tox -e cover deactivate cd ..