diff options
Diffstat (limited to 'vio')
-rw-r--r-- | vio/docker/Dockerfile | 4 | ||||
-rw-r--r-- | vio/requirements.txt | 14 | ||||
-rwxr-xr-x | vio/run.sh | 17 | ||||
-rwxr-xr-x | vio/stop.sh | 3 | ||||
-rw-r--r-- | vio/vio/api_v2/api_definition/images.yaml | 76 | ||||
-rw-r--r-- | vio/vio/api_v2/api_definition/ports.yaml | 83 | ||||
-rw-r--r-- | vio/vio/api_v2/api_router/controller_builder.py | 68 | ||||
-rwxr-xr-x | vio/vio/event_listener/server.py | 7 | ||||
-rw-r--r-- | vio/vio/pub/config/config.py | 4 | ||||
-rw-r--r-- | vio/vio/settings.py | 4 | ||||
-rw-r--r-- | vio/vio/swagger/urls.py | 7 | ||||
-rw-r--r-- | vio/vio/swagger/views/fakeplugin/fakeData/fakeResponse.py | 27 | ||||
-rw-r--r-- | vio/vio/swagger/views/fakeplugin/image/views.py | 18 | ||||
-rw-r--r-- | vio/vio/tests/test_aai_client.py | 169 | ||||
-rw-r--r-- | vio/vio/tests/test_image_view.py | 93 | ||||
-rw-r--r-- | vio/vio/tests/test_proxy_identity_view.py | 264 | ||||
-rw-r--r-- | vio/vio/tests/test_restcall.py | 66 |
17 files changed, 880 insertions, 44 deletions
diff --git a/vio/docker/Dockerfile b/vio/docker/Dockerfile index 9c67741..30d7ce8 100644 --- a/vio/docker/Dockerfile +++ b/vio/docker/Dockerfile @@ -7,8 +7,8 @@ ENV AAI_PORT "8443" ENV AAI_SCHEMA_VERSION "v11" ENV AAI_USERNAME "AAI" ENV AAI_PASSWORD "AAI" -ENV MR_ADDR “127.0.0.1” -ENV MR_PORT “3904” +ENV MR_ADDR "127.0.0.1" +ENV MR_PORT "3904" EXPOSE 9004 diff --git a/vio/requirements.txt b/vio/requirements.txt index 32384a9..1e2334c 100644 --- a/vio/requirements.txt +++ b/vio/requirements.txt @@ -13,7 +13,7 @@ django-redis-cache==0.13.1 httplib2==0.9.2 # for call openstack api -openstacksdk==0.9.14 +openstacksdk==0.9.15 python-cinderclient==3.5.0 # for unit test @@ -24,3 +24,15 @@ unittest_xml_reporting==1.12.0 # for onap logging onappylog>=1.0.6 + +# for event +oslo_messaging + +# for pecan framework +uwsgi +pecan>=1.2.1 +oslo.concurrency>=3.21.0 +oslo.config>=4.11.0 +oslo.service>=1.25.0 +eventlet>=0.20.0 +PyYAML>=3.1.0 @@ -26,11 +26,16 @@ sed -i "s/MR_PORT =.*/MR_PORT = \"${MR_PORT}\"/g" vio/pub/config/config.py logDir="/var/log/onap/multicloud/vio" -nohup python manage.py runserver 0.0.0.0:9004 2>&1 & -nohup python vio/event_listener/server.py 2>&1 & - -while [ ! -f $logDir/vio.log ]; do - sleep 1 -done +if [ "$WEB_FRAMEWORK" == "pecan" ] +then + python multivimbroker/scripts/api.py +else + # nohup python manage.py runserver 0.0.0.0:9004 2>&1 & + nohup uwsgi --http :9004 --module vio.wsgi --master --processes 4 & + nohup python vio/event_listener/server.py 2>&1 & + while [ ! -f $logDir/vio.log ]; do + sleep 1 + done tail -F $logDir/vio.log +fi diff --git a/vio/stop.sh b/vio/stop.sh index 718b3cb..e07394a 100755 --- a/vio/stop.sh +++ b/vio/stop.sh @@ -11,4 +11,5 @@ # distributed under the License is distributed on an "AS IS" BASIS, # 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 'manage.py runserver 0.0.0.0:9004' | awk '{print $2}' | xargs kill -9 +ps auxww |grep 'uwsgi --http :9004 --module vio.wsgi --master' |awk '{print $2}' |xargs kill -9 diff --git a/vio/vio/api_v2/api_definition/images.yaml b/vio/vio/api_v2/api_definition/images.yaml new file mode 100644 index 0000000..f2e4e72 --- /dev/null +++ b/vio/vio/api_v2/api_definition/images.yaml @@ -0,0 +1,76 @@ +--- + info: + version: "1.0.0" + title: "Multi Cloud Image" + description: "Definition of Image API" + termsOfService: "http://swagger.io/terms/" + schemes: + - "http" + produces: + - "application/json" + paths: + /{vimid}/{tenantid}/images/{imageid}: + parameters: + - type: string + name: vimid + - type: string + format: uuid + name: tenantid + - type: string + name: imageid + in: path + required: true + get: + produces: + - "application/json" + responses: + "200": + schema: + $ref: "#/definitions/image" + get_all: + produces: + - "application/json" + responses: + "200": + schema: + type: "array" + items: + $ref: "#/definitions/image" + post: + produces: + - "application/json" + responses: + "200": + schema: + $ref: "#/definitions/image" + delete: + responses: "204" + vim_path: "/image/v2/images" + definitions: + image: + plural_vim_resource: "images" + vim_resource: "image" + plural: "images" + properties: + name: + type: string + required: true + source: image.name + id: + type: string + source: image.id + status: + type: string + source: image.status + imageType: + type: string + source: image.disk_format + containerFormat: + type: string + source: image.container_format + visibility: + type: string + source: image.visibility + size: + type: integer + source: image.size diff --git a/vio/vio/api_v2/api_definition/ports.yaml b/vio/vio/api_v2/api_definition/ports.yaml new file mode 100644 index 0000000..0599ae2 --- /dev/null +++ b/vio/vio/api_v2/api_definition/ports.yaml @@ -0,0 +1,83 @@ +--- + info: + version: "1.0.0" + title: "Multi Cloud Port" + description: "Definition of Port API" + termsOfService: "http://swagger.io/terms/" + schemes: + - "http" + produces: + - "application/json" + paths: + /{vimid}/{tenantid}/ports/{portid}: + parameters: + - type: string + name: vimid + - type: string + format: uuid + name: tenantid + - type: string + name: portid + in: path + required: true + get: + produces: + - "application/json" + responses: + "200": + schema: + $ref: "#/definitions/port" + get_all: + produces: + - "application/json" + responses: + "200": + schema: + type: "array" + items: + $ref: "#/definitions/port" + post: + produces: + - "application/json" + responses: + "200": + schema: + $ref: "#/definitions/port" + delete: + responses: "204" + vim_path: "/network/v2.0/ports" + definitions: + port: + plural_vim_resource: "ports" + vim_resource: "port" + plural: "port" + properties: + name: + type: string + required: true + source: port.name + id: + type: string + source: port.id + status: + type: string + source: port.status + networkId: + type: string + source: port.network_id + required: true + vnicType: + source: port.binding:vnic_type + securityGroups: + type: string + source: port.security_groups + tenantId: + type: string + source: port.tenant_id + macAddress: + type: string + source: port.mac_address + subnetId: + source: port.fixed_ips[0].subnet_id + ip: + source: port.fixed_ips[0].ip_address diff --git a/vio/vio/api_v2/api_router/controller_builder.py b/vio/vio/api_v2/api_router/controller_builder.py index 9c01301..a3c70b2 100644 --- a/vio/vio/api_v2/api_router/controller_builder.py +++ b/vio/vio/api_v2/api_router/controller_builder.py @@ -16,12 +16,16 @@ from keystoneauth1.identity import v3 as keystone_v3 from keystoneauth1 import session import pecan from pecan import rest +import re from vio.api_v2.api_definition import utils from vio.pub import exceptions from vio.pub.msapi import extsys +OBJ_IN_ARRAY = "(\w+)\[(\d+)\]\.(\w+)" + + def _get_vim_auth_session(vim_id, tenant_id): """ Get the auth session to backend VIM """ @@ -67,48 +71,56 @@ def _convert_default_value(default): return default +def _property_exists(resource, attr, required=False): + if attr not in resource: + if required: + raise Exception("Required field %s is missed in VIM " + "resource %s", (attr, resource)) + else: + return False + + return True + + def _convert_vim_res_to_mc_res(vim_resource, res_properties): mc_resource = {} for key in res_properties: - vim_res, attr = res_properties[key]["source"].split('.') - - if attr not in vim_resource[vim_res]: - if res_properties[key].get("required"): - raise Exception("Required field %s is missed in VIM " - "resource %s", (attr, vim_resource)) + vim_res, attr = res_properties[key]["source"].split('.', 1) + # action = res_properties[key].get("action", "copy") + if re.match(OBJ_IN_ARRAY, attr): + attr, index, sub_attr = re.match(OBJ_IN_ARRAY, attr).groups() + if _property_exists(vim_resource[vim_res], attr): + mc_resource[key] = ( + vim_resource[vim_res][attr][int(index)][sub_attr]) + else: + if _property_exists(vim_resource[vim_res], attr, + res_properties[key].get("required")): + mc_resource[key] = vim_resource[vim_res][attr] else: if "default" in res_properties[key]: mc_resource[key] = _convert_default_value( res_properties[key]["default"]) - # None required fields missed, just skip. - continue - - action = res_properties[key].get("action", "copy") - # TODO(xiaohhui): Actions should be in constants. - if action == "copy": - mc_resource[key] = vim_resource[vim_res][attr] - return mc_resource def _convert_mc_res_to_vim_res(mc_resource, res_properties): vim_resource = {} for key in res_properties: - vim_res, attr = res_properties[key]["source"].split('.') - - if key not in mc_resource: - if res_properties[key].get("required"): - raise Exception("Required field %s is missed in MultiCloud " - "resource %s", (key, mc_resource)) - else: - # None required fields missed, just skip. - continue - - action = res_properties[key].get("action", "copy") - # TODO(xiaohhui): Actions should be in constants. - if action == "copy": - vim_resource[attr] = mc_resource[key] + vim_res, attr = res_properties[key]["source"].split('.', 1) + # action = res_properties[key].get("action", "copy") + if re.match(OBJ_IN_ARRAY, attr): + attr, index, sub_attr = re.match(OBJ_IN_ARRAY, attr).groups() + if _property_exists(mc_resource, key): + vim_resource[attr] = vim_resource.get(attr, []) + if vim_resource[attr]: + vim_resource[attr][0].update({sub_attr: mc_resource[key]}) + else: + vim_resource[attr].append({sub_attr: mc_resource[key]}) + else: + if _property_exists(mc_resource, key, + res_properties[key].get("required")): + vim_resource[attr] = mc_resource[key] return vim_resource diff --git a/vio/vio/event_listener/server.py b/vio/vio/event_listener/server.py index 83b9e6f..5e6dc00 100755 --- a/vio/vio/event_listener/server.py +++ b/vio/vio/event_listener/server.py @@ -9,8 +9,11 @@ import ConfigParser import json import os import requests -from vio.pub.config.config import MR_ADDR -from vio.pub.config.config import MR_PORT +import sys +sys.path.append("..") +from pub.config.config import MR_ADDR # noqa +from pub.config.config import MR_PORT # noqa + LOG = logging.getLogger(__name__) diff --git a/vio/vio/pub/config/config.py b/vio/vio/pub/config/config.py index 757ba28..b6b8caa 100644 --- a/vio/vio/pub/config/config.py +++ b/vio/vio/pub/config/config.py @@ -29,8 +29,8 @@ AAI_USERNAME = 'AAI' AAI_PASSWORD = 'AAI' # [DMaaP] -MR_ADDR = "127.0.0.1" -MR_PORT = "3904" +MR_ADDR = '127.0.0.1' +MR_PORT = '3904' # [MDC] SERVICE_NAME = "multicloud-vio" diff --git a/vio/vio/settings.py b/vio/vio/settings.py index f1dad0f..68411ea 100644 --- a/vio/vio/settings.py +++ b/vio/vio/settings.py @@ -26,9 +26,9 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) SECRET_KEY = '3o-wney!99y)^h3v)0$j16l9=fdjxcb+a8g+q3tfbahcnu2b0o' # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +# DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ['*'] # Application definition diff --git a/vio/vio/swagger/urls.py b/vio/vio/swagger/urls.py index 3871599..e0195fc 100644 --- a/vio/vio/swagger/urls.py +++ b/vio/vio/swagger/urls.py @@ -65,6 +65,8 @@ from vio.swagger.views.fakeplugin.image.views import FakeImage from vio.swagger.views.fakeplugin.image.views import FakeImageVersion from vio.swagger.views.fakeplugin.image.views import FakeImageDetail from vio.swagger.views.fakeplugin.image.views import FakeImageSchema +from vio.swagger.views.fakeplugin.image.views import FakeImageDownload +from vio.swagger.views.fakeplugin.image.views import FakeImageUpload from vio.swagger.views.fakeplugin.nova.views import FakeNovaServer from vio.swagger.views.fakeplugin.nova.views import FakeNovaHypervisors from vio.swagger.views.fakeplugin.nova.views import FakeNovaAggregate @@ -210,6 +212,11 @@ urlpatterns = [ FakeImageDetail.as_view()), url(r'^api/multicloud-vio/v0/vmware_fake/glance/v2/images', FakeImage.as_view()), + url(r'^api/multicloud-vio/v0/vmware_fake/glance/v2/image/file/' + r'(?P<imageid>[0-9a-z-A-Z\-\_]+)$', + FakeImageDownload.as_view()), + url(r'^api/multicloud-vio/v0/vmware_fake/glance/v2/image/file$', + FakeImageUpload.as_view()), url(r'^api/multicloud-vio/v0/vmware_fake/glance/version', FakeImageVersion.as_view()), url(r'^api/multicloud-vio/v0/vmware_fake/neutron$', diff --git a/vio/vio/swagger/views/fakeplugin/fakeData/fakeResponse.py b/vio/vio/swagger/views/fakeplugin/fakeData/fakeResponse.py index 0368f02..c23a1b2 100644 --- a/vio/vio/swagger/views/fakeplugin/fakeData/fakeResponse.py +++ b/vio/vio/swagger/views/fakeplugin/fakeData/fakeResponse.py @@ -1854,6 +1854,33 @@ def image_detail(): return data +def upload_image(req): + + data = { + "status": "active", + "name": req.get('name'), + "tags": [], + "container_format": req.get('container_format'), + "created_at": "2014-05-05T17:15:10Z", + "disk_format": req.get('disk_format'), + "updated_at": "2014-05-05T17:15:11Z", + "visibility": req.get('visibility'), + "self": "/v2/images/1bea47ed-f6a9-463b-b423-14b9cca9ad27", + "min_disk": 0, + "protected": "false", + "id": Imageid, + "file": "/v2/images/1bea47ed-f6a9-463b-b423-14b9cca9ad27/file", + "checksum": "64d7c1cd2b6f60c92c14662941cb7913", + "owner": "5ef70662f8b34079a6eddb8da9d75fe8", + "size": 13167616, + "min_ram": 0, + "schema": req.get('schema'), + "virtual_size": "null" + } + + return data + + def list_image(): data = { diff --git a/vio/vio/swagger/views/fakeplugin/image/views.py b/vio/vio/swagger/views/fakeplugin/image/views.py index 6d6e242..74d7467 100644 --- a/vio/vio/swagger/views/fakeplugin/image/views.py +++ b/vio/vio/swagger/views/fakeplugin/image/views.py @@ -2,11 +2,13 @@ from rest_framework import status from rest_framework.views import APIView from rest_framework.response import Response +import json from vio.swagger.views.fakeplugin.fakeData.fakeResponse import image_detail from vio.swagger.views.fakeplugin.fakeData.fakeResponse import list_image from vio.swagger.views.fakeplugin.fakeData.fakeResponse import image_schema from vio.swagger.views.fakeplugin.fakeData.fakeResponse import image_version +from vio.swagger.views.fakeplugin.fakeData.fakeResponse import upload_image false = "false" null = "null" @@ -42,3 +44,19 @@ class FakeImageVersion(APIView): data = image_version() return Response(data=data, status=status.HTTP_200_OK) + + +class FakeImageDownload(APIView): + + def get(self, request, imageid): + + data = image_detail() + return Response(data=data, status=status.HTTP_200_OK) + + +class FakeImageUpload(APIView): + + def post(self, request): + req = json.loads(request.body) + data = upload_image(dict(req)) + return Response(data=data, status=status.HTTP_201_CREATED) diff --git a/vio/vio/tests/test_aai_client.py b/vio/vio/tests/test_aai_client.py new file mode 100644 index 0000000..80d5200 --- /dev/null +++ b/vio/vio/tests/test_aai_client.py @@ -0,0 +1,169 @@ +# Copyright (c) 2018 VMware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import mock +import unittest + +from vio.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_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() diff --git a/vio/vio/tests/test_image_view.py b/vio/vio/tests/test_image_view.py new file mode 100644 index 0000000..112ee5a --- /dev/null +++ b/vio/vio/tests/test_image_view.py @@ -0,0 +1,93 @@ +# Copyright (c) 2018 VMware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import mock +import unittest + +from vio.pub.msapi import extsys +from vio.swagger.views.image import views +from vio.pub.vim.vimapi.glance import OperateImage + + +class TestGetDeleteImageView(unittest.TestCase): + + def setUp(self): + self.view = views.GetDeleteImageView() + + @mock.patch.object(OperateImage.OperateImage, "get_vim_image") + @mock.patch.object(extsys, "get_vim_by_id") + def test_get(self, mock_getvim, mock_getimg): + mock_getvim.return_value = { + "tenant": "tenant-id" + } + img = mock.Mock() + img.to_dict.return_value = { + "id": "image-id" + } + mock_getimg.return_value = img + resp = self.view.get(mock.Mock(), "vmware_nova", "tenant1", "image1") + self.assertEqual(200, resp.status_code) + self.assertEqual("image-id", resp.data.get('id')) + + @mock.patch.object(OperateImage.OperateImage, "delete_vim_image") + @mock.patch.object(extsys, "get_vim_by_id") + def test_delete(self, mock_getvim, mock_delimg): + mock_getvim.return_value = { + "tenant": "tenant-id" + } + resp = self.view.delete( + mock.Mock(), "vmware_nova", "tenant1", "image1") + self.assertEqual(204, resp.status_code) + mock_delimg.assert_called_once() + + +class TestCreateListImagesView(unittest.TestCase): + + def setUp(self): + self.view = views.CreateListImagesView() + + @mock.patch.object(OperateImage.OperateImage, "get_vim_images") + @mock.patch.object(extsys, "get_vim_by_id") + def test_get(self, mock_getvim, mock_getimgs): + mock_getvim.return_value = { + "tenant": "tenant-id" + } + img = mock.Mock() + img.to_dict.return_value = { + "id": "image-id" + } + mock_getimgs.return_value = [img] + resp = self.view.get( + mock.Mock(query_params=[]), "vmware_nova", "tenant1") + self.assertEqual(200, resp.status_code) + + @mock.patch.object(OperateImage.OperateImage, "get_vim_image") + @mock.patch.object(OperateImage.OperateImage, "get_vim_images") + @mock.patch.object(extsys, "get_vim_by_id") + def test_post(self, mock_getvim, mock_getimgs, mock_getimg): + mock_getvim.return_value = { + "tenant": "tenant-id" + } + img = mock.Mock() + img.id = "image-id" + img.name = "image-a" + img.to_dict.return_value = { + "id": "image-id", + "name": "image-a" + } + mock_getimgs.return_value = [img] + req = mock.Mock() + req.body = """{ + "name": "image-a" + }""" + resp = self.view.post(req, "vmware_nova", "tenant1") + self.assertEqual(200, resp.status_code) diff --git a/vio/vio/tests/test_proxy_identity_view.py b/vio/vio/tests/test_proxy_identity_view.py new file mode 100644 index 0000000..a8bf9fb --- /dev/null +++ b/vio/vio/tests/test_proxy_identity_view.py @@ -0,0 +1,264 @@ +# Copyright (c) 2018 VMware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import mock +import unittest + +from vio.pub.msapi import extsys +from vio.swagger.views.proxyplugin.httpclient import BaseClient +from vio.swagger.views.proxyplugin.identity import views + + +class TestIdentityServer(unittest.TestCase): + + def setUp(self): + self.view = views.IdentityServer() + + @mock.patch.object(BaseClient, "buildRequest") + @mock.patch.object(BaseClient, "_request") + def test_get(self, mock_req, mock_build): + mock_build.return_value = ("http://onap.org", {}, None) + self.view.get(mock.Mock(), "openstack_regionone") + mock_req.assert_called_once() + + @mock.patch.object(BaseClient, "send") + def test_patch(self, mock_send): + self.view.patch(mock.Mock(), "openstack_regionone", None) + mock_send.assert_called_once() + + @mock.patch.object(BaseClient, "send") + def test_post(self, mock_send): + self.view.post(mock.Mock(), "openstack_regionone", None) + mock_send.assert_called_once() + + @mock.patch.object(BaseClient, "send") + def test_delete(self, mock_send): + self.view.delete(mock.Mock(), "openstack_regionone", None) + mock_send.assert_called_once() + + @mock.patch.object(BaseClient, "send") + def test_head(self, mock_send): + self.view.head(mock.Mock(), "openstack_regionone", None) + mock_send.assert_called_once() + + +class TestTokenView(unittest.TestCase): + + def setUp(self): + self.view = views.TokenView() + + @mock.patch("requests.get") + @mock.patch.object(extsys, "get_vim_by_id") + def test_get_v3(self, mock_getvim, mock_req): + req = mock.Mock() + req.get_full_path.return_value = "identity/v3" + res = mock.Mock() + res.status_code = 200 + res.json.return_value = { + "version": { + "links": [{ + "href": "" + }] + } + } + mock_req.return_value = res + resp = self.view.get(req, "vmware_nova") + self.assertEqual(resp.status_code, 200) + + @mock.patch.object(extsys, "get_vim_by_id") + def test_get_v2(self, mock_getvim): + req = mock.Mock() + req.get_full_path.return_value = "identity/v2.0" + resp = self.view.get(req, "vmware_nova") + self.assertEqual(resp.status_code, 405) + + @mock.patch.object(BaseClient, "buildRequest") + @mock.patch.object(BaseClient, "_request") + def test_delete(self, mock_req, mock_build): + req = mock.Mock() + req.META = { + "HTTP_X_SUBJECT_TOKEN": "aaa" + } + mock_build.return_value = ("http://onap.org", {}, None) + self.view.delete(req, "openstack_regionone") + mock_req.assert_called_once() + + @mock.patch("requests.post") + @mock.patch.object(extsys, "get_vim_by_id") + def test_post_v3(self, mock_getvim, mock_post): + req = mock.Mock() + req.get_full_path.return_value = "identity/v3/auth/tokens" + req.body = "{}" + mock_getvim.return_value = { + "url": "http://onap.org/identity/v3/auth/tokens" + } + res = mock.Mock() + res.status_code = 200 + res.headers = [("X-Subject-Token", "fake-token")] + res.json.return_value = { + "token": { + "value": "token-value", + "project": { + "id": "project-id" + }, + "catalog": [{ + "type": "volume", + "id": "3e4941704e9941a582b157ac7203ec1b", + "name": "cinder", + "endpoints": [{ + "url": "http://onap.org/api/multicloud/v0/xxx", + "interface": "public" + }] + }] + } + } + mock_post.return_value = res + resp = self.view.post(req, "vmware_nova") + self.assertEqual(200, resp.status_code) + + @mock.patch("requests.post") + @mock.patch.object(extsys, "get_vim_by_id") + def test_post_v2(self, mock_getvim, mock_post): + req = mock.Mock() + req.get_full_path.return_value = "identity/v2.0/tokens" + req.body = """{ + "auth": { + "tenantName": "tenant-name", + "passwordCredentials": { + "username": "admin", + "password": "pass" + } + } + }""" + mock_getvim.return_value = { + "url": "http://onap.org/identity/v2.0/tokens" + } + res = mock.Mock() + res.status_code = 200 + res.headers = [("X-Subject-Token", "fake-token")] + res.json.return_value = { + "access": { + "token": { + "value": "token-value", + "tenant": { + "id": "tenant-id" + }, + }, + "serviceCatalog": [{ + "type": "volume", + "id": "3e4941704e9941a582b157ac7203ec1b", + "name": "cinder", + "endpoints": [{ + "adminURL": "http://onap.org/api/multicloud/v0/xxx", + "internalURL": "http://onap.org/api/multicloud/v0/xxx", + "publicURL": "http://onap.org/api/multicloud/v0/xxx" + }] + }] + } + } + mock_post.return_value = res + resp = self.view.post(req, "vmware_nova") + self.assertEqual(200, resp.status_code) + + +class TestTokenV2View(unittest.TestCase): + + def setUp(self): + self.view = views.TokenV2View() + + @mock.patch("requests.get") + @mock.patch.object(extsys, "get_vim_by_id") + def test_get_v2(self, mock_getvim, mock_get): + req = mock.Mock() + req.get_full_path.return_value = "identity/v2.0" + mock_getvim.return_value = { + "url": "http://onap.org/identity/v3" + } + res = mock.Mock() + res.status_code = 200 + res.json.return_value = { + "version": { + "links": [{ + "href": "" + }] + } + } + mock_get.return_value = res + resp = self.view.get(req, "vmware_nova") + self.assertEqual(resp.status_code, 200) + + @mock.patch("requests.post") + @mock.patch.object(extsys, "get_vim_by_id") + def test_post(self, mock_getvim, mock_post): + req = mock.Mock() + req.get_full_path.return_value = "identity/v2.0/tokens" + req.body = """{ + "auth": { + "tenantName": "tenant-name", + "passwordCredentials": { + "username": "admin", + "password": "pass" + } + } + }""" + mock_getvim.return_value = { + "url": "http://onap.org/identity/v2.0/tokens" + } + res = mock.Mock() + res.status_code = 200 + res.headers = [("X-Subject-Token", "fake-token")] + res.json.return_value = { + "access": { + "token": { + "value": "token-value", + "tenant": { + "id": "tenant-id" + }, + }, + "serviceCatalog": [{ + "type": "volume", + "id": "3e4941704e9941a582b157ac7203ec1b", + "name": "cinder", + "endpoints": [{ + "adminURL": "http://onap.org/api/multicloud/v0/xxx", + "internalURL": "http://onap.org/api/multicloud/v0/xxx", + "publicURL": "http://onap.org/api/multicloud/v0/xxx" + }] + }] + } + } + mock_post.return_value = res + resp = self.view.post(req, "vmware_nova") + self.assertEqual(200, resp.status_code) + + +class TestIdentityVersionLink(unittest.TestCase): + + def setUp(self): + self.view = views.IdentityVersionLink() + + @mock.patch.object(BaseClient, "buildRequest") + @mock.patch.object(BaseClient, "_request") + def test_get(self, mock_req, mock_build): + mock_build.return_value = ("http://onap.org", {}, None) + res = mock.Mock() + res.status_code = 200 + res.data = { + "version": { + "links": [{ + "href": "" + }] + } + } + mock_req.return_value = res + resp = self.view.get(mock.Mock(), "vmware_nova") + self.assertEqual(200, resp.status_code) diff --git a/vio/vio/tests/test_restcall.py b/vio/vio/tests/test_restcall.py new file mode 100644 index 0000000..051dddf --- /dev/null +++ b/vio/vio/tests/test_restcall.py @@ -0,0 +1,66 @@ +# Copyright (c) 2017-2018 VMware, Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import mock +import unittest + +from vio.pub.utils import restcall + + +class TestRestCall(unittest.TestCase): + + def test_combine_url(self): + url = ["http://a.com/test/", "http://a.com/test/", + "http://a.com/test", "http://a.com/test"] + res = ["/resource", "resource", "/resource", "resource"] + expected = "http://a.com/test/resource" + for i in range(len(url)): + self.assertEqual(expected, restcall.combine_url(url[i], res[i])) + + @mock.patch.object(restcall, "call_req") + def test_get_res_from_aai(self, mock_call): + res = "cloud-regions" + content = "" + expect_url = "https://aai.api.simpledemo.openecomp.org:8443/aai/v13" + expect_user = "AAI" + expect_pass = "AAI" + expect_headers = { + 'X-FromAppId': 'MultiCloud', + 'X-TransactionId': '9001', + 'content-type': 'application/json', + 'accept': 'application/json' + } + restcall.get_res_from_aai(res, content=content) + mock_call.assert_called_once_with( + expect_url, expect_user, expect_pass, restcall.rest_no_auth, + res, "GET", content, expect_headers) + + @mock.patch.object(restcall, "call_req") + def test_req_by_msb(self, mock_call): + res = "multicloud" + method = "GET" + content = "no content" + restcall.req_by_msb(res, method, content=content) + expect_url = "http://127.0.0.1:10080/" + mock_call.assert_called_once_with( + expect_url, "", "", restcall.rest_no_auth, res, method, + content) + + @mock.patch("httplib2.Http.request") + def test_call_req_success(self, mock_req): + mock_resp = { + "status": "200" + } + resp_content = "hello" + mock_req.return_value = mock_resp, resp_content + expect_ret = [0, resp_content, "200", mock_resp] + ret = restcall.call_req("http://onap.org/", "user", "pass", + restcall.rest_no_auth, "vim", "GET") + self.assertEqual(expect_ret, ret) |