summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--newton/newton/extensions/tests/__init__.py0
-rw-r--r--newton/newton/extensions/tests/test_epacaps.py67
-rw-r--r--newton/newton/extensions/tests/test_extensions.py45
-rw-r--r--newton/newton/extensions/views/epacaps.py6
-rw-r--r--newton/newton/extensions/views/extensions.py2
-rw-r--r--newton/newton/proxy/tests/test_service_proxy.py177
-rw-r--r--newton/newton/proxy/views/services.py475
-rw-r--r--newton/newton/requests/tests/test_request.py (renamed from newton/newton/requests/tests/test_reqeust.py)0
-rw-r--r--newton/newton/requests/views/util.py6
-rw-r--r--newton/newton/settings.py7
-rw-r--r--pom.xml2
-rw-r--r--windriver/.gitignore11
-rw-r--r--windriver/README.md12
-rw-r--r--windriver/assembly.xml70
-rw-r--r--windriver/docker/Dockerfile31
-rw-r--r--windriver/docker/build-image.sh32
-rw-r--r--windriver/initialize.sh13
-rw-r--r--windriver/logs/empty.txt0
-rw-r--r--windriver/manage.py19
-rw-r--r--windriver/pom.xml58
-rw-r--r--windriver/requirements.txt17
-rw-r--r--windriver/run.sh32
-rw-r--r--windriver/stop.sh16
-rw-r--r--windriver/titanium_cloud/__init__.py10
-rw-r--r--windriver/titanium_cloud/extensions/__init__.py10
-rw-r--r--windriver/titanium_cloud/extensions/urls.py29
-rw-r--r--windriver/titanium_cloud/extensions/views/__init__.py10
-rw-r--r--windriver/titanium_cloud/extensions/views/epacaps.py32
-rw-r--r--windriver/titanium_cloud/extensions/views/extensions.py73
-rw-r--r--windriver/titanium_cloud/extensions/views/fcaps.py320
-rw-r--r--windriver/titanium_cloud/proxy/__init__.py10
-rw-r--r--windriver/titanium_cloud/proxy/urls.py32
-rw-r--r--windriver/titanium_cloud/proxy/views/__init__.py10
-rw-r--r--windriver/titanium_cloud/proxy/views/identityV3.py27
-rw-r--r--windriver/titanium_cloud/proxy/views/services.py45
-rw-r--r--windriver/titanium_cloud/pub/__init__.py10
-rw-r--r--windriver/titanium_cloud/pub/config/__init__.py10
-rw-r--r--windriver/titanium_cloud/pub/config/config.py34
-rw-r--r--windriver/titanium_cloud/registration/__init__.py10
-rw-r--r--windriver/titanium_cloud/registration/views/__init__.py10
-rw-r--r--windriver/titanium_cloud/registration/views/registration.py28
-rw-r--r--windriver/titanium_cloud/requests/__init__.py13
-rw-r--r--windriver/titanium_cloud/requests/urls.py47
-rw-r--r--windriver/titanium_cloud/samples/__init__.py10
-rw-r--r--windriver/titanium_cloud/samples/tests.py29
-rw-r--r--windriver/titanium_cloud/samples/urls.py16
-rw-r--r--windriver/titanium_cloud/samples/views.py26
-rw-r--r--windriver/titanium_cloud/settings.py122
-rw-r--r--windriver/titanium_cloud/swagger/__init__.py10
-rw-r--r--windriver/titanium_cloud/swagger/tests.py29
-rw-r--r--windriver/titanium_cloud/swagger/urls.py21
-rw-r--r--windriver/titanium_cloud/swagger/views.py45
-rw-r--r--windriver/titanium_cloud/urls.py34
-rw-r--r--windriver/titanium_cloud/wsgi.py19
-rw-r--r--windriver/tox.ini14
56 files changed, 1779 insertions, 467 deletions
diff --git a/.gitignore b/.gitignore
index e86d02b0..7d298bc4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,4 +8,5 @@ logs/*.log
.tox
.coverage
htmlcov/
-
+.idea/
+mydatabase
diff --git a/newton/newton/extensions/tests/__init__.py b/newton/newton/extensions/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/newton/newton/extensions/tests/__init__.py
diff --git a/newton/newton/extensions/tests/test_epacaps.py b/newton/newton/extensions/tests/test_epacaps.py
new file mode 100644
index 00000000..65125a43
--- /dev/null
+++ b/newton/newton/extensions/tests/test_epacaps.py
@@ -0,0 +1,67 @@
+# Copyright (c) 2017 Intel Corporation.
+#
+# 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
+from django.test import Client
+from rest_framework import status
+import unittest
+
+from newton.requests.views.util import VimDriverUtils
+
+MOCK_VIM_INFO = {
+ "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',
+}
+
+
+class TestEpaCaps(unittest.TestCase):
+ def setUp(self):
+ self.client = Client()
+
+ @mock.patch.object(VimDriverUtils, 'get_vim_info')
+ def test_get_epa_caps_info(self, mock_get_vim_info):
+ mock_get_vim_info.return_value = MOCK_VIM_INFO
+ cloud_owner = "windriver-hudson-dc"
+ cloud_region_id = "RegionOne"
+ vimid = cloud_owner + "_" + cloud_region_id
+
+ response = self.client.get(
+ "/api/multicloud-newton/v0/" + vimid + "/extensions/epa-caps")
+ json_content = response.json()
+
+ self.assertEquals(status.HTTP_200_OK, response.status_code)
+ self.assertEquals(4, len(json_content.keys()))
+ self.assertEquals(cloud_owner, json_content["cloud-owner"])
+ self.assertEquals(cloud_region_id, json_content["cloud-region-id"])
+ self.assertEquals(vimid, json_content["vimid"])
+ self.assertEquals(json.loads(MOCK_VIM_INFO['cloud_epa_caps']),
+ json_content["cloud-epa-caps"]) \ No newline at end of file
diff --git a/newton/newton/extensions/tests/test_extensions.py b/newton/newton/extensions/tests/test_extensions.py
new file mode 100644
index 00000000..89ef0d11
--- /dev/null
+++ b/newton/newton/extensions/tests/test_extensions.py
@@ -0,0 +1,45 @@
+# Copyright (c) 2017 Intel Corporation.
+#
+# 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.test import Client
+from rest_framework import status
+import unittest
+
+
+class TestExtensions(unittest.TestCase):
+ def setUp(self):
+ self.client = Client()
+
+ def test_get_extensions_info(self):
+ cloud_owner = "windriver-hudson-dc"
+ cloud_region_id = "RegionOne"
+ vimid = cloud_owner + "_" + cloud_region_id
+
+ response = self.client.get(
+ "/api/multicloud-newton/v0/" + vimid + "/extensions/")
+ json_content = response.json()
+
+ self.assertEquals(status.HTTP_200_OK, response.status_code)
+ self.assertEquals(4, len(json_content.keys()))
+
+ self.assertEquals(cloud_owner, json_content["cloud-owner"])
+ self.assertEquals(cloud_region_id, json_content["cloud-region-id"])
+ self.assertEquals(vimid, json_content["vimid"])
+
+ self.assertEquals("epa-caps", json_content["extensions"][0]["alias"])
+ self.assertEquals("Multiple network support", json_content["extensions"][0]["description"])
+ self.assertEquals("EPACapsQuery", json_content["extensions"][0]["name"])
+ self.assertEquals("http://127.0.0.1:80/api/multicloud-newton/v0/%s/extensions/epa-caps" % vimid,
+ json_content["extensions"][0]["url"])
+ self.assertEquals("", json_content["extensions"][0]["spec"]) \ No newline at end of file
diff --git a/newton/newton/extensions/views/epacaps.py b/newton/newton/extensions/views/epacaps.py
index 54bd0ebe..e41d16c2 100644
--- a/newton/newton/extensions/views/epacaps.py
+++ b/newton/newton/extensions/views/epacaps.py
@@ -11,12 +11,11 @@
# 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.exceptions import HttpError
from rest_framework import status
from rest_framework.response import Response
@@ -29,8 +28,6 @@ from newton.pub.msapi import extsys
logger = logging.getLogger(__name__)
-DEBUG=True
-
class EpaCaps(APIView):
@@ -55,7 +52,6 @@ class EpaCaps(APIView):
"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:
diff --git a/newton/newton/extensions/views/extensions.py b/newton/newton/extensions/views/extensions.py
index a196edcc..c9f4df7b 100644
--- a/newton/newton/extensions/views/extensions.py
+++ b/newton/newton/extensions/views/extensions.py
@@ -52,7 +52,7 @@ class Extensions(APIView):
"alias": "epa-caps",
"description": "Multiple network support",
"name": "EPACapsQuery",
- "url": self.proxy_prefix+"/%s/extensions/epa-caps" \
+ "url": self.proxy_prefix + "/%s/extensions/epa-caps" \
% (vimid),
"spec": ""
}
diff --git a/newton/newton/proxy/tests/test_service_proxy.py b/newton/newton/proxy/tests/test_service_proxy.py
index 2dd558d5..adac3002 100644
--- a/newton/newton/proxy/tests/test_service_proxy.py
+++ b/newton/newton/proxy/tests/test_service_proxy.py
@@ -11,19 +11,17 @@
# 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
+import copy
+import json
from django.test import Client
+import mock
from rest_framework import status
+import unittest
-from keystoneauth1 import session
-from keystoneauth1.exceptions import HttpError
from newton.requests.views.util import VimDriverUtils
-from newton.proxy.views.services import Services, GetTenants
MOCK_VIM_INFO = {
"createTime": "2017-04-01 02:22:27",
@@ -696,7 +694,7 @@ MOCK_PATCH_IMAGE_RESPONSE = {
}
-class mock_get_servers_response_specs(object):
+class MockResponse(object):
status_code = 200
content = ''
@@ -707,68 +705,75 @@ class mock_get_servers_response_specs(object):
class TestServiceProxy(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')
@mock.patch.object(VimDriverUtils, 'get_token_cache')
- def test_get(self, mock_get_token_cache, mock_update_token_cache, mock_get_auth_state, mock_get_session, mock_get_vim_info):
- '''
- Test service proxy API: GET
-
- :param mock_get_token_cache:
- :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.patch.object(VimDriverUtils, 'get_vim_info')
+ def test_get_token(self, mock_get_vim_info, mock_get_token_cache, mock_get_session):
+ mock_session_specs = ["head"]
mock_session = mock.Mock(name='mock_session', spec=mock_session_specs)
- mock_get_servers_response_obj = mock.Mock(spec=mock_get_servers_response_specs)
+ mock_get_servers_response_obj = mock.Mock(spec=MockResponse)
mock_get_servers_response_obj.status_code=200
mock_get_servers_response_obj.content = MOCK_GET_SERVERS_RESPONSE
mock_get_servers_response_obj.json.return_value=MOCK_GET_SERVERS_RESPONSE
- mock_session.get.return_value = mock_get_servers_response_obj
+ mock_session.head.return_value = mock_get_servers_response_obj
mock_get_vim_info.return_value = MOCK_VIM_INFO
mock_get_session.return_value = mock_session
- mock_get_auth_state.return_value = json.dumps(MOCK_AUTH_STATE)
- mock_update_token_cache.return_value = MOCK_TOKEN_ID
mock_get_token_cache.return_value = (json.dumps(MOCK_AUTH_STATE),json.dumps(MOCK_INTERNAL_METADATA_CATALOG))
+ response = self.client.head(
+ "/api/multicloud-newton/v0/windriver-hudson-dc_RegionOne/compute/v2.1/fcca3cc49d5e42caae15459e27103efc/servers",
+ {}, HTTP_X_AUTH_TOKEN=MOCK_TOKEN_ID)
+ self.assertEquals(status.HTTP_200_OK, response.status_code)
- #simulate client to make the request
+ def test_unauthorized_access(self):
response = self.client.get(
- "/api/multicloud-newton/v0/windriver-hudson-dc_RegionOne/compute/v2.1/fcca3cc49d5e42caae15459e27103efc/servers",
- {}, HTTP_X_AUTH_TOKEN=MOCK_TOKEN_ID)
+ "/api/multicloud-newton/v0/windriver-hudson-dc_RegionOne/compute/v2.1/fcca3cc49d5e42caae15459e27103efc/servers")
+ self.assertEquals(status.HTTP_403_FORBIDDEN, response.status_code)
- self.failUnlessEqual(status.HTTP_200_OK, response.status_code)
- context = response.json()
+ @mock.patch.object(VimDriverUtils, 'get_vim_info')
+ def test_expired_auth_token(self, mock_get_vim_info):
+ mock_get_vim_info.return_value = MOCK_VIM_INFO
+
+ response = self.client.get(
+ "/api/multicloud-newton/v0/windriver-hudson-dc_RegionOne/compute/v2.1/fcca3cc49d5e42caae15459e27103efc/servers",
+ {}, HTTP_X_AUTH_TOKEN=MOCK_TOKEN_ID)
+ self.assertEquals(status.HTTP_403_FORBIDDEN, response.status_code)
+
+ @mock.patch.object(VimDriverUtils, 'get_token_cache')
+ @mock.patch.object(VimDriverUtils, 'get_vim_info')
+ def test_request_without_servicetype(self, mock_get_vim_info, mock_get_token_cache):
+ mock_get_vim_info.return_value = MOCK_VIM_INFO
+ mock_get_token_cache.return_value = (json.dumps(MOCK_AUTH_STATE), {})
+ servicetype = "compute"
+ url = ("/api/multicloud-newton/v0/windriver-hudson-dc_RegionOne/" + servicetype +
+ "/v2.1/fcca3cc49d5e42caae15459e27103efc/servers")
+ response = self.client.get(url, {}, HTTP_X_AUTH_TOKEN=MOCK_TOKEN_ID)
+ self.assertEquals(status.HTTP_500_INTERNAL_SERVER_ERROR, response.status_code)
- self.assertTrue(response['X-Subject-Token'] == MOCK_TOKEN_ID)
- self.assertTrue(context['servers'] != None)
+ metadata_catalog = copy.deepcopy(MOCK_INTERNAL_METADATA_CATALOG)
+ metadata_catalog[servicetype] = None
+ mock_get_token_cache.return_value = (json.dumps(MOCK_AUTH_STATE), json.dumps(metadata_catalog))
- pass
+ response = self.client.get(url, {}, HTTP_X_AUTH_TOKEN=MOCK_TOKEN_ID)
+ self.assertEquals(status.HTTP_500_INTERNAL_SERVER_ERROR, response.status_code)
+ metadata_catalog = copy.deepcopy(MOCK_INTERNAL_METADATA_CATALOG)
+ metadata_catalog[servicetype]['prefix'] = None
+ metadata_catalog[servicetype]['proxy_prefix'] = None
+ mock_get_token_cache.return_value = (json.dumps(MOCK_AUTH_STATE), json.dumps(metadata_catalog))
+ response = self.client.get(url, {}, HTTP_X_AUTH_TOKEN=MOCK_TOKEN_ID)
+ self.assertEquals(status.HTTP_500_INTERNAL_SERVER_ERROR, response.status_code)
@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')
@mock.patch.object(VimDriverUtils, 'get_token_cache')
- def test_post(self, mock_get_token_cache, mock_update_token_cache, mock_get_auth_state, mock_get_session, mock_get_vim_info):
+ def test_crud_resources(self, mock_get_token_cache, mock_update_token_cache, mock_get_auth_state, mock_get_session, mock_get_vim_info):
'''
- Test service proxy API: POST
+ Test service proxy API: GET
:param mock_get_token_cache:
:param mock_update_token_cache:
@@ -779,14 +784,31 @@ class TestServiceProxy(unittest.TestCase):
'''
#mock VimDriverUtils APIs
- mock_session_specs = ["post"]
+ mock_session_specs = ["get", "post", "put", "patch", "delete"]
- mock_session = mock.Mock(name='mock_session', spec=mock_session_specs)
- mock_post_server_response_obj = mock.Mock(spec=mock_get_servers_response_specs)
+ mock_get_servers_response_obj = mock.Mock(spec=MockResponse)
+ mock_get_servers_response_obj.status_code=200
+ mock_get_servers_response_obj.content = MOCK_GET_SERVERS_RESPONSE
+ mock_get_servers_response_obj.json.return_value=MOCK_GET_SERVERS_RESPONSE
+
+ mock_post_server_response_obj = mock.Mock(spec=MockResponse)
mock_post_server_response_obj.status_code=202
mock_post_server_response_obj.content = MOCK_POST_SERVER_RESPONSE
mock_post_server_response_obj.json.return_value=MOCK_POST_SERVER_RESPONSE
+
+ mock_patch_server_response_obj = mock.Mock(spec=MockResponse)
+ mock_patch_server_response_obj.status_code=202
+ mock_patch_server_response_obj.content = MOCK_PATCH_IMAGE_REQUEST
+ mock_patch_server_response_obj.json.return_value=MOCK_PATCH_IMAGE_REQUEST
+
+ mock_delete_server_response_obj = mock.Mock(spec=MockResponse)
+ mock_delete_server_response_obj.status_code=204
+
+ mock_session = mock.Mock(name='mock_session', spec=mock_session_specs)
+ mock_session.get.return_value = mock_get_servers_response_obj
mock_session.post.return_value = mock_post_server_response_obj
+ mock_session.patch.return_value = mock_patch_server_response_obj
+ mock_session.delete.return_value = mock_delete_server_response_obj
mock_get_vim_info.return_value = MOCK_VIM_INFO
mock_get_session.return_value = mock_session
@@ -794,57 +816,40 @@ class TestServiceProxy(unittest.TestCase):
mock_update_token_cache.return_value = MOCK_TOKEN_ID
mock_get_token_cache.return_value = (json.dumps(MOCK_AUTH_STATE),json.dumps(MOCK_INTERNAL_METADATA_CATALOG))
- #simulate client to make the request
+ # Create resource
response = self.client.post(
"/api/multicloud-newton/v0/windriver-hudson-dc_RegionOne/compute/v2.1/fcca3cc49d5e42caae15459e27103efc/servers",
MOCK_POST_SERVER_REQUEST, HTTP_X_AUTH_TOKEN=MOCK_TOKEN_ID)
- self.failUnlessEqual(status.HTTP_202_ACCEPTED, response.status_code)
+ self.assertEquals(status.HTTP_202_ACCEPTED, response.status_code)
context = response.json()
+ self.assertEquals(MOCK_TOKEN_ID, response['X-Subject-Token'])
+ self.assertIsNotNone(context['server'])
- self.assertTrue(response['X-Subject-Token'] == MOCK_TOKEN_ID)
- self.assertTrue(context['server'] != None)
-
- 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')
- @mock.patch.object(VimDriverUtils, 'get_token_cache')
- def test_delete(self, mock_get_token_cache, mock_update_token_cache, mock_get_auth_state, mock_get_session, mock_get_vim_info):
- '''
- Test service proxy API: DELETE
-
- :param mock_get_token_cache:
- :param mock_update_token_cache:
- :param mock_get_auth_state:
- :param mock_get_session:
- :param mock_get_vim_info:
- :return:
- '''
+ # Retrieve resource
+ response = self.client.get(
+ "/api/multicloud-newton/v0/windriver-hudson-dc_RegionOne/compute/v2.1/fcca3cc49d5e42caae15459e27103efc/servers",
+ {}, HTTP_X_AUTH_TOKEN=MOCK_TOKEN_ID)
+ self.assertEquals(status.HTTP_200_OK, response.status_code)
+ context = response.json()
- #mock VimDriverUtils APIs
- mock_session_specs = ["delete"]
+ self.assertEquals(MOCK_TOKEN_ID, response['X-Subject-Token'])
+ self.assertIsNotNone(context['servers'])
- mock_session = mock.Mock(name='mock_session', spec=mock_session_specs)
- mock_post_server_response_obj = mock.Mock(spec=mock_get_servers_response_specs)
- mock_post_server_response_obj.status_code=204
- mock_session.delete.return_value = mock_post_server_response_obj
+ # Update resource
+ response = self.client.get(
+ "/api/multicloud-newton/v0/windriver-hudson-dc_RegionOne/compute/v2.1/fcca3cc49d5e42caae15459e27103efc/servers",
+ {}, HTTP_X_AUTH_TOKEN=MOCK_TOKEN_ID)
+ self.assertEquals(status.HTTP_200_OK, response.status_code)
+ context = response.json()
- mock_get_vim_info.return_value = MOCK_VIM_INFO
- mock_get_session.return_value = mock_session
- mock_get_auth_state.return_value = json.dumps(MOCK_AUTH_STATE)
- mock_update_token_cache.return_value = MOCK_TOKEN_ID
- mock_get_token_cache.return_value = (json.dumps(MOCK_AUTH_STATE),json.dumps(MOCK_INTERNAL_METADATA_CATALOG))
+ self.assertEquals(MOCK_TOKEN_ID, response['X-Subject-Token'])
+ self.assertIsNotNone(context['servers'])
#simulate client to make the request
response = self.client.delete(
"/api/multicloud-newton/v0/windriver-hudson-dc_RegionOne/compute/v2.1/fcca3cc49d5e42caae15459e27103efc/servers/324dfb7d-f4a9-419a-9a19-237df04b443b",
HTTP_X_AUTH_TOKEN=MOCK_TOKEN_ID)
- self.failUnlessEqual(status.HTTP_204_NO_CONTENT, response.status_code)
- self.assertTrue(response['X-Subject-Token'] == MOCK_TOKEN_ID)
-
- pass
+ self.assertEquals(status.HTTP_204_NO_CONTENT, response.status_code)
+ self.assertEquals(MOCK_TOKEN_ID, response['X-Subject-Token'])
diff --git a/newton/newton/proxy/views/services.py b/newton/newton/proxy/views/services.py
index 6e166f95..b6e1be0c 100644
--- a/newton/newton/proxy/views/services.py
+++ b/newton/newton/proxy/views/services.py
@@ -15,51 +15,130 @@ 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
+import re
+from rest_framework.permissions import BasePermission
from rest_framework.response import Response
+from rest_framework import status
from rest_framework.views import APIView
+from newton.proxy.views.proxy_utils import ProxyUtils
from newton.pub.exceptions import VimDriverNewtonException
-from newton.requests.views.util import VimDriverUtils
from newton.pub.msapi import extsys
-from newton.proxy.views.proxy_utils import ProxyUtils
+from newton.requests.views.util import VimDriverUtils
logger = logging.getLogger(__name__)
DEBUG=True
+
+class HasValidToken(BasePermission):
+
+ def has_permission(self, request, view):
+ token = request.META.get('HTTP_X_AUTH_TOKEN', None)
+ if token:
+ state, metadata = VimDriverUtils.get_token_cache(token)
+ if state:
+ return True
+ return False
+
+
class Services(APIView):
+ permission_classes = (HasValidToken,)
def __init__(self):
self._logger = logger
+ def _get_token(self, request):
+ return request.META.get('HTTP_X_AUTH_TOKEN', None)
+
+ def _get_resource_and_metadata(self, servicetype, metadata_catalog, requri):
+ real_prefix = None
+ proxy_prefix = None
+ suffix = None
+ if servicetype and 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)
+
+ req_resource = ''
+ if requri and requri != '':
+ req_resource = "/" if re.match(r'//', requri) else '' + requri
+ return req_resource, metadata_catalog
+
+ def _do_action(self, action, request, vim_id, servicetype, requri):
+ tmp_auth_token = self._get_token(request)
+ try:
+ vim = VimDriverUtils.get_vim_info(vim_id)
+ # fetch the auth_state out of cache
+ auth_state, metadata_catalog = VimDriverUtils.get_token_cache(tmp_auth_token)
+ req_resource, metadata_catalog = self._get_resource_and_metadata(servicetype, metadata_catalog, requri)
+ sess = VimDriverUtils.get_session(vim, tenantid=None, auth_state=auth_state)
+
+ cloud_owner, regionid = extsys.decode_vim_id(vim_id)
+ interface = 'public'
+ service = {
+ 'service_type': servicetype,
+ 'interface': interface,
+ 'region_id': regionid
+ }
+
+ self._logger.debug("service " + action + " request uri %s" % (req_resource))
+ if(action == "get"):
+ resp = sess.get(req_resource, endpoint_filter=service)
+ elif(action == "post"):
+ resp = sess.post(req_resource, data=json.JSONEncoder().encode(request.data), endpoint_filter=service)
+ elif(action == "put"):
+ resp = sess.put(req_resource, data=json.JSONEncoder().encode(request.data), endpoint_filter=service)
+ elif(action == "patch"):
+ resp = sess.patch(req_resource, data=json.JSONEncoder().encode(request.data), endpoint_filter=service)
+ elif (action == "delete"):
+ resp = sess.delete(req_resource, endpoint_filter=service)
+ content = resp.json() if resp.content else None
+ self._logger.debug("service " + action + " response: %s, %s" % (resp.status_code, content))
+
+ if (action != "delete"):
+ content = ProxyUtils.update_prefix(metadata_catalog, content)
+ return Response(headers={'X-Subject-Token': tmp_auth_token}, data=content, status=resp.status_code)
+ return Response(headers={'X-Subject-Token': tmp_auth_token}, status=resp.status_code)
+ except VimDriverNewtonException as e:
+ return Response(data={'error': e.content}, status=e.status_code)
+ except HttpError as e:
+ self._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:
+ self._logger.error(traceback.format_exc())
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
def head(self, request, vimid="", servicetype="", requri=""):
self._logger.debug("Services--head::META> %s" % request.META)
self._logger.debug("Services--head::data> %s" % request.data)
self._logger.debug("Services--head::vimid, servicetype, requri> %s,%s,%s"
% (vimid, servicetype, requri))
+ token = self._get_token(request)
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)
-
+ auth_state, metadata_catalog = VimDriverUtils.get_token_cache(token)
+ sess = VimDriverUtils.get_session(vim, auth_state=auth_state)
- 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
@@ -73,13 +152,10 @@ class Services(APIView):
self._logger.debug("service head request uri %s" % (req_resource))
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() if resp.content else None
self._logger.debug("service head response: %s, %s" % (resp.status_code, content))
- return Response(headers={'X-Subject-Token': tmp_auth_token}, data=content, status=resp.status_code)
- #return resp
+ return Response(headers={'X-Subject-Token': 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:
@@ -95,377 +171,36 @@ class Services(APIView):
self._logger.debug("Services--get::data> %s" % request.data)
self._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:
-# self._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}
-
- self._logger.debug("service get request uri %s" % (req_resource))
-
- 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() if resp.content else None
- self._logger.debug("service get response: %s, %s" % (resp.status_code, content))
-
- content = ProxyUtils.update_prefix(metadata_catalog, 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:
- self._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:
- self._logger.error(traceback.format_exc())
- return Response(data={'error': str(e)},
- status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+ return self._do_action("get", request, vimid, servicetype, requri)
def post(self, request, vimid="", servicetype="", requri=""):
self._logger.debug("Services--post::META> %s" % request.META)
self._logger.debug("Services--post::data> %s" % request.data)
self._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:
-# self._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}
-
- self._logger.debug("service post request uri %s" % (req_resource))
-
- 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() if resp.content else None
- self._logger.debug("service post response: %s, %s" % (resp.status_code, content))
-
- content = ProxyUtils.update_prefix(metadata_catalog, 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:
- self._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:
- self._logger.error(traceback.format_exc())
- return Response(data={'error': str(e)},
- status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+ return self._do_action("post", request, vimid, servicetype, requri)
def put(self, request, vimid="", servicetype="", requri=""):
self._logger.debug("Services--put::META> %s" % request.META)
self._logger.debug("Services--put::data> %s" % request.data)
self._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:
-# self._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}
-
- self._logger.debug("service put request uri %s" % (req_resource))
-
- 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() if resp.content else None
- self._logger.debug("service put response: %s, %s" % (resp.status_code, content))
-
- content = ProxyUtils.update_prefix(metadata_catalog, 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:
- self._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:
- self._logger.error(traceback.format_exc())
- return Response(data={'error': str(e)},
- status=status.HTTP_500_INTERNAL_SERVER_ERROR)
-
+ return self._do_action("put", request, vimid, servicetype, requri)
def patch(self, request, vimid="", servicetype="", requri=""):
self._logger.debug("Services--patch::META> %s" % request.META)
self._logger.debug("Services--patch::data> %s" % request.data)
self._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:
-# self._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}
-
- self._logger.debug("service patch request uri %s" % (req_resource))
-
- 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() if resp.content else None
- self._logger.debug("service patch response: %s, %s" % (resp.status_code, content))
-
- content = ProxyUtils.update_prefix(metadata_catalog, 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:
- self._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:
- self._logger.error(traceback.format_exc())
- return Response(data={'error': str(e)},
- status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+ return self._do_action("patch", request, vimid, servicetype, requri)
def delete(self, request, vimid="", servicetype="", requri=""):
self._logger.debug("Services--delete::META> %s" % request.META)
self._logger.debug("Services--delete::data> %s" % request.data)
self._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:
-# self._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}
-
- self._logger.debug("service delete request uri %s" % (req_resource))
-
- 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)
-
- return Response(headers={'X-Subject-Token': tmp_auth_token}, status=resp.status_code)
-
- except VimDriverNewtonException as e:
- return Response(data={'error': e.content}, status=e.status_code)
- except HttpError as e:
- self._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:
- self._logger.error(traceback.format_exc())
- return Response(data={'error': str(e)},
- status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+ return self._do_action("delete", request, vimid, servicetype, requri)
class GetTenants(Services):
diff --git a/newton/newton/requests/tests/test_reqeust.py b/newton/newton/requests/tests/test_request.py
index d094314d..d094314d 100644
--- a/newton/newton/requests/tests/test_reqeust.py
+++ b/newton/newton/requests/tests/test_request.py
diff --git a/newton/newton/requests/views/util.py b/newton/newton/requests/views/util.py
index c5046387..f2c62896 100644
--- a/newton/newton/requests/views/util.py
+++ b/newton/newton/requests/views/util.py
@@ -124,15 +124,13 @@ class VimDriverUtils(object):
# return auth.get_auth_ref(session)
@staticmethod
- def get_token_cache(vim, token):
+ def get_token_cache(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)
+ return cache.get(token), cache.get("meta_%s" % token)
@staticmethod
diff --git a/newton/newton/settings.py b/newton/newton/settings.py
index b62a584f..d460758c 100644
--- a/newton/newton/settings.py
+++ b/newton/newton/settings.py
@@ -12,6 +12,13 @@
import os
import sys
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': 'mydatabase',
+ }
+}
+
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
diff --git a/pom.xml b/pom.xml
index 9f0acec8..ccfb334f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,6 +29,8 @@
<modules>
<module>newton</module>
+ <module>ocata</module>
+ <module>windriver</module>
</modules>
<build>
diff --git a/windriver/.gitignore b/windriver/.gitignore
new file mode 100644
index 00000000..e86d02b0
--- /dev/null
+++ b/windriver/.gitignore
@@ -0,0 +1,11 @@
+.project
+.classpath
+.settings/
+.checkstyle
+target/
+logs/*.log
+*.pyc
+.tox
+.coverage
+htmlcov/
+
diff --git a/windriver/README.md b/windriver/README.md
new file mode 100644
index 00000000..3de1facc
--- /dev/null
+++ b/windriver/README.md
@@ -0,0 +1,12 @@
+# 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.
+
+# Micro service of MultiCloud plugin for Wind River Titanium Cloud.
diff --git a/windriver/assembly.xml b/windriver/assembly.xml
new file mode 100644
index 00000000..ef3a749f
--- /dev/null
+++ b/windriver/assembly.xml
@@ -0,0 +1,70 @@
+<!--
+ 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.
+-->
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
+ <id>windriver</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <fileSets>
+ <fileSet>
+ <directory>titanium_cloud</directory>
+ <outputDirectory>/titanium_cloud</outputDirectory>
+ <includes>
+ <include>**/*.py</include>
+ <include>**/*.json</include>
+ <include>**/*.xml</include>
+ <include>**/*.wsdl</include>
+ <include>**/*.xsd</include>
+ <include>**/*.bpel</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>logs</directory>
+ <outputDirectory>/logs</outputDirectory>
+ <includes>
+ <include>*.txt</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>docker</directory>
+ <outputDirectory>/docker</outputDirectory>
+ <includes>
+ <include>*.sh</include>
+ <include>Dockerfile</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>.</directory>
+ <outputDirectory>/</outputDirectory>
+ <includes>
+ <include>*.py</include>
+ <include>*.txt</include>
+ <include>*.sh</include>
+ <include>*.ini</include>
+ <include>*.md</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+ <dependencySets>
+ <dependencySet>
+ <unpack>true</unpack>
+ <outputDirectory>/lib</outputDirectory>
+ <includes>
+ <include>org.onap.multicloud.openstack:multicloud-openstack-newton</include>
+ </includes>
+ </dependencySet>
+ </dependencySets>
+ <baseDirectory>windriver</baseDirectory>
+</assembly>
diff --git a/windriver/docker/Dockerfile b/windriver/docker/Dockerfile
new file mode 100644
index 00000000..ac2e62ef
--- /dev/null
+++ b/windriver/docker/Dockerfile
@@ -0,0 +1,31 @@
+FROM python:2
+
+ARG HTTP_PROXY=${HTTP_PROXY}
+ARG HTTPS_PROXY=${HTTPS_PROXY}
+
+ENV http_proxy $HTTP_PROXY
+ENV https_proxy $HTTPS_PROXY
+
+ENV MSB_ADDR "127.0.0.1"
+ENV MSB_PORT "80"
+ENV AAI_ADDR "aai.api.simpledemo.openecomp.org"
+ENV AAI_PORT "8443"
+ENV AAI_SCHEMA_VERSION "v11"
+ENV AAI_USERNAME "AAI"
+ENV AAI_PASSWORD "AAI"
+
+EXPOSE 9005
+
+# COPY ./ /opt/windriver/
+RUN apt-get update && \
+ apt-get install -y memcached && \
+ apt-get install -y unzip && \
+ cd /opt/ && \
+ wget -O multicloud-openstack-windriver.zip "https://nexus.onap.org/service/local/artifact/maven/redirect?r=snapshots&g=org.onap.multicloud.openstack&a=multicloud-openstack-windriver&e=zip&v=LATEST" && \
+ unzip -q -o -B multicloud-openstack-windriver.zip && \
+ chmod +x /opt/windriver/*.sh && \
+ rm -f multicloud-openstack-windriver.zip && \
+ pip install -r /opt/windriver/requirements.txt
+
+WORKDIR /opt/windriver
+CMD /bin/sh -c /opt/windriver/run.sh \ No newline at end of file
diff --git a/windriver/docker/build-image.sh b/windriver/docker/build-image.sh
new file mode 100644
index 00000000..cc32212e
--- /dev/null
+++ b/windriver/docker/build-image.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+DIRNAME=`dirname $0`
+DOCKER_BUILD_DIR=`cd $DIRNAME/; pwd`
+echo "DOCKER_BUILD_DIR=${DOCKER_BUILD_DIR}"
+cd ${DOCKER_BUILD_DIR}
+
+BUILD_ARGS="--no-cache"
+ORG="onap"
+VERSION="1.0.0-SNAPSHOT"
+PROJECT="multicloud"
+IMAGE="openstack-windriver"
+DOCKER_REPOSITORY="nexus3.onap.org:10003"
+IMAGE_NAME="${DOCKER_REPOSITORY}/${ORG}/${PROJECT}/${IMAGE}"
+
+if [ $HTTP_PROXY ]; then
+ BUILD_ARGS+=" --build-arg HTTP_PROXY=${HTTP_PROXY}"
+fi
+if [ $HTTPS_PROXY ]; then
+ BUILD_ARGS+=" --build-arg HTTPS_PROXY=${HTTPS_PROXY}"
+fi
+
+function build_image {
+ docker build ${BUILD_ARGS} -t ${IMAGE_NAME}:${VERSION} -t ${IMAGE_NAME}:latest .
+}
+
+function push_image {
+ docker push ${IMAGE_NAME}:${VERSION}
+ docker push ${IMAGE_NAME}:latest
+}
+
+build_image
+push_image \ No newline at end of file
diff --git a/windriver/initialize.sh b/windriver/initialize.sh
new file mode 100644
index 00000000..5fed1714
--- /dev/null
+++ b/windriver/initialize.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+# 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.
+
+pip install -r requirements.txt
diff --git a/windriver/logs/empty.txt b/windriver/logs/empty.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/windriver/logs/empty.txt
diff --git a/windriver/manage.py b/windriver/manage.py
new file mode 100644
index 00000000..14931558
--- /dev/null
+++ b/windriver/manage.py
@@ -0,0 +1,19 @@
+# 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.
+
+import os
+import sys
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "titanium_cloud.settings")
+
+if __name__ == "__main__":
+ from django.core.management import execute_from_command_line
+ execute_from_command_line(sys.argv)
diff --git a/windriver/pom.xml b/windriver/pom.xml
new file mode 100644
index 00000000..6e6c9d00
--- /dev/null
+++ b/windriver/pom.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.onap.oparent</groupId>
+ <artifactId>oparent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>../oparent</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.onap.multicloud.openstack</groupId>
+ <artifactId>multicloud-openstack-windriver</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+ <name>multicloud/openstack/windriver</name>
+ <description>multicloud for openstack Wind River Titanium Cloud</description>
+ <dependencies>
+ <dependency>
+ <groupId>org.onap.multicloud.openstack</groupId>
+ <artifactId>multicloud-openstack-newton</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <type>zip</type>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <appendAssemblyId>false</appendAssemblyId>
+ <descriptors>
+ <descriptor>assembly.xml</descriptor>
+ </descriptors>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/windriver/requirements.txt b/windriver/requirements.txt
new file mode 100644
index 00000000..841fe278
--- /dev/null
+++ b/windriver/requirements.txt
@@ -0,0 +1,17 @@
+# rest framework
+Django==1.9.6
+djangorestframework==3.3.3
+
+# for call rest api
+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
+unittest_xml_reporting==1.12.0
diff --git a/windriver/run.sh b/windriver/run.sh
new file mode 100644
index 00000000..031719b4
--- /dev/null
+++ b/windriver/run.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+# 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.
+
+#!/bin/bash
+
+sed -i "s/MSB_SERVICE_ADDR =.*/MSB_SERVICE_ADDR = \"${MSB_ADDR}\"/g" titanium_cloud/pub/config/config.py
+sed -i "s/MSB_SERVICE_PORT =.*/MSB_SERVICE_PORT = \"${MSB_PORT}\"/g" titanium_cloud/pub/config/config.py
+sed -i "s/AAI_ADDR =.*/AAI_ADDR = \"${AAI_ADDR}\"/g" titanium_cloud/pub/config/config.py
+sed -i "s/AAI_PORT =.*/AAI_PORT = \"${AAI_PORT}\"/g" titanium_cloud/pub/config/config.py
+sed -i "s/AAI_SCHEMA_VERSION =.*/AAI_SCHEMA_VERSION = \"${AAI_SCHEMA_VERSION}\"/g" titanium_cloud/pub/config/config.py
+sed -i "s/AAI_USERNAME =.*/AAI_USERNAME = \"${AAI_USERNAME}\"/g" titanium_cloud/pub/config/config.py
+sed -i "s/AAI_PASSWORD =.*/AAI_PASSWORD = \"${AAI_PASSWORD}\"/g" titanium_cloud/pub/config/config.py
+
+memcached -d -m 2048 -u root -c 1024 -p 11211 -P /tmp/memcached1.pid
+export PYTHONPATH=lib/newton
+nohup python manage.py runserver 0.0.0.0:9005 2>&1 &
+
+while [ ! -f logs/runtime_titanium_cloud.log ]; do
+ sleep 1
+done
+
+tail -F logs/runtime_titanium_cloud.log
+
diff --git a/windriver/stop.sh b/windriver/stop.sh
new file mode 100644
index 00000000..10ce7464
--- /dev/null
+++ b/windriver/stop.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+# 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.
+
+#!/bin/bash
+
+ps auxww | grep 'manage.py runserver 0.0.0.0:9005' | awk '{print $2}' | xargs kill -9
+ps auxww | grep 'memcached -d -m 2048 -u root -c 1024 -p 11211 -P /tmp/memcached1.pid' | awk '{print $2}' | xargs kill -9
diff --git a/windriver/titanium_cloud/__init__.py b/windriver/titanium_cloud/__init__.py
new file mode 100644
index 00000000..802f3fba
--- /dev/null
+++ b/windriver/titanium_cloud/__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/windriver/titanium_cloud/extensions/__init__.py b/windriver/titanium_cloud/extensions/__init__.py
new file mode 100644
index 00000000..802f3fba
--- /dev/null
+++ b/windriver/titanium_cloud/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/windriver/titanium_cloud/extensions/urls.py b/windriver/titanium_cloud/extensions/urls.py
new file mode 100644
index 00000000..b0ffec89
--- /dev/null
+++ b/windriver/titanium_cloud/extensions/urls.py
@@ -0,0 +1,29 @@
+# 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 titanium_cloud.extensions.views import extensions
+from titanium_cloud.extensions.views import epacaps
+from titanium_cloud.extensions.views import fcaps
+
+
+urlpatterns = [
+ url(r'^sions/?$', extensions.Extensions.as_view()),
+ url(r'^sions/epa-caps/?$', epacaps.EpaCaps.as_view()),
+ url(r'^sions/guest-monitor/(?P<vserverid>[0-9a-zA-Z_-]+)/?$', fcaps.GuestMonitor.as_view()),
+]
+
+urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/windriver/titanium_cloud/extensions/views/__init__.py b/windriver/titanium_cloud/extensions/views/__init__.py
new file mode 100644
index 00000000..802f3fba
--- /dev/null
+++ b/windriver/titanium_cloud/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/windriver/titanium_cloud/extensions/views/epacaps.py b/windriver/titanium_cloud/extensions/views/epacaps.py
new file mode 100644
index 00000000..7f638fad
--- /dev/null
+++ b/windriver/titanium_cloud/extensions/views/epacaps.py
@@ -0,0 +1,32 @@
+# 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 titanium_cloud.pub.config import config
+
+
+from newton.extensions.views import epacaps as newton_epacaps
+
+logger = logging.getLogger(__name__)
+
+DEBUG=True
+
+
+class EpaCaps(newton_epacaps.EpaCaps):
+
+ def __init__(self):
+ self.proxy_prefix = config.MULTICLOUD_PREFIX
+ self._logger = logger
diff --git a/windriver/titanium_cloud/extensions/views/extensions.py b/windriver/titanium_cloud/extensions/views/extensions.py
new file mode 100644
index 00000000..2dd61fe9
--- /dev/null
+++ b/windriver/titanium_cloud/extensions/views/extensions.py
@@ -0,0 +1,73 @@
+# 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
+
+from titanium_cloud.pub.config import config
+from newton.extensions.views import extensions as newton_extensions
+
+logger = logging.getLogger(__name__)
+
+DEBUG=True
+
+class Extensions(newton_extensions.Extensions):
+
+ def __init__(self):
+ self._logger = logger
+ self.proxy_prefix = config.MULTICLOUD_PREFIX
+
+
+ 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",
+ "url": self.proxy_prefix + "/%s/extensions/epa-caps" \
+ % (vimid),
+ "spec": ""
+ },
+ {
+ "alias": "guest-monitor",
+ "description": "Multiple network support",
+ "name": "EPACapsQuery",
+ "url": self.proxy_prefix +\
+ "/%s/extensions/guest-monitor/{server_id}" \
+ % (vimid),
+ "spec": ""
+ }
+ ]
+
+ 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)
+
+ 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/windriver/titanium_cloud/extensions/views/fcaps.py b/windriver/titanium_cloud/extensions/views/fcaps.py
new file mode 100644
index 00000000..ad054e95
--- /dev/null
+++ b/windriver/titanium_cloud/extensions/views/fcaps.py
@@ -0,0 +1,320 @@
+# 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 threading
+
+from django.core.cache import cache
+
+from keystoneauth1.exceptions import HttpError
+from rest_framework import status
+from rest_framework.response import Response
+from rest_framework.views import APIView
+
+from titanium_cloud.pub.config import config
+from newton.pub.exceptions import VimDriverNewtonException
+from newton.requests.views.util import VimDriverUtils
+from newton.pub.msapi import extsys
+
+
+
+#from newton.extensions.views import fcaps as newton_fcaps
+
+logger = logging.getLogger(__name__)
+
+DEBUG=True
+
+#dict to store running worker threads
+running_threads = {}
+running_thread_lock = threading.Lock()
+
+class GuestMonitorWorker (threading.Thread):
+ service = {'service_type': 'platform',
+ 'interface': 'public'}
+ def __init__(self, vimid, tenantid=None):
+ threading.Thread.__init__(self)
+ self.vimid = vimid
+ self.tenantid = tenantid
+ self.eventid = '700.213' #Guest Heartbeat failed for instance
+
+ def run(self):
+ logger.debug("start GuestMonitorWorker %s,%s" % (self.vimid, self.tenantid))
+
+ viminfo = VimDriverUtils.get_vim_info(self.vimid)
+ sess = VimDriverUtils.get_session(viminfo, tenantid=self.tenantid)
+
+ thread_info = running_threads.get(self.vimid)
+ if not thread_info:
+ return
+
+ while thread_info.get('state') == 'start':
+ #wait for jobs
+ vservers = thread_info.get('vservers') if thread_info else None
+ if not vservers:
+ continue
+
+ # do jobs
+ for (vserverid, vserverinfo) in vservers.items():
+ status_code, heartbeat_event = \
+ self.monitor_heartbeat(self.vimid, self.tenantid, vserverid, viminfo, sess)
+
+ if status_code == status.HTTP_403_FORBIDDEN:
+ #invalid tenant, so remove this job
+
+ running_thread_lock.acquire()
+ thread_info['state'] = 'error'
+ running_thread_lock.release()
+
+ return #exit this thread since error
+
+ if heartbeat_event:
+ #report to VES
+ #tbd
+ pass
+ else:
+ continue
+
+ running_thread_lock.acquire()
+ thread_info['state'] = 'stopped'
+ running_thread_lock.release()
+
+ logger.debug("stop GuestMonitorWorker %s, %s, %s" % (self.vimid, self.tenantid, self.vserverid))
+# running_thread_lock.acquire()
+# running_threads.pop(self.vimid)
+# running_thread_lock.release()
+
+ def monitor_heartbeat(self, vimid, tenantid, vserverid, viminfo, session):
+ logger.debug("GuestMonitorWorker--monitor_heartbeat::> %s" % (vserverid))
+ try:
+ # prepare request resource to vim instance
+ req_resouce = "/v1/event_log?q.field=entity_instance_id&\
+ q.field=event_log_id&\
+ q.op=eq&q.op=eq&q.type=&q.type=&\
+ q.value=tenant\%%s.instance\%%s&\
+ q.value=%s" % (tenantid, vserverid, self.eventid)
+
+ resp = session.get(req_resouce, endpoint_filter=self.service,
+ headers={"Content-Type": "application/json",
+ "Accept": "application/json"})
+
+ logger.debug("response status code of monitor_heartbeat %s" % resp.status_code)
+
+ return resp.status_code, resp.json() if resp.content else None
+
+ except HttpError as e:
+ logger.error("monitor_heartbeat, HttpError: status:%s, response:%s" % (e.http_status, e.response.json()))
+ return e.http_status, e.response.json()
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ logger.error("Failed to monitor_heartbeat:%s" % str(e))
+ return e.http_status, e.response.json()
+
+
+class GuestMonitor(APIView):
+
+ def __init__(self):
+ self.proxy_prefix = config.MULTICLOUD_PREFIX
+ self._logger = logger
+
+ def post(self, request, vimid="", vserverid=""):
+ '''Start guest monitoring on specified virtual server'''
+ self._logger.debug("GuestMonitor--post::data> %s" % request.data)
+ self._logger.debug("GuestMonitor--post::vimid > %s" % vimid)
+
+ try:
+ # populate proxy identity url
+ cloud_owner, cloud_region_id = extsys.decode_vim_id(vimid)
+
+ tenant_name = request.data.get('tenantName')
+ tenant_id = request.data.get('tenantID')
+ ves_url = request.data.get('vesurl')
+
+ # prepare request resource to vim instance
+ # get token:
+ viminfo = VimDriverUtils.get_vim_info(vimid)
+ # the tenant should have the privilege to access the event-log API
+ # usually it is 'admin'. Otherwise the 403 will be returned.
+ sess = None
+ if tenant_id:
+ sess = VimDriverUtils.get_session(viminfo, tenantid=tenant_id)
+ else:
+ sess = VimDriverUtils.get_session(viminfo, tenantname=tenant_name)
+
+ #now try to convert tenant_name to tenant_id
+ #tbd
+
+ thread_info = running_threads[vimid]
+
+ if thread_info and thread_info['state'] == 'error':
+ #the thread is in error state, so recreate with new tenant_id
+ running_thread_lock.acquire()
+ running_threads.pop(vimid)
+ running_thread_lock.release()
+ thread_info = None
+
+ if not thread_info:
+ tmp_thread = GuestMonitorWorker(vimid, tenant_id)
+ if not tmp_thread:
+ raise VimDriverNewtonException(message="internal error",
+ content="Fail to spawn thread for Guest Monitoring",
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR)
+ thread_info = {
+ 'thread': tmp_thread,
+ 'tenantid':tenant_id,
+ 'vservers':{},
+ 'state':'start'
+ }
+
+ running_thread_lock.acquire()
+ running_threads[vimid] = thread_info
+ running_thread_lock.release()
+ tmp_thread.start()
+ else:
+ thread_info['state'] = 'start'
+
+
+ vservers = thread_info.get('vservers')
+ vservers[vserverid] = {'vesurl': ves_url}
+
+ 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:
+ self._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:
+ self._logger.error(traceback.format_exc())
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+ def GET(self, request, vimid="", vserverid=""):
+ '''query guest monitoring on specified virtual server'''
+ self._logger.debug("GuestMonitor--get::data> %s" % request.data)
+ self._logger.debug("GuestMonitor--get::vimid > %s" % vimid)
+
+ try:
+ # populate proxy identity url
+ cloud_owner, cloud_region_id = extsys.decode_vim_id(vimid)
+
+ tenant_name = request.data.get('tenantName')
+ tenant_id = request.data.get('tenantID')
+ vserver_id = vserverid
+
+ # prepare request resource to vim instance
+ # get token:
+ viminfo = VimDriverUtils.get_vim_info(vimid)
+ # the tenant should have the privilege to access the event-log API
+ # usually it is 'admin'. Otherwise the 403 will be returned.
+ sess = None
+ if tenant_id:
+ sess = VimDriverUtils.get_session(viminfo, tenantid=tenant_id)
+ else:
+ sess = VimDriverUtils.get_session(viminfo, tenantname=tenant_name)
+
+ #now try to convert tenant_name to tenant_id, and vserver_name to vserver_id
+ #tbd
+
+ thread_info = running_threads[vimid]
+ if not thread_info \
+ or not thread_info.get('vservers') \
+ or not thread_info.get('vservers').get(vserverid):
+ status_code = status.HTTP_204_NO_CONTENT
+ content = {'error':
+ 'Guest Monitor job is not created for this virtual server,\
+ vim id: %s, vserver id: %s'
+ % (self.vimid, vserverid)}
+ pass
+ elif thread_info['state'] == 'error':
+ status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
+ content = {'error':
+ 'Guest Monitor job for this virtual server \
+ (vim id: %s, vserver id: %s) failed due to: %s'
+ % (self.vimid, vserverid, thread_info.get('message'))}
+ pass
+ else:
+ vserverinfo = thread_info.get('vservers').get(vserverid)
+ content = vserverinfo.get('message')
+ status_code = vserverinfo.get('status') or status.HTTP_200_OK
+ pass
+
+ #return Response(status=status.HTTP_202_ACCEPTED)
+ return Response(status=status_code, data=content)
+
+ except VimDriverNewtonException as e:
+ return Response(data={'error': e.content}, status=e.status_code)
+ except HttpError as e:
+ self._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:
+ self._logger.error(traceback.format_exc())
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+
+ def DELETE(self, request, vimid="", vserverid=""):
+ '''Stop guest monitoring on specified virtual server'''
+ self._logger.debug("GuestMonitor--delete::data> %s" % request.data)
+ self._logger.debug("GuestMonitor--delete::vimid > %s" % vimid)
+
+ try:
+ # populate proxy identity url
+ cloud_owner, cloud_region_id = extsys.decode_vim_id(vimid)
+
+ tenant_name = request.data.get('tenantName')
+ tenant_id = request.data.get('tenantID')
+
+ # prepare request resource to vim instance
+ # get token:
+ viminfo = VimDriverUtils.get_vim_info(vimid)
+ # the tenant should have the privilege to access the event-log API
+ # usually it is 'admin'. Otherwise the 403 will be returned.
+ sess = None
+ if tenant_id:
+ sess = VimDriverUtils.get_session(viminfo, tenantid=tenant_id)
+ else:
+ sess = VimDriverUtils.get_session(viminfo, tenantname=tenant_name)
+
+ #now try to convert tenant_name to tenant_id, and vserver_name to vserver_id
+ #tbd
+
+ thread_info = running_threads[vimid]
+ if not thread_info:
+ status_code = status.HTTP_204_NO_CONTENT
+ else:
+ vservers = thread_info.get('vservers')
+ if vservers.get(vserverid):
+ vservers.pop(vserverid)
+
+ running_thread_lock.acquire()
+ if len(vservers.items()) == 0:
+ thread_info.stop()
+ running_threads.pop(vimid)
+ running_thread_lock.release()
+ status_code = status.HTTP_202_ACCEPTED
+
+ return Response(status=status_code)
+
+ except VimDriverNewtonException as e:
+ return Response(data={'error': e.content}, status=e.status_code)
+ except HttpError as e:
+ self._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:
+ self._logger.error(traceback.format_exc())
+ return Response(data={'error': str(e)},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR) \ No newline at end of file
diff --git a/windriver/titanium_cloud/proxy/__init__.py b/windriver/titanium_cloud/proxy/__init__.py
new file mode 100644
index 00000000..802f3fba
--- /dev/null
+++ b/windriver/titanium_cloud/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/windriver/titanium_cloud/proxy/urls.py b/windriver/titanium_cloud/proxy/urls.py
new file mode 100644
index 00000000..f848e76c
--- /dev/null
+++ b/windriver/titanium_cloud/proxy/urls.py
@@ -0,0 +1,32 @@
+# 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 titanium_cloud.proxy.views import identityV3
+from titanium_cloud.proxy.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/(?: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/windriver/titanium_cloud/proxy/views/__init__.py b/windriver/titanium_cloud/proxy/views/__init__.py
new file mode 100644
index 00000000..802f3fba
--- /dev/null
+++ b/windriver/titanium_cloud/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/windriver/titanium_cloud/proxy/views/identityV3.py b/windriver/titanium_cloud/proxy/views/identityV3.py
new file mode 100644
index 00000000..a6efa6ac
--- /dev/null
+++ b/windriver/titanium_cloud/proxy/views/identityV3.py
@@ -0,0 +1,27 @@
+# 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
+
+from titanium_cloud.pub.config import config
+from newton.proxy.views import identityV3 as newton_identityV3
+
+logger = logging.getLogger(__name__)
+
+DEBUG=True
+
+class Tokens(newton_identityV3.Tokens):
+
+ def __init__(self):
+ self.proxy_prefix = config.MULTICLOUD_PREFIX
+ self._logger = logger
diff --git a/windriver/titanium_cloud/proxy/views/services.py b/windriver/titanium_cloud/proxy/views/services.py
new file mode 100644
index 00000000..9bd5cc4e
--- /dev/null
+++ b/windriver/titanium_cloud/proxy/views/services.py
@@ -0,0 +1,45 @@
+# 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
+
+from rest_framework import status
+
+from titanium_cloud.pub.config import config
+from newton.proxy.views import services as newton_services
+
+logger = logging.getLogger(__name__)
+
+DEBUG=True
+
+class Services(newton_services.Services):
+
+ def __init__(self):
+ self._logger = logger
+
+
+class GetTenants(newton_services.GetTenants):
+ '''
+ Backward compatible API for /v2.0/tenants
+ '''
+
+ def __init__(self):
+ self._logger = logger
+
+ def get(self, request, vimid="", servicetype="identity", requri='v3/projects'):
+ self._logger.debug("GetTenants--get::META> %s" % request.META)
+ self._logger.debug("GetTenants--get::data> %s" % request.data)
+ self._logger.debug("GetTenants--get::vimid, servicetype, requri> %s,%s,%s"
+ % (vimid, servicetype, requri))
+
+ return super(GetTenants,self).get(request, vimid, servicetype, requri)
diff --git a/windriver/titanium_cloud/pub/__init__.py b/windriver/titanium_cloud/pub/__init__.py
new file mode 100644
index 00000000..802f3fba
--- /dev/null
+++ b/windriver/titanium_cloud/pub/__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/windriver/titanium_cloud/pub/config/__init__.py b/windriver/titanium_cloud/pub/config/__init__.py
new file mode 100644
index 00000000..802f3fba
--- /dev/null
+++ b/windriver/titanium_cloud/pub/config/__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/windriver/titanium_cloud/pub/config/config.py b/windriver/titanium_cloud/pub/config/config.py
new file mode 100644
index 00000000..bc7e8553
--- /dev/null
+++ b/windriver/titanium_cloud/pub/config/config.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.
+
+import os
+
+# [MSB]
+MSB_SERVICE_ADDR = '127.0.0.1'
+MSB_SERVICE_PORT = '80'
+
+#[Multicloud]
+MULTICLOUD_PREFIX = "http://%s:%s/api/multicloud-titanium_cloud/v0" %(MSB_SERVICE_ADDR, MSB_SERVICE_PORT)
+
+# [A&AI]
+AAI_ADDR = "aai.api.simpledemo.openecomp.org"
+AAI_PORT = "8443"
+AAI_SERVICE_URL = 'https://%s:%s/aai' % (AAI_ADDR, AAI_PORT)
+AAI_SCHEMA_VERSION = "v11"
+AAI_USERNAME = 'AAI'
+AAI_PASSWORD = 'AAI'
+
+AAI_BASE_URL = "%s/%s" % (AAI_SERVICE_URL, AAI_SCHEMA_VERSION)
+
+MULTICLOUD_APP_ID = 'MultiCloud-Titanium_Cloud'
+
+# [IMAGE LOCAL PATH]
+ROOT_PATH = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
diff --git a/windriver/titanium_cloud/registration/__init__.py b/windriver/titanium_cloud/registration/__init__.py
new file mode 100644
index 00000000..802f3fba
--- /dev/null
+++ b/windriver/titanium_cloud/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/windriver/titanium_cloud/registration/views/__init__.py b/windriver/titanium_cloud/registration/views/__init__.py
new file mode 100644
index 00000000..802f3fba
--- /dev/null
+++ b/windriver/titanium_cloud/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/windriver/titanium_cloud/registration/views/registration.py b/windriver/titanium_cloud/registration/views/registration.py
new file mode 100644
index 00000000..e58e170b
--- /dev/null
+++ b/windriver/titanium_cloud/registration/views/registration.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.
+import logging
+
+from titanium_cloud.pub.config import config
+
+from newton.registration.views import registration as newton_registration
+
+logger = logging.getLogger(__name__)
+
+DEBUG=True
+
+class Registry(newton_registration.Registry):
+
+ def __init__(self):
+ self.proxy_prefix = config.MULTICLOUD_PREFIX
+ self._logger = logger
diff --git a/windriver/titanium_cloud/requests/__init__.py b/windriver/titanium_cloud/requests/__init__.py
new file mode 100644
index 00000000..48b6e44b
--- /dev/null
+++ b/windriver/titanium_cloud/requests/__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/windriver/titanium_cloud/requests/urls.py b/windriver/titanium_cloud/requests/urls.py
new file mode 100644
index 00000000..69f0e444
--- /dev/null
+++ b/windriver/titanium_cloud/requests/urls.py
@@ -0,0 +1,47 @@
+# 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 newton.requests.views import network
+from newton.requests.views import subnet
+from newton.requests.views import image
+from newton.requests.views import volume
+from newton.requests.views import server
+from newton.requests.views import vport
+from newton.requests.views import limits
+from newton.requests.views import hosts
+from newton.requests.views import flavor
+
+urlpatterns = [
+ url(r'^networks(/(?P<networkid>[0-9a-zA-Z_-]+))?',
+ network.Networks.as_view()),
+ url(r'^subnets(/(?P<subnetid>[0-9a-zA-Z_-]+))?',
+ subnet.Subnets.as_view()),
+ url(r'^images(/(?P<imageid>[0-9a-zA-Z_-]+))?',
+ image.Images.as_view()),
+ url(r'^volumes(/(?P<volumeid>[0-9a-zA-Z_-]+))?',
+ volume.Volumes.as_view()),
+ url(r'^servers(/(?P<serverid>[0-9a-zA-Z_-]+))?',
+ server.Servers.as_view()),
+ url(r'^ports(/(?P<portid>[0-9a-zA-Z_-]+))?',
+ vport.Vports.as_view()),
+ url(r'^flavors(/(?P<flavorid>[0-9a-zA-Z_-]+))?',
+ flavor.Flavors.as_view()),
+ url(r'^limits$', limits.Limits.as_view()),
+ url(r'^hosts(/(?P<hostname>[0-9a-zA-Z_-]+))?', hosts.Hosts.as_view()),
+]
+
+urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/windriver/titanium_cloud/samples/__init__.py b/windriver/titanium_cloud/samples/__init__.py
new file mode 100644
index 00000000..802f3fba
--- /dev/null
+++ b/windriver/titanium_cloud/samples/__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/windriver/titanium_cloud/samples/tests.py b/windriver/titanium_cloud/samples/tests.py
new file mode 100644
index 00000000..d419efa5
--- /dev/null
+++ b/windriver/titanium_cloud/samples/tests.py
@@ -0,0 +1,29 @@
+# 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.
+
+import unittest
+import json
+from django.test import Client
+from rest_framework import status
+
+
+class SampleViewTest(unittest.TestCase):
+ def setUp(self):
+ self.client = Client()
+
+ def tearDown(self):
+ pass
+
+ def test_sample(self):
+ response = self.client.get("/samples/")
+ self.assertEqual(status.HTTP_200_OK, response.status_code, response.content)
+ resp_data = response.json()
+ self.assertEqual({"status": "active"}, resp_data)
diff --git a/windriver/titanium_cloud/samples/urls.py b/windriver/titanium_cloud/samples/urls.py
new file mode 100644
index 00000000..ae67a819
--- /dev/null
+++ b/windriver/titanium_cloud/samples/urls.py
@@ -0,0 +1,16 @@
+# 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.
+
+from django.conf.urls import url
+from titanium_cloud.samples import views
+
+urlpatterns = [
+ url(r'^samples/?$', views.SampleList.as_view()), ]
diff --git a/windriver/titanium_cloud/samples/views.py b/windriver/titanium_cloud/samples/views.py
new file mode 100644
index 00000000..e51044ad
--- /dev/null
+++ b/windriver/titanium_cloud/samples/views.py
@@ -0,0 +1,26 @@
+# 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.
+
+import logging
+
+from rest_framework.views import APIView
+from rest_framework.response import Response
+
+logger = logging.getLogger(__name__)
+
+
+class SampleList(APIView):
+ """
+ List all samples.
+ """
+ def get(self, request, format=None):
+ logger.debug("get")
+ return Response({"status": "active"})
diff --git a/windriver/titanium_cloud/settings.py b/windriver/titanium_cloud/settings.py
new file mode 100644
index 00000000..393f994e
--- /dev/null
+++ b/windriver/titanium_cloud/settings.py
@@ -0,0 +1,122 @@
+# 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.
+
+import os
+import sys
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = '3o-wney!99y)^h3v)0$j16l9=fdjxcb+a8g+q3tfbahcnu2b0o'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+# Application definition
+
+INSTALLED_APPS = [
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ 'rest_framework',
+]
+
+MIDDLEWARE_CLASSES = [
+ 'django.middleware.security.SecurityMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'titanium_cloud.urls'
+
+WSGI_APPLICATION = 'titanium_cloud.wsgi.application'
+
+REST_FRAMEWORK = {
+ 'DEFAULT_RENDERER_CLASSES': (
+ 'rest_framework.renderers.JSONRenderer',
+ ),
+
+ 'DEFAULT_PARSER_CLASSES': (
+ 'rest_framework.parsers.JSONParser',
+ 'rest_framework.parsers.MultiPartParser',
+ # 'rest_framework.parsers.FormParser',
+ # 'rest_framework.parsers.FileUploadParser',
+ )
+}
+
+TIME_ZONE = 'UTC'
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/1.6/howto/static-files/
+
+STATIC_URL = '/static/'
+
+LOGGING = {
+ 'version': 1,
+ 'disable_existing_loggers': True,
+ 'formatters': {
+ 'standard': {
+ 'format': '%(asctime)s:[%(name)s]:[%(filename)s]-[%(lineno)d] [%(levelname)s]:%(message)s',
+ },
+ },
+ 'filters': {
+ },
+ 'handlers': {
+ 'titanium_cloud_handler': {
+ 'level': 'DEBUG',
+ 'class': 'logging.handlers.RotatingFileHandler',
+ 'filename': os.path.join(BASE_DIR, 'logs/runtime_titanium_cloud.log'),
+ 'formatter': 'standard',
+ 'maxBytes': 1024 * 1024 * 50,
+ 'backupCount': 5,
+ },
+ },
+
+ 'loggers': {
+ 'titanium_cloud': {
+ 'handlers': ['titanium_cloud_handler'],
+ 'level': 'DEBUG',
+ 'propagate': False
+ },
+ }
+}
+
+CACHES = {
+ 'default': {
+ 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
+ 'LOCATION': '127.0.0.1:11211',
+ }
+}
+
+if 'test' in sys.argv:
+ from titanium_cloud.pub.config import config
+
+ REST_FRAMEWORK = {}
+ import platform
+
+ if platform.system() == 'Linux':
+ TEST_RUNNER = 'xmlrunner.extra.djangotestrunner.XMLTestRunner'
+ TEST_OUTPUT_VERBOSE = True
+ TEST_OUTPUT_DESCRIPTIONS = True
+ TEST_OUTPUT_DIR = 'test-reports'
diff --git a/windriver/titanium_cloud/swagger/__init__.py b/windriver/titanium_cloud/swagger/__init__.py
new file mode 100644
index 00000000..802f3fba
--- /dev/null
+++ b/windriver/titanium_cloud/swagger/__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/windriver/titanium_cloud/swagger/tests.py b/windriver/titanium_cloud/swagger/tests.py
new file mode 100644
index 00000000..ea9c9e50
--- /dev/null
+++ b/windriver/titanium_cloud/swagger/tests.py
@@ -0,0 +1,29 @@
+# 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.
+
+import unittest
+import json
+from django.test import Client
+from rest_framework import status
+
+
+class SampleViewTest(unittest.TestCase):
+ def setUp(self):
+ self.client = Client()
+
+ def tearDown(self):
+ pass
+
+ def test_sample(self):
+ response = self.client.get("/api/multicloud-titanium_cloud/v0/swagger.json")
+ self.assertEqual(status.HTTP_200_OK, response.status_code, response.content)
+# resp_data = response.json()
+# self.assertEqual({"status": "active"}, resp_data)
diff --git a/windriver/titanium_cloud/swagger/urls.py b/windriver/titanium_cloud/swagger/urls.py
new file mode 100644
index 00000000..21ef4bde
--- /dev/null
+++ b/windriver/titanium_cloud/swagger/urls.py
@@ -0,0 +1,21 @@
+# 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.
+
+from django.conf.urls import patterns, url
+from rest_framework.urlpatterns import format_suffix_patterns
+
+from titanium_cloud.swagger.views import SwaggerJsonView
+
+urlpatterns = [
+ url(r'^api/multicloud-titanium_cloud/v0/swagger.json$', SwaggerJsonView.as_view()),
+]
+
+urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/windriver/titanium_cloud/swagger/views.py b/windriver/titanium_cloud/swagger/views.py
new file mode 100644
index 00000000..01f9374e
--- /dev/null
+++ b/windriver/titanium_cloud/swagger/views.py
@@ -0,0 +1,45 @@
+# 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.
+
+import json
+import logging
+import os
+import traceback
+
+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.swagger import views as newton_json_view
+
+logger = logging.getLogger(__name__)
+
+
+class SwaggerJsonView(newton_json_view.SwaggerJsonView):
+
+ def get(self, request):
+ '''
+ reuse newton code and update the basePath
+ :param request:
+ :return:
+ '''
+
+ resp = super(SwaggerJsonView,self).get(request)
+ json_data = resp.data if resp else None
+ if json_data:
+ json_data["basePath"] = "/api/multicloud-titanium_cloud/v0/"
+ json_data["info"]["title"] = "Service NBI of MultiCloud plugin for OpenStack Newton"
+ return Response(data=json_data, status=200)
+ else:
+ return Response(data={'error':'internal error'}, status=500)
+
+
diff --git a/windriver/titanium_cloud/urls.py b/windriver/titanium_cloud/urls.py
new file mode 100644
index 00000000..664d8b3e
--- /dev/null
+++ b/windriver/titanium_cloud/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.
+
+from django.conf.urls import include, url
+
+from titanium_cloud.registration.views import registration
+from newton.requests.views import tenants
+
+urlpatterns = [
+ url(r'^', include('titanium_cloud.swagger.urls')),
+ url(r'^', include('titanium_cloud.samples.urls')),
+ url(r'^api/multicloud-titanium_cloud/v0/(?P<vimid>[0-9a-zA-Z_-]+)/registry/?$',
+ registration.Registry.as_view()),
+ url(r'^api/multicloud-titanium_cloud/v0/(?P<vimid>[0-9a-zA-Z_-]+)/?$',
+ registration.Registry.as_view()),
+ url(r'^api/multicloud-titanium_cloud/v0/(?P<vimid>[0-9a-zA-Z_-]+)/exten',
+ include('titanium_cloud.extensions.urls')),
+ url(r'^api/multicloud-titanium_cloud/v0/(?P<vimid>[0-9a-zA-Z_-]+)/',
+ include('titanium_cloud.proxy.urls')),
+ url(r'^api/multicloud-titanium_cloud/v0/(?P<vimid>[0-9a-zA-Z_-]+)/tenants/?$',
+ tenants.Tenants.as_view()),
+ url(r'^api/multicloud-titanium_cloud/v0/(?P<vimid>[0-9a-zA-Z_-]+)/'
+ '(?P<tenantid>[0-9a-zA-Z_-]{8,})/', include('titanium_cloud.requests.urls')),
+]
+
+
diff --git a/windriver/titanium_cloud/wsgi.py b/windriver/titanium_cloud/wsgi.py
new file mode 100644
index 00000000..2962328d
--- /dev/null
+++ b/windriver/titanium_cloud/wsgi.py
@@ -0,0 +1,19 @@
+# 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.
+
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "titanium_cloud.settings")
+
+application = get_wsgi_application()
diff --git a/windriver/tox.ini b/windriver/tox.ini
new file mode 100644
index 00000000..764cf01c
--- /dev/null
+++ b/windriver/tox.ini
@@ -0,0 +1,14 @@
+[tox]
+envlist = py27,py35
+skipsdist = true
+
+[tox:jenkins]
+downloadcache = ~/cache/pip
+
+[testenv]
+setenv =
+ PYTHONPATH = {toxinidir}/../newton
+deps = -r{toxinidir}/requirements.txt
+commands = coverage run --branch manage.py test titanium_cloud
+ coverage html --omit=".tox*,*test*,*__init__.py" -d htmlcov
+