summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBin Yang <bin.yang@windriver.com>2017-08-29 16:18:45 +0800
committerBin Yang <bin.yang@windriver.com>2017-08-29 16:18:45 +0800
commitcb7770b35559af5d63cf44e20ea425b89046c096 (patch)
treec76f092a302a65b9bd4b2bc60c83f6ba411da542
parent74e6b85a978ea6e98cd11f1984baef197712520c (diff)
Add OpenStack proxy for newton
refactor seed code for newton add proxy for identiy,service, add registration, extension management Issue-Id: MULTICLOUD-58 Change-Id: I6a7a21427af4c88b7f060470c1176009c13fc19e Signed-off-by: Bin Yang <bin.yang@windriver.com>
-rw-r--r--License.txt89
-rw-r--r--newton/README.md2
-rw-r--r--newton/assembly.xml1
-rw-r--r--newton/newton/extensions/__init__.py10
-rw-r--r--newton/newton/extensions/urls.py28
-rw-r--r--newton/newton/extensions/views/__init__.py10
-rw-r--r--newton/newton/extensions/views/epacaps.py65
-rw-r--r--newton/newton/extensions/views/extensions.py76
-rw-r--r--newton/newton/proxy/__init__.py10
-rw-r--r--newton/newton/proxy/tests/__init__.py13
-rw-r--r--newton/newton/proxy/tests/test_identity_proxy.py533
-rw-r--r--newton/newton/proxy/urls.py34
-rw-r--r--newton/newton/proxy/views/__init__.py10
-rw-r--r--newton/newton/proxy/views/identityV3.py202
-rw-r--r--newton/newton/proxy/views/services.py502
-rw-r--r--newton/newton/pub/config/config.py30
-rw-r--r--newton/newton/pub/msapi/extsys.py78
-rw-r--r--newton/newton/registration/__init__.py10
-rw-r--r--newton/newton/registration/views/__init__.py10
-rw-r--r--newton/newton/registration/views/registration.py93
-rw-r--r--newton/newton/requests/views/util.py134
-rw-r--r--newton/newton/settings.py21
-rw-r--r--newton/newton/swagger/multivim.flavor.swagger.json2
-rw-r--r--newton/newton/swagger/multivim.host.swagger.json2
-rw-r--r--newton/newton/swagger/multivim.image.swagger.json2
-rw-r--r--newton/newton/swagger/multivim.limit.swagger.json2
-rw-r--r--newton/newton/swagger/multivim.network.swagger.json2
-rw-r--r--newton/newton/swagger/multivim.server.swagger.json2
-rw-r--r--newton/newton/swagger/multivim.subnet.swagger.json2
-rw-r--r--newton/newton/swagger/multivim.tenant.swagger.json2
-rw-r--r--newton/newton/swagger/multivim.volume.swagger.json2
-rw-r--r--newton/newton/swagger/multivim.vport.swagger.json2
-rw-r--r--newton/newton/swagger/tests.py2
-rw-r--r--newton/newton/swagger/urls.py2
-rw-r--r--newton/newton/swagger/views.py2
-rw-r--r--newton/newton/urls.py21
-rw-r--r--newton/pom.xml16
-rw-r--r--newton/requirements.txt3
-rw-r--r--newton/tox.ini2
-rw-r--r--pom.xml9
40 files changed, 1926 insertions, 112 deletions
diff --git a/License.txt b/License.txt
index dd08487b..94e53422 100644
--- a/License.txt
+++ b/License.txt
@@ -471,3 +471,92 @@ the avoidance of doubt, this paragraph does not form part of the
public licenses.
Creative Commons may be contacted at creativecommons.org.
+
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+“Warranty Disclaimer & Limitation of Liability
+
+
+
+OPEN SOURCE SOFTWARE: "Open Source Software" is software that may be
+
+delivered with the Software and is licensed in accordance with open
+
+source licenses, including, but not limited to, any software licensed
+
+under Academic Free License, Apache Software License, Artistic License,
+
+BSD License, GNU General Public License, GNU Library General Public
+
+License, GNU Lesser Public License, Mozilla Public License, Python
+
+License or any other similar license.
+
+
+
+DISCLAIMER OF WARRANTIES: WIND RIVER AND ITS LICENSORS DISCLAIM ALL
+
+WARRANTIES, EXPRESS, IMPLIED AND STATUTORY INCLUDING, WITHOUT
+
+LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+
+PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT OF THIRD PARTY RIGHTS
+
+WITH RESPECT TO OPEN SOURCE SOFTWARE. NO ORAL OR WRITTEN INFORMATION OR
+
+ADVICE GIVEN BY WIND RIVER, ITS DEALERS, DISTRIBUTORS, AGENTS OR
+
+EMPLOYEES SHALL IN ANY WAY INCREASE THE SCOPE OF THIS WARRANTY. Some
+
+jurisdictions do not allow the limitation or exclusion of implied
+
+warranties or how long an implied warranty may last, so the above
+
+limitations may not apply to Customer. This warranty gives Customer
+
+specific legal rights and Customer may have other rights that vary from
+
+jurisdiction to jurisdiction.
+
+
+
+LIMITATION OF LIABILITY: WIND RIVER AND ITS LICENSORS SHALL NOT BE
+
+LIABLE FOR ANY INCIDENTAL, SPECIAL, CONSEQUENTIAL OR INDIRECT DAMAGES
+
+OF ANY KIND (INCLUDING DAMAGES FOR INTERRUPTION OF BUSINESS, PROCUREMENT
+
+OF SUBSTITUTE GOODS, LOSS OF PROFITS, OR THE LIKE) REGARDLESS OF THE
+
+FORM OF ACTION WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT
+
+PRODUCT LIABILITY OR ANY OTHER LEGAL OR EQUITABLE THEORY, ARISING OUT OF
+
+OR RELATED TO OPEN SOURCE SOFTWARE, EVEN IF WIND RIVER HAS BEEN ADVISED
+
+OF THE POSSIBILITY OF SUCH DAMAGES. IN NO EVENT WILL WIND RIVER'S
+
+AGGREGATE CUMULATIVE LIABILITY FOR ANY CLAIMS ARISING OUT OF OR RELATED
+
+TO OPEN SOURCE SOFTWARE EXCEED ONE HUNDRED DOLLARS ($100). Some
+
+jurisdictions do not allow the exclusion or limitation of incidental or
+
+consequential damages so this limitation and exclusion may not apply to
+
+Customer.
+
+
+
+THE WARRANTY DISCLAIMER AND LIMITED LIABILITY ARE FUNDAMENTAL ELEMENTS
+
+OF THE BASIS OF THE BARGAIN BETWEEN WIND RIVER AND CUSTOMER. WIND RIVER
+
+WOULD NOT BE ABLE TO PROVIDE OPEN SOURCE SOFTWARE WITHOUT SUCH
+
+LIMITATIONS.
+
+
+
+The End”
diff --git a/newton/README.md b/newton/README.md
index ca2bb587..f8434d2b 100644
--- a/newton/README.md
+++ b/newton/README.md
@@ -9,4 +9,4 @@
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# Micro service of network service life cycle management.
+# Micro service of MultiCloud plugin for newton.
diff --git a/newton/assembly.xml b/newton/assembly.xml
index 81b17ee6..89f1a954 100644
--- a/newton/assembly.xml
+++ b/newton/assembly.xml
@@ -50,5 +50,4 @@
</fileSet>
</fileSets>
<baseDirectory>newton</baseDirectory>
- <!--baseDirectory>multivimdriver-openstack/newton</baseDirectory-->
</assembly>
diff --git a/newton/newton/extensions/__init__.py b/newton/newton/extensions/__init__.py
new file mode 100644
index 00000000..802f3fba
--- /dev/null
+++ b/newton/newton/extensions/__init__.py
@@ -0,0 +1,10 @@
+# Copyright (c) 2017 Wind River Systems, 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.
diff --git a/newton/newton/extensions/urls.py b/newton/newton/extensions/urls.py
new file mode 100644
index 00000000..ade2b6dc
--- /dev/null
+++ b/newton/newton/extensions/urls.py
@@ -0,0 +1,28 @@
+# Copyright (c) 2017 Wind River Systems, 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.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from django.conf.urls import url
+from rest_framework.urlpatterns import format_suffix_patterns
+
+from views import extensions
+from views import epacaps
+
+urlpatterns = [
+ url(r'^sions$', extensions.Extensions.as_view()),
+ url(r'^sions/$', extensions.Extensions.as_view()),
+ url(r'^sions/epa-caps$', epacaps.EpaCaps.as_view()),
+ url(r'^sions/epa-caps/$', epacaps.EpaCaps.as_view()),
+]
+
+urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/newton/newton/extensions/views/__init__.py b/newton/newton/extensions/views/__init__.py
new file mode 100644
index 00000000..802f3fba
--- /dev/null
+++ b/newton/newton/extensions/views/__init__.py
@@ -0,0 +1,10 @@
+# Copyright (c) 2017 Wind River Systems, 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.
diff --git a/newton/newton/extensions/views/epacaps.py b/newton/newton/extensions/views/epacaps.py
new file mode 100644
index 00000000..7d3dd0af
--- /dev/null
+++ b/newton/newton/extensions/views/epacaps.py
@@ -0,0 +1,65 @@
+# Copyright (c) 2017 Wind River Systems, 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.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import logging
+import json
+import traceback
+
+from django.core.cache import cache
+
+from keystoneauth1 import access
+from keystoneauth1.access import service_catalog
+from keystoneauth1.exceptions import HttpError
+from rest_framework import status
+from rest_framework.response import Response
+from rest_framework.views import APIView
+
+from newton.pub.config import config
+from newton.pub.exceptions import VimDriverNewtonException
+from newton.requests.views.util import VimDriverUtils
+from newton.pub.msapi import extsys
+
+logger = logging.getLogger(__name__)
+
+DEBUG=True
+
+
+class EpaCaps(APIView):
+
+ def get(self, request, vimid=""):
+ logger.debug("EpaCaps--get::data> %s" % request.data)
+ logger.debug("EpaCaps--get::vimid> %s"
+ % vimid)
+ try:
+
+ vim = VimDriverUtils.get_vim_info(vimid)
+ caps_json = json.loads(vim['cloud_epa_caps'])
+
+ cloud_owner, cloud_region_id = extsys.decode_vim_id(vimid)
+ content = {
+ "cloud-owner":cloud_owner,
+ "cloud-region-id":cloud_region_id,
+ "vimid":vimid,
+ "cloud-epa-caps": caps_json,
+ }
+ return Response(data=content, status=status.HTTP_200_OK)
+ #return resp
+ except VimDriverNewtonException as e:
+ return Response(data={'error': e.content}, status=e.status_code)
+ except HttpError as e:
+ logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json()))
+ return Response(data=e.response.json(), status=e.http_status)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
diff --git a/newton/newton/extensions/views/extensions.py b/newton/newton/extensions/views/extensions.py
new file mode 100644
index 00000000..e930f06d
--- /dev/null
+++ b/newton/newton/extensions/views/extensions.py
@@ -0,0 +1,76 @@
+# Copyright (c) 2017 Wind River Systems, 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.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import logging
+import json
+import traceback
+
+from django.core.cache import cache
+
+from keystoneauth1 import access
+from keystoneauth1.access import service_catalog
+from keystoneauth1.exceptions import HttpError
+from rest_framework import status
+from rest_framework.response import Response
+from rest_framework.views import APIView
+
+from newton.pub.config import config
+from newton.pub.exceptions import VimDriverNewtonException
+from newton.requests.views.util import VimDriverUtils
+from newton.pub.msapi import extsys
+
+logger = logging.getLogger(__name__)
+
+DEBUG=True
+
+
+class Extensions(APIView):
+
+ def get(self, request, vimid=""):
+ logger.debug("Extensions--get::data> %s" % request.data)
+ logger.debug("Extensions--get::vimid> %s"
+ % vimid)
+ try:
+ cloud_owner, cloud_region_id = extsys.decode_vim_id(vimid)
+ registered_extensions = \
+ [
+ {
+ "alias": "epa-caps",
+ "description": "Multiple network support",
+ "name": "EPACapsQuery",
+ 'links': [ \
+ {
+ "url": "http://%s:%s/api/multicloud-newton/v0/%s/extensions/epa-caps" \
+ % (config.MSB_SERVICE_IP, config.MSB_SERVICE_PORT, vimid), \
+ }
+ ]
+ }
+ ]
+
+ content = {
+ "cloud-owner":cloud_owner,
+ "cloud-region-id":cloud_region_id,
+ "vimid":vimid,
+ "extensions": registered_extensions
+ }
+ return Response(data=content, status=status.HTTP_200_OK)
+ #return resp
+ except VimDriverNewtonException as e:
+ return Response(data={'error': e.content}, status=e.status_code)
+ except HttpError as e:
+ logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json()))
+ return Response(data=e.response.json(), status=e.http_status)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
diff --git a/newton/newton/proxy/__init__.py b/newton/newton/proxy/__init__.py
new file mode 100644
index 00000000..802f3fba
--- /dev/null
+++ b/newton/newton/proxy/__init__.py
@@ -0,0 +1,10 @@
+# Copyright (c) 2017 Wind River Systems, 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.
diff --git a/newton/newton/proxy/tests/__init__.py b/newton/newton/proxy/tests/__init__.py
new file mode 100644
index 00000000..48b6e44b
--- /dev/null
+++ b/newton/newton/proxy/tests/__init__.py
@@ -0,0 +1,13 @@
+# Copyright (c) 2017 Wind River Systems, 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.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/newton/newton/proxy/tests/test_identity_proxy.py b/newton/newton/proxy/tests/test_identity_proxy.py
new file mode 100644
index 00000000..5066ed67
--- /dev/null
+++ b/newton/newton/proxy/tests/test_identity_proxy.py
@@ -0,0 +1,533 @@
+# Copyright (c) 2017 Wind River Systems, 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.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import json
+
+import mock
+import unittest
+
+from django.test import Client
+from rest_framework import status
+
+from keystoneauth1 import session
+from keystoneauth1.exceptions import HttpError
+
+from newton.requests.views.util import VimDriverUtils
+from newton.proxy.views.identityV3 import Tokens, Catalog
+
+mock_viminfo = {
+ "createTime": "2017-04-01 02:22:27",
+ "domain": "Default",
+ "name": "TiS_R4",
+ "password": "admin",
+ "tenant": "admin",
+ "type": "openstack",
+ "url": "http://128.224.180.14:5000/v3",
+ "userName": "admin",
+ "vendor": "WindRiver",
+ "version": "newton",
+ "vimId": "windriver-hudson-dc_RegionOne",
+ 'cloud_owner':'windriver-hudson-dc',
+ 'cloud_region_id':'RegionOne',
+ 'cloud_extra_info':'',
+ 'cloud_epa_caps':'{"huge_page":"true","cpu_pinning":"true",\
+ "cpu_thread_policy":"true","numa_aware":"true","sriov":"true",\
+ "dpdk_vswitch":"true","rdt":"false","numa_locality_pci":"true"}',
+ 'insecure':'True',
+}
+
+mock_auth_state = {
+ "body" : {
+ "token" : {
+ "is_domain" : "false",
+ "expires_at" : "2017-08-27T14:19:15.000000Z",
+ "issued_at" : "2017-08-27T13:19:15.000000Z",
+ "roles" : [
+ {
+ "id" : "9fe2ff9ee4384b1894a90878d3e92bab",
+ "name" : "_member_"
+ },
+ {
+ "id" : "b86a7e02935844b899d3d326f83c1b1f",
+ "name" : "admin"
+ },
+ {
+ "name" : "heat_stack_owner",
+ "id" : "7de502236e954c8282de32e773fc052e"
+ }
+ ],
+ "methods" : [
+ "password"
+ ],
+ "catalog" : [
+ {
+ "id" : "99aefcc82a9246f98f8c281e61ffc754",
+ "endpoints" : [
+ {
+ "region" : "RegionOne",
+ "url" : "http://128.224.180.14:9696",
+ "id" : "39583c1508ad4b71b380570a745ee10a",
+ "interface" : "public",
+ "region_id" : "RegionOne"
+ },
+ {
+ "url" : "http://192.168.204.2:9696",
+ "region" : "RegionOne",
+ "id" : "37e8d07ba24e4b8f93490c9daaba06e2",
+ "interface" : "internal",
+ "region_id" : "RegionOne"
+ },
+ {
+ "interface" : "admin",
+ "id" : "7eee4ca98d444b1abb00a50d4b89373f",
+ "region_id" : "RegionOne",
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:9696"
+ }
+ ],
+ "name" : "neutron",
+ "type" : "network"
+ },
+ {
+ "endpoints" : [
+ {
+ "interface" : "public",
+ "id" : "10496738fa374295a4a88a63b81a1589",
+ "region_id" : "RegionOne",
+ "url" : "http://128.224.180.14:8777",
+ "region" : "RegionOne"
+ },
+ {
+ "id" : "02dcb8c0bd464c4489fa0a0c9f28571f",
+ "region_id" : "RegionOne",
+ "interface" : "internal",
+ "url" : "http://192.168.204.2:8777",
+ "region" : "RegionOne"
+ },
+ {
+ "region_id" : "RegionOne",
+ "id" : "8a73b0d3743b4e78b87614690f6e97fe",
+ "interface" : "admin",
+ "url" : "http://192.168.204.2:8777",
+ "region" : "RegionOne"
+ }
+ ],
+ "id" : "d131054da83f4c93833799747a0f4709",
+ "name" : "ceilometer",
+ "type" : "metering"
+ },
+ {
+ "type" : "volumev2",
+ "name" : "cinderv2",
+ "endpoints" : [
+ {
+ "id" : "35a67ad36f0447d19c9662babf7cf609",
+ "interface" : "public",
+ "region_id" : "RegionOne",
+ "url" : "http://128.224.180.14:8776/v2/fcca3cc49d5e42caae15459e27103efc",
+ "region" : "RegionOne"
+ },
+ {
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:8776/v2/fcca3cc49d5e42caae15459e27103efc",
+ "id" : "c6ea42052268420fa2c8d351ee68c922",
+ "interface" : "internal",
+ "region_id" : "RegionOne"
+ },
+ {
+ "region_id" : "RegionOne",
+ "id" : "91cb24853dc3450d847b0c286a2e44ea",
+ "interface" : "admin",
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:8776/v2/fcca3cc49d5e42caae15459e27103efc"
+ }
+ ],
+ "id" : "40440057102440739c30be10a66bc5d1"
+ },
+ {
+ "name" : "heat",
+ "type" : "orchestration",
+ "id" : "35300cce88db4bd4bb5a72ffe3b88b00",
+ "endpoints" : [
+ {
+ "id" : "58999d7b4a94439089ecfb2aca2d7f6c",
+ "region_id" : "RegionOne",
+ "interface" : "public",
+ "region" : "RegionOne",
+ "url" : "http://128.224.180.14:8004/v1/fcca3cc49d5e42caae15459e27103efc"
+ },
+ {
+ "url" : "http://192.168.204.2:8004/v1/fcca3cc49d5e42caae15459e27103efc",
+ "region" : "RegionOne",
+ "interface" : "internal",
+ "id" : "1e0ee1a2aef84802b921d422372a567e",
+ "region_id" : "RegionOne"
+ },
+ {
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:8004/v1/fcca3cc49d5e42caae15459e27103efc",
+ "id" : "17661bf4859741b8a43a461dedad1871",
+ "region_id" : "RegionOne",
+ "interface" : "admin"
+ }
+ ]
+ },
+ {
+ "id" : "08dc6912aea64c01925012c8a6df250a",
+ "endpoints" : [
+ {
+ "id" : "02792c4eed77486083f9b2e52d7b94b0",
+ "region_id" : "RegionOne",
+ "interface" : "public",
+ "region" : "RegionOne",
+ "url" : "http://128.224.180.14:5000/v3"
+ },
+ {
+ "id" : "b6d5cad394b94309ae40d8de88059c5f",
+ "region_id" : "RegionOne",
+ "interface" : "internal",
+ "url" : "http://192.168.204.2:5000/v3",
+ "region" : "RegionOne"
+ },
+ {
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:35357/v3",
+ "region_id" : "RegionOne",
+ "id" : "1f18e2b7c6a34493b86853b65917888e",
+ "interface" : "admin"
+ }
+ ],
+ "type" : "identity",
+ "name" : "keystone"
+ },
+ {
+ "name" : "vim",
+ "type" : "nfv",
+ "endpoints" : [
+ {
+ "url" : "http://128.224.180.14:4545",
+ "region" : "RegionOne",
+ "id" : "b33e317345e4480ab0786e4960995ec9",
+ "interface" : "public",
+ "region_id" : "RegionOne"
+ },
+ {
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:4545",
+ "interface" : "internal",
+ "id" : "03c85828d5bf432ab04831aa65ac9c52",
+ "region_id" : "RegionOne"
+ },
+ {
+ "id" : "067983abb061476cb53a9e23a740d98f",
+ "region_id" : "RegionOne",
+ "interface" : "admin",
+ "url" : "http://192.168.204.2:4545",
+ "region" : "RegionOne"
+ }
+ ],
+ "id" : "01636c856fc84988b38b9117eb4a8021"
+ },
+ {
+ "name" : "aodh",
+ "type" : "alarming",
+ "id" : "eb269151d0e44744a5b5449657bdc61c",
+ "endpoints" : [
+ {
+ "id" : "5bfc6c056e0244c493642eb82f6aaa11",
+ "region_id" : "RegionOne",
+ "interface" : "public",
+ "url" : "http://128.224.180.14:8042",
+ "region" : "RegionOne"
+ },
+ {
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:8042",
+ "region_id" : "RegionOne",
+ "id" : "ad69c7f76dce4089a195b9221ddbfb44",
+ "interface" : "internal"
+ },
+ {
+ "interface" : "admin",
+ "id" : "3e8fcdfa7bcb40b0ae33c282adfcc9ff",
+ "region_id" : "RegionOne",
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:8042"
+ }
+ ]
+ },
+ {
+ "name" : "sysinv",
+ "type" : "platform",
+ "endpoints" : [
+ {
+ "region" : "RegionOne",
+ "url" : "http://128.224.180.14:6385/v1",
+ "interface" : "public",
+ "id" : "ba4ba8104590421b84672306c7e0e1f1",
+ "region_id" : "RegionOne"
+ },
+ {
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:6385/v1",
+ "interface" : "internal",
+ "id" : "a1cba34b163f496ab1acd6e9b51e39a2",
+ "region_id" : "RegionOne"
+ },
+ {
+ "url" : "http://192.168.204.2:6385/v1",
+ "region" : "RegionOne",
+ "id" : "7c171210a2c841a6a52a5713e316d6fc",
+ "interface" : "admin",
+ "region_id" : "RegionOne"
+ }
+ ],
+ "id" : "256bbad671f946fea543e6bd71f98875"
+ },
+ {
+ "id" : "e84665dcce814c05b4c5084964547534",
+ "endpoints" : [
+ {
+ "url" : "http://128.224.180.14:8000/v1/fcca3cc49d5e42caae15459e27103efc",
+ "region" : "RegionOne",
+ "region_id" : "RegionOne",
+ "id" : "b2ed1a23dc6944bea129c20861e0286a",
+ "interface" : "public"
+ },
+ {
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:8000/v1/fcca3cc49d5e42caae15459e27103efc",
+ "interface" : "internal",
+ "id" : "c4df7c6bc15646848eff35caf6ffea8e",
+ "region_id" : "RegionOne"
+ },
+ {
+ "region_id" : "RegionOne",
+ "id" : "61b3dabb761443a89ab549f437c05ab0",
+ "interface" : "admin",
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:8000/v1/fcca3cc49d5e42caae15459e27103efc"
+ }
+ ],
+ "name" : "heat-cfn",
+ "type" : "cloudformation"
+ },
+ {
+ "id" : "823024424a014981a3721229491c0b1a",
+ "endpoints" : [
+ {
+ "region" : "RegionOne",
+ "url" : "http://128.224.180.14:8776/v1/fcca3cc49d5e42caae15459e27103efc",
+ "region_id" : "RegionOne",
+ "id" : "4a52e4e54ff440789f9a797919c4a0f2",
+ "interface" : "public"
+ },
+ {
+ "url" : "http://192.168.204.2:8776/v1/fcca3cc49d5e42caae15459e27103efc",
+ "region" : "RegionOne",
+ "id" : "d4f9a84476524a39844f0fce63f1022e",
+ "region_id" : "RegionOne",
+ "interface" : "internal"
+ },
+ {
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:8776/v1/fcca3cc49d5e42caae15459e27103efc",
+ "interface" : "admin",
+ "id" : "81bf3810a8cc4697b68c6e93b5b8fe1f",
+ "region_id" : "RegionOne"
+ }
+ ],
+ "type" : "volume",
+ "name" : "cinder"
+ },
+ {
+ "name" : "glance",
+ "type" : "image",
+ "endpoints" : [
+ {
+ "id" : "bd930aba961946cfb1401bada56d55e3",
+ "region_id" : "RegionOne",
+ "interface" : "public",
+ "region" : "RegionOne",
+ "url" : "http://128.224.180.14:9292"
+ },
+ {
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:9292",
+ "id" : "c11da585f0b141b99d1e18bb9a607beb",
+ "region_id" : "RegionOne",
+ "interface" : "internal"
+ },
+ {
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:9292",
+ "id" : "31b26c625a6a4fc7910dc5935155996e",
+ "interface" : "admin",
+ "region_id" : "RegionOne"
+ }
+ ],
+ "id" : "3b78cf039bc54d1bbb99ab3a4be15ef1"
+ },
+ {
+ "id" : "b8701374bf254de1beee8a2c9ecc6b33",
+ "endpoints" : [
+ {
+ "region_id" : "RegionOne",
+ "id" : "f7407f330c8b4577b1d377d3fab9c2f8",
+ "interface" : "public",
+ "region" : "RegionOne",
+ "url" : "http://128.224.180.14:15491"
+ },
+ {
+ "url" : "http://192.168.204.2:5491",
+ "region" : "RegionOne",
+ "interface" : "internal",
+ "id" : "0b37ce31a32f4b6fa5e1aa0d6c20680f",
+ "region_id" : "RegionOne"
+ },
+ {
+ "region_id" : "RegionOne",
+ "id" : "7b87ea72adf245e1991e9e0df29b7ea9",
+ "interface" : "admin",
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:5491"
+ }
+ ],
+ "type" : "patching",
+ "name" : "patching"
+ },
+ {
+ "id" : "0ec0923a58f04ffeb6fced3bbc5c0947",
+ "endpoints" : [
+ {
+ "url" : "http://128.224.180.14:8774/v2.1/fcca3cc49d5e42caae15459e27103efc",
+ "region" : "RegionOne",
+ "id" : "13168b12da17451fb39630de67db168f",
+ "region_id" : "RegionOne",
+ "interface" : "public"
+ },
+ {
+ "id" : "22dd6a44209f42d986b82e3aa6535f82",
+ "interface" : "internal",
+ "region_id" : "RegionOne",
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:8774/v2.1/fcca3cc49d5e42caae15459e27103efc"
+ },
+ {
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:8774/v2.1/fcca3cc49d5e42caae15459e27103efc",
+ "id" : "552a991ae501492f841c1b6e2ff38fc5",
+ "region_id" : "RegionOne",
+ "interface" : "admin"
+ }
+ ],
+ "type" : "compute",
+ "name" : "nova"
+ },
+ {
+ "id" : "50b219650f1049b097b3f14e8c70cdf8",
+ "endpoints" : [
+ {
+ "interface" : "public",
+ "id" : "5a4276cd6e4d43e883cf8640d4e13f7d",
+ "region_id" : "RegionOne",
+ "region" : "RegionOne",
+ "url" : "http://128.224.180.14:8776/v3/fcca3cc49d5e42caae15459e27103efc"
+ },
+ {
+ "region" : "RegionOne",
+ "url" : "http://192.168.204.2:8776/v3/fcca3cc49d5e42caae15459e27103efc",
+ "region_id" : "RegionOne",
+ "id" : "c796df3ca5a84fc18db5b43a55283953",
+ "interface" : "internal"
+ },
+ {
+ "region_id" : "RegionOne",
+ "id" : "cf55c2b34d0049ba835a2e48b9ad0e2e",
+ "interface" : "admin",
+ "url" : "http://192.168.204.2:8776/v3/fcca3cc49d5e42caae15459e27103efc",
+ "region" : "RegionOne"
+ }
+ ],
+ "type" : "volumev3",
+ "name" : "cinderv3"
+ }
+ ],
+ "project" : {
+ "name" : "admin",
+ "id" : "fcca3cc49d5e42caae15459e27103efc",
+ "domain" : {
+ "id" : "default",
+ "name" : "Default"
+ }
+ },
+ "user" : {
+ "name" : "admin",
+ "id" : "9efb043c7629497a8028d7325ca1afb0",
+ "domain" : {
+ "id" : "default",
+ "name" : "Default"
+ }
+ },
+ "audit_ids" : [
+ "_ZWT10DtSZKRXIvIcxun7w"
+ ]
+ }
+ },
+ "auth_token" : "1a62b3971d774404a504c5d9a3e506e3"
+}
+
+
+class TestIdentityService(unittest.TestCase):
+ def setUp(self):
+ self.client = Client()
+ pass
+
+ def tearDown(self):
+ pass
+
+ @mock.patch.object(VimDriverUtils, 'get_vim_info')
+ @mock.patch.object(VimDriverUtils, 'get_session')
+ @mock.patch.object(VimDriverUtils, 'get_auth_state')
+ @mock.patch.object(VimDriverUtils, 'update_token_cache')
+ def test_token(self, mock_update_token_cache, mock_get_auth_state, mock_get_session, mock_get_vim_info):
+ '''
+ test API: get token
+ :param mock_update_token_cache:
+ :param mock_get_auth_state:
+ :param mock_get_session:
+ :param mock_get_vim_info:
+ :return:
+ '''
+
+ #mock VimDriverUtils APIs
+ mock_session_specs = ["get"]
+ mock_session_get_response = {'status':200}
+ mock_session = mock.Mock(name='mock_session', spec=mock_session_specs)
+ mock_session.get.return_value = mock_session_get_response
+
+ mock_get_vim_info.return_value = mock_viminfo
+ mock_get_session.return_value = mock_session
+ mock_get_auth_state.return_value = json.dumps(mock_auth_state)
+ mock_update_token_cache.return_value = 0
+
+ #simulate client to make the request
+ data ={}
+ response = self.client.post("/api/multicloud-newton/v0/windriver-hudson-dc_RegionOne/identity/v3/auth/tokens", data=data, format='json')
+ self.failUnlessEqual(status.HTTP_201_CREATED, response.status_code)
+ context = json.loads(response.content)
+
+ self.assertTrue(response['X-Subject-Token'] != None)
+ self.assertTrue(context['token']['catalog'] != None)
+
+ pass
diff --git a/newton/newton/proxy/urls.py b/newton/newton/proxy/urls.py
new file mode 100644
index 00000000..01d2007c
--- /dev/null
+++ b/newton/newton/proxy/urls.py
@@ -0,0 +1,34 @@
+# Copyright (c) 2017 Wind River Systems, 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.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from django.conf.urls import url
+from rest_framework.urlpatterns import format_suffix_patterns
+
+from views import identityV3
+from views import services
+
+urlpatterns = [
+ # url(r'^identity/v2)$',
+ # identityV2.Tokens.as_view()),
+ url(r'^identity/v3/auth/tokens$',
+ identityV3.Tokens.as_view()),
+ url(r'^identity/v3/auth/catalog$',
+ identityV3.Catalog.as_view()),
+ url(r'^identity/(?:v2.0/|)tenants$',
+ services.GetTenants.as_view()),
+ url(r'^(?P<servicetype>[0-9a-zA-Z_-]+)/(?P<requri>[0-9a-zA-Z./_-]*)$',
+ services.Services.as_view()),
+]
+
+urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/newton/newton/proxy/views/__init__.py b/newton/newton/proxy/views/__init__.py
new file mode 100644
index 00000000..802f3fba
--- /dev/null
+++ b/newton/newton/proxy/views/__init__.py
@@ -0,0 +1,10 @@
+# Copyright (c) 2017 Wind River Systems, 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.
diff --git a/newton/newton/proxy/views/identityV3.py b/newton/newton/proxy/views/identityV3.py
new file mode 100644
index 00000000..b75dcd3b
--- /dev/null
+++ b/newton/newton/proxy/views/identityV3.py
@@ -0,0 +1,202 @@
+# Copyright (c) 2017 Wind River Systems, 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.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import logging
+import json
+import traceback
+
+from django.core.cache import cache
+
+from keystoneauth1 import access
+from keystoneauth1.access import service_catalog
+from keystoneauth1.exceptions import HttpError
+from rest_framework import status
+from rest_framework.response import Response
+from rest_framework.views import APIView
+
+from newton.pub.config import config
+from newton.pub.exceptions import VimDriverNewtonException
+from newton.requests.views.util import VimDriverUtils
+
+logger = logging.getLogger(__name__)
+
+DEBUG=True
+MULTICLOUD_PREFIX = "http://%s:%s/api/multicloud-newton/v0" %(config.MSB_SERVICE_IP, config.MSB_SERVICE_PORT)
+
+def update_catalog(vimid, catalog, multicould_namespace):
+ '''
+ replace the orignal endpoints with multicloud's
+ return the catalog with updated endpoints, and also another catalog with prefix and suffix of each endpoint
+ :param vimid:
+ :param catalog: service catalog to be updated
+ :param multicould_namespace: multicloud namespace prefix to replace the real one in catalog endpoints url
+ :return:updated catalog, and metadata_catalog looks like:
+ {
+ 'compute': {
+ 'prefix': 'http://ip:port',
+ 'proxy_prefix': 'http://another_ip: another_port',
+ 'suffix': 'v2.1/53a4ab9015c84ee892e46d294f3b8b2d',
+ },
+ 'network': {
+ 'prefix': 'http://ip:port',
+ 'proxy_prefix': 'http://another_ip: another_port',
+ 'suffix': '',
+ },
+ }
+ '''
+
+ metadata_catalog = {}
+ if catalog:
+ # filter and replace endpoints of catalogs
+ for item in catalog:
+ one_catalog = {}
+ metadata_catalog[item['type']] = one_catalog
+
+ endpoints = item['endpoints']
+ item['endpoints']=[]
+ for endpoint in endpoints:
+ interface = endpoint.get('interface', None)
+ if interface != 'public':
+ continue
+# elif item["type"] == "identity":
+# endpoint["url"] = multicould_namespace + "/%s/identity/v3" % vimid
+ else:
+ # replace the endpoint with MultiCloud's proxy
+ import re
+ endpoint_url = endpoint["url"]
+# m = re.search(r'^http[s]*://([0-9.]+:[0-9]+)[/]*([0-9a-zA-Z/._-]*)$', endpoint_url)
+ m = re.search(r'^(http[s]?://[0-9.]+:[0-9]+)(/([0-9a-zA-Z/._-]+)$)?', endpoint_url)
+ if m:
+ real_prefix = m.group(1)
+ real_suffix = m.group(3)
+
+ # populate metadata_catalog
+ one_catalog['prefix'] = real_prefix
+ one_catalog['suffix'] = real_suffix if real_suffix else ''
+ one_catalog['proxy_prefix'] = multicould_namespace + "/%s" % vimid + "/" + item["type"]
+
+ endpoint_url = multicould_namespace + "/%s" % vimid + "/" + item["type"]
+
+ if real_suffix:
+ endpoint_url += "/" + real_suffix
+
+ if item["type"] == "identity":
+ endpoint_url = multicould_namespace + "/%s/identity/v3" % vimid
+
+# endpoint["url"] = re.sub(r"^http([s]*)://([0-9.]+):([0-9]+)",
+# multicould_namespace + "/%s/" % vimid + item["type"],
+# endpoint["url"])
+
+
+ endpoint["url"] = endpoint_url
+ item['endpoints'].append( endpoint )
+
+ return catalog, metadata_catalog
+ else:
+ return None
+ pass
+
+
+
+
+class Tokens(APIView):
+ service = {'service_type': 'identity',
+ 'interface': 'public'}
+
+ def __init__(self):
+ self.proxy_prefix = MULTICLOUD_PREFIX
+
+ def post(self, request, vimid=""):
+ logger.debug("identityV3--post::> %s" % request.data)
+ sess = None
+ resp = None
+ resp_body = None
+ try:
+ # prepare request resource to vim instance
+ vim = VimDriverUtils.get_vim_info(vimid)
+ sess = VimDriverUtils.get_session(vim)
+
+ tmp_auth_state = VimDriverUtils.get_auth_state(vim, sess)
+ tmp_auth_info = json.loads(tmp_auth_state)
+ tmp_auth_token = tmp_auth_info['auth_token']
+ tmp_auth_data = tmp_auth_info['body']
+
+ #store the auth_state, redis/memcached
+ #set expiring in 1 hour
+
+ #update the catalog
+ tmp_auth_data['token']['catalog'], tmp_metadata_catalog = update_catalog(vimid, tmp_auth_data['token']['catalog'], self.proxy_prefix)
+ VimDriverUtils.update_token_cache(vim, sess, tmp_auth_token, tmp_auth_state, json.dumps(tmp_metadata_catalog))
+
+ resp = Response(headers={'X-Subject-Token': tmp_auth_token}, data=tmp_auth_data, status=status.HTTP_201_CREATED)
+ return resp
+ except VimDriverNewtonException as e:
+
+ return Response(data={'error': e.content}, status=e.status_code)
+ except HttpError as e:
+ logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json()))
+ return Response(data=e.response.json(), status=e.http_status)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+ pass
+
+
+class Catalog(APIView):
+
+ service = {'service_type': 'identity',
+ 'interface': 'public'}
+
+ def __init__(self):
+ self.proxy_prefix = MULTICLOUD_PREFIX
+
+ def get(self, request, vimid=""):
+ logger.debug("Catalog--get::data> %s" % request.data)
+# logger.debug("Catalog--get::META> %s" % request.META)
+ try:
+ # prepare request resource to vim instance
+ #get token:
+ tmp_auth_token = request.META.get('HTTP_X_AUTH_TOKEN', None)
+ if not tmp_auth_token:
+ return Response(data={'error': "No X-Auth-Token found in headers"}, status=status.HTTP_401_UNAUTHORIZED)
+
+ vim = VimDriverUtils.get_vim_info(vimid)
+ #fetch the auth_state out of cache
+ tmp_auth_state, metadata_catalog = VimDriverUtils.get_token_cache(vim, tmp_auth_token)
+ if not tmp_auth_state:
+ return Response(data={'error': "Expired X-Auth-Token found in headers"}, status=status.HTTP_401_UNAUTHORIZED)
+
+ sess = VimDriverUtils.get_session(vim, auth_state=tmp_auth_state)
+ req_resource = "/auth/catalog"
+
+ resp = sess.get(req_resource, endpoint_filter=self.service)
+ #update token cache in case the token was required during the requests
+ tmp_auth_token = VimDriverUtils.update_token_cache(vim, sess, tmp_auth_token, tmp_auth_state)
+
+ content = resp.json()
+ tmp_auth_catalog = content['catalog']
+ update_catalog(vimid, tmp_auth_catalog, self.proxy_prefix)
+
+ return Response(headers={'X-Subject-Token':tmp_auth_token}, data={'catalog': tmp_auth_catalog}, status=resp.status_code)
+ except VimDriverNewtonException as e:
+ return Response(data={'error': e.content}, status=e.status_code)
+ except HttpError as e:
+ logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json()))
+ return Response(data=e.response.json(), status=e.http_status)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+ pass
diff --git a/newton/newton/proxy/views/services.py b/newton/newton/proxy/views/services.py
new file mode 100644
index 00000000..d3069111
--- /dev/null
+++ b/newton/newton/proxy/views/services.py
@@ -0,0 +1,502 @@
+# Copyright (c) 2017 Wind River Systems, 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.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import logging
+import json
+import traceback
+
+import re
+from django.core.cache import cache
+
+from keystoneauth1 import access
+from keystoneauth1.access import service_catalog
+from keystoneauth1.exceptions import HttpError
+from rest_framework import status
+from rest_framework.response import Response
+from rest_framework.views import APIView
+
+from newton.pub.exceptions import VimDriverNewtonException
+from newton.requests.views.util import VimDriverUtils
+from newton.pub.msapi import extsys
+
+logger = logging.getLogger(__name__)
+
+DEBUG=True
+
+class Services(APIView):
+
+ def head(self, request, vimid="", servicetype="", requri=""):
+ logger.debug("Services--head::data> %s" % request.data)
+ logger.debug("Services--head::vimid, servicetype, requri> %s,%s,%s"
+ % (vimid, servicetype, requri))
+
+ try:
+ # prepare request resource to vim instance
+ #get token:
+ tmp_auth_token = request.META.get('HTTP_X_AUTH_TOKEN', None)
+ if not tmp_auth_token:
+ return Response(data={'error': "No X-Auth-Token found in headers"}, status=status.HTTP_401_UNAUTHORIZED)
+
+ vim = VimDriverUtils.get_vim_info(vimid)
+ #fetch the auth_state out of cache
+ tmp_auth_state, metadata_catalog = VimDriverUtils.get_token_cache(vim,tmp_auth_token)
+ if not tmp_auth_state:
+ return Response(data={'error': "Expired X-Auth-Token found in headers"}, status=status.HTTP_401_UNAUTHORIZED)
+
+
+ sess = VimDriverUtils.get_session(vim, tenantid=None, auth_state=tmp_auth_state)
+ req_resource = ''
+ if requri and requri != '':
+ req_resource = "/" if re.match(r'//', requri) else ''+ requri
+
+ cloud_owner, regionid = extsys.decode_vim_id(vimid)
+ interface = 'public'
+ service = {'service_type': servicetype,
+ 'interface': interface,
+ 'region_id': regionid}
+
+ resp = sess.head(req_resource, endpoint_filter=service)
+ #update token cache in case the token was required during the requests
+ tmp_auth_token = VimDriverUtils.update_token_cache(vim, sess, tmp_auth_token, tmp_auth_state)
+ content = resp.json()
+ return Response(headers={'X-Subject-Token': tmp_auth_token}, data=content, status=resp.status_code)
+ #return resp
+ except VimDriverNewtonException as e:
+ return Response(data={'error': e.content}, status=e.status_code)
+ except HttpError as e:
+ logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json()))
+ return Response(data=e.response.json(), status=e.http_status)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ def get(self, request, vimid="", servicetype="", requri=""):
+ logger.debug("Services--get::data> %s" % request.data)
+ logger.debug("Services--get::vimid, servicetype, requri> %s,%s,%s"
+ % (vimid, servicetype, requri))
+ try:
+ # prepare request resource to vim instance
+ #get token:
+ tmp_auth_token = request.META.get('HTTP_X_AUTH_TOKEN', None)
+ if not tmp_auth_token:
+ return Response(data={'error': "No X-Auth-Token found in headers"}, status=status.HTTP_401_UNAUTHORIZED)
+
+ vim = VimDriverUtils.get_vim_info(vimid)
+ # fetch the auth_state out of cache
+ tmp_auth_state, metadata_catalog = VimDriverUtils.get_token_cache(vim, tmp_auth_token)
+ if not tmp_auth_state:
+ return Response(data={'error': "Expired X-Auth-Token found in headers"}, status=status.HTTP_401_UNAUTHORIZED)
+
+ real_prefix = None
+ proxy_prefix = None
+ suffix = None
+ if servicetype and metadata_catalog:
+# logger.error("metadata_catalog:%s" % metadata_catalog)
+ metadata_catalog = json.loads(metadata_catalog)
+ service_metadata = metadata_catalog.get(servicetype, None)
+ if service_metadata:
+ real_prefix = service_metadata['prefix']
+ proxy_prefix = service_metadata['proxy_prefix']
+ suffix = service_metadata['suffix']
+
+ if not real_prefix or not proxy_prefix:
+ raise VimDriverNewtonException(message="internal state error",
+ content="invalid cached metadata",
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ if requri == suffix:
+ requri = None
+
+ if suffix and requri:
+ #remove the suffix from the requri to avoid duplicated suffix in real request uri later
+ tmp_pattern = re.compile(suffix)
+ requri = tmp_pattern.sub('', requri)
+
+ sess = VimDriverUtils.get_session(vim, tenantid=None, auth_state=tmp_auth_state)
+ req_resource = ''
+ if requri and requri != '':
+ req_resource = "/" if re.match(r'//', requri) else ''+ requri
+
+ cloud_owner, regionid = extsys.decode_vim_id(vimid)
+ interface = 'public'
+ service = {'service_type': servicetype,
+ 'interface': interface,
+ 'region_id': regionid}
+
+ resp = sess.get(req_resource, endpoint_filter=service)
+ #update token cache in case the token was required during the requests
+ tmp_auth_token = VimDriverUtils.update_token_cache(vim, sess, tmp_auth_token, tmp_auth_state)
+ content = resp.json()
+
+ #filter the resp content and replace all endpoint prefix
+ tmp_content = json.dumps(content)
+ tmp_pattern = re.compile(real_prefix)
+ tmp_content = tmp_pattern.sub(proxy_prefix, tmp_content)
+ content = json.loads(tmp_content)
+
+ return Response(headers={'X-Subject-Token': tmp_auth_token}, data=content, status=resp.status_code)
+ #return resp
+ except VimDriverNewtonException as e:
+ return Response(data={'error': e.content}, status=e.status_code)
+ except HttpError as e:
+ logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json()))
+ return Response(data=e.response.json(), status=e.http_status)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ def post(self, request, vimid="", servicetype="", requri=""):
+ logger.debug("Services--post::data> %s" % request.data)
+ logger.debug("Services--post::vimid, servicetype, requri> %s,%s,%s"
+ % (vimid, servicetype, requri))
+ try:
+ # prepare request resource to vim instance
+ # get token:
+ tmp_auth_token = request.META.get('HTTP_X_AUTH_TOKEN', None)
+ if not tmp_auth_token:
+ return Response(data={'error': "No X-Auth-Token found in headers"}, status=status.HTTP_401_UNAUTHORIZED)
+
+ vim = VimDriverUtils.get_vim_info(vimid)
+ # fetch the auth_state out of cache
+ tmp_auth_state, metadata_catalog = VimDriverUtils.get_token_cache(vim, tmp_auth_token)
+ if not tmp_auth_state:
+ return Response(data={'error': "Expired X-Auth-Token found in headers"},
+ status=status.HTTP_401_UNAUTHORIZED)
+
+ real_prefix = None
+ proxy_prefix = None
+ suffix = None
+ if servicetype and metadata_catalog:
+# logger.error("metadata_catalog:%s" % metadata_catalog)
+ metadata_catalog = json.loads(metadata_catalog)
+ service_metadata = metadata_catalog.get(servicetype, None)
+ if service_metadata:
+ real_prefix = service_metadata['prefix']
+ proxy_prefix = service_metadata['proxy_prefix']
+ suffix = service_metadata['suffix']
+
+ if not real_prefix or not proxy_prefix:
+ raise VimDriverNewtonException(message="internal state error",
+ content="invalid cached metadata",
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ if requri == suffix:
+ requri = None
+
+ if suffix and requri:
+ #remove the suffix from the requri to avoid duplicated suffix in real request uri later
+ tmp_pattern = re.compile(suffix)
+ requri = tmp_pattern.sub('', requri)
+
+ sess = VimDriverUtils.get_session(vim, tenantid=None, auth_state=tmp_auth_state)
+ req_resource = ""
+ if requri and requri != "":
+ req_resource = "/" if re.match(r'//', requri) else ''+ requri
+
+ cloud_owner, regionid = extsys.decode_vim_id(vimid)
+ interface = 'public'
+ service = {'service_type': servicetype,
+ 'interface': interface,
+ 'region_id': regionid}
+
+ resp = sess.post(req_resource, data=json.JSONEncoder().encode(request.data),endpoint_filter=service)
+ # update token cache in case the token was required during the requests
+ tmp_auth_token = VimDriverUtils.update_token_cache(vim, sess, tmp_auth_token, tmp_auth_state)
+ content = resp.json()
+
+ #filter the resp content and replace all endpoint prefix
+ tmp_content = json.dumps(content)
+ tmp_pattern = re.compile(real_prefix)
+ tmp_content = tmp_pattern.sub(proxy_prefix, tmp_content)
+ content = json.loads(tmp_content)
+
+ return Response(headers={'X-Subject-Token': tmp_auth_token}, data=content, status=resp.status_code)
+
+ except VimDriverNewtonException as e:
+ return Response(data={'error': e.content}, status=e.status_code)
+ except HttpError as e:
+ logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json()))
+ return Response(data=e.response.json(), status=e.http_status)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ def put(self, request, vimid="", servicetype="", requri=""):
+ logger.debug("Services--put::data> %s" % request.data)
+ logger.debug("Services--put::vimid, servicetype, requri> %s,%s,%s"
+ % (vimid, servicetype, requri))
+ try:
+ # prepare request resource to vim instance
+ # get token:
+ tmp_auth_token = request.META.get('HTTP_X_AUTH_TOKEN', None)
+ if not tmp_auth_token:
+ return Response(data={'error': "No X-Auth-Token found in headers"}, status=status.HTTP_401_UNAUTHORIZED)
+
+ vim = VimDriverUtils.get_vim_info(vimid)
+ # fetch the auth_state out of cache
+ tmp_auth_state, metadata_catalog = VimDriverUtils.get_token_cache(vim, tmp_auth_token)
+ if not tmp_auth_state:
+ return Response(data={'error': "Expired X-Auth-Token found in headers"},
+ status=status.HTTP_401_UNAUTHORIZED)
+
+ real_prefix = None
+ proxy_prefix = None
+ suffix = None
+ if servicetype and metadata_catalog:
+# logger.error("metadata_catalog:%s" % metadata_catalog)
+ metadata_catalog = json.loads(metadata_catalog)
+ service_metadata = metadata_catalog.get(servicetype, None)
+ if service_metadata:
+ real_prefix = service_metadata['prefix']
+ proxy_prefix = service_metadata['proxy_prefix']
+ suffix = service_metadata['suffix']
+
+ if not real_prefix or not proxy_prefix:
+ raise VimDriverNewtonException(message="internal state error",
+ content="invalid cached metadata",
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ if requri == suffix:
+ requri = None
+
+ if suffix and requri:
+ #remove the suffix from the requri to avoid duplicated suffix in real request uri later
+ tmp_pattern = re.compile(suffix)
+ requri = tmp_pattern.sub('', requri)
+
+ sess = VimDriverUtils.get_session(vim, tenantid=None, auth_state=tmp_auth_state)
+ req_resource = ""
+ if requri and requri != "":
+ req_resource = "/" + requri
+
+ cloud_owner, regionid = extsys.decode_vim_id(vimid)
+ interface = 'public'
+ service = {'service_type': servicetype,
+ 'interface': interface,
+ 'region_id': regionid}
+
+ resp = sess.put(req_resource, data=json.JSONEncoder().encode(request.data),endpoint_filter=service)
+ # update token cache in case the token was required during the requests
+ tmp_auth_token = VimDriverUtils.update_token_cache(vim, sess, tmp_auth_token, tmp_auth_state)
+ content = resp.json()
+
+ #filter the resp content and replace all endpoint prefix
+ tmp_content = json.dumps(content)
+ tmp_pattern = re.compile(real_prefix)
+ tmp_content = tmp_pattern.sub(proxy_prefix, tmp_content)
+ content = json.loads(tmp_content)
+
+ return Response(headers={'X-Subject-Token': tmp_auth_token}, data=content, status=resp.status_code)
+
+ except VimDriverNewtonException as e:
+ return Response(data={'error': e.content}, status=e.status_code)
+ except HttpError as e:
+ logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json()))
+ return Response(data=e.response.json(), status=e.http_status)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+ def patch(self, request, vimid="", servicetype="", requri=""):
+ logger.debug("Services--patch::data> %s" % request.data)
+ logger.debug("Services--patch::vimid, servicetype, requri> %s,%s,%s"
+ % (vimid, servicetype, requri))
+ try:
+ # prepare request resource to vim instance
+ # get token:
+ tmp_auth_token = request.META.get('HTTP_X_AUTH_TOKEN', None)
+ if not tmp_auth_token:
+ return Response(data={'error': "No X-Auth-Token found in headers"}, status=status.HTTP_401_UNAUTHORIZED)
+
+ vim = VimDriverUtils.get_vim_info(vimid)
+ # fetch the auth_state out of cache
+ tmp_auth_state, metadata_catalog = VimDriverUtils.get_token_cache(vim, tmp_auth_token)
+ if not tmp_auth_state:
+ return Response(data={'error': "Expired X-Auth-Token found in headers"},
+ status=status.HTTP_401_UNAUTHORIZED)
+
+ real_prefix = None
+ proxy_prefix = None
+ suffix = None
+ if servicetype and metadata_catalog:
+# logger.error("metadata_catalog:%s" % metadata_catalog)
+ metadata_catalog = json.loads(metadata_catalog)
+ service_metadata = metadata_catalog.get(servicetype, None)
+ if service_metadata:
+ real_prefix = service_metadata['prefix']
+ proxy_prefix = service_metadata['proxy_prefix']
+ suffix = service_metadata['suffix']
+
+ if not real_prefix or not proxy_prefix:
+ raise VimDriverNewtonException(message="internal state error",
+ content="invalid cached metadata",
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ if requri == suffix:
+ requri = None
+
+ if suffix and requri:
+ #remove the suffix from the requri to avoid duplicated suffix in real request uri later
+ tmp_pattern = re.compile(suffix)
+ requri = tmp_pattern.sub('', requri)
+
+ sess = VimDriverUtils.get_session(vim, tenantid=None, auth_state=tmp_auth_state)
+ req_resource = ""
+ if requri and requri != "":
+ req_resource = "/" if re.match(r'//', requri) else ''+ requri
+
+ cloud_owner, regionid = extsys.decode_vim_id(vimid)
+ interface = 'public'
+ service = {'service_type': servicetype,
+ 'interface': interface,
+ 'region_id': regionid}
+
+ resp = sess.patch(req_resource, data=json.JSONEncoder().encode(request.data),endpoint_filter=service)
+ # update token cache in case the token was required during the requests
+ tmp_auth_token = VimDriverUtils.update_token_cache(vim, sess, tmp_auth_token, tmp_auth_state)
+ content = resp.json()
+
+ #filter the resp content and replace all endpoint prefix
+ tmp_content = json.dumps(content)
+ tmp_pattern = re.compile(real_prefix)
+ tmp_content = tmp_pattern.sub(proxy_prefix, tmp_content)
+ content = json.loads(tmp_content)
+
+ return Response(headers={'X-Subject-Token': tmp_auth_token}, data=content, status=resp.status_code)
+
+ except VimDriverNewtonException as e:
+ return Response(data={'error': e.content}, status=e.status_code)
+ except HttpError as e:
+ logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json()))
+ return Response(data=e.response.json(), status=e.http_status)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ def delete(self, request, vimid="", servicetype="", requri=""):
+ logger.debug("Services--delete::data> %s" % request.data)
+ logger.debug("Services--delete::vimid, servicetype, requri> %s,%s,%s"
+ % (vimid, servicetype, requri))
+ try:
+ # prepare request resource to vim instance
+ # get token:
+ tmp_auth_token = request.META.get('HTTP_X_AUTH_TOKEN', None)
+ if not tmp_auth_token:
+ return Response(data={'error': "No X-Auth-Token found in headers"}, status=status.HTTP_401_UNAUTHORIZED)
+
+ vim = VimDriverUtils.get_vim_info(vimid)
+ # fetch the auth_state out of cache
+ tmp_auth_state, metadata_catalog = VimDriverUtils.get_token_cache(vim, tmp_auth_token)
+ if not tmp_auth_state:
+ return Response(data={'error': "Expired X-Auth-Token found in headers"},
+ status=status.HTTP_401_UNAUTHORIZED)
+
+ real_prefix = None
+ proxy_prefix = None
+ suffix = None
+ if servicetype and metadata_catalog:
+# logger.error("metadata_catalog:%s" % metadata_catalog)
+ metadata_catalog = json.loads(metadata_catalog)
+ service_metadata = metadata_catalog.get(servicetype, None)
+ if service_metadata:
+ real_prefix = service_metadata['prefix']
+ proxy_prefix = service_metadata['proxy_prefix']
+ suffix = service_metadata['suffix']
+
+ if not real_prefix or not proxy_prefix:
+ raise VimDriverNewtonException(message="internal state error",
+ content="invalid cached metadata",
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ if requri == suffix:
+ requri = None
+
+ if suffix and requri:
+ #remove the suffix from the requri to avoid duplicated suffix in real request uri later
+ tmp_pattern = re.compile(suffix)
+ requri = tmp_pattern.sub('', requri)
+
+ sess = VimDriverUtils.get_session(vim, tenantid=None, auth_state=tmp_auth_state)
+ req_resource = ""
+ if requri and requri != "":
+ req_resource = "/" if re.match(r'//', requri) else ''+ requri
+
+ cloud_owner, regionid = extsys.decode_vim_id(vimid)
+ interface = 'public'
+ service = {'service_type': servicetype,
+ 'interface': interface,
+ 'region_id': regionid}
+
+ resp = sess.delete(req_resource, endpoint_filter=service)
+ # update token cache in case the token was required during the requests
+ tmp_auth_token = VimDriverUtils.update_token_cache(vim, sess, tmp_auth_token, tmp_auth_state)
+ content = resp.json()
+
+ #filter the resp content and replace all endpoint prefix
+ tmp_content = json.dumps(content)
+ tmp_pattern = re.compile(real_prefix)
+ tmp_content = tmp_pattern.sub(proxy_prefix, tmp_content)
+ content = json.loads(tmp_content)
+
+ return Response(headers={'X-Subject-Token': tmp_auth_token}, data=content, status=resp.status_code)
+
+ except VimDriverNewtonException as e:
+ return Response(data={'error': e.content}, status=e.status_code)
+ except HttpError as e:
+ logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json()))
+ return Response(data=e.response.json(), status=e.http_status)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+class GetTenants(Services):
+ '''
+ Backward compatible API for /v2.0/tenants
+ '''
+ def get(self, request, vimid="", servicetype="identity", requri='projects'):
+ logger.debug("GetTenants--get::data> %s" % request.data)
+ logger.debug("GetTenants--get::vimid, servicetype, requri> %s,%s,%s"
+ % (vimid, servicetype, requri))
+
+ tmp_auth_token = request.META.get('HTTP_X_AUTH_TOKEN', None)
+
+ resp = super(GetTenants,self).get(request, vimid, servicetype, requri)
+ if resp.status_code == status.HTTP_200_OK:
+ content = resp.data
+ return Response(headers={'X-Subject-Token': tmp_auth_token}, data={'tenants': content['projects'],'tenants_links':[]},
+ status=resp.status_code)
+ else:
+ return resp
+
+ def head(self, request, vimid="", servicetype="", requri=""):
+ return Response(data={'error': 'unsupported operation'}, status=status.HTTP_400_BAD_REQUEST)
+
+ def post(self, request, vimid="", servicetype="", requri=""):
+ return Response(data={'error': 'unsupported operation'}, status=status.HTTP_400_BAD_REQUEST)
+
+ def put(self, request, vimid="", servicetype="", requri=""):
+ return Response(data={'error': 'unsupported operation'}, status=status.HTTP_400_BAD_REQUEST)
+
+ def patch(self, request, vimid="", servicetype="", requri=""):
+ return Response(data={'error': 'unsupported operation'}, status=status.HTTP_400_BAD_REQUEST)
+
+ def delete(self, request, vimid="", servicetype="", requri=""):
+ return Response(data={'error': 'unsupported operation'}, status=status.HTTP_400_BAD_REQUEST)
diff --git a/newton/newton/pub/config/config.py b/newton/newton/pub/config/config.py
index e27682bd..fc7775b5 100644
--- a/newton/newton/pub/config/config.py
+++ b/newton/newton/pub/config/config.py
@@ -13,35 +13,7 @@ import os
# [MSB]
MSB_SERVICE_IP = '127.0.0.1'
-MSB_SERVICE_PORT = '10080'
+MSB_SERVICE_PORT = '80'
# [IMAGE LOCAL PATH]
ROOT_PATH = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-# [REDIS]
-REDIS_HOST = '127.0.0.1'
-REDIS_PORT = '6379'
-REDIS_PASSWD = ''
-
-# [mysql]
-DB_IP = "127.0.0.1"
-DB_PORT = 3306
-DB_NAME = "multivimnewton"
-DB_USER = "root"
-DB_PASSWD = "password"
-
-# [register]
-REG_TO_MSB_WHEN_START = True
-REG_TO_MSB_REG_URL = "/openoapi/microservices/v1/services"
-REG_TO_MSB_REG_PARAM = {
- "serviceName": "multivim-newton",
- "version": "v1",
- "url": "/openoapi/multivim-newton/v1",
- "protocol": "REST",
- "visualRange": "1",
- "nodes": [{
- "ip": "127.0.0.1",
- "port": "9003",
- "ttl": 0
- }]
-}
diff --git a/newton/newton/pub/msapi/extsys.py b/newton/newton/pub/msapi/extsys.py
index daab5037..449ad5b5 100644
--- a/newton/newton/pub/msapi/extsys.py
+++ b/newton/newton/pub/msapi/extsys.py
@@ -11,6 +11,7 @@
import json
import logging
+import re
from rest_framework import status
from newton.pub.exceptions import VimDriverNewtonException
@@ -18,22 +19,67 @@ from newton.pub.utils.restcall import req_by_msb
logger = logging.getLogger(__name__)
+def get_vim_by_id(vim_id):
-def get_vims():
- retcode, content, status_code = \
- req_by_msb("/openoapi/extsys/v1/vims", "GET")
- if retcode != 0:
- logger.error("Status code is %s, detail is %s.", status_code, content)
- raise VimDriverNewtonException("Failed to query VIMs from extsys.")
- return json.JSONDecoder().decode(content)
+ cloud_owner,cloud_region_id = decode_vim_id(vim_id)
+ if cloud_owner and cloud_region_id:
+ retcode, content, status_code = \
+ req_by_msb("/api/aai-cloudInfrastructure/v1/cloud-infrastructure/cloud-regions/cloud-region/%s/%s"
+ % (cloud_owner,cloud_region_id), "GET")
+ if retcode != 0:
+ logger.error("Status code is %s, detail is %s.", status_code, content)
+ raise VimDriverNewtonException(
+ "Failed to query VIM with id (%s:%s,%s) from extsys." % (vim_id,cloud_owner,cloud_region_id),
+ status_code, content)
+ tmp_viminfo = json.JSONDecoder().decode(content)
+ #convert vim information
+ #tbd
+
+ if tmp_viminfo:
+ viminfo = {}
+ viminfo['vimId'] = vim_id
+ viminfo['cloud_owner'] = cloud_owner
+ viminfo['cloud_region_id'] = cloud_region_id
+ viminfo['type'] = tmp_viminfo['cloud-type']
+ viminfo['name'] = tmp_viminfo['complex-name']
+ viminfo['version'] = tmp_viminfo['cloud-region-version']
+ viminfo['cloud_extra_info'] = tmp_viminfo['cloud-extra-info']
+ viminfo['cloud_epa_caps'] = tmp_viminfo['cloud-epa-caps']
+
+ tmp_authinfo = tmp_viminfo['auth-info-items'][0]
+ if tmp_authinfo:
+ viminfo['userName'] = tmp_authinfo['username']
+ viminfo['password'] = tmp_authinfo['password']
+ viminfo['domain'] = tmp_authinfo['cloud-domain']
+ viminfo['url'] = tmp_authinfo['auth-url']
+ viminfo['tenant'] = tmp_authinfo['defaultTenant']['name'] if not tmp_authinfo['defaultTenant'] else None
+ viminfo['cacert'] = tmp_authinfo['ssl-cacert']
+ viminfo['insecure'] = tmp_authinfo['ssl-insecure']
+
+ return viminfo
+ else:
+ return None
+ else:
+ return None
+
+def delete_vim_by_id(vim_id):
+ cloud_owner, cloud_region_id = decode_vim_id(vim_id)
+ if cloud_owner and cloud_region_id:
+ retcode, content, status_code = \
+ req_by_msb("/api/aai-cloudInfrastructure/v1/cloud-infrastructure/cloud-regions/cloud-region/%s/%s"
+ % ( cloud_owner, cloud_region_id), "DELETE")
+ if retcode != 0:
+ logger.error("Status code is %s, detail is %s.", status_code, content)
+ raise VimDriverNewtonException(
+ "Failed to delete VIM in AAI with id (%s:%s,%s) from extsys." % (vim_id,cloud_owner,cloud_region_id),
+ status_code, content)
+ return 0
+ # return non zero if failed to decode cloud owner and region id
+ return 1
+
+def decode_vim_id(vim_id):
+ m = re.search(r'^([0-9a-zA-Z-]+)_([0-9a-zA-Z_-]+)$', vim_id)
+ cloud_owner, cloud_region_id = m.group(1), m.group(2)
+ return cloud_owner, cloud_region_id
-def get_vim_by_id(vim_id):
- retcode, content, status_code = \
- req_by_msb("/openoapi/extsys/v1/vims/%s" % vim_id, "GET")
- if retcode != 0:
- logger.error("Status code is %s, detail is %s.", status_code, content)
- raise VimDriverNewtonException(
- "Failed to query VIM with id (%s) from extsys." % vim_id,
- status.HTTP_404_NOT_FOUND, content)
- return json.JSONDecoder().decode(content)
diff --git a/newton/newton/registration/__init__.py b/newton/newton/registration/__init__.py
new file mode 100644
index 00000000..802f3fba
--- /dev/null
+++ b/newton/newton/registration/__init__.py
@@ -0,0 +1,10 @@
+# Copyright (c) 2017 Wind River Systems, 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.
diff --git a/newton/newton/registration/views/__init__.py b/newton/newton/registration/views/__init__.py
new file mode 100644
index 00000000..802f3fba
--- /dev/null
+++ b/newton/newton/registration/views/__init__.py
@@ -0,0 +1,10 @@
+# Copyright (c) 2017 Wind River Systems, 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.
diff --git a/newton/newton/registration/views/registration.py b/newton/newton/registration/views/registration.py
new file mode 100644
index 00000000..9f2f31be
--- /dev/null
+++ b/newton/newton/registration/views/registration.py
@@ -0,0 +1,93 @@
+# Copyright (c) 2017 Wind River Systems, 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.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import logging
+import json
+import traceback
+
+from django.core.cache import cache
+
+from keystoneauth1 import access
+from keystoneauth1.access import service_catalog
+from keystoneauth1.exceptions import HttpError
+from rest_framework import status
+from rest_framework.response import Response
+from rest_framework.views import APIView
+
+from newton.pub.exceptions import VimDriverNewtonException
+from newton.requests.views.util import VimDriverUtils
+
+logger = logging.getLogger(__name__)
+
+DEBUG=True
+
+class Registry(APIView):
+
+ def post(self, request, vimid=""):
+ logger.debug("Registration--post::data> %s" % request.data)
+ logger.debug("Registration--post::vimid > %s" % vimid)
+
+ try:
+ # prepare request resource to vim instance
+ # get token:
+ vim = VimDriverUtils.get_vim_info(vimid)
+ #set the default tenant since there is no tenant info in the VIM yet
+ sess = VimDriverUtils.get_session(vim, tenantname=request.data['defaultTenant'])
+
+ #step 1. discover all projects and populate into AAI
+ req_resource = "/projects"
+ service = {'service_type': "identity",
+ 'interface': 'public',
+ 'region_id': vim['cloud_region_id']}
+
+ resp = sess.get(req_resource, endpoint_filter=service)
+ content = resp.json()
+ #iterate all projects and populate them into AAI
+ # TBD
+
+ # discover all flavors
+ # discover all images
+ # discover all az
+ # discover all vg
+ # discover all snapshots
+ # discover all server groups
+ # discover all pservers
+ # discover all epa resources, e.g. sriov pf and vf, etc.
+
+ return Response(status=status.HTTP_202_ACCEPTED)
+
+ except VimDriverNewtonException as e:
+ return Response(data={'error': e.content}, status=e.status_code)
+ except HttpError as e:
+ logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json()))
+ return Response(data=e.response.json(), status=e.http_status)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ def delete(self, request, vimid=""):
+ logger.debug("Registration--delete::data> %s" % request.data)
+ logger.debug("Registration--delete::vimid > %s"% vimid)
+ try:
+ ret_code = VimDriverUtils.delete_vim_info(vimid)
+ return Response(status=status.HTTP_202_ACCEPTED)
+ except VimDriverNewtonException as e:
+ return Response(data={'error': e.content}, status=e.status_code)
+ except HttpError as e:
+ logger.error("HttpError: status:%s, response:%s" % (e.http_status, e.response.json()))
+ return Response(data=e.response.json(), status=e.http_status)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
diff --git a/newton/newton/requests/views/util.py b/newton/newton/requests/views/util.py
index 089a0e1f..eab4c370 100644
--- a/newton/newton/requests/views/util.py
+++ b/newton/newton/requests/views/util.py
@@ -13,11 +13,17 @@
# limitations under the License.
import logging
+import datetime
+
+from django.core.cache import cache
+
+from keystoneauth1 import _utils as utils
from keystoneauth1.identity import v2 as keystone_v2
from keystoneauth1.identity import v3 as keystone_v3
from keystoneauth1 import session
-from newton.pub.msapi.extsys import get_vim_by_id
+#from newton.pub.msapi.extsys import get_vim_by_id
+from newton.pub.msapi import extsys
logger = logging.getLogger(__name__)
@@ -27,10 +33,14 @@ class VimDriverUtils(object):
def get_vim_info(vimid):
# get vim info from local cache firstly
# if cache miss, get it from ESR service
- vim = get_vim_by_id(vimid)
+ vim = extsys.get_vim_by_id(vimid)
return vim
@staticmethod
+ def delete_vim_info(vimid):
+ return extsys.delete_vim_by_id(vimid)
+
+ @staticmethod
def get_query_part(request):
query = ""
full_path = request.get_full_path()
@@ -39,25 +49,117 @@ class VimDriverUtils(object):
return query
@staticmethod
- def get_session(vim, tenantid=None):
+ def get_session(vim, tenantid=None, tenantname=None, auth_state=None):
"""
- get vim info from ESR and create auth plugin and session object
+ get session object and optionally preload auth_state
"""
auth = None
- if '/v2' in vim["url"]:
- auth = keystone_v2.Password(auth_url=vim["url"],
- username=vim["userName"],
- password=vim["password"],
- tenant_name=vim["tenant"])
- elif '/v3' in vim["url"]:
- auth = keystone_v3.Password(auth_url=vim["url"],
- username=vim["userName"],
- password=vim["password"],
- project_name=vim["tenant"],
- user_domain_id='default',
- project_domain_id='default')
+
+ #tenantid takes precedence over tenantname
+ if not tenantid:
+ #input tenant name takes precedence over the default one from AAI data store
+ tenant_name = tenantname if tenantname else vim['tenant']
+
+ if tenantid:
+ if '/v2' in vim["url"]:
+ auth = keystone_v2.Password(auth_url=vim["url"],
+ username=vim["userName"],
+ password=vim["password"],
+ tenant_id=tenantid)
+ elif '/v3' in vim["url"]:
+ auth = keystone_v3.Password(auth_url=vim["url"],
+ username=vim["userName"],
+ password=vim["password"],
+ project_id=tenantid)
+ elif tenant_name:
+ if '/v2' in vim["url"]:
+ auth = keystone_v2.Password(auth_url=vim["url"],
+ username=vim["userName"],
+ password=vim["password"],
+ tenant_name=tenant_name)
+ elif '/v3' in vim["url"]:
+ auth = keystone_v3.Password(auth_url=vim["url"],
+ username=vim["userName"],
+ password=vim["password"],
+ project_name=tenant_name,
+ user_domain_name=vim["domain"],
+ project_domain_name=vim["domain"])
+
+ else:
+ #something wrong
+ return None
+ pass
+
+ #preload auth_state which was acquired in last requests
+ if auth_state:
+ auth.set_auth_state(auth_state)
+
return session.Session(auth=auth)
+
+ @staticmethod
+ def get_auth_state(vim, session):
+ auth = session._auth_required(None, 'fetch a token')
+ if not auth:
+ return None
+
+ #trigger the authenticate request
+ session.get_auth_headers(auth)
+
+# norm_expires = utils.normalize_time(auth.expires)
+
+ #return a string dump of json object with token and resp_data of authentication request
+ return auth.get_auth_state()
+# return auth.get_auth_ref(session)
+
+ @staticmethod
+ def get_token_cache(vim, token):
+ '''
+ get auth_state and metadata fromm cache
+ :param vim:
+ :param token:
+ :return:
+ '''
+ metadata_key = "meta_%s" % token
+ return cache.get(token), cache.get(metadata_key)
+
+
+ @staticmethod
+ def update_token_cache(vim, session, old_token, auth_state, metadata=None):
+ '''
+ cache the auth_state as well as metadata_catalog
+ :param vim:
+ :param session:
+ :param old_token:
+ :param auth_state:
+ :param matadata:
+ :return:
+ '''
+
+ metadata_key = "meta_%s" % old_token
+
+ if not metadata:
+ metadata = cache.get(metadata_key)
+ if not metadata:
+ #something wrong since metadata is neither inputted, nor cached previously. but ignore temporarily
+ pass
+
+ tmp_auth_token = session.get_token()
+ #check if need to update token:auth_state mapping
+ if tmp_auth_token != old_token:
+ cache.delete(old_token)
+ cache.delete(metadata_key)
+ metadata_key = "meta_%s" % tmp_auth_token
+
+ elif not cache.get(old_token):
+ # store the auth_state, memcached
+ # set expiring in 1 hour
+ cache.set(tmp_auth_token, auth_state, 3600)
+ cache.set(metadata_key, metadata, 3600)
+
+ #return new token
+ return tmp_auth_token
+
@staticmethod
def replace_a_key(dict_obj, keypair, reverse=False):
old_key, new_key = None, None
diff --git a/newton/newton/settings.py b/newton/newton/settings.py
index b0be17e8..682e8eb4 100644
--- a/newton/newton/settings.py
+++ b/newton/newton/settings.py
@@ -66,13 +66,6 @@ REST_FRAMEWORK = {
)
}
-DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.sqlite3',
- 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
- }
-}
-
TIME_ZONE = 'UTC'
# Static files (CSS, JavaScript, Images)
@@ -110,14 +103,16 @@ LOGGING = {
}
}
+CACHES = {
+ 'default': {
+ 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
+ 'LOCATION': '127.0.0.1:11211',
+ }
+}
+
if 'test' in sys.argv:
from newton.pub.config import config
- config.REG_TO_MSB_WHEN_START = False
- DATABASES = {}
- DATABASES['default'] = {
- 'ENGINE': 'django.db.backends.sqlite3',
- 'NAME': ':memory:',
- }
+
REST_FRAMEWORK = {}
import platform
diff --git a/newton/newton/swagger/multivim.flavor.swagger.json b/newton/newton/swagger/multivim.flavor.swagger.json
index 2053e039..e73be9ed 100644
--- a/newton/newton/swagger/multivim.flavor.swagger.json
+++ b/newton/newton/swagger/multivim.flavor.swagger.json
@@ -4,7 +4,7 @@
"version": "1.0.0",
"title": "MultiVIM Service rest API"
},
- "basePath": "/openoapi/multivim/v1/",
+ "basePath": "/api/multicloud-newton/v0/",
"tags": [
{
"name": "MultiVIM services"
diff --git a/newton/newton/swagger/multivim.host.swagger.json b/newton/newton/swagger/multivim.host.swagger.json
index e04b5267..1ea4603e 100644
--- a/newton/newton/swagger/multivim.host.swagger.json
+++ b/newton/newton/swagger/multivim.host.swagger.json
@@ -4,7 +4,7 @@
"version": "1.0.0",
"title": "MultiVIM Service rest API"
},
- "basePath": "/openoapi/multivim/v1/",
+ "basePath": "/api/multicloud-newton/v0/",
"tags": [
{
"name": "MultiVIM services"
diff --git a/newton/newton/swagger/multivim.image.swagger.json b/newton/newton/swagger/multivim.image.swagger.json
index dcbba06b..1ff3741a 100644
--- a/newton/newton/swagger/multivim.image.swagger.json
+++ b/newton/newton/swagger/multivim.image.swagger.json
@@ -4,7 +4,7 @@
"version": "1.0.0",
"title": "MultiVIM Service rest API"
},
- "basePath": "/openoapi/multivim/v1/",
+ "basePath": "/api/multicloud-newton/v0/",
"tags": [
{
"name": "MultiVIM services"
diff --git a/newton/newton/swagger/multivim.limit.swagger.json b/newton/newton/swagger/multivim.limit.swagger.json
index 4665af47..3fea1b72 100644
--- a/newton/newton/swagger/multivim.limit.swagger.json
+++ b/newton/newton/swagger/multivim.limit.swagger.json
@@ -4,7 +4,7 @@
"version": "1.0.0",
"title": "MultiVIM Service rest API"
},
- "basePath": "/openoapi/multivim/v1/",
+ "basePath": "/api/multicloud-newton/v0/",
"tags": [
{
"name": "MultiVIM services"
diff --git a/newton/newton/swagger/multivim.network.swagger.json b/newton/newton/swagger/multivim.network.swagger.json
index fb8524bc..3962e891 100644
--- a/newton/newton/swagger/multivim.network.swagger.json
+++ b/newton/newton/swagger/multivim.network.swagger.json
@@ -4,7 +4,7 @@
"version": "1.0.0",
"title": "MultiVIM Service rest API"
},
- "basePath": "/openoapi/multivim/v1/",
+ "basePath": "/api/multicloud-newton/v0/",
"tags": [
{
"name": "MultiVIM services"
diff --git a/newton/newton/swagger/multivim.server.swagger.json b/newton/newton/swagger/multivim.server.swagger.json
index 14b1d0e9..c309a394 100644
--- a/newton/newton/swagger/multivim.server.swagger.json
+++ b/newton/newton/swagger/multivim.server.swagger.json
@@ -4,7 +4,7 @@
"version": "1.0.0",
"title": "MultiVIM Service rest API"
},
- "basePath": "/openoapi/multivim/v1/",
+ "basePath": "/api/multicloud-newton/v0/",
"tags": [
{
"name": "MultiVIM services"
diff --git a/newton/newton/swagger/multivim.subnet.swagger.json b/newton/newton/swagger/multivim.subnet.swagger.json
index 301c0fc8..ae466d49 100644
--- a/newton/newton/swagger/multivim.subnet.swagger.json
+++ b/newton/newton/swagger/multivim.subnet.swagger.json
@@ -4,7 +4,7 @@
"version": "1.0.0",
"title": "MultiVIM Service rest API"
},
- "basePath": "/openoapi/multivim/v1/",
+ "basePath": "/api/multicloud-newton/v0/",
"tags": [
{
"name": "MultiVIM services"
diff --git a/newton/newton/swagger/multivim.tenant.swagger.json b/newton/newton/swagger/multivim.tenant.swagger.json
index 0f718745..ed0c6c45 100644
--- a/newton/newton/swagger/multivim.tenant.swagger.json
+++ b/newton/newton/swagger/multivim.tenant.swagger.json
@@ -4,7 +4,7 @@
"version": "1.0.0",
"title": "MultiVIM Service rest API"
},
- "basePath": "/openoapi/multivim/v1/",
+ "basePath": "/api/multicloud-newton/v0/",
"tags": [
{
"name": "MultiVIM services"
diff --git a/newton/newton/swagger/multivim.volume.swagger.json b/newton/newton/swagger/multivim.volume.swagger.json
index fda75973..7dd787d1 100644
--- a/newton/newton/swagger/multivim.volume.swagger.json
+++ b/newton/newton/swagger/multivim.volume.swagger.json
@@ -4,7 +4,7 @@
"version": "1.0.0",
"title": "MultiVIM Service rest API"
},
- "basePath": "/openoapi/multivim/v1/",
+ "basePath": "/api/multicloud-newton/v0/",
"tags": [
{
"name": "MultiVIM services"
diff --git a/newton/newton/swagger/multivim.vport.swagger.json b/newton/newton/swagger/multivim.vport.swagger.json
index 5a70dfbc..5b0a04a7 100644
--- a/newton/newton/swagger/multivim.vport.swagger.json
+++ b/newton/newton/swagger/multivim.vport.swagger.json
@@ -4,7 +4,7 @@
"version": "1.0.0",
"title": "MultiVIM Service rest API"
},
- "basePath": "/openoapi/multivim/v1/",
+ "basePath": "/api/multicloud-newton/v0/",
"tags": [
{
"name": "MultiVIM services"
diff --git a/newton/newton/swagger/tests.py b/newton/newton/swagger/tests.py
index 299f3ff9..29efb26b 100644
--- a/newton/newton/swagger/tests.py
+++ b/newton/newton/swagger/tests.py
@@ -23,7 +23,7 @@ class SampleViewTest(unittest.TestCase):
pass
def test_sample(self):
- response = self.client.get("/openoapi/multivim-newton/v1/swagger.json")
+ response = self.client.get("/api/multicloud-newton/v0/swagger.json")
self.assertEqual(status.HTTP_200_OK, response.status_code, response.content)
# resp_data = json.loads(response.content)
# self.assertEqual({"status": "active"}, resp_data)
diff --git a/newton/newton/swagger/urls.py b/newton/newton/swagger/urls.py
index 279a430e..76c0ed46 100644
--- a/newton/newton/swagger/urls.py
+++ b/newton/newton/swagger/urls.py
@@ -16,7 +16,7 @@ from newton.swagger import views
from newton.swagger.views import SwaggerJsonView
urlpatterns = [
- url(r'^openoapi/multivim-newton/v1/swagger.json$', SwaggerJsonView.as_view()),
+ url(r'^api/multicloud-newton/v0/swagger.json$', SwaggerJsonView.as_view()),
]
urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/newton/newton/swagger/views.py b/newton/newton/swagger/views.py
index 2e87bc74..66d42d68 100644
--- a/newton/newton/swagger/views.py
+++ b/newton/newton/swagger/views.py
@@ -83,7 +83,7 @@ class SwaggerJsonView(APIView):
f.close()
json_data["paths"].update(json_data_temp["paths"])
json_data["definitions"].update(json_data_temp["definitions"])
- json_data["basePath"] = "/openoapi/multivim-newton/v1/"
+ json_data["basePath"] = "/api/multicloud-newton/v0/"
json_data["info"]["title"] = "MultiVIM driver of OpenStack Newton Service NBI"
return Response(json_data)
diff --git a/newton/newton/urls.py b/newton/newton/urls.py
index e831feb6..3c740a06 100644
--- a/newton/newton/urls.py
+++ b/newton/newton/urls.py
@@ -10,24 +10,25 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
from django.conf.urls import include, url
-from newton.pub.config.config \
- import REG_TO_MSB_WHEN_START, REG_TO_MSB_REG_URL, REG_TO_MSB_REG_PARAM
+from newton.registration.views import registration
from newton.requests.views import tenants
urlpatterns = [
url(r'^', include('newton.swagger.urls')),
url(r'^', include('newton.samples.urls')),
- url(r'^openoapi/multivim-newton/v1/(?P<vimid>[0-9a-zA-Z_-]+)/tenants$',
+ url(r'^api/multicloud-newton/v0/(?P<vimid>[0-9a-zA-Z_-]+)/registry$',
+ registration.Registry.as_view()),
+ url(r'^api/multicloud-newton/v0/(?P<vimid>[0-9a-zA-Z_-]+)$',
+ registration.Registry.as_view()),
+ url(r'^api/multicloud-newton/v0/(?P<vimid>[0-9a-zA-Z_-]+)/exten',
+ include('newton.extensions.urls')),
+ url(r'^api/multicloud-newton/v0/(?P<vimid>[0-9a-zA-Z_-]+)/',
+ include('newton.proxy.urls')),
+ url(r'^api/multicloud-newton/v0/(?P<vimid>[0-9a-zA-Z_-]+)/tenants$',
tenants.Tenants.as_view()),
- url(r'^openoapi/multivim-newton/v1/(?P<vimid>[0-9a-zA-Z_-]+)/'
+ url(r'^api/multicloud-newton/v0/(?P<vimid>[0-9a-zA-Z_-]+)/'
'(?P<tenantid>[0-9a-zA-Z_-]{8,})/', include('newton.requests.urls')),
]
-# regist to MSB when startup
-if REG_TO_MSB_WHEN_START:
- import json
- from newton.pub.utils.restcall import req_by_msb
- req_by_msb(REG_TO_MSB_REG_URL, "POST",
- json.JSONEncoder().encode(REG_TO_MSB_REG_PARAM))
diff --git a/newton/pom.xml b/newton/pom.xml
index 0c8782ed..6d668991 100644
--- a/newton/pom.xml
+++ b/newton/pom.xml
@@ -13,17 +13,17 @@
-->
<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.openo.multivimdriver.openstack</groupId>
- <artifactId>multivimdriver-openstack-root</artifactId>
- <version>1.1.0-SNAPSHOT</version>
+ <groupId>org.onap.multicloud.openstack</groupId>
+ <artifactId>multicloud-openstack-root</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
- <groupId>org.openo.multivimdriver.openstack</groupId>
- <artifactId>multivimdriver-openstack-newton</artifactId>
- <version>1.1.0-SNAPSHOT</version>
+ <groupId>org.onap.multicloud.openstack</groupId>
+ <artifactId>multicloud-openstack-newton</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
- <name>multivimdriver/openstack/newton</name>
- <description>multivimdriver for openstack newton</description>
+ <name>multicloud/openstack/newton</name>
+ <description>multicloud for openstack newton</description>
<build>
<plugins>
<plugin>
diff --git a/newton/requirements.txt b/newton/requirements.txt
index 5976f5c9..841fe278 100644
--- a/newton/requirements.txt
+++ b/newton/requirements.txt
@@ -8,6 +8,9 @@ httplib2==0.9.2
# for call openstack auth and transport api
keystoneauth1==2.18.0
+#python-memcached
+python-memcached
+
# for unit test
coverage==4.2
mock==2.0.0
diff --git a/newton/tox.ini b/newton/tox.ini
index 87aca481..4e15a2e7 100644
--- a/newton/tox.ini
+++ b/newton/tox.ini
@@ -8,3 +8,5 @@ downloadcache = ~/cache/pip
[testenv]
deps = -r{toxinidir}/requirements.txt
commands = coverage run --branch manage.py test newton
+ coverage html --omit="*test*,*__init__.py" -d htmlcov
+
diff --git a/pom.xml b/pom.xml
index 276b6760..2234f546 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,15 +21,14 @@
</parent>
<modelVersion>4.0.0</modelVersion>
- <groupId>org.openo.multivimdriver.openstack</groupId>
- <artifactId>multivimdriver-openstack-root</artifactId>
- <version>1.1.0-SNAPSHOT</version>
- <name>multivim-openstack</name>
+ <groupId>org.onap.multicloud.openstack</groupId>
+ <artifactId>multicloud-openstack-root</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <name>multicloud/openstack</name>
<packaging>pom</packaging>
<modules>
<module>newton</module>
- <module>kilo</module>
</modules>
<build>