Added V0 Registry API 59/64959/2
authorSudhakarReddy <Sudhakar.Reddy@amdocs.com>
Thu, 6 Sep 2018 09:37:26 +0000 (12:37 +0300)
committerSudhakarReddy <Sudhakar.Reddy@amdocs.com>
Thu, 6 Sep 2018 09:54:35 +0000 (12:54 +0300)
Change-Id: Iac61b136485ddb06b76d8b701ab51e8e18439e94
Issue-ID: MULTICLOUD-354
Signed-off-by: SudhakarReddy <Sudhakar.Reddy@amdocs.com>
89 files changed:
azure/assembly.xml
azure/azure/swagger/views/registry/views.py [deleted file]
azure/azure/tests/test_aai_client.py [deleted file]
azure/manage.py
azure/multicloud_azure/__init__.py [moved from azure/azure/__init__.py with 100% similarity]
azure/multicloud_azure/api_v2/__init__.py [moved from azure/azure/api_v2/__init__.py with 100% similarity]
azure/multicloud_azure/api_v2/api_definition/__init__.py [moved from azure/azure/api_v2/api_definition/__init__.py with 100% similarity]
azure/multicloud_azure/api_v2/api_definition/hosts.yaml [moved from azure/azure/api_v2/api_definition/hosts.yaml with 100% similarity]
azure/multicloud_azure/api_v2/api_definition/images.yaml [moved from azure/azure/api_v2/api_definition/images.yaml with 100% similarity]
azure/multicloud_azure/api_v2/api_definition/networks.yaml [moved from azure/azure/api_v2/api_definition/networks.yaml with 100% similarity]
azure/multicloud_azure/api_v2/api_definition/ports.yaml [moved from azure/azure/api_v2/api_definition/ports.yaml with 100% similarity]
azure/multicloud_azure/api_v2/api_definition/subnets.yaml [moved from azure/azure/api_v2/api_definition/subnets.yaml with 100% similarity]
azure/multicloud_azure/api_v2/api_definition/utils.py [moved from azure/azure/api_v2/api_definition/utils.py with 100% similarity]
azure/multicloud_azure/api_v2/api_router/__init__.py [moved from azure/azure/api_v2/api_router/__init__.py with 100% similarity]
azure/multicloud_azure/api_v2/api_router/root.py [moved from azure/azure/api_v2/api_router/root.py with 93% similarity]
azure/multicloud_azure/api_v2/api_router/swagger_json.py [moved from azure/azure/api_v2/api_router/swagger_json.py with 94% similarity]
azure/multicloud_azure/api_v2/api_router/v0_controller.py [moved from azure/azure/api_v2/api_router/v0_controller.py with 95% similarity]
azure/multicloud_azure/api_v2/app.py [moved from azure/azure/api_v2/app.py with 100% similarity]
azure/multicloud_azure/api_v2/service.py [moved from azure/azure/api_v2/service.py with 93% similarity]
azure/multicloud_azure/event_listener/__init__.py [moved from azure/azure/event_listener/__init__.py with 100% similarity]
azure/multicloud_azure/event_listener/i18n.py [moved from azure/azure/event_listener/i18n.py with 100% similarity]
azure/multicloud_azure/event_listener/listener.conf [moved from azure/azure/event_listener/listener.conf with 100% similarity]
azure/multicloud_azure/event_listener/server.py [moved from azure/azure/event_listener/server.py with 96% similarity]
azure/multicloud_azure/middleware.py [moved from azure/azure/middleware.py with 93% similarity]
azure/multicloud_azure/pub/__init__.py [moved from azure/azure/pub/__init__.py with 100% similarity]
azure/multicloud_azure/pub/config/__init__.py [moved from azure/azure/pub/config/__init__.py with 100% similarity]
azure/multicloud_azure/pub/config/config.py [moved from azure/azure/pub/config/config.py with 100% similarity]
azure/multicloud_azure/pub/config/log.yml [moved from azure/azure/pub/config/log.yml with 100% similarity]
azure/multicloud_azure/pub/database/__init__.py [moved from azure/azure/pub/database/__init__.py with 100% similarity]
azure/multicloud_azure/pub/database/models.py [moved from azure/azure/pub/database/models.py with 100% similarity]
azure/multicloud_azure/pub/exceptions.py [moved from azure/azure/pub/exceptions.py with 100% similarity]
azure/multicloud_azure/pub/msapi/__init__.py [moved from azure/azure/pub/msapi/__init__.py with 100% similarity]
azure/multicloud_azure/pub/msapi/extsys.py [moved from azure/azure/pub/msapi/extsys.py with 84% similarity]
azure/multicloud_azure/pub/utils/__init__.py [moved from azure/azure/pub/utils/__init__.py with 100% similarity]
azure/multicloud_azure/pub/utils/enumutil.py [moved from azure/azure/pub/utils/enumutil.py with 100% similarity]
azure/multicloud_azure/pub/utils/fileutil.py [moved from azure/azure/pub/utils/fileutil.py with 100% similarity]
azure/multicloud_azure/pub/utils/idutil.py [moved from azure/azure/pub/utils/idutil.py with 100% similarity]
azure/multicloud_azure/pub/utils/restcall.py [moved from azure/azure/pub/utils/restcall.py with 64% similarity]
azure/multicloud_azure/pub/utils/syscomm.py [moved from azure/azure/pub/utils/syscomm.py with 100% similarity]
azure/multicloud_azure/pub/utils/timeutil.py [moved from azure/azure/pub/utils/timeutil.py with 100% similarity]
azure/multicloud_azure/pub/utils/values.py [moved from azure/azure/pub/utils/values.py with 100% similarity]
azure/multicloud_azure/pub/vim/__init__.py [moved from azure/azure/pub/vim/__init__.py with 100% similarity]
azure/multicloud_azure/pub/vim/const.py [moved from azure/azure/pub/vim/const.py with 100% similarity]
azure/multicloud_azure/pub/vim/vimapi/__init__.py [moved from azure/azure/samples/__init__.py with 100% similarity]
azure/multicloud_azure/pub/vim/vimapi/baseclient.py [new file with mode: 0644]
azure/multicloud_azure/pub/vim/vimapi/compute/OperateCompute.py [new file with mode: 0644]
azure/multicloud_azure/pub/vim/vimapi/compute/OperateFlavors.py [new file with mode: 0644]
azure/multicloud_azure/pub/vim/vimapi/compute/__init__.py [moved from azure/azure/scripts/__init__.py with 100% similarity]
azure/multicloud_azure/pub/vim/vimsdk/__init__.py [moved from azure/azure/swagger/__init__.py with 100% similarity]
azure/multicloud_azure/pub/vim/vimsdk/azure_credentials.py [new file with mode: 0644]
azure/multicloud_azure/pub/vim/vimsdk/sdk.py [new file with mode: 0644]
azure/multicloud_azure/samples/__init__.py [moved from azure/azure/swagger/views/__init__.py with 100% similarity]
azure/multicloud_azure/samples/tests.py [moved from azure/azure/samples/tests.py with 100% similarity]
azure/multicloud_azure/samples/urls.py [moved from azure/azure/samples/urls.py with 93% similarity]
azure/multicloud_azure/samples/views.py [moved from azure/azure/samples/views.py with 100% similarity]
azure/multicloud_azure/scripts/__init__.py [moved from azure/azure/swagger/views/registry/__init__.py with 100% similarity]
azure/multicloud_azure/scripts/api.py [moved from azure/azure/scripts/api.py with 95% similarity]
azure/multicloud_azure/settings-cover.py [moved from azure/azure/settings-cover.py with 80% similarity]
azure/multicloud_azure/settings.py [moved from azure/azure/settings.py with 89% similarity]
azure/multicloud_azure/swagger/__init__.py [moved from azure/azure/tests/__init__.py with 100% similarity]
azure/multicloud_azure/swagger/compute_utils.py [new file with mode: 0644]
azure/multicloud_azure/swagger/image_utils.py [moved from azure/azure/swagger/image_utils.py with 100% similarity]
azure/multicloud_azure/swagger/multivim.flavor.swagger.json [new file with mode: 0644]
azure/multicloud_azure/swagger/tests.py [moved from azure/azure/swagger/tests.py with 100% similarity]
azure/multicloud_azure/swagger/urls.py [moved from azure/azure/swagger/urls.py with 82% similarity]
azure/multicloud_azure/swagger/utils.py [moved from azure/azure/swagger/utils.py with 100% similarity]
azure/multicloud_azure/swagger/views.py [moved from azure/azure/swagger/views.py with 87% similarity]
azure/multicloud_azure/swagger/views/__init__.py [new file with mode: 0644]
azure/multicloud_azure/swagger/views/flavor/__init__.py [new file with mode: 0644]
azure/multicloud_azure/swagger/views/flavor/views.py [new file with mode: 0644]
azure/multicloud_azure/swagger/views/multivim.flavor.swagger.json [new file with mode: 0644]
azure/multicloud_azure/swagger/views/multivim.swagger.json [moved from azure/azure/swagger/views/multivim.swagger.json with 100% similarity]
azure/multicloud_azure/swagger/views/registry/__init__.py [new file with mode: 0644]
azure/multicloud_azure/swagger/views/registry/views.py [new file with mode: 0644]
azure/multicloud_azure/swagger/views/swagger_json.py [moved from azure/azure/swagger/views/swagger_json.py with 100% similarity]
azure/multicloud_azure/swagger/volume_utils.py [moved from azure/azure/swagger/volume_utils.py with 100% similarity]
azure/multicloud_azure/tests/__init__.py [new file with mode: 0644]
azure/multicloud_azure/tests/test_aai_client.py [new file with mode: 0644]
azure/multicloud_azure/tests/test_flavor_view.py [new file with mode: 0644]
azure/multicloud_azure/tests/test_restcall.py [moved from azure/azure/tests/test_restcall.py with 98% similarity]
azure/multicloud_azure/tests/test_syscomm.py [moved from azure/azure/tests/test_syscomm.py with 96% similarity]
azure/multicloud_azure/urls.py [moved from azure/azure/urls.py with 82% similarity]
azure/multicloud_azure/wsgi.py [moved from azure/azure/wsgi.py with 88% similarity]
azure/requirements.txt
azure/run.sh
azure/setup.py
azure/stop.sh
azure/tox.ini
sonar.sh

