summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--multivimbroker/multivimbroker/forwarder/base.py65
-rw-r--r--multivimbroker/multivimbroker/forwarder/urls.py10
-rw-r--r--multivimbroker/multivimbroker/forwarder/views.py125
-rw-r--r--multivimbroker/multivimbroker/pub/exceptions.py23
-rw-r--r--multivimbroker/multivimbroker/pub/msapi/extsys.py4
-rw-r--r--multivimbroker/multivimbroker/pub/utils/restcall.py33
-rw-r--r--multivimbroker/multivimbroker/pub/utils/syscomm.py44
-rw-r--r--multivimbroker/multivimbroker/swagger/multivim.identity.swagger.json145
-rw-r--r--multivimbroker/multivimbroker/swagger/views.py7
9 files changed, 377 insertions, 79 deletions
diff --git a/multivimbroker/multivimbroker/forwarder/base.py b/multivimbroker/multivimbroker/forwarder/base.py
new file mode 100644
index 0000000..8f70c8b
--- /dev/null
+++ b/multivimbroker/multivimbroker/forwarder/base.py
@@ -0,0 +1,65 @@
+# 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 django.http import HttpResponse
+from rest_framework import status
+
+import multivimbroker.pub.exceptions as exceptions
+from multivimbroker.pub.utils.syscomm import getHeadersKeys
+from multivimbroker.pub.utils.syscomm import getMultivimDriver
+from multivimbroker.pub.utils.restcall import req_by_msb
+
+
+logger = logging.getLogger(__name__)
+
+class BaseHandler(object):
+
+ def _request(self,route_uri,method,body="",headers=None):
+
+ try:
+ retcode, content, status_code, resp = \
+ req_by_msb(route_uri, method, body, headers)
+ if retcode != 0:
+ # Execptions are handled within req_by_msb
+ logger.error("Status code is %s, detail is %s.",
+ status_code, content)
+
+ except exceptions.NotFound as e:
+ return HttpResponse(str(e), status=status.HTTP_404_NOT_FOUND)
+
+ except Exception as e:
+ content = e
+ status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
+ logger.exception("exception: %s" % e)
+
+ response = HttpResponse(content, status=status_code)
+ for k in getHeadersKeys(resp):
+ response[k] = resp[k]
+ return response
+
+
+ def send(self,vimid,full_path,body,method,headers=None):
+
+ try:
+ url = getMultivimDriver(vimid,full_path=full_path)
+
+ except exceptions.VimBrokerException as e:
+ logging.exception("vimbroker exception: %s"%e)
+ return HttpResponse(e.content,status=e.status_code)
+ except Exception as e:
+ logging.exception("unkown exception: %s" %e)
+ return HttpResponse(str(e),status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ return self._request(url,method,body=body,headers=headers)
+
diff --git a/multivimbroker/multivimbroker/forwarder/urls.py b/multivimbroker/multivimbroker/forwarder/urls.py
index 5598c44..be20280 100644
--- a/multivimbroker/multivimbroker/forwarder/urls.py
+++ b/multivimbroker/multivimbroker/forwarder/urls.py
@@ -15,10 +15,16 @@
from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
-from . import views
+from multivimbroker.forwarder.views import Forward
+from multivimbroker.forwarder.views import Identity
+
urlpatterns = [
- url(r'^openoapi/multivim/v1/(?P<vimid>[0-9a-zA-Z_-]+)', views.route)
+
+ url(r'^openoapi/multivim/v1/(?P<vimid>[0-9a-zA-Z_-]+)/identity/v3$',Identity.as_view()),
+ url(r'^openoapi/multivim/v1/(?P<vimid>[0-9a-zA-Z_-]+)/identity/v3/auth/tokens$',Identity.as_view()),
+ url(r'^openoapi/multivim/v1/(?P<vimid>[0-9a-zA-Z_-]+)', Forward.as_view()),
+
]
urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/multivimbroker/multivimbroker/forwarder/views.py b/multivimbroker/multivimbroker/forwarder/views.py
index ca93b8e..82759e5 100644
--- a/multivimbroker/multivimbroker/forwarder/views.py
+++ b/multivimbroker/multivimbroker/forwarder/views.py
@@ -11,62 +11,69 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-import logging
-import re
-
-from django.http import HttpResponse
-from django.views.decorators.csrf import csrf_exempt
-
-from rest_framework import status
-
-from multivimbroker.pub.utils.restcall import req_by_msb
-from multivimbroker.pub.msapi.extsys import get_vim_by_id
-
-logger = logging.getLogger(__name__)
-
-
-@csrf_exempt
-def route(request, vimid=''):
- """ get vim info from vimid from local cache first
- and then to ESR if cache miss
- """
- content = ""
- status_code = status.HTTP_200_OK
- try:
- vim = get_vim_by_id(vimid)
- if vim["type"] and vim["version"]:
- pass
-
- except Exception as e:
- logger.error("get_vim_by_id, exception: %s" % e)
- return HttpResponse("Not a valid VIM instance", status=status.HTTP_404_NOT_FOUND)
-
- try:
- if vim and vim["type"] == "openstack":
- if vim["version"] == "kilo":
- multivimdriver = "multivim-kilo"
- elif vim["version"] == "newton":
- multivimdriver = "multivim-newton"
- else:
- # if vim type is openstack, use latest "newton" version as default
- multivimdriver = "multivim-newton"
- elif vim and vim["type"] == "vmware":
- multivimdriver = "multivim-vio"
- else:
- logger.error("wrong vim id: %s, return from extsys:%s" %
- vimid, vim)
- return HttpResponse("Not support VIM type", status=status.HTTP_404_NOT_FOUND)
-
- route_uri = re.sub('multivim', multivimdriver, request.get_full_path())
-
- retcode, content, status_code = \
- req_by_msb(route_uri, request.method, request.body)
- if retcode != 0:
- # Execptions are handled within req_by_msb
- logger.error("Status code is %s, detail is %s.",
- status_code, content)
- except Exception as e:
- content = e
- status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
- logger.error("exception: %s" % e)
- return HttpResponse(content, status=status_code)
+
+from rest_framework.views import APIView
+from multivimbroker.forwarder.base import BaseHandler
+
+#
+class BaseServer(BaseHandler,APIView):
+
+
+ def get(self,request,vimid):
+ raise NotImplementedError()
+
+ def post(self,request,vimid):
+ raise NotImplementedError()
+
+ def put(self,request,vimid):
+ raise NotImplementedError()
+
+ def delete(self,request,vimid):
+ raise NotImplementedError()
+
+ def head(self,request,vimid):
+ raise NotImplementedError()
+
+ def patch(self,request,vimid):
+ raise NotImplementedError()
+
+
+# vio proxy handler
+class Identity(BaseServer):
+
+ def get(self,request,vimid):
+
+ return self.send(vimid,request.get_full_path(),request.body,"GET")
+
+ def post(self,request,vimid):
+
+ return self.send(vimid,request.get_full_path(),request.body,"POST")
+
+
+# forward handler
+class Forward(BaseServer):
+
+ def get(self,request,vimid):
+
+ return self.send(vimid,request.get_full_path(),request.body,"GET")
+
+ def post(self,request,vimid):
+
+ return self.send(vimid,request.get_full_path(),request.body,"POST",headers=None)
+
+ def patch(self,request,vimid):
+
+ return self.send(vimid,request.get_full_path(),request.body,"PATCH",headers=None)
+
+ def delete(self,request,vimid):
+
+ return self.send(vimid,request.get_full_path(),request.body,"DELETE",headers=None)
+
+ def head(self,request,vimid):
+
+ return self.send(vimid,request.get_full_path(),request.body,"HEAD")
+
+ def put(self,request,vimid):
+
+ return self.send(vimid,request.get_full_path(),request.body,"PUT",headers=None)
+
diff --git a/multivimbroker/multivimbroker/pub/exceptions.py b/multivimbroker/multivimbroker/pub/exceptions.py
index f11bb16..d2b2c80 100644
--- a/multivimbroker/multivimbroker/pub/exceptions.py
+++ b/multivimbroker/multivimbroker/pub/exceptions.py
@@ -10,5 +10,24 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-class VimBrokerException(Exception):
- pass
+
+class BaseException(Exception):
+
+ message = "Exception"
+
+ def __init__(self, message=None, status_code="", content=""):
+ super(BaseException, self).__init__(message)
+ self.message = message or self.message
+ self.status_code = status_code
+ self.content = content
+
+class VimBrokerException(BaseException):
+
+ message = "vim error"
+
+
+class NotFound(BaseException):
+
+ message = "not found error"
+
+
diff --git a/multivimbroker/multivimbroker/pub/msapi/extsys.py b/multivimbroker/multivimbroker/pub/msapi/extsys.py
index ac2fa13..1baa08a 100644
--- a/multivimbroker/multivimbroker/pub/msapi/extsys.py
+++ b/multivimbroker/multivimbroker/pub/msapi/extsys.py
@@ -23,7 +23,7 @@ def get_vims():
ret = req_by_msb(ESR_GET_VIM_URI, "GET")
if ret[0] != 0:
logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
- raise VimBrokerException("Failed to query VIMs from extsys.")
+ raise VimBrokerException(status_code=404 ,content="Failed to query VIMs from extsys.")
return json.JSONDecoder().decode(ret[1])
@@ -31,6 +31,6 @@ def get_vim_by_id(vim_id):
ret = req_by_msb("%s/%s" % (ESR_GET_VIM_URI, vim_id), "GET")
if ret[0] != 0:
logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
- raise VimBrokerException(
+ raise VimBrokerException(status_code=404,content=
"Failed to query VIM with id (%s) from extsys." % vim_id)
return json.JSONDecoder().decode(ret[1])
diff --git a/multivimbroker/multivimbroker/pub/utils/restcall.py b/multivimbroker/multivimbroker/pub/utils/restcall.py
index 0b76bae..dc0b822 100644
--- a/multivimbroker/multivimbroker/pub/utils/restcall.py
+++ b/multivimbroker/multivimbroker/pub/utils/restcall.py
@@ -16,6 +16,7 @@ import urllib2
import uuid
import httplib2
+
from multivimbroker.pub.config.config import MSB_SERVICE_IP, MSB_SERVICE_PORT
rest_no_auth, rest_oneway_auth, rest_bothway_auth = 0, 1, 2
@@ -26,15 +27,22 @@ HTTP_404_NOTFOUND, HTTP_403_FORBIDDEN, HTTP_401_UNAUTHORIZED, HTTP_400_BADREQUES
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))
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 == None:
+ headers = {}
+ headers['content-type']='application/json'
+
if user:
headers['Authorization'] = 'Basic ' + ('%s:%s' % (user, passwd)).encode("base64")
ca_certs = None
@@ -42,42 +50,41 @@ def call_req(base_url, user, passwd, auth_type, resource, method, content=''):
http = httplib2.Http(ca_certs=ca_certs, disable_ssl_certificate_validation=(auth_type == rest_no_auth))
http.follow_all_redirects = True
try:
-# logger.debug("request=%s)" % full_url)
+ 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))
+
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]
+ 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)))
return ret
-def req_by_msb(resource, method, content=''):
+def req_by_msb(resource, method, content='',headers=None):
base_url = "http://%s:%s/" % (MSB_SERVICE_IP, MSB_SERVICE_PORT)
- return call_req(base_url, "", "", rest_no_auth, resource, method, content)
+ return call_req(base_url, "", "", rest_no_auth, resource, method, content,headers)
def combine_url(base_url, resource):
diff --git a/multivimbroker/multivimbroker/pub/utils/syscomm.py b/multivimbroker/multivimbroker/pub/utils/syscomm.py
index 735129a..07606bf 100644
--- a/multivimbroker/multivimbroker/pub/utils/syscomm.py
+++ b/multivimbroker/multivimbroker/pub/utils/syscomm.py
@@ -10,7 +10,49 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import inspect
+import re
-
+import multivimbroker.pub.exceptions as exceptions
+from multivimbroker.pub.msapi.extsys import get_vim_by_id
def fun_name():
return inspect.stack()[1][3]
+
+
+
+
+# Which headers are hop-by-hop headers by default
+HOP_BY_HOP = ['connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization', 'te', 'trailers', 'transfer-encoding', 'upgrade']
+def getHeadersKeys(response):
+ hopbyhop = HOP_BY_HOP
+ hopbyhop.extend([x.strip() for x in response.get('connection', '').split(',')])
+ return [header for header in response.keys() if header not in hopbyhop]
+
+
+
+def findMultivimDriver(vim=None):
+
+ if vim and vim["type"] == "openstack":
+ if vim["version"] == "kilo":
+ multivimdriver = "multivim-kilo"
+ elif vim["version"] == "newton":
+ multivimdriver = "multivim-newton"
+ else:
+ # if vim type is openstack, use latest "newton" version as default
+ multivimdriver = "multivim-newton"
+ elif vim and vim["type"] == "vmware":
+ multivimdriver = "multivim-vio"
+ else:
+ raise exceptions.NotFound("Not support VIM type")
+ return multivimdriver
+
+
+
+def getMultivimDriver(vimid,full_path=""):
+
+ multivim = "multivim"
+ vim = get_vim_by_id(vimid)
+ if vim["type"] and vim["version"]:
+ pass
+
+ multivimdriver = findMultivimDriver(vim=vim)
+ return re.sub(multivim, multivimdriver, full_path)
diff --git a/multivimbroker/multivimbroker/swagger/multivim.identity.swagger.json b/multivimbroker/multivimbroker/swagger/multivim.identity.swagger.json
new file mode 100644
index 0000000..923924e
--- /dev/null
+++ b/multivimbroker/multivimbroker/swagger/multivim.identity.swagger.json
@@ -0,0 +1,145 @@
+{
+ "swagger": "2.0",
+ "info": {
+ "version": "1.0.0",
+ "title": "MultiVIM Service rest API"
+ },
+ "basePath": "/openoapi/multivim/v1/",
+ "tags": [
+ {
+ "name": "MultiVIM services"
+ }
+ ],
+ "paths": {
+ "/{vimid}/identity/v3": {
+ "get": {
+ "tags": [
+ "vim identity"
+ ],
+ "summary": "query vim identity server ",
+ "description": "query vim identity server",
+ "operationId": "query_vim_identity",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "name": "vimid",
+ "in": "path",
+ "description": "vim instance id",
+ "required": true,
+ "type": "string"
+ }
+
+
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "schema": {
+ "$ref": "#/definitions/IdentityInfo"
+ }
+ },
+ "404": {
+ "description": "the vim id is wrong"
+ },
+ "500": {
+ "description": "the vim tenants is not accessable"
+ }
+ }
+ }
+ },
+ "/{vimid}/identity/v3/auth/tokens":{
+ "post": {
+ "tags": [
+ "vim identity"
+ ],
+ "summary": "get vim token ",
+ "description": "get vim token",
+ "operationId": "get_vim_token",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "name": "vimid",
+ "in": "path",
+ "description": "vim instance id",
+ "required": true,
+ "type": "string"
+ },
+ {
+ "name": "body",
+ "in": "body",
+ "description": "authrication data",
+ "required": true,
+ "type": "string"
+ }
+
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "schema": {
+ "$ref": "#/definitions/TokenInfo"
+ }
+ },
+ "404": {
+ "description": "the vim id is wrong"
+ },
+ "500": {
+ "description": "the vim tenants is not accessable"
+ }
+ }
+ }
+ }
+ },
+ "definitions": {
+ "IdentityInfo": {
+ "type": "object",
+ "required": [
+ "href",
+ "id"
+ ],
+ "properties": {
+ "href": {
+ "type": "string",
+ "description": "keystone url"
+ },
+ "id": {
+ "type": "string",
+ "description": "keystone version"
+ }
+ }
+ },
+ "TokenInfo": {
+ "type": "object",
+ "required": [
+ "value",
+ "endpoints"
+ ],
+ "properties": {
+ "value": {
+ "type": "string",
+ "description": "token uuid"
+ },
+ "endpoints": {
+ "type": "string",
+ "description": "serivce endpoints"
+ }
+ }
+ }
+ }
+}
+
+
+
+
+
+
diff --git a/multivimbroker/multivimbroker/swagger/views.py b/multivimbroker/multivimbroker/swagger/views.py
index 8e8a2bf..5fcfb53 100644
--- a/multivimbroker/multivimbroker/swagger/views.py
+++ b/multivimbroker/multivimbroker/swagger/views.py
@@ -83,5 +83,12 @@ class SwaggerJsonView(APIView):
f.close()
json_data["paths"].update(json_data_temp["paths"])
json_data["definitions"].update(json_data_temp["definitions"])
+ #
+ json_file = os.path.join(os.path.dirname(__file__), 'multivim.identity.swagger.json')
+ f = open(json_file)
+ json_data_temp = json.JSONDecoder().decode(f.read())
+ f.close()
+ json_data["paths"].update(json_data_temp["paths"])
+ json_data["definitions"].update(json_data_temp["definitions"])
return Response(json_data)