diff options
-rw-r--r-- | newton/newton/pub/msapi/extsys.py | 39 | ||||
-rw-r--r-- | newton/newton/pub/tests/__init__.py | 0 | ||||
-rw-r--r-- | newton/newton/pub/tests/test_extsys.py | 111 | ||||
-rw-r--r-- | newton/newton/pub/tests/test_restcall.py | 110 | ||||
-rw-r--r-- | newton/newton/pub/utils/restcall.py | 34 |
5 files changed, 251 insertions, 43 deletions
diff --git a/newton/newton/pub/msapi/extsys.py b/newton/newton/pub/msapi/extsys.py index 76066991..aa6a159c 100644 --- a/newton/newton/pub/msapi/extsys.py +++ b/newton/newton/pub/msapi/extsys.py @@ -13,9 +13,8 @@ import json import logging import re -from rest_framework import status from newton.pub.exceptions import VimDriverNewtonException -from newton.pub.utils.restcall import req_by_msb,req_to_aai +from newton.pub.utils import restcall logger = logging.getLogger(__name__) @@ -26,7 +25,7 @@ def get_vim_by_id(vim_id): if cloud_owner and cloud_region_id: retcode, content, status_code = \ - req_to_aai("/cloud-infrastructure/cloud-regions/cloud-region/%s/%s" + restcall.req_to_aai("/cloud-infrastructure/cloud-regions/cloud-region/%s/%s" % (cloud_owner,cloud_region_id),"GET") if retcode != 0: logger.error("Status code is %s, detail is %s.", status_code, content) @@ -37,10 +36,9 @@ def get_vim_by_id(vim_id): #assume esr-system-info-id is composed by {cloud-owner} _ {cloud-region-id} retcode2,content2,status_code2 = \ - req_to_aai("/cloud-infrastructure/cloud-regions/cloud-region/%s/%s" - + "/esr-system-info-list/esr-system-info/%s_%s" \ - % (cloud_owner,cloud_region_id,cloud_owner,cloud_region_id), - "GET") + restcall.req_to_aai(("/cloud-infrastructure/cloud-regions/cloud-region/%(owner)s/%(region)s" + "/esr-system-info-list/esr-system-info/%(owner)s_%(region)s" % { + "owner": cloud_owner, "region": cloud_region_id}), "GET") if retcode2 != 0: logger.error("Status code is %s, detail is %s.", status_code, content) raise VimDriverNewtonException( @@ -49,8 +47,7 @@ def get_vim_by_id(vim_id): tmp_authinfo = json.JSONDecoder().decode(content2) #convert vim information - - if tmp_viminfo: + if tmp_viminfo and tmp_authinfo: viminfo = {} viminfo['vimId'] = vim_id viminfo['cloud_owner'] = cloud_owner @@ -61,28 +58,22 @@ def get_vim_by_id(vim_id): viminfo['cloud_extra_info'] = tmp_viminfo['cloud-extra-info'] viminfo['cloud_epa_caps'] = tmp_viminfo['cloud-epa-caps'] - if tmp_authinfo: - viminfo['userName'] = tmp_authinfo['user-name'] - viminfo['password'] = tmp_authinfo['password'] - viminfo['domain'] = tmp_authinfo['cloud-domain'] - viminfo['url'] = tmp_authinfo['service-url'] - viminfo['tenant'] = tmp_authinfo['default-tenant'] - viminfo['cacert'] = tmp_authinfo['ssl-cacert'] - viminfo['insecure'] = tmp_authinfo['ssl-insecure'] - else: - return None + viminfo['userName'] = tmp_authinfo['user-name'] + viminfo['password'] = tmp_authinfo['password'] + viminfo['domain'] = tmp_authinfo['cloud-domain'] + viminfo['url'] = tmp_authinfo['service-url'] + viminfo['tenant'] = tmp_authinfo['default-tenant'] + viminfo['cacert'] = tmp_authinfo['ssl-cacert'] + viminfo['insecure'] = tmp_authinfo['ssl-insecure'] return viminfo - else: - return None - else: - return None + return None def delete_vim_by_id(vim_id): cloud_owner, cloud_region_id = decode_vim_id(vim_id) if cloud_owner and cloud_region_id: retcode, content, status_code = \ - req_to_aai("/cloud-infrastructure/cloud-regions/cloud-region/%s/%s" + restcall.req_to_aai("/cloud-infrastructure/cloud-regions/cloud-region/%s/%s" % ( cloud_owner, cloud_region_id), "DELETE") if retcode != 0: logger.error("Status code is %s, detail is %s.", status_code, content) diff --git a/newton/newton/pub/tests/__init__.py b/newton/newton/pub/tests/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/newton/newton/pub/tests/__init__.py diff --git a/newton/newton/pub/tests/test_extsys.py b/newton/newton/pub/tests/test_extsys.py new file mode 100644 index 00000000..5ddbbcba --- /dev/null +++ b/newton/newton/pub/tests/test_extsys.py @@ -0,0 +1,111 @@ +# 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 +import six +import unittest + +from newton.pub.exceptions import VimDriverNewtonException +from newton.pub.msapi import extsys +from newton.pub.utils import restcall + +MOCK_VIM_INFO = { + "cloud-type": "openstack", + "complex-name": "complex", + "cloud-region-version": "Regionv1", + "cloud-extra-info": "type", + "cloud-epa-caps": "epa" +} + +MOCK_ESR_SYSTEM_INFO = { + "user-name": "test", + "password": "secret", + "cloud-domain": "default", + "service-url": "http://localhost", + "default-tenant": "demo", + "ssl-cacert": None, + "ssl-insecure": None +} + + +def returnList(items): + def func(): + for item in items: + yield item + yield mock.DEFAULT + + generator = func() + + def effect(*args, **kwargs): + return six.next(generator) + + return effect + + +class TestEpaCaps(unittest.TestCase): + cloud_onwer = "windriver-hudson-cd" + cloud_region_id = "RegionOne" + vim_id = cloud_onwer + "_" + cloud_region_id + + def setUp(self): + self.req_to_aai_backup = restcall.req_to_aai + + def tearDown(self): + restcall.req_to_aai = self.req_to_aai_backup + + def test_get_vim_by_id(self): + values = [ + (1, "test_content", 500), # Failure first call + (0, json.dumps(MOCK_VIM_INFO), None), (1, "test_content", 500), # Failure second call + (0, json.dumps(MOCK_VIM_INFO), None), (0, json.dumps(MOCK_ESR_SYSTEM_INFO), None) # Success calls + ] + + restcall.req_to_aai = mock.Mock(side_effect=returnList(values)) + self.assertRaises(VimDriverNewtonException, extsys.get_vim_by_id, self.vim_id) + restcall.req_to_aai.assert_called_once() + + self.assertRaises(VimDriverNewtonException, extsys.get_vim_by_id, self.vim_id) + + viminfo = extsys.get_vim_by_id(self.vim_id) + self.assertIsNotNone(viminfo) + self.assertEquals(self.vim_id, viminfo['vimId']) + self.assertEquals(self.cloud_onwer, viminfo['cloud_owner']) + self.assertEquals(self.cloud_region_id, viminfo['cloud_region_id']) + self.assertEquals(MOCK_VIM_INFO['cloud-type'], viminfo['type']) + self.assertEquals(MOCK_VIM_INFO['complex-name'], viminfo['name']) + self.assertEquals(MOCK_VIM_INFO['cloud-region-version'], viminfo['version']) + self.assertEquals(MOCK_VIM_INFO['cloud-extra-info'], viminfo['cloud_extra_info']) + self.assertEquals(MOCK_VIM_INFO['cloud-epa-caps'], viminfo['cloud_epa_caps']) + + self.assertEquals(MOCK_ESR_SYSTEM_INFO['user-name'], viminfo['userName']) + self.assertEquals(MOCK_ESR_SYSTEM_INFO['password'], viminfo['password']) + self.assertEquals(MOCK_ESR_SYSTEM_INFO['cloud-domain'], viminfo['domain']) + self.assertEquals(MOCK_ESR_SYSTEM_INFO['service-url'], viminfo['url']) + self.assertEquals(MOCK_ESR_SYSTEM_INFO['default-tenant'], viminfo['tenant']) + self.assertEquals(MOCK_ESR_SYSTEM_INFO['ssl-cacert'], viminfo['cacert']) + self.assertEquals(MOCK_ESR_SYSTEM_INFO['ssl-insecure'], viminfo['insecure']) + + def test_delete_vim_by_id(self): + values = [(1, "test_content", 500),(0, None, None)] + + restcall.req_to_aai = mock.Mock(side_effect=returnList(values)) + self.assertRaises(VimDriverNewtonException, extsys.delete_vim_by_id, self.vim_id) + self.assertEquals(0, extsys.delete_vim_by_id(self.vim_id)) + + def test_decode_vim_id_successfuly(self): + owner, region_id = extsys.decode_vim_id(self.vim_id) + self.assertEquals(self.cloud_onwer, owner) + self.assertEquals(self.cloud_region_id, region_id)
\ No newline at end of file diff --git a/newton/newton/pub/tests/test_restcall.py b/newton/newton/pub/tests/test_restcall.py new file mode 100644 index 00000000..28def73f --- /dev/null +++ b/newton/newton/pub/tests/test_restcall.py @@ -0,0 +1,110 @@ +# 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 httplib2 import Http +import mock +from rest_framework import status +import unittest + +from newton.pub.utils import restcall + + +class TestRestCall(unittest.TestCase): + base_url = "http://localhost" + resource = "compute" + + @mock.patch.object(Http, 'request') + def test_unknown_failure_call_req(self, mock_http): + mock_http.raiseError.side_effect = mock.Mock( + side_effect=Exception('Test')) + args = [ + self.base_url, "user", "password", "auth_type", + self.resource, "get", {"extra": "test"} + ] + + ret = restcall._call_req(*args) + self.assertEquals(3, ret[0]) + self.assertEquals(status.HTTP_500_INTERNAL_SERVER_ERROR, ret[2]) + + + @mock.patch.object(Http, 'request') + def test_invalid_output_call_req(self, mock_http): + args = [ + self.base_url, "user", "password", "auth_type", + self.resource, "get", {"extra": "test"} + ] + + mock_http.return_value = ({'status': None}, + str.encode("test", 'utf-8')) + + ret = restcall._call_req(*args) + self.assertEquals(1, ret[0]) + self.assertEquals("test", ret[1]) + self.assertIsNone(ret[2]) + + @mock.patch.object(Http, 'request') + def test_req_by_msb(self, mock_http): + resp_body = "test_body" + resp_status=status.HTTP_200_OK + mock_http.return_value = ( + {'status': resp_status}, + str.encode(resp_body, 'utf-8')) + + + ret = restcall.req_by_msb(self.resource, "delete") + self.assertEquals(0, ret[0]) + self.assertEquals(resp_body, ret[1]) + self.assertEquals(resp_status, ret[2]) + + @mock.patch.object(Http, 'request') + def test_req_to_vim(self, mock_http): + resp_body = "test_body" + resp_status=status.HTTP_200_OK + mock_http.return_value = ( + {'status': resp_status}, + str.encode(resp_body, 'utf-8')) + + ret = restcall.req_to_vim(self.base_url, self.resource, "get") + self.assertEquals(0, ret[0]) + self.assertEquals(resp_body, ret[1]) + self.assertEquals(resp_status, ret[2]) + + @mock.patch.object(Http, 'request') + def test_req_to_aai(self, mock_http): + resp_body = "test_body" + resp_status=status.HTTP_200_OK + mock_http.return_value = ( + {'status': resp_status}, + str.encode(resp_body, 'utf-8')) + + ret = restcall.req_to_aai(self.resource, "post") + self.assertEquals(0, ret[0]) + self.assertEquals(resp_body, ret[1]) + self.assertEquals(resp_status, ret[2]) + + def test_combine_url(self): + self.assertEquals(self.base_url, + restcall._combine_url(self.base_url, "")) + self.assertEquals(self.base_url + "/" + self.resource, + restcall._combine_url(self.base_url + "/", + "/" + self.resource)) + self.assertEquals(self.base_url + "/" + self.resource, + restcall._combine_url(self.base_url + "/", + self.resource)) + self.assertEquals(self.base_url + "/" + self.resource, + restcall._combine_url(self.base_url, + "/" + self.resource)) + self.assertEquals(self.base_url + "/" + self.resource, + restcall._combine_url(self.base_url, + self.resource)) diff --git a/newton/newton/pub/utils/restcall.py b/newton/newton/pub/utils/restcall.py index a2838680..6444014d 100644 --- a/newton/newton/pub/utils/restcall.py +++ b/newton/newton/pub/utils/restcall.py @@ -9,13 +9,13 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -import sys +import codecs import json import traceback +import sys + import logging from six.moves import urllib -import uuid -from six.moves import http_client import httplib2 import uuid @@ -32,15 +32,13 @@ MAX_RETRY_TIME = 3 logger = logging.getLogger(__name__) -def call_req(base_url, user, passwd, auth_type, +def _call_req(base_url, user, passwd, auth_type, resource, method, extra_headers='', content=''): callid = str(uuid.uuid1()) -# logger.debug("[%s]call_req('%s','%s','%s',%s,'%s','%s','%s')" % ( -# callid, base_url, user, passwd, auth_type, resource, method, content)) ret = None resp_status = None try: - full_url = combine_url(base_url, resource) + full_url = _combine_url(base_url, resource) headers = { 'content-type': 'application/json', 'accept': 'application/json' @@ -50,7 +48,8 @@ def call_req(base_url, user, passwd, auth_type, headers.update(extra_headers) if user: headers['Authorization'] = \ - 'Basic ' + ('%s:%s' % (user, passwd)).encode("base64") + 'Basic ' + str(codecs.encode('%s:%s' % (user, passwd), "ascii")) + ca_certs = None for retry_times in range(MAX_RETRY_TIME): http = httplib2.Http( @@ -63,9 +62,8 @@ def call_req(base_url, user, passwd, auth_type, body=content, headers=headers) resp_status, resp_body = \ - resp['status'], resp_content.decode('UTF-8') -# logger.debug("[%s][%d]status=%s,resp_body=%s)" % -# (callid, retry_times, resp_status, resp_body)) + resp['status'], codecs.decode( + resp_content, 'UTF-8') if resp_status in status_ok_list: ret = [0, resp_body, resp_status] else: @@ -80,7 +78,7 @@ def call_req(base_url, user, passwd, auth_type, raise ex except urllib.error.URLError as err: ret = [2, str(err), resp_status] - except Exception as ex: + except Exception: logger.error(traceback.format_exc()) logger.error("[%s]ret=%s" % (callid, str(sys.exc_info()))) if not resp_status: @@ -89,22 +87,20 @@ def call_req(base_url, user, passwd, auth_type, except: logger.error(traceback.format_exc()) ret = [4, str(sys.exc_info()), resp_status] - -# logger.debug("[%s]ret=%s" % (callid, str(ret))) return ret def req_by_msb(resource, method, content=''): base_url = "http://%s:%s/" % (config.MSB_SERVICE_ADDR, config.MSB_SERVICE_PORT) -# logger.debug("requests--get::> %s" % "33") - return call_req(base_url, "", "", rest_no_auth, + return _call_req(base_url, "", "", rest_no_auth, resource, method, "", content) def req_to_vim(base_url, resource, method, extra_headers='', content=''): - return call_req(base_url, "", "", rest_no_auth, + return _call_req(base_url, "", "", rest_no_auth, resource, method, extra_headers, content) + def req_to_aai(resource, method, content='', appid=config.MULTICLOUD_APP_ID): tmp_trasaction_id = str(uuid.uuid1()) headers = { @@ -115,11 +111,11 @@ def req_to_aai(resource, method, content='', appid=config.MULTICLOUD_APP_ID): } logger.debug("req_to_aai--%s::> %s, %s" % (tmp_trasaction_id, method, resource)) - return call_req(config.AAI_BASE_URL, config.AAI_USERNAME, config.AAI_PASSWORD, rest_no_auth, + return _call_req(config.AAI_BASE_URL, config.AAI_USERNAME, config.AAI_PASSWORD, rest_no_auth, resource, method, content=json.dumps(content), extra_headers=headers) -def combine_url(base_url, resource): +def _combine_url(base_url, resource): full_url = None if not resource: |