index 61a4883..48255fd 100644 (file)
@@ -20,8 +20,8 @@
     </formats>
     <fileSets>
         <fileSet>
-            <directory>azure</directory>
-            <outputDirectory>/azure</outputDirectory>
+            <directory>multicloud_azure</directory>
+            <outputDirectory>/multicloud_azure</outputDirectory>
             <includes>
                 <include>**/*.py</include>
                 <include>**/*.json</include>
@@ -61,6 +61,6 @@
             </includes>
         </fileSet>
     </fileSets>
-    <baseDirectory>azure</baseDirectory>
+    <baseDirectory>multicloud_azure</baseDirectory>
     <!--baseDirectory>multivimdriver-openstack/azure</baseDirectory-->
 </assembly>
diff --git a/azure/azure/swagger/views/registry/views.py b/azure/azure/swagger/views/registry/views.py
deleted file mode 100644 (file)
index b5db805..0000000
+++ /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 (file)
index 31ff37d..0000000
+++ /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"]))
index 4a98417..9b219de 100644 (file)
@@ -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
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 (file)
@@ -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):
@@ -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):
@@ -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):
similarity index 93%
rename from azure/azure/api_v2/service.py
rename to azure/multicloud_azure/api_v2/service.py
index 2b73c15..d6e3923 100644 (file)
@@ -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
similarity index 96%
rename from azure/azure/event_listener/server.py
rename to azure/multicloud_azure/event_listener/server.py
index 7f1f830..90e3461 100644 (file)
@@ -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__)
similarity index 93%
rename from azure/azure/middleware.py
rename to azure/multicloud_azure/middleware.py
index 1edc44b..5b99e9a 100644 (file)
@@ -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):
similarity index 84%
rename from azure/azure/pub/msapi/extsys.py
rename to azure/multicloud_azure/pub/msapi/extsys.py
index f0b9dcc..4d78337 100644 (file)
@@ -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', ""),
similarity index 64%
rename from azure/azure/pub/utils/restcall.py
rename to azure/multicloud_azure/pub/utils/restcall.py
index 4b28098..984c425 100644 (file)
@@ -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/multicloud_azure/pub/vim/vimapi/baseclient.py b/azure/multicloud_azure/pub/vim/vimapi/baseclient.py
new file mode 100644 (file)
index 0000000..4a9844b
--- /dev/null
@@ -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 (file)
index 0000000..799a0d1
--- /dev/null
@@ -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 (file)
index 0000000..827366b
--- /dev/null
@@ -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/multicloud_azure/pub/vim/vimsdk/azure_credentials.py b/azure/multicloud_azure/pub/vim/vimsdk/azure_credentials.py
new file mode 100644 (file)
index 0000000..e66ac7b
--- /dev/null
@@ -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 (file)
index 0000000..c716620
--- /dev/null
@@ -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
similarity index 93%
rename from azure/azure/samples/urls.py
rename to azure/multicloud_azure/samples/urls.py
index 39da376..3c10ace 100644 (file)
@@ -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()), ]
similarity index 95%
rename from azure/azure/scripts/api.py
rename to azure/multicloud_azure/scripts/api.py
index 792fd5d..b516ca8 100644 (file)
@@ -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():
similarity index 80%
rename from azure/azure/settings-cover.py
rename to azure/multicloud_azure/settings-cover.py
index b4fecdd..0c1316a 100644 (file)
@@ -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',
 ]
