diff options
Diffstat (limited to 'vio')
-rw-r--r-- | vio/assembly.xml | 8 | ||||
-rw-r--r-- | vio/docker/Dockerfile | 27 | ||||
-rwxr-xr-x | vio/docker/build_image.sh | 34 | ||||
-rwxr-xr-x | vio/docker/docker-entrypoint.sh | 35 | ||||
-rwxr-xr-x | vio/docker/instance-config.sh | 29 | ||||
-rwxr-xr-x | vio/docker/instance-init.sh | 9 | ||||
-rwxr-xr-x | vio/docker/instance-run.sh | 9 | ||||
-rw-r--r-- | vio/pom.xml | 10 | ||||
-rwxr-xr-x | vio/run.sh | 29 | ||||
-rw-r--r-- | vio/version.properties | 13 | ||||
-rw-r--r-- | vio/vio/pub/config/config.py | 20 | ||||
-rw-r--r-- | vio/vio/pub/msapi/extsys.py | 37 | ||||
-rw-r--r-- | vio/vio/pub/utils/restcall.py | 244 | ||||
-rw-r--r-- | vio/vio/pub/vim/drivers/vimsdk/compute.py | 4 | ||||
-rw-r--r-- | vio/vio/pub/vim/vimapi/nova/OperateHypervisor.py | 8 | ||||
-rw-r--r-- | vio/vio/swagger/urls.py | 10 | ||||
-rw-r--r-- | vio/vio/swagger/views/proxyplugin/identity/views.py | 18 | ||||
-rw-r--r-- | vio/vio/swagger/views/registry/__init__.py | 0 | ||||
-rw-r--r-- | vio/vio/swagger/views/registry/views.py | 179 |
19 files changed, 657 insertions, 66 deletions
diff --git a/vio/assembly.xml b/vio/assembly.xml index c59ad59..5df8abe 100644 --- a/vio/assembly.xml +++ b/vio/assembly.xml @@ -38,6 +38,14 @@ <include>*.txt</include> </includes> </fileSet> + <fileSet> + <directory>docker</directory> + <outputDirectory>/docker</outputDirectory> + <includes> + <include>*.sh</include> + <include>Dockerfile</include> + </includes> + </fileSet> <fileSet> <directory>.</directory> <outputDirectory>/</outputDirectory> diff --git a/vio/docker/Dockerfile b/vio/docker/Dockerfile new file mode 100644 index 0000000..7d2e84f --- /dev/null +++ b/vio/docker/Dockerfile @@ -0,0 +1,27 @@ +FROM python:2 + +ENV MSB_ADDR "127.0.0.1" +ENV MSB_PORT "80" +ENV AAI_ADDR "aai.api.simpledemo.openecomp.org" +ENV AAI_PORT "8443" +ENV AAI_SCHEMA_VERSION "v11" +ENV AAI_USERNAME "AAI" +ENV AAI_PASSWORD "AAI" + +EXPOSE 9004 + +RUN apt-get update && \ + apt-get install -y unzip && \ + apt-get install -y curl && \ + apt-get install -y wget + + +RUN cd /opt/ && \ + wget -q -O multicloud-vio.zip 'https://nexus.onap.org/service/local/artifact/maven/redirect?r=snapshots&g=org.onap.multicloud.openstack.vmware&a=multicloud-vio&v=LATEST&e=zip' && \ + unzip multicloud-vio.zip && \ + rm -rf multicloud-vio.zip && \ + pip install -r vio/requirements.txt + + +WORKDIR /opt +ENTRYPOINT vio/docker/docker-entrypoint.sh diff --git a/vio/docker/build_image.sh b/vio/docker/build_image.sh new file mode 100755 index 0000000..b1e691b --- /dev/null +++ b/vio/docker/build_image.sh @@ -0,0 +1,34 @@ +#!/bin/bash +DIRNAME=`dirname $0` +DOCKER_BUILD_DIR=`cd $DIRNAME/; pwd` +echo "DOCKER_BUILD_DIR=${DOCKER_BUILD_DIR}" +cd ${DOCKER_BUILD_DIR} + +BUILD_ARGS="--no-cache" +ORG="onap" +VERSION="1.0.0-SNAPSHOT" +PROJECT="multicloud" +IMAGE="vio" +DOCKER_REPOSITORY="nexus3.onap.org:10003" +IMAGE_NAME="${DOCKER_REPOSITORY}/${ORG}/${PROJECT}/${IMAGE}" + +if [ $HTTP_PROXY ]; then + BUILD_ARGS+=" --build-arg HTTP_PROXY=${HTTP_PROXY}" +fi +if [ $HTTPS_PROXY ]; then + BUILD_ARGS+=" --build-arg HTTPS_PROXY=${HTTPS_PROXY}" +fi + +function build_image { + echo "Start build docker image: ${IMAGE_NAME}" + docker build ${BUILD_ARGS} -t ${IMAGE_NAME}:${VERSION} -t ${IMAGE_NAME}:latest . +} + +function push_image { + echo "Start push docker image: ${IMAGE_NAME}" + docker push ${IMAGE_NAME}:${VERSION} + docker push ${IMAGE_NAME}:latest +} + +build_image +push_image diff --git a/vio/docker/docker-entrypoint.sh b/vio/docker/docker-entrypoint.sh new file mode 100755 index 0000000..632c558 --- /dev/null +++ b/vio/docker/docker-entrypoint.sh @@ -0,0 +1,35 @@ +#!/bin/bash + + +if [ -z "$SERVICE_IP" ]; then + export SERVICE_IP=`hostname -i` +fi +echo +echo Environment Variables: +echo "SERVICE_IP=$SERVICE_IP" + +if [ -z "$MSB_ADDR" ]; then + echo "Missing required variable MSB_ADDR: Microservices Service Bus address <ip>:<port>" + exit 1 +fi +echo "MSB_ADDR=$MSB_ADDR" +echo + + +echo + +# Configure service based on docker environment variables +vio/docker/instance-config.sh + + +# Perform one-time config +if [ ! -e init.log ]; then + + # microservice-specific one-time initialization + vio/docker/instance-init.sh + + date > init.log +fi + +# Start the microservice +vio/docker/instance-run.sh diff --git a/vio/docker/instance-config.sh b/vio/docker/instance-config.sh new file mode 100755 index 0000000..221cac9 --- /dev/null +++ b/vio/docker/instance-config.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +# Configure MSB IP address +MSB_IP=`echo $MSB_ADDR | cut -d: -f 1` +MSB_PORT=`echo $MSB_ADDR | 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 +sed -i "s|DB_USER.*|DB_USER = 'inventory'|" vio/vio/pub/config/config.py +sed -i "s|DB_PASSWD.*|DB_PASSWD = 'inventory'|" vio/vio/pub/config/config.py +sed -i "s|\"ip\": \".*\"|\"ip\": \"$SERVICE_IP\"|" vio/vio/pub/config/config.py + +# Configure MYSQL +if [ -z "$MYSQL_ADDR" ]; then + export MYSQL_IP=`hostname -i` + export MYSQL_PORT=3306 + export MYSQL_ADDR=$MYSQL_IP:$MYSQL_PORT +else + MYSQL_IP=`echo $MYSQL_ADDR | cut -d: -f 1` + MYSQL_PORT=`echo $MYSQL_ADDR | cut -d: -f 2` +fi +echo "MYSQL_ADDR=$MYSQL_ADDR" +sed -i "s|DB_IP.*|DB_IP = '$MYSQL_IP'|" vio/vio/pub/config/config.py +sed -i "s|DB_PORT.*|DB_PORT = $MYSQL_PORT|" vio/vio/pub/config/config.py + +cat vio/vio/pub/config/config.py + +sed -i "s/sip=.*/sip=$SERVICE_IP/g" vio/run.sh +sed -i "s/sip=.*/sip=$SERVICE_IP/g" vio/stop.sh
\ No newline at end of file diff --git a/vio/docker/instance-init.sh b/vio/docker/instance-init.sh new file mode 100755 index 0000000..f7e0e0e --- /dev/null +++ b/vio/docker/instance-init.sh @@ -0,0 +1,9 @@ +#!/bin/bash -v + +# Initialize DB schema +#./bin/initDB.sh root rootpass 3306 127.0.0.1 + +# Install python requirements +cd /opt/vio +./initialize.sh +cd /opt diff --git a/vio/docker/instance-run.sh b/vio/docker/instance-run.sh new file mode 100755 index 0000000..d01cebb --- /dev/null +++ b/vio/docker/instance-run.sh @@ -0,0 +1,9 @@ +#!/bin/bash -v + +cd ./vio +./run.sh + +while [ ! -f logs/runtime_vio.log ]; do + sleep 1 +done +tail -F logs/runtime_vio.log diff --git a/vio/pom.xml b/vio/pom.xml index a3bda08..0c60fac 100644 --- a/vio/pom.xml +++ b/vio/pom.xml @@ -12,7 +12,9 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project + xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>org.onap.oparent</groupId> <artifactId>oparent</artifactId> @@ -22,10 +24,10 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.onap.multicloud.openstack.vmware</groupId> <artifactId>multicloud-vio</artifactId> - <version>1.1.0-SNAPSHOT</version> + <version>1.0.0-SNAPSHOT</version> <packaging>pom</packaging> - <name>multicloud/openstack/vmware</name> - <description>multiclouddriver for vio</description> + <name>multicloud-opentack-vmware</name> + <description>multicloud vio</description> <build> <plugins> <plugin> @@ -1,14 +1,17 @@ #!/bin/bash -# Copyright (c) 2017 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. - -nohup python manage.py runserver 127.0.0.1:9004 > /dev/null & + +sed -i "s/MSB_SERVICE_IP =.*/MSB_SERVICE_IP = \"${MSB_ADDR}\"/g" vio/pub/config/config.py +sed -i "s/MSB_SERVICE_PORT =.*/MSB_SERVICE_PORT = \"${MSB_PORT}\"/g" vio/pub/config/config.py +sed -i "s/AAI_ADDR =.*/AAI_ADDR = \"${AAI_ADDR}\"/g" vio/pub/config/config.py +sed -i "s/AAI_PORT =.*/AAI_PORT = \"${AAI_PORT}\"/g" vio/pub/config/config.py +sed -i "s/AAI_SCHEMA_VERSION =.*/AAI_SCHEMA_VERSION = \"${AAI_SCHEMA_VERSION}\"/g" vio/pub/config/config.py +sed -i "s/AAI_USERNAME =.*/AAI_USERNAME = \"${AAI_USERNAME}\"/g" vio/pub/config/config.py +sed -i "s/AAI_PASSWORD =.*/AAI_PASSWORD = \"${AAI_PASSWORD}\"/g" vio/pub/config/config.py + +nohup python manage.py runserver 0.0.0.0:9004 2>&1 & + +while [ ! -f logs/runtime_vio.log ]; do + sleep 1 +done + +tail -F logs/runtime_vio.log diff --git a/vio/version.properties b/vio/version.properties new file mode 100644 index 0000000..7f86aa1 --- /dev/null +++ b/vio/version.properties @@ -0,0 +1,13 @@ +# Versioning variables +# Note that these variables cannot be structured (e.g. : version.release or version.snapshot etc... ) +# because they are used in Jenkins, whose plug-in doesn't support + +major=1 +minor=1 +patch=0 + +base_version=${major}.${minor}.${patch} + +# Release must be completed with git revision # in Jenkins +release_version=${base_version} +snapshot_version=${base_version}-SNAPSHOT diff --git a/vio/vio/pub/config/config.py b/vio/vio/pub/config/config.py index a31d63c..1231dd0 100644 --- a/vio/vio/pub/config/config.py +++ b/vio/vio/pub/config/config.py @@ -20,20 +20,28 @@ MSB_SERVICE_PORT = '10080' ROOT_PATH = os.path.dirname(os.path.dirname( os.path.dirname(os.path.abspath(__file__)))) +# [A&AI] +AAI_ADDR = "aai.api.simpledemo.openecomp.org" +AAI_PORT = "8443" +AAI_SERVICE_URL = 'https://%s:%s/aai' % (AAI_ADDR, AAI_PORT) +AAI_SCHEMA_VERSION = "v11" +AAI_USERNAME = 'AAI' +AAI_PASSWORD = 'AAI' + # [REDIS] REDIS_HOST = '127.0.0.1' REDIS_PORT = '6379' REDIS_PASSWD = '' # [mysql] -DB_IP = '127.0.0.1' -DB_PORT = 3306 -DB_NAME = 'multivimvio' -DB_USER = 'root' -DB_PASSWD = 'password' +# DB_IP = '127.0.0.1' +# DB_PORT = 3306 +# DB_NAME = 'multivimvio' +# DB_USER = 'root' +# DB_PASSWD = 'password' # [register] -REG_TO_MSB_WHEN_START = True +REG_TO_MSB_WHEN_START = False REG_TO_MSB_REG_URL = "/api/microservices/v1/services" REG_TO_MSB_REG_PARAM = { "serviceName": "multicloud-vio", diff --git a/vio/vio/pub/msapi/extsys.py b/vio/vio/pub/msapi/extsys.py index 19ea80d..5584a3f 100644 --- a/vio/vio/pub/msapi/extsys.py +++ b/vio/vio/pub/msapi/extsys.py @@ -10,28 +10,33 @@ # 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 logging -from rest_framework import status -from vio.pub.exceptions import VimDriverVioException -from vio.pub.utils.restcall import req_by_msb +from vio.pub.utils.restcall import AAIClient logger = logging.getLogger(__name__) -def get_vims(): - ret = req_by_msb("/openoapi/extsys/v1/vims", "GET") - if ret[0] != 0: - logger.error("Status code is %s, detail is %s.", ret[2], ret[1]) - raise VimDriverVioException("Failed to query VIMs from extsys.") - return json.JSONDecoder().decode(ret[1]) +def split_vim_to_owner_region(vim_id): + split_vim = vim_id.split('_') + cloud_owner = split_vim[0] + cloud_region = "".join(split_vim[1:]) + return cloud_owner, cloud_region def get_vim_by_id(vim_id): - ret = req_by_msb("/openoapi/extsys/v1/vims/%s" % vim_id, "GET") - if ret[0] != 0: - logger.error("Status code is %s, detail is %s.", ret[2], ret[1]) - raise VimDriverVioException("Failed to query VIM with \ - id (%s) from extsys." % vim_id, status.HTTP_404_NOT_FOUND) - return json.JSONDecoder().decode(ret[1]) + cloud_owner, cloud_region = split_vim_to_owner_region(vim_id) + client = AAIClient(cloud_owner, cloud_region) + ret = client.get_vim(get_all=True) + ret['type'] = ret['cloud-type'] + ret['version'] = ret['cloud-region-version'] + ret['vimId'] = vim_id + ret['userName'] = ret['esr-system-info-list'][ + 'esr-system-info'][0]['username'] + ret['password'] = ret['esr-system-info-list'][ + 'esr-system-info'][0]['password'] + ret['tenant'] = ret['esr-system-info-list'][ + 'esr-system-info'][0]['default-tenant'] + ret['url'] = ret['esr-system-info-list'][ + 'esr-system-info'][0]['service-url'] + return ret diff --git a/vio/vio/pub/utils/restcall.py b/vio/vio/pub/utils/restcall.py index 590e52f..99ed9d9 100644 --- a/vio/vio/pub/utils/restcall.py +++ b/vio/vio/pub/utils/restcall.py @@ -16,9 +16,16 @@ import logging import urllib2 import uuid import httplib2 +import json +from vio.pub.config.config import AAI_SCHEMA_VERSION +from vio.pub.config.config import AAI_SERVICE_URL +from vio.pub.config.config import AAI_USERNAME +from vio.pub.config.config import AAI_PASSWORD from vio.pub.config.config import MSB_SERVICE_IP, MSB_SERVICE_PORT +from vio.pub.exceptions import VimDriverVioException + rest_no_auth, rest_oneway_auth, rest_bothway_auth = 0, 1, 2 HTTP_200_OK, HTTP_201_CREATED = '200', '201' HTTP_204_NO_CONTENT, HTTP_202_ACCEPTED = '204', '202' @@ -30,16 +37,22 @@ HTTP_401_UNAUTHORIZED, HTTP_400_BADREQUEST = '401', '400' logger = logging.getLogger(__name__) -def call_req(base_url, user, passwd, auth_type, resource, method, content=''): +def call_req(base_url, user, passwd, auth_type, resource, method, content='', + headers=None): callid = str(uuid.uuid1()) - logger.debug("[%s]call_req('%s','%s','%s',%s,'%s','%s','%s')" % ( - callid, base_url, user, passwd, auth_type, resource, method, content)) +# logger.debug("[%s]call_req('%s','%s','%s',%s,'%s','%s','%s')" % ( +# callid, base_url, user, passwd, auth_type, resource, method, content)) ret = None resp_status = '' + resp = "" + full_url = "" + try: full_url = combine_url(base_url, resource) - headers = {'content-type': 'application/json', - 'accept': 'application/json'} + if headers is None: + headers = {} + headers['content-type'] = 'application/json' + if user: headers['Authorization'] = 'Basic ' + \ ('%s:%s' % (user, passwd)).encode("base64") @@ -51,41 +64,40 @@ def call_req(base_url, user, passwd, auth_type, resource, method, content=''): auth_type == rest_no_auth)) http.follow_all_redirects = True try: + logger.debug("request=%s" % full_url) resp, resp_content = http.request( - full_url, method=method.upper(), - body=content, headers=headers) - resp_status, resp_body = resp['status'], resp_content.decode( - 'UTF-8') - logger.debug("[%s][%d]status=%s,resp_body=%s)" % - (callid, retry_times, resp_status, resp_body)) + full_url, method=method.upper(), body=content, + headers=headers) + resp_status = resp['status'] + resp_body = resp_content.decode('UTF-8') + if resp_status in status_ok_list: - ret = [0, resp_body, resp_status] + ret = [0, resp_body, resp_status, resp] else: - ret = [1, resp_body, resp_status] + ret = [1, resp_body, resp_status, resp] break except Exception as ex: if 'httplib.ResponseNotReady' in str(sys.exc_info()): - logger.debug("retry_times=%d", retry_times) logger.error(traceback.format_exc()) - ret = [1, "Unable to connect to %s" % - full_url, resp_status] + ret = [1, "Unable to connect to %s" % full_url, + resp_status, resp] continue raise ex except urllib2.URLError as err: - ret = [2, str(err), resp_status] + ret = [2, str(err), resp_status, resp] except Exception as ex: logger.error(traceback.format_exc()) logger.error("[%s]ret=%s" % (callid, str(sys.exc_info()))) res_info = str(sys.exc_info()) if 'httplib.ResponseNotReady' in res_info: - res_info = "The URL[%s] request failed \ - or is not responding." % full_url - ret = [3, res_info, resp_status] + res_info = ("The URL[%s] request failed or is not responding." % + full_url) + ret = [3, res_info, resp_status, resp] except: logger.error(traceback.format_exc()) - ret = [4, str(sys.exc_info()), resp_status] + ret = [4, str(sys.exc_info()), resp_status, resp] - logger.debug("[%s]ret=%s" % (callid, str(ret))) +# logger.debug("[%s]ret=%s" % (callid, str(ret))) return ret @@ -105,3 +117,191 @@ def combine_url(base_url, resource): else: full_url = base_url + '/' + resource return full_url + + +def get_res_from_aai(resource, content=''): + headers = { + 'X-FromAppId': 'MultiCloud', + 'X-TransactionId': '9001', + 'content-type': 'application/json', + 'accept': 'application/json' + } + base_url = "%s/%s" % (AAI_SERVICE_URL, AAI_SCHEMA_VERSION) + return call_req(base_url, AAI_USERNAME, AAI_PASSWORD, rest_no_auth, + resource, "GET", content, headers) + + +class AAIClient(object): + def __init__(self, cloud_owner, cloud_region): + self.base_url = "%s/%s" % (AAI_SERVICE_URL, AAI_SCHEMA_VERSION) + self.username = AAI_USERNAME + self.password = AAI_PASSWORD + self.default_headers = { + 'X-FromAppId': 'multicloud-openstack-vmware', + 'X-TransactionId': '9004', + 'content-type': 'application/json', + 'accept': 'application/json' + } + self.cloud_owner = cloud_owner + self.cloud_region = cloud_region + + def get_vim(self, get_all=False): + resource = ("/cloud-infrastructure/cloud-regions/cloud-region" + "/%s/%s" % (self.cloud_owner, self.cloud_region)) + if get_all: + resource = "%s?depth=all" % resource + resp = call_req(self.base_url, self.username, self.password, + rest_no_auth, resource, "GET", + headers=self.default_headers) + if resp[0] != 0: + raise VimDriverVioException( + status_code=404, + content="Failed to query VIM with id (%s_%s) from extsys." % ( + self.cloud_owner, self.cloud_region)) + return json.loads(resp[1]) + + def delete_vim(self): + resource = ("/cloud-infrastructure/cloud-regions/cloud-region" + "/%s/%s" % (self.cloud_owner, self.cloud_region)) + 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 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 + self.update_identity_url() + # update tenants + self.add_tenants(content) + # update flavors + self.add_images(content) + # update images + self.add_flavors(content) + # update pservers + self.add_pservers(content) + + def update_identity_url(self): + vim = self.get_vim() + vim['identity-url'] = ("http://%s/api/multicloud/v0/%s_%s/identity/" + "v3" % (MSB_SERVICE_IP, self.cloud_owner, + self.cloud_region)) + resource = ("/cloud-infrastructure/cloud-regions/cloud-region" + "/%s/%s" % (self.cloud_owner, self.cloud_region)) + call_req(self.base_url, self.username, self.password, + rest_no_auth, resource, "PUT", + 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']} + 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'])) + 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'] + } + call_req(self.base_url, self.username, self.password, + rest_no_auth, resource, "PUT", + 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'])) + body = { + 'image-name': image['name'], + # 'image-architecture': image[''], + 'image-os-distro': image['name'].split("-")[0], + 'image-os-version': image['name'].split("-")[1], + # 'application': image[''], + # 'application-vendor': image[''], + # 'application-version': image[''], + # TODO replace this with image proxy endpoint + 'image-selflink': "", + } + 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' + } + 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 + } + ] + } + call_req(self.base_url, self.username, self.password, + rest_no_auth, resource, "PUT", + content=json.dumps(body), + headers=self.default_headers) diff --git a/vio/vio/pub/vim/drivers/vimsdk/compute.py b/vio/vio/pub/vim/drivers/vimsdk/compute.py index 1ed4b25..23a3637 100644 --- a/vio/vio/pub/vim/drivers/vimsdk/compute.py +++ b/vio/vio/pub/vim/drivers/vimsdk/compute.py @@ -125,3 +125,7 @@ class ComputeClient(base.DriverBase): @sdk.translate_exception def get_hypervisor(self, hypervisor, **query): return self.conn.compute.get_hypervisor(hypervisor=hypervisor, **query) + + @sdk.translate_exception + def list_hypervisors(self, **query): + return self.conn.compute.hypervisors(**query) diff --git a/vio/vio/pub/vim/vimapi/nova/OperateHypervisor.py b/vio/vio/pub/vim/vimapi/nova/OperateHypervisor.py index d48b421..96e77bc 100644 --- a/vio/vio/pub/vim/vimapi/nova/OperateHypervisor.py +++ b/vio/vio/pub/vim/vimapi/nova/OperateHypervisor.py @@ -29,3 +29,11 @@ class OperateHypervisor(OperateNova): **kwargs) except exceptions.ResourceNotFound: return None + + def list_hypervisors(self, data, **query): + try: + return self.request('list_hypervisors', data, + project_id=data['project_id'], + **query) + except exceptions.ResourceNotFound: + return None diff --git a/vio/vio/swagger/urls.py b/vio/vio/swagger/urls.py index 920edb7..3448424 100644 --- a/vio/vio/swagger/urls.py +++ b/vio/vio/swagger/urls.py @@ -38,6 +38,10 @@ from vio.swagger.views.proxyplugin.neutron.views import NetWorkServer from vio.swagger.views.proxyplugin.volumn.views import VolumeServer from vio.swagger.views.proxyplugin.heat.views import HeatServer +# Registry +from vio.swagger.views.registry.views import Registry + + urlpatterns = [ url(r'^api/multicloud-vio/v0/swagger.json$', SwaggerJsonView.as_view()), url(r'^api/multicloud-vio/v0/(?P<vimid>[0-9a-zA-Z_-]+)/' @@ -96,6 +100,12 @@ urlpatterns = [ r'(?P<portid>[0-9a-zA-Z\-\_]+)$', DeletePortView.as_view()), + # 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()), + # proxy url(r'^api/multicloud-vio/v0/(?P<vimid>[0-9a-z-A-Z\-\_]+)/identity/v3', TokenView.as_view()), diff --git a/vio/vio/swagger/views/proxyplugin/identity/views.py b/vio/vio/swagger/views/proxyplugin/identity/views.py index 0ce6312..cee11e7 100644 --- a/vio/vio/swagger/views/proxyplugin/identity/views.py +++ b/vio/vio/swagger/views/proxyplugin/identity/views.py @@ -93,9 +93,14 @@ class TokenView(BaseClient): logger.info("vimid(%(vimid)s) get keystone url %(url)s ", {"vimid": vimid, "url": keystoneURL}) try: - res = requests.get(url=keystoneURL).json() - res['version']['links'][0]['href'] = "http://" + \ - MSB_ADDRESS + "/multicloud-vio/v0/" + vimid + "/identity/v3" + res = requests.get(url=keystoneURL, verify=False) + if res.status_code != status.HTTP_200_OK: + return Response(data={"error": res.content}, + status=res.status_code) + res = res.json() + res['version']['links'][0]['href'] = \ + "http://" + MSB_ADDRESS + "/multicloud-vio/v0/" \ + + vimid + "/identity/v3" except Exception as e: logging.exception("error %s" % e) @@ -143,8 +148,11 @@ class TokenView(BaseClient): {"vimid": vimid, "url": url}) try: - res = requests.post(url=url, data=json.dumps( - create_req), headers=headers) + res = requests.post(url=url, data=json.dumps(create_req), + headers=headers, verify=False) + if res.status_code != status.HTTP_201_CREATED: + return Response(data={"error": res.content}, + status=res.status_code) tokenInfo = res.json() resHeader = dict(res.headers) except Exception as e: diff --git a/vio/vio/swagger/views/registry/__init__.py b/vio/vio/swagger/views/registry/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/vio/vio/swagger/views/registry/__init__.py diff --git a/vio/vio/swagger/views/registry/views.py b/vio/vio/swagger/views/registry/views.py new file mode 100644 index 0000000..cde3b5d --- /dev/null +++ b/vio/vio/swagger/views/registry/views.py @@ -0,0 +1,179 @@ +# Copyright (c) 2017 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 logging + +from rest_framework import status +from rest_framework.response import Response +from rest_framework.views import APIView + +from vio.pub.exceptions import VimDriverVioException +from vio.pub.msapi import extsys +from vio.pub.utils.restcall import AAIClient +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 + + +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: + 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 = {"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: + 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 = {"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: + 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 = {"flavors": []} + for flavor in flavors: + rsp['flavors'].append(flavor[0].to_dict()) + return rsp + + def _get_hypervisors(self, auth_info): + hypervisor_op = OperateHypervisor.OperateHypervisor() + try: + hypervisors = hypervisor_op.list_hypervisors(auth_info) + 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 = {"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 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['userName'] = vim_info['userName'] + data['password'] = vim_info['password'] + data['url'] = vim_info['url'] + data['project_name'] = vim_info['tenant'] + + rsp = {} + # get tenants + try: + print('Updating 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 + print('Updating images') + images = self._get_images(data) + rsp.update(images) + # get flavors + print('Updating flavors') + flavors = self._get_flavors(data) + rsp.update(flavors) + # get hypervisors + print('Updating hypervisors') + hypervisors = self._get_hypervisors(data) + rsp.update(hypervisors) + # update A&AI + print('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: + return Response(data=e.message, + 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'] + + query = dict(request.query_params) + tenant_instance = OperateTenant.OperateTenant() + try: + projects = tenant_instance.get_projects(data, **query) + 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) |