diff options
-rwxr-xr-x | vio/docker/instance-config.sh | 2 | ||||
-rwxr-xr-x | vio/stop.sh | 2 | ||||
-rw-r--r-- | vio/vio/pub/msapi/extsys.py | 6 | ||||
-rw-r--r-- | vio/vio/pub/utils/restcall.py | 137 | ||||
-rw-r--r-- | vio/vio/pub/vim/drivers/vimsdk/image_v2.py | 1 | ||||
-rw-r--r-- | vio/vio/swagger/urls.py | 5 | ||||
-rw-r--r-- | vio/vio/swagger/views/proxyplugin/httpclient.py | 7 | ||||
-rw-r--r-- | vio/vio/swagger/views/proxyplugin/identity/views.py | 21 | ||||
-rw-r--r-- | vio/vio/swagger/views/registry/views.py | 69 | ||||
-rw-r--r-- | vio/vio/tests/tests_registry_view.py | 123 |
10 files changed, 299 insertions, 74 deletions
diff --git a/vio/docker/instance-config.sh b/vio/docker/instance-config.sh index 221cac9..cb05a9a 100755 --- a/vio/docker/instance-config.sh +++ b/vio/docker/instance-config.sh @@ -2,7 +2,7 @@ # Configure MSB IP address MSB_IP=`echo $MSB_ADDR | cut -d: -f 1` -MSB_PORT=`echo $MSB_ADDR | cut -d: -f 2` +MSB_PORT=`echo $MSB_PORT | cut -d: -f 2` sed -i "s|MSB_SERVICE_IP.*|MSB_SERVICE_IP = '$MSB_IP'|" vio/vio/pub/config/config.py sed -i "s|MSB_SERVICE_PORT.*|MSB_SERVICE_PORT = '$MSB_PORT'|" vio/vio/pub/config/config.py sed -i "s|DB_NAME.*|DB_NAME = 'inventory'|" vio/vio/pub/config/config.py diff --git a/vio/stop.sh b/vio/stop.sh index 0196606..1d35d39 100755 --- a/vio/stop.sh +++ b/vio/stop.sh @@ -11,4 +11,4 @@ # 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 127.0.0.1:9004' | awk '{print $2}' | xargs kill -9 +ps auxww | grep 'manage.py runserver 0.0.0.0:9004' | awk '{print $2}' | xargs kill -9 diff --git a/vio/vio/pub/msapi/extsys.py b/vio/vio/pub/msapi/extsys.py index b3ed044..c3d87d1 100644 --- a/vio/vio/pub/msapi/extsys.py +++ b/vio/vio/pub/msapi/extsys.py @@ -33,7 +33,7 @@ def get_vim_by_id(vim_id): ret['vimId'] = vim_id ret['name'] = vim_id ret['userName'] = ret['esr-system-info-list'][ - 'esr-system-info'][0]['username'] + 'esr-system-info'][0]['user-name'] ret['password'] = ret['esr-system-info-list'][ 'esr-system-info'][0]['password'] ret['tenant'] = ret['esr-system-info-list'][ @@ -43,7 +43,7 @@ def get_vim_by_id(vim_id): ret['domain'] = ret['esr-system-info-list'][ 'esr-system-info'][0]['cloud-domain'] ret['cacert'] = ret['esr-system-info-list'][ - 'esr-system-info'][0]['ssl-cacert'] + 'esr-system-info'][0].get('ssl-cacert', "") ret['insecure'] = ret['esr-system-info-list'][ - 'esr-system-info'][0]['ssl-insecure'] + 'esr-system-info'][0].get('ssl-insecure', False) return ret diff --git a/vio/vio/pub/utils/restcall.py b/vio/vio/pub/utils/restcall.py index 99ed9d9..15dd90b 100644 --- a/vio/vio/pub/utils/restcall.py +++ b/vio/vio/pub/utils/restcall.py @@ -161,8 +161,22 @@ class AAIClient(object): return json.loads(resp[1]) 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" % (self.cloud_owner, self.cloud_region)) + "/%s/%s?resource-version=%s" % + (self.cloud_owner, self.cloud_region, + resp['resource-version'])) resp = call_req(self.base_url, self.username, self.password, rest_no_auth, resource, "DELETE", headers=self.default_headers) @@ -171,7 +185,6 @@ class AAIClient(object): status_code=400, content="Failed to delete cloud %s_%s: %s." % ( self.cloud_owner, self.cloud_region, resp[1])) - return json.loads(resp[1]) def update_vim(self, content): # update identity url @@ -182,6 +195,8 @@ class AAIClient(object): self.add_images(content) # update images self.add_flavors(content) + # update networks + self.add_networks(content) # update pservers self.add_pservers(content) @@ -234,11 +249,15 @@ class AAIClient(object): 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': image['name'].split("-")[0], - 'image-os-version': image['name'].split("-")[1], + 'image-os-distro': os_distro, + 'image-os-version': os_version, # 'application': image[''], # 'application-vendor': image[''], # 'application-version': image[''], @@ -250,6 +269,22 @@ class AAIClient(object): 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, + } + 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" % ( @@ -305,3 +340,97 @@ class AAIClient(object): 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 VimDriverVioException( + status_code=400, + content="Failed to delete tenant %s: %s." % ( + tenant['tenant-id'], resp[1])) + + def _del_flavors(self, rsp): + tenants = rsp.get("flavors", []) + if not tenants: + return + for tenant in tenants["flavor"]: + resource = ("/cloud-infrastructure/cloud-regions/cloud-region/" + "%s/%s/flavors/flavor/%s?resource-version=%s" % ( + self.cloud_owner, self.cloud_region, + tenant['flavor-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 VimDriverVioException( + status_code=400, + content="Failed to delete flavor %s: %s." % ( + tenant['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 VimDriverVioException( + 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 VimDriverVioException( + 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 VimDriverVioException( + status_code=400, + content="Failed to delete availability zone %s: %s." % ( + az['availability-zone-name'], resp[1])) diff --git a/vio/vio/pub/vim/drivers/vimsdk/image_v2.py b/vio/vio/pub/vim/drivers/vimsdk/image_v2.py index 6d040c6..3ea0291 100644 --- a/vio/vio/pub/vim/drivers/vimsdk/image_v2.py +++ b/vio/vio/pub/vim/drivers/vimsdk/image_v2.py @@ -24,7 +24,6 @@ class GlanceClient(base.DriverBase): def __init__(self, params): super(GlanceClient, self).__init__(params) - LOG.info("%s", str(params)) self.conn = sdk.create_connection(params) self.session = self.conn.session self._proxy = self.conn.image diff --git a/vio/vio/swagger/urls.py b/vio/vio/swagger/urls.py index 21c21b8..43b5a7f 100644 --- a/vio/vio/swagger/urls.py +++ b/vio/vio/swagger/urls.py @@ -40,6 +40,7 @@ from vio.swagger.views.proxyplugin.heat.views import HeatServer # Registry from vio.swagger.views.registry.views import Registry +from vio.swagger.views.registry.views import UnRegistry # Extensions from vio.swagger.views.extensions.views import Extensions @@ -189,8 +190,8 @@ urlpatterns = [ # Registry url(r'^api/multicloud-vio/v0/(?P<vimid>[0-9a-z-A-Z\-\_]+)/registry$', Registry.as_view()), - # url(r'^api/multicloud-vio/v0/(?P<vimid>[0-9a-z-A-Z\-\_]+)$', - # Registry.as_view()), + url(r'^api/multicloud-vio/v0/(?P<vimid>[0-9a-z-A-Z\-\_]+)$', + UnRegistry.as_view()), # proxy url(r'^api/multicloud-vio/v0/(?P<vimid>[0-9a-z-A-Z\-\_]+)/identity/v3', diff --git a/vio/vio/swagger/views/proxyplugin/httpclient.py b/vio/vio/swagger/views/proxyplugin/httpclient.py index f1cfbb1..bf1bc17 100644 --- a/vio/vio/swagger/views/proxyplugin/httpclient.py +++ b/vio/vio/swagger/views/proxyplugin/httpclient.py @@ -69,14 +69,15 @@ class BaseClient(APIView): def buildRequest(self, request, vimid, tenantid="", tail=None): + headers = {} preUrl = catalog.getEndpointBy( vimid, serverType=self.serverType, interface="public") token = request.META.get('HTTP_X_AUTH_TOKEN', "") tail = "/" + tail if tail else "" tenantid = "/" + tenantid if tenantid else "" endPointURL = preUrl + tenantid + tail - - headers = {"X-Auth-Token": token} + headers["X-Auth-Token"] = token + headers["X-Subject-Token"] = token headers['Content-Type'] = request.META.get( "CONTENT_TYPE", "application/json") try: @@ -84,7 +85,7 @@ class BaseClient(APIView): except Exception: json_req = "" - return (endPointURL, headers, json_req) + return endPointURL, headers, json_req def _request(self, url, method, redirect=20, connect_retries=0, connect_retry_delay=0.5, **kwargs): diff --git a/vio/vio/swagger/views/proxyplugin/identity/views.py b/vio/vio/swagger/views/proxyplugin/identity/views.py index cee11e7..56ac864 100644 --- a/vio/vio/swagger/views/proxyplugin/identity/views.py +++ b/vio/vio/swagger/views/proxyplugin/identity/views.py @@ -46,7 +46,26 @@ class IdentityServer(BaseClient): if query != "": query = query[:-1] url += "/?" + query - return self._request(url, method="GET", headers=headers) + + try: + res = self._request(url, method="GET", headers=headers) + if res.status_code != status.HTTP_200_OK: + return Response(data={"error": res.content}, + status=res.status_code) + res = res.data + # replace keystone auth url with multicloud + # identity url + if other is None: + res['version']['links'][0]['href'] = \ + "http://" + MSB_ADDRESS + "/multicloud-vio/v0/" \ + + vimid + "/identity" + + except Exception as e: + logging.exception("error %s" % e) + return Response(data={"error": str(e)}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + return Response(data=res, status=status.HTTP_200_OK) def patch(self, request, vimid, other): diff --git a/vio/vio/swagger/views/registry/views.py b/vio/vio/swagger/views/registry/views.py index cde3b5d..7969ad1 100644 --- a/vio/vio/swagger/views/registry/views.py +++ b/vio/vio/swagger/views/registry/views.py @@ -24,6 +24,7 @@ from vio.pub.vim.vimapi.keystone import OperateTenant from vio.pub.vim.vimapi.glance import OperateImage from vio.pub.vim.vimapi.nova import OperateFlavors from vio.pub.vim.vimapi.nova import OperateHypervisor +from vio.pub.vim.vimapi.network import OperateNetwork logger = logging.getLogger(__name__) @@ -76,6 +77,20 @@ class Registry(APIView): rsp['flavors'].append(flavor[0].to_dict()) 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: + 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 = {'networks': resp['networks']} + return rsp + def _get_hypervisors(self, auth_info): hypervisor_op = OperateHypervisor.OperateHypervisor() try: @@ -112,7 +127,7 @@ class Registry(APIView): rsp = {} # get tenants try: - print('Updating tenants') + logger.debug('Getting tenants') tenants = self._get_tenants(data) rsp.update(tenants) data['tenant'] = self._find_tenant_id( @@ -120,19 +135,23 @@ class Registry(APIView): data['project_id'] = data['tenant'] # set default tenant # get images - print('Updating images') + logger.debug('Getting images') images = self._get_images(data) rsp.update(images) # get flavors - print('Updating 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 - print('Updating hypervisors') + logger.debug('Getting hypervisors') hypervisors = self._get_hypervisors(data) rsp.update(hypervisors) # update A&AI - print('Put data into 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) @@ -142,38 +161,16 @@ class Registry(APIView): status=status.HTTP_500_INTERNAL_SERVER_ERROR) return Response(data="", status=status.HTTP_200_OK) - def delete(self, request, vimid): - try: - vim_info = extsys.get_vim_by_id(vimid) - except VimDriverVioException as e: - return Response(data={'error': str(e)}, status=e.status_code) - data = {} - data['vimId'] = vim_info['vimId'] - data['username'] = vim_info['userName'] - data['password'] = vim_info['password'] - data['url'] = vim_info['url'] - data['project_name'] = vim_info['tenant'] +class UnRegistry(APIView): - query = dict(request.query_params) - tenant_instance = OperateTenant.OperateTenant() + def delete(self, request, vimid): try: - projects = tenant_instance.get_projects(data, **query) + 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: - 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 = {} - rsp['vimId'] = vim_info['vimId'] - rsp['vimName'] = vim_info['name'] - rsp['tenants'] = [] - - for project in projects: - tenant = {} - tenant['id'] = project.id - tenant['name'] = project.name - rsp['tenants'].append(tenant) - return Response(data=rsp, status=status.HTTP_200_OK) + return Response(data=e.message, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + return Response(data="", status=status.HTTP_204_NO_CONTENT) diff --git a/vio/vio/tests/tests_registry_view.py b/vio/vio/tests/tests_registry_view.py index 9013332..31c2d78 100644 --- a/vio/vio/tests/tests_registry_view.py +++ b/vio/vio/tests/tests_registry_view.py @@ -14,11 +14,15 @@ import unittest import mock from rest_framework import status from vio.swagger.views.registry.views import Registry +from vio.swagger.views.registry.views import UnRegistry from vio.pub.msapi import extsys +from vio.pub.utils.restcall import AAIClient from vio.pub.vim.vimapi.keystone.OperateTenant import OperateTenant from vio.pub.vim.vimapi.glance.OperateImage import OperateImage +from vio.pub.vim.vimapi.nova.OperateFlavors import OperateFlavors +from vio.pub.vim.vimapi.nova.OperateHypervisor import OperateHypervisor VIM_INFO = {'vimId': 1, 'name': 'name1', 'userName': 'user1', 'password': '1234', 'url': 'abc', 'tenant': 't1'} @@ -34,28 +38,6 @@ class RegistryViewTest(unittest.TestCase): @mock.patch.object(OperateTenant, 'get_projects') @mock.patch.object(extsys, 'get_vim_by_id') - def test_reg_delete_view(self, mock_vim_info, mock_projects): - mock_vim_info.return_value = VIM_INFO - - class Project: - def __init__(self, id, name): - self.id = id - self.name = name - p1 = Project(1, "p1") - p2 = Project(2, "p2") - projects = [p1, p2] - mock_projects.return_value = projects - - class Request: - def __init__(self, query_params): - self.query_params = query_params - req = Request({'k': 'v'}) - self.assertEqual( - status.HTTP_200_OK, - self.reg.delete(req, "vimid").status_code) - - @mock.patch.object(OperateTenant, 'get_projects') - @mock.patch.object(extsys, 'get_vim_by_id') def test_reg_get_tenants_view(self, mock_vim_info, mock_projects): mock_vim_info.return_value = VIM_INFO @@ -113,3 +95,100 @@ class RegistryViewTest(unittest.TestCase): self.assertEqual( {'images': [{'id': 1, 'name': 'i1'}, {'id': 2, 'name': 'i2'}]}, self.reg._get_images(a)) + + @mock.patch.object(OperateFlavors, 'list_flavors') + @mock.patch.object(extsys, 'get_vim_by_id') + def test_reg_get_flavors_view_fail(self, mock_vim_info, mock_flavors): + mock_vim_info.return_value = VIM_INFO + + class Flavor: + def __init__(self, id, name): + self.id = id + self.name = name + + def to_dict(self): + return {"name": self.name, "id": self.id} + f1 = Flavor(1, "f1") + f2 = Flavor(2, "f2") + flavors = [[f1], [f2]] + mock_flavors.return_value = flavors + auth = {"name": "user", "tenant": "t1", "auth_url": "url"} + + self.assertEqual( + {'flavors': [{'id': 1, 'name': 'f1'}, {'id': 2, 'name': 'f2'}]}, + self.reg._get_flavors(auth)) + + @mock.patch.object(OperateFlavors, 'list_flavors') + @mock.patch.object(extsys, 'get_vim_by_id') + def test_reg_get_flavors_view_fail2(self, mock_vim_info, mock_flavors): + mock_vim_info.return_value = VIM_INFO + mock_flavors.side_effect = TypeError("wrong type") + self.assertEqual( + status.HTTP_500_INTERNAL_SERVER_ERROR, + self.reg._get_flavors("viminfo").status_code) + + @mock.patch.object(OperateHypervisor, 'list_hypervisors') + @mock.patch.object(extsys, 'get_vim_by_id') + def test_reg_get_hypervisors_view(self, mock_vim_info, mock_hypervisor): + mock_vim_info.return_value = VIM_INFO + + class Hypervisor: + def __init__(self, id, name): + self.id = id + self.name = name + + def to_dict(self): + return {"name": self.name, "id": self.id} + h1 = Hypervisor(1, "h1") + h2 = Hypervisor(2, "h2") + hypervisors = [h1, h2] + mock_hypervisor.return_value = hypervisors + + class Auth: + def __init__(self, id): + self.id = id + + def get(self, username): + self.username = username + a = Auth(1) + self.assertEqual( + {'hypervisors': [{'id': 1, 'name': 'h1'}, + {'id': 2, 'name': 'h2'}]}, + self.reg._get_hypervisors(a)) + + @mock.patch.object(OperateHypervisor, 'list_hypervisors') + @mock.patch.object(extsys, 'get_vim_by_id') + def test_reg_get_hypervisors_view_fail(self, + mock_vim_info, mock_hypervisor): + mock_vim_info.return_value = VIM_INFO + mock_hypervisor.side_effect = TypeError("wrong type") + self.assertEqual( + status.HTTP_500_INTERNAL_SERVER_ERROR, + self.reg._get_hypervisors("viminfo").status_code) + + def test_reg_find_tenant(self): + tenants = {"tenants": [ + {"name": "t1", "id": 1}, {"name": "t2", "id": 2}]} + self.assertEqual(self.reg._find_tenant_id("t2", tenants), 2) + + +class UnRegistryViewTest(unittest.TestCase): + + def setUp(self): + self.reg = UnRegistry() + + def tearDown(self): + pass + + @mock.patch.object(AAIClient, 'delete_vim') + @mock.patch.object(extsys, 'get_vim_by_id') + def test_reg_delete_view(self, mock_vim_info, mock_del_vim): + mock_vim_info.return_value = VIM_INFO + + class Request: + def __init__(self, query_params): + self.query_params = query_params + req = Request({'k': 'v'}) + self.assertEqual( + status.HTTP_204_NO_CONTENT, + self.reg.delete(req, "vimid").status_code) |