similarity index 89%
rename from azure/azure/settings.py
rename to azure/multicloud_azure/settings.py
index ace6e8f..5078754 100644 (file)
@@ -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/multicloud_azure/swagger/compute_utils.py b/azure/multicloud_azure/swagger/compute_utils.py
new file mode 100644 (file)
index 0000000..53bd587
--- /dev/null
@@ -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/multicloud_azure/swagger/multivim.flavor.swagger.json b/azure/multicloud_azure/swagger/multivim.flavor.swagger.json
new file mode 100644 (file)
index 0000000..76e53f4
--- /dev/null
@@ -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"
+        }
+      }
+    }
+  }
+}
similarity index 82%
rename from azure/azure/swagger/urls.py
rename to azure/multicloud_azure/swagger/urls.py
index f80fa26..6acd327 100644 (file)
 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 = [
similarity index 87%
rename from azure/azure/swagger/views.py
rename to azure/multicloud_azure/swagger/views.py
index f0b7028..d6ea65c 100644 (file)
@@ -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 (file)
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 (file)
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 (file)
index 0000000..c4eb060
--- /dev/null
@@ -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 (file)
index 0000000..76e53f4
--- /dev/null
@@ -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/multicloud_azure/swagger/views/registry/__init__.py b/azure/multicloud_azure/swagger/views/registry/__init__.py
new file mode 100644 (file)
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 (file)
index 0000000..8464ce4
--- /dev/null
@@ -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/multicloud_azure/tests/__init__.py b/azure/multicloud_azure/tests/__init__.py
new file mode 100644 (file)
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 (file)
index 0000000..c782bd9
--- /dev/null
@@ -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 (file)
index 0000000..d946ece
--- /dev/null
@@ -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))
similarity index 98%
rename from azure/azure/tests/test_restcall.py
rename to azure/multicloud_azure/tests/test_restcall.py
index bf45ccf..9f60317 100644 (file)
@@ -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):
similarity index 96%
rename from azure/azure/tests/test_syscomm.py
rename to azure/multicloud_azure/tests/test_syscomm.py
index d700ed7..12507a4 100644 (file)
@@ -12,7 +12,7 @@
 
 import unittest
 
-from azure.pub.utils import syscomm
+from multicloud_azure.pub.utils import syscomm
 
 
 class SyscommTest(unittest.TestCase):
similarity index 82%
rename from azure/azure/urls.py
rename to azure/multicloud_azure/urls.py
index 028f008..bcc63b1 100644 (file)
@@ -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')),
 ]
similarity index 88%
rename from azure/azure/wsgi.py
rename to azure/multicloud_azure/wsgi.py
index 355b604..f6f77d6 100644 (file)
@@ -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()
index aa98578..f7225e9 100644 (file)
@@ -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
index 6883739..5ec19e2 100644 (file)
@@ -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
index c81e04f..92167ca 100644 (file)
@@ -15,7 +15,7 @@
 import setuptools
 
 setuptools.setup(
-    name="azure",
+    name="azure-plugin",
     version="1.0",
     packages=setuptools.find_packages(),
     include_package_data=True,
index 04e822a..3c367de 100644 (file)
@@ -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
index d6559ab..4c2c67e 100644 (file)
@@ -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}
index 25cc44c..eee6415 100755 (executable)
--- 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 ..