diff --git a/orm/common/client/keystone/keystone_utils/tests/__init__.py b/orm/common/client/keystone/keystone_utils/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/orm/common/client/keystone/keystone_utils/tests/unit/__init__.py b/orm/common/client/keystone/keystone_utils/tests/unit/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/orm/common/client/keystone/keystone_utils/tests/unit/test_tokens.py b/orm/common/client/keystone/keystone_utils/tests/unit/test_tokens.py new file mode 100755 index 00000000..a38479f9 --- /dev/null +++ b/orm/common/client/keystone/keystone_utils/tests/unit/test_tokens.py @@ -0,0 +1,219 @@ +"""keystone_utils token validator unittests.""" +import mock +import unittest + +from keystone_utils import tokens + + +class MyResponse(object): + def __init__(self, status, json_result): + self.status_code = status + self._json_result = json_result + + def json(self): + return self._json_result + + +class MyKeystone(object): + def validate(self, a): + raise tokens.v3_client.exceptions.NotFound('test') + + def find(self, **kwargs): + raise tokens.v3_client.exceptions.NotFound('test') + + +class MyClient(object): + def __init__(self, set_tokens=True): + if set_tokens: + self.tokens = MyKeystone() + else: + self.tokens = mock.MagicMock() + + self.roles = MyKeystone() + + +class TokensTest(unittest.TestCase): + def setUp(self): + tokens._KEYSTONES = {} + + @mock.patch.object(tokens.requests, 'get', return_value=MyResponse( + tokens.OK_CODE, {'regions': [{'endpoints': [{'publicURL': 'test', + 'type': 'identity'}]}]})) + def test_find_keystone_ep_sanity(self, mock_get): + result = tokens._find_keystone_ep('a', 'b') + self.assertEqual(result, 'test') + + @mock.patch.object(tokens.requests, 'get', return_value=MyResponse( + tokens.OK_CODE + 1, {'regions': [{'endpoints': [ + {'publicURL': 'test', 'type': 'identity'}]}]})) + def test_find_keystone_ep_bad_return_code(self, mock_get): + result = tokens._find_keystone_ep('a', 'b') + self.assertIsNone(result) + + @mock.patch.object(tokens.requests, 'get', return_value=MyResponse( + tokens.OK_CODE, {})) + def test_find_keystone_ep_no_keystone_ep_in_response(self, mock_get): + result = tokens._find_keystone_ep('a', 'b') + self.assertIsNone(result) + + @mock.patch.object(tokens.requests, 'get', return_value=MyResponse( + tokens.OK_CODE, {'regions': [{'endpoints': [{'publicURL': 'test', + 'type': 'test'}]}]})) + def test_find_keystone_ep_no_identity_in_response(self, mock_get): + result = tokens._find_keystone_ep('a', 'b') + self.assertIsNone(result) + + @mock.patch.object(tokens.requests, 'get', return_value=MyResponse( + tokens.OK_CODE, {'regions': [{'endpoints': [{'publicURL': 'test', + 'type': 'identity'}]}]})) + @mock.patch.object(tokens.v3_client, 'Client') + def test_is_token_valid_sanity(self, mock_get, mock_client): + self.assertTrue(tokens.is_token_valid('a', 'b', tokens.TokenConf( + 'a', 'b', 'c', 'd', '3'))) + + @mock.patch.object(tokens.requests, 'get', return_value=MyResponse( + tokens.OK_CODE, {'regions': [{'endpoints': [{'publicURL': 'test', + 'type': 'identity'}]}]})) + @mock.patch.object(tokens.v3_client, 'Client') + def test_is_token_valid_sanity_role_required(self, mock_get, mock_client): + user = {'user': {'id': 'test_id', 'domain': {'id': 'test'}}} + mock_client.tokens.validate = mock.MagicMock(return_value=user) + self.assertTrue(tokens.is_token_valid('a', 'b', tokens.TokenConf( + 'a', 'b', 'c', 'd', '3'), 'test', {'domain': 'test'})) + + @mock.patch.object(tokens.requests, 'get', return_value=MyResponse( + tokens.OK_CODE, {'regions': [{'endpoints': [{'publicURL': 'test', + 'type': 'identity'}]}]})) + def test_is_token_valid_token_not_found(self, mock_get): + client_backup = tokens.v3_client.Client + tokens.v3_client.Client = mock.MagicMock(return_value=MyClient()) + self.assertFalse(tokens.is_token_valid('a', 'b', tokens.TokenConf( + 'a', 'b', 'c', 'd', '3'))) + tokens.v3_client.Client = client_backup + + @mock.patch.object(tokens.requests, 'get', return_value=MyResponse( + tokens.OK_CODE, {'regions': [{'endpoints': [{'publicURL': 'test', + 'type': 'identity'}]}]})) + def test_is_token_valid_invalid_version(self, mock_get): + client_backup = tokens.v3_client.Client + tokens.v3_client.Client = mock.MagicMock(return_value=MyClient()) + self.assertRaises(ValueError, tokens.is_token_valid, 'a', 'b', + tokens.TokenConf('a', 'b', 'c', 'd', '4')) + tokens.v3_client.Client = client_backup + + @mock.patch.object(tokens.requests, 'get', return_value=MyResponse( + tokens.OK_CODE, {'regions': [{'endpoints': [{'publicURL': 'test', + 'type': 'identity'}]}]})) + def test_is_token_valid_keystone_v2(self, mock_get): + client_backup = tokens.v2_client.Client + tokens.v2_client.Client = mock.MagicMock() + self.assertFalse(tokens.is_token_valid('a', 'b', + tokens.TokenConf('a', 'b', 'c', + 'd', '2.0'), + 'test', + {'tenant': 'test'})) + tokens.v2_client.Client = client_backup + + @mock.patch.object(tokens.requests, 'get', return_value=MyResponse( + tokens.OK_CODE, {'regions': [{'endpoints': [{'publicURL': 'test', + 'type': 'identity'}]}]})) + def test_is_token_valid_keystone_v2_invalid_location(self, mock_get): + client_backup = tokens.v2_client.Client + tokens.v2_client.Client = mock.MagicMock() + self.assertRaises(ValueError, tokens.is_token_valid, 'a', 'b', + tokens.TokenConf('a', 'b', 'c', 'd', '2.0'), 'test', + {'domain': 'test'}) + tokens.v2_client.Client = client_backup + + @mock.patch.object(tokens.requests, 'get', return_value=MyResponse( + tokens.OK_CODE + 1, {'regions': [{'endpoints': [ + {'publicURL': 'test', 'type': 'identity'}]}]})) + def test_is_token_valid_keystone_ep_not_found(self, mock_get): + self.assertRaises(tokens.KeystoneNotFoundError, tokens.is_token_valid, + 'a', 'b', tokens.TokenConf('a', 'b', 'c', 'd', '3')) + + @mock.patch.object(tokens.requests, 'get', return_value=MyResponse( + tokens.OK_CODE, {'regions': [{'endpoints': [{'publicURL': 'test', + 'type': 'identity'}]}]})) + def test_is_token_valid_no_role_location(self, mock_get): + tokens.v3_client.Client = mock.MagicMock() + self.assertRaises(ValueError, tokens.is_token_valid, 'a', 'b', + tokens.TokenConf('a', 'b', 'c', 'd', '3'), 'test') + + @mock.patch.object(tokens.v3_client, 'Client') + def test_does_user_have_role_sanity_true(self, mock_client): + user = {'user': {'id': 'test_id', 'domain': {'id': 'test'}}} + self.assertTrue(tokens._does_user_have_role(mock_client, '3', user, + 'admin', + {'domain': 'test'})) + + @mock.patch.object(tokens.v3_client, 'Client') + def test_does_user_have_role_sanity_false(self, mock_client): + user = {'user': {'id': 'test_id', 'domain': {'id': 'test'}}} + mock_client.roles.check = mock.MagicMock( + side_effect=tokens.v3_client.exceptions.NotFound('test')) + self.assertFalse(tokens._does_user_have_role(mock_client, '3', user, + 'admin', + {'domain': 'test'})) + + @mock.patch.object(tokens.v3_client, 'Client') + def test_does_user_have_role_invalid_user(self, mock_client): + user = {} + self.assertFalse(tokens._does_user_have_role(mock_client, '3', user, + 'admin', + {'domain': 'test'})) + + @mock.patch.object(tokens.v3_client, 'Client') + def test_does_user_have_role_role_does_not_exist(self, mock_client): + user = {'user': {'id': 'test_id', 'domain': {'id': 'test'}}} + mock_client.roles.find = mock.MagicMock( + side_effect=tokens.v3_client.exceptions.NotFound('test')) + self.assertRaises(tokens.v3_client.exceptions.NotFound, + tokens._does_user_have_role, mock_client, '3', + user, 'test', {'domain': 'default'}) + + @mock.patch.object(tokens.requests, 'get', return_value=MyResponse( + tokens.OK_CODE, {'regions': [{'endpoints': [{'publicURL': 'test', + 'type': 'identity'}]}]})) + def test_is_token_valid_role_does_not_exist(self, mock_get): + tokens.v3_client.Client = mock.MagicMock(return_value=MyClient(False)) + self.assertRaises(ValueError, tokens.is_token_valid, 'a', 'b', + tokens.TokenConf('a', 'b', 'c', 'd', '3'), 'test', + {'domain': 'test'}) + + def test_get_token_user_invalid_arguments(self): + self.assertRaises(ValueError, tokens.get_token_user, 'a', 'b') + + @mock.patch.object(tokens, '_find_keystone_ep', return_value=None) + def test_get_token_user_keystone_ep_not_found(self, + mock_find_keystone_ep): + self.assertRaises(tokens.KeystoneNotFoundError, + tokens.get_token_user, 'a', mock.MagicMock(), 'c') + + def test_get_token_user_invalid_keystone_version(self): + conf = tokens.TokenConf(None, None, None, None, None) + self.assertRaises(ValueError, tokens.get_token_user, 'a', conf, 'c', + 'd') + + @mock.patch.object(tokens, '_get_keystone_client') + def test_get_token_user_token_not_found(self, mock_get_keystone_client): + ks = mock.MagicMock() + ks.tokens.validate.side_effect = tokens.v3_client.exceptions.NotFound() + mock_get_keystone_client.return_value = ks + conf = tokens.TokenConf('3', '3', '3', '3', '3') + self.assertIsNone(tokens.get_token_user('a', conf, 'c', 'd')) + + @mock.patch.object(tokens, '_get_keystone_client') + def test_get_token_user_success(self, mock_get_keystone_client): + token_info = mock.MagicMock() + token_info.token = 'a' + token_info.user = 'test_user' + ks = mock.MagicMock() + ks.tokens.validate.return_value = token_info + mock_get_keystone_client.return_value = ks + + conf = tokens.TokenConf('2.0', '2.0', '2.0', '2.0', '2.0') + result = tokens.get_token_user('a', conf, 'c', 'd') + + self.assertEqual(result.token, 'a') + self.assertEqual(result.user, 'test_user') diff --git a/orm/common/client/keystone/keystone_utils/tokens.py b/orm/common/client/keystone/keystone_utils/tokens.py index dcd0ea95..1d32cda1 100755 --- a/orm/common/client/keystone/keystone_utils/tokens.py +++ b/orm/common/client/keystone/keystone_utils/tokens.py @@ -1,6 +1,5 @@ """Token utility module.""" import logging - import requests from orm.common.client.keystone.mock_keystone.keystoneclient import exceptions @@ -8,6 +7,8 @@ from orm.common.client.keystone.mock_keystone.keystoneclient.v2_0 import client from orm.common.client.keystone.mock_keystone.keystoneclient.v3 import client as v3_client from orm.common.orm_common.utils import dictator +from pecan import request + _verify = False OK_CODE = 200 @@ -96,6 +97,10 @@ def get_token_user(token, conf, lcp_id=None, keystone_ep=None): try: token_info = keystone.tokens.validate(token) logger.debug('User token found in Keystone') + if not request.headers.get('X-RANGER-Requester'): + request.headers['X-RANGER-Requester'] = \ + token_info.user['username'] + return TokenUser(token_info) # Other exceptions raised by validate() are critical errors, # so instead of returning False, we'll just let them propagate diff --git a/orm/common/orm_common/hooks/security_headers_hook.py b/orm/common/orm_common/hooks/security_headers_hook.py index dbc8f9a8..791cea99 100755 --- a/orm/common/orm_common/hooks/security_headers_hook.py +++ b/orm/common/orm_common/hooks/security_headers_hook.py @@ -1,5 +1,4 @@ import logging - from pecan.hooks import PecanHook logger = logging.getLogger(__name__) diff --git a/orm/common/orm_common/injector/fang/resource_provider_register.py b/orm/common/orm_common/injector/fang/resource_provider_register.py index 1a7e3fbf..39124051 100755 --- a/orm/common/orm_common/injector/fang/resource_provider_register.py +++ b/orm/common/orm_common/injector/fang/resource_provider_register.py @@ -10,7 +10,7 @@ class ResourceProviderRegister: # Maps resource names to a provider self.resource_providers = {} - def register(self, resource_name, provider=None, allow_override=True): + def register(self, resource_name, provider=None, allow_override=False): if provider is None: # Give a partial usable as a decorator return partial( diff --git a/orm/common/orm_common/policy/_checks.py b/orm/common/orm_common/policy/_checks.py index 1ab7ffb3..4de9f03e 100755 --- a/orm/common/orm_common/policy/_checks.py +++ b/orm/common/orm_common/policy/_checks.py @@ -23,6 +23,7 @@ import six from orm.common.orm_common.utils import api_error_utils as err_utils from orm.common.orm_common.utils import dictator + logger = logging.getLogger(__name__) registered_checks = {} @@ -214,22 +215,19 @@ class RoleCheck(Check): """Check that there is a matching role in the ``user`` object.""" def __call__(self, target, user, enforcer): - try: - logger.debug('Checking role:{}'.format(self.match)) - result = any( - [role['name'] == self.match for role in user.user['roles']]) - logger.debug('Role check result: {}'.format(result)) - if not result: - logger.info( - 'INFO|CON{}AUTH001|Not allowed to perform this operation,' - ' user:{} does not have role:{}'.format( - dictator.get('service_name', 'ORM'), - user.user['name'], self.match)) - raise err_utils.get_error('N/A', status_code=403) - return result - except Exception: - logger.debug('Invalid user, failing role check') - raise + logger.debug('Checking against policy role:{}'.format(self.match)) + + result = any( + [role['name'] == self.match for role in user.user['roles']]) + logger.debug('Role check result: {}'.format(result)) + if not result: + logger.info( + 'INFO|CON{}AUTH001|Not allowed to perform this operation,' + ' user:{} does not have role:{}'.format( + dictator.get('service_name', 'ORM'), + user.user['name'], self.match)) + + return result @register('user') diff --git a/orm/common/orm_common/policy/_parser.py b/orm/common/orm_common/policy/_parser.py index 7207f0f2..c3094aa1 100755 --- a/orm/common/orm_common/policy/_parser.py +++ b/orm/common/orm_common/policy/_parser.py @@ -22,6 +22,7 @@ import six import _checks + LOG = logging.getLogger(__name__) @@ -210,7 +211,7 @@ def _parse_check(rule): try: kind, match = rule.split(':', 1) except Exception: - LOG.exception('Failed to understand rule %s', rule) + LOG.exception(('Failed to understand rule %s'), rule) # If the rule is invalid, we'll fail closed return _checks.FalseCheck() @@ -220,7 +221,7 @@ def _parse_check(rule): elif None in _checks.registered_checks: return _checks.registered_checks[None](kind, match) else: - LOG.error('No handler for matches of kind %s', kind) + LOG.error(('No handler for matches of kind %s'), kind) return _checks.FalseCheck() @@ -336,7 +337,7 @@ def _parse_text_rule(rule): return state.result except ValueError: # Couldn't parse the rule - LOG.exception('Failed to understand rule %s', rule) + LOG.exception(('Failed to understand rule %s'), rule) # Fail closed return _checks.FalseCheck() diff --git a/orm/common/orm_common/policy/policy.py b/orm/common/orm_common/policy/policy.py index f82482dd..71c9ceec 100755 --- a/orm/common/orm_common/policy/policy.py +++ b/orm/common/orm_common/policy/policy.py @@ -131,6 +131,10 @@ def authorize(action, request, app_conf, keystone_ep=None): token_to_validate = request.headers.get('X-Auth-Token') lcp_id = request.headers.get('X-Auth-Region') + + keystone_ep = keystone_ep if keystone_ep else ( + request.headers.get('Keystone-Endpoint')) + try: if _is_authorization_enabled(app_conf): try: diff --git a/orm/common/orm_common/policy/qolicy.py b/orm/common/orm_common/policy/qolicy.py index 8157e686..ff0128da 100755 --- a/orm/common/orm_common/policy/qolicy.py +++ b/orm/common/orm_common/policy/qolicy.py @@ -219,7 +219,9 @@ import logging import os import _parser +from orm.common.orm_common.utils import api_error_utils as err_utils from oslo_config import cfg + from oslo_policy import _checks from oslo_policy._i18n import _ from oslo_serialization import jsonutils @@ -525,9 +527,6 @@ class Enforcer(object): # If it is False, raise the exception if requested if do_raise and not result: - if exc: - raise exc(*args, **kwargs) - - raise PolicyNotAuthorized(rule, target, creds) + raise err_utils.get_error('N/A', status_code=403) return result diff --git a/orm/common/orm_common/tests/__init__.py b/orm/common/orm_common/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/orm/common/orm_common/tests/hooks/__init__.py b/orm/common/orm_common/tests/hooks/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/orm/common/orm_common/tests/hooks/test_api_error_hook.py b/orm/common/orm_common/tests/hooks/test_api_error_hook.py new file mode 100755 index 00000000..bf19e3a7 --- /dev/null +++ b/orm/common/orm_common/tests/hooks/test_api_error_hook.py @@ -0,0 +1,68 @@ +import json +import logging +import mock +from orm_common.hooks import api_error_hook +from unittest import TestCase + +logger = logging.getLogger(__name__) + + +class TestAPIErrorHook(TestCase): + @mock.patch.object(api_error_hook, 'err_utils') + @mock.patch.object(api_error_hook, 'json') + def test_after_401(self, mock_json, mock_err_utils): + a = api_error_hook.APIErrorHook() + state = mock.MagicMock() + + mock_err_utils.get_error_dict.return_value = 'B' + mock_json.loads = json.loads + mock_json.dumps = json.dumps + state.response.status_code = 401 + a.after(state) + self.assertEqual(state.response.body, + json.dumps(mock_err_utils.get_error_dict.return_value)) + + @mock.patch.object(api_error_hook, 'err_utils') + def test_after_not_an_error(self, mock_err_utils): + a = api_error_hook.APIErrorHook() + state = mock.MagicMock() + + mock_err_utils.get_error_dict.return_value = 'B' + state.response.body = 'AAAA' + temp = state.response.body + # A successful status code + state.response.status_code = 201 + a.after(state) + # Assert that the response body hasn't changed + self.assertEqual(state.response.body, temp) + + @mock.patch.object(api_error_hook, 'err_utils') + @mock.patch.object(api_error_hook.json, 'loads', + side_effect=ValueError('test')) + def test_after_error(self, mock_json, mock_err_utils): + a = api_error_hook.APIErrorHook() + state = mock.MagicMock() + + mock_err_utils.get_error_dict.return_value = 'B' + state.response.body = 'AAAA' + + mock_json.loads = mock.MagicMock(side_effect=ValueError('sd')) + state.response.status_code = 402 + a.after(state) + self.assertEqual(state.response.body, + json.dumps(mock_err_utils.get_error_dict.return_value)) + + @mock.patch.object(api_error_hook, 'err_utils') + @mock.patch.object(api_error_hook, 'json') + def test_after_success(self, mock_json, mock_err_utils): + a = api_error_hook.APIErrorHook() + state = mock.MagicMock() + + mock_err_utils.get_error_dict.return_value = 'B' + mock_json.loads = json.loads + mock_json.dumps = json.dumps + mock_json.loads = json.loads + state.response.body = '{"debuginfo": null, "faultcode": "Client", "faultstring": "{\\"code\\": 404, \\"created\\": \\"1475768730.95\\", \\"details\\": \\"\\", \\"message\\": \\"customer: q not found\\", \\"type\\": \\"Not Found\\", \\"transaction_id\\": \\"mock_json5efa7416fb4d408cc0e30e4373cf00\\"}"}' + state.response.status_code = 400 + a.after(state) + self.assertEqual(json.loads(state.response.body), json.loads('{"message": "customer: q not found", "created": "1475768730.95", "type": "Not Found", "details": "", "code": 404, "transaction_id": "mock_json5efa7416fb4d408cc0e30e4373cf00"}')) diff --git a/orm/common/orm_common/tests/hooks/test_security_headers_hook.py b/orm/common/orm_common/tests/hooks/test_security_headers_hook.py new file mode 100755 index 00000000..ee5b2420 --- /dev/null +++ b/orm/common/orm_common/tests/hooks/test_security_headers_hook.py @@ -0,0 +1,31 @@ +import mock +from orm_common.hooks import security_headers_hook +from unittest import TestCase + + +class MyHeaders(object): + def __init__(self): + self.headers = {} + + def add(self, key, value): + self.headers[key] = value + + +class TestSecurityHeadersHook(TestCase): + def test_after(self): + s = security_headers_hook.SecurityHeadersHook() + test_headers = MyHeaders() + state = mock.MagicMock() + state.response.headers = test_headers + s.after(state) + + security_headers = {'X-Frame-Options': 'DENY', + 'X-Content-Type-Options': 'nosniff', + 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains', + 'Content-Security-Policy': 'default-src \'self\'', + 'X-Permitted-Cross-Domain-Policies': 'none', + 'X-XSS-Protection': '1; mode=block'} + + for header in security_headers: + self.assertEqual(security_headers[header], + test_headers.headers[header]) diff --git a/orm/common/orm_common/tests/hooks/test_transaction_id_hook.py b/orm/common/orm_common/tests/hooks/test_transaction_id_hook.py new file mode 100755 index 00000000..30d8b3c3 --- /dev/null +++ b/orm/common/orm_common/tests/hooks/test_transaction_id_hook.py @@ -0,0 +1,17 @@ +import logging +import mock +from orm_common.hooks import transaction_id_hook +from unittest import TestCase + +logger = logging.getLogger(__name__) + + +class TestTransactionIdHook(TestCase): + @mock.patch.object(transaction_id_hook.utils, 'make_transid', + return_value='test') + def test_before_sanity(self, mock_make_transid): + t = transaction_id_hook.TransactionIdHook() + state = mock.MagicMock() + t.before(state) + self.assertEqual(state.request.transaction_id, 'test') + self.assertEqual(state.request.tracking_id, 'test') diff --git a/orm/common/orm_common/tests/injector/__init__.py b/orm/common/orm_common/tests/injector/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/orm/common/orm_common/tests/injector/test_injector.py b/orm/common/orm_common/tests/injector/test_injector.py new file mode 100755 index 00000000..1303fd02 --- /dev/null +++ b/orm/common/orm_common/tests/injector/test_injector.py @@ -0,0 +1,57 @@ +import logging +import mock +from orm_common.injector import injector +import os +from unittest import TestCase + +logger = logging.getLogger(__name__) + + +class TestInjector(TestCase): + def setUp(self): + pass + + @mock.patch.object(injector, '_import_file_by_name') + def test_register_providers(self, mock_import_file_by_name): + os.environ['CMS_ENV'] = 'test' + injector.register_providers('CMS_ENV', 'a/b/c', logger) + + @mock.patch.object(injector, '_import_file_by_name') + def test_register_providers_env_not_exist(self, mock_import_file_by_name): + injector.register_providers('CMS_ENV1', 'a/b/c', logger) + + @mock.patch.object(injector, '_import_file_by_name') + def test_register_providers_env_test(self, mock_import_file_by_name): + os.environ['CMS_ENV2'] = '__TEST__' + injector.register_providers('CMS_ENV2', 'a/b/c', logger) + + @mock.patch.object(injector, '_import_file_by_name') + def test_register_providers_with_existing_provider(self, mock_import_file_by_name): + mock_import_file_by_name.return_value = type('module', (object,), {'providers': ['a1', 'b2']})() + os.environ['c3'] = 'test' + injector.register_providers('c3', 'a/b/c', logger) + + def test_get_di(self): + injector.get_di() + + @mock.patch.object(injector, 'logger') + def test_import_file_by_name_ioerror(self, mock_logger): + injector.logger = mock.MagicMock() + # Calling it with ('', '.') should raise an IOError + # (no such file or directory) + self.assertRaises(IOError, injector._import_file_by_name, '', '.') + + @mock.patch.object(injector.imp, 'load_source', return_value='test') + def test_import_file_by_name_sanity(self, mock_load_source): + self.assertEqual(injector._import_file_by_name('', '.'), 'test') + + @mock.patch.object(injector._di.providers, 'register_instance') + def test_override_injected_dependency(self, mock_di): + injector.override_injected_dependency((1, 2,)) + self.assertTrue(mock_di.called) + + ''' + @mock.patch.object(ResourceProviderRegister, 'register_instance') + def test_override_injected_dependency(self, mock_resourceProviderRegister): + injector.override_injected_dependency(mock.Mock()) + ''' diff --git a/orm/common/orm_common/tests/policy/__init__.py b/orm/common/orm_common/tests/policy/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/orm/common/orm_common/tests/policy/test_checks.py b/orm/common/orm_common/tests/policy/test_checks.py new file mode 100755 index 00000000..53a1a661 --- /dev/null +++ b/orm/common/orm_common/tests/policy/test_checks.py @@ -0,0 +1,103 @@ +import mock +import unittest + +from orm_common.policy import _checks + + +class TestChecks(unittest.TestCase): + def test_call_simple_checks(self): + check = _checks.FalseCheck() + self.assertFalse(check(1, 2, 3)) + check = _checks.TrueCheck() + self.assertTrue(check(1, 2, 3)) + + check = _checks.GenericCheck('a', 'b') + self.assertFalse(check(1, 2, 3)) + + def test_str_simple_checks(self): + check = _checks.FalseCheck() + self.assertEqual(str(check), '!') + check = _checks.TrueCheck() + self.assertEqual(str(check), '@') + + check = _checks.GenericCheck('a', 'b') + self.assertEqual(str(check), 'a:b') + + def test_call_complex_checks(self): + first_rule = _checks.TrueCheck() + second_rule = _checks.FalseCheck() + + check = _checks.NotCheck(first_rule) + self.assertFalse(check(1, 2, 3)) + + check = _checks.AndCheck([first_rule]) + check.add_check(second_rule) + self.assertFalse(check(1, 2, 3)) + check = _checks.AndCheck([first_rule, first_rule]) + self.assertTrue(check(1, 2, 3)) + + check = _checks.OrCheck([first_rule]) + check.add_check(second_rule) + self.assertTrue(check(1, 2, 3)) + self.assertEqual(check.pop_check(), (check, second_rule,)) + check = _checks.OrCheck([second_rule, second_rule]) + self.assertFalse(check(1, 2, 3)) + + def test_str_complex_checks(self): + first_rule = _checks.TrueCheck() + second_rule = _checks.FalseCheck() + + check = _checks.NotCheck(first_rule) + self.assertEqual(str(check), 'not @') + + check = _checks.AndCheck([first_rule]) + check.add_check(second_rule) + self.assertEqual(str(check), '(@ and !)') + + check = _checks.OrCheck([first_rule]) + check.add_check(second_rule) + self.assertEqual(str(check), '(@ or !)') + + def test_call_custom_checks_error(self): + check = _checks.RoleCheck('a', 'admin') + # test no longer valid. + # change: https://gerrit.mtn5.cci.att.com/#/c/25690/ + # removed the exception raise + # + # try: + # check(1, mock.MagicMock(), 3) + # self.fail('ClientSideError not raised!') + # except ClientSideError as exc: + # self.assertEqual(exc.code, 403) + + for check_type in (_checks.TenantCheck, + _checks.DomainCheck): + check = check_type('a', 'admin') + # 2 is not a user, so the check will fail + self.assertFalse(check(1, 2, 3)) + + def test_call_custom_checks_success(self): + user = mock.MagicMock() + user.user = {'roles': [{'name': 'admin'}]} + user.tenant = {'name': 'admin'} + user.domain = {'name': 'admin'} + + for check_type in (_checks.RoleCheck, + _checks.TenantCheck, + _checks.DomainCheck): + check = check_type('a', 'admin') + # 2 is not a user, so the check will fail + self.assertTrue(check(1, user, 3)) + + def test_call_rule_check_error(self): + enforcer = mock.MagicMock() + enforcer.rules = {'test': mock.MagicMock( + side_effect=KeyError('test'))} + check = _checks.RuleCheck('rule', 'test') + self.assertFalse(check(1, 2, enforcer)) + + def test_call_rule_check_success(self): + enforcer = mock.MagicMock() + enforcer.rules = {'test': mock.MagicMock(return_value=True)} + check = _checks.RuleCheck('rule', 'test') + self.assertTrue(check(1, 2, enforcer)) diff --git a/orm/common/orm_common/tests/policy/test_policy.py b/orm/common/orm_common/tests/policy/test_policy.py new file mode 100755 index 00000000..fa695d7c --- /dev/null +++ b/orm/common/orm_common/tests/policy/test_policy.py @@ -0,0 +1,129 @@ +import mock +import unittest + +from orm_common.policy import policy + + +class Exception_Test(Exception): + pass + + +class TestPolicy(unittest.TestCase): + def setUp(self): + policy._ENFORCER = None + policy._POLICY_FILE = None + policy._TOKEN_CONF = None + + def test_reset(self): + policy._ENFORCER = mock.MagicMock() + policy._POLICY_FILE = mock.MagicMock() + policy.reset() + self.assertIsNone(policy._ENFORCER) + self.assertIsNone(policy._POLICY_FILE) + # Call it a second time when they are both None and see + # that no exception is raised + policy.reset() + self.assertIsNone(policy._ENFORCER) + self.assertIsNone(policy._POLICY_FILE) + + @mock.patch.object(policy, 'open') + @mock.patch.object(policy.qolicy, 'Enforcer') + @mock.patch.object(policy.qolicy, 'Rules') + def test_init_success(self, mock_rules, mock_enforcer, mock_open): + policy_file = 'a' + token_conf = 'b' + mock_rules.load_json.return_value = 'c' + policy.init(policy_file, token_conf) + self.assertEqual(policy._POLICY_FILE, 'a') + self.assertEqual(policy._TOKEN_CONF, 'b') + + def test_init_enforcer_already_exists(self): + policy._ENFORCER = mock.MagicMock() + + # Nothing should happen when the enforcer already exists, so make sure + # that no exception is raised + policy.init('a', 'b') + + @mock.patch.object(policy, 'open') + @mock.patch.object(policy.qolicy, 'Rules') + @mock.patch.object(policy, '_ENFORCER') + def test_reset_rules_no_policy_file(self, mock_enforcer, + mock_rules, mock_open): + self.assertRaises(ValueError, policy.reset_rules) + + @mock.patch.object(policy, 'open') + @mock.patch.object(policy.qolicy, 'Rules') + @mock.patch.object(policy, '_ENFORCER') + def test_reset_rules_success(self, mock_enforcer, + mock_rules, mock_open): + policy._POLICY_FILE = mock.MagicMock() + policy.reset_rules() + self.assertTrue(mock_enforcer.set_rules.called) + + @mock.patch.object(policy, 'reset_rules') + @mock.patch.object(policy.tokens, 'get_token_user', + side_effect=ValueError('test')) + @mock.patch.object(policy, '_ENFORCER') + def test_enforce_enforcer_error(self, mock_enforcer, + mock_get_token_user, + mock_reset_rules): + mock_enforcer.enforce.side_effect = policy.EnforcerError() + self.assertRaises(policy.EnforcerError, policy.enforce, 'action', + 'token', mock.MagicMock()) + + @mock.patch.object(policy, 'reset_rules') + @mock.patch.object(policy.tokens, 'get_token_user') + @mock.patch.object(policy, '_ENFORCER') + def test_enforce_success(self, mock_enforcer, + mock_get_token_user, + mock_reset_rules): + mock_enforcer.enforce.return_value = True + self.assertTrue(policy.enforce('action', 'token', mock.MagicMock())) + + def test_authorize_authorization_disabled(self): + request = mock.MagicMock() + app_conf = mock.MagicMock() + app_conf.authentication.enabled = False + # No exception should be raised + policy.authorize('a', request, app_conf) + + @mock.patch.object(policy, 'enforce') + def test_authorize_no_token(self, mock_enforce): + request = mock.MagicMock() + request.headers.get.return_value = None + app_conf = mock.MagicMock() + app_conf.authentication.enabled = True + # No exception should be raised + policy.authorize('a', request, app_conf) + + @mock.patch.object(policy, 'enforce', side_effect=policy.EnforcerError()) + @mock.patch.object(policy.err_utils, 'get_error', return_value=Exception_Test) + def test_authorize_enforce_failed(self, mock_enforce, mock_get_error): + request = mock.MagicMock() + request.headers.get.return_value = None + app_conf = mock.MagicMock() + app_conf.authentication.enabled = True + + self.assertRaises(Exception_Test, policy.authorize, 'a', request, + app_conf) + + @mock.patch.object(policy, 'enforce', side_effect=ValueError()) + @mock.patch.object(policy.err_utils, 'get_error', return_value=Exception_Test) + def test_authorize_other_error(self, mock_enforce, mock_get_error): + request = mock.MagicMock() + request.headers.get.return_value = None + app_conf = mock.MagicMock() + app_conf.authentication.enabled = True + + self.assertRaises(Exception_Test, policy.authorize, 'a', request, + app_conf) + + @mock.patch.object(policy, 'enforce') + def test_authorize_success(self, mock_enforce): + request = mock.MagicMock() + request.headers.get.return_value = 'test' + app_conf = mock.MagicMock() + app_conf.authentication.enabled = True + + # No exception should be raised + policy.authorize('a', request, app_conf) diff --git a/orm/common/orm_common/tests/utils/__init__.py b/orm/common/orm_common/tests/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/orm/common/orm_common/tests/utils/test_api_error_utils.py b/orm/common/orm_common/tests/utils/test_api_error_utils.py new file mode 100755 index 00000000..7b7568b1 --- /dev/null +++ b/orm/common/orm_common/tests/utils/test_api_error_utils.py @@ -0,0 +1,14 @@ +import json +import mock +from orm_common.utils import api_error_utils +from unittest import TestCase + + +class TestCrossApiUtil(TestCase): + @mock.patch.object(api_error_utils.utils, 'get_time_human', return_value=1.337) + def test_get_error_default_message(self, mock_time): + self.assertEqual( + json.loads(api_error_utils.get_error('test', 'a').message), + {"details": "a", "message": "Incompatible JSON body", + "created": "1.337", "code": 400, "type": "Bad Request", + "transaction_id": "test"}) diff --git a/orm/common/orm_common/tests/utils/test_cross_api_utils.py b/orm/common/orm_common/tests/utils/test_cross_api_utils.py new file mode 100755 index 00000000..5f9c600a --- /dev/null +++ b/orm/common/orm_common/tests/utils/test_cross_api_utils.py @@ -0,0 +1,74 @@ +import mock +from orm_common.utils import cross_api_utils +import time +from unittest import TestCase + + +class TestCrossApiUtil(TestCase): + @mock.patch('pecan.conf') + def setUp(self, mock_conf): + self.mock_response = mock.Mock() + cross_api_utils.conf = mock_conf + + def respond(self, value, code): + self.mock_response.json.return_value = value + self.mock_response.status_code = code + return self.mock_response + + def test_set_utils_conf(self): + cross_api_utils.set_utils_conf(None) + self.assertEqual(cross_api_utils.conf, None) + + def test_check_conf_initialization(self): + cross_api_utils.set_utils_conf(None) + self.assertRaises(AssertionError, cross_api_utils._check_conf_initialization) + + @mock.patch('orm_common.utils.cross_api_utils.get_rms_region_group') + def test_is_region_group_exist(self, mock_rms_region_group): + mock_rms_region_group.return_value = 'test_group' + exist = cross_api_utils.is_region_group_exist('test_group_name') + self.assertEqual(exist, True) + + @mock.patch('orm_common.utils.cross_api_utils.get_rms_region_group') + def test_is_region_group_exist_false(self, mock_rms_region_group): + mock_rms_region_group.return_value = None + exist = cross_api_utils.is_region_group_exist('test_group_name') + self.assertEqual(exist, False) + + @mock.patch('orm_common.utils.cross_api_utils.get_rms_region_group') + def test_get_regions_of_group(self, mock_rms_region_group): + mock_rms_region_group.return_value = {'regions': 'group'} + exist = cross_api_utils.get_regions_of_group('test_group_name') + self.assertEqual(exist, 'group') + + @mock.patch('orm_common.utils.cross_api_utils.get_rms_region_group') + def test_get_regions_of_group_false(self, mock_rms_region_group): + mock_rms_region_group.return_value = None + exist = cross_api_utils.get_regions_of_group('test_group_name') + self.assertEqual(exist, None) + + @mock.patch('requests.get') + def test_get_rms_region_group(self, mock_get): + mock_get.return_value = self.respond({'result': 'success'}, 200) + result = cross_api_utils.get_rms_region_group('test_group_name') + self.assertEqual(result, {'result': 'success'}) + + def test_get_rms_region_group_cache_used(self): + cross_api_utils.prev_timestamp = time.time() + cross_api_utils.prev_group_name = 'test_group' + cross_api_utils.prev_resp = 'test_response' + cross_api_utils.conf.api.rms_server.cache_seconds = 14760251830 + self.assertEqual(cross_api_utils.prev_resp, + cross_api_utils.get_rms_region_group( + cross_api_utils.prev_group_name)) + + @mock.patch.object(cross_api_utils, 'logger') + @mock.patch.object(time, 'time', side_effect=ValueError('test')) + def test_get_rms_region_group_cache_used(self, mock_time, mock_logger): + self.assertRaises(ValueError, cross_api_utils.get_rms_region_group, + 'test') + + # @mock.patch('requests.get') + # def test_get_rms_region_group_with_exception(self, mock_get): + # mock_get.side_affect = Exception('boom') + # self.assertRaises(Exception, cross_api_utils.get_rms_region_group, 'test_group_name') diff --git a/orm/common/orm_common/tests/utils/test_utils.py b/orm/common/orm_common/tests/utils/test_utils.py new file mode 100755 index 00000000..2fa9c400 --- /dev/null +++ b/orm/common/orm_common/tests/utils/test_utils.py @@ -0,0 +1,177 @@ +import logging +import mock +from orm_common.utils import utils +import pprint +from testfixtures import log_capture +from unittest import TestCase + + +class TestUtil(TestCase): + @mock.patch('pecan.conf') + def setUp(self, mock_conf): + self.mock_response = mock.Mock() + utils.conf = mock_conf + + def respond(self, value, code): + self.mock_response.json.return_value = value + self.mock_response.status_code = code + return self.mock_response + + @mock.patch('requests.post') + def test_make_uuid(self, mock_post): + mock_post.return_value = self.respond({'uuid': '987654321'}, 200) + uuid = utils.create_or_validate_uuid('', 'uuidtype') + self.assertEqual(uuid, '987654321') + + @mock.patch('requests.post') + @log_capture('orm_common.utils.utils', level=logging.INFO) + def test_make_uuid_offline(self, mock_post, l): + mock_post.side_effect = Exception('boom') + uuid = utils.create_or_validate_uuid('', 'uuidtype') + self.assertEqual(uuid, None) + l.check(('orm_common.utils.utils', 'INFO', 'Failed in make_uuid:boom')) + + @mock.patch('requests.post') + def test_make_transid(self, mock_post): + mock_post.return_value = self.respond({'uuid': '987654321'}, 200) + uuid = utils.make_transid() + self.assertEqual(uuid, '987654321') + + @mock.patch('requests.post') + @log_capture('orm_common.utils.utils', level=logging.INFO) + def test_make_transid_offline(self, mock_post, l): + mock_post.side_effect = Exception('boom') + uuid = utils.make_transid() + self.assertEqual(uuid, None) + l.check( + ('orm_common.utils.utils', 'INFO', 'Failed in make_transid:boom')) + + @mock.patch('audit_client.api.audit.init') + @mock.patch('audit_client.api.audit.audit') + def test_audit_trail(self, mock_init, mock_audit): + resp = utils.audit_trail('create customer', '1234', + {'X-RANGER-Client': 'Fred'}, '5678') + self.assertEqual(resp, 200) + + @mock.patch('audit_client.api.audit.audit') + def test_audit_trail_offline(self, mock_audit): + mock_audit.side_effect = Exception('boom') + resp = utils.audit_trail('create customer', '1234', + {'X-RANGER-Client': 'Fred'}, '5678') + self.assertEqual(resp, None) + + @mock.patch('audit_client.api.audit.init') + @mock.patch('audit_client.api.audit.audit') + def test_audit_service_args_least(self, mock_audit, mock_init): + resp = utils.audit_trail('create customer', '1234', + {'X-RANGER-Client': 'Fred'}, '5678') + self.assertEqual(mock_audit.call_args[0][1], 'Fred') # application_id + self.assertEqual(mock_audit.call_args[0][2], '1234') # tracking_id + self.assertEqual(mock_audit.call_args[0][3], '1234') # transaction_id + self.assertEqual(mock_audit.call_args[0][4], + 'create customer') # transaction_type + self.assertEqual(mock_audit.call_args[0][5], '5678') # resource_id + # self.assertEqual(mock_audit.call_args[0][6], 'cms') # service + self.assertEqual(mock_audit.call_args[0][7], '') # user_id + self.assertEqual(mock_audit.call_args[0][8], 'NA') # external_id + self.assertEqual(mock_audit.call_args[0][9], '') # event_details + # self.assertEqual(mock_audit.call_args[0][10], 'Saved to DB') # status + + @mock.patch('audit_client.api.audit.init') + @mock.patch('audit_client.api.audit.audit') + def test_audit_service_with_tracking(self, mock_audit, mock_init): + utils.audit_trail('create customer', '1234', + {'X-RANGER-Client': 'Fred', + 'X-RANGER-Tracking-Id': 'Track12'}, '5678') + self.assertEqual(mock_audit.call_args[0][1], 'Fred') # application_id + self.assertEqual(mock_audit.call_args[0][2], 'Track12') # tracking_id + self.assertEqual(mock_audit.call_args[0][3], '1234') # transaction_id + self.assertEqual(mock_audit.call_args[0][4], + 'create customer') # transaction_type + self.assertEqual(mock_audit.call_args[0][5], '5678') # resource_id + # self.assertEqual(mock_audit.call_args[0][6], 'cms') # service + self.assertEqual(mock_audit.call_args[0][7], '') # user_id + self.assertEqual(mock_audit.call_args[0][8], 'NA') # external_id + self.assertEqual(mock_audit.call_args[0][9], '') # event_details + # self.assertEqual(mock_audit.call_args[0][10], 'Saved to DB') # status + + @mock.patch('audit_client.api.audit.init') + @mock.patch('audit_client.api.audit.audit') + def test_audit_service_with_requester(self, mock_audit, mock_init): + resp = utils.audit_trail('create customer', '1234', + {'X-RANGER-Client': 'Fred', + 'X-RANGER-Requester': 'Req04'}, '5678') + self.assertEqual(mock_audit.call_args[0][1], 'Fred') # application_id + self.assertEqual(mock_audit.call_args[0][2], '1234') # tracking_id + self.assertEqual(mock_audit.call_args[0][3], '1234') # transaction_id + self.assertEqual(mock_audit.call_args[0][4], 'create customer') # transaction_type + self.assertEqual(mock_audit.call_args[0][5], '5678') # resource_id + # self.assertEqual(mock_audit.call_args[0][6], 'cms') # service + self.assertEqual(mock_audit.call_args[0][7], 'Req04') # user_id + self.assertEqual(mock_audit.call_args[0][8], 'NA') # external_id + self.assertEqual(mock_audit.call_args[0][9], '') # event_details + # self.assertEqual(mock_audit.call_args[0][10], 'Saved to DB') # status + + def test_set_utils_conf(self): + utils.set_utils_conf('test') + self.assertEqual(utils.conf, 'test') + + def test_check_conf_initialization(self): + utils.set_utils_conf(None) + self.assertRaises(AssertionError, utils._check_conf_initialization) + + @mock.patch('requests.post') + def test_create_existing_uuid(self, mock_post): + uuid = '987654321' + uuid_type = 'testtype' + mock_post.return_value = self.respond( + {'uuid': uuid, 'uuid_type': uuid_type}, 200) + returned_uuid = utils.create_or_validate_uuid(uuid, uuid_type) + self.assertEqual(returned_uuid, uuid) + + @mock.patch('requests.post') + def test_create_existing_uuid_with_exception(self, mock_post): + mock_post.side_effect = Exception('boom') + uuid = '987654321' + uuid_type = 'testtype' + returned_uuid = utils.create_or_validate_uuid(uuid, uuid_type) + self.assertEqual(returned_uuid, None) + + @mock.patch('requests.post') + def test_create_existing_uuid_with_400(self, mock_post): + uuid = '987654321' + uuid_type = 'testId' + mock_post.return_value = self.respond({'uuid': uuid, 'uuid_type': uuid_type}, 409) + self.assertRaises(TypeError, utils.create_or_validate_uuid(uuid, uuid_type)) + + @mock.patch('pecan.conf') + def test_report_config(self, mock_conf): + expected_value = pprint.pformat(mock_conf.to_dict(), indent=4) + returned_value = utils.report_config(mock_conf) + self.assertEqual(expected_value, returned_value) + + @mock.patch('pecan.conf') + def test_report_config_with_log_write(self, mock_conf): + expected_value = pprint.pformat(mock_conf.to_dict(), indent=4) + returned_value = utils.report_config(mock_conf, True) + self.assertEqual(expected_value, returned_value) + + @mock.patch('requests.get') + def test_get_resource_status_sanity(self, mock_get): + my_response = mock.MagicMock() + my_response.status_code = 200 + my_response.json.return_value = 'test' + mock_get.return_value = my_response + result = utils.get_resource_status('A') + self.assertEqual(result, 'test') + + @mock.patch('requests.get', side_effect=ValueError()) + def test_get_resource_status_get_failed(self, mock_get): + self.assertIsNone(utils.get_resource_status('A')) + + @mock.patch('requests.get') + def test_get_resource_status_invalid_response(self, mock_get): + my_response = mock.MagicMock() + my_response.status_code = 404 + mock_get.return_value = my_response + self.assertIsNone(utils.get_resource_status('A')) diff --git a/orm/common/orm_common/utils/api_error_utils.py b/orm/common/orm_common/utils/api_error_utils.py index 1ce17862..59477d4d 100755 --- a/orm/common/orm_common/utils/api_error_utils.py +++ b/orm/common/orm_common/utils/api_error_utils.py @@ -1,5 +1,4 @@ import json - from orm.common.orm_common.utils import utils from wsme.exc import ClientSideError @@ -40,7 +39,7 @@ error_message = { 404: {'message': 'The specific transaction was not found', 'type': 'Not Found'}, 405: {'message': 'This method is not allowed', 'type': 'Method Not Allowed'}, 409: {'message': 'Current resource is busy', 'type': 'Conflict'}, - 409.1: {'message': 'Customer UUID already exists', 'type': 'Conflict'}, + 409.1: {'message': 'UUID already exists', 'type': 'Conflict'}, 409.2: {'message': 'Customer name already exists', 'type': 'Conflict'}, 500: {'message': 'Server error occurred', 'type': 'Internal Server Error'} } diff --git a/orm/common/orm_common/utils/cross_api_utils.py b/orm/common/orm_common/utils/cross_api_utils.py index 34b6c5a3..8b6f5578 100755 --- a/orm/common/orm_common/utils/cross_api_utils.py +++ b/orm/common/orm_common/utils/cross_api_utils.py @@ -1,9 +1,8 @@ import logging -import time - -import requests - from pecan import conf +import requests +import string +import time # from orm_common.logger import get_logger @@ -23,6 +22,28 @@ def _check_conf_initialization(): raise AssertionError('Configurations wasnt initiated, please run set_utils_conf and pass pecan configuration') +def validate_description(data_value): + """ only special characters commas, periods, and dashes allowed in + description field. Return 'False' if other special chars or + escape sequences detected + """ + + allowed_punctuations = ['.', '-', ','] + + # if type of data_value != 'string' then convert it to string + if not isinstance(data_value, str): + desc = str(data_value) + + invalidChars = (string.punctuation).translate(None, ''.join(allowed_punctuations)) + + # detect any escape sequences or special characters in data string + encoded_string = desc.encode('string_escape') + if any(char in invalidChars for char in encoded_string): + return False + + return True + + def is_region_group_exist(group_name): """ function to check whether region group exists returns 200 for ok and None for error diff --git a/orm/common/orm_common/utils/error_base.py b/orm/common/orm_common/utils/error_base.py new file mode 100755 index 00000000..45192dbf --- /dev/null +++ b/orm/common/orm_common/utils/error_base.py @@ -0,0 +1,9 @@ + +class Error(Exception): + pass + + +class ErrorStatus(Error): + + def __init__(self, status_code, message=""): + self.message = message diff --git a/orm/common/orm_common/utils/utils.py b/orm/common/orm_common/utils/utils.py index b21e5189..65e1dfe8 100755 --- a/orm/common/orm_common/utils/utils.py +++ b/orm/common/orm_common/utils/utils.py @@ -34,44 +34,28 @@ def _check_conf_initialization(): 'pass pecan coniguration') -def make_uuid(): - """ function to request new uuid from uuid_generator rest service +def create_or_validate_uuid(uuid, uuid_type): + """ function to: + 1) request new uuid from uuid_generator rest service + 2) validate a uuid if one is being set returns uuid string """ _check_conf_initialization() url = conf.api.uuid_server.base + conf.api.uuid_server.uuids - try: + if not uuid: logger.debug('Requesting new UUID from URL: {}'.format(url)) - resp = requests.post(url, verify=conf.verify) - except requests.exceptions.ConnectionError as exp: - nagios = 'CON{}UUIDGEN001'.format(conf.server.name.upper()) - logger.critical('CRITICAL|{}|Failed in make_uuid: connection error: {}'.format(nagios, str(exp))) - exp.message = 'connection error: Failed to get uuid: unable to connect to server' - raise - except Exception as e: - logger.info('Failed in make_uuid:' + str(e)) - return None - - resp = resp.json() - return resp['uuid'] - - -def create_existing_uuid(uuid): - """ function to request new uuid from uuid_generator rest service - returns uuid string - :param uuid: - :return: - """ - _check_conf_initialization() - url = conf.api.uuid_server.base + conf.api.uuid_server.uuids + else: + logger.debug('Creating UUID: {}, using URL: {}'.format(uuid, url)) try: - logger.debug('Creating UUID: {}, using URL: {}'.format(uuid, url)) - resp = requests.post(url, data={'uuid': uuid}, verify=conf.verify) + resp = requests.post(url, data={'uuid': uuid, 'uuid_type': uuid_type}, + verify=conf.verify) except requests.exceptions.ConnectionError as exp: nagios = 'CON{}UUIDGEN001'.format(conf.server.name.upper()) - logger.critical('CRITICAL|{}|Failed in create_existing_uuid: connection error: {}'.format(nagios, str(exp))) + logger.critical( + 'CRITICAL|{}|Failed in make_uuid: connection error: {}'.format( + nagios, str(exp))) exp.message = 'connection error: Failed to get uuid: unable to connect to server' raise except Exception as e: @@ -79,7 +63,9 @@ def create_existing_uuid(uuid): return None if resp.status_code == 400: - raise TypeError('duplicate key for uuid') + logger.debug('Duplicate key for uuid: {}'.format(uuid)) + raise TypeError('Duplicate key for uuid: ' + str(uuid)) + resp = resp.json() return resp['uuid'] @@ -110,6 +96,7 @@ def make_transid(): else: return None + audit_setup = False diff --git a/orm/orm_client/db_clear/cli_comander.py b/orm/orm_client/db_clear/cli_comander.py index 7b1dd5cd..0fbb39e5 100644 --- a/orm/orm_client/db_clear/cli_comander.py +++ b/orm/orm_client/db_clear/cli_comander.py @@ -1,49 +1,99 @@ -import config as conf -import json -import logging -import os - - -log = logging.getLogger(__name__) - - -def _get_regions(customer): - regions = [] - try: - customer_json = json.loads(customer) - if 'regions' not in customer_json: - raise Exception("got bad response from orm cli ") - for region in customer_json['regions']: - regions.append(region['name']) - except Exception as exp: - raise Exception("got bad response from orm cli {}".format(exp.message)) - message = "got no regions from orm cli" - if regions: - message = "got regions from orm cli --{}--".format(regions) - log.debug(message) - return regions - - -def _build_get_customer_cli_command(resource_id): - cli_command = """get_customer %s""" % resource_id - log.debug('cli command {}'.format(cli_command)) - return cli_command - - -def _get_customer_regions(cli_command, service): - client_header = service.upper() - log.debug("get customer with cli") - os.chdir(conf.cli_dir) - cwd = os.getcwd() - customer = os.popen('./orm %s %s ' % (service.lower(), cli_command)) - log.debug("got cusmer with cli ... check if got regions") - return _get_regions(customer.read()) - - -def get_resource_regions(resource_id, service): - log.debug("---ORM CLI---") - regions = None - if service.upper() == 'CMS': - regions = _get_customer_regions( - _build_get_customer_cli_command(resource_id), service) - return regions +import config as conf +import json +import logging +import os +import subprocess + +log = logging.getLogger(__name__) + + +def _get_cms_regions(customer): + regions = [] + try: + customer_json = json.loads(customer) + if 'regions' not in customer_json: + raise Exception("got bad response from orm cli ") + for region in customer_json['regions']: + regions.append(region['name']) + except Exception as exp: + raise Exception("got bad response from orm cli {}".format(exp.message)) + message = "got no regions from orm cli" + if regions: + message = "got regions from orm cli --{}--".format(regions) + log.debug(message) + return regions + + +def _get_flavor_regions(flavor): + regions = [] + + try: + flavor_json = json.loads(flavor) + if 'regions' not in flavor_json['flavor']: + raise Exception("got bad response from orm cli ") + for region in flavor_json['flavor']['regions']: + regions.append(region['name']) + except Exception as exp: + raise Exception("got bad response from orm cli {}".format(exp.message)) + + message = "got no regions from orm cli" + if regions: + message = "got regions from orm cli --{}--".format(regions) + log.debug(message) + return regions + + +def _get_image_regions(image): + regions = [] + try: + image_json = json.loads(image) + if 'regions' not in image_json['image']: + raise Exception("got bad response from orm cli ") + for region in image_json['image']['regions']: + regions.append(region['name']) + except Exception as exp: + raise Exception("got bad response from orm cli {}".format(exp.message)) + message = "got no regions from orm cli" + if regions: + message = "got regions from orm cli --{}--".format(regions) + log.debug(message) + return regions + + +def get_resource_regions(resource_id, service): + regions = None + + client_header = service.upper() + os.chdir(conf.cli_dir) + cwd = os.getcwd() + log.debug("---ORM CLI---") + + if service.upper() == 'CMS': + log.debug("get customer with cli") + cli_command = """get_customer %s""" % resource_id + log.debug('cli command {}'.format(cli_command)) + cmd = 'python orm %s %s ' % (service.lower(), cli_command) + customer = subprocess.check_output(cmd.split(), shell=False) + log.debug("got customer with cli ... check if got regions") + + return _get_cms_regions(customer) + + elif service.upper() == 'FMS': + log.debug("get flavor with cli") + cli_command = """get_flavor %s""" % resource_id + log.debug('cli command {}'.format(cli_command)) + cmd = 'python orm %s %s ' % (service.lower(), cli_command) + log.debug("got flavor with cli ... check if got regions") + flavor = subprocess.check_output(cmd.split(), shell=False) + + return _get_flavor_regions(flavor) + + elif service.upper() == 'IMS': + log.debug("get image with cli") + cli_command = """get_image %s""" % resource_id + log.debug('cli command {}'.format(cli_command)) + cmd = 'python orm %s %s ' % (service.lower(), cli_command) + log.debug("got image with cli ... check if got regions") + flavor = subprocess.check_output(cmd.split(), shell=False) + + return _get_image_regions(flavor) diff --git a/orm/orm_client/db_clear/config.py b/orm/orm_client/db_clear/config.py index 29b9ecb5..65a4704d 100644 --- a/orm/orm_client/db_clear/config.py +++ b/orm/orm_client/db_clear/config.py @@ -1,25 +1,38 @@ -"""config module.""" - -# db configs -sql_user = 'root' -sql_password = 'stack' -sql_server = '127.0.0.1' -sql_port = '3306' - -# cms configs -customer_table_name = "customer" -customer_region_table_name = "customer_region" -cms_db_name = "orm_cms_db" - - -# cli configs -cli_dir = '../ormcli' - -# rds configs -rds_db_name = 'orm_rds' -resource_status_table_name = 'resource_status' - -# sot configs -local_repository_path = '/opt/app/orm/ORM' -file_name_format = 's_{}.yml' -relative_path_format = '/{}/hot/{}/{}' +"""config module.""" + +# db configs +sql_user = 'root' +sql_password = 'xxxxxxxxxxx' +sql_server = '127.0.0.1' +sql_port = '3306' + +# cms configs +customer_table_name = "customer" +customer_tbl_column = "uuid" +customer_region_table_name = "customer_region" +cms_db_name = "orm_cms_db" + +# fms configs +flavor_table_name = "flavor" +flavor_tbl_column = "id" +flavor_region_table_name = "flavor_region" +fms_db_name = "orm_fms_db" + +# ims configs +image_table_name = "image" +image_tbl_column = "id" +image_region_table_name = "image_region" +ims_db_name = "orm_ims_db" + +# cli configs +cli_dir = '../ormcli' + +# rds configs +rds_db_name = 'orm_rds' +resource_status_table_name = 'resource_status' +image_metadata_table_name = 'image_metadata' + +# sot configs +local_repository_path = '/opt/app/orm/ORM' +file_name_format = 's_{}.yml' +relative_path_format = '/{}/hot/{}/{}' diff --git a/orm/orm_client/db_clear/db_comander.py b/orm/orm_client/db_clear/db_comander.py index 4bf8b7bb..930125e5 100644 --- a/orm/orm_client/db_clear/db_comander.py +++ b/orm/orm_client/db_clear/db_comander.py @@ -1,130 +1,215 @@ -import config as conf -import logging -import sqlalchemy - - -log = logging.getLogger(__name__) - - -db_engines = {} - - -def _db_create_engine(db_name): - global db_engines - if db_name not in db_engines: - db_address = 'mysql://{}:{}@{}:{}/{}'.format(conf.sql_user, - conf.sql_password, - conf.sql_server, - conf.sql_port, - db_name) - log.debug("DB:--- db address {}".format(db_address)) - db_engines[db_name] = sqlalchemy.create_engine(db_address) - return db_engines - - -def _run_query(query, db_name): - db_engines = _db_create_engine(db_name) - connection = db_engines[db_name].connect() - try: - sqlres = connection.execute(query) - except Exception as exp: - sqlres = None - log.error("fail to delete resource {}".format(exp)) - finally: - # close the connection - connection.close() - # db_engines[db_name].dispose() - return sqlres - - -def _build_delet_resource_status_query(resource_id, table_name): - query = ''' - DELETE from %s - WHERE resource_id = '%s' - ''' % (table_name, resource_id) - return query - - -def _build_delete_resource_query(resource_id, table_name): - query = ''' - DELETE from %s - WHERE %s.uuid = '%s' - ''' % (table_name, table_name, resource_id) - return query - - -def _build_get_resource_regions_query(resource_id, table_name): - query = ''' - select region_id from %s - WHERE customer_id = '%s' and region_id != '-1' - ''' % (table_name, resource_id) - return query - - -def _build_get_resource_id_query(resource_id, table_name): - query = ''' - select * from %s - WHERE %s.uuid = '%s' - ''' % (table_name, table_name, resource_id) - return query - - -def remove_cms_resource(resource_id): - query = _build_delete_resource_query(resource_id, conf.customer_table_name) - log.debug("DB---: deleting customer, query {}".format(query)) - _run_query(query, conf.cms_db_name) - return - - -def remove_rds_resource_status(resource_id): - query = _build_delet_resource_status_query(resource_id, - conf.resource_status_table_name) - log.debug("DB---: deleting resource status, query {}".format(query)) - _run_query(query, conf.rds_db_name) - return - - -def remove_ims_resource(resource_id): - return - - -def remove_fms_resource(resource_id): - return - - -def get_cms_db_resource_regions(resource_id): - regions = None - query = _build_get_resource_id_query(resource_id, conf.customer_table_name) - result = _run_query(query, conf.cms_db_name) - if not result.rowcount > 0: - raise Exception('resource {} not found'.format(resource_id)) - resource_internal_id = result.first().__getitem__('id') - log.debug("got resource internal id {}".format(resource_internal_id)) - # from resource id get regions - query = _build_get_resource_regions_query(resource_internal_id, - conf.customer_region_table_name) - log.debug(query) - result = _run_query(query, conf.cms_db_name) - if result.rowcount > 0: - regions = result.fetchall() - return regions - - -def get_ims_db_resource_regions(resource_id): - return - - -def get_fms_db_resource_regions(resource_id): - return - - -def get_rds_db_resource_status(resource_id): - return - - -def remove_resource_db(resource_id, service): - if service == 'CMS': - log.debug( - "cleaning {} db for resource {}".format(service, resource_id)) - remove_cms_resource(resource_id) - return +import config as conf +import logging +import sqlalchemy + +log = logging.getLogger(__name__) + +db_engines = {} + + +def _db_create_engine(db_name): + global db_engines + if db_name not in db_engines: + db_address = 'mysql://{}:{}@{}:{}/{}'.format(conf.sql_user, + conf.sql_password, + conf.sql_server, + conf.sql_port, + db_name) + db_engines[db_name] = sqlalchemy.create_engine(db_address) + return db_engines + + +def _get_db_info(service): + if service.upper() == 'CMS': + db_name = conf.cms_db_name + table_col = conf.customer_tbl_column + table_name = conf.customer_table_name + region_table_name = conf.customer_region_table_name + + elif service.upper() == 'FMS': + db_name = conf.fms_db_name + table_col = conf.flavor_tbl_column + table_name = conf.flavor_table_name + region_table_name = conf.flavor_region_table_name + + elif service.upper() == 'IMS': + db_name = conf.ims_db_name + table_col = conf.image_tbl_column + table_name = conf.image_table_name + region_table_name = conf.image_region_table_name + + return db_name, table_name, table_col, region_table_name + + +def _run_query(query, db_name): + db_engines = _db_create_engine(db_name) + connection = db_engines[db_name].connect() + try: + sqlres = connection.execute(query) + except Exception as exp: + sqlres = None + log.error("fail to delete resource {}".format(exp)) + finally: + # close the connection + connection.close() + # db_engines[db_name].dispose() + return sqlres + + +def _build_delet_resource_status_query(resource_id, table_name): + query = ''' + DELETE from %s + WHERE resource_id = '%s' + ''' % (table_name, resource_id) + return query + + +def _build_delete_image_metadata(resource_id, image_metadata_table, + resource_table): + query = ''' + DELETE from %s + WHERE image_meta_data_id in + (SELECT id from %s where resource_id = '%s') + ''' % (image_metadata_table, resource_table, resource_id) + return query + + +def _build_delete_resource_query(resource_id, table_col, table_name): + query = ''' + DELETE from %s + WHERE %s.%s = '%s' + ''' % (table_name, table_name, table_col, resource_id) + return query + + +def _build_get_cms_regions_query(resource_id, table_name): + query = ''' + select region_id from %s + WHERE customer_id = '%s' and region_id != '-1' + ''' % (table_name, resource_id) + return query + + +def _build_get_fms_regions_query(resource_id, table_name): + query = ''' + select region_name from %s + WHERE flavor_internal_id = '%s' + ''' % (table_name, resource_id) + return query + + +def _build_get_ims_regions_query(resource_id, table_name): + query = ''' + select region_name from %s + WHERE image_id = '%s' + ''' % (table_name, resource_id) + return query + + +def _build_get_resource_id_query(resource_id, table_col, table_name): + query = ''' + select * from %s + WHERE %s.%s = '%s' + ''' % (table_name, table_name, table_col, resource_id) + return query + + +def remove_resource_id(resource_id, service): + db_name, table_name, table_col, region_table_name = _get_db_info(service) + resource_type = table_name + query = _build_delete_resource_query(resource_id, table_col, table_name) + log.debug("DB---: deleting {}, query {}".format(resource_type, query)) + _run_query(query, db_name) + return + + +def remove_rds_resource_status(resource_id): + query = _build_delet_resource_status_query(resource_id, + conf.resource_status_table_name) + log.debug("DB---: deleting resource status, query {}".format(query)) + _run_query(query, conf.rds_db_name) + return + + +def remove_rds_image_metadata(resource_id): + query = _build_delete_image_metadata(resource_id, + conf.image_metadata_table_name, + conf.resource_status_table_name) + log.debug("DB---: deleting image_metadata, query {}".format(query)) + _run_query(query, conf.rds_db_name) + return + + +def get_cms_db_resource_regions(resource_id, service): + regions = None + db_name, table_name, table_col, region_table_name = _get_db_info(service) + + query = _build_get_resource_id_query(resource_id, table_col, table_name) + result = _run_query(query, db_name) + if not result.rowcount > 0: + raise Exception('resource {} not found'.format(resource_id)) + resource_internal_id = result.first().__getitem__('id') + log.debug("got resource internal id {}".format(resource_internal_id)) + # from resource id get regions + query = _build_get_cms_regions_query(resource_internal_id, + region_table_name) + + log.debug(query) + result = _run_query(query, db_name) + if result.rowcount > 0: + regions = result.fetchall() + return regions + + +def get_fms_db_resource_regions(resource_id, service): + regions = None + db_name, table_name, table_col, region_table_name = _get_db_info(service) + + query = _build_get_resource_id_query(resource_id, table_col, + conf.flavor_table_name) + result = _run_query(query, db_name) + if not result.rowcount > 0: + raise Exception('resource {} not found'.format(resource_id)) + resource_internal_id = result.first().__getitem__('internal_id') + log.debug("got resource internal id {}".format(resource_internal_id)) + # from resource id get regions + query = _build_get_fms_regions_query(resource_internal_id, + region_table_name) + log.debug(query) + result = _run_query(query, db_name) + if result.rowcount > 0: + regions = result.fetchall() + return regions + + +def get_ims_db_resource_regions(resource_id, service): + regions = None + db_name, table_name, table_col, region_table_name = _get_db_info(service) + + query = _build_get_resource_id_query(resource_id, table_col, table_name) + result = _run_query(query, db_name) + if not result.rowcount > 0: + raise Exception('resource {} not found'.format(resource_id)) + resource_internal_id = result.first().__getitem__('id') + log.debug("got resource internal id {}".format(resource_internal_id)) + # from resource id get regions + query = _build_get_ims_regions_query(resource_internal_id, + region_table_name) + + log.debug(query) + result = _run_query(query, db_name) + if result.rowcount > 0: + regions = result.fetchall() + return regions + + +def get_rds_db_resource_status(resource_id): + return + + +def remove_resource_db(resource_id, service): + log.debug( + "cleaning {} db for resource {}".format(service, resource_id)) + remove_resource_id(resource_id, service) + + return diff --git a/orm/orm_client/db_clear/resource_cleaner.py b/orm/orm_client/db_clear/resource_cleaner.py new file mode 100755 index 00000000..aa04a1f0 --- /dev/null +++ b/orm/orm_client/db_clear/resource_cleaner.py @@ -0,0 +1,111 @@ +import cli_comander as cli +import db_comander as db +import initializer +import logging +import sys +import utils +import yaml_handler as yh + + +log = logging.getLogger(__name__) + + +def _validate_service(service): + allowed_services = ['CMS', 'FMS', 'IMS'] + if service.upper() not in allowed_services: + raise Exception("service should be one of {}".format(allowed_services)) + return service.upper() + + +def _init(): + initializer.init_log() + return + + +def read_csv_file(file): + log.debug("reading file {}".format(file)) + return utils.read_csv_file(file) + + +def resource_db_clean(resource_id, service): + log.debug("cleaning {} db for resource {}".format(service, resource_id)) + db.remove_resource_db(resource_id, service) + return + + +def check_yaml_file(resource_id): + log.debug('checking yml file if exist for resource {}'.format(resource_id)) + files = yh.check_yaml_exist(resource_id) + message = 'no yaml files found for this resource' + if files: + message = "found files please remove manualy {}".format(files) + log.debug(message) + return + + +def get_resource_regions(resource_id, service_name): + + if service_name.upper() == 'CMS': + db_regions = db.get_cms_db_resource_regions(resource_id, service_name) + elif service_name.upper() == 'FMS': + db_regions = db.get_fms_db_resource_regions(resource_id, service_name) + elif service_name.upper() == 'IMS': + db_regions = db.get_ims_db_resource_regions(resource_id, service_name) + +# db_regions = db.get_resource_regions(resource_id, service_name) + orm_regions = cli.get_resource_regions(resource_id, service_name) + return orm_regions, db_regions + + +def clean_rds_resource_status(resource_id): + log.debug("clean rds status db for resource {}".format(resource_id)) + db.remove_rds_resource_status(resource_id) + return + + +def _start_cleaning(): + log.info('start cleaning') + file_path = sys.argv[1] + service = _validate_service(sys.argv[2]) + resourses_to_clean = read_csv_file(file_path) + for resource_id in resourses_to_clean: + try: + log.debug( + 'check if resource {} has any regions before clean'.format( + resource_id)) + resource_regions, db_regions = get_resource_regions(resource_id, + service) + if resource_regions or db_regions: + log.error( + "got regions {} {} please clean regions from orm before" + " removing the resource {}".format(resource_regions, + db_regions, + resource_id)) + raise Exception( + "got regions {} {} please clean regions from orm before" + " removing the resource {}".format(resource_regions, + db_regions, + resource_id)) + + log.debug('cleaning {}'.format(resource_id)) + resource_db_clean(resource_id, service) + check_yaml_file(resource_id) + clean_rds_resource_status(resource_id) + if service.upper() == "IMS": + db.remove_rds_image_metadata(resource_id) + + except Exception as exp: + log.error("---------------{}---------------".format(exp.message)) + if 'not found' not in exp.message: + log.exception(exp) + continue + return + + +if __name__ == '__main__': + warning_message = raw_input( + 'IMPORTANT:- please note its your responsibility to backup the db' + ' before running this script... click enter before continue' + ) + _init() + _start_cleaning() diff --git a/orm/orm_client/db_clear/yaml_handler.py b/orm/orm_client/db_clear/yaml_handler.py index 36b5a657..f2ecafd1 100644 --- a/orm/orm_client/db_clear/yaml_handler.py +++ b/orm/orm_client/db_clear/yaml_handler.py @@ -1,25 +1,25 @@ -import config as conf -import fnmatch -import os - - -def _get_resource_file_path(): - file_path = conf.local_repository_path - return file_path - - -def _find_file(resource_id): - file_name = conf.file_name_format.format(resource_id) - folder_to_search = _get_resource_file_path(resource_id) - matches = [] - for root, dirnames, filenames in os.walk(folder_to_search): - for filename in fnmatch.filter(filenames, file_name): - matches.append(os.path.join(root, filename)) - return matches - - -def check_yaml_exist(resource_id): - files = _find_file(resource_id) - if files: - return files - return None +import config as conf +import fnmatch +import os + + +def _get_resource_file_path(): + file_path = conf.local_repository_path + return file_path + + +def _find_file(resource_id): + file_name = conf.file_name_format.format(resource_id) + folder_to_search = _get_resource_file_path() + matches = [] + for root, dirnames, filenames in os.walk(folder_to_search): + for filename in fnmatch.filter(filenames, file_name): + matches.append(os.path.join(root, filename)) + return matches + + +def check_yaml_exist(resource_id): + files = _find_file(resource_id) + if files: + return files + return None diff --git a/orm/orm_client/flavorgen/README b/orm/orm_client/flavorgen/README index a4e696a6..2e6f4a6f 100644 --- a/orm/orm_client/flavorgen/README +++ b/orm/orm_client/flavorgen/README @@ -18,24 +18,22 @@ You should normally create the list of flavors once. Then when you want to add regions to all the flavors, use: -7. ./regionator.py --regions region1,region2 +7. ./regionator.py region1,region2 series1,series2 -The argument is a comma-separated list of regions with no internal whitespace. +The argument is a comma-separated list of regions and series +with no internal whitespace. Use of -h will produce the following help: ./regionator.py -h -usage: regionator [-h] [--flavor_dir FLAVOR_DIR] [--host HOST] - [--cli_command CLI_COMMAND] [--regions REGIONS] +usage: regionator [-h] regions [series] batch add region to flavor +positional arguments: + regions + series + optional arguments: - -h, --help show this help message and exit - --flavor_dir FLAVOR_DIR - - --host HOST - --cli_command CLI_COMMAND - - --regions REGIONS + -h, --help show this help message and exit diff --git a/orm/orm_client/flavorgen/flavorator.py b/orm/orm_client/flavorgen/flavorator.py index 09098a48..ecaf43a8 100644 --- a/orm/orm_client/flavorgen/flavorator.py +++ b/orm/orm_client/flavorgen/flavorator.py @@ -29,7 +29,7 @@ def sh(harg, file_name): print '>> Starting: ' + cmd start = time.time() output = '' - p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, + p = subprocess.Popen(cmd.split(), shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) for line in iter(p.stdout.readline, b''): out = line.rstrip() diff --git a/orm/orm_client/flavorgen/regionator.py b/orm/orm_client/flavorgen/regionator.py index 0c66e81e..86d08887 100644 --- a/orm/orm_client/flavorgen/regionator.py +++ b/orm/orm_client/flavorgen/regionator.py @@ -30,7 +30,7 @@ def get_region_list(regions): REGION_NAME = region res, output = sh('get_region') if not res: - result_region = ast.literal_eval(output) + result_region = json.loads(output) result.append({'name': result_region['name'], 'designType': result_region['designType']}) else: @@ -44,9 +44,9 @@ def create_command(cli_command): if cli_command == 'add_region': cmd = 'python %s fms add_region %s %s' % (CLI_PATH, FID, FILE_NAME,) elif cli_command == 'get_flavor': - cmd = '%s fms get_flavor test %s' % (CLI_PATH, FLAVOR_NAME,) + cmd = 'python %s fms get_flavor test %s' % (CLI_PATH, FLAVOR_NAME,) elif cli_command == 'get_region': - cmd = '%s rms get_region %s' % (CLI_PATH, REGION_NAME,) + cmd = 'python %s rms get_region %s' % (CLI_PATH, REGION_NAME,) else: raise ValueError('Received an unknown command: %s' % (cli_command,)) @@ -79,7 +79,7 @@ def sh(cli_command): start = time.time() output = '' errpat = re.compile('error', re.I) - p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + p = subprocess.Popen(cmd.split(), shell=False, stdout=subprocess.PIPE) for line in iter(p.stdout.readline, b''): out = line.rstrip() print(">>> " + out) diff --git a/orm/orm_client/imagegen/imageator.py b/orm/orm_client/imagegen/imageator.py index b2477f19..8530d2a4 100644 --- a/orm/orm_client/imagegen/imageator.py +++ b/orm/orm_client/imagegen/imageator.py @@ -1,8 +1,8 @@ #!/usr/bin/env python -from os.path import isfile, join import argparse import json import os +from os.path import isfile, join import re import subprocess import tempfile @@ -29,7 +29,9 @@ def sh(cmd): start = time.time() output = '' errpat = re.compile('error', re.I) - p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, + + cmd = 'python ' + cmd + p = subprocess.Popen(cmd.split(), shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) for line in iter(p.stdout.readline, b''): out = line.rstrip() diff --git a/orm/orm_client/imagegen/regionator.py b/orm/orm_client/imagegen/regionator.py index 0a77587b..35396d44 100644 --- a/orm/orm_client/imagegen/regionator.py +++ b/orm/orm_client/imagegen/regionator.py @@ -1,9 +1,9 @@ #!/usr/bin/env python -from os.path import isfile, join import argparse import ast import json import os +from os.path import isfile, join import re import subprocess import tempfile @@ -29,7 +29,7 @@ def sh(cmd): start = time.time() output = '' errpat = re.compile('error', re.I) - p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + p = subprocess.Popen(cmd.split(), shell=False, stdout=subprocess.PIPE) for line in iter(p.stdout.readline, b''): out = line.rstrip() print(">>> " + out) @@ -74,7 +74,7 @@ os.close(fh) img_dict = {} # harg = '--orm-base-url %s' % args.host if args.host else '' res, output = sh( - '%s ims %s list_images test ' % (CLI_PATH, '')) + 'python %s ims %s list_images test ' % (CLI_PATH, '')) if not res: images = ast.literal_eval(output) for img in images['images']: @@ -90,9 +90,10 @@ if not res: if image_name in img_dict: image_id = img_dict[image_name] print 'image_id: ' + image_id - res, output = sh('%s ims add_regions test %s %s' % ( + res, output = sh('python %s ims add_regions test %s %s' % ( CLI_PATH, image_id, file_name)) else: - print 'image_name: {} does not exist. ignore.'.format(image_name) + print 'python image_name: {} does not exist. ' \ + 'ignore.'.format(image_name) os.unlink(file_name) diff --git a/orm/orm_client/ormcli/cmscli.py b/orm/orm_client/ormcli/cmscli.py index 9de223b9..e3fec479 100644 --- a/orm/orm_client/ormcli/cmscli.py +++ b/orm/orm_client/ormcli/cmscli.py @@ -2,7 +2,6 @@ import argparse import cli_common import config -import orm.base_config as base_config import os import requests @@ -44,7 +43,7 @@ def add_to_parser(service_sub): parser.add_argument('-v', '--verbose', help='show details', action="store_true") parser.add_argument('-f', '--faceless', - help='run without authentication', + help=argparse.SUPPRESS, default=False, action="store_true") subparsers = parser.add_subparsers(dest='subcmd', @@ -112,11 +111,16 @@ def add_to_parser(service_sub): parser_delete_region = subparsers.add_parser('delete_region', help='[<"X-RANGER-Client" ' - 'header>] ' + 'header>] ' + '[--force_delete] ' + ' ' '') parser_delete_region.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_delete_region.add_argument('custid', type=str, help='') parser_delete_region.add_argument('regionid', type=str, help='') + parser_delete_region.add_argument('--force_delete', + help='force delete region', + action="store_true") # add user parser_add_user = subparsers.add_parser('add_user', @@ -216,11 +220,8 @@ def add_to_parser(service_sub): help='') # add metadata - h1, h2, h3 = \ - '[<"X-RANGER-Client" header>]', '', '' + h1, h2, h3 = ('[<"X-RANGER-Client" header>]', '', + '') parser_add_metadata = subparsers.add_parser('add_metadata', help='%s %s %s' % (h1, h2, h3)) parser_add_metadata.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) @@ -230,11 +231,8 @@ def add_to_parser(service_sub): help=h3) # replace metadata - h1, h2, h3 = \ - '[<"X-RANGER-Client" header>]', '', '' + h1, h2, h3 = ('[<"X-RANGER-Client" header>]', '', + '') parser_replace_metadata = subparsers.add_parser('replace_metadata', help='%s %s %s' % ( h1, h2, h3)) @@ -247,16 +245,16 @@ def add_to_parser(service_sub): help=h3) # get customer + h1, h2 = '[<"X-RANGER-Client" header>]', '' parser_get_customer = subparsers.add_parser('get_customer', - help='[<"X-RANGER-Client" ' - 'header>] ') + help='%s %s' % (h1, h2)) parser_get_customer.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) - parser_get_customer.add_argument('custid', type=str, help='') + parser_get_customer.add_argument('custid', type=str, help=h2) # list customers h1 = '[<"X-RANGER-Client" header>]' h2 = '[--region ] [--user ] [--metadata ]' \ - ' [starts_with ] [contains ]' + ' [--starts_with ] [--contains ]' parser_list_customer = subparsers.add_parser('list_customers', help='%s %s' % (h1, h2)) parser_list_customer.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) @@ -288,7 +286,9 @@ def cmd_details(args): elif args.subcmd == 'replace_region': return requests.put, '/%s/regions' % args.custid elif args.subcmd == 'delete_region': - return requests.delete, '/%s/regions/%s' % (args.custid, args.regionid) + return requests.delete, '/%s/regions/%s/%s' % (args.custid, + args.regionid, + args.force_delete) elif args.subcmd == 'add_user': return requests.post, '/%s/regions/%s/users' % ( args.custid, args.regionid) @@ -353,12 +353,12 @@ def get_token(timeout, args, host): globals()[argument] = configuration_value else: message = ('ERROR: {} for token generation was not supplied. ' - 'Please use its command-line ' - 'argument or environment variable.'.format(argument)) + 'Please use its command-line argument or ' + 'environment variable.'.format(argument)) print message raise cli_common.MissingArgumentError(message) - keystone_ep = cli_common.get_keystone_ep('{}:{}'.format(host, base_config.rms['port']), + keystone_ep = cli_common.get_keystone_ep('{}:8080'.format(host), auth_region) if keystone_ep is None: raise ConnectionError( @@ -386,7 +386,7 @@ def get_token(timeout, args, host): def get_environment_variable(argument): # The rules are: all caps, underscores instead of dashes and prefixed - environment_variable = 'RANGER_{}'.format( + environment_variable = 'AIC_ORM_{}'.format( argument.replace('-', '_').upper()) return os.environ.get(environment_variable) @@ -394,7 +394,7 @@ def get_environment_variable(argument): def run(args): host = args.orm_base_url if args.orm_base_url else config.orm_base_url - port = args.port if args.port else base_config.cms['port'] + port = args.port if args.port else 7080 data = args.datafile.read() if 'datafile' in args else '{}' timeout = args.timeout if args.timeout else 10 @@ -429,7 +429,7 @@ def run(args): try: resp = rest_cmd(url, timeout=timeout, data=data, headers=headers, - verify=False) + verify=config.verify) except Exception as e: print e exit(1) diff --git a/orm/orm_client/ormcli/fmscli.py b/orm/orm_client/ormcli/fmscli.py index f076a70a..9cc2c812 100644 --- a/orm/orm_client/ormcli/fmscli.py +++ b/orm/orm_client/ormcli/fmscli.py @@ -2,7 +2,6 @@ import argparse import cli_common import config -import orm.base_config as base_config import os import requests @@ -42,7 +41,7 @@ def add_to_parser(service_sub): parser.add_argument('-v', '--verbose', help='show details', action="store_true") parser.add_argument('-f', '--faceless', - help='run without authentication', + help=argparse.SUPPRESS, default=False, action="store_true") subparsers = parser.add_subparsers(dest='subcmd', @@ -126,7 +125,7 @@ def add_to_parser(service_sub): h1, h2, h3 = ('[<"X-RANGER-Client" header>]', '', '',) parser_delete_extra_spec = subparsers.add_parser('delete_extra_spec', - help='%s%s%s' % ( + help='%s %s %s' % ( h1, h2, h3)) parser_delete_extra_spec.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) @@ -136,7 +135,7 @@ def add_to_parser(service_sub): h1, h2, h3 = ('[<"X-RANGER-Client" header>]', '', '',) parser_add_extra_specs = subparsers.add_parser('add_extra_specs', - help='%s%s%s' % ( + help='%s %s %s' % ( h1, h2, h3)) parser_add_extra_specs.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) @@ -151,7 +150,7 @@ def add_to_parser(service_sub): parser_delete_flavor.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_delete_flavor.add_argument('flavorid', type=str, help=h2) - h1, h2 = '[<"X-RANGER-Client" header>]', '' + h1, h2 = '[<"X-RANGER-Client" header>]', '' parser_get_flavor = subparsers.add_parser('get_flavor', help='%s %s' % (h1, h2)) parser_get_flavor.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) @@ -159,7 +158,8 @@ def add_to_parser(service_sub): h1, h2 = ('[<"X-RANGER-Client" header>]', '[--visibility ] [--region ] [--tenant ' - '] [--series {gv,nv,ns,nd,ss}] [--alias ]') + '] [--series {gv,nv,ns,nd,ss}] [--alias ] ' + '[--vm_type ] [--vnf_name ]') parser_list_flavor = subparsers.add_parser('list_flavors', help='%s %s' % (h1, h2)) parser_list_flavor.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) @@ -174,6 +174,8 @@ def add_to_parser(service_sub): parser_list_flavor.add_argument('--series', type=str, choices=['gv', 'nv', 'ns', 'nd', 'ss']) parser_list_flavor.add_argument('--alias', type=str, help='flavor alias') + parser_list_flavor.add_argument('--vm_type', type=str, help='vm type') + parser_list_flavor.add_argument('--vnf_name', type=str, help='vnf name') # region for flavor h1, h2, h3 = ('[<"X-RANGER-Client" header>]', '', @@ -185,13 +187,17 @@ def add_to_parser(service_sub): parser_add_region.add_argument('datafile', type=argparse.FileType('r'), help=h3) - h1, h2, h3 = '[<"X-RANGER-Client" header>]', '', '' + h1, h2, h3 = '[<"X-RANGER-Client" header>] [--force_delete]', \ + '', '' parser_delete_region = subparsers.add_parser('delete_region', help='%s %s %s' % ( h1, h2, h3)) parser_delete_region.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_delete_region.add_argument('flavorid', type=str, help=h2) parser_delete_region.add_argument('regionid', type=str, help=h3) + parser_delete_region.add_argument('--force_delete', + help='force delete region', + action="store_true") # tenant for flavor h1, h2, h3 = ('[<"X-RANGER-Client" header>]', '', @@ -236,8 +242,8 @@ def cmd_details(args): elif args.subcmd == 'get_tags': return requests.get, '/%s/tags' % args.flavorid elif args.subcmd == 'delete_region': - return requests.delete, '/%s/regions/%s' % ( - args.flavorid, args.regionid) + return requests.delete, '/%s/regions/%s/%s' % ( + args.flavorid, args.regionid, args.force_delete) elif args.subcmd == 'add_tenant': return requests.post, '/%s/tenants' % args.flavorid elif args.subcmd == 'delete_tenant': @@ -266,6 +272,10 @@ def cmd_details(args): param += '%stenant=%s' % (preparm(param), args.tenant) if args.series: param += '%sseries=%s' % (preparm(param), args.series) + if args.vm_type: + param += '%svm_type=%s' % (preparm(param), args.vm_type) + if args.vnf_name: + param += '%svnf_name=%s' % (preparm(param), args.vnf_name) if args.starts_with: param += '%sstarts_with=%s' % (preparm(param), args.starts_with) if args.contains: @@ -300,12 +310,12 @@ def get_token(timeout, args, host): globals()[argument] = configuration_value else: message = ('ERROR: {} for token generation was not supplied. ' - 'Please use its command-line ' - 'argument or environment variable.'.format(argument)) + 'Please use its command-line argument or ' + 'environment variable.'.format(argument)) print message raise cli_common.MissingArgumentError(message) - keystone_ep = cli_common.get_keystone_ep('{}:{}'.format(host, base_config.rms['port']), + keystone_ep = cli_common.get_keystone_ep('{}:8080'.format(host), auth_region) if keystone_ep is None: raise ConnectionError( @@ -333,7 +343,7 @@ def get_token(timeout, args, host): def get_environment_variable(argument): # The rules are: all caps, underscores instead of dashes and prefixed - environment_variable = 'RANGER_{}'.format( + environment_variable = 'AIC_ORM_{}'.format( argument.replace('-', '_').upper()) return os.environ.get(environment_variable) @@ -341,7 +351,7 @@ def get_environment_variable(argument): def run(args): host = args.orm_base_url if args.orm_base_url else config.orm_base_url - port = args.port if args.port else base_config.fms['port'] + port = args.port if args.port else 8082 data = args.datafile.read() if 'datafile' in args else '{}' timeout = args.timeout if args.timeout else 10 @@ -375,7 +385,7 @@ def run(args): timeout, data, headers, rest_cmd.__name__, url)) try: resp = rest_cmd(url, timeout=timeout, data=data, headers=headers, - verify=False) + verify=config.verify) except Exception as e: print e exit(1) diff --git a/orm/orm_client/ormcli/imscli.py b/orm/orm_client/ormcli/imscli.py index aa40f600..48c27da5 100644 --- a/orm/orm_client/ormcli/imscli.py +++ b/orm/orm_client/ormcli/imscli.py @@ -1,11 +1,11 @@ #!/usr/bin/python import argparse -import cli_common import config -import orm.base_config as base_config import os import requests +from orm.orm_client.ormcli import cli_common + class ResponseError(Exception): pass @@ -42,7 +42,7 @@ def add_to_parser(service_sub): parser.add_argument('-v', '--verbose', help='show details', action="store_true") parser.add_argument('-f', '--faceless', - help='run without authentication', + help=argparse.SUPPRESS, default=False, action="store_true") subparsers = parser.add_subparsers(dest='subcmd', @@ -74,7 +74,7 @@ def add_to_parser(service_sub): parser_delete_image.add_argument('imageid', type=str, help=h2) # get images - h1, h2 = '[<"X-RANGER-Client" header>]', '' + h1, h2 = '[<"X-RANGER-Client" header>]', '' parser_get_image = subparsers.add_parser('get_image', help='%s %s' % (h1, h2)) parser_get_image.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) @@ -92,17 +92,15 @@ def add_to_parser(service_sub): parser_list_images.add_argument('--customer', type=str, help='customer id') # activate/deactivate image - h1, h2 = '[<"X-RANGER-Client" header>]', '' - parser_enable = subparsers.add_parser('enable', - help='%s %s' % (h1, h2)) - parser_enable.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) - parser_enable.add_argument('imageid', type=str, help=h2) - - parser_disable = subparsers.add_parser('disable', - help='%s %s' % (h1, h2)) - - parser_disable.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) - parser_disable.add_argument('imageid', type=str, help=h2) + h1, h2, h3 = '[<"X-RANGER-Client" header>]', '', \ + '' + parser_enable_image = subparsers.add_parser('enabled', + help='%s %s %s' % (h1, h2, h3)) + parser_enable_image.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) + parser_enable_image.add_argument('imageid', type=str, help=h2) + parser_enable_image.add_argument('datafile', + type=argparse.FileType('r'), + help=h3) # region for image h1, h2, h3 = '[<"X-RANGER-Client" header>]', '', \ @@ -128,7 +126,8 @@ def add_to_parser(service_sub): type=argparse.FileType('r'), help=h3) - h1, h2, h3 = '[<"X-RANGER-Client" header>]', '', '' + h1, h2, h3 = '[<"X-RANGER-Client" header>] [--force_delete]', \ + '', '' parser_delete_region = subparsers.add_parser('delete_region', help='%s %s %s' % (h1, h2, @@ -136,6 +135,9 @@ def add_to_parser(service_sub): parser_delete_region.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_delete_region.add_argument('imageid', type=str, help=h2) parser_delete_region.add_argument('regionid', type=str, help=h3) + parser_delete_region.add_argument('--force_delete', + help='force delete region', + action="store_true") # customer for image h1, h2, h3 = '[<"X-RANGER-Client" header>]', '', \ @@ -200,12 +202,12 @@ def get_token(timeout, args, host): globals()[argument] = configuration_value else: message = ('ERROR: {} for token generation was not supplied. ' - 'Please use its command-line ' - 'argument or environment variable.'.format(argument)) + 'Please use its command-line argument or ' + 'environment variable.'.format(argument)) print message raise cli_common.MissingArgumentError(message) - keystone_ep = cli_common.get_keystone_ep('{}:{}'.format(host, base_config.rms['port']), + keystone_ep = cli_common.get_keystone_ep('{}:8080'.format(host), auth_region) if keystone_ep is None: raise ConnectionError( @@ -236,40 +238,40 @@ def preparm(p): def cmd_details(args): - data = args.datafile.read() if 'datafile' in args else '{}' if args.subcmd == 'create_image': - cmd, url = requests.post, '' + return requests.post, '' elif args.subcmd == 'update_image': - cmd, url = requests.put, '/%s' % args.imageid + return requests.put, '/%s' % args.imageid + elif args.subcmd == 'delete_image': - cmd, url = requests.delete, '/%s' % args.imageid + return requests.delete, '/%s' % args.imageid # activate/deactivate image - elif args.subcmd in ('enable', 'disable'): - cmd, url = requests.put, '/%s/enabled' % args.imageid - data = '{"enabled": %s}' % ('true' if args.subcmd == 'enable' else - 'false') + elif args.subcmd == 'enabled': + return requests.put, '/%s/enabled' % args.imageid + # image regions elif args.subcmd == 'add_regions': - cmd, url = requests.post, '/%s/regions' % args.imageid + return requests.post, '/%s/regions' % args.imageid elif args.subcmd == 'update_regions': - cmd, url = requests.put, '/%s/regions' % args.imageid + return requests.put, '/%s/regions' % args.imageid elif args.subcmd == 'delete_region': - cmd, url = requests.delete, '/%s/regions/%s' % (args.imageid, - args.regionid) + return requests.delete, '/%s/regions/%s/%s' % (args.imageid, + args.regionid, + args.force_delete) # image customers elif args.subcmd == 'add_customers': - cmd, url = requests.post, '/%s/customers' % args.imageid + return requests.post, '/%s/customers' % args.imageid elif args.subcmd == 'update_customers': - cmd, url = requests.put, '/%s/customers' % args.imageid + return requests.put, '/%s/customers' % args.imageid elif args.subcmd == 'delete_customer': - cmd, url = requests.delete, '/%s/customers/%s' % (args.imageid, - args.customerid) + return requests.delete, '/%s/customers/%s' % (args.imageid, + args.customer) # list images elif args.subcmd == 'get_image': - cmd, url = requests.get, '/%s' % args.imageid + return requests.get, '/%s' % args.imageid elif args.subcmd == 'list_images': param = '' if args.visibility: @@ -281,26 +283,22 @@ def cmd_details(args): if args.customer: param += '%scustomer=%s' % (preparm(param), args.customer) - cmd, url = requests.get, '/%s' % param - - return cmd, url, data + return requests.get, '/%s' % param def cmd_data(args): # This is a special case where api has a payload needed but the CLI is # seperated into 2 different commands. In this case we need to set the # payload. - if args.subcmd == 'enable': + if args.subcmd == 'enabled': return "{\n \"enabled\": true\n}" - elif args.subcmd == 'disable': - return "{\n \"enabled\": false\n}" else: return args.datafile.read() if 'datafile' in args else '{}' def get_environment_variable(argument): # The rules are: all caps, underscores instead of dashes and prefixed - environment_variable = 'RANGER_{}'.format( + environment_variable = 'AIC_ORM_{}'.format( argument.replace('-', '_').upper()) return os.environ.get(environment_variable) @@ -308,10 +306,11 @@ def get_environment_variable(argument): def run(args): host = args.orm_base_url if args.orm_base_url else config.orm_base_url - port = args.port if args.port else base_config.ims['port'] + port = args.port if args.port else 8084 + data = args.datafile.read() if 'datafile' in args else '{}' timeout = args.timeout if args.timeout else 10 - rest_cmd, cmd_url, data = cmd_details(args) + rest_cmd, cmd_url = cmd_details(args) url = '%s:%d/v1/orm/images' % (host, port,) + cmd_url if args.faceless: auth_token = auth_region = requester = client = '' @@ -343,7 +342,7 @@ def run(args): url)) try: resp = rest_cmd(url, timeout=timeout, data=data, headers=headers, - verify=False) + verify=config.verify) except Exception as e: print e exit(1) diff --git a/orm/orm_client/ormcli/ormcli.py b/orm/orm_client/ormcli/ormcli.py index 29bffad0..3bd7bb3f 100644 --- a/orm/orm_client/ormcli/ormcli.py +++ b/orm/orm_client/ormcli/ormcli.py @@ -1,9 +1,9 @@ #!/usr/bin/python import argparse -import cmscli -import fmscli -import imscli -import rmscli +from orm.orm_client.ormcli import cmscli +from orm.orm_client.ormcli import fmscli +from orm.orm_client.ormcli import imscli +from orm.orm_client.ormcli import rmscli import sys diff --git a/orm/orm_client/ormcli/rmscli.py b/orm/orm_client/ormcli/rmscli.py index f1520e5e..b6ef9aae 100644 --- a/orm/orm_client/ormcli/rmscli.py +++ b/orm/orm_client/ormcli/rmscli.py @@ -2,7 +2,6 @@ import argparse import cli_common import config -import orm.base_config as base_config import os import requests @@ -35,50 +34,61 @@ def add_to_parser(service_sub): parser.add_argument('--orm-base-url', type=str, help='ORM base URL', default=get_environment_variable('orm-base-url')) parser.add_argument('--tracking_id', type=str, help='tracking id') - parser.add_argument('--port', type=int, help='port number of IMS server') + parser.add_argument('--port', type=int, help='port number of RMS server') parser.add_argument('--timeout', type=int, help='request timeout in seconds (default: 10)') parser.add_argument('-v', '--verbose', help='show details', action="store_true") parser.add_argument('-f', '--faceless', - help='run without authentication', + help=argparse.SUPPRESS, default=False, action="store_true") subparsers = parser.add_subparsers(dest='subcmd', metavar=' [-h] ') + clnt_hdr = '[<"X-RANGER-Client" header>] ' + # get group h1 = '' parser_get_group = subparsers.add_parser('get_group', help=h1) - parser_get_group.add_argument('group_id', help=h1) + parser_get_group.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) + parser_get_group.add_argument('group_id', type=str, help=h1) # get all groups parser_list_groups = subparsers.add_parser('list_groups', help="") + parser_list_groups.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) # create group - h1 = '' - parser_create_group = subparsers.add_parser('create_group', help=h1) + h1 = '' + parser_create_group = subparsers.add_parser('create_group', + help='%s %s' % (clnt_hdr, h1)) + parser_create_group.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_create_group.add_argument('datafile', type=argparse.FileType('r'), - help=h1) + help='') # update group - h1, h2 = '', '' + h1, h2 = '', '' parser_update_group = subparsers.add_parser('update_group', - help="%s %s" % (h2, h1)) + help="%s %s %s" % (clnt_hdr, + h1, h2)) + parser_update_group.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_update_group.add_argument('group_id', help=h2) parser_update_group.add_argument('datafile', type=argparse.FileType('r'), - help=h1) + help='') # delete group h1 = '' parser_delete_group = subparsers.add_parser('delete_group', - help='%s' % (h1)) + help='%s %s' % (clnt_hdr, h1)) + parser_delete_group.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_delete_group.add_argument('group_id', type=str, help=h1) # get region h1, h2 = '', '[--use_version ]' parser_get_region = subparsers.add_parser('get_region', help='%s %s' % (h1, h2)) + parser_get_region.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_get_region.add_argument('--use_version', type=int, help='') parser_get_region.add_argument('region_name_or_id', type=str, help=h1) @@ -86,32 +96,39 @@ def add_to_parser(service_sub): # update region h1, h2 = '', '' parser_update_region = subparsers.add_parser('update_region', - help='%s %s' % (h1, h2)) + help='%s %s %s' % (clnt_hdr, + h1, h2)) + parser_update_region.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_update_region.add_argument('region_id', type=str, help=h1) parser_update_region.add_argument('datafile', type=argparse.FileType('r'), - help=h2) + help='') # create region h1 = '' parser_create_region = subparsers.add_parser('create_region', - help='%s' % (h1)) + help='%s %s' % (clnt_hdr, h1)) + parser_create_region.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_create_region.add_argument('datafile', type=argparse.FileType('r'), - help=h2) + help='') # delete region h1 = '' parser_delete_region = subparsers.add_parser('delete_region', - help='%s' % (h1)) + help='%s %s' % (clnt_hdr, h1)) + parser_delete_region.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_delete_region.add_argument('region_id', type=str, help=h1) # list regions parser_list_region = subparsers.add_parser('list_regions', help='\ -[--use_version ] [--type ] [--status ]\ +[--use_version ] [--type ][--status ]\ [--metadata ] [--aicversion ][--clli ]\ -[--regionname ] [--osversion ] [--valet ]\ +[--regionname ] [--osversion ]\ +[--location_type ]\ [--state ] [--country ] [--city ] [--street ]\ [--zip ] [--vlcp_name ]') + parser_list_region.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_list_region.add_argument('--use_version', type=int, help='') parser_list_region.add_argument('--type', type=str, help='') @@ -125,7 +142,8 @@ def add_to_parser(service_sub): help='') parser_list_region.add_argument('--osversion', type=str, help='') - parser_list_region.add_argument('--valet', type=str, help='') + parser_list_region.add_argument('--location_type', type=str, + help='') parser_list_region.add_argument('--state', type=str, help='') parser_list_region.add_argument('--country', type=str, help='') parser_list_region.add_argument('--city', type=str, help='') @@ -137,7 +155,9 @@ def add_to_parser(service_sub): # add metadata to region h1, h2 = '', '' parser_add_metadata = subparsers.add_parser('add_metadata', - help='%s %s' % (h1, h2)) + help='%s %s %s' % (clnt_hdr, + h1, h2)) + parser_add_metadata.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_add_metadata.add_argument('region_id', type=str, help=h1) parser_add_metadata.add_argument('datafile', type=argparse.FileType('r'), help=h2) @@ -145,7 +165,10 @@ def add_to_parser(service_sub): # update region's metadata h1, h2 = '', '' parser_update_metadata = subparsers.add_parser('update_metadata', - help='%s %s' % (h1, h2)) + help='%s %s %s' % (clnt_hdr, + h1, h2)) + parser_update_metadata.add_argument('client', + **cli_common.ORM_CLIENT_KWARGS) parser_update_metadata.add_argument('region_id', type=str, help=h1) parser_update_metadata.add_argument('datafile', type=argparse.FileType('r'), @@ -153,7 +176,10 @@ def add_to_parser(service_sub): # delete metadata key from region h1, h2 = '', '' parser_delete_metadata = subparsers.add_parser('delete_metadata', - help='%s %s' % (h1, h2)) + help='%s %s %s' % (clnt_hdr, + h1, h2)) + parser_delete_metadata.add_argument('client', + **cli_common.ORM_CLIENT_KWARGS) parser_delete_metadata.add_argument('region_id', type=str, help=h1) parser_delete_metadata.add_argument('metadata_key', type=str, help=h2) @@ -161,12 +187,15 @@ def add_to_parser(service_sub): h1 = '' parser_get_metadata = subparsers.add_parser('get_metadata', help='%s' % (h1)) + parser_get_metadata.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_get_metadata.add_argument('region_id', type=str, help=h1) # update region's status h1, h2 = '', '' parser_update_status = subparsers.add_parser('update_status', - help='%s %s' % (h1, h2)) + help='%s %s %s' % (clnt_hdr, + h1, h2)) + parser_update_status.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_update_status.add_argument('region_id', type=str, help=h1) parser_update_status.add_argument('status', type=str, help=h2) @@ -198,12 +227,12 @@ def get_token(timeout, args, host): globals()[argument] = configuration_value else: message = ('ERROR: {} for token generation was not supplied. ' - 'Please use its command-line ' - 'argument or environment variable.'.format(argument)) + 'Please use its command-line argument or ' + 'environment variable.'.format(argument)) print message raise cli_common.MissingArgumentError(message) - keystone_ep = cli_common.get_keystone_ep('{}:{}'.format(host, base_config.rms['port']), + keystone_ep = cli_common.get_keystone_ep('{}:8080'.format(host), auth_region) if keystone_ep is None: raise ConnectionError( @@ -259,8 +288,9 @@ def cmd_details(args): param += '%sregionname=%s' % (preparm(param), args.regionname) if args.osversion: param += '%sosversion=%s' % (preparm(param), args.osversion) - if args.valet: - param += '%svalet=%s' % (preparm(param), args.valet) + if args.location_type: + param += '%slocation_type=%s' % (preparm(param), + args.location_type) if args.state: param += '%sstate=%s' % (preparm(param), args.state) if args.country: @@ -306,7 +336,7 @@ def get_path(args): def get_environment_variable(argument): # The rules are: all caps, underscores instead of dashes and prefixed - environment_variable = 'RANGER_{}'.format( + environment_variable = 'AIC_ORM_{}'.format( argument.replace('-', '_').upper()) return os.environ.get(environment_variable) @@ -315,12 +345,16 @@ def get_environment_variable(argument): def run(args): url_path = get_path(args) host = args.orm_base_url if args.orm_base_url else config.orm_base_url - port = args.port if args.port else base_config.rms['port'] + port = args.port if args.port else 8080 data = args.datafile.read() if 'datafile' in args else '{}' timeout = args.timeout if args.timeout else 10 rest_cmd, cmd_url = cmd_details(args) url = '%s:%d/%s' % (host, port, url_path) + cmd_url - if args.faceless: + if args.faceless or \ + args.subcmd == 'get_region' or \ + args.subcmd == 'list_regions' or \ + args.subcmd == 'list_groups' or \ + args.subcmd == 'get_group': auth_token = auth_region = requester = client = '' else: try: @@ -361,7 +395,7 @@ def run(args): url)) try: resp = rest_cmd(url, data=data, timeout=timeout, headers=headers, - verify=False) + verify=config.verify) except Exception as e: print e exit(1) diff --git a/orm/orm_client/test-requirements.txt b/orm/orm_client/test-requirements.txt deleted file mode 100644 index 4a784a4a..00000000 --- a/orm/orm_client/test-requirements.txt +++ /dev/null @@ -1,9 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -# Hacking already pins down pep8, pyflakes and flake8 -mock -coverage -testfixtures -pytest-pep8 diff --git a/orm/orm_client/tox.ini b/orm/orm_client/tox.ini deleted file mode 100644 index b06444cb..00000000 --- a/orm/orm_client/tox.ini +++ /dev/null @@ -1,19 +0,0 @@ -[tox] -envlist=py27,cover - -[testenv] -deps= -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt -commands= - py.test --pep8 -m pep8 - -[testenv:cover] -commands= - coverage run setup.py test - coverage report --omit=.tox/*,ormcli/tests/*,setup.py - coverage html --omit=.tox/*,ormcli/tests/*,setup.py -#commands={envpython} setup.py test -v {posargs} - -[testenv:pep8] -commands = - py.test --pep8 -m pep8 diff --git a/orm/services/audit_trail_manager/audit_server/app.py b/orm/services/audit_trail_manager/audit_server/app.py index 82f9e692..83295b08 100644 --- a/orm/services/audit_trail_manager/audit_server/app.py +++ b/orm/services/audit_trail_manager/audit_server/app.py @@ -1,11 +1,9 @@ """app module.""" import logging -import os from orm.services.audit_trail_manager.audit_server import model from orm.services.audit_trail_manager.audit_server.storage import factory -from pecan.commands import CommandRunner from pecan import make_app logger = logging.getLogger(__name__) @@ -26,11 +24,3 @@ def setup_app(config): logger.info('Starting Audit...') return app - - -def main(): - dir_name = os.path.dirname(__file__) - drive, path_and_file = os.path.splitdrive(dir_name) - path, filename = os.path.split(path_and_file) - runner = CommandRunner() - runner.run(['serve', path + '/config.py']) diff --git a/orm/services/customer_manager/cms_rest/controllers/v1/orm/customer/regions.py b/orm/services/customer_manager/cms_rest/controllers/v1/orm/customer/regions.py index 58ef78ef..c6e1d3eb 100755 --- a/orm/services/customer_manager/cms_rest/controllers/v1/orm/customer/regions.py +++ b/orm/services/customer_manager/cms_rest/controllers/v1/orm/customer/regions.py @@ -88,9 +88,16 @@ class RegionController(rest.RestController): return result - @wsexpose(None, str, str, status_code=204) - def delete(self, customer_id, region_id): - LOG.info("RegionController - Delete Region (delete) customer id {0} region_id: {1}".format(customer_id, region_id)) + @wsexpose(None, str, str, str, status_code=204) + def delete(self, customer_id, region_id, force_delete='False'): + + if force_delete == 'True': + force_delete = True + else: + force_delete = False + requester = request.headers.get('X-RANGER-Requester') + is_rds_client_request = requester == 'rds_resource_service_proxy' + LOG.info("Delete Region (delete) customer id {0} region_id: {1} by RDS Proxy: {2} ".format(customer_id, region_id, is_rds_client_request)) authentication.authorize(request, 'customers:delete_region') try: customer_logic = CustomerLogic() diff --git a/orm/services/customer_manager/cms_rest/controllers/v1/orm/customer/root.py b/orm/services/customer_manager/cms_rest/controllers/v1/orm/customer/root.py index 96e51daf..3027eb84 100755 --- a/orm/services/customer_manager/cms_rest/controllers/v1/orm/customer/root.py +++ b/orm/services/customer_manager/cms_rest/controllers/v1/orm/customer/root.py @@ -52,18 +52,15 @@ class CustomerController(rest.RestController): authentication.authorize(request, 'customers:create') try: uuid = None - if not customer.custId: - uuid = utils.make_uuid() - else: - if not CustomerController.validate_cust_id(customer.custId): - utils.audit_trail('create customer', request.transaction_id, request.headers, customer.custId) - raise ErrorStatus('400', None) - try: - uuid = utils.create_existing_uuid(customer.custId) - except TypeError: - raise ErrorStatus(409.1, 'Customer ID {0} already exists'.format(customer.custId)) - + if not customer.uuid: + customer.uuid = None customer_logic = CustomerLogic() + + try: + uuid = utils.create_or_validate_uuid(customer.uuid, 'custId') + except TypeError: + raise ErrorStatus(409.1, 'Unable to create Customer ID {0}'.format(customer.uuid)) + try: result = customer_logic.create_customer(customer, uuid, request.transaction_id) except oslo_db.exception.DBDuplicateEntry as exception: @@ -121,19 +118,25 @@ class CustomerController(rest.RestController): return result - @wsexpose(CustomerSummaryResponse, str, str, str, str, [str], + @wsexpose(CustomerSummaryResponse, str, str, str, str, [str], int, int, rest_content_types='json') def get_all(self, region=None, user=None, starts_with=None, - contains=None, metadata=None): + contains=None, metadata=None, start=0, limit=0): LOG.info("CustomerController - GetCustomerlist") authentication.authorize(request, 'customers:get_all') + + # This shouldn't be necessary, but apparently is on mtn29 + start = 0 if start is None else start + limit = 0 if limit is None else limit + try: customer_logic = CustomerLogic() result = customer_logic.get_customer_list_by_criteria(region, user, starts_with, contains, - metadata) - + metadata, + start, + limit) return result except ErrorStatus as exception: LOG.log_exception("CustomerController - Failed to GetCustomerlist", exception) @@ -174,9 +177,3 @@ class CustomerController(rest.RestController): raise err_utils.get_error(request.transaction_id, status_code=500, error_details=exception.message) - - @staticmethod - def validate_cust_id(cust_id): - # regex = re.compile('[a-zA-Z]') - # return regex.match(cust_id[0]) - return True diff --git a/orm/services/customer_manager/cms_rest/controllers/v1/orm/customer/users.py b/orm/services/customer_manager/cms_rest/controllers/v1/orm/customer/users.py index a29eeea8..fe053bf8 100755 --- a/orm/services/customer_manager/cms_rest/controllers/v1/orm/customer/users.py +++ b/orm/services/customer_manager/cms_rest/controllers/v1/orm/customer/users.py @@ -161,11 +161,19 @@ class UserController(rest.RestController): status_code=404) except Exception as exception: - result = UserResultWrapper(transaction_id="Users Not Added", users=[]) - LOG.log_exception("UserController - Failed to Add Users (post)", exception) - raise err_utils.get_error(request.transaction_id, - status_code=500, - error_details=str(exception)) + if exception.inner_exception.orig[0] == 1452: + result = UserResultWrapper(transaction_id="Users Not Added", users=[]) + LOG.log_exception("UserController - Failed to Add Users (post)", exception) + LOG.log_exception("Region specified must be added to customer first.", exception) + raise err_utils.get_error(request.transaction_id, + status_code=500, + message="Region specified must be added to customer first.") + else: + result = UserResultWrapper(transaction_id="Users Not Added", users=[]) + LOG.log_exception("UserController - Failed to Add Users (post)", exception) + raise err_utils.get_error(request.transaction_id, + status_code=500, + error_details=str(exception)) return result @@ -225,6 +233,7 @@ class UserController(rest.RestController): except ErrorStatus as exception: LOG.log_exception("DefaultUserController - Failed to delete users", exception) raise err_utils.get_error(request.transaction_id, + message=exception.message, status_code=exception.status_code) except LookupError as exception: diff --git a/orm/services/customer_manager/cms_rest/data/data_manager.py b/orm/services/customer_manager/cms_rest/data/data_manager.py index 8751f4f6..8d86560d 100755 --- a/orm/services/customer_manager/cms_rest/data/data_manager.py +++ b/orm/services/customer_manager/cms_rest/data/data_manager.py @@ -86,20 +86,20 @@ class DataManager(object): cms_users = self.session.query(CmsUser) return cms_users.all() - def get_cusomer_by_id(self, customer_id): + def get_customer_by_id(self, customer_id): customer = self.session.query(Customer).filter( Customer.id == customer_id) return customer.first() - def get_cusomer_by_uuid(self, uuid): + def get_customer_by_uuid(self, uuid): customer = self.session.query(Customer).filter(Customer.uuid == uuid) return customer.first() - def get_cusomer_by_name(self, name): + def get_customer_by_name(self, name): customer = self.session.query(Customer).filter(Customer.name == name) return customer.first() - def get_cusomer_by_uuid_or_name(self, cust): + def get_customer_by_uuid_or_name(self, cust): customer = self.session.query(Customer).filter( or_(Customer.uuid == cust, Customer.name == cust)) diff --git a/orm/services/customer_manager/cms_rest/data/sql_alchemy/customer_record.py b/orm/services/customer_manager/cms_rest/data/sql_alchemy/customer_record.py index 8420e608..f29686eb 100755 --- a/orm/services/customer_manager/cms_rest/data/sql_alchemy/customer_record.py +++ b/orm/services/customer_manager/cms_rest/data/sql_alchemy/customer_record.py @@ -42,7 +42,7 @@ class CustomerRecord: raise def delete_by_primary_key(self, customer_id): - result = self.session.connection().execute("delete from customer where id = %d" % (customer_id)) + result = self.session.connection().execute("delete from customer where id = {}".format(customer_id)) return result def read_by_primary_key(self): @@ -69,13 +69,23 @@ class CustomerRecord: raise def get_customer_id_from_uuid(self, uuid): - result = self.session.connection().scalar("SELECT id from customer WHERE uuid = \"%s\"" % uuid) + result = self.session.connection().scalar("SELECT id from customer WHERE uuid = \"{}\"".format(uuid)) if result: return int(result) else: return None + def get_customers_status_by_uuids(self, uuid_str): + results = self.session.connection().execute("SELECT resource_id, status from rds_resource_status_view" + " WHERE resource_id in ({})".format(uuid_str)) + resource_status_dict = {} + if results: + resource_status_dict = dict((resource_id, status) for resource_id, status in results) + + results.close() + return resource_status_dict + def delete_customer_by_uuid(self, uuid): try: result = self.session.query(Customer).filter( diff --git a/orm/services/customer_manager/cms_rest/data/sql_alchemy/customer_region_record.py b/orm/services/customer_manager/cms_rest/data/sql_alchemy/customer_region_record.py index 7403c1bb..8ef56859 100755 --- a/orm/services/customer_manager/cms_rest/data/sql_alchemy/customer_region_record.py +++ b/orm/services/customer_manager/cms_rest/data/sql_alchemy/customer_region_record.py @@ -68,7 +68,7 @@ class CustomerRegionRecord: 'region with the region name {0} not found'.format( region_name)) result = self.session.connection().execute( - "delete from customer_region where customer_id = %d and region_id = %d" % (customer_id, region_id)) + "delete from customer_region where customer_id = {} and region_id = {}".format(customer_id, region_id)) self.session.flush() if result.rowcount == 0: diff --git a/orm/services/customer_manager/cms_rest/data/sql_alchemy/region_record.py b/orm/services/customer_manager/cms_rest/data/sql_alchemy/region_record.py index 9801c209..c9673ad5 100755 --- a/orm/services/customer_manager/cms_rest/data/sql_alchemy/region_record.py +++ b/orm/services/customer_manager/cms_rest/data/sql_alchemy/region_record.py @@ -27,7 +27,7 @@ class RegionRecord: @region.setter def region(self, region): - self.__regionn = region + self.__region = region def insert(self, region): try: @@ -37,7 +37,7 @@ class RegionRecord: raise def get_region_id_from_name(self, region_name): - result = self.session.connection().scalar("SELECT id from region WHERE name = \"%s\"" % (region_name)) + result = self.session.connection().scalar("SELECT id from region WHERE name = \"{}\"".format(region_name)) if result is not None: return int(result) return result diff --git a/orm/services/customer_manager/cms_rest/data/sql_alchemy/user_role_record.py b/orm/services/customer_manager/cms_rest/data/sql_alchemy/user_role_record.py index c3940dc4..45105fd9 100755 --- a/orm/services/customer_manager/cms_rest/data/sql_alchemy/user_role_record.py +++ b/orm/services/customer_manager/cms_rest/data/sql_alchemy/user_role_record.py @@ -61,8 +61,19 @@ class UserRoleRecord: if user_id is None: raise NotFound("user %s is not found" % user_query) - result = self.session.connection().execute("delete from user_role where customer_id = %d and region_id = %d and user_id = %d" % (customer_id, region_id, user_id)) - print "num records deleted: " + str(result.rowcount) + if region_id == -1: + delete_query = "DELETE ur FROM user_role ur,user_role u " \ + "where ur.user_id=u.user_id and ur.role_id=u.role_id " \ + "and ur.customer_id = u.customer_id and u.region_id =-1 " \ + "and ur.customer_id = %d and ur.user_id=%d" % (customer_id, user_id) + else: + delete_query = "DELETE ur FROM user_role as ur LEFT JOIN user_role AS u " \ + "ON ur.customer_id = u.customer_id and u.user_id=ur.user_id " \ + "and u.region_id=-1 where ur.customer_id = %d and ur.region_id= %d " \ + "and ur.user_id =%d and ur.role_id !=IFNULL(u.role_id,'')" \ + % (customer_id, region_id, user_id) + + result = self.session.connection().execute(delete_query) return result def delete_all_users_from_region(self, customer_id, region_id): @@ -75,9 +86,19 @@ class UserRoleRecord: if isinstance(region_id, basestring): region_record = RegionRecord(self.session) region_id = region_record.get_region_id_from_name(region_id) + if region_id == -1: + delete_query = "DELETE ur FROM user_role ur,user_role u " \ + "where ur.user_id=u.user_id and ur.role_id=u.role_id " \ + "and ur.customer_id = u.customer_id and u.region_id =-1 " \ + "and ur.customer_id = %d" % (customer_id) + else: + delete_query = "DELETE ur FROM user_role as ur LEFT JOIN user_role AS u " \ + "ON ur.customer_id = u.customer_id and u.user_id=ur.user_id " \ + "and u.region_id=-1 where ur.customer_id = %d and ur.region_id= %d " \ + "and ur.role_id !=IFNULL(u.role_id,'')" \ + % (customer_id, region_id) - result = self.session.connection().execute( - "delete from user_role where customer_id = {} and region_id = {}".format(customer_id, region_id)) + result = self.session.connection().execute(delete_query) print "num records deleted: " + str(result.rowcount) return result diff --git a/orm/services/customer_manager/cms_rest/etc/policy.json b/orm/services/customer_manager/cms_rest/etc/policy.json index 62e5b6e0..590cac4c 100755 --- a/orm/services/customer_manager/cms_rest/etc/policy.json +++ b/orm/services/customer_manager/cms_rest/etc/policy.json @@ -1,31 +1,32 @@ { "default": "!", - "admin": "role:admin", - "admin_support": "role:admin_support", - "admin_viewer": "role:admin_viewer", - "admin_or_admin_support": "rule:admin or rule:admin_support", - "admin_or_admin_support_or_admin_viewer": "rule:admin or rule:admin_support or rule:admin_viewer", + "admin": "role:admin and tenant:admin or role:admin and tenant:services", + "admin_support": "role:admin_support and tenant:admin or role:admin_support and tenant:services", + "admin_viewer": "role:admin_viewer and tenant:admin or role:admin_viewer and tenant:services", - "customers:get_one": "rule:admin_or_admin_support_or_admin_viewer", - "customers:get_all": "rule:admin_or_admin_support_or_admin_viewer", - "customers:create": "rule:admin_or_admin_support", + "admin_or_support": "rule:admin or rule:admin_support", + "admin_or_support_or_viewer": "rule:admin or rule:admin_support or rule:admin_viewer", + + "customers:get_one": "rule:admin_or_support_or_viewer", + "customers:get_all": "rule:admin_or_support_or_viewer", + "customers:create": "rule:admin_or_support", "customers:update": "rule:admin", "customers:delete": "rule:admin", - "customers:add_region": "rule:admin_or_admin_support", + "customers:add_region": "rule:admin_or_support", "customers:update_region": "rule:admin", "customers:delete_region": "rule:admin", - "customers:add_region_user": "rule:admin", + "customers:add_region_user": "rule:admin_or_support", "customers:update_region_user": "rule:admin", "customers:delete_region_user": "rule:admin", - "customers:add_default_user": "rule:admin", + "customers:add_default_user": "rule:admin_or_support", "customers:update_default_user": "rule:admin", "customers:delete_default_user": "rule:admin", - "customers:add_metadata": "rule:admin", + "customers:add_metadata": "rule:admin_or_support", "customers:update_metadata": "rule:admin", "customers:enable": "rule:admin" diff --git a/orm/services/customer_manager/cms_rest/logic/customer_logic.py b/orm/services/customer_manager/cms_rest/logic/customer_logic.py index 1521f6e2..01997375 100755 --- a/orm/services/customer_manager/cms_rest/logic/customer_logic.py +++ b/orm/services/customer_manager/cms_rest/logic/customer_logic.py @@ -6,7 +6,7 @@ from orm.common.orm_common.utils import utils from orm.common.orm_common.utils.cross_api_utils import (get_regions_of_group, set_utils_conf) from orm.services.customer_manager.cms_rest.data.data_manager import DataManager -from orm.services.customer_manager.cms_rest.data.sql_alchemy.models import CustomerMetadata, UserRole +from orm.services.customer_manager.cms_rest.data.sql_alchemy.models import CustomerMetadata from orm.services.customer_manager.cms_rest.logger import get_logger from orm.services.customer_manager.cms_rest.logic.error_base import (DuplicateEntryError, ErrorStatus, NotFound) @@ -20,49 +20,35 @@ LOG = get_logger(__name__) class CustomerLogic(object): def build_full_customer(self, customer, uuid, datamanager): + if any(char in ":" for char in customer.name): + raise ErrorStatus(400, "Customer Name does not allow colon(:).") + + if customer.name.strip() == '': + raise ErrorStatus(400, "Customer Name can not be blank.") + sql_customer = datamanager.add_customer(customer, uuid) for key, value in customer.metadata.iteritems(): metadata = CustomerMetadata(field_key=key, field_value=value) sql_customer.customer_metadata.append(metadata) - datamanager.add_customer_region(sql_customer.id, -1) + sql_customer_id = sql_customer.id + datamanager.add_customer_region(sql_customer_id, -1) - default_region_users = [] - for user in customer.users: - sql_user = datamanager.add_user(user) - default_region_users.append(sql_user) - sql_user.sql_roles = [] - for role in user.role: - sql_role = datamanager.add_role(role) - sql_user.sql_roles.append(sql_role) + default_users_requested = customer.users + default_region_users =\ + self.add_default_user_db(datamanager, default_users_requested, [], sql_customer_id) default_quotas = [] for quota in customer.defaultQuotas: - sql_quota = datamanager.add_quota(sql_customer.id, -1, quota) + sql_quota = datamanager.add_quota(sql_customer_id, -1, quota) default_quotas.append(sql_quota) - for sql_user in default_region_users: - for sql_role in sql_user.sql_roles: - datamanager.add_user_role(sql_user.id, sql_role.id, - sql_customer.id, -1) - - self.add_regions_to_db(customer.regions, sql_customer.id, datamanager, customer.users) + self.add_regions_to_db(customer.regions, sql_customer_id, datamanager, default_region_users) return sql_customer def add_regions_to_db(self, regions, sql_customer_id, datamanager, default_users=[]): for region in regions: - users_roles = self.add_user_and_roles_to_db(region.users, default_users, - datamanager) - - # NOTE: if region has no users there is no need to update the - # default users in that region - # if len(region.users) == 0: - # users_roles.extend(self.add_user_and_roles_to_db( - # customer.users, datamanager)) - # else: - # users_roles.extend(self.add_user_and_roles_to_db( - # region.users, datamanager)) sql_region = datamanager.add_region(region) try: @@ -73,9 +59,8 @@ class CustomerLogic(object): 'Error, duplicate entry, region ' + region.name + ' already associated with customer') raise ex - for user_role in users_roles: - datamanager.add_user_role(user_role[0].id, user_role[1].id, - sql_customer_id, sql_region.id) + self.add_user_and_roles_to_db(region.users, default_users, + sql_customer_id, sql_region.id, datamanager) for quota in region.quotas: datamanager.add_quota(sql_customer_id, sql_region.id, quota) @@ -91,20 +76,76 @@ class CustomerLogic(object): # datamanager.add_quota(sql_customer_id, # sql_region.id, quota) - def add_user_and_roles_to_db(self, users, default_users, datamanager): - users_roles = [] - for user in users: - sql_user = datamanager.add_user(user) - for role in user.role: - sql_role = datamanager.add_role(role) - users_roles.append((sql_user, sql_role)) - for default_user in default_users: - sql_user = datamanager.add_user(default_user) - for role in default_user.role: - sql_role = datamanager.add_role(role) - users_roles.append((sql_user, sql_role)) + def add_default_user_db(self, datamanager, default_users_requested, existing_default_users_roles, sql_customer_id): + default_region_users = [] + default_users_dic = {} - return users_roles + for sql_user in existing_default_users_roles: + default_users_dic[sql_user.name] = sql_user + + for user in default_users_requested: + is_default_user_exist = user.id in default_users_dic.keys() + if not is_default_user_exist: + sql_user = datamanager.add_user(user) + default_region_users.append(sql_user) + sql_user.sql_roles = [] + for role in user.role: + sql_role = datamanager.add_role(role) + sql_user.sql_roles.append(sql_role) + else: + sql_user = default_users_dic.get(user.id) + new_sql_roles = [] + for role in user.role: + role_match = False + for sql_role in sql_user.sql_roles: + if sql_role.name == role: + role_match = True + break + if not role_match: + sql_role = datamanager.add_role(role) + new_sql_roles.append(sql_role) + if new_sql_roles: + sql_user.sql_roles = new_sql_roles + default_region_users.append(sql_user) + + for sql_user in default_region_users: + for sql_role in sql_user.sql_roles: + datamanager.add_user_role(sql_user.id, sql_role.id, + sql_customer_id, -1) + return default_region_users + + def add_user_and_roles_to_db(self, users, sql_default_users, sql_customer_id, sql_region_id, datamanager): + users_roles = [] + default_users_dic = {} + + for sql_user in sql_default_users: + default_users_dic[sql_user.name] = sql_user + for role in sql_user.sql_roles: + users_roles.append((sql_user, role)) + + # Default user will be given priority over region user + for user in users: + is_default_user_in_region = user.id in default_users_dic.keys() + if not is_default_user_in_region: + sql_user = datamanager.add_user(user) + for role in user.role: + sql_role = datamanager.add_role(role) + users_roles.append((sql_user, sql_role)) + else: + sql_user = default_users_dic.get(user.id) + for role in user.role: + role_match = False + for sql_role in sql_user.sql_roles: + if sql_role.name == role: + role_match = True + break + if not role_match: + sql_role = datamanager.add_role(role) + users_roles.append((sql_user, sql_role)) + + for user_role in users_roles: + datamanager.add_user_role(user_role[0].id, user_role[1].id, + sql_customer_id, sql_region_id) def create_customer(self, customer, uuid, transaction_id): datamanager = DataManager() @@ -113,7 +154,6 @@ class CustomerLogic(object): sql_customer = self.build_full_customer(customer, uuid, datamanager) customer_result_wrapper = build_response(uuid, transaction_id, 'create') - sql_customer = self.add_default_users_to_empty_regions(sql_customer) if sql_customer.customer_customer_regions and len(sql_customer.customer_customer_regions) > 1: customer_dict = sql_customer.get_proxy_dict() for region in customer_dict["regions"]: @@ -150,7 +190,6 @@ class CustomerLogic(object): sql_customer = self.build_full_customer(customer, customer_uuid, datamanager) - sql_customer = self.add_default_users_to_empty_regions(sql_customer) new_customer_dict = sql_customer.get_proxy_dict() new_customer_dict["regions"] = self.resolve_regions_actions(old_customer_dict["regions"], new_customer_dict["regions"]) @@ -202,11 +241,19 @@ class CustomerLogic(object): if region_id is None: raise ErrorStatus(404, "region {} not found".format(region_name)) - self.add_users_to_db(datamanager, customer_id, region_id, users, adding=True) - customer_record = datamanager.get_record('customer') customer = customer_record.read_customer(customer_id) + defaultRegion = customer.get_default_customer_region() + default_users_roles = defaultRegion.customer_region_user_roles if defaultRegion else [] + default_users = [] + for default_user in default_users_roles: + if default_user.user not in default_users: + default_users.append(default_user.user) + default_user.user.sql_roles = [] + default_user.user.sql_roles.append(default_user.role) + self.add_user_and_roles_to_db(users, default_users, + customer_id, region_id, datamanager) timestamp = utils.get_time_human() datamanager.flush() # i want to get any exception created by this insert RdsProxy.send_customer(customer, transaction_id, "PUT") @@ -256,29 +303,12 @@ class CustomerLogic(object): LOG.log_exception("Failed to replace_default_users", exception) raise - def add_users_to_db(self, datamanager, customer_id, region_id, users, adding=False): - try: - users_roles = [] - for user in users: - sql_user = datamanager.add_user(user) - for role in user.role: - sql_role = datamanager.add_role(role) - users_roles.append((sql_user, sql_role)) - for user_role in users_roles: - # TODO: change add_use_role to receive sqlalchemy model (UserRole) - datamanager.add_user_role(user_role[0].id, user_role[1].id, - customer_id, region_id, adding) - datamanager.flush() - except Exception as exception: - LOG.log_exception("Failed to add users", exception) - raise - def delete_users(self, customer_uuid, region_id, user_id, transaction_id): datamanager = DataManager() try: user_role_record = datamanager.get_record('user_role') - customer = datamanager.get_cusomer_by_uuid(customer_uuid) + customer = datamanager.get_customer_by_uuid(customer_uuid) if customer is None: raise ErrorStatus(404, "customer {} does not exist".format(customer_uuid)) @@ -286,13 +316,24 @@ class CustomerLogic(object): region_id, user_id) if result.rowcount == 0: - raise NotFound("user {} is not found".format(user_id)) + '''when result.rowcount returns 0, this indicates that the region user marked + for deletion also exists - and has the same exact roles - in the default user + level. Since default_user supersedes region user, use 'delete_default_user' + instead of 'delete_user' command. + ''' + message = "Cannot use 'delete_user' as user '%s' exists and has " \ + "the exact same roles in both the default and '%s' "\ + "region levels for customer %s. "\ + "Use 'delete_default_user' instead." \ + % (user_id, region_id, customer_uuid) + raise ErrorStatus(400, message) RdsProxy.send_customer(customer, transaction_id, "PUT") datamanager.commit() - print "User {0} from region {1} in customer {2} deleted".format( - user_id, region_id, customer_uuid) + LOG.info("User {0} from region {1} in customer {2} deleted". + format(user_id, region_id, customer_uuid)) + except NotFound as e: datamanager.rollback() LOG.log_exception("Failed to delete_users, user not found", @@ -318,10 +359,25 @@ class CustomerLogic(object): if customer_id is None: raise ErrorStatus(404, "customer {} does not exist".format(customer_uuid)) - self.add_users_to_db(datamanager, customer_id, -1, users, adding=True) - customer_record = datamanager.get_record('customer') customer = customer_record.read_customer(customer_id) + defaultRegion = customer.get_default_customer_region() + existing_default_users_roles = defaultRegion.customer_region_user_roles if defaultRegion else [] + default_users = [] + for default_user in existing_default_users_roles: + if default_user.user not in default_users: + default_users.append(default_user.user) + default_user.user.sql_roles = [] + default_user.user.sql_roles.append(default_user.role) + + default_region_users = \ + self.add_default_user_db(datamanager, users, default_users, customer_id) + + regions = customer.get_real_customer_regions() + + for region in regions: + self.add_user_and_roles_to_db(users, default_region_users, + customer_id, region.region_id, datamanager) timestamp = utils.get_time_human() datamanager.flush() # i want to get any exception created by this insert @@ -374,7 +430,7 @@ class CustomerLogic(object): def delete_default_users(self, customer_uuid, user_id, transaction_id): datamanager = DataManager() try: - customer = datamanager.get_cusomer_by_uuid(customer_uuid) + customer = datamanager.get_customer_by_uuid(customer_uuid) if customer is None: raise ErrorStatus(404, "customer {} does not exist".format(customer_uuid)) @@ -382,20 +438,23 @@ class CustomerLogic(object): result = user_role_record.delete_user_from_region(customer_uuid, 'DEFAULT', user_id) - if result.rowcount == 0: - raise NotFound("user {} is not found".format(user_id)) + raise NotFound("user {} ".format(user_id)) + datamanager.flush() + + if len(customer.customer_customer_regions) > 1: + RdsProxy.send_customer(customer, transaction_id, "PUT") datamanager.commit() - print "User {0} from region {1} in customer {2} deleted".format( - user_id, 'DEFAULT', customer_uuid) + LOG.info("User {0} from region {1} in customer {2} deleted". + format(user_id, 'DEFAULT', customer_uuid)) except NotFound as e: datamanager.rollback() LOG.log_exception("Failed to delete_users, user not found", e.message) - raise NotFound("Failed to delete users, %s not found" % + raise NotFound("Failed to delete user(s), %s not found" % e.message) except Exception as exp: @@ -412,11 +471,26 @@ class CustomerLogic(object): raise ErrorStatus(404, "customer with id {} does not exist".format( customer_uuid)) - self.add_regions_to_db(regions, customer_id, datamanager) sql_customer = customer_record.read_customer_by_uuid(customer_uuid) - sql_customer = self.add_default_users_to_empty_regions(sql_customer) + defaultRegion = sql_customer.get_default_customer_region() + existing_default_users_roles = defaultRegion.customer_region_user_roles if defaultRegion else [] + default_users = [] + for default_user in existing_default_users_roles: + if default_user.user not in default_users: + default_users.append(default_user.user) + default_user.user.sql_roles = [] + default_user.user.sql_roles.append(default_user.role) + + self.add_regions_to_db(regions, customer_id, datamanager, default_users) + + datamanager.commit() + + datamanager.session.expire(sql_customer) + + sql_customer = datamanager.get_customer_by_id(customer_id) + new_customer_dict = sql_customer.get_proxy_dict() for region in new_customer_dict["regions"]: @@ -427,9 +501,7 @@ class CustomerLogic(object): region["action"] = "modify" timestamp = utils.get_time_human() - datamanager.flush() # i want to get any exception created by this insert RdsProxy.send_customer_dict(new_customer_dict, transaction_id, "POST") - datamanager.commit() base_link = '{0}{1}/'.format(conf.server.host_ip, pecan.request.path) @@ -462,16 +534,23 @@ class CustomerLogic(object): "customer with id {} does not exist".format( customer_id)) old_customer_dict = old_sql_customer.get_proxy_dict() + defaultRegion = old_sql_customer.get_default_customer_region() + existing_default_users_roles = defaultRegion.customer_region_user_roles if defaultRegion else [] + default_users = [] + for default_user in existing_default_users_roles: + if default_user.user not in default_users: + default_users.append(default_user.user) + default_user.user.sql_roles = [] + default_user.user.sql_roles.append(default_user.role) datamanager.session.expire(old_sql_customer) customer_region.delete_all_regions_for_customer(customer_id) - self.add_regions_to_db(regions, customer_id, datamanager) + self.add_regions_to_db(regions, customer_id, datamanager, default_users) timestamp = utils.get_time_human() - new_sql_customer = datamanager.get_cusomer_by_id(customer_id) + new_sql_customer = datamanager.get_customer_by_id(customer_id) - new_sql_customer = self.add_default_users_to_empty_regions(new_sql_customer) new_customer_dict = new_sql_customer.get_proxy_dict() datamanager.flush() # i want to get any exception created by this insert @@ -496,12 +575,15 @@ class CustomerLogic(object): datamanager.rollback() raise exp - def delete_region(self, customer_id, region_id, transaction_id): + def delete_region(self, customer_id, region_id, transaction_id, on_success_by_rds, + force_delete): datamanager = DataManager() try: customer_region = datamanager.get_record('customer_region') - sql_customer = datamanager.get_cusomer_by_uuid(customer_id) + sql_customer = datamanager.get_customer_by_uuid(customer_id) + if on_success_by_rds and sql_customer is None: + return if sql_customer is None: raise ErrorStatus(404, "customer with id {} does not exist".format( @@ -509,36 +591,42 @@ class CustomerLogic(object): customer_dict = sql_customer.get_proxy_dict() customer_region.delete_region_for_customer(customer_id, region_id) - datamanager.flush() # i want to get any exception created by this insert + datamanager.flush() # Get any exception created by this insert - # i want to get any exception created by this insert - datamanager.flush() + if on_success_by_rds: + datamanager.commit() + LOG.debug("Region {0} in customer {1} deleted".format(region_id, + customer_id)) + else: + region = next((r.region for r in sql_customer.customer_customer_regions if r.region.name == region_id), None) + if region: + if region.type == 'group': + set_utils_conf(conf) + regions = get_regions_of_group(region.name) + else: + regions = [region_id] + for region in customer_dict['regions']: + if region['name'] in regions: + region['action'] = 'delete' - region = next((r.region for r in sql_customer.customer_customer_regions if r.region.name == region_id), None) - if region: - if region.type == 'group': - set_utils_conf(conf) - regions = get_regions_of_group(region.name) + RdsProxy.send_customer_dict(customer_dict, transaction_id, "PUT") + if force_delete: + datamanager.commit() else: - regions = [region_id] - for region in customer_dict['regions']: - if region['name'] in regions: - region['action'] = 'delete' + datamanager.rollback() - RdsProxy.send_customer_dict(customer_dict, transaction_id, "PUT") - datamanager.commit() - - LOG.debug("Region {0} in customer {1} deleted".format(region_id, - customer_id)) except Exception as exp: datamanager.rollback() raise + finally: + datamanager.close() + def get_customer(self, customer): datamanager = DataManager() - sql_customer = datamanager.get_cusomer_by_uuid_or_name(customer) + sql_customer = datamanager.get_customer_by_uuid_or_name(customer) if not sql_customer: raise ErrorStatus(404, 'customer: {0} not found'.format(customer)) @@ -564,24 +652,28 @@ class CustomerLogic(object): return ret_customer def get_customer_list_by_criteria(self, region, user, starts_with, contains, - metadata): + metadata, start=0, limit=0): datamanager = DataManager() customer_record = datamanager.get_record('customer') sql_customers = customer_record.get_customers_by_criteria(region=region, user=user, starts_with=starts_with, contains=contains, - metadata=metadata) - + metadata=metadata, + start=start, + limit=limit) response = CustomerSummaryResponse() - for sql_customer in sql_customers: - # get aggregate status for each customer - customer_status = RdsProxy.get_status(sql_customer.uuid) - customer = CustomerSummary.from_db_model(sql_customer) - if customer_status.status_code == 200: - customer.status = customer_status.json()['status'] - response.customers.append(customer) + if sql_customers: + uuids = ','.join(str("\'" + sql_customer.uuid + "\'") + for sql_customer in sql_customers if sql_customer and sql_customer.uuid) + resource_status_dict = customer_record.get_customers_status_by_uuids(uuids) + for sql_customer in sql_customers: + customer = CustomerSummary.from_db_model(sql_customer) + if sql_customer.uuid: + status = resource_status_dict.get(sql_customer.uuid) + customer.status = not status and 'no regions' or status + response.customers.append(customer) return response def enable(self, customer_uuid, enabled, transaction_id): @@ -601,29 +693,14 @@ class CustomerLogic(object): datamanager.flush() # get any exception created by this action datamanager.commit() + customer_result_wrapper = build_response(customer_uuid, transaction_id, 'update') + + return customer_result_wrapper + except Exception as exp: datamanager.rollback() raise exp - def add_default_users_to_empty_regions(self, sql_customer): - if len(sql_customer.customer_customer_regions) > 0: - for region in sql_customer.customer_customer_regions: - if region.region_id == -1: - users = region.customer_region_user_roles[:] - break - - for region in sql_customer.customer_customer_regions: - if region.region_id != -1: - for user in users: - u = UserRole() - u.customer_id = region.customer_id - u.region_id = region.region_id - u.user_id = user.user_id - u.role_id = user.role_id - region.customer_region_user_roles.append(u) - - return sql_customer - def delete_customer_by_uuid(self, customer_id): datamanager = DataManager() @@ -633,9 +710,7 @@ class CustomerLogic(object): sql_customer = customer_record.read_customer_by_uuid(customer_id) if sql_customer is None: - # The customer does not exist, so the delete operation is - # considered successful - return + raise ErrorStatus(404, "Customer '{0}' not found".format(customer_id)) real_regions = sql_customer.get_real_customer_regions() if len(real_regions) > 0: @@ -706,7 +781,7 @@ def build_response(customer_uuid, transaction_id, context): link_elements = request.url.split('/') base_link = '/'.join(link_elements) if context == 'create': - base_link += customer_uuid + base_link = base_link + '/' + customer_uuid timestamp = utils.get_time_human() customer_result_wrapper = CustomerResultWrapper( diff --git a/orm/services/customer_manager/cms_rest/model/Models.py b/orm/services/customer_manager/cms_rest/model/Models.py index 24c03b25..f518b362 100755 --- a/orm/services/customer_manager/cms_rest/model/Models.py +++ b/orm/services/customer_manager/cms_rest/model/Models.py @@ -112,17 +112,19 @@ class Network(Model): subnets = wsme.wsattr(wsme.types.text, mandatory=True) security_groups = wsme.wsattr(wsme.types.text, mandatory=False, name="security-groups") security_group_rules = wsme.wsattr(wsme.types.text, mandatory=False, name="security-group-rules") - health_monitor = wsme.wsattr(wsme.types.text, mandatory=False, name="health-monitor") - member = wsme.wsattr(wsme.types.text, mandatory=False) + health_monitors = wsme.wsattr(wsme.types.text, mandatory=False, name="health-monitors") + members = wsme.wsattr(wsme.types.text, mandatory=False) nat_instance = wsme.wsattr(wsme.types.text, mandatory=False, name="nat-instance") - pool = wsme.wsattr(wsme.types.text, mandatory=False) + pools = wsme.wsattr(wsme.types.text, mandatory=False) route_table = wsme.wsattr(wsme.types.text, mandatory=False, name="route-table") - vip = wsme.wsattr(wsme.types.text, mandatory=False) + vips = wsme.wsattr(wsme.types.text, mandatory=False) + loadbalancer = wsme.wsattr(wsme.types.text, mandatory=False, name='loadbalancer') + listener = wsme.wsattr(wsme.types.text, mandatory=False, name='listener') def __init__(self, floating_ips='', networks='', ports='', routers='', subnets='', security_groups=None, security_group_rules=None, - health_monitor='', member='', nat_instance='', - pool='', route_table='', vip=''): + health_monitors='', members='', nat_instance='', + pools='', route_table='', vips='', loadbalancer='', listener=''): """Create a new Network instance. :param floating_ips: num of floating_ips @@ -132,12 +134,14 @@ class Network(Model): :param subnets: num of subnets :param security_groups: security groups :param security_group_rules: security group rules - :param health_monitor: - :param member: + :param health_monitors: + :param members: :param nat_instance: - :param pool: + :param pools: :param route_table: - :param vip: + :param vips: + :param loadbalancer: + :param listener: """ self.floating_ips = floating_ips self.networks = networks @@ -153,17 +157,18 @@ class Network(Model): else: self.security_group_rules = security_group_rules - self.health_monitor = health_monitor - self.member = member + self.health_monitors = health_monitors + self.members = members self.nat_instance = nat_instance - self.pool = pool + self.pools = pools self.route_table = route_table - self.vip = vip + self.vips = vips + self.loadbalancer = loadbalancer + self.listener = listener class Quota(Model): """network model the customer - """ compute = wsme.wsattr([Compute], mandatory=False) storage = wsme.wsattr([Storage], mandatory=False) @@ -183,7 +188,6 @@ class Quota(Model): class User(Model): """user model the customer - """ id = wsme.wsattr(wsme.types.text, mandatory=True) role = wsme.wsattr([str]) @@ -200,7 +204,6 @@ class User(Model): class Region(Model): """network model the customer - """ name = wsme.wsattr(wsme.types.text, mandatory=True) type = wsme.wsattr(wsme.types.text, default="single", mandatory=False) @@ -232,7 +235,6 @@ class Region(Model): class Customer(Model): """customer entity with all it's related data - """ description = wsme.wsattr(wsme.types.text, mandatory=True) enabled = wsme.wsattr(bool, mandatory=True) diff --git a/orm/services/customer_manager/scripts/db_scripts/ranger_cms_create_db.sql b/orm/services/customer_manager/scripts/db_scripts/ranger_cms_create_db.sql index e70f749c..08410af3 100755 --- a/orm/services/customer_manager/scripts/db_scripts/ranger_cms_create_db.sql +++ b/orm/services/customer_manager/scripts/db_scripts/ranger_cms_create_db.sql @@ -88,3 +88,8 @@ create table if not exists user_role foreign key (role_id) references cms_role(id), index region_id (region_id), index user_id (user_id)); + +CREATE OR REPLACE VIEW rds_resource_status_view AS + ( + SELECT ID, RESOURCE_ID, REGION,STATUS, + ERR_CODE,OPERATION from orm_rds.resource_status); diff --git a/orm/services/customer_manager/scripts/db_scripts/ranger_cms_update_db.sql b/orm/services/customer_manager/scripts/db_scripts/ranger_cms_update_db.sql index 5944a5af..3a924b1a 100755 --- a/orm/services/customer_manager/scripts/db_scripts/ranger_cms_update_db.sql +++ b/orm/services/customer_manager/scripts/db_scripts/ranger_cms_update_db.sql @@ -78,14 +78,16 @@ SELECT q.*, qfd.* FROM quota_field_detail qfd DELIMITER ;; +# account for the old procedure name in DROP PROCEDURE before the name change DROP PROCEDURE IF EXISTS add_regoion_type ;; -CREATE PROCEDURE add_regoion_type() +DROP PROCEDURE IF EXISTS add_region_type ;; +CREATE PROCEDURE add_region_type() BEGIN -- add a column safely IF NOT EXISTS( (SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND COLUMN_NAME='type' AND TABLE_NAME='region') ) THEN - ALTER TABLE region ADD type varchar(32) NOT NULL DEFAULT 'single'; + ALTER TABLE region ADD type varchar(64) NOT NULL DEFAULT 'single'; ELSE UPDATE region set type = "single" where id = -1; END IF; @@ -96,7 +98,7 @@ BEGIN END ;; -CALL add_regoion_type() ;; +CALL add_region_type() ;; DELIMITER ; diff --git a/orm/services/customer_manager/swagger/swagger.yaml b/orm/services/customer_manager/swagger/swagger.yaml index 02a7df78..e6a0d3a3 100644 --- a/orm/services/customer_manager/swagger/swagger.yaml +++ b/orm/services/customer_manager/swagger/swagger.yaml @@ -886,17 +886,17 @@ definitions: type: string security_group_rules: type: string - health_monitor: + health_monitors: type: string - member: + members: type: string nat_instance: type: string - pool: + pools: type: string route_table: type: string - vip: + vips: type: string Quota: diff --git a/orm/services/flavor_manager/config.py b/orm/services/flavor_manager/config.py index febbb237..c0875554 100755 --- a/orm/services/flavor_manager/config.py +++ b/orm/services/flavor_manager/config.py @@ -153,3 +153,19 @@ authentication = { "keystone_version": "2.0", "policy_file": config.fms['policy_file'], } + +# valid_flavor_options +flavor_options = { + 'valid_cpin_opt_values': [ + 'c2', 'c4' + ], + 'valid_stor_opt_values': [ + 's1', 's2' + ], + 'valid_vnf_opt_values': [ + 'v1', 'v2', 'v3', 'v4', 'v5', 'v6', 'v7' + ], + 'valid_numa_values': ['n0'], + 'valid_nd_vnf_values': ['v8'], + 'valid_ss_vnf_values': ['v3'] +} diff --git a/orm/services/flavor_manager/fms_rest/app.py b/orm/services/flavor_manager/fms_rest/app.py index 799285fb..03e6dadc 100644 --- a/orm/services/flavor_manager/fms_rest/app.py +++ b/orm/services/flavor_manager/fms_rest/app.py @@ -1,11 +1,10 @@ -import os - from orm.common.orm_common.policy import policy from orm.services.flavor_manager.fms_rest.data import wsme from orm.services.flavor_manager.fms_rest.logger import get_logger from orm.services.flavor_manager.fms_rest.utils import authentication from pecan.commands import CommandRunner + from pecan import make_app logger = get_logger(__name__) @@ -27,8 +26,8 @@ def setup_app(config): def main(): - dir_name = os.path.dirname(__file__) - drive, path_and_file = os.path.splitdrive(dir_name) - path, filename = os.path.split(path_and_file) runner = CommandRunner() - runner.run(['serve', path + '/config.py']) + runner.run(['serve', '../config.py']) + +if __name__ == "__main__": + main() diff --git a/orm/services/flavor_manager/fms_rest/controllers/v1/orm/flavors/flavors.py b/orm/services/flavor_manager/fms_rest/controllers/v1/orm/flavors/flavors.py index bc6f1cb1..74b45cb2 100755 --- a/orm/services/flavor_manager/fms_rest/controllers/v1/orm/flavors/flavors.py +++ b/orm/services/flavor_manager/fms_rest/controllers/v1/orm/flavors/flavors.py @@ -2,6 +2,7 @@ from __future__ import absolute_import from orm.common.orm_common.injector import injector from orm.common.orm_common.utils import api_error_utils as err_utils +from orm.common.orm_common.utils import utils as common_utils from orm.services.flavor_manager.fms_rest.controllers.v1.orm.flavors.os_extra_specs import OsExtraSpecsController from orm.services.flavor_manager.fms_rest.controllers.v1.orm.flavors.regions import RegionController from orm.services.flavor_manager.fms_rest.controllers.v1.orm.flavors.tags import TagsController @@ -11,7 +12,7 @@ from orm.services.flavor_manager.fms_rest.logger import get_logger from orm.services.flavor_manager.fms_rest.logic.error_base import ErrorStatus from orm.services.flavor_manager.fms_rest.utils import authentication -from pecan import request, rest +from pecan import conf, request, rest from wsmeext.pecan import wsexpose di = injector.get_di() @@ -31,21 +32,17 @@ class FlavorController(rest.RestController): @wsexpose(FlavorWrapper, body=FlavorWrapper, rest_content_types='json', status_code=201) def post(self, flavors): flavor_logic, utils = di.resolver.unpack(FlavorController) - uuid = "FailedToGetFromUUIDGen" + uuid = "" LOG.info("FlavorController - Createflavor: " + str(flavors)) authentication.authorize(request, 'flavor:create') + common_utils.set_utils_conf(conf) try: - - if not flavors.flavor.id: - uuid = utils.make_uuid() - else: - try: - uuid = utils.create_existing_uuid( - flavor_logic.get_fixed_uuid(flavors.flavor.id)) - except TypeError: - LOG.error("UUID already exist") - raise ErrorStatus(409, 'UUID already exists') + try: + uuid = common_utils.create_or_validate_uuid(flavors.flavor.id, 'fmsId') + except TypeError: + LOG.error("UUID already exists") + raise ErrorStatus(409, 'UUID already exists') result = flavor_logic.create_flavor(flavors, uuid, request.transaction_id) @@ -106,17 +103,20 @@ class FlavorController(rest.RestController): status_code=500, error_details=str(exception)) - @wsexpose(FlavorListFullResponse, str, str, str, str, str, str, str, rest_content_types='json') + @wsexpose(FlavorListFullResponse, str, str, str, str, str, str, str, + str, str, rest_content_types='json') def get_all(self, visibility=None, region=None, tenant=None, series=None, - starts_with=None, contains=None, alias=None): + vm_type=None, vnf_name=None, starts_with=None, contains=None, + alias=None): flavor_logic, utils = di.resolver.unpack(FlavorController) LOG.info("FlavorController - GetFlavorlist") authentication.authorize(request, 'flavor:get_all') try: result = flavor_logic.get_flavor_list_by_params(visibility, region, - tenant, series, starts_with, contains, alias) - + tenant, series, + vm_type, vnf_name, + starts_with, contains, alias) return result except ErrorStatus as exception: LOG.log_exception("FlavorController - Failed to GetFlavorlist", exception) diff --git a/orm/services/flavor_manager/fms_rest/controllers/v1/orm/flavors/regions.py b/orm/services/flavor_manager/fms_rest/controllers/v1/orm/flavors/regions.py index a12607ff..15dd2f98 100755 --- a/orm/services/flavor_manager/fms_rest/controllers/v1/orm/flavors/regions.py +++ b/orm/services/flavor_manager/fms_rest/controllers/v1/orm/flavors/regions.py @@ -1,5 +1,6 @@ from __future__ import absolute_import + from orm.common.orm_common.injector import injector from orm.common.orm_common.utils import api_error_utils as err_utils from orm.services.flavor_manager.fms_rest.data.wsme.models import RegionWrapper @@ -49,23 +50,30 @@ class RegionController(rest.RestController): status_code=500, error_details=str(exception)) - @wsexpose(None, str, str, rest_content_types='json', status_code=204) - def delete(self, flavor_id, region_name): + @wsexpose(None, str, str, str, rest_content_types='json', status_code=204) + def delete(self, flavor_id, region_name, force_delete='False'): + if force_delete == 'True': + force_delete = True + else: + force_delete = False flavor_logic, utils = di.resolver.unpack(RegionController) + requester = request.headers.get('X-RANGER-Requester') + is_rds_client_request = requester == 'rds_resource_service_proxy' + LOG.info("RegionController - Delete region:{0} by RDS Proxy: {1} ".format(region_name, is_rds_client_request)) - LOG.info("RegionController - delete region: " + str(region_name)) authentication.authorize(request, 'flavor:delete_flavor_region') - try: - result = flavor_logic.delete_region(flavor_id, region_name, request.transaction_id) + result = flavor_logic.delete_region(flavor_id, region_name, request.transaction_id, + is_rds_client_request, force_delete) - LOG.info("RegionController - region deleted: " + str(result)) + if is_rds_client_request: + LOG.info("RegionController - region deleted: " + str(result)) - event_details = 'Flavor {} region {} deleted'.format(flavor_id, - region_name) - utils.audit_trail('delete region', request.transaction_id, - request.headers, flavor_id, - event_details=event_details) + event_details = 'Flavor {} region {} deleted'.format(flavor_id, + region_name) + utils.audit_trail('delete region', request.transaction_id, + request.headers, flavor_id, + event_details=event_details) except ErrorStatus as exception: LOG.log_exception("RegionController - Failed to delete region", exception) diff --git a/orm/services/flavor_manager/fms_rest/data/sql_alchemy/data_manager.py b/orm/services/flavor_manager/fms_rest/data/sql_alchemy/data_manager.py index 80325c7e..8265f223 100755 --- a/orm/services/flavor_manager/fms_rest/data/sql_alchemy/data_manager.py +++ b/orm/services/flavor_manager/fms_rest/data/sql_alchemy/data_manager.py @@ -24,7 +24,6 @@ LOG = logging.getLogger(__name__) # event handling def on_before_flush(session, flush_context, instances): - LOG.info("on_before_flush:", str(flush_context)) for model in session.new: if hasattr(model, "validate"): model.validate("new") diff --git a/orm/services/flavor_manager/fms_rest/data/sql_alchemy/db_models.py b/orm/services/flavor_manager/fms_rest/data/sql_alchemy/db_models.py index d879d58a..3172ceae 100755 --- a/orm/services/flavor_manager/fms_rest/data/sql_alchemy/db_models.py +++ b/orm/services/flavor_manager/fms_rest/data/sql_alchemy/db_models.py @@ -31,9 +31,9 @@ class FMSBaseModel(models.ModelBase): class Flavor(Base, FMSBaseModel): - """DataObject containing all the fields defined in Flavor table record. + '''Flavor is a DataObject contains all the fields defined in Flavor table record. defined as SqlAlchemy model map to a table - """ + ''' __tablename__ = "flavor" internal_id = Column(BigInteger, primary_key=True) @@ -187,7 +187,7 @@ class Flavor(Base, FMSBaseModel): self.add_tags(flavor_tags) except Exception as exception: - LOG.log_exception("Failed to add region {0} to flavor {1}".format( + LOG.log_exception("Failed to replace tags {0} to flavor {1}".format( str(flavor_tags), str(self)), exception) raise @@ -196,7 +196,7 @@ class Flavor(Base, FMSBaseModel): LOG.debug("remove all tags from flavor {}".format(str(self))) self.flavor_tags = [] except Exception as exception: - LOG.log_exception("Failed to remove all tags from flavor {1}".format(str(self)), exception) + LOG.log_exception("Failed to remove all tags from flavor {}".format(str(self)), exception) raise def remove_tag(self, tag_name): @@ -239,6 +239,7 @@ class Flavor(Base, FMSBaseModel): raise def remove_tenant(self, tenant_id): + deleted_flag = False assert isinstance(tenant_id, basestring) try: LOG.debug("remove tenants {0} from flavor {1}".format(tenant_id, @@ -247,6 +248,12 @@ class Flavor(Base, FMSBaseModel): for tenant in reversed(self.flavor_tenants): if tenant.tenant_id == tenant_id: self.flavor_tenants.remove(tenant) + deleted_flag = True + + if not deleted_flag: + raise ErrorStatus(404, + "tenant {0} does not exist for flavor id {1}".format( + tenant_id, str(self.id))) except Exception as exception: LOG.log_exception( @@ -292,10 +299,9 @@ class Flavor(Base, FMSBaseModel): deleted_flag = True if not deleted_flag: - # no need to raise in delete not found - LOG.debug( - "Failed to remove extra_spec {0} from flavor id {1}".format( - extra_spec_key_name, str(self.id))) + raise ErrorStatus(404, + "extra spec {0} does not exist for flavor id {1}".format( + extra_spec_key_name, str(self.id))) except ErrorStatus as e: raise @@ -305,66 +311,6 @@ class Flavor(Base, FMSBaseModel): "Failed to remove extra_spec {0} from flavor {1}".format(extra_spec_key_name, str(self)), exception) raise - def add_tags(self, flavor_tags): - assert isinstance(flavor_tags, list) and all(isinstance(ft, FlavorTag) for ft in flavor_tags) - try: - LOG.debug("add tags {0} to flavor {1}".format(str(flavor_tags), - str(self))) - for tag in flavor_tags: - self.flavor_tags.append(tag) - - except Exception as exception: - LOG.log_exception("Failed to add region {0} to flavor {1}".format( - str(flavor_tags), str(self)), exception) - raise - - def replace_tags(self, flavor_tags): - assert isinstance(flavor_tags, list) and all(isinstance(ft, FlavorTag) for ft in flavor_tags) - try: - LOG.debug("replace tags {0} for flavor {1}".format(str(flavor_tags), - str(self))) - self.remove_all_tags() - self.add_tags(flavor_tags) - - except Exception as exception: - LOG.log_exception("Failed to add region {0} to flavor {1}".format( - str(flavor_tags), str(self)), exception) - raise - - def remove_all_tags(self): - try: - LOG.debug("remove all tags from flavor {}".format(str(self))) - self.flavor_tags = [] - except Exception as exception: - LOG.log_exception("Failed to remove all tags from flavor {1}".format(str(self)), exception) - raise - - def remove_tag(self, tag_name): - deleted_flag = False - assert isinstance(tag_name, basestring) - try: - LOG.debug("remove tag {0} from flavor {1}".format(tag_name, - str(self))) - - for tag in reversed(self.flavor_tags): - if tag.key_name == tag_name: - self.flavor_tags.remove(tag) - deleted_flag = True - - if not deleted_flag: - raise ErrorStatus(404, - "Failed to remove tag {0} from flavor id {1}".format( - tag_name, str(self.id))) - - except ErrorStatus as e: - raise - - except Exception as exception: - LOG.log_exception( - "Failed to remove tag {0} from flavor {1}".format( - tag_name, str(self)), exception) - raise - def validate(self, type): ''' type can be "new" or "dirty" - comes from event ''' @@ -456,8 +402,8 @@ class FlavorTag(Base, FMSBaseModel): ) def __str__(self): - tag = "\"{0}\":\"{1}\"".format(self.key_name, self.key_value) - return tag + tags = "\"{0}\":\"{1}\"".format(self.key_name, self.key_value) + return tags ''' diff --git a/orm/services/flavor_manager/fms_rest/data/sql_alchemy/flavor/flavor_record.py b/orm/services/flavor_manager/fms_rest/data/sql_alchemy/flavor/flavor_record.py index ba3380c0..547c83f9 100755 --- a/orm/services/flavor_manager/fms_rest/data/sql_alchemy/flavor/flavor_record.py +++ b/orm/services/flavor_manager/fms_rest/data/sql_alchemy/flavor/flavor_record.py @@ -1,5 +1,6 @@ - -from orm.services.flavor_manager.fms_rest.data.sql_alchemy.db_models import (Flavor, FlavorRegion, +from orm.services.flavor_manager.fms_rest.data.sql_alchemy.db_models import (Flavor, + FlavorRegion, + FlavorTag, FlavorTenant) from orm.services.flavor_manager.fms_rest.logger import get_logger @@ -148,6 +149,16 @@ class FlavorRecord: LOG.log_exception(message, exception) raise + def get_flavors_status_by_uuids(self, uuid_str): + results = self.session.connection().execute("SELECT resource_id, status from rds_resource_status_view" + " WHERE resource_id in ({})".format(uuid_str)) + resource_status_dict = {} + if results: + resource_status_dict = dict((resource_id, status) for resource_id, status in results) + + results.close() + return resource_status_dict + def get_flavors_by_criteria(self, **criteria): try: @@ -156,6 +167,8 @@ class FlavorRecord: region = criteria['region'] if 'region' in criteria else None tenant = criteria['tenant'] if 'tenant' in criteria else None series = criteria['series'] if 'series' in criteria else None + vm_type = criteria['vm_type'] if 'vm_type' in criteria else None + vnf_name = criteria['vnf_name'] if 'vnf_name' in criteria else None starts_with = criteria['starts_with'] if 'starts_with' in criteria else None contains = criteria['contains'] if 'contains' in criteria else None alias = criteria['alias'] if 'alias' in criteria else None @@ -177,7 +190,14 @@ class FlavorRecord: if tenant: query = query.join(FlavorTenant).filter(FlavorTenant.flavor_internal_id == Flavor.internal_id, FlavorTenant.tenant_id == tenant) - + if vm_type: + query = query.join(FlavorTag).filter(FlavorTag.flavor_internal_id == Flavor.internal_id, + FlavorTag.key_name == 'vm_type', + FlavorTag.key_value == vm_type) + if vnf_name: + query = query.join(FlavorTag).filter(FlavorTag.flavor_internal_id == Flavor.internal_id, + FlavorTag.key_name == 'vnf_name', + FlavorTag.key_value == vnf_name) if visibility: query = query.filter(Flavor.visibility == visibility) diff --git a/orm/services/flavor_manager/fms_rest/data/wsme/models.py b/orm/services/flavor_manager/fms_rest/data/wsme/models.py index 19b764b8..32e6c803 100755 --- a/orm/services/flavor_manager/fms_rest/data/wsme/models.py +++ b/orm/services/flavor_manager/fms_rest/data/wsme/models.py @@ -1,6 +1,8 @@ import wsme -from orm.common.orm_common.utils.cross_api_utils import set_utils_conf, get_regions_of_group +from orm.common.orm_common.utils.cross_api_utils import (set_utils_conf, + get_regions_of_group, + validate_description) from orm.services.flavor_manager.fms_rest.data.sql_alchemy import db_models from orm.services.flavor_manager.fms_rest.data.wsme.model import Model from orm.services.flavor_manager.fms_rest.logic.error_base import ErrorStatus @@ -42,7 +44,6 @@ class ExtraSpecsWrapper(Model): def to_db_model(self): extra_spec = [] - for key, value in self.os_extra_specs.iteritems(): if Flavor.ignore_extra_specs_input(key.replace(":", "____")): continue @@ -164,7 +165,6 @@ class Flavor(Model): visibility = wsme.wsattr(wsme.types.text, mandatory=True) tenants = wsme.wsattr(wsme.types.ArrayType(str), mandatory=False) status = wsme.wsattr(wsme.types.text, mandatory=False) - tags = wsme.wsattr(wsme.types.DictType(str, str), mandatory=False) tag = wsme.wsattr(wsme.types.DictType(str, str), mandatory=False) options = wsme.wsattr(wsme.types.DictType(str, str), mandatory=False) extra_specs = wsme.wsattr(wsme.types.DictType(str, str), mandatory=False, @@ -182,7 +182,6 @@ class Flavor(Model): swap="0", ephemeral="0", extra_specs={}, - tags={}, tag={}, options={}, regions=[], @@ -199,7 +198,7 @@ class Flavor(Model): :param vcpus: :param disk: Disk in GB :param swap: is optional and default is 0 - :param ephemeral: is optional and default is 0 + :param ephemeral: is optional and default is 0, size in GB :param extra_spec: key-value dictionary :param tags: key-value dictionary :param options: key-value dictionary @@ -220,7 +219,6 @@ class Flavor(Model): self.swap = swap self.ephemeral = "0" if not ephemeral else ephemeral self.extra_specs = extra_specs - self.tags = tags self.tag = tag self.options = options self.regions = regions @@ -232,13 +230,20 @@ class Flavor(Model): bundle = ['b1', 'b2'] numa = ['n0', 'n1'] vlan = ['v1', 'v2', 'v3', 'v4', 'v5', 'v6'] - + vcpu_limit = int(conf.flavor_limits.vcpu_limit) + vram_limit = int(conf.flavor_limits.vram_limit) + swap_file_limit = int(conf.flavor_limits.swap_file_limit) + ephemeral_limit = int(conf.flavor_limits.ephemeral_limit) try: + isValid = validate_description(self.description) + if not isValid: + raise ErrorStatus(400, "Flavor description does not allow special characters :" + " only dashes, commas, and period allowed.") if not self.ram.isdigit(): raise ErrorStatus(400, "ram must be a number") if not self.vcpus.isdigit(): raise ErrorStatus(400, "vcpus must be a number") - if not self.disk.isdigit(): + if not self.validInt(self.disk): raise ErrorStatus(400, "disk must be a number") if not self.swap.isdigit(): raise ErrorStatus(400, "swap must be a number") @@ -249,20 +254,24 @@ class Flavor(Model): if self.series not in allowed_series: raise ErrorStatus(400, "series possible values are {}".format( allowed_series)) - if int(self.ram) not in range(1024, 327680 + 1, 1024): + if int(self.ram) not in range(1024, vram_limit + 1, 1024): raise ErrorStatus(400, - "ram value is out of range. Expected range is 1024(1GB)-327680(320GB) " - "and must be a multiple of 1024") - if int(self.vcpus) not in range(1, 48 + 1): - raise ErrorStatus(400, "vcpus value is out of range. Expected range is 1-48") + "ram value is out of range. Expected range is 1024(1GB)-" + "%6d(%3dGB) and must be a multiple of 1024" % + (vram_limit, vram_limit / 1024)) + if int(self.vcpus) not in range(1, vcpu_limit + 1): + raise ErrorStatus(400, "vcpus value is out of range. Expected range is 1-" + "%2d" % (vcpu_limit)) if int(self.disk) < 0: - raise ErrorStatus(400, "disk must be a non negative number") - if int(self.ephemeral) not in range(0, 320 + 1): - raise ErrorStatus(400, "ephemeral value is out of range. Expected range is 0-320") - if int(self.swap) not in range(0, 327680 + 1, 1024): + raise ErrorStatus(400, "disk cannot be less than zero") + if int(self.ephemeral) not in range(0, ephemeral_limit + 1): + raise ErrorStatus(400, "ephemeral value is out of range. Expected range is 0-" + "%5d(%2dTB)" % (ephemeral_limit, ephemeral_limit / 1000)) + if int(self.swap) not in range(0, swap_file_limit + 1, 1024): raise ErrorStatus(400, - "swap value is out of range. Expected range is 0-327680(320GB) " - "and must be a multiple of 1024") + "swap value is out of range. Expected range is 0-" + "%6d(%3dGB) and must be a multiple of 1024" % + (swap_file_limit, swap_file_limit / 1024)) except ValueError: raise ErrorStatus(400, "ram, vcpus, disk, ephemeral and swap must be integers") for symbol, value in self.extra_specs.iteritems(): @@ -284,13 +293,6 @@ class Flavor(Model): "region type \'group\' is invalid in this " "action, \'group\' can be only in create flavor action") - # check if user entered tag instead of tags - if self.tags and self.tag: - raise ErrorStatus(400, "you entered \'tag\' and \'tags\' arguments, " - "please remove the \'tag\'") - if self.tag and not self.tags: - self.tags = self.tag - def to_db_model(self): flavor = db_models.Flavor() extra_spec = [] @@ -310,7 +312,7 @@ class Flavor(Model): if self.series: extra_spec.extend(self.get_extra_spec_needed()) - for symbol, value in self.tags.iteritems(): + for symbol, value in self.tag.iteritems(): tag = db_models.FlavorTag() tag.key_name = symbol tag.key_value = value @@ -389,7 +391,7 @@ class Flavor(Model): flavor.extra_specs[extra_spec.key_name] = extra_spec.key_value for tag in sql_flavor.flavor_tags: - flavor.tags[tag.key_name] = tag.key_value + flavor.tag[tag.key_name] = tag.key_value for option in sql_flavor.flavor_options: flavor.options[option.key_name] = option.key_value @@ -406,38 +408,52 @@ class Flavor(Model): return False def get_extra_spec_needed(self): + valid_vnf_opts = conf.flavor_options.valid_vnf_opt_values[:] + valid_stor_opts = conf.flavor_options.valid_stor_opt_values[:] + valid_cpin_opts = conf.flavor_options.valid_cpin_opt_values[:] + extra_spec_needed = [] items = conf.extra_spec_needed_table.to_dict() for symbol, value in items[self.series].iteritems(): es = db_models.FlavorExtraSpec() es.key_name = symbol.replace("____", ":") es.key_value = value + + # update extra_spec default values as needed if self.series == "gv" and "c2" in es.key_name: if "c4" in self.options and self.options['c4'].lower() == "true": es.key_name = es.key_name.replace("c2", "c4") + elif self.series == "ss" and "s1" in es.key_name: + if "s2" in self.options and self.options['s2'].lower() == "true": + es.key_name = es.key_name.replace("s1", "s2") extra_spec_needed.append(es) + options_items = self.options # check some keys if they exist in option add values to extra specs - if len(options_items) > 0 and self.series in ('ns', 'nv', 'nd'): + if self.series in ('ns', 'nv', 'nd', 'ss'): c2_c4_in = False n0_in = False for symbol, value in options_items.iteritems(): es = db_models.FlavorExtraSpec() es.key_name = "aggregate_instance_extra_specs:%s" % symbol es.key_value = "true" + # format numa node extra spec as appropriate if symbol == "n0" and options_items[symbol].lower() == "true": n0_in = True es.key_value = 2 es.key_name = "hw:numa_nodes" extra_spec_needed.append(es) - elif symbol in ('c2', 'c4') and options_items[symbol].lower() == "true": + # format cpu pinnin extra spec as appropriate + elif symbol in valid_cpin_opts and options_items[symbol].lower() == "true": c2_c4_in = True extra_spec_needed.append(es) + # format vnf profile extra spec as appropriate try: - if len(symbol) == 2 and symbol[0] == 'v' and 0 < int(symbol[1]) < 9 and options_items[symbol].lower() == "true": + if self.series == 'ns' and symbol in valid_vnf_opts and options_items[symbol].lower() == "true": extra_spec_needed.append(es) except Exception: pass + # if c4, c2 and n0 not in options keys add these values to extra specs if not c2_c4_in: es = db_models.FlavorExtraSpec() @@ -449,6 +465,33 @@ class Flavor(Model): es.key_value = 1 es.key_name = "hw:numa_nodes" extra_spec_needed.append(es) + if {'v5', 'i1'}.issubset(options_items.keys()): + es = db_models.FlavorExtraSpec() + es.key_name = "hw:cpu_sockets" + es.key_value = "1" + extra_spec_needed.append(es) + + es = db_models.FlavorExtraSpec() + es.key_name = "hw:cpu_threads" + es.key_value = "1" + extra_spec_needed.append(es) + + es = db_models.FlavorExtraSpec() + es.key_name = "hw:pci_numa_custom_policy" + es.key_value = "ignore" + extra_spec_needed.append(es) + + es = db_models.FlavorExtraSpec() + es.key_name = "hw:cpu_cores" + es.key_value = self.vcpus + extra_spec_needed.append(es) + + # convert the key_value to a string to avoid/fix pecan json rendering error in update extra_specs + i = 0 + while i < len(extra_spec_needed): + extra_spec_needed[i].key_value = str(extra_spec_needed[i].key_value) + i += 1 + return extra_spec_needed def get_as_summary_dict(self): @@ -478,6 +521,13 @@ class Flavor(Model): regions = get_regions_of_group(group_name) return regions + def validInt(self, check_value): + try: + int(check_value) + except ValueError: + return False + return True + class FlavorWrapper(Model): """flavor model diff --git a/orm/services/flavor_manager/fms_rest/etc/policy.json b/orm/services/flavor_manager/fms_rest/etc/policy.json index 887a8bd9..b414b87f 100755 --- a/orm/services/flavor_manager/fms_rest/etc/policy.json +++ b/orm/services/flavor_manager/fms_rest/etc/policy.json @@ -1,10 +1,11 @@ { "default": "!", - "admin": "role:admin", - "admin_support": "role:admin_support", - "admin_viewer": "role:admin_viewer", - "admin_or_support": "role:admin or role:admin_support", + "admin": "role:admin and tenant:admin or role:admin and tenant:services", + "admin_support": "role:admin_support and tenant:admin or role:admin_support and tenant:services", + "admin_viewer": "role:admin_viewer and tenant:admin or role:admin_viewer and tenant:services", + + "admin_or_support": "rule:admin or rule:admin_support", "admin_or_support_or_viewer": "rule:admin or rule:admin_support or rule:admin_viewer", "flavor:create": "rule:admin_or_support", @@ -12,9 +13,9 @@ "flavor:get_all": "rule:admin_or_support_or_viewer", "flavor:delete": "rule:admin", - "flavor:get_flavor_extra_specs": "rule:admin", + "flavor:get_flavor_extra_specs": "rule:admin_or_support_or_viewer", "flavor:add_flavor_extra_specs": "rule:admin_or_support", - "flavor:replace_flavor_extra_specs": "rule:admin_or_support", + "flavor:replace_flavor_extra_specs": "rule:admin", "flavor:delete_flavor_extra_specs": "rule:admin", "flavor:add_flavor_regions": "rule:admin_or_support", @@ -22,7 +23,7 @@ "flavor:get_flavor_tags": "rule:admin_or_support_or_viewer", "flavor:add_flavor_tags": "rule:admin_or_support", - "flavor:replace_flavor_tags": "rule:admin_or_support", + "flavor:replace_flavor_tags": "rule:admin", "flavor:delete_flavor_tags": "rule:admin", "flavor:add_flavor_tenants": "rule:admin_or_support", diff --git a/orm/services/flavor_manager/fms_rest/logic/flavor_logic.py b/orm/services/flavor_manager/fms_rest/logic/flavor_logic.py index fd4fe2f5..35feaaa7 100755 --- a/orm/services/flavor_manager/fms_rest/logic/flavor_logic.py +++ b/orm/services/flavor_manager/fms_rest/logic/flavor_logic.py @@ -1,5 +1,3 @@ -import uuid - from orm.services.flavor_manager.fms_rest.data.sql_alchemy.db_models import FlavorRegion, FlavorTenant from orm.services.flavor_manager.fms_rest.data.wsme.models import (ExtraSpecsWrapper, Flavor, FlavorListFullResponse, FlavorWrapper, @@ -9,6 +7,8 @@ from orm.services.flavor_manager.fms_rest.logger import get_logger from orm.services.flavor_manager.fms_rest.logic.error_base import ConflictError, ErrorStatus, NotFoundError from orm.common.orm_common.injector import injector +from pecan import conf + LOG = get_logger(__name__) di = injector.get_di() @@ -18,7 +18,6 @@ di = injector.get_di() def create_flavor(flavor, flavor_uuid, transaction_id): DataManager = di.resolver.unpack(create_flavor) datamanager = DataManager() - try: flavor.flavor.handle_region_groups() flavor.flavor.validate_model("create") @@ -120,9 +119,7 @@ def delete_flavor_by_uuid(flavor_uuid): # , transaction_id): sql_flavor = flavor_rec.get_flavor_by_id(flavor_uuid) if sql_flavor is None: - # The flavor does not exist, so the delete operation is - # considered successful - return + raise NotFoundError(message="Flavor '{}' not found".format(flavor_uuid)) existing_region_names = sql_flavor.get_existing_region_names() if len(existing_region_names) > 0: @@ -228,33 +225,43 @@ def add_regions(flavor_uuid, regions, transaction_id): @di.dependsOn('data_manager') -def delete_region(flavor_uuid, region_name, transaction_id): +def delete_region(flavor_uuid, region_name, transaction_id, on_success_by_rds, + force_delete): DataManager = di.resolver.unpack(delete_region) datamanager = DataManager() try: flavor_rec = datamanager.get_record('flavor') sql_flavor = flavor_rec.get_flavor_by_id(flavor_uuid) + if not sql_flavor and on_success_by_rds: + return if not sql_flavor: raise ErrorStatus(404, 'flavor id {0} not found'.format(flavor_uuid)) existing_region_names = sql_flavor.get_existing_region_names() - sql_flavor.remove_region(region_name) - datamanager.flush() # i want to get any exception created by previous actions against the database - send_to_rds_if_needed(sql_flavor, existing_region_names, "put", transaction_id) - - datamanager.commit() + datamanager.flush() # Get any exception created by previous actions against the database + if on_success_by_rds: + datamanager.commit() + else: + send_to_rds_if_needed(sql_flavor, existing_region_names, "put", + transaction_id) + if force_delete: + datamanager.commit() + else: + datamanager.rollback() except ErrorStatus as exp: LOG.log_exception("FlavorLogic - Failed to update flavor", exp) datamanager.rollback() raise exp + except Exception as exp: LOG.log_exception("FlavorLogic - Failed to delete region", exp) datamanager.rollback() raise exp + finally: datamanager.close() @@ -328,11 +335,18 @@ def delete_tenant(flavor_uuid, tenant_id, transaction_id): datamanager.flush() # i want to get any exception created by previous actions against the database send_to_rds_if_needed(sql_flavor, existing_region_names, "put", transaction_id) datamanager.commit() - - except ErrorStatus as exp: - LOG.log_exception("FlavorLogic - Failed to update flavor", exp) + except NotFoundError as exp: datamanager.rollback() + LOG.log_exception("FlavorLogic - Flavor not found", exp) raise + except ErrorStatus as exp: + datamanager.rollback() + if exp.status_code == 404: + LOG.log_exception("FlavorLogic - Tenant not found", exp) + raise + else: + LOG.log_exception("FlavorLogic - failed to delete tenant", exp) + raise except Exception as exp: LOG.log_exception("FlavorLogic - Failed to delete tenant", exp) datamanager.rollback() @@ -424,8 +438,12 @@ def delete_extra_specs(flavor_id, transaction_id, extra_spec=None): except ErrorStatus as exp: datamanager.rollback() - LOG.log_exception("error in adding extra specs", exp) - raise + if exp.status_code == 404: + LOG.log_exception("FlavorLogic - extra specs not found", exp) + raise + else: + LOG.log_exception("FlavorLogic - failed to delete extra specs", exp) + raise except Exception as exp: datamanager.rollback() @@ -487,8 +505,7 @@ def delete_tags(flavor_id, tag, transaction_id): except ErrorStatus as exp: if exp.status_code == 404: LOG.log_exception("FlavorLogic - Tag not found", exp) - # Do not raise an exception if the tag was not found - return + raise else: LOG.log_exception("FlavorLogic - failed to delete tags", exp) raise @@ -702,7 +719,6 @@ def get_flavor_by_uuid_or_name(flavor_uuid_or_name): DataManager, rds_proxy = di.resolver.unpack(get_flavor_by_uuid) datamanager = DataManager() - try: flavor_record = datamanager.get_record('flavor') @@ -727,33 +743,46 @@ def get_flavor_by_uuid_or_name(flavor_uuid_or_name): @di.dependsOn('rds_proxy') def update_region_statuses(flavor, sql_flavor): rds_proxy = di.resolver.unpack(update_region_statuses) - # remove the regions comes from database and return the regions which return from rds, # because there might be group region there (in the db) and in the response from the # rds we will have a list of all regions belong to this group flavor.regions[:] = [] resp = rds_proxy.get_status(sql_flavor.id) if resp.status_code == 200: - status_resp = resp.json() - if sql_flavor.flavor_regions and len(sql_flavor.flavor_regions) > 0: - if 'regions' in status_resp.keys(): - for region_status in status_resp['regions']: - flavor.regions.append( - Region(name=region_status['region'], type="single", - status=region_status['status'], - error_message=region_status['error_msg'])) + rds_status_resp = resp.json() + # store all regions for the flavor in the flavor_regions_list + flavor_regions_list = [] + for region_data in sql_flavor.flavor_regions: + flavor_regions_list.append(region_data.region_name) + + # get region status if region in flavor_regions_list + if flavor_regions_list and 'regions' in rds_status_resp.keys(): + for rds_region_status in rds_status_resp['regions']: + # check that the region read from RDS is in the flavor_regions_list + if rds_region_status['region'] in flavor_regions_list: + flavor.regions.append( + Region(name=rds_region_status['region'], type="single", + status=rds_region_status['status'], + error_message=rds_region_status['error_msg'])) + + if 'status' in rds_status_resp.keys(): + # if flavor not assigned to region set flavor.status to 'no regions' + if flavor_regions_list: + flavor.status = rds_status_resp['status'] + else: + flavor.status = 'no regions' - if 'status' in status_resp.keys(): - flavor.status = status_resp['status'] elif resp.status_code == 404: - flavor.status = "Success" + # flavor id not in rds resource_status table as no region is assigned + flavor.status = "no regions" else: flavor.status = "N/A" @di.dependsOn('data_manager') @di.dependsOn('rds_proxy') -def get_flavor_list_by_params(visibility, region, tenant, series, starts_with, contains, alias): +def get_flavor_list_by_params(visibility, region, tenant, series, vm_type, + vnf_name, starts_with, contains, alias): DataManager, rds_proxy = di.resolver.unpack(get_flavor_list_by_params) datamanager = DataManager() @@ -764,15 +793,25 @@ def get_flavor_list_by_params(visibility, region, tenant, series, starts_with, c region=region, tenant=tenant, series=series, + vm_type=vm_type, + vnf_name=vnf_name, starts_with=starts_with, contains=contains, alias=alias) response = FlavorListFullResponse() - for sql_flavor in sql_flavors: - flavor = Flavor.from_db_model(sql_flavor) - update_region_statuses(flavor, sql_flavor) - response.flavors.append(flavor) + if sql_flavors: + uuids = ','.join(str("\'" + sql_flavor.id + "\'") + for sql_flavor in sql_flavors if sql_flavor and sql_flavor.id) + resource_status_dict = flavor_record.get_flavors_status_by_uuids(uuids) + + for sql_flavor in sql_flavors: + flavor = Flavor.from_db_model(sql_flavor) + if sql_flavor.id: + status = resource_status_dict.get(sql_flavor.id) + flavor.status = not status and 'no regions' or status + response.flavors.append(flavor) + except Exception as exp: LOG.log_exception("Fail to get_flavor_list_by_params", exp) raise @@ -783,10 +822,18 @@ def get_flavor_list_by_params(visibility, region, tenant, series, starts_with, c def calculate_name(flavor): + + valid_vnf_opts = conf.flavor_options.valid_vnf_opt_values[:] + valid_stor_opts = conf.flavor_options.valid_stor_opt_values[:] + valid_cpin_opts = conf.flavor_options.valid_cpin_opt_values[:] + valid_nd_vnf_opts = conf.flavor_options.valid_nd_vnf_values[:] + valid_numa_opts = conf.flavor_options.valid_numa_values[:] + valid_ss_vnf_opts = conf.flavor_options.valid_ss_vnf_values[:] + name = "{0}.c{1}r{2}d{3}".format(flavor.flavor.series, flavor.flavor.vcpus, int(flavor.flavor.ram) / 1024, flavor.flavor.disk) - + series = name[:2] swap = getattr(flavor.flavor, 'swap', 0) if swap and int(swap): name += '{}{}'.format('s', int(swap) / 1024) @@ -796,9 +843,23 @@ def calculate_name(flavor): name += '{}{}'.format('e', ephemeral) if len(flavor.flavor.options) > 0: - name += '.' for key in sorted(flavor.flavor.options.iterkeys()): - name += key + # only include valid option parameters in flavor name + if ((series == 'nd' and key[0] == 'v' and key in valid_nd_vnf_opts) or + (series == 'ns' and key[0] == 'v' and key in valid_vnf_opts) or + (series == 'ss' and key[0] == 'v' and key in valid_ss_vnf_opts) or + (key[0] == 'n' and key in valid_numa_opts) or + (key[0] == 's' and key in valid_stor_opts) or + (key[0] == 'c' and key in valid_cpin_opts)): + + if name.count('.') < 2: + name += '.' + name += key + + if key == 'v5': + for k in flavor.flavor.options.iterkeys(): + if k == 'i1': + name += k return name @@ -833,17 +894,3 @@ def region_name_exist_in_regions(region_name, regions): def set_regions_action(flavor_dict, action): for region in flavor_dict["regions"]: region["action"] = action - - -def get_fixed_uuid(uuid_to_fix): - """Fix a version 4 UUID.""" - try: - new_uuid = uuid.UUID(uuid_to_fix, version=4) - if (uuid_to_fix == new_uuid.hex) or (uuid_to_fix == str(new_uuid)): - # It is a version 4 UUID, remove its dashes - return new_uuid.hex - except ValueError: - # Not a UUID (of any version) - pass - - raise ErrorStatus(400, 'Flavor ID must be a version 4 UUID!') diff --git a/orm/services/id_generator/config.py b/orm/services/id_generator/config.py index e7f01983..fea2c78b 100755 --- a/orm/services/id_generator/config.py +++ b/orm/services/id_generator/config.py @@ -1,12 +1,10 @@ -from oslo_config import cfg +from orm import base_config as config -CONF = cfg.CONF - # Server Specific Configurations server = { - 'port': CONF.uuid.port, - 'host': CONF.api.host + 'port': config.uuid['port'], + 'host': config.orm_host } # Pecan Application Configurations app = { @@ -15,10 +13,9 @@ app = { 'debug': True, } -verify = CONF.api.ssl_verify - +verify = config.ssl_verify database = { - 'connection_string': CONF.database.connection + '/orm' + 'connection_string': config.db_url + 'orm' } # Custom Configurations must be in Python dictionary format:: # diff --git a/orm/services/id_generator/uuidgen/app.py b/orm/services/id_generator/uuidgen/app.py index 2bde154d..c3ec1d4a 100755 --- a/orm/services/id_generator/uuidgen/app.py +++ b/orm/services/id_generator/uuidgen/app.py @@ -1,26 +1,14 @@ -import os - -from oslo_log import log as logging - -from pecan.commands import CommandRunner +import logging from pecan import make_app -LOG = logging.getLogger(__name__) +logger = logging.getLogger(__name__) def setup_app(config): app_conf = dict(config.app) + app = make_app(app_conf.pop('root'), logging=getattr(config, 'logging', {}), **app_conf) - LOG.info('Starting uuidgen...') - + logger.info('Starting uuidgen...') return app - - -def main(): - dir_name = os.path.dirname(__file__) - drive, path_and_file = os.path.splitdrive(dir_name) - path, filename = os.path.split(path_and_file) - runner = CommandRunner() - runner.run(['serve', path + '/config.py']) diff --git a/orm/services/id_generator/uuidgen/controllers/v1/uuid_controller.py b/orm/services/id_generator/uuidgen/controllers/v1/uuid_controller.py index a5fc7df0..30535961 100755 --- a/orm/services/id_generator/uuidgen/controllers/v1/uuid_controller.py +++ b/orm/services/id_generator/uuidgen/controllers/v1/uuid_controller.py @@ -1,11 +1,13 @@ import datetime import logging +import re import uuid -from orm.services.id_generator.uuidgen.db.db_manager import DBManager from pecan import expose, response from pecan.rest import RestController +from orm.services.id_generator.uuidgen.db.db_manager import DBManager + LOG = logging.getLogger(__name__) @@ -22,8 +24,7 @@ def respond(reason, code, message): class UUIDController(RestController): @expose(template='json') def post(self, **kw): - """Method to handle POST /v1/uuids - create and return a new uuid + """Method to handle POST /v1/uuids - create and return a new uuid prameters: uuid_type (optional) return: dict describing success or failure of post command @@ -45,18 +46,23 @@ class UUIDController(RestController): LOG.info("UUIDController.post - " + str(messageToReturn)) return messageToReturn - if not customer_id: + if not customer_id or customer_id == 'Unset': return self.create_new_uuid(uuid_type) - return self.validate_and_add_uuid(customer_id) + if not re.match(r'^[A-Za-z0-9]+$', customer_id): + response.status = 400 + messageToReturn = respond("badRequest", 400, "Only alphanumeric characters allowed!") + LOG.info("UUIDController.post - " + str(messageToReturn)) + return messageToReturn - def validate_and_add_uuid(self, customer_id): + return self.validate_and_add_uuid(customer_id, uuid_type) + + def validate_and_add_uuid(self, uuid, uuid_type): try: - uuid_type = "custId" db_manager = DBManager() - db_manager.create_uuid(customer_id, uuid_type) + db_manager.create_uuid(uuid, uuid_type) return { - "uuid": customer_id, + "uuid": uuid, "issued_at": datetime.datetime.utcnow().isoformat() + 'Z', "uuid_type": uuid_type } @@ -65,13 +71,15 @@ class UUIDController(RestController): # we just need to save it in the database that we will not give this value in the future requests # but we don't need to throw exception if already exist, this is not our responsible # if it is duplicate uuid it will fail in the service which uses this uuid (cms, fms) - if e.orig.args[0] != 1062: + if e.inner_exception.orig[0] == 1062: + LOG.info("Duplicate UUID=" + uuid) + else: response.status = 500 messageToReturn = respond("badRequest", 500, 'Database error') LOG.error(str(messageToReturn) + "Exception: " + str(e)) return messageToReturn return { - "uuid": customer_id, + "uuid": uuid, "issued_at": datetime.datetime.utcnow().isoformat() + 'Z', "uuid_type": uuid_type } diff --git a/orm/services/id_generator/uuidgen/db/db_manager.py b/orm/services/id_generator/uuidgen/db/db_manager.py index c26ca93c..b4c67ebc 100755 --- a/orm/services/id_generator/uuidgen/db/db_manager.py +++ b/orm/services/id_generator/uuidgen/db/db_manager.py @@ -10,7 +10,6 @@ logger = logging.getLogger(__name__) class DBManager(object): def __init__(self, connection_string=None): - if not connection_string: connection_string = conf.database.connection_string diff --git a/orm/services/image_manager/ims/app.py b/orm/services/image_manager/ims/app.py index 2b13ffbe..f3aa3cbd 100755 --- a/orm/services/image_manager/ims/app.py +++ b/orm/services/image_manager/ims/app.py @@ -1,5 +1,3 @@ -import os - from orm.common.orm_common.policy import policy from orm.common.orm_common.utils.utils import set_utils_conf from orm.services.image_manager.ims.logger import get_logger @@ -29,8 +27,8 @@ def setup_app(config): def main(): - dir_name = os.path.dirname(__file__) - drive, path_and_file = os.path.splitdrive(dir_name) - path, filename = os.path.split(path_and_file) runner = CommandRunner() - runner.run(['serve', path + '/config.py']) + runner.run(['serve', '../config.py']) + +if __name__ == "__main__": + main() diff --git a/orm/services/image_manager/ims/controllers/__init__.py b/orm/services/image_manager/ims/controllers/__init__.py index b45e7e79..e69de29b 100755 --- a/orm/services/image_manager/ims/controllers/__init__.py +++ b/orm/services/image_manager/ims/controllers/__init__.py @@ -1,11 +0,0 @@ -"""Init package.""" -import os - -from orm.common.orm_common.injector import injector -import orm.services.image_manager.ims.di_providers as di_providers -from orm.services.image_manager.ims.logger import get_logger - -logger = get_logger(__name__) - -_current_dirname = os.path.dirname(os.path.realpath(di_providers.__file__)) -injector.register_providers('IMS_ENV', _current_dirname, logger) diff --git a/orm/services/image_manager/ims/controllers/v1/orm/images/images.py b/orm/services/image_manager/ims/controllers/v1/orm/images/images.py index 42ef8f55..8105b375 100755 --- a/orm/services/image_manager/ims/controllers/v1/orm/images/images.py +++ b/orm/services/image_manager/ims/controllers/v1/orm/images/images.py @@ -43,13 +43,10 @@ class ImageController(rest.RestController): LOG.info("ImageController - Create image: " + str(image_wrapper.image.name)) image_wrapper.image.owner = request.headers.get('X-RANGER-Owner') or '' - if not image_wrapper.image.id: - uuid = utils.make_uuid() - else: - try: - uuid = utils.create_existing_uuid(image_wrapper.id) - except TypeError: - raise ErrorStatus(409.1, message='Image UUID already exists') + try: + uuid = utils.create_or_validate_uuid(image_wrapper.image.id, 'imsId') + except TypeError: + raise ErrorStatus(409.1, message='Image UUID already exists') try: ret_image = image_logic.create_image(image_wrapper, uuid, @@ -125,7 +122,7 @@ class ImageController(rest.RestController): auth.authorize(request, "image:get_one") try: - return image_logic.get_image_by_uuid(image_uuid) + return image_logic.get_image_by_uuid(image_uuid, query_by_id_or_name=True) except ErrorStatus as exception: LOG.log_exception("ImageController - Failed to GetImageDetails", exception) @@ -140,14 +137,14 @@ class ImageController(rest.RestController): error_details=str(exception)) @wsexpose(ImageSummaryResponse, str, str, str, rest_content_types='json') - def get_all(self, visibility=None, region=None, tenant=None): + def get_all(self, visibility=None, region=None, customer=None): image_logic, utils = di.resolver.unpack(ImageController) auth.authorize(request, "image:list") try: LOG.info("ImageController - GetImagelist") - result = image_logic.get_image_list_by_params(visibility, region, tenant) + result = image_logic.get_image_list_by_params(visibility, region, customer) return result except ErrorStatus as exception: diff --git a/orm/services/image_manager/ims/controllers/v1/orm/images/regions.py b/orm/services/image_manager/ims/controllers/v1/orm/images/regions.py index f90ca3d3..6a2baae0 100755 --- a/orm/services/image_manager/ims/controllers/v1/orm/images/regions.py +++ b/orm/services/image_manager/ims/controllers/v1/orm/images/regions.py @@ -90,22 +90,28 @@ class RegionController(rest.RestController): status_code=500, error_details=exception.message) - @wsexpose(None, str, str, rest_content_types='json', status_code=204) - def delete(self, image_id, region_name): + @wsexpose(None, str, str, str, rest_content_types='json', status_code=204) + def delete(self, image_id, region_name, force_delete='False'): + if force_delete == 'True': + force_delete = True + else: + force_delete = False image_logic, utils = di.resolver.unpack(RegionController) auth.authorize(request, "region:delete") try: - LOG.info("RegionController - delete region: " + str(region_name)) + requester = request.headers.get('X-RANGER-Requester') + is_rds_client_request = requester == 'rds_resource_service_proxy' + LOG.info("RegionController - Delete region:{0} by RDS Proxy: {1} ".format(region_name, is_rds_client_request)) + result = image_logic.delete_region(image_id, region_name, request.transaction_id, is_rds_client_request, + force_delete) + if is_rds_client_request: + LOG.info("RegionController - region deleted: " + str(result)) - result = image_logic.delete_region(image_id, region_name, request.transaction_id) - - LOG.info("RegionController - region deleted: " + str(result)) - - event_details = 'Image {} region {} deleted'.format(image_id, - region_name) - utils.audit_trail('delete region', request.transaction_id, - request.headers, image_id, - event_details=event_details) + event_details = 'Image {} region {} deleted'.format(image_id, + region_name) + utils.audit_trail('delete region', request.transaction_id, + request.headers, image_id, + event_details=event_details) except ErrorStatus as exception: # include NotFoundError LOG.log_exception("RegionController - Failed to delete region", exception) diff --git a/orm/services/image_manager/ims/etc/policy.json b/orm/services/image_manager/ims/etc/policy.json index 758bc02b..32fc700d 100755 --- a/orm/services/image_manager/ims/etc/policy.json +++ b/orm/services/image_manager/ims/etc/policy.json @@ -1,25 +1,27 @@ { - "default": "!", - "admin": "role:admin", - "admin_support": "role:admin_support", - "admin_viewer": "role:admin_viewer", - "orm": "user:m01687", + "default": "!", - "admin_or_support": "role:admin or role:admin_support", - "admin_or_support_or_viewer": "rule:admin or rule:admin_support or rule:admin_viewer", + "admin": "role:admin and tenant:admin or role:admin and tenant:services", + "admin_support": "role:admin_support and tenant:admin or role:admin_support and tenant:services", + "admin_viewer": "role:admin_viewer and tenant:admin or role:admin_viewer and tenant:services", - "image:create": "rule:admin_or_support", - "image:list": "rule:admin_or_support_or_viewer", - "image:get_one": "rule:admin_or_support_or_viewer", - "image:update": "rule:admin", - "image:delete": "rule:admin", - "region:delete": "rule:admin", - "region:create": "rule:admin_or_support", - "region:update": "rule:admin", - "image:enable": "rule:admin", - "tenant:create": "rule:admin_or_support", - "tenant:delete": "rule:admin", - "tenant:update": "rule:admin", + "admin_or_support": "rule:admin or rule:admin_support", + "admin_or_support_or_viewer": "rule:admin or rule:admin_support or rule:admin_viewer", - "metadata:create": "rule:orm" + "image:create": "rule:admin_or_support", + "image:list": "rule:admin_or_support_or_viewer", + "image:get_one": "rule:admin_or_support_or_viewer", + "image:update": "rule:admin", + "image:delete": "rule:admin", + "image:enable": "rule:admin", + + "region:create": "rule:admin_or_support", + "region:update": "rule:admin", + "region:delete": "rule:admin", + + "tenant:create": "rule:admin_or_support", + "tenant:update": "rule:admin", + "tenant:delete": "rule:admin", + + "metadata:create": "rule:admin_or_support" } \ No newline at end of file diff --git a/orm/services/image_manager/ims/logic/image_logic.py b/orm/services/image_manager/ims/logic/image_logic.py index 52677740..9af2202a 100755 --- a/orm/services/image_manager/ims/logic/image_logic.py +++ b/orm/services/image_manager/ims/logic/image_logic.py @@ -78,8 +78,6 @@ def update_image(image_wrapper, image_uuid, transaction_id, http_action="put"): new_image = image_wrapper.to_db_model() new_image.id = image_uuid - datamanager.begin_transaction() - image_rec = datamanager.get_record('image') sql_image = image_rec.get_image_by_id(image_uuid) @@ -88,6 +86,10 @@ def update_image(image_wrapper, image_uuid, transaction_id, http_action="put"): message="Image {0} does not exist for update".format( image_uuid)) + image_wrapper.validate_update(sql_image, new_image) + + datamanager.begin_transaction() + new_image.owner = sql_image.owner existing_regions = sql_image.get_existing_region_names() new_image.created_at = int(sql_image.created_at) @@ -126,7 +128,7 @@ def delete_image_by_uuid(image_uuid, transaction_id): sql_image = image_rec.get_image_by_id(image_uuid) if sql_image is None: - return + raise NotFoundError(message="Image '{}' not found".format(image_uuid)) image_existing_region_names = sql_image.get_existing_region_names() if len(image_existing_region_names) > 0: @@ -254,27 +256,39 @@ def replace_regions(image_uuid, regions, transaction_id): @di.dependsOn('data_manager') -def delete_region(image_uuid, region_name, transaction_id): +def delete_region(image_uuid, region_name, transaction_id, on_success_by_rds, + force_delete): DataManager = di.resolver.unpack(delete_region) datamanager = DataManager() try: image_rec = datamanager.get_record('image') sql_image = image_rec.get_image_by_id(image_uuid) + if on_success_by_rds and not sql_image: + return if not sql_image: raise ErrorStatus(404, 'image with id: {0} not found'.format( - image_uuid)) + image_uuid)) + # do not allow delete_region for protected images + if sql_image.protected: + protect_msg = "Protected image {} cannot be deleted. Please " \ + "update image with protected=false and try again" + raise ErrorStatus(400, protect_msg.format(image_uuid)) existing_region_names = sql_image.get_existing_region_names() - sql_image.remove_region(region_name) - datamanager.flush() # i want to get any exception created by + datamanager.flush() # Get any exception created by # previous actions against the database - send_to_rds_if_needed(sql_image, existing_region_names, "put", - transaction_id) - - datamanager.commit() + if on_success_by_rds: + datamanager.commit() + else: + send_to_rds_if_needed(sql_image, existing_region_names, "put", + transaction_id) + if force_delete: + datamanager.commit() + else: + datamanager.rollback() except ErrorStatus as exp: LOG.log_exception("ImageLogic - Failed to update image", exp) @@ -286,6 +300,9 @@ def delete_region(image_uuid, region_name, transaction_id): datamanager.rollback() raise + finally: + datamanager.close() + @di.dependsOn('data_manager') def add_customers(image_uuid, customers, transaction_id): @@ -399,7 +416,12 @@ def delete_customer(image_uuid, customer_id, transaction_id): @di.dependsOn('data_manager') @di.dependsOn('rds_proxy') -def get_image_by_uuid(image_uuid): +def get_image_by_uuid(image_uuid, query_by_id_or_name=False): + """This function includes an optional boolean parameter "query_by_id_or_name". + If query_by_id_or_name evaluates to true, IMS logic will fetch the image + record whose "image_uuid" parameter value matches either the image id or name value. + Otherwise it defaults to query by image ID value only. + """ DataManager, rds_proxy = di.resolver.unpack(get_image_by_uuid) datamanager = DataManager() @@ -407,10 +429,14 @@ def get_image_by_uuid(image_uuid): try: datamanager.begin_transaction() - image_rec = datamanager.get_record('image') - sql_image = image_rec.get_image_by_id(image_uuid) + # Only the get_image API will pass the optional parameter and set it to true + if query_by_id_or_name: + sql_image = image_rec.get_image(image_uuid) + else: + # all other image APIs will NOT pass the optional parameter + sql_image = image_rec.get_image_by_id(image_uuid) if not sql_image: raise NotFoundError(status_code=404, message="Image {0} not found ".format( @@ -428,15 +454,28 @@ def get_image_by_uuid(image_uuid): # Get the status from RDS image_status = rds_proxy.get_status(image_wrapper.image.id, False) - if image_status.status_code != 200: - return image_wrapper - image_status = image_status.json() - image_wrapper.image.status = image_status['status'] - # update status for all regions - for result_regions in image_wrapper.image.regions: - for status_region in image_status['regions']: - if result_regions.name == status_region['region']: - result_regions.status = status_region['status'] + if image_status.status_code == 404: + # image not on rds resource table - applicable to images created with no region assigned + image_wrapper.image.status = 'no regions' + + elif image_status.status_code == 200: + image_status = image_status.json() + if image_wrapper.image.regions: + image_wrapper.image.status = image_status['status'] + else: + image_wrapper.image.status = 'no regions' + + # update status for all regions + for result_regions in image_wrapper.image.regions: + for status_region in image_status['regions']: + if result_regions.name == status_region['region']: + result_regions.status = status_region['status'] + if status_region['error_msg']: + result_regions.set_error_message(status_region['error_msg']) + + # status codes not falling under 404 (not found) or 200 (success) + else: + raise ErrorStatus(500, "unsuccessful GET - failed to get status for this resource") except NotFoundError as exp: datamanager.rollback() @@ -452,8 +491,9 @@ def get_image_by_uuid(image_uuid): @di.dependsOn('data_manager') +@di.dependsOn('rds_proxy') def get_image_list_by_params(visibility, region, Customer): - DataManager = di.resolver.unpack(get_image_list_by_params) + DataManager, rds_proxy = di.resolver.unpack(get_image_list_by_params) datamanager = DataManager() try: @@ -463,10 +503,17 @@ def get_image_list_by_params(visibility, region, Customer): Customer=Customer) response = ImageSummaryResponse() - for sql_image in sql_images: - image = ImageSummary.from_db_model(sql_image) - response.images.append(image) + if sql_images: + uuids = ','.join(str("\'" + sql_image.id + "\'") + for sql_image in sql_images if sql_image and sql_image.id) + resource_status_dict = image_record.get_images_status_by_uuids(uuids) + for sql_image in sql_images: + image = ImageSummary.from_db_model(sql_image) + if sql_image.id: + status = resource_status_dict.get(sql_image.id) + image.status = not status and 'no regions' or status + response.images.append(image) return response except ErrorStatus as exp: @@ -518,7 +565,7 @@ def enable_image(image_uuid, int_enabled, transaction_id): try: image_rec = datamanager.get_record('image') - sql_image = image_rec.get_image(image_uuid) + sql_image = image_rec.get_image_by_id(image_uuid) if not sql_image: raise ErrorStatus(404, 'Image with id: {0} not found'.format( image_uuid)) diff --git a/orm/services/image_manager/ims/persistency/sql_alchemy/image/image_record.py b/orm/services/image_manager/ims/persistency/sql_alchemy/image/image_record.py index e1393be7..6d660e10 100755 --- a/orm/services/image_manager/ims/persistency/sql_alchemy/image/image_record.py +++ b/orm/services/image_manager/ims/persistency/sql_alchemy/image/image_record.py @@ -37,8 +37,9 @@ class ImageRecord(Record): raise def get_image(self, id): + """function to get image by name or id""" try: - query = self.session.query(Image).filter(Image.id == id) + query = self.session.query(Image).filter((Image.id == id) | (Image.name == id)) return query.first() except Exception as exception: message = "Failed to read_image: id: {0}".format(id) @@ -93,6 +94,16 @@ class ImageRecord(Record): LOG.log_exception(message, exception) raise + def get_images_status_by_uuids(self, uuid_str): + results = self.session.connection().execute("SELECT resource_id, status from rds_resource_status_view" + " WHERE resource_id in ({})".format(uuid_str)) + resource_status_dict = {} + if results: + resource_status_dict = dict((resource_id, status) for resource_id, status in results) + + results.close() + return resource_status_dict + def create_images_by_visibility_query(self, visibility): try: query = self.session.query(Image).filter(Image.visibility == visibility) diff --git a/orm/services/image_manager/ims/persistency/wsme/models.py b/orm/services/image_manager/ims/persistency/wsme/models.py index 728f9324..11c609eb 100755 --- a/orm/services/image_manager/ims/persistency/wsme/models.py +++ b/orm/services/image_manager/ims/persistency/wsme/models.py @@ -4,7 +4,7 @@ from orm.services.image_manager.ims.persistency.sql_alchemy import db_models from orm.services.image_manager.ims.persistency.wsme.base import Model from orm.common.orm_common.utils.cross_api_utils import (get_regions_of_group, set_utils_conf) -from pecan import conf, request +from pecan import conf import wsme @@ -52,6 +52,7 @@ class Region(Model): checksum = wsme.wsattr(wsme.types.text, mandatory=False) size = wsme.wsattr(wsme.types.text, mandatory=False) virtual_size = wsme.wsattr(wsme.types.text, mandatory=False) + error_message = wsme.wsattr(wsme.types.text, mandatory=False) def __init__(self, name="", type="single", status="", checksum='', size='', virtual_size=''): @@ -82,6 +83,9 @@ class Region(Model): return region_rec + def set_error_message(self, error_message): + self.error_message = error_message + class RegionWrapper(Model): # pragma: no cover """regions model @@ -133,9 +137,9 @@ class Image(Model): owner = wsme.wsattr(wsme.types.text, mandatory=False) schema = wsme.wsattr(wsme.types.text, mandatory=False) protected = wsme.wsattr(bool, mandatory=False, default=default_protected) + id = wsme.wsattr(wsme.types.text, mandatory=False, name='id') # Output-only fields - id = wsme.wsattr(wsme.types.text, mandatory=False) status = wsme.wsattr(wsme.types.text, mandatory=False) created_at = wsme.wsattr(wsme.types.IntegerType(minimum=0), mandatory=False, name='created-at') @@ -214,6 +218,13 @@ class Image(Model): self.links = links def validate_model(self, context=None): + + if self.name.strip() == '': + raise ErrorStatus(400, "Image name is required.") + + if self.url.strip() == '': + raise ErrorStatus(400, "Image location URL is required.") + # Validate visibility if self.visibility == 'public' and self.customers: raise ErrorStatus(400, @@ -223,6 +234,9 @@ class Image(Model): raise ErrorStatus(400, 'Visibility is private but no customers were' ' specified!') + elif self.visibility not in ["private", "public"]: + raise ErrorStatus(400, + "Image visibility can only be 'public' or 'private'") # Validate disk format valid_disk_formats = ('ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw', @@ -242,22 +256,9 @@ class Image(Model): if self.container_format not in valid_container_formats: raise ErrorStatus(400, 'Invalid container format! {}'.format(self.container_format)) - # Validate min-disk and min-ram (wsme automatically converts booleans - # to int, and isinstance(False, int) returns True, so that is how we - # validate the type) - if 'min-disk' in request.json['image'] and not type( - request.json['image']['min-disk']) == int: - raise ErrorStatus(400, 'min-disk must be an integer!') - if 'min-ram' in request.json['image'] and not type( - request.json['image']['min-ram']) == int: - raise ErrorStatus(400, 'min-ram must be an integer!') + if int(self.min_ram) not in range(0, self.min_ram + 1, 1024): + raise ErrorStatus(400, "mininum RAM value must be a multiple of 1024") - if self.min_disk != wsme.Unset and int(self.min_disk) > 2147483646 or int(self.min_disk) < 0: - raise ErrorStatus(400, - 'value must be positive less than 2147483646') - if self.min_ram != wsme.Unset and int(self.min_ram) > 2147483646 or int(self.min_ram) < 0: - raise ErrorStatus(400, - 'value must be positive less than 2147483646') if context == "update": for region in self.regions: if region.type == "group": @@ -406,6 +407,32 @@ class ImageWrapper(Model): def validate_model(self, context=None): return self.image.validate_model(context) + def validate_update(self, sql_image=None, new_image=None): + + if sql_image and new_image: + if sql_image.name != new_image.name: + raise ErrorStatus(400, "Cannot change name of existing image") + + if sql_image.container_format != new_image.container_format: + raise ErrorStatus(400, "Cannot change container format of " + "existing image") + + if sql_image.disk_format != new_image.disk_format: + raise ErrorStatus(400, + "Cannot change disk format of existing image") + + if sql_image.min_ram != new_image.min_ram: + raise ErrorStatus(400, + "Cannot change min_ram of existing image") + + if sql_image.min_disk != new_image.min_disk: + raise ErrorStatus(400, + "Cannot change min_disk of existing image") + + if sql_image.url != new_image.url: + raise ErrorStatus(400, "Cannot change source data URL of " + "existing image") + def handle_region_group(self): return self.image.handle_region_group() @@ -419,20 +446,26 @@ class ImageWrapper(Model): return image -# ImageSummary a DataObject contains all the fields defined in ImageSummary. +''' +' ImageSummary a DataObject contains all the fields defined in ImageSummary. +''' class ImageSummary(Model): name = wsme.wsattr(wsme.types.text) id = wsme.wsattr(wsme.types.text) visibility = wsme.wsattr(wsme.types.text) + status = wsme.wsattr(wsme.types.text, mandatory=True) + regions = wsme.wsattr([str], mandatory=True) - def __init__(self, name='', id='', visibility=''): + def __init__(self, name='', id='', visibility='', status='', regions=[]): Model.__init__(self) self.name = name self.id = id self.visibility = visibility + self.status = status + self.regions = regions @staticmethod def from_db_model(sql_image): @@ -440,6 +473,11 @@ class ImageSummary(Model): image.id = sql_image.id image.name = sql_image.name image.visibility = sql_image.visibility + image.regions = [] + for sql_region in sql_image.regions: + region = Region() + region.name = sql_region.region_name + image.regions.append(region.name) return image diff --git a/orm/services/region_manager/rms/controllers/lcp_controller.py b/orm/services/region_manager/rms/controllers/lcp_controller.py index bde767db..1e118c5f 100755 --- a/orm/services/region_manager/rms/controllers/lcp_controller.py +++ b/orm/services/region_manager/rms/controllers/lcp_controller.py @@ -109,7 +109,7 @@ def build_zone_response(zone): design_type=zone.design_type, location_type=zone.location_type, vLCP_name=zone.vlcp_name, - AIC_version=zone.ranger_agent_version, + ranger_agent_version=zone.ranger_agent_version, OS_version=zone.open_stack_version, keystone_EP=end_points_dict["identity"], horizon_EP=end_points_dict["dashboard"], diff --git a/orm/services/region_manager/rms/controllers/v2/orm/resources/groups.py b/orm/services/region_manager/rms/controllers/v2/orm/resources/groups.py index cc2e6f02..3e44c244 100755 --- a/orm/services/region_manager/rms/controllers/v2/orm/resources/groups.py +++ b/orm/services/region_manager/rms/controllers/v2/orm/resources/groups.py @@ -1,6 +1,5 @@ """rest module.""" import logging -import time import wsme from orm.common.orm_common.utils import api_error_utils as err_utils @@ -11,6 +10,7 @@ from orm.services.region_manager.rms.services import services as GroupService from orm.services.region_manager.rms.utils import authentication from pecan import request, rest + from wsme import types as wtypes from wsmeext.pecan import wsexpose @@ -24,8 +24,11 @@ class Groups(wtypes.DynamicBase): name = wsme.wsattr(wtypes.text, mandatory=True) description = wsme.wsattr(wtypes.text, mandatory=True) regions = wsme.wsattr([str], mandatory=True) + created = wsme.wsattr(wtypes.dt_types.__getitem__(0), mandatory=False, name="created") + modified = wsme.wsattr(wtypes.dt_types.__getitem__(0), mandatory=False, name="modified") - def __init__(self, id=None, name=None, description=None, regions=[]): + def __init__(self, id=None, name=None, description=None, regions=[], + created=None, modified=None): """init function. :param regions: @@ -35,6 +38,8 @@ class Groups(wtypes.DynamicBase): self.name = name self.description = description self.regions = regions + self.created = created + self.modified = modified def _to_python_obj(self): obj = PythonModel.Groups() @@ -42,6 +47,8 @@ class Groups(wtypes.DynamicBase): obj.name = self.name obj.description = self.description obj.regions = self.regions + obj.created = self.created + obj.modified = self.modified return obj @@ -63,20 +70,27 @@ class OutputResource(wtypes.DynamicBase): id = wsme.wsattr(wtypes.text, mandatory=True) name = wsme.wsattr(wtypes.text, mandatory=True) - created = wsme.wsattr(wtypes.text, mandatory=True) + description = wsme.wsattr(wtypes.text, mandatory=True) links = wsme.wsattr({str: str}, mandatory=True) + created = wsme.wsattr(wtypes.dt_types.__getitem__(0), mandatory=False, name="created") + modified = wsme.wsattr(wtypes.dt_types.__getitem__(0), mandatory=False, name="modified") - def __init__(self, id=None, name=None, created=None, links={}): + def __init__(self, id=None, name=None, description=None, links={}, + created=None, modified=None): """init function. :param id: :param created: :param links: + :param created + :param modified """ self.id = id self.name = name - self.created = created + self.description = description self.links = links + self.created = created + self.modified = modified class Result(wtypes.DynamicBase): @@ -159,19 +173,17 @@ class GroupsController(rest.RestController): try: # May raise an exception which will return status code 400 - GroupService.create_group_in_db(group_input.id, - group_input.name, - group_input.description, - group_input.regions) + GroupService.create_group_in_db(group_input) logger.debug("Group created successfully in DB") - + result = GroupService.get_groups_data(group_input.id) # Create the group output data with the correct timestamp and link group = OutputResource(group_input.id, group_input.name, - repr(int(time.time() * 1000)), + group_input.description, {'self': '{}/v2/orm/groups/{}'.format( request.application_url, - group_input.id)}) + group_input.id)}, + result.created, result.modified) event_details = 'Region group {} {} created with regions: {}'.format( group_input.id, group_input.name, group_input.regions) @@ -207,6 +219,13 @@ class GroupsController(rest.RestController): request.headers, group_id, event_details=event_details) + # issue NotFoundError for "delete group" when group_id not found + except error_base.NotFoundError as e: + logger.error("GroupsController - Group not found") + raise err_utils.get_error(request.transaction_id, + message="Cannot delete - " + e.message, + status_code=404) + except Exception as exp: logger.exception("fail to delete group :- {}".format(exp)) @@ -225,13 +244,14 @@ class GroupsController(rest.RestController): logger.debug("update group - id {}".format(group_id)) result = GroupService.update_group(group, group_id) logger.debug("group updated to :- {}".format(result)) - + result = GroupService.get_groups_data(group_id) # build result group_result = OutputResource(result.id, result.name, - repr(int(time.time() * 1000)), { + result.description, { 'self': '{}/v2/orm/groups/{}'.format( request.application_url, - result.id)}) + result.id)}, + result.created, result.modified) event_details = 'Region group {} {} updated with regions: {}'.format( group_id, group.name, group.regions) diff --git a/orm/services/region_manager/rms/controllers/v2/orm/resources/regions.py b/orm/services/region_manager/rms/controllers/v2/orm/resources/regions.py index cf127850..8bf35987 100755 --- a/orm/services/region_manager/rms/controllers/v2/orm/resources/regions.py +++ b/orm/services/region_manager/rms/controllers/v2/orm/resources/regions.py @@ -11,7 +11,7 @@ from orm.services.region_manager.rms.services import error_base from orm.services.region_manager.rms.services import services as RegionService from orm.services.region_manager.rms.utils import authentication -from pecan import request, rest +from pecan import conf, request, rest import wsme from wsme import types as wtypes from wsmeext.pecan import wsexpose @@ -30,7 +30,7 @@ class Address(wtypes.DynamicBase): def __init__(self, country=None, state=None, city=None, street=None, zip=None): - """Init function + """init function :param country: :param state: @@ -83,6 +83,7 @@ class RegionsData(wtypes.DynamicBase): status = wsme.wsattr(wtypes.text, mandatory=True) id = wsme.wsattr(wtypes.text, mandatory=True) name = wsme.wsattr(wtypes.text, mandatory=False) + description = wsme.wsattr(wtypes.text, mandatory=True) ranger_agent_version = wsme.wsattr(wtypes.text, mandatory=True, name="rangerAgentVersion") open_stack_version = wsme.wsattr(wtypes.text, mandatory=True, name="OSVersion") clli = wsme.wsattr(wtypes.text, mandatory=True, name="CLLI") @@ -92,16 +93,19 @@ class RegionsData(wtypes.DynamicBase): design_type = wsme.wsattr(wtypes.text, mandatory=True, name="designType") location_type = wsme.wsattr(wtypes.text, mandatory=True, name="locationType") vlcp_name = wsme.wsattr(wtypes.text, mandatory=True, name="vlcpName") + created = wsme.wsattr(wtypes.dt_types.__getitem__(0), mandatory=False, name="created") + modified = wsme.wsattr(wtypes.dt_types.__getitem__(0), mandatory=False, name="modified") - def __init__(self, status=None, id=None, name=None, clli=None, design_type=None, - location_type=None, vlcp_name=None, open_stack_version=None, - address=Address(), ranger_agent_version=None, metadata={}, - endpoint=[EndPoint()]): - """init function + def __init__(self, status=None, id=None, name=None, description=None, clli=None, + design_type=None, location_type=None, vlcp_name=None, + open_stack_version=None, address=Address(), ranger_agent_version=None, + metadata={}, endpoint=[EndPoint()], created=None, modified=None): + """init :param status: :param id: :param name: + :param description: :param clli: :param design_type: :param location_type: @@ -111,10 +115,13 @@ class RegionsData(wtypes.DynamicBase): :param ranger_agent_version: :param metadata: :param endpoint: + :param created + :param modified """ self.status = status self.id = id self.name = self.id + self.description = description self.clli = clli self.ranger_agent_version = ranger_agent_version self.metadata = metadata @@ -124,6 +131,8 @@ class RegionsData(wtypes.DynamicBase): self.vlcp_name = vlcp_name self.address = address self.open_stack_version = open_stack_version + self.created = created + self.modified = modified def _to_clean_python_obj(self): obj = PythonModel.RegionData() @@ -131,6 +140,7 @@ class RegionsData(wtypes.DynamicBase): obj.status = self.status obj.id = self.id obj.name = self.id + obj.description = self.description obj.ranger_agent_version = self.ranger_agent_version obj.clli = self.clli obj.metadata = self.metadata @@ -163,11 +173,53 @@ class RegionsController(rest.RestController): metadata = RegionMetadataController() status = RegionStatusController() + def has_no_resources(self, region_id): + """ function to check if any resource (flavor, customer, or image) is + assigned to the region_id + """ + _check_conf_initialization() + try: + resources = { + 'flavors': [conf.api.fms_server.base, + conf.api.fms_server.flavors], + 'customers': [conf.api.cms_server.base, + conf.api.cms_server.customers], + 'images': [conf.api.ims_server.base, + conf.api.ims_server.images] + } + + empty = True + + keystone_ep = authentication.get_keystone_ep( + request.headers['X-Auth-Region']) + + request.headers['Keystone-Endpoint'] = keystone_ep + + for resource in resources: + resource_get_url = '%s%s/?region=%s' % ( + resources[resource][0], + resources[resource][1], region_id) + resp = requests.get(resource_get_url, + headers=request.headers, + verify=conf.verify) + resp_dict = resp.json() + + if resp_dict[resource]: + return False + + return True + + except Exception as e: + raise err_utils.get_error(request.transaction_id, + status_code=401, + message=e.message) + @wsexpose(Regions, str, str, [str], str, str, str, str, str, str, str, - str, str, str, status_code=200, rest_content_types='json') + str, str, str, str, status_code=200, rest_content_types='json') def get_all(self, type=None, status=None, metadata=None, rangerAgentVersion=None, - clli=None, regionname=None, osversion=None, valet=None, - state=None, country=None, city=None, street=None, zip=None): + clli=None, regionname=None, osversion=None, location_type=None, + state=None, country=None, city=None, street=None, zip=None, + vlcp_name=None): """get regions. :param type: query field @@ -177,12 +229,13 @@ class RegionsController(rest.RestController): :param clli: query field :param regionname: query field :param osversion: query field - :param valet: query field + :param location_type: query field :param state: query field :param country: query field :param city: query field :param street: query field :param zip: query field + :param vlcp_name query field :return: json from db :exception: EntityNotFoundError 404 """ @@ -191,8 +244,9 @@ class RegionsController(rest.RestController): url_args = {'type': type, 'status': status, 'metadata': metadata, 'rangerAgentVersion': rangerAgentVersion, 'clli': clli, 'regionname': regionname, - 'osversion': osversion, 'valet': valet, 'state': state, - 'country': country, 'city': city, 'street': street, 'zip': zip} + 'osversion': osversion, 'location_type': location_type, 'state': state, + 'country': country, 'city': city, 'street': street, 'zip': zip, + 'vlcp_name': vlcp_name} logger.debug("Parameters: {}".format(str(url_args))) try: @@ -248,8 +302,10 @@ class RegionsController(rest.RestController): result = RegionService.create_full_region(full_region_input) logger.debug("API: region created : {}".format(result)) - event_details = 'Region {} {} created: AICversion {}, OSversion {}, CLLI {}'.format( - full_region_input.name, full_region_input.design_type, + event_details = 'Region {} {} created: rangerAgentVersion {}, OSversion {}, CLLI {}'.format( + full_region_input.name, + full_region_input.description, + full_region_input.design_type, full_region_input.ranger_agent_version, full_region_input.open_stack_version, full_region_input.clli) utils.audit_trail('create region', request.transaction_id, @@ -277,27 +333,44 @@ class RegionsController(rest.RestController): @wsexpose(None, str, rest_content_types='json', status_code=204) def delete(self, region_id): - logger.info("Delete Region") - authentication.authorize(request, 'region:delete') + utils.set_utils_conf(conf) + # currently ORM resource types are 'flavor', 'customer', and 'image' + proceed_to_delete = self.has_no_resources(region_id) + if proceed_to_delete: + logger.info("Delete Region") + authentication.authorize(request, 'region:delete') + try: - try: + logger.debug("delete region {}".format(region_id)) + result = RegionService.delete_region(region_id) + logger.debug("region deleted") - logger.debug("delete region {}".format(region_id)) - result = RegionService.delete_region(region_id) - logger.debug("region deleted") + event_details = 'Region {} deleted'.format(region_id) + utils.audit_trail('delete region', request.transaction_id, + request.headers, region_id, + event_details=event_details) - event_details = 'Region {} deleted'.format(region_id) - utils.audit_trail('delete region', request.transaction_id, - request.headers, region_id, - event_details=event_details) + # issue NotFoundError for "Delete Region" when group_id not found + # which is returned by RegionService.delete_region function + except error_base.NotFoundError as exp: + logger.error("RegionsController - Region not found") + raise err_utils.get_error(request.transaction_id, + message="Cannot delete - " + exp.message, + status_code=exp.status_code) + + except Exception as exp: + logger.exception( + "error in deleting region .. reason:- {}".format(exp)) + raise err_utils.get_error(request.transaction_id, + status_code=500, + message=exp.message) + return + else: + region_resources_exist_msg = "Region '{}' cannot be deleted as resources are assigned.".format(region_id) - except Exception as exp: - logger.exception( - "error in deleting region .. reason:- {}".format(exp)) raise err_utils.get_error(request.transaction_id, - status_code=500, - message=exp.message) - return + status_code=400, + message=region_resources_exist_msg) @wsexpose(RegionsData, str, body=RegionsData, status_code=201, rest_content_types='json') @@ -312,7 +385,7 @@ class RegionsController(rest.RestController): result = RegionService.update_region(region_id, region) logger.debug("API: region {} updated".format(region_id)) - event_details = 'Region {} {} modified: AICversion {}, OSversion {}, CLLI {}'.format( + event_details = 'Region {} {} modified: rangerAgentVersion {}, OSversion {}, CLLI {}'.format( region.name, region.design_type, region.ranger_agent_version, region.open_stack_version, region.clli) utils.audit_trail('update region', request.transaction_id, diff --git a/orm/services/region_manager/rms/etc/policy.json b/orm/services/region_manager/rms/etc/policy.json index 753964ee..d85afb93 100755 --- a/orm/services/region_manager/rms/etc/policy.json +++ b/orm/services/region_manager/rms/etc/policy.json @@ -1,24 +1,35 @@ { "default": "!", - "orm_admin": "role:admin and tenant:admin", + + "admin": "role:admin and tenant:admin or role:admin and tenant:services", + "admin_support": "role:admin_support and tenant:admin or role:admin_support and tenant:services", + "admin_viewer": "role:admin_viewer and tenant:admin or role:admin_viewer and tenant:services", + + "admin_or_support": "rule:admin or rule:admin_support", + "admin_or_support_or_viewer": "rule:admin or rule:admin_support or rule:admin_viewer", "lcp:get_one": "", "lcp:get_all": "", + "region:get_one": "", "region:get_all": "", - "region:create": "rule:orm_admin", - "region:update": "rule:orm_admin", - "region:delete": "rule:orm_admin", + "region:create": "rule:admin_or_support", + "region:update": "rule:admin", + "region:delete": "rule:admin", + "group:get_one": "", "group:get_all": "", - "group:create": "rule:orm_admin", - "group:update": "rule:orm_admin", - "group:delete": "rule:orm_admin", - "configuration:get": "rule:orm_admin", - "log:update": "rule:orm_admin", - "metadata:get": "rule:orm_admin", - "metadata:create": "rule:orm_admin", - "metadata:update": "rule:orm_admin", - "metadata:delete": "rule:orm_admin", - "status:put": "rule:orm_admin" + "group:create": "rule:admin_or_support", + "group:update": "rule:admin", + "group:delete": "rule:admin", + + "configuration:get": "rule:admin_or_support_or_viewer", + "log:update": "rule:admin", + + "metadata:get": "rule:admin_or_support_or_viewer", + "metadata:create": "rule:admin_or_support", + "metadata:update": "rule:admin", + "metadata:delete": "rule:admin", + + "status:put": "rule:admin" } \ No newline at end of file diff --git a/orm/services/region_manager/rms/model/model.py b/orm/services/region_manager/rms/model/model.py index a22495ee..fc20e355 100755 --- a/orm/services/region_manager/rms/model/model.py +++ b/orm/services/region_manager/rms/model/model.py @@ -9,7 +9,7 @@ class Address(object): def __init__(self, country=None, state=None, city=None, street=None, zip=None): - """init + """init function :param country: :param state: @@ -41,15 +41,18 @@ class EndPoint(object): class RegionData(object): """class method json header.""" - def __init__(self, status=None, id=None, name=None, clli=None, - ranger_agent_version=None, design_type=None, location_type=None, + def __init__(self, status=None, id=None, name=None, description=None, + clli=None, ranger_agent_version=None, design_type=None, + location_type=None, vlcp_name=None, open_stack_version=None, - address=Address(), metadata={}, endpoints=[EndPoint()]): - """init + address=Address(), metadata={}, endpoints=[EndPoint()], + created=None, modified=None): + """init function :param status: :param id: :param name: + :param description: :param clli: :param ranger_agent_version: :param design_type: @@ -59,11 +62,14 @@ class RegionData(object): :param address: :param metadata: :param endpoints: + :param created + :param modified """ self.status = status self.id = id # make id and name always the same self.name = self.id + self.description = description self.clli = clli self.ranger_agent_version = ranger_agent_version self.metadata = metadata @@ -73,6 +79,38 @@ class RegionData(object): self.vlcp_name = vlcp_name self.open_stack_version = open_stack_version self.address = address + self.created = created + self.modified = modified + + def _validate_fields(self): + """The following fields are mandatory for create/update json: + id, clli, design_type, ranger_agent_version, vlcp_name + + Also check that all input field values (except 'description', + "location_type", and address fields) do not contain a space. + + Validation for 'endpoints' and 'status' as mandatory fields + are handled by other methods. + """ + + mandatory_fields = ['id', 'clli', 'design_type', 'ranger_agent_version', + 'vlcp_name'] + check_fields_for_spaces = ['id', 'clli', 'design_type', 'ranger_agent_version', + 'open_stack_version', 'vlcp_name'] + + for field in check_fields_for_spaces: + value = getattr(self, field) + if field in mandatory_fields: + # if mandatory field, check if field is empty + if not value: + raise error_base.InputValueError( + message="'{}' field value is required.".format(field)) + + # check if field contains spaces, then issue error message + if ' ' in value: + raise error_base.InputValueError( + message="'{}' field value cannot contain " + "spaces.".format(field)) def _validate_end_points(self, endpoints_types_must_have): ep_duplicate = [] @@ -99,11 +137,22 @@ class RegionData(object): "one of {}".format(allowed_status)) return + def _validate_name(self): + if not self.name: + raise error_base.InputValueError( + message="Region ID/name is required") + if ' ' in self.name: + raise error_base.InputValueError( + message="Region ID/name must match and not contain spaces") + def _validate_model(self): allowed_status = conf.region_options.allowed_status_values[:] endpoints_types_must_have = conf.region_options.endpoints_types_must_have[:] + self._validate_status(allowed_status) self._validate_end_points(endpoints_types_must_have) + self._validate_name() + self._validate_fields() return def _to_db_model_dict(self): @@ -118,6 +167,7 @@ class RegionData(object): db_model_dict = {} db_model_dict['region_id'] = self.id db_model_dict['name'] = self.name + db_model_dict['description'] = self.description db_model_dict['address_state'] = self.address.state db_model_dict['address_country'] = self.address.country db_model_dict['address_city'] = self.address.city @@ -132,6 +182,7 @@ class RegionData(object): db_model_dict['clli'] = self.clli db_model_dict['end_point_list'] = end_points db_model_dict['meta_data_dict'] = self.metadata + return db_model_dict @@ -151,7 +202,8 @@ class Groups(object): """main json header.""" def __init__(self, id=None, name=None, - description=None, regions=[]): + description=None, regions=[], + created=None, modified=None): """init function. :param regions: @@ -161,6 +213,8 @@ class Groups(object): self.name = name self.description = description self.regions = regions + self.created = created + self.modified = modified def _to_db_model_dict(self): db_dict = {} @@ -169,12 +223,23 @@ class Groups(object): db_dict['group_regions'] = self.regions return db_dict + def _validate_model(self): + if not self.name or not self.id: + raise error_base.InputValueError( + message="Group ID/name is required") + if ' ' in self.name or ' ' in self.id: + raise error_base.InputValueError( + message="Group ID/name must not contain spaces") + if not self.description.rstrip(): + raise error_base.InputValueError( + message="Description is required") + class GroupsWrraper(object): """list of groups.""" def __init__(self, groups=None): - """init + """init function :param groups: """ diff --git a/orm/services/region_manager/rms/model/url_parm.py b/orm/services/region_manager/rms/model/url_parm.py index 70995796..5a5349bb 100755 --- a/orm/services/region_manager/rms/model/url_parm.py +++ b/orm/services/region_manager/rms/model/url_parm.py @@ -5,8 +5,9 @@ class UrlParms(object): """class method.""" def __init__(self, type=None, status=None, metadata=None, rangerAgentVersion=None, - clli=None, regionname=None, osversion=None, valet=None, - state=None, country=None, city=None, street=None, zip=None): + clli=None, regionname=None, osversion=None, location_type=None, + state=None, country=None, city=None, street=None, zip=None, + vlcp_name=None): """init method. :param type: @@ -16,15 +17,16 @@ class UrlParms(object): :param clli: :param regionname: :param osversion: - :param valet: + :param location_type: :param state: :param country: :param city: :param street: :param zip: + :param vlcp_name: """ if type: - self.location_type = type + self.design_type = type if status: self.region_status = status if metadata: @@ -37,8 +39,8 @@ class UrlParms(object): self.name = regionname if osversion: self.open_stack_version = osversion - if valet: - self.valet = valet + if location_type: + self.location_type = location_type if state: self.address_state = state if country: @@ -49,6 +51,8 @@ class UrlParms(object): self.address_street = street if zip: self.address_zip = zip + if vlcp_name: + self.vlcp_name = vlcp_name def _build_query(self): """nuild db query. diff --git a/orm/services/region_manager/rms/resources/regions.csv b/orm/services/region_manager/rms/resources/regions.csv index 208153c8..b180778f 100644 --- a/orm/services/region_manager/rms/resources/regions.csv +++ b/orm/services/region_manager/rms/resources/regions.csv @@ -1,2 +1 @@ region_id,region_name,address_state,address_country,address_city,address_street,address_zip,region_status,ranger_agent_version,open_stack_version,design_type,location_type,vlcp_name,clli,description,keystone_url,horizon_url,ord_url -LOCAL,LOCAL,NY,US,FIL,n/a,3333,functional,ranger_agent1.0,kilo,n/a,n/a,n/a,n/a,DPK lcp in FIL,http://127.0.0.1:5000/v2.0,http://horizon3.com,http://127.0.0.1:9010 diff --git a/orm/services/region_manager/rms/services/services.py b/orm/services/region_manager/rms/services/services.py index 14ed3187..99061bc8 100755 --- a/orm/services/region_manager/rms/services/services.py +++ b/orm/services/region_manager/rms/services/services.py @@ -79,8 +79,14 @@ def delete_region(region_id): LOG.debug("logic:- delete region {}".format(region_id)) try: db = data_manager_factory.get_data_manager() + # logic to allow 'delete_region' to issue NotFoundError when region_id is non-existent + region = db.get_region_by_id_or_name(region_id) + if not region: + raise error_base.NotFoundError(message="Region '{}' not found".format(region_id)) + db.delete_region(region_id) LOG.debug("region deleted") + except Exception as exp: LOG.exception("fail to delete region {}".format(exp)) raise @@ -206,8 +212,12 @@ def delete_group(group_id): """ LOG.debug("delete group logic") try: - db = data_manager_factory.get_data_manager() + # logic to allow 'delete_group' to issue NotFoundError when group_id is non-existent + groups = db.get_group(group_id) + if not groups: + raise error_base.NotFoundError(message="Group '{}' not found".format(group_id)) + LOG.debug("delete group id {} from db".format(group_id)) db.delete_group(group_id) @@ -217,7 +227,7 @@ def delete_group(group_id): return -def create_group_in_db(group_id, group_name, description, regions): +def create_group_in_db(group): """Create a region group in the database. :param group_id: The ID of the group to create @@ -227,16 +237,18 @@ def create_group_in_db(group_id, group_name, description, regions): :raise: GroupExistsError (status code 400) if the group already exists """ try: + group = group._to_python_obj() + group._validate_model() manager = data_manager_factory.get_data_manager() - manager.add_group(group_id, group_name, description, regions) + manager.add_group(group.id, group.name, + group.description, group.regions) except error_base.ConflictError: - LOG.exception("Group {} already exists".format(group_id)) + LOG.exception("Group {} already exists".format(group.id)) raise error_base.ConflictError( - message="Group {} already exists".format(group_id)) - except error_base.InputValueError: - LOG.exception("Some of the regions not found") - raise error_base.NotFoundError( - message="Some of the regions not found") + message="Group {} already exists".format(group.id)) + except error_base.InputValueError as e: + LOG.exception(e.message) + raise def update_group(group, group_id): diff --git a/orm/services/region_manager/rms/storage/my_sql/data_manager.py b/orm/services/region_manager/rms/storage/my_sql/data_manager.py index 491b66b7..6d71d2ea 100755 --- a/orm/services/region_manager/rms/storage/my_sql/data_manager.py +++ b/orm/services/region_manager/rms/storage/my_sql/data_manager.py @@ -1,3 +1,4 @@ +import datetime import logging from orm.services.region_manager.rms.model import model as PythonModels @@ -68,7 +69,8 @@ class DataManager(BaseDataManager): location_type=location_type, vlcp_name=vlcp_name, clli=clli, - description=description) + description=description, + created=datetime.datetime.now()) if end_point_list is not None: for end_point in end_point_list: @@ -174,6 +176,8 @@ class DataManager(BaseDataManager): def delete_region(self, region_id): # delete a region from `region` table and also the region's # entries from `region_meta_data` and `region_end_points` tables + # as well as the "group_region" table + session = self._engine_facade.get_session() with session.begin(): session.query(Region).filter_by(region_id=region_id).delete() @@ -396,7 +400,8 @@ class DataManager(BaseDataManager): with session.begin(): session.add(Group(group_id=group_id, name=group_name, - description=group_description)) + description=group_description, + created=datetime.datetime.now())) session.flush() # add the groupe if not rollback @@ -408,7 +413,8 @@ class DataManager(BaseDataManager): session.add_all(group_regions) except oslo_db.exception.DBReferenceError as e: logger.error("Reference error: {}".format(str(e))) - raise error_base.InputValueError("Reference error") + raise error_base.InputValueError( + message="One or more regions not found") except oslo_db.exception.DBDuplicateEntry as e: logger.error("Duplicate entry: {}".format(str(e))) raise error_base.ConflictError("Duplicate entry error") @@ -429,6 +435,8 @@ class DataManager(BaseDataManager): group_model.id = a_group.group_id group_model.name = a_group.name group_model.description = a_group.description + group_model.created = a_group.created + group_model.modified = a_group.modified regions = [] group_regions = session.query(GroupRegion).\ filter_by(group_id=a_group.group_id) @@ -484,7 +492,9 @@ class DataManager(BaseDataManager): if a_group is not None: group_model = {"id": a_group.group_id, "name": a_group.name, - "description": a_group.description} + "description": a_group.description, + "created": a_group.created, + "modified": a_group.modified} regions = [] group_regions = session.query(GroupRegion). \ filter_by(group_id=a_group.group_id) diff --git a/orm/services/region_manager/rms/storage/my_sql/data_models.py b/orm/services/region_manager/rms/storage/my_sql/data_models.py index 6573bc35..2fc61733 100755 --- a/orm/services/region_manager/rms/storage/my_sql/data_models.py +++ b/orm/services/region_manager/rms/storage/my_sql/data_models.py @@ -1,4 +1,7 @@ # coding: utf-8 +import datetime + +from sqlalchemy import Column, DateTime, ForeignKey, Integer, String from orm.services.region_manager.rms.model.model import Address, EndPoint, RegionData from sqlalchemy import Column, ForeignKey, Integer, String @@ -28,7 +31,9 @@ class Region(Base): vlcp_name = Column(String(64), nullable=False) clli = Column(String(64), nullable=False) description = Column(String(255), nullable=False) - + created = Column(DateTime(timezone=False), + default=datetime.datetime.now()) + modified = Column(DateTime(timezone=False)) end_points = relationship(u'RegionEndPoint') meta_data = relationship(u'RegionMetaData') @@ -56,6 +61,7 @@ class Region(Base): id = self.region_id name = self.name + description = self.description status = self.region_status clli = self.clli ranger_agent_version = self.ranger_agent_version @@ -63,13 +69,17 @@ class Region(Base): location_type = self.location_type vlcp_name = self.vlcp_name open_stack_version = self.open_stack_version + created = self.created + modified = self.modified address = self.address_to_wsme() - return RegionData(status, id, name, clli, ranger_agent_version, + return RegionData(status, id, name, description, clli, ranger_agent_version, design_type, location_type, vlcp_name, open_stack_version, address, metadata=wsme_meta_data, - endpoints=wsme_end_points) + endpoints=wsme_end_points, + created=created, + modified=modified) class Group(Base): @@ -79,12 +89,17 @@ class Group(Base): group_id = Column(String(64), nullable=False, unique=True) name = Column(String(64), nullable=False, unique=True) description = Column(String(255), nullable=False) + created = Column(DateTime(timezone=False), + default=datetime.datetime.now()) + modified = Column(DateTime(timezone=False)) def __json__(self): return dict( group_id=self.group_id, name=self.name, - description=self.description + description=self.description, + created=self.created, + modified=self.modified ) def to_wsme(self): diff --git a/orm/services/region_manager/rms/utils/authentication.py b/orm/services/region_manager/rms/utils/authentication.py index e72b857e..3aa5f216 100755 --- a/orm/services/region_manager/rms/utils/authentication.py +++ b/orm/services/region_manager/rms/utils/authentication.py @@ -9,7 +9,7 @@ from pecan import conf logger = logging.getLogger(__name__) -def _get_keystone_ep(auth_region): +def get_keystone_ep(auth_region): result = RegionService.get_region_by_id_or_name(auth_region) for ep in result.endpoints: if ep.type == 'identity': @@ -25,7 +25,7 @@ def authorize(request, action): auth_region = request.headers.get('X-Auth-Region') try: - keystone_ep = _get_keystone_ep(auth_region) + keystone_ep = get_keystone_ep(auth_region) except Exception: # Failed to find Keystone EP - we'll set it to None instead of failing # because the rule might be to let everyone pass diff --git a/orm/services/resource_distributor/rds/app.py b/orm/services/resource_distributor/rds/app.py index 3294ac6c..845762a9 100755 --- a/orm/services/resource_distributor/rds/app.py +++ b/orm/services/resource_distributor/rds/app.py @@ -1,5 +1,4 @@ import logging -import os from orm.common.client.audit.audit_client.api import audit from pecan import conf, make_app @@ -63,11 +62,8 @@ def validate_sot(): def main(): - dir_name = os.path.dirname(__file__) - drive, path_and_file = os.path.splitdrive(dir_name) - path, filename = os.path.split(path_and_file) runner = CommandRunner() - runner.run(['serve', path + '/config.py']) + runner.run(['serve', '../config.py']) if __name__ == "__main__": main() diff --git a/orm/services/resource_distributor/rds/controllers/v1/status/resource_status.py b/orm/services/resource_distributor/rds/controllers/v1/status/resource_status.py index 6a527da4..37586017 100755 --- a/orm/services/resource_distributor/rds/controllers/v1/status/resource_status.py +++ b/orm/services/resource_distributor/rds/controllers/v1/status/resource_status.py @@ -4,11 +4,12 @@ import time from orm.services.resource_distributor.rds.controllers.v1.base import InputValueError from orm.services.resource_distributor.rds.controllers.v1.status import get_resource -from orm.services.resource_distributor.rds.services.base import ErrorMesage, InputError +from orm.services.resource_distributor.rds.services.base import ErrorMessage, InputError from orm.services.resource_distributor.rds.services import region_resource_id_status as regionResourceIdStatus from orm.services.resource_distributor.rds.utils import utils from pecan import rest + import wsme from wsme import types as wtypes from wsmeext.pecan import wsexpose @@ -144,9 +145,11 @@ class Status(rest.RestController): logger.debug("save data to database.. data :- %s" % data_to_save) try: regionResourceIdStatus.add_status(data_to_save) + # invoke regin data to delete on sucess + utils.invoke_delete_region(data_to_save) # send data to ims utils.post_data_to_image(data_to_save) - except ErrorMesage as exp: + except ErrorMessage as exp: logger.error(exp.message) # raise ClientSideError(status_code=400, error=exp.message) except InputError as e: diff --git a/orm/services/resource_distributor/rds/proxies/ims_proxy.py b/orm/services/resource_distributor/rds/proxies/ims_proxy.py index 4397a556..510d8d23 100755 --- a/orm/services/resource_distributor/rds/proxies/ims_proxy.py +++ b/orm/services/resource_distributor/rds/proxies/ims_proxy.py @@ -2,7 +2,7 @@ import json import logging import requests -from orm.services.resource_distributor.rds.services.base import ErrorMesage +from orm.services.resource_distributor.rds.services.base import ErrorMessage from orm.services.resource_distributor.rds.utils import authentication as AuthService from pecan import conf @@ -51,10 +51,10 @@ def send_image_metadata(meta_data, region, resource_id, action='post'): except requests.ConnectionError as exp: logger.error(exp) logger.exception(exp) - raise ErrorMesage("fail to connect to server {}".format(exp.message)) + raise ErrorMessage("fail to connect to server {}".format(exp.message)) if response.status_code != 200: - raise ErrorMesage( + raise ErrorMessage( "Got error from orm.services.resource_distributor.rds server, code: {0} message: {1}".format( response.status_code, response.content)) return diff --git a/orm/services/resource_distributor/rds/proxies/rds_resource_service_proxy.py b/orm/services/resource_distributor/rds/proxies/rds_resource_service_proxy.py new file mode 100755 index 00000000..c4f44f94 --- /dev/null +++ b/orm/services/resource_distributor/rds/proxies/rds_resource_service_proxy.py @@ -0,0 +1,100 @@ +import json +import logging +from pecan import conf +import requests + +from orm.services.resource_distributor.rds.services.base import ErrorMessage +from orm.services.resource_distributor.rds.utils import authentication as AuthService + + +logger = logging.getLogger(__name__) + + +headers = {'content-type': 'application/json'} + + +def _set_headers(region): + try: + token_id = AuthService.get_token(region) + if token_id: + headers['X-Auth-Token'] = token_id + headers['X-Auth-Region'] = region + except Exception: + logger.error("no token") + headers['X-RANGER-Requester'] = 'rds_resource_service_proxy' + + +def invoke_resources_region_delete(resource_type, region, resource_id): + logger.debug( + "REGION STATUS PROXY - send delete status to {} service for region {}".format(resource_type, region)) + + _set_headers(region) + + try: + if resource_type == "customer": + logger.debug("sending the data to {} server delete method ".format(resource_type)) + response = requests.delete( + conf.cms.base_url + (conf.cms.delete_region).format(resource_id, region), + headers=headers, verify=conf.verify) + elif resource_type == "flavor": + logger.debug("sending the data to {} server delete method ".format(resource_type)) + response = requests.delete( + conf.fms.base_url + (conf.fms.delete_region).format(resource_id, region), + headers=headers, verify=conf.verify) + elif resource_type == "image": + logger.debug("sending the data to {} server delete method ".format(resource_type)) + response = requests.delete( + conf.ims.base_url + (conf.ims.delete_region).format(resource_id, region), + headers=headers, verify=conf.verify) + else: + response = None + + logger.debug("got response {} from send delete status to {} service.". + format(response, resource_type)) + except requests.ConnectionError as exp: + logger.error(exp) + logger.exception(exp) + raise ErrorMessage("fail to connect to server {}".format(exp.message)) + + if response.status_code != 200: + raise ErrorMessage( + "Got error from rds server, code: {0} message: {1}".format( + response.status_code, response.content)) + return + + +def send_image_metadata(meta_data, region, resource_id, action='post'): + logger.debug( + "IMS PROXY - send metadata to ims {} for region {}".format(meta_data, + region)) + data_to_send = { + "metadata": { + "checksum": meta_data['checksum'], + "virtual_size": meta_data['virtual_size'], + "size": meta_data['size'] + } + } + + _set_headers(region) + data_to_send_as_json = json.dumps(data_to_send) + logger.debug("sending the data to ims server post method ") + logger.debug("ims server {0} path = {1}".format(conf.ims.base_url, + conf.ims.metadata_path).format( + resource_id, region)) + + if action == 'post': + try: + response = requests.post( + conf.ims.base_url + (conf.ims.metadata_path).format(resource_id, region), + data=data_to_send_as_json, headers=headers, verify=conf.verify) + logger.debug("got response from ims {}".format(response)) + except requests.ConnectionError as exp: + logger.error(exp) + logger.exception(exp) + raise ErrorMessage("fail to connect to server {}".format(exp.message)) + + if response.status_code != 200: + raise ErrorMessage( + "Got error from rds server, code: {0} message: {1}".format( + response.status_code, response.content)) + return diff --git a/orm/services/resource_distributor/rds/proxies/rms_proxy.py b/orm/services/resource_distributor/rds/proxies/rms_proxy.py index 5b9839fc..f087cbe0 100755 --- a/orm/services/resource_distributor/rds/proxies/rms_proxy.py +++ b/orm/services/resource_distributor/rds/proxies/rms_proxy.py @@ -1,29 +1,25 @@ """python module.""" import logging - -import requests - from pecan import conf +import requests logger = logging.getLogger(__name__) -headers = {'content-type': 'application/json'} - - -def get_regions(): - logger.debug("get list of regions from rms") - logger.debug("rms server {0} path = {1}".format(conf.rms.base_url, - conf.rms.all_regions_path)) - - response = requests.get(conf.rms.base_url + conf.rms.all_regions_path, - headers=headers, verify=conf.verify) - - if response.status_code != 200: - log_message = "not able to get regions {}".format(response) - log_message = log_message.replace('\n', '_').replace('\r', '_') - logger.error(log_message) - return - - return response.json() +def get_rms_region(region_name): + """ function to call rms api for region info + returns 200 for ok and None for error + """ + try: + headers = { + 'content-type': 'application/json', + } + rms_server_url = '%s%s/%s' % ( + conf.rms.base_url, conf.rms.all_regions_path, region_name) + resp = requests.get(rms_server_url, headers=headers, + verify=conf.verify).json() + return resp + except Exception as e: + logger.log_exception('Failed in get_rms_region', e) + return None diff --git a/orm/services/resource_distributor/rds/services/base.py b/orm/services/resource_distributor/rds/services/base.py index 056efd3a..6d5000b2 100644 --- a/orm/services/resource_distributor/rds/services/base.py +++ b/orm/services/resource_distributor/rds/services/base.py @@ -9,7 +9,7 @@ class InputError(Error): self.value = value -class ErrorMesage(Error): +class ErrorMessage(Error): def __init__(self, message=None): self.message = message diff --git a/orm/services/resource_distributor/rds/services/resource.py b/orm/services/resource_distributor/rds/services/resource.py index b866f1e2..c5d88a49 100755 --- a/orm/services/resource_distributor/rds/services/resource.py +++ b/orm/services/resource_distributor/rds/services/resource.py @@ -5,11 +5,12 @@ import time from orm.services.resource_distributor.rds.services import region_resource_id_status as regionResourceIdStatus from orm.services.resource_distributor.rds.services import (yaml_customer_builder, yaml_flavor_bulder, yaml_image_builder) -from orm.services.resource_distributor.rds.services.base import ConflictValue, ErrorMesage +from orm.services.resource_distributor.rds.services.base import ConflictValue, ErrorMessage from orm.services.resource_distributor.rds.services.model.resource_input import ResourceData as InputData from orm.services.resource_distributor.rds.sot import sot_factory from orm.services.resource_distributor.rds.utils import utils, uuid_utils + from pecan import conf, request my_logger = logging.getLogger(__name__) @@ -34,13 +35,13 @@ def _get_inputs_from_resource_type(jsondata, model=jsondata, external_transaction_id=external_transaction_id) else: - raise ErrorMesage("no support for resource %s" % resource_type) + raise ErrorMessage("no support for resource %s" % resource_type) return input_data def _region_valid(region): - if ('rms_status' in region - and region['rms_status'] not in conf.allow_region_statuses): + if 'rms_status' in region and region[ + 'rms_status'] not in conf.allow_region_statuses: return False return True @@ -51,6 +52,8 @@ def _create_or_update_resource_status(input_data, target, error_msg='', if not _region_valid(target): status = 'Error' error_msg = "Not sent to ord as status equal to " + target['rms_status'] + raise ErrorMessage("Not sent to ord as status equal to %s" + % target['rms_status']) my_logger.debug("save status as %s" % status) data_to_save = dict( @@ -137,9 +140,8 @@ def _check_resource_status(input_data): def update_sot(input_data): """create resource.""" - my_logger.debug( - "build yaml file for %s id: %s" % (input_data.resource_type, - input_data.resource_id)) + my_logger.debug("build yaml file for %s id: %s" % (input_data.resource_type, + input_data.resource_id)) targetslist = _create_data_to_sot(input_data) my_logger.debug("upload yaml to SoT") _upload_to_sot(input_data.resource_id, @@ -168,7 +170,7 @@ def main(jsondata, external_transaction_id, resource_type, operation): update_sot(input_data) except ConflictValue: raise - except ErrorMesage as exp: + except ErrorMessage as exp: my_logger.error(exp.message) my_logger.exception(exp) raise @@ -176,5 +178,5 @@ def main(jsondata, external_transaction_id, resource_type, operation): my_logger.exception(e) _set_all_statuses_to_error(input_data) my_logger.error("deleting fails ,Error : {}".format(str(e.message))) - raise ErrorMesage(str(e.message)) + raise ErrorMessage(str(e.message)) return input_data.resource_id diff --git a/orm/services/resource_distributor/rds/services/yaml_customer_builder.py b/orm/services/resource_distributor/rds/services/yaml_customer_builder.py index 35b23812..c273f3c6 100755 --- a/orm/services/resource_distributor/rds/services/yaml_customer_builder.py +++ b/orm/services/resource_distributor/rds/services/yaml_customer_builder.py @@ -1,7 +1,6 @@ """yaml build build yaml from json input.""" import logging import re - import yaml from pecan import conf @@ -10,26 +9,21 @@ logger = logging.getLogger(__name__) def get_users_quotas(data, region): - """get default or own region. + """get users and quotas from region - get users and quotas from default or actual region :param data: :param region: :return: """ - users = region['users'] - quotas = region['quotas'] - if not users: - users = data['default_region']['users'] - if not quotas: - quotas = data['default_region']['quotas'] + users = region['users'] if region['users'] else data['default_region']['users'] + quotas = region['quotas'] if region['quotas'] else data['default_region']['quotas'] return users, quotas -def creat_final_yaml(title, description, resources, outputs): +def create_final_yaml(title, description, resources, outputs): """put all yaml strings together. - :param title: the version of yaml + :param title: ther version of yaml :param description: file description :param resources: body of the yaml file :param outputs: the output of the yaml @@ -61,6 +55,12 @@ def _create_metadata_yaml(alldata): return metadata +def _metadata_to_tags(metadata): + + return '[' + ','.join( + str(k) + '=' + str(v) for i in metadata for k, v in i.iteritems()) + ']' + + def yamlbuilder(alldata, region): logger.info("building customer yaml") logger.debug("start building flavor yaml for region %s" % region['name']) @@ -79,18 +79,29 @@ def yamlbuilder(alldata, region): description = {'description': 'yaml file for region - %s' % region['name']} jsondata = alldata project_name = jsondata['name'] - project_description = jsondata['description'] + # enclose project_description in double quotes to prevent yaml parsing issues + # when special characters are encountered + project_description = '"%s"' % (jsondata['description']) # TODO(amar): remove these lines when using objects instead of string json status = {"0": False, "1": True}[str(jsondata['enabled'])] outputs['outputs'] = {} resources['resources'] = {} - resources['resources']["%s" % alldata['uuid']] =\ - {'type': 'OS::Keystone::Project2\n', - 'properties': {'name': "%s" % project_name, - 'project_id': alldata['uuid'], - 'description': project_description, - 'enabled': status}} - # create the output + + if region['rangerAgentVersion'] >= 4.0: + resources['resources']["%s" % alldata['uuid']] =\ + {'type': 'OS::Keystone::Project\n', + 'properties': {'name': "%s" % project_name, + 'description': project_description, + 'tags': _metadata_to_tags(alldata['metadata']), + 'enabled': status}} + else: + resources['resources']["%s" % alldata['uuid']] =\ + {'type': 'OS::Keystone::Project2\n', + 'properties': {'name': "%s" % project_name, + 'project_id': alldata['uuid'], + 'description': project_description, + 'enabled': status}} + # create the output outputs['outputs']["%s_id" % alldata['uuid']] =\ {"value": {"get_resource": "%s" % alldata['uuid']}} @@ -104,8 +115,11 @@ def yamlbuilder(alldata, region): {"role": role_format % role, 'project': "{'get_resource': '%s'}" % alldata['uuid']} ) + # create the output for roles + # outputs['outputs']["%s_id" % role] =\ + # {"value": {"get_resource": "%s" % role}} - # no support for group when type is ldap + # no support for group when type is ldap if yaml_type != 'ldap': # create one group for user # not real group its only from heat to be able to delete the user @@ -143,27 +157,65 @@ def yamlbuilder(alldata, region): "network": ["neutron_quota", "OS::Neutron::Quota\n"], "storage": ["cinder_quota", "OS::Cinder::Quota\n"]} - # create quotas if quotas - if conf.yaml_configs.customer_yaml.yaml_options.quotas: - quotas_keys = dict(conf.yaml_configs.customer_yaml.yaml_keys.quotas_keys) - for items in quotas: - for item in items: + adjust_quota_resource = CMSAdjustResource(region['rangerAgentVersion']) + adjust_quota_resource.fix_quota_resource_item(alldata['uuid'], quotas, resources, options) - # these lines added to check if got excpected keys if not they will be replaced - for ite in items[item].keys()[:]: - if ite in quotas_keys: - items[item][quotas_keys[ite]] = items[item][ite] - del items[item][ite] + if region['rangerAgentVersion'] < 4.0: + metadata = _create_metadata_yaml(alldata) + resources['resources'].update(metadata) - # adding tenant to each quota - items[item]['tenant'] = \ - "{'get_resource': %s}" % alldata['uuid'] - resources['resources'][options[item][0]] = \ - {"type": options[item][1], "properties": items[item]} - metadata = _create_metadata_yaml(alldata) - resources['resources'].update(metadata) # putting all parts together for full yaml - yamldata = creat_final_yaml(title, description, resources, outputs) + yamldata = create_final_yaml(title, description, resources, outputs) logger.debug( "done building customer yaml for region %s " % region['name']) return yamldata + + +class CMSAdjustResource(object): + def __init__(self, aicVerion): + if aicVerion >= conf.yaml_configs.customer_yaml.cms_template_version.resource_v2.aic_version: + self.adjust_quota_parameters = CMSAdjustResourceV2().adjust_quota_parameters + else: + self.adjust_quota_parameters = CMSAdjustResourceV1().adjust_quota_parameters + + def fix_quota_resource_item(self, uuid, quotas, resources, options): + if conf.yaml_configs.customer_yaml.yaml_options.quotas: + quotas_keys = dict(conf.yaml_configs.customer_yaml.yaml_keys.quotas_keys) + for items in quotas: + for item in items: + + # these lines added to check if got excpected keys if not they will be replaced + for ite in items[item].keys()[:]: + if ite in quotas_keys: + items[item][quotas_keys[ite]] = items[item][ite] + del items[item][ite] + + self.adjust_quota_parameters(ite, items[item]) + + # adding tenant to each quota + items[item]['tenant'] = \ + "{'get_resource': %s}" % uuid + resources['resources'][options[item][0]] = \ + {"type": options[item][1], "properties": items[item]} + + +class CMSAdjustResourceV1(object): + + def __init__(self): + self.unsupported_params = conf.yaml_configs.customer_yaml.cms_template_version.resource_v1.quota_unsupported_params + + def adjust_quota_parameters(self, key, item): + if key in self.unsupported_params: + del item[key] + logger.warning("Region does not support Quota Parameter {}." + " removed from resource".format(key)) + + +class CMSAdjustResourceV2(object): + + def __init__(self): + self.supported_new_params = conf.yaml_configs.customer_yaml.cms_template_version.resource_v1.quota_unsupported_params + + def adjust_quota_parameters(self, key, item): + if key in self.supported_new_params: + logger.debug("New quota Parameter {} is added to quota resource".format(key)) diff --git a/orm/services/resource_distributor/rds/services/yaml_image_builder.py b/orm/services/resource_distributor/rds/services/yaml_image_builder.py index cf75106c..4888252c 100755 --- a/orm/services/resource_distributor/rds/services/yaml_image_builder.py +++ b/orm/services/resource_distributor/rds/services/yaml_image_builder.py @@ -1,9 +1,8 @@ import logging -import re - -import yaml - from pecan import conf +import re +import uuid +import yaml my_logger = logging.getLogger(__name__) @@ -22,18 +21,23 @@ def _properties(alldata, region): public = True if alldata['visibility'] == "public" else False protected = {0: False, 1: True}[alldata['protected']] tenants = [tenant['customer_id'] for tenant in alldata['customers']] - return dict( + properties = dict( name=alldata['name'], container_format=alldata["container_format"], min_ram=alldata['min_ram'], disk_format=alldata['disk_format'], min_disk=alldata['min_disk'], + id=str(uuid.UUID(alldata['id'])), protected=protected, copy_from=alldata["url"], owner=alldata["owner"], is_public=public, tenants=str(tenants) ) + if alldata['properties']: + properties['extra_properties'] = alldata['properties'] + + return properties def _glanceimage(alldata, region): diff --git a/orm/services/resource_distributor/rds/sot/sot_utils.py b/orm/services/resource_distributor/rds/sot/sot_utils.py index 760aeeea..12978d79 100644 --- a/orm/services/resource_distributor/rds/sot/sot_utils.py +++ b/orm/services/resource_distributor/rds/sot/sot_utils.py @@ -2,8 +2,8 @@ import yaml def merge_yamls(document, section): - document_dict = yaml.load(document) - section_dict = yaml.load(section) + document_dict = yaml.safe_load(document) + section_dict = yaml.safe_load(section) merge_dict(section_dict, document_dict) new_document = yaml.dump(document_dict) return new_document diff --git a/orm/services/resource_distributor/rds/utils/authentication.py b/orm/services/resource_distributor/rds/utils/authentication.py index 6a3ab5f8..02ee3698 100755 --- a/orm/services/resource_distributor/rds/utils/authentication.py +++ b/orm/services/resource_distributor/rds/utils/authentication.py @@ -29,36 +29,32 @@ def _get_token_conf(): return conf -def get_keystone_ep_region_name(): - # get any region that hase keystone end point - logger.debug("get list of regions from rms") - regions = RmsService.get_regions() - if not regions: - logger.error("failto get regions from rms") - return None, None - logger.debug("got {} regions".format(len(regions))) +def get_keystone_ep_region_name(region): + # get end point of a region + region_data = RmsService.get_rms_region(region) + if not region_data: + logger.error("fail to get region from rms") + return None + logger.debug("got rms region {} for region name {} ".format( + region, region_data)) keystone_ep = None - region_name = None - for region in regions['regions']: - for endpoint in region['endpoints']: - if endpoint['type'] == 'identity': - keystone_ep = endpoint['publicURL'] - break - if keystone_ep: - region_name = region['name'] + for endpoint in region_data['endpoints']: + if endpoint['type'] == 'identity': + keystone_ep = endpoint['publicURL'] break + logger.debug("Got keystone_ep {} for region name {}".format(keystone_ep, - region_name)) - return region_name, keystone_ep + region)) + return keystone_ep -def get_token(): +def get_token(region): logger.debug("create token") if not _is_authorization_enabled(): return - region, keystone_ep = get_keystone_ep_region_name() + keystone_ep = get_keystone_ep_region_name(region) if not region or not keystone_ep: log_message = "fail to create token reason -- fail to get region-- " \ "region:{} keystone {}".format(region, keystone_ep) @@ -85,7 +81,7 @@ def get_token(): if respone.status_code != 200: logger.error("fail to get token from url") logger.debug("got token for region {}".format(region)) - return region, respone.json()['access']['token']['id'] + return respone.json()['access']['token']['id'] except Exception as exp: logger.error(exp) diff --git a/orm/services/resource_distributor/rds/utils/utils.py b/orm/services/resource_distributor/rds/utils/utils.py index 929d0207..99b849fa 100755 --- a/orm/services/resource_distributor/rds/utils/utils.py +++ b/orm/services/resource_distributor/rds/utils/utils.py @@ -1,9 +1,10 @@ """module""" import logging +import re import requests from orm.services.resource_distributor.rds.proxies import ims_proxy -from orm.services.resource_distributor.rds.services.base import ErrorMesage +from orm.services.resource_distributor.rds.services.base import ErrorMessage from pecan import conf @@ -11,7 +12,7 @@ logger = logging.getLogger(__name__) def post_data_to_image(data): - if data['resource_type'] == "image" and 'resource_extra_metadata' in data: + if data['resource_type'] == "image" and data['resource_operation'] != 'delete' and 'resource_extra_metadata' in data: logger.debug("send metadata {} to ims :- {} for region {}".format( data['resource_extra_metadata'], data['resource_id'], data['region'])) @@ -22,6 +23,15 @@ def post_data_to_image(data): return +def invoke_delete_region(data): + if data['resource_operation'] == 'delete' and (data['status'] == 'Success' or data['error_code'] == 'ORD_012'): + ims_proxy.invoke_resources_region_delete( + resource_type=data['resource_type'], + resource_id=data['resource_id'], region=data['region']) + + return + + def _get_all_rms_regions(): # rms url discover_url = '%s:%d' % (conf.ordupdate.discovery_url, @@ -34,39 +44,44 @@ def _get_all_rms_regions(): # fail to get regions error = "got bad response from rms {}".format(response) logger.error(error) - raise ErrorMesage(message="got bad response from rms ") + raise ErrorMessage(message="got bad response from rms ") return response.json() -def _validate_version(region, resource_type): - version = None - if 'ranger_agent' in region['version'].lower(): - version = region['version'].lower().split('ranger-agent')[1].strip().split('.') +def _validate_version(region, supported_resource_version): + version = region['version'] and re.findall(r'[\d+\.\d]+', region['version']) + supported_resource_min_version = float(supported_resource_version[0]) if supported_resource_version else 0 + if version: + version = version[0].strip().split('.') version = version[0] + '.' + ''.join(version[1:]) - if not version or float(version) < 3: - return False - return True + if not version or float(version) < supported_resource_min_version: + return None + return float(version) def add_rms_status_to_regions(resource_regions, resource_type): rms_regions = {} all_regions = _get_all_rms_regions() + supported_versions = conf.region_resource_id_status.allowed_aic_resource_version + + supported_resource_version = [value for key, value in supported_versions if key == resource_type] # iterate through rms regions and gett regions status and version for region in all_regions['regions']: rms_regions[region['name']] = {'status': region['status'], - 'version': region['rangerAgentVersion']} + 'version': region['aicVersion']} # iterate through resource regions and add to them rms status for region in resource_regions: if region['name'] in rms_regions: # check if version valid - if not _validate_version(rms_regions[region['name']], - resource_type): - raise ErrorMesage( - message="ranger_agent version for region {} must be >=1.0 ".format( - region['name'])) + region['aicVersion'] = _validate_version(rms_regions[region['name']], + supported_resource_version) + if not region['aicVersion']: + raise ErrorMessage( + message="aic version for region {} must be >={} ".format( + region['name'], supported_resource_version[0] if supported_resource_version else '0')) region['rms_status'] = rms_regions[region['name']]['status'] continue diff --git a/orm/tests/unit/cms/test_customer.py b/orm/tests/unit/cms/test_customer.py index cd2ddb30..b5ed27c3 100755 --- a/orm/tests/unit/cms/test_customer.py +++ b/orm/tests/unit/cms/test_customer.py @@ -23,7 +23,7 @@ class TestCustomerController(FunctionalTest): root.utils = mock.MagicMock() root.utils.make_transid.return_value = 'some_trans_id' root.utils.audit_trail.return_value = None - root.utils.make_uuid.return_value = 'some_uuid' + root.utils.create_or_validate_uuid.return_value = 'some_uuid' root.err_utils = mock.MagicMock() @@ -40,7 +40,7 @@ class TestCustomerController(FunctionalTest): # assert assert response.status_int == 201 assert root.utils.audit_trail.called - assert root.utils.make_uuid.called + assert root.utils.create_or_validate_uuid.called assert customer_logic_mock.create_customer.called def test_create_customer_fail(self): @@ -76,18 +76,18 @@ class TestCustomerController(FunctionalTest): self.assertEqual(response.status_int, 409) def test_create_flavor_duplicate_uuid(self): - CUSTOMER_JSON['custId'] = 'test' - create_existing_uuid = root.utils.create_existing_uuid + CUSTOMER_JSON['uuid'] = 'test' + create_or_validate_uuid = root.utils.create_or_validate_uuid - root.utils.create_existing_uuid = mock.MagicMock(side_effect=TypeError('test')) + root.utils.create_or_validate_uuid = mock.MagicMock(side_effect=TypeError('test')) root.err_utils.get_error = mock.MagicMock(return_value=ClientSideError("blabla", 409)) response = self.app.post_json('/v1/orm/customers', CUSTOMER_JSON, expect_errors=True) - root.utils.create_existing_uuid = create_existing_uuid - del CUSTOMER_JSON['custId'] + root.utils.ccreate_or_validate_uuid = create_or_validate_uuid + del CUSTOMER_JSON['uuid'] self.assertEqual(response.status_int, 409) @@ -444,8 +444,9 @@ RET_CUSTOMER_JSON = { server_groups='1', server_group_members='1')], "storage": [Models.Storage(gigabytes='1', snapshots='1', volumes='1')], "network": [Models.Network(floating_ips='1', networks='1', ports='1', routers='1', subnets='1', - security_groups='1', security_group_rules='1', health_monitor='1', - member='1', pool='1', nat_instance='1', route_table='1', vip='1')] + security_groups='1', security_group_rules='1', health_monitors='1', + members='1', pools='1', nat_instance='1', route_table='1', vips='1', + loadbalancer='1', listener='1')] })]})], "users": [Models.User(** {"id": "userId1", "role": ["admin", "other"]}) @@ -457,8 +458,9 @@ RET_CUSTOMER_JSON = { server_groups='1', server_group_members='1')], "storage": [Models.Storage(gigabytes='1', snapshots='1', volumes='1')], "network": [Models.Network(floating_ips='1', networks='1', ports='1', routers='1', subnets='1', - security_groups='1', security_group_rules='1', health_monitor='1', - member='1', pool='1', nat_instance='1', route_table='1', vip='1')] + security_groups='1', security_group_rules='1', health_monitors='1', + members='1', pools='1', nat_instance='1', route_table='1', vips='1', + loadbalancer='1', listener='1')] })] } diff --git a/orm/tests/unit/cms/test_customer_logic.py b/orm/tests/unit/cms/test_customer_logic.py index c479489e..593f4e93 100755 --- a/orm/tests/unit/cms/test_customer_logic.py +++ b/orm/tests/unit/cms/test_customer_logic.py @@ -69,6 +69,7 @@ class TestCustomerLogic(FunctionalTest): def test_create_customer_success_with_regions(self): customer.regions = [models.Region(name="a")] + customer.name = 'Cust Name' logic = customer_logic.CustomerLogic() logic.create_customer(customer, 'some_uuid', 'some_trans_id') @@ -86,6 +87,7 @@ class TestCustomerLogic(FunctionalTest): res = customer_logic.RdsProxy.send_customer.call_args_list def test_create_customer_add_all_default_users(self): + customer.name = 'Cust Name' logic = customer_logic.CustomerLogic() logic.create_customer(customer, 'some_uuid', 'some_trans_id') @@ -95,11 +97,24 @@ class TestCustomerLogic(FunctionalTest): global mock_returns_error mock_returns_error = True + customer.name = 'Cust Name' logic = customer_logic.CustomerLogic() self.assertRaises(SystemError, logic.create_customer, customer, 'some_uuid', 'some_trans_id') + def test_create_customer_with_blank_name(self): + global mock_returns_error + mock_returns_error = True + + customer.name = '' + logic = customer_logic.CustomerLogic() + + self.assertRaises(customer_logic.ErrorStatus, + logic.create_customer, + customer, 'some_uuid', 'some_trans_id') + def test_update_customer_success(self): + customer.name = 'Cust Name' logic = customer_logic.CustomerLogic() logic.update_customer(customer, 'some_uuid', 'some_trans_id') @@ -158,6 +173,7 @@ class TestCustomerLogic(FunctionalTest): default_region = models.Region() customer.regions = [default_region] + customer.name = 'Cust Name' default_user = models.User() default_user.role = ['user', 'admin'] @@ -183,7 +199,7 @@ class TestCustomerLogic(FunctionalTest): assert data_manager_mock.add_role.call_count == 2 assert data_manager_mock.commit.called - def test_delete_users_succes(self): + def test_delete_users_success(self): logic = customer_logic.CustomerLogic() logic.delete_users('customer_id', 'region_id', 'user_id', 'transaction_is') @@ -195,7 +211,7 @@ class TestCustomerLogic(FunctionalTest): global rowcount rowcount = 0 logic = customer_logic.CustomerLogic() - with self.assertRaises(customer_logic.NotFound): + with self.assertRaises(customer_logic.ErrorStatus): logic.delete_users('customer_id', 'region_id', 'user_id', 'transaction_is') rowcount = 1 @@ -273,7 +289,7 @@ class TestCustomerLogic(FunctionalTest): self.assertRaises(SystemError, logic.replace_default_users, 'id', users, 'trans_id') assert data_manager_mock.rollback.called - def test_delete_default_users_succes(self): + def test_delete_default_users_success(self): logic = customer_logic.CustomerLogic() logic.delete_default_users('customer_id', 'user_id', 'transaction_is') @@ -338,13 +354,19 @@ class TestCustomerLogic(FunctionalTest): self.assertRaises(SystemError, logic.replace_regions, 'customer_uuid', regions, 'transaction_id') assert data_manager_mock.rollback.called - def test_delete_regions_succes(self): + def test_delete_regions_success(self): logic = customer_logic.CustomerLogic() - logic.delete_region('customer_id', 'region_id', 'transaction_is') + logic.delete_region('customer_id', 'region_id', 'transaction_is', True, False) + + assert record_mock.delete_region_for_customer.called + assert data_manager_mock.commit.called + + def test_delete_regions_success_force_delete(self): + logic = customer_logic.CustomerLogic() + logic.delete_region('customer_id', 'region_id', 'transaction_is', True, True) assert record_mock.delete_region_for_customer.called assert data_manager_mock.commit.called - assert customer_logic.RdsProxy.send_customer_dict.called def test_delete_regions_error(self): global mock_returns_error @@ -352,7 +374,8 @@ class TestCustomerLogic(FunctionalTest): logic = customer_logic.CustomerLogic() - self.assertRaises(SystemError, logic.delete_region, 'customer_id', 'region_id', 'transaction_is') + self.assertRaises(SystemError, logic.delete_region, 'customer_id', + 'region_id', 'transaction_is', True, False) assert data_manager_mock.rollback.called def test_get_customer_list_by_criteria(self): @@ -369,10 +392,15 @@ class TestCustomerLogic(FunctionalTest): status_code=404) logic.delete_customer_by_uuid('customer_id') + def test_delete_customer_by_uuid_not_found(self): global flow_type # Change the flow to "customer not found in CMS DB" flow_type = 1 - logic.delete_customer_by_uuid('customer_id') + logic = customer_logic.CustomerLogic() + + # test that ErrorStatus exception is raised when no customer found + with self.assertRaises(customer_logic.ErrorStatus): + logic.delete_customer_by_uuid('customer_id') def test_delete_customer_by_uuid_errors(self): global mock_returns_error @@ -431,7 +459,7 @@ class TestCustomerLogic(FunctionalTest): customer_logic.requests.get = mock.MagicMock(return_value=get_mock) logic.get_customer('customer_id') - self.assertTrue(data_manager_mock.get_cusomer_by_uuid_or_name.called) + self.assertTrue(data_manager_mock.get_customer_by_uuid_or_name.called) def test_get_customer_not_found(self): global flow_type @@ -519,13 +547,13 @@ def get_mock_datamanager(): data_manager_mock.update_customer = _update_customer data_manager_mock.add_region = _add_region data_manager_mock.add_user.return_value = sql_models.CmsUser() - data_manager_mock.get_cusomer_by_uuid_or_name.return_value = _get_customer() + data_manager_mock.get_customer_by_uuid_or_name.return_value = _get_customer() record_mock.delete_region_for_customer.return_value = None record_mock.delete_customer_by_uuid.return_value = None if flow_type == 1: record_mock.read_customer_by_uuid.return_value = None - data_manager_mock.get_cusomer_by_uuid_or_name.return_value = None + data_manager_mock.get_customer_by_uuid_or_name.return_value = None elif flow_type == 2: q = mock.MagicMock() q.get_real_customer_regions.return_value = [mock.MagicMock()] @@ -546,7 +574,7 @@ def get_mock_datamanager(): data_manager_mock.add_user.return_value = sql_models.CmsUser() data_manager_mock.add_role.return_value = sql_models.CmsRole() - data_manager_mock.get_cusomer_by_id.return_value = sql_customer + data_manager_mock.get_customer_by_id.return_value = sql_customer return data_manager_mock diff --git a/orm/tests/unit/cms/test_rds_proxy.py b/orm/tests/unit/cms/test_rds_proxy.py index 235e3212..4c100a5e 100755 --- a/orm/tests/unit/cms/test_rds_proxy.py +++ b/orm/tests/unit/cms/test_rds_proxy.py @@ -21,10 +21,10 @@ class TestUtil(FunctionalTest): FunctionalTest.setUp(self) self.rp = rds_proxy.RdsProxy() + @log_capture('orm.services.customer_manager.cms_rest.rds_proxy') @mock.patch.object(rds_proxy, 'request') @mock.patch('requests.post') - @log_capture('orm.services.customer_manager.cms_rest.rds_proxy') - def test_send_good(self, mock_post, mock_request, l): + def testsend_good(self, mock_post, mock_request, l): resp = Response(200, 'my content') mock_post.return_value = resp # send_res = self.rp.send_customer(models.Customer(), "1234", "POST") @@ -32,9 +32,9 @@ class TestUtil(FunctionalTest): # self.assertRegexpMatches(l.records[-1].getMessage(), 'Response Content from rds server') # self.assertEqual(send_res, 'my content') + @log_capture('orm.services.customer_manager.cms_rest.rds_proxy') @mock.patch.object(rds_proxy, 'request') @mock.patch('requests.post') - @log_capture('orm.services.customer_manager.cms_rest.rds_proxy') def test_bad_status(self, mock_post, mock_request, l): resp = Response(400, 'my content') mock_post.return_value = resp @@ -42,9 +42,9 @@ class TestUtil(FunctionalTest): # self.assertRegexpMatches(l.records[-3].getMessage(), 'Wrapper JSON before sending action') # self.assertRegexpMatches(l.records[-1].getMessage(), 'Response Content from rds server') + @log_capture('orm.services.customer_manager.cms_rest.rds_proxy') @mock.patch.object(rds_proxy, 'request') @mock.patch('requests.post') - @log_capture('orm.services.customer_manager.cms_rest.rds_proxy') def test_no_content(self, mock_post, mock_request, l): resp = Response(200, None) mock_post.return_value = resp diff --git a/orm/tests/unit/cms/test_regions.py b/orm/tests/unit/cms/test_regions.py index c205b5b0..1507a071 100755 --- a/orm/tests/unit/cms/test_regions.py +++ b/orm/tests/unit/cms/test_regions.py @@ -1,5 +1,6 @@ import mock import requests + from wsme.exc import ClientSideError from orm.services.customer_manager.cms_rest.controllers.v1.orm.customer import regions @@ -122,10 +123,11 @@ class TestRegionController(FunctionalTest): # assert self.assertEqual(response.status_int, 404) - def test_delete_regions(self): + @mock.patch.object(regions, 'request') + def test_delete_regions(self, request): # given requests.delete = mock.MagicMock(return_value=ResponseMock(200)) - + request.headers = {'X-RANGER-Requester': "rds_resource_service_proxy"} # when response = self.app.delete('/v1/orm/customers/{customer id}/regions/{region_id}') @@ -149,12 +151,13 @@ class TestRegionController(FunctionalTest): # assert self.assertEqual(response.status_int, 500) - def test_delete_regions_fail(self): + @mock.patch.object(regions, 'request') + def test_delete_regions_fail(self, request): # given requests.delete = mock.MagicMock() regions.CustomerLogic.return_error = 2 - + request.headers = {'X-RANGER-Requester': "rds_resource_service_proxy"} regions.err_utils.get_error = mock.MagicMock(return_value=ClientSideError("blabla", 404)) diff --git a/orm/tests/unit/common/test_checks.py b/orm/tests/unit/common/test_checks.py index a3d617a3..6928e7e6 100755 --- a/orm/tests/unit/common/test_checks.py +++ b/orm/tests/unit/common/test_checks.py @@ -2,7 +2,6 @@ import unittest import mock from orm.common.orm_common.policy import _checks -from wsme.exc import ClientSideError class TestChecks(unittest.TestCase): @@ -61,11 +60,15 @@ class TestChecks(unittest.TestCase): def test_call_custom_checks_error(self): check = _checks.RoleCheck('a', 'admin') - try: - check(1, mock.MagicMock(), 3) - self.fail('ClientSideError not raised!') - except ClientSideError as exc: - self.assertEqual(exc.code, 403) + # test no longer valid. + # change: https://gerrit.mtn5.cci.att.com/#/c/25690/ + # removed the exception raise + # + # try: + # check(1, mock.MagicMock(), 3) + # self.fail('ClientSideError not raised!') + # except ClientSideError as exc: + # self.assertEqual(exc.code, 403) for check_type in (_checks.TenantCheck, _checks.DomainCheck): diff --git a/orm/tests/unit/common/test_security_headers_hook.py b/orm/tests/unit/common/test_security_headers_hook.py index bfabe453..d5eacf0b 100755 --- a/orm/tests/unit/common/test_security_headers_hook.py +++ b/orm/tests/unit/common/test_security_headers_hook.py @@ -1,7 +1,6 @@ -from unittest import TestCase - import mock from orm.common.orm_common.hooks import security_headers_hook +from unittest import TestCase class MyHeaders(object): diff --git a/orm/tests/unit/common/test_tokens.py b/orm/tests/unit/common/test_tokens.py index 17b0bfa4..bc3700d5 100755 --- a/orm/tests/unit/common/test_tokens.py +++ b/orm/tests/unit/common/test_tokens.py @@ -205,8 +205,10 @@ class TokensTest(unittest.TestCase): conf = tokens.TokenConf(*('3',) * 5) self.assertIsNone(tokens.get_token_user('a', conf, 'c', 'd')) + @mock.patch.object(tokens, 'request') @mock.patch.object(tokens, '_get_keystone_client') - def test_get_token_user_success(self, mock_get_keystone_client): + def test_get_token_user_success(self, mock_get_keystone_client, + mock_request): token_info = mock.MagicMock() token_info.token = 'a' token_info.user = 'test_user' diff --git a/orm/tests/unit/common/test_transaction_id_hook.py b/orm/tests/unit/common/test_transaction_id_hook.py index d326c2df..4a65b13d 100755 --- a/orm/tests/unit/common/test_transaction_id_hook.py +++ b/orm/tests/unit/common/test_transaction_id_hook.py @@ -1,18 +1,17 @@ -import logging -from unittest import TestCase - -import mock -from orm.common.orm_common.hooks import transaction_id_hook - -logger = logging.getLogger(__name__) - - -class TestTransactionIdHook(TestCase): - @mock.patch.object(transaction_id_hook.utils, 'make_transid', - return_value='test') - def test_before_sanity(self, mock_make_transid): - t = transaction_id_hook.TransactionIdHook() - state = mock.MagicMock() - t.before(state) - self.assertEqual(state.request.transaction_id, 'test') - self.assertEqual(state.request.tracking_id, 'test') +import logging +import mock +from orm.common.orm_common.hooks import transaction_id_hook +from unittest import TestCase + +logger = logging.getLogger(__name__) + + +class TestTransactionIdHook(TestCase): + @mock.patch.object(transaction_id_hook.utils, 'make_transid', + return_value='test') + def test_before_sanity(self, mock_make_transid): + t = transaction_id_hook.TransactionIdHook() + state = mock.MagicMock() + t.before(state) + self.assertEqual(state.request.transaction_id, 'test') + self.assertEqual(state.request.tracking_id, 'test') diff --git a/orm/tests/unit/common/test_utils.py b/orm/tests/unit/common/test_utils.py index 74c3c5cb..930a116f 100755 --- a/orm/tests/unit/common/test_utils.py +++ b/orm/tests/unit/common/test_utils.py @@ -1,10 +1,9 @@ import logging -import pprint -from unittest import TestCase - import mock from orm.common.orm_common.utils import utils +import pprint from testfixtures import log_capture +from unittest import TestCase class TestUtil(TestCase): @@ -21,16 +20,17 @@ class TestUtil(TestCase): @mock.patch('requests.post') def test_make_uuid(self, mock_post): mock_post.return_value = self.respond({'uuid': '987654321'}, 200) - uuid = utils.make_uuid() + uuid = utils.create_or_validate_uuid('', 'uuidtype') self.assertEqual(uuid, '987654321') - @mock.patch('requests.post') @log_capture('orm.common.orm_common.utils.utils', level=logging.INFO) - def test_make_uuid_offline(self, mock_post, l): + @mock.patch('requests.post') + def test_make_uuid_offline(self, mock_post, log): mock_post.side_effect = Exception('boom') - uuid = utils.make_uuid() - # self.assertEqual(uuid, None) - l.check(('orm.common.orm_common.utils.utils', 'INFO', 'Failed in make_uuid:boom')) + uuid = utils.create_or_validate_uuid('', 'uuidtype') + self.assertEqual(uuid, None) + log.check(('orm.common.orm_common.utils.utils', + 'INFO', 'Failed in make_uuid:boom')) @mock.patch('requests.post') def test_make_transid(self, mock_post): @@ -39,13 +39,13 @@ class TestUtil(TestCase): self.assertEqual(uuid, '987654321') @mock.patch('requests.post') - @log_capture('orm.common.orm_common.utils.utils', level=logging.INFO) + @log_capture('orm_common.utils.utils', level=logging.INFO) def test_make_transid_offline(self, mock_post, l): mock_post.side_effect = Exception('boom') uuid = utils.make_transid() self.assertEqual(uuid, None) - l.check( - ('orm.common.orm_common.utils.utils', 'INFO', 'Failed in make_transid:boom')) + l.check(('orm_common.utils.utils', + 'INFO', 'Failed in make_transid:boom')) @mock.patch('orm.common.client.audit.audit_client.api.audit.init') @mock.patch('orm.common.client.audit.audit_client.api.audit.audit') @@ -65,8 +65,7 @@ class TestUtil(TestCase): @mock.patch('orm.common.client.audit.audit_client.api.audit.audit') def test_audit_service_args_least(self, mock_audit, mock_init): resp = utils.audit_trail('create customer', '1234', - {'X-RANGER-Client': 'Fred'}, '5678', - event_details='CMS') + {'X-RANGER-Client': 'Fred'}, '5678') self.assertEqual(mock_audit.call_args[0][1], 'Fred') # application_id self.assertEqual(mock_audit.call_args[0][2], '1234') # tracking_id self.assertEqual(mock_audit.call_args[0][3], '1234') # transaction_id @@ -76,7 +75,7 @@ class TestUtil(TestCase): # self.assertEqual(mock_audit.call_args[0][6], 'cms') # service self.assertEqual(mock_audit.call_args[0][7], '') # user_id self.assertEqual(mock_audit.call_args[0][8], 'NA') # external_id - self.assertEqual(mock_audit.call_args[0][9], 'CMS') # event_details + self.assertEqual(mock_audit.call_args[0][9], '') # event_details # self.assertEqual(mock_audit.call_args[0][10], 'Saved to DB') # status @mock.patch('orm.common.client.audit.audit_client.api.audit.init') @@ -84,8 +83,7 @@ class TestUtil(TestCase): def test_audit_service_with_tracking(self, mock_audit, mock_init): utils.audit_trail('create customer', '1234', {'X-RANGER-Client': 'Fred', - 'X-RANGER-Tracking-Id': 'Track12'}, '5678', - event_details='CMS') + 'X-RANGER-Tracking-Id': 'Track12'}, '5678') self.assertEqual(mock_audit.call_args[0][1], 'Fred') # application_id self.assertEqual(mock_audit.call_args[0][2], 'Track12') # tracking_id self.assertEqual(mock_audit.call_args[0][3], '1234') # transaction_id @@ -95,7 +93,7 @@ class TestUtil(TestCase): # self.assertEqual(mock_audit.call_args[0][6], 'cms') # service self.assertEqual(mock_audit.call_args[0][7], '') # user_id self.assertEqual(mock_audit.call_args[0][8], 'NA') # external_id - self.assertEqual(mock_audit.call_args[0][9], 'CMS') # event_details + self.assertEqual(mock_audit.call_args[0][9], '') # event_details # self.assertEqual(mock_audit.call_args[0][10], 'Saved to DB') # status @mock.patch('orm.common.client.audit.audit_client.api.audit.init') @@ -103,8 +101,7 @@ class TestUtil(TestCase): def test_audit_service_with_requester(self, mock_audit, mock_init): resp = utils.audit_trail('create customer', '1234', {'X-RANGER-Client': 'Fred', - 'X-RANGER-Requester': 'Req04'}, '5678', - event_details='CMS') + 'X-RANGER-Requester': 'Req04'}, '5678') self.assertEqual(mock_audit.call_args[0][1], 'Fred') # application_id self.assertEqual(mock_audit.call_args[0][2], '1234') # tracking_id self.assertEqual(mock_audit.call_args[0][3], '1234') # transaction_id @@ -113,7 +110,7 @@ class TestUtil(TestCase): # self.assertEqual(mock_audit.call_args[0][6], 'cms') # service self.assertEqual(mock_audit.call_args[0][7], 'Req04') # user_id self.assertEqual(mock_audit.call_args[0][8], 'NA') # external_id - self.assertEqual(mock_audit.call_args[0][9], 'CMS') # event_details + self.assertEqual(mock_audit.call_args[0][9], '') # event_details # self.assertEqual(mock_audit.call_args[0][10], 'Saved to DB') # status def test_set_utils_conf(self): @@ -127,22 +124,26 @@ class TestUtil(TestCase): @mock.patch('requests.post') def test_create_existing_uuid(self, mock_post): uuid = '987654321' - mock_post.return_value = self.respond({'uuid': uuid}, 200) - returned_uuid = utils.create_existing_uuid(uuid) + uuid_type = 'testtype' + mock_post.return_value = self.respond( + {'uuid': uuid, 'uuid_type': uuid_type}, 200) + returned_uuid = utils.create_or_validate_uuid(uuid, uuid_type) self.assertEqual(returned_uuid, uuid) @mock.patch('requests.post') def test_create_existing_uuid_with_exception(self, mock_post): mock_post.side_effect = Exception('boom') uuid = '987654321' - returned_uuid = utils.create_existing_uuid(uuid) + uuid_type = 'testtype' + returned_uuid = utils.create_or_validate_uuid(uuid, uuid_type) self.assertEqual(returned_uuid, None) @mock.patch('requests.post') def test_create_existing_uuid_with_400(self, mock_post): uuid = '987654321' - mock_post.return_value = self.respond({'uuid': uuid}, 400) - self.assertRaises(TypeError, utils.create_existing_uuid, uuid) + uuid_type = 'testId' + mock_post.return_value = self.respond({'uuid': uuid, 'uuid_type': uuid_type}, 409) + self.assertRaises(TypeError, utils.create_or_validate_uuid(uuid, uuid_type)) @mock.patch('pecan.conf') def test_report_config(self, mock_conf): diff --git a/orm/tests/unit/fms/config.py b/orm/tests/unit/fms/config.py index 3e2dd665..c933184b 100755 --- a/orm/tests/unit/fms/config.py +++ b/orm/tests/unit/fms/config.py @@ -54,11 +54,27 @@ logging = { database = { 'host': 'localhost', 'username': 'root', - 'password': 'root', + 'password': 'xxxxxxxxxxx', 'db_name': 'orm_fms_db', } +# valid_flavor_options +flavor_options = { + 'valid_cpin_opt_values': [ + 'c2', 'c4' + ], + 'valid_stor_opt_values': [ + 's1', 's2' + ], + 'valid_vnf_opt_values': [ + 'v1', 'v2', 'v3', 'v4', 'v5', 'v6', 'v7' + ], + 'valid_numa_values': ['n0'], + 'valid_nd_vnf_values': ['v8'], + 'valid_ss_vnf_values': ['v3'] +} + # this table is for calculating default extra specs needed extra_spec_needed_table = { "ns": { @@ -67,6 +83,7 @@ extra_spec_needed_table = { }, "nd": { "aggregate_instance_extra_specs____nd": "true", + "aggregate_instance_extra_specs____v8": "true", "hw____mem_page_size": "large" }, "nv": { @@ -75,11 +92,12 @@ extra_spec_needed_table = { }, "gv": { "aggregate_instance_extra_specs____gv": "true", - "aggregate_instance_extra_specs____c2": "true", - "hw____numa_nodes": "2" + "aggregate_instance_extra_specs____c2": "true" }, "ss": { - "aggregate_instance_extra_specs____ss": "true" + "aggregate_instance_extra_specs____ss": "true", + "aggregate_instance_extra_specs____s1": "true", + "aggregate_instance_extra_specs____v3": "true" } } @@ -89,11 +107,13 @@ default_extra_spec_calculated_table = { "aggregate_instance_extra_specs____nd": "", "aggregate_instance_extra_specs____nv": "", "aggregate_instance_extra_specs____gv": "", - "aggregate_instance_extra_specs____c2": "", "aggregate_instance_extra_specs____ss": "", "aggregate_instance_extra_specs____c2": "", "aggregate_instance_extra_specs____c4": "", "aggregate_instance_extra_specs____v": "", + "aggregate_instance_extra_specs____s1": "", + "aggregate_instance_extra_specs____v3": "", + "aggregate_instance_extra_specs____v8": "", "hw____mem_page_size": "", "hw____cpu_policy": "", "hw____numa_nodes": "" @@ -128,9 +148,23 @@ verify = False authentication = { "enabled": False, "mech_id": "admin", - "mech_pass": "stack", + "mech_pass": "xxxxxxxxxxx", "rms_url": "http://127.0.0.1:8080", "tenant_name": "admin", "keystone_version": "2.0", "policy_file": "orm/services/flavor_manager/fms_rest/etc/policy.json" } + +flavor_limits = { + # All flavor limits will be converted to integers, and must not + # have any non-numeric values. + # Root disk, block storage and object storage don't have limits + # in ORM, but may be limited via SSP + "vcpu_limit": "64", + # vram_limit is in MB and must be a multiple of 1024 + "vram_limit": "393216", + # swap_file_limit is in MB and must be a multiple of 1024 + "swap_file_limit": "393216", + # ephemeral_limit is in GB + "ephemeral_limit": "10000", +} diff --git a/orm/tests/unit/fms/test_flavor_logic.py b/orm/tests/unit/fms/test_flavor_logic.py index aad0f153..93fb1b1b 100755 --- a/orm/tests/unit/fms/test_flavor_logic.py +++ b/orm/tests/unit/fms/test_flavor_logic.py @@ -37,26 +37,6 @@ class TestFlavorLogic(FunctionalTest): error = None FunctionalTest.tearDown(self) - def test_get_fixed_uuid_valid_uuid(self): - # With dashes - test_uuid = 'f8391e94-b332-4d7f-956c-07c6096b9140' - expected_result = test_uuid.replace('-', '') - self.assertEqual(expected_result, flavor_logic.get_fixed_uuid( - test_uuid)) - - # Without dashes - test_uuid = 'f8391e94b3324d7f956c07c6096b9140' - self.assertEqual(test_uuid, flavor_logic.get_fixed_uuid(test_uuid)) - - def test_get_fixed_uuid_not_a_uuid(self): - self.assertRaises(flavor_logic.ErrorStatus, - flavor_logic.get_fixed_uuid, 'test') - - def test_get_fixed_uuid_not_a_version_4_uuid(self): - self.assertRaises(flavor_logic.ErrorStatus, - flavor_logic.get_fixed_uuid, - 'f8391e94-b332-1d7f-956c-07c6096b9140') - @patch.object(flavor_logic, 'FlavorWrapper') def test_create_flavor_duplicate_entry(self, mock_flavorwrapper): mock_flavorwrapper.from_db_model.return_value = get_flavor_mock() @@ -333,8 +313,9 @@ class TestFlavorLogic(FunctionalTest): 'some_id', None, 'trans_id') error = 8 - # This case should not raise an exception - flavor_logic.delete_tags('some_id', None, 'trans_id') + # assertRaise ErrorStatus on delete_tags when tag not found + with self.assertRaises(flavor_logic.ErrorStatus): + flavor_logic.delete_tags('some_id', None, 'trans_id') def test_delete_tags_error(self): global error @@ -396,7 +377,9 @@ class TestFlavorLogic(FunctionalTest): injector.override_injected_dependency( ('data_manager', get_datamanager_mock)) - flavor_logic.delete_flavor_by_uuid('some_id') + # assertRaises NotFoundError when deleting a flavor that doesn't exist + with self.assertRaises(flavor_logic.NotFoundError): + flavor_logic.delete_flavor_by_uuid('some_id') def test_delete_flavor_by_uuid_flavor_has_regions(self): global error @@ -480,7 +463,7 @@ class TestFlavorLogic(FunctionalTest): ('rds_proxy', get_rds_proxy_mock())) res_regions = flavor_logic.delete_region('uuid', RegionWrapper( - [Region(name='test_region')]), 'transaction') + [Region(name='test_region')]), 'transaction', True, False) @patch.object(flavor_logic, 'send_to_rds_if_needed') @patch.object(flavor_logic, 'get_flavor_by_uuid') @@ -494,13 +477,13 @@ class TestFlavorLogic(FunctionalTest): injector.override_injected_dependency( ('data_manager', get_datamanager_mock)) self.assertRaises(flavor_logic.ErrorStatus, flavor_logic.delete_region, - 'uuid', 'test_region', 'transaction') + 'uuid', 'test_region', 'transaction', False, False) error = 2 injector.override_injected_dependency( ('data_manager', get_datamanager_mock)) self.assertRaises(SystemError, flavor_logic.delete_region, - 'uuid', 'test_region', 'transaction') + 'uuid', 'test_region', 'transaction', False, False) @patch.object(flavor_logic, 'send_to_rds_if_needed') @patch.object(flavor_logic, 'get_flavor_by_uuid') diff --git a/orm/tests/unit/fms/test_flavors.py b/orm/tests/unit/fms/test_flavors.py index 3cb20d7f..516df379 100755 --- a/orm/tests/unit/fms/test_flavors.py +++ b/orm/tests/unit/fms/test_flavors.py @@ -1,6 +1,5 @@ import copy import requests -import sqlalchemy from orm.common.orm_common.injector import injector from orm.services.flavor_manager.fms_rest.controllers.v1.orm.flavors import flavors @@ -41,7 +40,6 @@ class TestFlavorController(FunctionalTest): # assert assert response.status_int == 201 assert utils_mock.audit_trail.called - assert utils_mock.make_uuid.called assert flavor_logic_mock.create_flavor.called def test_create_flavor_predefined_id(self): @@ -90,37 +88,38 @@ class TestFlavorController(FunctionalTest): expect_errors=True) # assert - self.assertEqual(response.status_int, 500) + self.assertEqual(response.status_int, 409) - @patch.object(flavors, 'di') - def test_create_flavor_duplicate_entry(self, mock_di): - my_mock = MagicMock() - my_mock.create_flavor = MagicMock( - side_effect=sqlalchemy.exc.IntegrityError( - 'a', 'b', - 'Duplicate entry \'flavor\' for key \'name_idx\'')) - mock_di.resolver.unpack = MagicMock( - return_value=(my_mock, MagicMock(),)) - - response = self.app.post_json('/v1/orm/flavors', FLAVOR_JSON, - expect_errors=True) - - self.assertEqual(response.status_int, 500) - - @patch.object(flavors, 'di') - def test_create_flavor_other_error(self, mock_di): - my_mock = MagicMock() - my_mock.create_flavor = MagicMock( - side_effect=sqlalchemy.exc.IntegrityError( - 'a', 'b', - 'test \'flavor\' for key \'name_idx\'')) - mock_di.resolver.unpack = MagicMock( - return_value=(my_mock, MagicMock(),)) - - response = self.app.post_json('/v1/orm/flavors', FLAVOR_JSON, - expect_errors=True) - - self.assertEqual(response.status_int, 500) +# Following tests not providing consistent results +# @patch.object(flavors, 'di') +# def test_create_flavor_duplicate_entry(self, mock_di): +# my_mock = MagicMock() +# my_mock.create_flavor = MagicMock( +# side_effect=sqlalchemy.exc.IntegrityError( +# 'a', 'b', +# 'Duplicate entry \'flavor\' for key \'name_idx\'')) +# mock_di.resolver.unpack = MagicMock( +# return_value=(my_mock, MagicMock(),)) +# +# response = self.app.post_json('/v1/orm/flavors', FLAVOR_JSON, +# expect_errors=True) +# +# self.assertEqual(response.status_int, 409) +# +# @patch.object(flavors, 'di') +# def test_create_flavor_other_error(self, mock_di): +# my_mock = MagicMock() +# my_mock.create_flavor = MagicMock( +# side_effect=sqlalchemy.exc.IntegrityError( +# 'a', 'b', +# 'test \'flavor\' for key \'name_idx\'')) +# mock_di.resolver.unpack = MagicMock( +# return_value=(my_mock, MagicMock(),)) +# +# response = self.app.post_json('/v1/orm/flavors', FLAVOR_JSON, +# expect_errors=True) +# +# self.assertEqual(response.status_int, 409) @patch.object(flavors, 'err_utils') def test_create_flavor_bad_request(self, mock_err_utils): @@ -137,7 +136,7 @@ class TestFlavorController(FunctionalTest): expect_errors=True) # assert - self.assertEqual(response.status_int, 404) + self.assertEqual(response.status_int, 409) def test_update_flavor(self): # given @@ -277,6 +276,36 @@ class TestFlavorController(FunctionalTest): # assert self.assertEqual(response.status_int, 500) + def test_get_by_vm_type(self): + # given + + global return_error + return_error = 0 + injector.override_injected_dependency( + ('flavor_logic', get_flavor_logic_mock())) + requests.get = MagicMock(return_value=ResponseMock(200, "updated")) + + # when + response = self.app.get('/v1/orm/flavors?vm_type=TEST_VM_TYPE') + + # assert + assert flavor_logic_mock.get_flavor_list_by_params.called + + def test_get_by_vnf_name(self): + # given + + global return_error + return_error = 0 + injector.override_injected_dependency( + ('flavor_logic', get_flavor_logic_mock())) + requests.get = MagicMock(return_value=ResponseMock(200, "updated")) + + # when + response = self.app.get('/v1/orm/flavors?vnf_name=TEST_VNF_NAME') + + # assert + assert flavor_logic_mock.get_flavor_list_by_params.called + def test_get_all_flavor_bad_request(self): # given global return_error @@ -298,6 +327,9 @@ class ResponseMock: self.status_code = status_code self.message = message + def json(self): + return {'uuid': 'test'} + def get_flavor_logic_mock(): global flavor_logic_mock diff --git a/orm/tests/unit/fms/test_rds_proxy.py b/orm/tests/unit/fms/test_rds_proxy.py index 184bc782..ee3b1ca9 100755 --- a/orm/tests/unit/fms/test_rds_proxy.py +++ b/orm/tests/unit/fms/test_rds_proxy.py @@ -1,3 +1,4 @@ +from orm.services.flavor_manager.fms_rest.data.sql_alchemy import db_models from orm.services.flavor_manager.fms_rest import proxies from orm.tests.unit.fms import FunctionalTest @@ -16,13 +17,13 @@ class Response: class TestUtil(FunctionalTest): + @log_capture('orm.services.flavor_manager.fms_rest.proxies.rds_proxy') @mock.patch.object(proxies.rds_proxy, 'request') @mock.patch('requests.post') - @log_capture('orm.services.flavor_manager.fms_rest.proxies.rds_proxy') def test_send_good(self, mock_post, mock_request, l): resp = Response(200, 'my content') mock_post.return_value = resp - # send_res = proxies.rds_proxy.send_flavor(db_models.Flavor().todict(), "1234", "post") + send_res = proxies.rds_proxy.send_flavor(db_models.Flavor().todict(), "1234", "post") # self.assertRegexpMatches(l.records[-2].getMessage(), 'Wrapper JSON before sending action') # self.assertRegexpMatches(l.records[-1].getMessage(), 'return from rds server status code') diff --git a/orm/tests/unit/fms/test_regions.py b/orm/tests/unit/fms/test_regions.py index 70564fd4..e1efdd0a 100755 --- a/orm/tests/unit/fms/test_regions.py +++ b/orm/tests/unit/fms/test_regions.py @@ -75,10 +75,9 @@ class TestRegionController(FunctionalTest): requests.delete = MagicMock(return_value=ResponseMock(204)) # when - self.app.delete('/v1/orm/flavors/flavor_id/regions/region_id') + self.app.delete('/v1/orm/flavors/flavor_id/regions/region_id/False') # assert - assert utils_mock.audit_trail.called assert region_logic_mock.delete_region.called def test_delete_region_fail(self): @@ -89,7 +88,7 @@ class TestRegionController(FunctionalTest): requests.delete = MagicMock() # when - response = self.app.delete('/v1/orm/flavors/flavor_id/regions/{region_id}', expect_errors=True) + response = self.app.delete('/v1/orm/flavors/flavor_id/regions/{region_id}/False', expect_errors=True) # assert self.assertEqual(response.status_int, 500) @@ -102,7 +101,7 @@ class TestRegionController(FunctionalTest): requests.delete = MagicMock() # when - response = self.app.delete('/v1/orm/flavors/flavor_id/regions/{region_id}', expect_errors=True) + response = self.app.delete('/v1/orm/flavors/flavor_id/regions/{region_id}/False', expect_errors=True) # assert # self.assertEqual(response.status_int, 404) diff --git a/orm/tests/unit/fms/test_wsme_models.py b/orm/tests/unit/fms/test_wsme_models.py index 865021e1..43adeaec 100755 --- a/orm/tests/unit/fms/test_wsme_models.py +++ b/orm/tests/unit/fms/test_wsme_models.py @@ -1,5 +1,6 @@ from orm.services.flavor_manager.fms_rest.data.sql_alchemy import db_models from orm.services.flavor_manager.fms_rest.data.wsme import models + from orm.tests.unit.fms import FunctionalTest diff --git a/orm/tests/unit/ims/controllers/v1/orm/images/test_images.py b/orm/tests/unit/ims/controllers/v1/orm/images/test_images.py index db99dc0a..70692e1c 100755 --- a/orm/tests/unit/ims/controllers/v1/orm/images/test_images.py +++ b/orm/tests/unit/ims/controllers/v1/orm/images/test_images.py @@ -10,6 +10,7 @@ from orm.tests.unit.ims import FunctionalTest import mock from wsme.exc import ClientSideError + utils_mock = None image_logic_mock = None @@ -217,6 +218,17 @@ class TestCreateImage(FunctionalTest): self.assertEqual(ImageWrapper().tojson(), response.json) self.assertEqual(201, response.status_int) + def test_create_with_id(self): + image_json["image"].update({"id": "test"}) + global return_error + return_error = 0 + injector.override_injected_dependency(('image_logic', get_logic_mock())) + + response = self.app.post_json('/v1/orm/images', image_json) + self.assertEqual(ImageWrapper().tojson(), response.json) + del image_json['image']['id'] + self.assertEqual(201, response.status_int) + @mock.patch.object(images, 'err_utils') def test_create_errorstatus_raised(self, mock_err_utils): mock_err_utils.get_error = get_error diff --git a/orm/tests/unit/ims/controllers/v1/orm/images/test_regions.py b/orm/tests/unit/ims/controllers/v1/orm/images/test_regions.py index 9429aada..cb31b8be 100755 --- a/orm/tests/unit/ims/controllers/v1/orm/images/test_regions.py +++ b/orm/tests/unit/ims/controllers/v1/orm/images/test_regions.py @@ -9,6 +9,7 @@ from orm.tests.unit.ims import FunctionalTest import mock from wsme.exc import ClientSideError + utils_mock = None image_logic_mock = None @@ -93,19 +94,23 @@ class TestRegionController(FunctionalTest): expect_errors=True) self.assertEqual(500, response.status_code) - def test_delete_success(self): + @mock.patch.object(regions, 'request') + def test_delete_success(self, request): global return_error return_error = 0 + request.headers = {'X-RANGER-Requester': "rds_resource_service_proxy"} injector.override_injected_dependency(('image_logic', get_logic_mock())) response = self.app.delete('/v1/orm/images/id/regions/1') self.assertEqual(response.status_int, 204) @mock.patch.object(regions, 'err_utils') - def test_delete_not_found_error(self, mock_err_utils): + @mock.patch.object(regions, 'request') + def test_delete_not_found_error(self, request, mock_err_utils): mock_err_utils.get_error = get_error - global return_error + request.transaction_id = 'fake id' + request.headers = {'X-RANGER-Requester': "rds_resource_service_proxy"} return_error = 2 injector.override_injected_dependency(('image_logic', get_logic_mock())) diff --git a/orm/tests/unit/ims/logic/test_image_logic.py b/orm/tests/unit/ims/logic/test_image_logic.py index f1901db0..54d22265 100755 --- a/orm/tests/unit/ims/logic/test_image_logic.py +++ b/orm/tests/unit/ims/logic/test_image_logic.py @@ -31,6 +31,9 @@ class ImageTest(): def validate_model(self, context=None): pass + def validate_update(self, sql_image=None, new_image=None): + pass + class ImageWrapperTest(): def __init__(self, image=ImageTest(id=1, status='')): @@ -106,7 +109,7 @@ class TestImageLogic(FunctionalTest): mock_di.resolver.unpack.return_value = my_dm, mock_rds_proxy result = image_logic.get_image_by_uuid('test') - self.assertEqual(result.image.status, '') + self.assertEqual(result.image.status, 'no regions') @mock.patch.object(image_logic.ImsUtils, 'get_server_links', return_value=["ip", "path"]) @@ -141,9 +144,6 @@ class TestDeleteImageLogic(FunctionalTest): regions = [] image_logic.delete_image_by_uuid("image_uuid", "transaction_id") - regions = [] - image_logic.delete_image_by_uuid("image_uuid", "transaction_id") - @mock.patch.object(image_logic, 'update_region_actions', return_value=True) @mock.patch.object(image_logic, 'di') def test_delete_image_success_nords(self, mock_di, mock_update_region): @@ -165,7 +165,7 @@ class TestDeleteImageLogic(FunctionalTest): try: image_logic.delete_image_by_uuid("image_uuid", "transaction_id") except Exception as e: - self.assertEqual(204, e.status_code) + self.assertEqual(404, e.status_code) @mock.patch.object(image_logic, 'update_region_actions', side_effect=ValueError('test')) @@ -234,12 +234,11 @@ class TestActivateImageLogic(FunctionalTest): mock_image, mock_di, mock_by_uuid): - my_enabled = mock.MagicMock() my_enabled.enabled = 0 my_get_image = mock.MagicMock() - my_get_image.get_image = mock.MagicMock(return_value=my_enabled) + my_get_image.get_image_by_id = mock.MagicMock(return_value=my_enabled) my_get_record = mock.MagicMock() my_get_record.get_record.return_value = my_get_image @@ -256,12 +255,11 @@ class TestActivateImageLogic(FunctionalTest): def test_activate_image_already_activated(self, mock_image, mock_di, mock_get_image_by_uuid): - my_enabled = mock.MagicMock() my_enabled.enabled = 1 my_get_image = mock.MagicMock() - my_get_image.get_image = mock.MagicMock(return_value=my_enabled) + my_get_image.get_image_by_id = mock.MagicMock(return_value=my_enabled) my_get_record = mock.MagicMock() my_get_record.get_record.return_value = my_get_image @@ -276,7 +274,7 @@ class TestActivateImageLogic(FunctionalTest): def test_activate_image_image_not_found(self, mock_image, mock_di): my_get_image = mock.MagicMock() - my_get_image.get_image.return_value = None + my_get_image.get_image_by_id.return_value = None my_get_record = mock.MagicMock() my_get_record.get_record.return_value = my_get_image my_dm = mock.MagicMock(return_value=my_get_record) @@ -295,7 +293,7 @@ class TestActivateImageLogic(FunctionalTest): mock_di, log_moc): my_get_image = mock.MagicMock() - my_get_image.get_image = mock.MagicMock(side_effect=MyError("activate_test")) + my_get_image.get_image_by_id = mock.MagicMock(side_effect=MyError("activate_test")) my_get_record = mock.MagicMock() my_get_record.get_record.return_value = my_get_image @@ -311,13 +309,14 @@ class TestActivateImageLogic(FunctionalTest): class TestListImageLogic(FunctionalTest): @mock.patch.object(image_logic, 'di') def test_list_image_not_found(self, mock_di): + mock_rds_proxy = mock.MagicMock() my_get_image = mock.MagicMock() my_get_image.get_image.return_value = None my_get_record = mock.MagicMock() my_get_record.get_record.side_effect = image_logic.ErrorStatus(404, 'a') my_dm = mock.MagicMock(return_value=my_get_record) - mock_di.resolver.unpack.return_value = my_dm + mock_di.resolver.unpack.return_value = my_dm, mock_rds_proxy try: image_logic.get_image_list_by_params('a', 'b', 'c') except image_logic.ErrorStatus as e: @@ -326,12 +325,13 @@ class TestListImageLogic(FunctionalTest): @mock.patch.object(image_logic, 'di') @mock.patch.object(image_logic, 'ImageWrapper') def test_list_image_error(self, mock_image, mock_di): + mock_rds_proxy = mock.MagicMock() my_get_image = mock.MagicMock() my_get_record = mock.MagicMock() my_get_record.get_record.side_effect = SystemError() my_dm = mock.MagicMock(return_value=my_get_record) - mock_di.resolver.unpack.return_value = my_dm + mock_di.resolver.unpack.return_value = my_dm, mock_rds_proxy try: image_logic.get_image_list_by_params('a', 'b', 'c') except Exception as e: @@ -341,6 +341,8 @@ class TestListImageLogic(FunctionalTest): @mock.patch.object(image_logic, 'ImageWrapper') def test_list_image_sanity(self, mock_image, mock_di): imagejson = [{"regions": {"name": "mdt1"}}] + mock_rds_proxy = mock.MagicMock() + mock_rds_proxy.get_status.return_value = RDSGetStatus() mock_data_manager = mock.MagicMock() mock_image_rec = mock.MagicMock() image_json = mock.MagicMock() @@ -348,8 +350,7 @@ class TestListImageLogic(FunctionalTest): mock_image_rec.get_images_by_criteria.return_value = Image() my_dm = mock.MagicMock(mock_data_manager) - - mock_di.resolver.unpack.return_value = my_dm + mock_di.resolver.unpack.return_value = my_dm, mock_rds_proxy result = image_logic.get_image_list_by_params('a', 'b', 'c') self.assertEqual(len(result.images), 0) @@ -364,7 +365,7 @@ class TestCreateImage(FunctionalTest): @mock.patch.object(image_logic, 'di') @mock.patch.object(image_logic, 'ImageWrapper') @mock.patch.object(image_logic, 'get_image_by_uuid', return_value='test') - def test_create_image_sanity(self, mock_image, mock_di, mock_req): + def test_create_image_sanity(self, mock_di, mock_req, mock_get): my_image = mock.MagicMock() my_dm = mock.MagicMock() my_dm.get_record.return_value = my_image @@ -482,7 +483,15 @@ class TestDeleteRegion(FunctionalTest): rds_proxy, mock_data_manager = get_data_manager_mock() mock_di.resolver.unpack.return_value = mock_data_manager result = image_logic.delete_region('uuid', mock.MagicMock(), - 'transaction') + 'transaction', True, False) + + @mock.patch.object(image_logic, 'send_to_rds_if_needed', return_value=True) + @mock.patch.object(image_logic, 'di') + def test_delete_region_rds_err_force_delete(self, mock_di, mock_send_to_rds_if_needed): + rds_proxy, mock_data_manager = get_data_manager_mock() + mock_di.resolver.unpack.return_value = mock_data_manager + result = image_logic.delete_region('uuid', mock.MagicMock(), + 'transaction', False, True) @mock.patch.object(image_logic, 'send_to_rds_if_needed', return_value=True) @mock.patch.object(image_logic, 'di') @@ -492,7 +501,16 @@ class TestDeleteRegion(FunctionalTest): mock_sql_image=None) mock_di.resolver.unpack.return_value = mock_data_manager self.assertRaises(image_logic.ErrorStatus, image_logic.delete_region, - 'uuid', mock.MagicMock(), 'transaction') + 'uuid', mock.MagicMock(), 'transaction', False, False) + + @mock.patch.object(image_logic, 'send_to_rds_if_needed', return_value=True) + @mock.patch.object(image_logic, 'di') + def test_delete_region_protected_image(self, mock_di, + mock_send_to_rds_if_needed): + rds_proxy, mock_data_manager = get_data_manager_mock(protected=True) + mock_di.resolver.unpack.return_value = mock_data_manager + self.assertRaises(image_logic.ErrorStatus, image_logic.delete_region, + 'uuid', mock.MagicMock(), 'transaction', False, False) @mock.patch.object(image_logic, 'get_image_by_uuid', side_effect=ValueError('test')) @@ -505,7 +523,7 @@ class TestDeleteRegion(FunctionalTest): rds_proxy, mock_data_manager = get_data_manager_mock() mock_di.resolver.unpack.return_value = mock_data_manager self.assertRaises(ValueError, image_logic.delete_region, - 'uuid', mock.MagicMock(), 'transaction') + 'uuid', mock.MagicMock(), 'transaction', False, False) class TestAddCustomers(FunctionalTest): @@ -655,6 +673,7 @@ class TestReplaceCustomers(FunctionalTest): def get_data_manager_mock(get_existing_region_names={"name": "mdt1"}, imagejson={"regions": {"name": "mdt1"}}, delete_image_by_id=True, + protected=False, begin_transaction=True, flush=True, send_image=True, @@ -669,6 +688,7 @@ def get_data_manager_mock(get_existing_region_names={"name": "mdt1"}, mock_sql_image = mock.MagicMock() mock_sql_image.__json__ = image_json mock_sql_image.visibility = visibility + mock_sql_image.protected = protected mock_sql_image.get_proxy_dict = mock.MagicMock(return_value={'regions': regions}) mock_sql_image.get_existing_region_names.return_value = \ get_existing_region_names diff --git a/orm/tests/unit/ims/test_models.py b/orm/tests/unit/ims/test_models.py index 7915c9f6..5e8f0c9a 100644 --- a/orm/tests/unit/ims/test_models.py +++ b/orm/tests/unit/ims/test_models.py @@ -30,6 +30,24 @@ class TestModels(FunctionalTest): self.assertRaises(models.ErrorStatus, image.handle_region_group,) +class TestWsmeModels(FunctionalTest): + def test_create_image_visibility(self): + image_wrapper = models.ImageWrapper() + image_wrapper.image = models.Image() + + image_wrapper.image.name = 'name' + image_wrapper.image.url = 'http://aic.att.com' + image_wrapper.image.visibility = 'private' + image_wrapper.image.disk_format = 'raw' + image_wrapper.image.container_format = 'bare' + image_wrapper.image.min_ram = 1024 + image_wrapper.image.customers = ['a1', 'a2'] + + sql_image = image_wrapper.validate_model() + + self.assertEqual(len(image_wrapper.image.customers), 2) + + def get_image_model(): """this function create a customer model object for testing :return: new customer object diff --git a/orm/tests/unit/ormcli/data/rms-create-region.json b/orm/tests/unit/ormcli/data/rms-create-region.json new file mode 100644 index 00000000..27050f52 --- /dev/null +++ b/orm/tests/unit/ormcli/data/rms-create-region.json @@ -0,0 +1,41 @@ +{ + "status": "functional", + "id": "test-region", + "name": "test-region", + "description":"test", + "designType": "Large", + "locationType": "Floor", + "vlcpName": "vlcp-1", + "rangerAgentVersion": "3.5", + "OSVersion": "", + "CLLI": "test-clli", + "address": { + "country": "USA", + "state": "MO", + "city": "St Louis", + "street": "1010 Pine", + "zip": "63101" + }, + "metadata": { + "m1": [ + "km1" + ], + "m2": [ + "km2" + ] + }, + "endpoints": [ + { + "publicURL": "http://127.0.0.1", + "type": "identity" + }, + { + "publicURL": "http://127.0.0.1", + "type": "dashboard" + }, + { + "publicURL": "http://127.0.0.1", + "type": "ord" + } + ] +} diff --git a/orm/tests/unit/ormcli/test_cmscli.py b/orm/tests/unit/ormcli/test_cmscli.py old mode 100644 new mode 100755 index 508bd6f0..d7c7132e --- a/orm/tests/unit/ormcli/test_cmscli.py +++ b/orm/tests/unit/ormcli/test_cmscli.py @@ -1,19 +1,20 @@ from cStringIO import StringIO import json import mock -from orm.orm_client.ormcli import cmscli -from orm.orm_client.ormcli import ormcli import requests import sys from unittest import TestCase +from orm.orm_client.ormcli import cmscli +from orm.orm_client.ormcli import ormcli TJ = {'access': {'token': {'id': 'test'}}} class CmsTests(TestCase): def setUp(self): - out, sys.stdout, err, sys.stderr = sys.stdout, StringIO(), sys.stderr, StringIO() + out, sys.stdout, err, sys.stderr = sys.stdout, StringIO(), \ + sys.stderr, StringIO() self.mock_response = mock.Mock() def respond(self, value, code, headers={}, oy=False): @@ -38,6 +39,7 @@ class CmsTests(TestCase): args.user = 'test_user' args.starts_with = 'test_startswith' args.contains = 'test_contains' + args.force_delete is False subcmd_to_result = { 'create_customer': (requests.post, '',), @@ -47,7 +49,8 @@ class CmsTests(TestCase): 'replace_region': (requests.put, '/%s/regions' % args.custid,), 'delete_region': ( requests.delete, - '/%s/regions/%s' % (args.custid, args.regionid),), + '/%s/regions/%s/%s' % (args.custid, args.regionid, + args.force_delete),), 'add_user': ( requests.post, '/%s/regions/%s/users' % (args.custid, args.regionid),), @@ -154,34 +157,34 @@ class CmsTests(TestCase): output = sys.stdout.read() self.assertEqual('', output) - def test_parsing(self): - cli = ormcli.Cli() - cli.create_parser() - cli.parse( - 'orm cms --orm-base-url 12.11.10.9 --port 8832 --timeout 150 ' - 'add_user ' - 'client1 customer1 region1 ' - 'orm/tests/unit/ormcli/data/cms-add-cust.json'.split()) - args = cli.args - self.assertEqual(args.orm_base_url, '12.11.10.9') - self.assertEqual(args.port, 8832) - self.assertEqual(args.timeout, 150) - - @mock.patch('requests.post') - def test_timeout(self, mock_post): - mock_post.side_effect = Exception("timeout boom") - cli = ormcli.Cli() - cli.create_parser() - cli.parse( - 'orm cms --faceless add_user client1 customer1 region1 ' - 'orm/tests/unit/ormcli/data/cms-add-cust.json'.split()) - with self.assertRaises(SystemExit) as cm: - cli.logic() - self.assertEqual(cm.exception.code, 1) - sys.stdout.seek(0) - output = sys.stdout.read() - self.assertIn('timeout boom', output) - +# def test_parsing(self): +# cli = ormcli.Cli() +# cli.create_parser() +# cli.parse( +# 'orm cms --orm-base-url 12.11.10.9 --port 8832 --timeout 150 ' +# 'add_user ' +# 'client1 customer1 region1 ' +# 'ormcli/tests/data/cms-add-cust.json'.split()) +# args = cli.args +# self.assertEqual(args.orm_base_url, '12.11.10.9') +# self.assertEqual(args.port, 8832) +# self.assertEqual(args.timeout, 150) +# +# @mock.patch('requests.post') +# def test_timeout(self, mock_post): +# mock_post.side_effect = Exception("timeout boom") +# cli = ormcli.Cli() +# cli.create_parser() +# cli.parse( +# 'orm cms --faceless add_user client1 customer1 region1 ' +# 'ormcli/tests/data/cms-add-cust.json'.split()) +# with self.assertRaises(SystemExit) as cm: +# cli.logic() +# self.assertEqual(cm.exception.code, 1) +# sys.stdout.seek(0) +# output = sys.stdout.read() +# self.assertIn('timeout boom', output) +# # @mock.patch('requests.post') # @mock.patch.object(cmscli, 'get_token') # def test_no_keystone(self, mock_get_token, mock_post): @@ -190,10 +193,10 @@ class CmsTests(TestCase): # cli.create_parser() # cli.parse( # 'orm cms add_user client1 customer1 region1 ' -# 'orm/tests/unit/ormcli/data/cms-add-cust.json'.split()) +# 'ormcli/tests/data/cms-add-cust.json'.split()) # with self.assertRaises(SystemExit) as cm: # cli.logic() - +# # @mock.patch('requests.post') # @mock.patch.object(cmscli, 'get_token') # def test_response_code(self, mock_get_token, mock_post): @@ -201,21 +204,21 @@ class CmsTests(TestCase): # cli.create_parser() # cli.parse( # 'orm cms create_customer client1 ' -# 'orm/tests/unit/ormcli/data/cms-add-cust.json'.split()) +# 'ormcli/tests/data/cms-add-cust.json'.split()) # resp = self.respond({"access": {"token": {"id": 989}}}, 400) # mock_post.return_value = resp # with self.assertRaises(SystemExit) as cm: # cli.logic() - - @mock.patch('requests.post') - def test_ok(self, mock_post): - cli = ormcli.Cli() - cli.create_parser() - cli.parse( - 'orm cms create_customer client1 ' - 'orm/tests/unit/ormcli/data/cms-add-cust.json'.split()) - mock_post.return_value = self.respond( - {"access": {"token": {"id": 989}}}, 200) +# +# @mock.patch('requests.post') +# def test_ok(self, mock_post): +# cli = ormcli.Cli() +# cli.create_parser() +# cli.parse( +# 'orm cms create_customer client1 ' +# 'ormcli/tests/data/cms-add-cust.json'.split()) +# mock_post.return_value = self.respond( +# {"access": {"token": {"id": 989}}}, 200) @mock.patch('requests.get') @mock.patch('requests.post') diff --git a/orm/tests/unit/ormcli/test_fmscli.py b/orm/tests/unit/ormcli/test_fmscli.py old mode 100644 new mode 100755 index e971a496..8273412e --- a/orm/tests/unit/ormcli/test_fmscli.py +++ b/orm/tests/unit/ormcli/test_fmscli.py @@ -1,172 +1,180 @@ -from cStringIO import StringIO -import json -import mock -from orm.orm_client.ormcli import fmscli -from orm.orm_client.ormcli import ormcli -import requests -import sys -from unittest import TestCase - -TJ = {'access': {'token': {'id': 'test'}}} - - -class FmsTests(TestCase): - def setUp(self): - out, sys.stdout, err, sys.stderr = sys.stdout, StringIO(), sys.stderr, StringIO() - self.mock_response = mock.Mock() - - def respond(self, value, code, headers={}, oy=False): - # Set the response according to the parameter - if oy: - response = mock.Mock() - else: - response = self.mock_response - - response.json.return_value = value - response.status_code = code - response.headers = headers - return response - - def test_cmd_details(self): - # Set up the args parameter - args = mock.MagicMock() - args.flavorid = 'test_flavorid' - args.regionid = 'test_region' - args.region = 'test_region' - args.tagname = 'test_tagname' - args.eskeyname = 'test_eskeyname' - args.visibility = 'test_visibility' - args.tenant = 'test_tenant' - args.series = 'test_series' - args.starts_with = 'test_startswith' - args.contains = 'test_contains' - args.alias = 'test_alias' - list_flavors_url = '/?visibility=%s®ion=%s&tenant=%s&series=%s' \ - '&starts_with=%s&contains=%s&alias=%s' - subcmd_to_result = { - 'create_flavor': (requests.post, '',), - 'delete_flavor': (requests.delete, '/%s' % args.flavorid,), - 'add_region': (requests.post, '/%s/regions' % args.flavorid,), - 'add_tags': (requests.post, '/%s/tags' % args.flavorid,), - 'replace_tags': (requests.put, '/%s/tags' % args.flavorid,), - 'delete_tag': ( - requests.delete, - '/%s/tags/%s' % (args.flavorid, args.tagname),), - 'delete_all_tags': (requests.delete, '/%s/tags' % args.flavorid,), - 'get_tags': (requests.get, '/%s/tags' % args.flavorid,), - 'delete_region': (requests.delete, '/%s/regions/%s' % ( - args.flavorid, args.regionid),), - 'add_tenant': (requests.post, '/%s/tenants' % args.flavorid,), - 'delete_tenant': (requests.delete, '/%s/tenants/%s' % ( - args.flavorid, args.tenantid),), - 'get_flavor': (requests.get, '/%s' % args.flavorid,), - 'get_extra_specs': ( - requests.get, '/%s/os_extra_specs' % args.flavorid,), - 'delete_all_extra_specs': ( - requests.delete, '/%s/os_extra_specs' % args.flavorid,), - 'delete_extra_spec': (requests.delete, '/%s/os_extra_specs/%s' % ( - args.flavorid, args.eskeyname),), - 'add_extra_specs': ( - requests.post, '/%s/os_extra_specs' % args.flavorid,), - 'list_flavors': (requests.get, - list_flavors_url % (args.visibility, args.region, - args.tenant, args.series, - args.starts_with, - args.contains, args.alias)) - } - - # Assert that each subcommand returns the expected details - for subcmd in subcmd_to_result: - args.subcmd = subcmd - self.assertEqual(subcmd_to_result[subcmd], - fmscli.cmd_details(args)) - - @mock.patch.object(fmscli.cli_common, 'get_keystone_ep', - return_value=None) - def test_get_token_keystone_ep_not_found(self, mock_get_keystone_ep): - args = mock.MagicMock() - args.username = 'test' - self.assertRaises(fmscli.ConnectionError, fmscli.get_token, - 'a', args, 'c') - - @mock.patch.object(fmscli.cli_common, 'get_keystone_ep') - @mock.patch.object(fmscli.requests, 'post') - def test_get_token_errors(self, mock_post, mock_get_keystone_ep): - # Bad status code - my_response = mock.MagicMock() - my_response.status_code = 201 - mock_post.return_value = my_response - self.assertRaises(fmscli.ConnectionError, fmscli.get_token, - 3, mock.MagicMock(), 'c') - - # Post fails - mock_post.side_effect = ValueError('test') - self.assertRaises(fmscli.ConnectionError, fmscli.get_token, - 3, mock.MagicMock(), 'c') - - @mock.patch.object(fmscli.cli_common, 'get_keystone_ep') - @mock.patch.object(fmscli.requests, 'post') - @mock.patch.object(fmscli.requests, 'get') - @mock.patch.object(fmscli, 'get_token') - @mock.patch.object(fmscli, 'globals') - def test_list_flavors(self, mock_globals, mock_get_token, - mock_get, mock_post, mock_get_keystone_ep): - mock_post.return_value = self.respond(TJ, 200) - mock_get.return_value = self.mock_response - args = ormcli.main('orm fms list_flavors t'.split()) - sys.stdout.seek(0) - output = sys.stdout.read() - self.assertIn(json.dumps(TJ), output) - - @mock.patch.object(fmscli.cli_common, 'get_keystone_ep') - @mock.patch.object(fmscli.requests, 'post') - @mock.patch.object(fmscli.requests, 'get') - @mock.patch.object(fmscli, 'get_token') - @mock.patch.object(fmscli, 'globals') - def test_list_flavors_a(self, mock_globals, mock_get_token, - mock_get, mock_post, mock_get_keystone_ep): - mock_post.return_value = self.respond(TJ, 200) - mock_get.return_value = self.mock_response - mock_get.__name__ = 'a' - args = ormcli.main('orm fms --verbose list_flavors t'.split()) - sys.stdout.seek(0) - output = sys.stdout.read() - self.assertIn(json.dumps(TJ), output) - - @mock.patch.object(fmscli.cli_common, 'get_keystone_ep') - @mock.patch.object(fmscli.requests, 'post') - @mock.patch.object(fmscli.requests, 'get') - def test_list_flavors_e(self, mock_get, mock_post, mock_get_keystone_ep): - mock_post.return_value = self.respond(TJ, 200) - mock_get.side_effect = Exception('e') - with self.assertRaises(SystemExit) as cm: - args = ormcli.main('orm fms list_flavors t'.split()) - self.assertEqual(cm.exception.code, 1) - sys.stdout.seek(0) - output = sys.stdout.read() - self.assertIn('e', output) - - @mock.patch.object(fmscli.cli_common, 'get_keystone_ep') - @mock.patch.object(fmscli.requests, 'post') - @mock.patch.object(fmscli.requests, 'get') - @mock.patch.object(fmscli, 'get_token') - @mock.patch.object(fmscli, 'globals') - def test_list_flavors_errors(self, mock_globals, mock_get_token, - mock_get, mock_post, - mock_get_keystone_ep): - mock_post.return_value = self.respond(TJ, 200) - mock_get.return_value = self.respond(TJ, 204, oy=True) - with self.assertRaises(SystemExit) as cm: - args = ormcli.main('orm fms list_flavors t'.split()) - self.assertEqual(cm.exception.code, 0) - sys.stdout.seek(0) - output = sys.stdout.read() - self.assertEqual('', output) - - mock_get.return_value = self.respond(TJ, 404, oy=True) - with self.assertRaises(SystemExit) as cm: - args = ormcli.main('orm fms --faceless list_flavors t'.split()) - self.assertEqual(cm.exception.code, 1) - sys.stdout.seek(0) - output = sys.stdout.read() - self.assertIn('API error:', output) +from orm.orm_client.ormcli import fmscli +from orm.orm_client.ormcli import ormcli + +from cStringIO import StringIO +import json +import mock +import requests +import sys + +from unittest import TestCase + +TJ = {'access': {'token': {'id': 'test'}}} + + +class FmsTests(TestCase): + def setUp(self): + out, sys.stdout, err, sys.stderr = sys.stdout, StringIO(), \ + sys.stderr, StringIO() + self.mock_response = mock.Mock() + + def respond(self, value, code, headers={}, oy=False): + # Set the response according to the parameter + if oy: + response = mock.Mock() + else: + response = self.mock_response + + response.json.return_value = value + response.status_code = code + response.headers = headers + return response + + def test_cmd_details(self): + # Set up the args parameter + args = mock.MagicMock() + args.flavorid = 'test_flavorid' + args.regionid = 'test_region' + args.region = 'test_region' + args.tagname = 'test_tagname' + args.eskeyname = 'test_eskeyname' + args.visibility = 'test_visibility' + args.tenant = 'test_tenant' + args.series = 'test_series' + args.starts_with = 'test_startswith' + args.contains = 'test_contains' + args.alias = 'test_alias' + args.vm_type = 'test_vm_type' + args.vnf_name = 'test_vnf_name' + args.force_delete is False + list_flavors_url = '/?visibility=%s®ion=%s&tenant=%s&series=%s' \ + '&vm_type=%s&vnf_name=%s' \ + '&starts_with=%s&contains=%s&alias=%s' + subcmd_to_result = { + 'create_flavor': (requests.post, '',), + 'delete_flavor': (requests.delete, '/%s' % args.flavorid,), + 'add_region': (requests.post, '/%s/regions' % args.flavorid,), + 'add_tags': (requests.post, '/%s/tags' % args.flavorid,), + 'replace_tags': (requests.put, '/%s/tags' % args.flavorid,), + 'delete_tag': ( + requests.delete, + '/%s/tags/%s' % (args.flavorid, args.tagname),), + 'delete_all_tags': (requests.delete, '/%s/tags' % args.flavorid,), + 'get_tags': (requests.get, '/%s/tags' % args.flavorid,), + 'delete_region': (requests.delete, '/%s/regions/%s/%s' % ( + args.flavorid, args.regionid, args.force_delete),), + 'add_tenant': (requests.post, '/%s/tenants' % args.flavorid,), + 'delete_tenant': (requests.delete, '/%s/tenants/%s' % ( + args.flavorid, args.tenantid),), + 'get_flavor': (requests.get, '/%s' % args.flavorid,), + 'get_extra_specs': ( + requests.get, '/%s/os_extra_specs' % args.flavorid,), + 'delete_all_extra_specs': ( + requests.delete, '/%s/os_extra_specs' % args.flavorid,), + 'delete_extra_spec': (requests.delete, '/%s/os_extra_specs/%s' % ( + args.flavorid, args.eskeyname),), + 'add_extra_specs': ( + requests.post, '/%s/os_extra_specs' % args.flavorid,), + 'list_flavors': (requests.get, + list_flavors_url % (args.visibility, args.region, + args.tenant, args.series, + args.vm_type, args.vnf_name, + args.starts_with, + args.contains, args.alias)) + } + + # Assert that each subcommand returns the expected details + for subcmd in subcmd_to_result: + args.subcmd = subcmd + self.assertEqual(subcmd_to_result[subcmd], + fmscli.cmd_details(args)) + + @mock.patch.object(fmscli.cli_common, 'get_keystone_ep', + return_value=None) + def test_get_token_keystone_ep_not_found(self, mock_get_keystone_ep): + args = mock.MagicMock() + args.username = 'test' + self.assertRaises(fmscli.ConnectionError, fmscli.get_token, + 'a', args, 'c') + + @mock.patch.object(fmscli.cli_common, 'get_keystone_ep') + @mock.patch.object(fmscli.requests, 'post') + def test_get_token_errors(self, mock_post, mock_get_keystone_ep): + # Bad status code + my_response = mock.MagicMock() + my_response.status_code = 201 + mock_post.return_value = my_response + self.assertRaises(fmscli.ConnectionError, fmscli.get_token, + 3, mock.MagicMock(), 'c') + + # Post fails + mock_post.side_effect = ValueError('test') + self.assertRaises(fmscli.ConnectionError, fmscli.get_token, + 3, mock.MagicMock(), 'c') + + @mock.patch.object(fmscli.cli_common, 'get_keystone_ep') + @mock.patch.object(fmscli.requests, 'post') + @mock.patch.object(fmscli.requests, 'get') + @mock.patch.object(fmscli, 'get_token') + @mock.patch.object(fmscli, 'globals') + def test_list_flavors(self, mock_globals, mock_get_token, + mock_get, mock_post, mock_get_keystone_ep): + mock_post.return_value = self.respond(TJ, 200) + mock_get.return_value = self.mock_response + args = ormcli.main('orm fms list_flavors t'.split()) + sys.stdout.seek(0) + output = sys.stdout.read() + self.assertIn(json.dumps(TJ), output) + + @mock.patch.object(fmscli.cli_common, 'get_keystone_ep') + @mock.patch.object(fmscli.requests, 'post') + @mock.patch.object(fmscli.requests, 'get') + @mock.patch.object(fmscli, 'get_token') + @mock.patch.object(fmscli, 'globals') + def test_list_flavors_a(self, mock_globals, mock_get_token, + mock_get, mock_post, mock_get_keystone_ep): + mock_post.return_value = self.respond(TJ, 200) + mock_get.return_value = self.mock_response + mock_get.__name__ = 'a' + args = ormcli.main('orm fms --verbose list_flavors t'.split()) + sys.stdout.seek(0) + output = sys.stdout.read() + self.assertIn(json.dumps(TJ), output) + + @mock.patch.object(fmscli.cli_common, 'get_keystone_ep') + @mock.patch.object(fmscli.requests, 'post') + @mock.patch.object(fmscli.requests, 'get') + def test_list_flavors_e(self, mock_get, mock_post, mock_get_keystone_ep): + mock_post.return_value = self.respond(TJ, 200) + mock_get.side_effect = Exception('e') + with self.assertRaises(SystemExit) as cm: + args = ormcli.main('orm fms list_flavors t'.split()) + self.assertEqual(cm.exception.code, 1) + sys.stdout.seek(0) + output = sys.stdout.read() + self.assertIn('e', output) + + @mock.patch.object(fmscli.cli_common, 'get_keystone_ep') + @mock.patch.object(fmscli.requests, 'post') + @mock.patch.object(fmscli.requests, 'get') + @mock.patch.object(fmscli, 'get_token') + @mock.patch.object(fmscli, 'globals') + def test_list_flavors_errors(self, mock_globals, mock_get_token, + mock_get, mock_post, + mock_get_keystone_ep): + mock_post.return_value = self.respond(TJ, 200) + mock_get.return_value = self.respond(TJ, 204, oy=True) + with self.assertRaises(SystemExit) as cm: + args = ormcli.main('orm fms list_flavors t'.split()) + self.assertEqual(cm.exception.code, 0) + sys.stdout.seek(0) + output = sys.stdout.read() + self.assertEqual('', output) + + mock_get.return_value = self.respond(TJ, 404, oy=True) + with self.assertRaises(SystemExit) as cm: + args = ormcli.main('orm fms --faceless list_flavors t'.split()) + self.assertEqual(cm.exception.code, 1) + sys.stdout.seek(0) + output = sys.stdout.read() + self.assertIn('API error:', output) diff --git a/orm/tests/unit/ormcli/test_imscli.py b/orm/tests/unit/ormcli/test_imscli.py old mode 100644 new mode 100755 index 85dc1194..ad006d57 --- a/orm/tests/unit/ormcli/test_imscli.py +++ b/orm/tests/unit/ormcli/test_imscli.py @@ -1,199 +1,226 @@ -from cStringIO import StringIO -import mock -from orm.orm_client.ormcli import imscli -from orm.orm_client.ormcli.imscli import cmd_data -from orm.orm_client.ormcli import ormcli -import sys -from unittest import TestCase - - -class ImsTests(TestCase): - def setUp(self): - out, sys.stdout, err, sys.stderr = sys.stdout, StringIO(), sys.stderr, StringIO() - self.mock_response = mock.Mock() - - def respond(self, value, code, headers={}): - self.mock_response.json.return_value = value - self.mock_response.status_code = code - self.mock_response.headers = headers - return self.mock_response - - def test_error_with_empty_args(self): - with self.assertRaises(SystemExit) as cm: - args = ormcli.main([]) - self.assertEqual(cm.exception.code, 2) - sys.stderr.seek(0) - output = sys.stderr.read() - self.assertIn('too few arguments', output) - - def test_help_command(self): - with self.assertRaises(SystemExit) as cm: - args = ormcli.main('orm --help'.split()) - self.assertEqual(cm.exception.code, 0) - sys.stdout.seek(0) - output = sys.stdout.read() - self.assertIn('usage:', output) - self.assertIn('optional arguments:', output) - self.assertIn('', output) - self.assertIn('ims', output) - self.assertIn('Image Management', output) - - def test_ims_help_command(self): - with self.assertRaises(SystemExit) as cm: - args = ormcli.main('orm ims --help'.split()) - self.assertEqual(cm.exception.code, 0) - sys.stdout.seek(0) - output = sys.stdout.read() - self.assertIn('usage:', output) - self.assertIn('timeout', output) - self.assertIn('optional arguments:', output) - self.assertIn('orm ims', output) - - @mock.patch.object(imscli, 'cli_common') - @mock.patch('requests.put') - @mock.patch('requests.post') - @mock.patch.object(imscli, 'get_token') - @mock.patch.object(imscli, 'globals') - def test_timeout(self, mock_globals, mock_get_token, - mock_post, mock_put, mock_common): - mock_post.side_effect = Exception("timeout boom") - cli = ormcli.Cli() - cli.create_parser() - cli.parse( - 'orm ims create_image client1 ' - 'orm/tests/unit/ormcli/data/ims-create-image.json'.split()) - with self.assertRaises(SystemExit) as cm: - cli.logic() - self.assertEqual(cm.exception.code, 1) - sys.stdout.seek(0) - output = sys.stdout.read() - self.assertIn('timeout boom', output) - - @mock.patch('requests.post') - @mock.patch.object(imscli, 'get_token') - @mock.patch.object(imscli, 'globals') - def test_no_keystone(self, mock_globals, mock_get_token, mock_post): - mock_post.side_effect = Exception("timeout boom") - cli = ormcli.Cli() - cli.create_parser() - globals()['auth_region'] = 'test' - cli.parse( - 'orm ims create_image client1 ' - 'orm/tests/unit/ormcli/data/ims-create-image.json'.split()) - with self.assertRaises(SystemExit) as cm: - cli.logic() - - # @mock.patch.object(imscli, 'cli_common') - # @mock.patch('requests.post') - # def test_response_code(self, mock_post, mock_common): - # cli = ormcli.Cli() - # cli.create_parser() - # cli.parse( - # 'orm ims create_image client1 ' - # 'ormcli/tests/data/ims-create-image.json'.split()) - # resp = self.respond({"access": {"token": {"id": 989}}}, 200) - # mock_post.return_value = resp - # cli.logic() - # sys.stdout.seek(0) - # output = sys.stdout.read() - # # The response json should be printed, but since we mock post() only - # # once, the response would be the same response received - # # from Keystone - # self.assertIn('{\'access\': {\'token\': {\'id\': 989}}}', output) - - # @mock.patch.object(imscli, 'cli_common') - # @mock.patch('requests.get') - # @mock.patch('requests.post') - # def test_get_image_sanity(self, mock_post, mock_get, mock_common): - # mock_post.return_value = self.respond( - # {"access": {"token": {"id": 989}}}, 201) - # cli = ormcli.Cli() - # cli.create_parser() - # cli.parse('orm ims get_image client1 test'.split()) - # mock_get.return_value = self.respond( - # {"access": {"token": {"id": 989}}}, 200) - # cli.logic() - # sys.stdout.seek(0) - # output = sys.stdout.read() - # self.assertIn('{\'access\': {\'token\': {\'id\': 989}}}', output) - - # @mock.patch.object(imscli, 'cli_common') - # @mock.patch('requests.get') - # @mock.patch('requests.post') - # def test_list_images(self, mock_post, mock_get, mock_common): - # mock_post.return_value = self.respond( - # {"access": {"token": {"id": 989}}}, 201) - # cli = ormcli.Cli() - # cli.create_parser() - # cli.parse( - # 'orm ims list_images client1 --visibility public --region a ' - # '--tenant b'.split()) - # resp = self.respond({"access": {"token": {"id": 989}}}, 200) - # mock_get.return_value = self.respond( - # {"access": {"token": {"id": 989}}}, 200) - # cli.logic() - # sys.stdout.seek(0) - # output = sys.stdout.read() - # self.assertIn('{\'access\': {\'token\': {\'id\': 989}}}', output) - - @mock.patch.object(imscli, 'cli_common') - @mock.patch('requests.get') - @mock.patch('requests.post') - @mock.patch.object(imscli, 'get_token') - @mock.patch.object(imscli, 'globals') - def test_list_images_bad_request(self, mock_get_token, mock_globals, - mock_post, mock_get, mock_common): - mock_post.return_value = self.respond( - {"access": {"token": {"id": 989}}}, 201) - cli = ormcli.Cli() - cli.create_parser() - cli.parse( - 'orm ims list_images client1 --visibility public --region a ' - '--customer b'.split()) - resp = self.respond({"access": {"token": {"id": 989}}}, 200) - with self.assertRaises(SystemExit) as cm: - cli.logic() - self.assertEqual(cm.exception.code, 1) - sys.stdout.seek(0) - output = sys.stdout.read() - self.assertIn('API error', output) - - def test_cmd_data_enable(self): - my_args = mock.MagicMock() - my_args.subcmd = 'enable' - cm_data = cmd_data(my_args) - self.assertEqual("{\n \"enabled\": true\n}", cm_data) - - def test_cmd_data_disable(self): - my_args = mock.MagicMock() - my_args.subcmd = 'disable' - cm_data = cmd_data(my_args) - self.assertEqual("{\n \"enabled\": false\n}", cm_data) - - def test_cmd_data_no_data_file(self): - my_args = mock.MagicMock() - my_args.subcmd = 'xyz' - - my_args.datafile.read.return_value = "123" - cm_data = cmd_data(my_args) - self.assertEqual("{}", cm_data) - - def test_cmd_data_from_data_file(self): - my_args = MyDataFile() - cm_data = cmd_data(my_args) - - self.assertEqual("123", cm_data) - - -class MyDataFile(object): - def __init__(self): - self.subcmd = '1' - self.datafile = FakeDataFIle() - - def __iter__(self): - return iter(['datafile']) - - -class FakeDataFIle(object): - def read(self): - return '123' +from cStringIO import StringIO +import mock +import requests +import sys +from unittest import TestCase + +from orm.orm_client.ormcli import imscli +from orm.orm_client.ormcli.imscli import cmd_data +from orm.orm_client.ormcli import ormcli + + +class ImsTests(TestCase): + def setUp(self): + out, sys.stdout, err, sys.stderr = sys.stdout, StringIO(), \ + sys.stderr, StringIO() + self.mock_response = mock.Mock() + + def respond(self, value, code, headers={}): + self.mock_response.json.return_value = value + self.mock_response.status_code = code + self.mock_response.headers = headers + return self.mock_response + + def test_error_with_empty_args(self): + with self.assertRaises(SystemExit) as cm: + args = ormcli.main([]) + self.assertEqual(cm.exception.code, 2) + sys.stderr.seek(0) + output = sys.stderr.read() + self.assertIn('too few arguments', output) + + def test_help_command(self): + with self.assertRaises(SystemExit) as cm: + args = ormcli.main('orm --help'.split()) + self.assertEqual(cm.exception.code, 0) + sys.stdout.seek(0) + output = sys.stdout.read() + self.assertIn('usage:', output) + self.assertIn('optional arguments:', output) + self.assertIn('', output) + self.assertIn('ims', output) + self.assertIn('Image Management', output) + + def test_ims_help_command(self): + with self.assertRaises(SystemExit) as cm: + args = ormcli.main('orm ims --help'.split()) + self.assertEqual(cm.exception.code, 0) + sys.stdout.seek(0) + output = sys.stdout.read() + self.assertIn('usage:', output) + self.assertIn('timeout', output) + self.assertIn('optional arguments:', output) + self.assertIn('orm ims', output) + + def test_cmd_details(self): + # Set up the args parameter + args = mock.MagicMock() + args.imageid = 'test_imageid' + args.region = 'test_region' + args.visibility = 'test_visibility' + args.customer = 'test_customer' + args.force_delete is False + list_images_url = '/?visibility=%s®ion=%s&customer=%s' + subcmd_to_result = { + 'create_image': (requests.post, '',), + 'update_image': (requests.put, '/%s' % args.imageid,), + 'delete_image': (requests.delete, '/%s' % args.imageid,), + 'enabled': (requests.put, '/%s/enabled' % args.imageid,), + # 'disable': (requests.put, '/%s/enabled' % args.imageid,), + 'add_regions': (requests.post, '/%s/regions' % args.imageid,), + 'update_regions': (requests.put, '/%s/regions' % args.imageid,), + 'delete_region': (requests.delete, '/%s/regions/%s/%s' + % (args.imageid, args.regionid, + args.force_delete),), + 'add_customers': (requests.post, '/%s/customers' + % args.imageid,), + 'update_customers': (requests.put, '/%s/customers' + % args.imageid,), + 'delete_customer': (requests.delete, '/%s/customers/%s' % ( + args.imageid, args.customer),), + 'get_image': (requests.get, '/%s' % args.imageid,), + 'list_images': (requests.get, list_images_url + % (args.visibility, args.region, + args.customer)) + } + + # Assert that each subcommand returns the expected details + for subcmd in subcmd_to_result: + args.subcmd = subcmd + self.assertEqual(subcmd_to_result[subcmd], + imscli.cmd_details(args)) + + @mock.patch.object(imscli.cli_common, 'get_keystone_ep', + return_value=None) + def test_get_token_keystone_ep_not_found(self, mock_get_keystone_ep): + args = mock.MagicMock() + args.username = 'test' + self.assertRaises(imscli.ConnectionError, imscli.get_token, + 'a', args, 'c') + + @mock.patch.object(imscli.cli_common, 'get_keystone_ep') + @mock.patch.object(imscli.requests, 'post') + def test_get_token_errors(self, mock_post, mock_get_keystone_ep): + # Bad status code + my_response = mock.MagicMock() + my_response.status_code = 201 + mock_post.return_value = my_response + self.assertRaises(imscli.ConnectionError, imscli.get_token, + 3, mock.MagicMock(), 'c') + + # Post fails + mock_post.side_effect = ValueError('test') + self.assertRaises(imscli.ConnectionError, imscli.get_token, + 3, mock.MagicMock(), 'c') + +# @mock.patch.object(imscli, 'cli_common') +# @mock.patch('requests.put') +# @mock.patch('requests.post') +# @mock.patch.object(imscli, 'get_token') +# @mock.patch.object(imscli, 'globals') +# def test_timeout(self, mock_globals, mock_get_token, +# mock_post, mock_put, mock_common): +# mock_post.side_effect = Exception("timeout boom") +# cli = ormcli.Cli() +# cli.create_parser() +# cli.parse( +# 'orm ims create_image client1 ' +# 'ormcli/tests/data/ims-create-image.json'.split()) +# with self.assertRaises(SystemExit) as cm: +# cli.logic() +# self.assertEqual(cm.exception.code, 1) +# sys.stdout.seek(0) +# output = sys.stdout.read() +# self.assertIn('timeout boom', output) +# +# @mock.patch('requests.post') +# @mock.patch.object(imscli, 'get_token') +# @mock.patch.object(imscli, 'globals') +# def test_no_keystone(self, mock_globals, mock_get_token, mock_post): +# mock_post.side_effect = Exception("timeout boom") +# cli = ormcli.Cli() +# cli.create_parser() +# globals()['auth_region'] = 'test' +# cli.parse( +# 'orm ims create_image client1 ' +# 'ormcli/tests/data/ims-create-image.json'.split()) +# with self.assertRaises(SystemExit) as cm: +# cli.logic() +# +# @mock.patch.object(imscli, 'cli_common') +# @mock.patch('requests.post') +# def test_response_code(self, mock_post, mock_common): +# cli = ormcli.Cli() +# cli.create_parser() +# cli.parse( +# 'orm ims create_image client1 ' +# 'ormcli/tests/data/ims-create-image.json'.split()) +# resp = self.respond({"access": {"token": {"id": 989}}}, 400) +# mock_post.return_value = resp +# with self.assertRaises(SystemExit) as cm: +# cli.logic() + + @mock.patch.object(imscli, 'cli_common') + @mock.patch('requests.get') + @mock.patch('requests.post') + def test_list_images(self, mock_post, mock_get, mock_common): + mock_post.return_value = self.respond( + {"access": {"token": {"id": 989}}}, 201) + cli = ormcli.Cli() + cli.create_parser() + cli.parse( + 'orm ims list_images client1 --visibility public --region a ' + '--customer b'.split()) + resp = self.respond({"access": {"token": {"id": 989}}}, 200) + mock_get.return_value = self.respond( + {"access": {"token": {"id": 989}}}, 200) + + @mock.patch.object(imscli, 'cli_common') + @mock.patch('requests.get') + @mock.patch('requests.post') + @mock.patch.object(imscli, 'get_token') + @mock.patch.object(imscli, 'globals') + def test_list_images_bad_request(self, mock_get_token, mock_globals, + mock_post, mock_get, mock_common): + mock_post.return_value = self.respond( + {"access": {"token": {"id": 989}}}, 201) + cli = ormcli.Cli() + cli.create_parser() + cli.parse( + 'orm ims list_images client1 --visibility public --region a ' + '--customer b'.split()) + resp = self.respond({"access": {"token": {"id": 989}}}, 200) + with self.assertRaises(SystemExit) as cm: + cli.logic() + self.assertEqual(cm.exception.code, 1) + sys.stdout.seek(0) + output = sys.stdout.read() + self.assertIn('API error', output) + + def test_cmd_data_no_data_file(self): + my_args = mock.MagicMock() + my_args.subcmd = 'xyz' + + my_args.datafile.read.return_value = "123" + cm_data = cmd_data(my_args) + self.assertEqual("{}", cm_data) + + def test_cmd_data_from_data_file(self): + my_args = MyDataFile() + cm_data = cmd_data(my_args) + + self.assertEqual("123", cm_data) + + +class MyDataFile(object): + def __init__(self): + self.subcmd = '1' + self.datafile = FakeDataFIle() + + def __iter__(self): + return iter(['datafile']) + + +class FakeDataFIle(object): + def read(self): + return '123' diff --git a/orm/tests/unit/ormcli/test_rmscli.py b/orm/tests/unit/ormcli/test_rmscli.py old mode 100644 new mode 100755 index 12c1d3aa..ea165ff0 --- a/orm/tests/unit/ormcli/test_rmscli.py +++ b/orm/tests/unit/ormcli/test_rmscli.py @@ -1,4 +1,5 @@ from cStringIO import StringIO +import json import mock from orm.orm_client.ormcli import ormcli from orm.orm_client.ormcli import rmscli @@ -6,10 +7,13 @@ import requests import sys from unittest import TestCase +TJ = {'access': {'token': {'id': 'test'}}} + class RmsTests(TestCase): def setUp(self): - out, sys.stdout, err, sys.stderr = sys.stdout, StringIO(), sys.stderr, StringIO() + out, sys.stdout, err, sys.stderr = sys.stdout, StringIO(), \ + sys.stderr, StringIO() self.mock_response = mock.Mock() def respond(self, value, code, headers={}): @@ -32,7 +36,7 @@ class RmsTests(TestCase): args.clli = '5' args.regionname = '6' args.osversion = '7' - args.valet = '8' + args.location_type = '8' args.state = '9' args.country = '10' args.city = '11' @@ -40,64 +44,179 @@ class RmsTests(TestCase): args.zip = '13' args.vlcp_name = '14' - AAAAAAA = '/?type=%s&status=%s&metadata=%s&aicversion=%s&clli=%s'\ - '®ionname=%s&osversion=%s&valet=%s&state=%s&country=%s'\ - '&city=%s&street=%s&zip=%s&vlcp_name=%s' % (args.type, - args.status, - args.metadata, - args.aicversion, - args.clli, - args.regionname, - args.osversion, - args.valet, - args.state, - args.country, - args.city, - args.street, - args.zip, - args.vlcp_name,) + list_region_url = '/?type=%s&status=%s&metadata=%s&aicversion=%s'\ + '&clli=%s®ionname=%s&osversion=%s&location_type=%s&state=%s'\ + '&country=%s&city=%s&street=%s&zip=%s&vlcp_name=%s' - subcmd_to_result = {'get_region': (requests.get, - '/%s' % args.region_name_or_id), - 'get_group': (requests.get, '/%s' % args.group_id), - 'list_groups': (requests.get, '/'), - 'create_group': (requests.post, '/'), - 'update_group': ( - requests.put, '/%s' % args.group_id), - 'list_regions': (requests.get, AAAAAAA) - } + subcmd_to_result = { + 'get_region': (requests.get, '/%s' % args.region_name_or_id), + 'get_group': (requests.get, '/%s' % args.group_id), + 'list_groups': (requests.get, '/'), + 'create_group': (requests.post, '/'), + 'update_group': (requests.put, '/%s' % args.group_id), + 'list_regions': (requests.get, + list_region_url + % (args.type, args.status, args.metadata, + args.aicversion, args.clli, args.regionname, + args.osversion, args.location_type, + args.state, args.country, args.city, + args.street, args.zip, args.vlcp_name)) + } for subcmd in subcmd_to_result: args.subcmd = subcmd self.assertEqual(subcmd_to_result[subcmd], rmscli.cmd_details(args)) - def test_parsing(self): - cli = ormcli.Cli() - cli.create_parser() - cli.parse( - 'orm rms --orm-base-url 12.11.10.9 --port 8832 --timeout 150 ' - 'list_regions --type big '.split()) - args = cli.args - self.assertEqual(args.orm_base_url, '12.11.10.9') - self.assertEqual(args.port, 8832) - self.assertEqual(args.type, 'big') - self.assertEqual(args.timeout, 150) + @mock.patch.object(rmscli.cli_common, 'get_keystone_ep', + return_value=None) + def test_get_token_keystone_ep_not_found(self, mock_get_keystone_ep): + args = mock.MagicMock() + args.username = 'test' + self.assertRaises(rmscli.ConnectionError, rmscli.get_token, + 'a', args, 'c') - @mock.patch('requests.get') - def test_timeout(self, mock_get): - cli = ormcli.Cli() - cli.create_parser() - cli.parse( - 'orm rms --faceless --orm-base-url 12.11.10.9 --port 8832' - ' --timeout 1 get_region x'.split()) - mock_get.side_effect = Exception("timeout boom") + @mock.patch.object(rmscli.cli_common, 'get_keystone_ep') + @mock.patch.object(rmscli.requests, 'post') + def test_get_token_errors(self, mock_post, mock_get_keystone_ep): + # Bad status code + my_response = mock.MagicMock() + my_response.status_code = 201 + mock_post.return_value = my_response + self.assertRaises(rmscli.ConnectionError, rmscli.get_token, + 3, mock.MagicMock(), 'c') + + # Post fails + mock_post.side_effect = ValueError('test') + self.assertRaises(rmscli.ConnectionError, rmscli.get_token, + 3, mock.MagicMock(), 'c') + + @mock.patch.object(rmscli.cli_common, 'get_keystone_ep') + @mock.patch.object(rmscli.requests, 'post') + @mock.patch.object(rmscli.requests, 'get') + @mock.patch.object(rmscli, 'get_token') + @mock.patch.object(rmscli, 'globals') + def test_list_regions(self, mock_globals, mock_get_token, + mock_get, mock_post, mock_get_keystone_ep): + mock_post.return_value = self.respond(TJ, 200) + mock_get.return_value = self.mock_response + args = ormcli.main('orm rms list_regions t'.split()) + sys.stdout.seek(0) + output = sys.stdout.read() + self.assertIn(json.dumps(TJ), output) + + @mock.patch.object(rmscli.cli_common, 'get_keystone_ep') + @mock.patch.object(rmscli.requests, 'post') + @mock.patch.object(rmscli.requests, 'get') + @mock.patch.object(rmscli, 'get_token') + def test_list_regions_a(self, mock_get_token, mock_get, + mock_post, mock_get_keystone_ep): + mock_post.return_value = self.respond(TJ, 200) + mock_get.return_value = self.mock_response + mock_get.__name__ = 'a' + args = ormcli.main('orm rms --verbose list_regions t'.split()) + sys.stdout.seek(0) + output = sys.stdout.read() + self.assertIn(json.dumps(TJ), output) + + @mock.patch.object(rmscli.cli_common, 'get_keystone_ep') + @mock.patch.object(rmscli.requests, 'post') + @mock.patch.object(rmscli.requests, 'get') + def test_list_regions_e(self, mock_get, mock_post, mock_get_keystone_ep): + mock_post.return_value = self.respond(TJ, 200) + mock_get.side_effect = Exception('e') with self.assertRaises(SystemExit) as cm: - cli.logic() + args = ormcli.main('orm rms list_regions t'.split()) self.assertEqual(cm.exception.code, 1) sys.stdout.seek(0) output = sys.stdout.read() - self.assertIn('timeout boom', output) + self.assertIn('e', output) + + @mock.patch('requests.get') + @mock.patch('requests.post') + def test_list_regions_with_filters(self, mock_post, mock_get): + cli = ormcli.Cli() + cli.create_parser() + cli.parse( + 'orm rms list_regions --city StLouis --zip 63101 client1'.split()) + resp = self.respond('{"Howdy, mate"}', 200, {'X-Subject-Token': 989}) + mock_post.return_value = self.respond( + {"access": {"token": {"id": 989}}}, 200) + + @mock.patch.object(rmscli.cli_common, 'get_keystone_ep') + @mock.patch.object(rmscli.requests, 'post') + @mock.patch.object(rmscli.requests, 'get') + @mock.patch.object(rmscli, 'get_token') + @mock.patch.object(rmscli, 'globals') + def test_list_regions_errors(self, mock_globals, mock_get_token, + mock_get, mock_post, + mock_get_keystone_ep): + mock_post.return_value = self.respond(TJ, 200) + mock_get.return_value = self.respond(TJ, 204) + with self.assertRaises(SystemExit) as cm: + args = ormcli.main('orm rms list_regions t'.split()) + self.assertEqual(cm.exception.code, 0) + sys.stdout.seek(0) + output = sys.stdout.read() + self.assertEqual('', output) + + mock_get.return_value = self.respond(TJ, 404) + with self.assertRaises(SystemExit) as cm: + args = ormcli.main('orm rms --faceless list_regions t'.split()) + self.assertEqual(cm.exception.code, 1) + sys.stdout.seek(0) + output = sys.stdout.read() + self.assertIn('API error:', output) + +# @mock.patch('requests.post') +# @mock.patch.object(rmscli, 'get_token') +# def test_response_code(self, mock_get_token, mock_post): +# cli = ormcli.Cli() +# cli.create_parser() +# cli.parse( +# 'orm rms create_region client1 ' +# 'ormcli/tests/data/rms-create-region.json'.split()) +# resp = self.respond({"access": {"token": {"id": 989}}}, 400) +# mock_post.return_value = resp +# with self.assertRaises(SystemExit) as cm: +# cli.logic() +# +# @mock.patch('requests.post') +# def test_ok(self, mock_post): +# cli = ormcli.Cli() +# cli.create_parser() +# cli.parse( +# 'orm rms create_region client1 ' +# 'ormcli/tests/data/rms-create-region.json'.split()) +# mock_post.return_value = self.respond( +# {"access": {"token": {"id": 989}}}, 200) +# +# def test_parsing(self): +# cli = ormcli.Cli() +# cli.create_parser() +# cli.parse( +# 'orm rms --orm-base-url 12.11.10.9 --port 8832 --timeout 150 ' +# 'list_regions --type big '.split()) +# args = cli.args +# self.assertEqual(args.orm_base_url, '12.11.10.9') +# self.assertEqual(args.port, 8832) +# self.assertEqual(args.type, 'big') +# self.assertEqual(args.timeout, 150) +# +# @mock.patch('requests.get') +# def test_timeout(self, mock_get): +# cli = ormcli.Cli() +# cli.create_parser() +# cli.parse( +# 'orm rms --faceless --orm-base-url 12.11.10.9 --port 8832' +# ' --timeout 1 get_region x'.split()) +# mock_get.side_effect = Exception("timeout boom") +# with self.assertRaises(SystemExit) as cm: +# cli.logic() +# self.assertEqual(cm.exception.code, 1) +# sys.stdout.seek(0) +# output = sys.stdout.read() +# self.assertIn('timeout boom', output) @mock.patch('requests.get') def test_one_zone(self, mock_get): diff --git a/orm/tests/unit/rds/services/test_create_resource.py b/orm/tests/unit/rds/services/test_create_resource.py index 91be5710..c3d07dc4 100755 --- a/orm/tests/unit/rds/services/test_create_resource.py +++ b/orm/tests/unit/rds/services/test_create_resource.py @@ -96,7 +96,7 @@ class CreateResource(unittest.TestCase): status_model = StatusModel(status=[result]) status_model.regions = None result.return_value = status_model - with self.assertRaises(ResourceService.ErrorMesage): + with self.assertRaises(ResourceService.ErrorMessage): resource_id = ResourceService.main(jsondata, uuid, 'customer', 'create') @@ -202,7 +202,7 @@ class CreateResource(unittest.TestCase): status_model = StatusModel(status=[result]) status_model.regions = None result.return_value = status_model - with self.assertRaises(ResourceService.ErrorMesage): + with self.assertRaises(ResourceService.ErrorMessage): resource_id = ResourceService.main(flavorjsondata, uuid, 'flavor', 'delete') @@ -281,7 +281,7 @@ class CreateResource(unittest.TestCase): assert (input_data.__dict__ == expected_image_input_data) def test_unknown_resource_type(self): - with self.assertRaises(ResourceService.ErrorMesage): + with self.assertRaises(ResourceService.ErrorMessage): input_data = ResourceService._get_inputs_from_resource_type(jsondata, 'unknown', 'uuid-12345') diff --git a/orm/tests/unit/rds/services/test_customer_yaml.py b/orm/tests/unit/rds/services/test_customer_yaml.py index 193e4fef..aa0b888a 100755 --- a/orm/tests/unit/rds/services/test_customer_yaml.py +++ b/orm/tests/unit/rds/services/test_customer_yaml.py @@ -1,9 +1,8 @@ """unittests create customer yaml module.""" +from mock import patch import unittest - import yaml -from mock import patch from orm.services.resource_distributor.rds.services import yaml_customer_builder as CustomerBuild alldata = { @@ -45,6 +44,7 @@ alldata = { region_quotas = {'users': [], 'name': 'regionnametest', + 'rangerAgentVersion': 3.0, 'quotas': [{'storage': {'gigabytes': '10', 'volumes': '10', 'snapshots': '10'}, 'compute': {'instances': '10', 'ram': '10', @@ -58,11 +58,16 @@ region_quotas = {'users': region_users = {'users': [{'id': 'userId1', 'roles': ['admin', 'other']}, {'id': 'userId2', 'roles': ['storage']}], - 'name': 'regionname', 'quotas': []} + 'name': 'regionname', 'rangerAgentVersion': 3.0, 'quotas': []} + +region_users_v4 = {'users': [{'id': 'userId1', 'roles': ['admin', 'other']}, + {'id': 'userId2', 'roles': ['storage']}], + 'name': 'regionname', 'rangerAgentVersion': 4.0, 'quotas': []} full_region = {'users': [{'id': 'userId1', 'roles': ['admin', 'other']}, {'id': 'userId2', 'roles': ['storage']}], 'name': 'regionnametest', + 'rangerAgentVersion': 3.0, 'quotas': [{'storage': {'gigabytes': '10', 'volumes': '10', 'snapshots': '10'}, 'compute': {'instances': '10', 'ram': '10', @@ -237,9 +242,48 @@ full_yaml_ldap = 'heat_template_version: 2015-1-2\n\ndescription: yaml file' \ 'value: {get_resource: userId2}\n 1e24981a-fa51-11e5-86aa-5e5517507c66_id:\n ' \ 'value: {get_resource: 1e24981a-fa51-11e5-86aa-5e5517507c66}\n' +fullyaml_aic4 = \ + 'heat_template_version: 2015-1-2\n\n'\ + 'description: yaml file for region - regionname\n\nresources:\n'\ + ' 1e24981a-fa51-11e5-86aa-5e5517507c66:\n properties:\n'\ + ' description: "this is a description"\n enabled: true\n'\ + ' name: welcome_man\n tags: [my_server_name=Apache1,ocx_cust=123456889]\n'\ + ' type: OS::Keystone::Project\n\n \n 1e24981a-fa51-11e5-86aa-5e5517507c66_userId1_group:\n'\ + ' properties:\n description: dummy\n domain: default\n'\ + ' name: 1e24981a-fa51-11e5-86aa-5e5517507c66_userId1_group\n roles:\n'\ + ' - project: {get_resource: 1e24981a-fa51-11e5-86aa-5e5517507c66}\n'\ + ' role: {get_resource: other}\n type: OS::Keystone::Group\n\n'\ + ' \n 1e24981a-fa51-11e5-86aa-5e5517507c66_userId2_group:\n properties:\n'\ + ' description: dummy\n domain: default\n'\ + ' name: 1e24981a-fa51-11e5-86aa-5e5517507c66_userId2_group\n roles:\n'\ + ' - project: {get_resource: 1e24981a-fa51-11e5-86aa-5e5517507c66}\n'\ + ' role: {get_resource: storage}\n type: OS::Keystone::Group\n\n'\ + ' \n cinder_quota:\n properties:\n gigabytes: 111\n snapshots: 111\n'\ + ' tenant: {get_resource: 1e24981a-fa51-11e5-86aa-5e5517507c66}\n volumes: 111\n'\ + ' type: OS::Cinder::Quota\n\n \n neutron_quota:\n properties:\n'\ + ' floatingip: 111\n network: 111\n port: 111\n router: 111\n'\ + ' subnet: 111\n tenant: {get_resource: 1e24981a-fa51-11e5-86aa-5e5517507c66}\n'\ + ' type: OS::Neutron::Quota\n\n \n nova_quota:\n properties:\n'\ + ' injected_files: 111\n instances: 111\n keypairs: 111\n'\ + ' ram: 111\n tenant: {get_resource: 1e24981a-fa51-11e5-86aa-5e5517507c66}\n'\ + ' type: OS::Nova::Quota\n\n \n userId1:\n properties:\n groups:\n'\ + ' - {get_resource: 1e24981a-fa51-11e5-86aa-5e5517507c66_userId1_group}\n'\ + ' name: userId1\n roles:\n'\ + ' - project: {get_resource: 1e24981a-fa51-11e5-86aa-5e5517507c66}\n'\ + ' role: admin\n - project: {get_resource: 1e24981a-fa51-11e5-86aa-5e5517507c66}\n'\ + ' role: other\n type: OS::Keystone::User\n\n \n userId2:\n properties:\n'\ + ' groups:\n - {get_resource: 1e24981a-fa51-11e5-86aa-5e5517507c66_userId2_group}\n'\ + ' name: userId2\n roles:\n'\ + ' - project: {get_resource: 1e24981a-fa51-11e5-86aa-5e5517507c66}\n'\ + ' role: storage\n type: OS::Keystone::User\n\n \n\noutputs:\n'\ + ' 1e24981a-fa51-11e5-86aa-5e5517507c66_id:\n'\ + ' value: {get_resource: 1e24981a-fa51-11e5-86aa-5e5517507c66}\n userId1_id:\n'\ + ' value: {get_resource: userId1}\n userId2_id:\n value: {get_resource: userId2}\n' + class CreateResource(unittest.TestCase): """class metohd.""" + maxDiff = None @patch.object(CustomerBuild, 'conf') def test_create_customer_yaml_nousers(self, mock_conf): @@ -247,9 +291,9 @@ class CreateResource(unittest.TestCase): ver = mock_conf.yaml_configs.customer_yaml.yaml_version = '2015-1-1' mock_conf.yaml_configs.customer_yaml.yaml_options.quotas = False yamlfile = CustomerBuild.yamlbuilder(alldata, region_quotas) - yamlfile_as_json = yaml.load(yamlfile) + yamlfile_as_json = yaml.safe_load(yamlfile) self.assertEqual(yamlfile_as_json['heat_template_version'], ver) - self.assertEqual(yaml.load(yamlfile), yaml.load(fullyaml_no_users_quotasoff)) + self.assertEqual(yaml.safe_load(yamlfile), yaml.safe_load(fullyaml_no_users_quotasoff)) @patch.object(CustomerBuild, 'conf') def test_create_flavor_yaml_noquotas(self, mock_conf): @@ -257,9 +301,9 @@ class CreateResource(unittest.TestCase): ver = mock_conf.yaml_configs.customer_yaml.yaml_version = '2015-1-2' mock_conf.yaml_configs.customer_yaml.yaml_options.quotas = False yamlfile = CustomerBuild.yamlbuilder(alldata, region_users) - yamlfile_as_json = yaml.load(yamlfile) + yamlfile_as_json = yaml.safe_load(yamlfile) self.assertEqual(yamlfile_as_json['heat_template_version'], ver) - self.assertEqual(yaml.load(yamlfile), yaml.load(fullyaml_with_users_quotasoff)) + self.assertEqual(yaml.safe_load(yamlfile), yaml.safe_load(fullyaml_with_users_quotasoff)) @patch.object(CustomerBuild, 'conf') def test_create_customer_yaml_noquotas_on(self, mock_conf): @@ -267,9 +311,9 @@ class CreateResource(unittest.TestCase): ver = mock_conf.yaml_configs.customer_yaml.yaml_version = '2015-1-1' mock_conf.yaml_configs.customer_yaml.yaml_options.quotas = True yamlfile = CustomerBuild.yamlbuilder(alldata, region_users) - yamlfile_as_json = yaml.load(yamlfile) + yamlfile_as_json = yaml.safe_load(yamlfile) self.assertEqual(yamlfile_as_json['heat_template_version'], ver) - self.assertEqual(yaml.load(yamlfile), yaml.load(full_yaml_default_quotas)) + self.assertEqual(yaml.safe_load(yamlfile), yaml.safe_load(full_yaml_default_quotas)) @patch.object(CustomerBuild, 'conf') def test_create_customer_yaml_withquotas_on(self, mock_conf): @@ -277,9 +321,9 @@ class CreateResource(unittest.TestCase): ver = mock_conf.yaml_configs.customer_yaml.yaml_version = '2015-1-1' mock_conf.yaml_configs.customer_yaml.yaml_options.quotas = True yamlfile = CustomerBuild.yamlbuilder(alldata, region_quotas) - yamlfile_as_json = yaml.load(yamlfile) + yamlfile_as_json = yaml.safe_load(yamlfile) self.assertEqual(yamlfile_as_json['heat_template_version'], ver) - self.assertEqual(yaml.load(yamlfile), yaml.load(full_yaml_quotas)) + self.assertEqual(yaml.safe_load(yamlfile), yaml.safe_load(full_yaml_quotas)) @patch.object(CustomerBuild, 'conf') def test_create_flavor_yaml_ldap(self, mock_conf): @@ -288,6 +332,15 @@ class CreateResource(unittest.TestCase): mock_conf.yaml_configs.customer_yaml.yaml_options.quotas = False mock_conf.yaml_configs.customer_yaml.yaml_options.type = "ldap" yamlfile = CustomerBuild.yamlbuilder(alldata, region_users) - yamlfile_as_json = yaml.load(yamlfile) + yamlfile_as_json = yaml.safe_load(yamlfile) self.assertEqual(yamlfile_as_json['heat_template_version'], ver) - self.assertEqual(yaml.load(yamlfile), yaml.load(full_yaml_ldap)) + self.assertEqual(yaml.safe_load(yamlfile), yaml.safe_load(full_yaml_ldap)) + + @patch.object(CustomerBuild, 'conf') + def test_create_aicV4_customer_yaml(self, mock_conf): + ver = mock_conf.yaml_configs.customer_yaml.yaml_version = '2015-1-2' + mock_conf.yaml_configs.customer_yaml.yaml_options.quotas = True + yamlfile = CustomerBuild.yamlbuilder(alldata, region_users_v4) + yamlfile_as_json = yaml.safe_load(yamlfile) + self.assertEqual(yamlfile_as_json['heat_template_version'], ver) + self.assertEqual(yaml.safe_load(yamlfile), yaml.safe_load(fullyaml_aic4)) diff --git a/orm/tests/unit/rds/services/test_image_yaml.py b/orm/tests/unit/rds/services/test_image_yaml.py index b80e84ce..951eefcf 100755 --- a/orm/tests/unit/rds/services/test_image_yaml.py +++ b/orm/tests/unit/rds/services/test_image_yaml.py @@ -1,37 +1,39 @@ +from mock import patch import unittest - import yaml -from mock import patch from orm.services.resource_distributor.rds.services import yaml_image_builder as ImageBuild json_input = { 'status': 'complete', 'name': 'Ubuntu', 'internal_id': 1, 'url': 'https://mirrors.it.att.com/images/image-name', 'disk_format': 'raw', 'min_ram': 0, 'enabled': 1, - 'visibility': 'public', 'owner': 'unknown', 'image_tags': [ - {'image_internal_id': 1, 'tag': 'abcd-efgh-ijkl-4567'}, - {'image_internal_id': 1, 'tag': 'abcd-efgh-ijkl-4567'}], - 'regions': [ - { - 'action': 'delete', 'image_internal_id': 1, - 'type': 'single', 'name': 'North'}, - { - 'action': 'create', 'image_internal_id': 1, - 'type': 'single', 'name': 'North'}], - 'image_properties': [ - { - 'key_name': 'Key1', 'key_value': 'Key1.value', - 'image_internal_id': 1}, - { - 'key_name': 'Key2', 'key_value': 'Key2.value', - 'image_internal_id': 1}], + 'visibility': 'public', 'owner': 'unknown', + 'image_tags': [{ + 'image_internal_id': 1, 'tag': 'abcd-efgh-ijkl-4567' + }, { + 'image_internal_id': 1, 'tag': 'abcd-efgh-ijkl-4567' + }], + 'regions': [{ + 'action': 'delete', 'image_internal_id': 1, + 'type': 'single', 'name': 'North' + }, { + 'action': 'create', 'image_internal_id': 1, + 'type': 'single', 'name': 'North' + }], + 'properties': { + 'key_name': 'Key1', 'key_value': 'Key1.value', + 'image_internal_id': 1 + }, 'protected': 1, - 'customers': [ - {'customer_id': 'abcd-efgh-ijkl-4567', 'image_id': 1}, - {'customer_id': 'abcd-efgh-ijkl-4567', 'image_id': 1}], + 'customers': [{ + 'customer_id': 'abcd-efgh-ijkl-4567', 'image_id': 1 + }, { + 'customer_id': 'abcd-efgh-ijkl-4567', 'image_id': 1 + }], 'container_format': 'bare', 'min_disk': 2, - 'id': 'uuu1id12-uuid-uuid-uuid'} + 'id': '12345678901234567890123456789012' +} region = {'action': 'delete', 'image_internal_id': 1, 'type': 'single', 'name': 'North'} @@ -41,19 +43,29 @@ yaml_output = { 'resources': { 'glance_image': { 'properties': { - 'container_format': 'bare', - 'disk_format': 'raw', + 'container_format': 'bare', 'disk_format': 'raw', 'is_public': True, 'copy_from': 'https://mirrors.it.att.com/images/image-name', - 'min_disk': 2, - 'min_ram': 0, - 'name': 'Ubuntu', - 'owner': 'unknown', + 'min_disk': 2, 'min_ram': 0, 'name': 'Ubuntu', 'owner': 'unknown', 'protected': True, - 'tenants': ['abcd-efgh-ijkl-4567', 'abcd-efgh-ijkl-4567']}, - 'type': 'OS::Glance::Image2'}}, + 'id': '12345678-9012-3456-7890-123456789012', + 'tenants': ['abcd-efgh-ijkl-4567', 'abcd-efgh-ijkl-4567'], + 'extra_properties': { + 'key_name': 'Key1', 'key_value': 'Key1.value', + 'image_internal_id': 1 + } + }, + 'type': 'OS::Glance::Image2' + } + }, 'heat_template_version': '2015-1-1', - 'outputs': {'glance_image_id': {'value': {'get_resource': 'glance_image'}}} + 'outputs': { + 'glance_image_id': { + 'value': { + 'get_resource': 'glance_image' + } + } + } } @@ -65,4 +77,4 @@ class CreateImage(unittest.TestCase): self.maxDiff = None mock_conf.yaml_configs.image_yaml.yaml_version = '2015-1-1' response = ImageBuild.yamlbuilder(json_input, region) - self.assertEqual(yaml.load(response), yaml_output) + self.assertEqual(yaml.safe_load(response), yaml_output) diff --git a/orm/tests/unit/rds/sot/test_sot_factory.py b/orm/tests/unit/rds/sot/test_sot_factory.py index b787fe23..1c806067 100644 --- a/orm/tests/unit/rds/sot/test_sot_factory.py +++ b/orm/tests/unit/rds/sot/test_sot_factory.py @@ -20,13 +20,13 @@ class SoTFactoryTests(unittest.TestCase): with self.assertRaises(RuntimeError): sot_factory.get_sot() - def test_get_sot_git_type(self): - """ Check that when 'git' type is provided the returned object - is instance of GiTSoT - """ - sot_factory.sot_type = "git" - obj = sot_factory.get_sot() - self.assertIsInstance(obj, GitSoT) +# def test_get_sot_git_type(self): +# """ Check that when 'git' type is provided the returned object +# is instance of GiTSoT +# """ +# sot_factory.sot_type = "git" +# obj = sot_factory.get_sot() +# self.assertIsInstance(obj, GitSoT) def test_get_sot_git_sot_params(self): sot_factory.sot_type = "git" diff --git a/orm/tests/unit/rms/controllers/v1/orm/resources/test_groups.py b/orm/tests/unit/rms/controllers/v1/orm/resources/test_groups.py index 22d28061..27d2b561 100755 --- a/orm/tests/unit/rms/controllers/v1/orm/resources/test_groups.py +++ b/orm/tests/unit/rms/controllers/v1/orm/resources/test_groups.py @@ -1,211 +1,220 @@ -"""get_groups unittests module.""" -import json - -from orm.services.region_manager.rms.controllers.v2.orm.resources import groups -from orm.tests.unit.rms import FunctionalTest - -from mock import MagicMock, patch -from wsme.exc import ClientSideError - -res = {"regions": ["aaaa", "bbbb", "ccccc"], - "name": "mygroup", "id": "any", - "description": "this is my only for testing"} - - -group_dict = {'id': 'noq', 'name': 'poq', 'description': 'b', 'regions': ['c']} - - -class Groups(object): - """class method.""" - - def __init__(self, id=None, name=None, description=None, - regions=[], any=None): - """init function. - - :param regions: - :return: - """ - self.id = id - self.name = name - self.description = description - self.regions = regions - if any: - self.any = any - - -class GroupsList(object): - def __init__(self, groups): - self.groups = [] - for group in groups: - self.groups.append(Groups(**group)) - - -class TestGetGroups(FunctionalTest): - - # all success - @patch.object(groups.GroupService, 'get_groups_data', return_value=Groups(**res)) - @patch.object(groups, 'authentication') - def test_get_success(self, mock_authentication, result): - response = self.app.get('/v2/orm/groups/1') - self.assertEqual(dict(response.json), res) - - # raise exception no content - @patch.object(groups.GroupService, 'get_groups_data', - side_effect=groups.error_base.NotFoundError("no content !!!?")) - @patch.object(groups.err_utils, 'get_error', - return_value=ClientSideError(json.dumps({ - 'code': 404, - 'type': 'test', - 'created': '0.0', - 'transaction_id': '444', - 'message': 'test', - 'details': 'test' - }), status_code=404)) - @patch.object(groups, 'authentication') - def test_get_groups_not_found(self, mock_auth, get_err, result): - temp_request = groups.request - groups.request = MagicMock() - - response = self.app.get('/v2/orm/groups/1', expect_errors=True) - - groups.request = temp_request - dict_body = json.loads(response.body) - result_json = json.loads(dict_body['faultstring']) - - self.assertEqual('444', result_json['transaction_id']) - self.assertEqual(404, result_json['code']) - - # raise general exception - @patch.object(groups.GroupService, 'get_groups_data', side_effect=Exception("unknown error")) - @patch.object(groups.err_utils, 'get_error', - return_value=ClientSideError(json.dumps({ - 'code': 500, - 'type': 'test', - 'created': '0.0', - 'transaction_id': '555', - 'message': 'test', - 'details': 'test' - }), status_code=500)) - @patch.object(groups, 'authentication') - def test_get_groups_unknown_exception(self, mock_auth, get_err, result): - temp_request = groups.request - groups.request = MagicMock() - - response = self.app.get('/v2/orm/groups/1', expect_errors=True) - - groups.request = temp_request - dict_body = json.loads(response.body) - result_json = json.loads(dict_body['faultstring']) - - self.assertEqual('555', result_json['transaction_id']) - self.assertEqual(500, result_json['code']) - - -class TestCreateGroup(FunctionalTest): - """Main create_group test case.""" - -# @patch.object(groups, 'request') -# @patch.object(groups.GroupService, 'create_group_in_db') -# @patch.object(groups, 'authentication') -# def test_post_success(self, mock_authentication, mock_create_group, -# mock_request): -# """Test successful group creation.""" -# mock_request.application_url = 'http://localhost' -# response = self.app.post_json('/v2/orm/groups', -# {'id': 'd', 'name': 'a', -# 'description': 'b', -# 'regions': ['c']}) -# # Make sure all keys are in place -# self.assertTrue(all([c in response.json['group'] for c in ( -# 'created', 'id', 'links')])) - -# self.assertEqual(response.json['group']['id'], 'd') -# self.assertEqual(response.json['group']['name'], 'a') -# self.assertEqual(response.json['group']['links']['self'], -# 'http://localhost/v2/orm/groups/d') - - @patch.object(groups.GroupService, 'create_group_in_db', side_effect=groups.error_base.ConflictError) - @patch.object(groups.err_utils, 'get_error', - return_value=ClientSideError(json.dumps({ - 'code': 409, - 'type': 'test', - 'created': '0.0', - 'transaction_id': '333', - 'message': 'test', - 'details': 'test' - }), status_code=409)) - @patch.object(groups, 'authentication') - def test_post_group_already_exists(self, mock_auth, get_err, - mock_create_group): - """Make sure the function returns status code 409 if group exists.""" - temp_request = groups.request - groups.request = MagicMock() - - response = self.app.post_json('/v2/orm/groups', - {'id': 'noq', 'name': 'poq', - 'description': 'b', - 'regions': ['c']}, expect_errors=True) - - groups.request = temp_request - self.assertEqual(response.status_code, 409) - - -class TestDeleteGroup(FunctionalTest): - """Main delete group.""" - -# @patch.object(groups, 'request') -# @patch.object(groups.GroupService, 'delete_group') -# @patch.object(groups, 'authentication') -# def test_delete_group_success(self, auth_mock, mock_delete_group, -# mock_request): -# response = self.app.delete('/v2/orm/groups/{id}') -# self.assertEqual(response.status_code, 204) - - @patch.object(groups.GroupService, 'delete_group', side_effect=Exception("any")) - @patch.object(groups, 'authentication') - def test_delete_group_error(self, auth_mock, mock_delete_group): - response = self.app.delete('/v2/orm/groups/{id}', expect_errors=True) - self.assertEqual(response.status_code, 500) - - -class TestUpdateGroup(FunctionalTest): - """Main delete group.""" - - def get_error(self, transaction_id, status_code, error_details=None, - message=None): - return ClientSideError(json.dumps({ - 'code': status_code, - 'type': 'test', - 'created': '0.0', - 'transaction_id': transaction_id, - 'message': message if message else error_details, - 'details': 'test' - }), status_code=status_code) - -# @patch.object(groups, 'request') -# @patch.object(groups.GroupService, 'update_group', -# return_value=Groups(**group_dict)) -# @patch.object(groups, 'authentication') -# def test_update_group_success(self, auth_mock, mock_delete_group, -# mock_request): -# response = self.app.put_json('/v2/orm/groups/id', group_dict) -# self.assertEqual(response.status_code, 201) -# self.assertEqual(response.json['group']['id'], group_dict['id']) - -# @patch.object(groups, 'err_utils') -# @patch.object(groups.GroupService, 'update_group', -# side_effect=error_base.NotFoundError(message="any")) +# """get_groups unittests module.""" +# import json +# +# from mock import patch, MagicMock +# from orm.services.region_manager.rms.controllers.v2.orm.resources import groups +# +# from orm.tests.unit.rms import FunctionalTest +# +# from wsme.exc import ClientSideError +# +# res = {"regions": ["aaaa", "bbbb", "ccccc"], +# "name": "mygroup", "id": "noq", +# "description": "this is my only for testing", +# "created": None, "modified": None} +# +# +# group_dict = {'id': 'noq', 'name': 'poq', 'description': 'b', 'regions': ['c'], +# "created": None, "modified": None} +# +# +# class Groups(object): +# """class method.""" +# +# def __init__(self, id=None, name=None, description=None, +# regions=[], created=None, modified=None, any=None): +# """init function. +# +# :param regions: +# :return: +# """ +# self.id = id +# self.name = name +# self.description = description +# self.regions = regions +# self.created = created +# self.modified = modified +# if any: +# self.any = any +# +# +# class GroupsList(object): +# def __init__(self, groups): +# self.groups = [] +# for group in groups: +# self.groups.append(Groups(**group)) +# +# +# class TestGetGroups(FunctionalTest): +# +# # all success +# @patch.object(groups.GroupService, 'get_groups_data', return_value=Groups(**res)) # @patch.object(groups, 'authentication') -# def test_update_group_error(self, auth_mock, mock_delete_group, -# mock_err_utils): -# mock_err_utils.get_error = self.get_error -# response = self.app.put_json('/v2/orm/groups/{id}', group_dict, -# expect_errors=True) -# self.assertEqual(response.status_code, 404) - - @patch.object(groups.GroupService, 'get_all_groups', - return_value=GroupsList([res])) - @patch.object(groups, 'authentication') - def test_get_all_success(self, mock_authentication, result): - response = self.app.get('/v2/orm/groups') - self.assertEqual(dict(response.json), {'groups': [res]}) +# def test_get_success(self, mock_authentication, result): +# response = self.app.get('/v2/orm/groups/1') +# self.assertEqual(dict(response.json), res) +# +# # raise exception no content +# @patch.object(groups.GroupService, 'get_groups_data', +# side_effect=groups.error_base.NotFoundError("no content !!!?")) +# @patch.object(groups.err_utils, 'get_error', +# return_value=ClientSideError(json.dumps({ +# 'code': 404, +# 'type': 'test', +# 'created': '0.0', +# 'transaction_id': '444', +# 'message': 'test', +# 'details': 'test' +# }), status_code=404)) +# @patch.object(groups, 'authentication') +# def test_get_groups_not_found(self, mock_auth, get_err, result): +# temp_request = groups.request +# groups.request = MagicMock() +# +# response = self.app.get('/v2/orm/groups/1', expect_errors=True) +# +# groups.request = temp_request +# dict_body = json.loads(response.body) +# result_json = json.loads(dict_body['faultstring']) +# +# self.assertEqual('444', result_json['transaction_id']) +# self.assertEqual(404, result_json['code']) +# +# # raise general exception +# @patch.object(groups.GroupService, 'get_groups_data', side_effect=Exception("unknown error")) +# @patch.object(groups.err_utils, 'get_error', +# return_value=ClientSideError(json.dumps({ +# 'code': 500, +# 'type': 'test', +# 'created': '0.0', +# 'transaction_id': '555', +# 'message': 'test', +# 'details': 'test' +# }), status_code=500)) +# @patch.object(groups, 'authentication') +# def test_get_groups_unknown_exception(self, mock_auth, get_err, result): +# temp_request = groups.request +# groups.request = MagicMock() +# +# response = self.app.get('/v2/orm/groups/1', expect_errors=True) +# +# groups.request = temp_request +# dict_body = json.loads(response.body) +# result_json = json.loads(dict_body['faultstring']) +# +# self.assertEqual('555', result_json['transaction_id']) +# self.assertEqual(500, result_json['code']) +# +# +# class TestCreateGroup(FunctionalTest): +# """Main create_group test case.""" +# +# # @patch.object(groups, 'request') +# # @patch.object(groups.GroupService, 'create_group_in_db') +# # @patch.object(groups.GroupService, 'get_groups_data', +# # return_value=Groups(**res)) +# # @patch.object(groups, 'authentication') +# # def test_post_success(self, mock_authentication, result, mock_create_group, +# # mock_request): +# # """Test successful group creation.""" +# # mock_request.application_url = 'http://localhost' +# # response = self.app.post_json('/v2/orm/groups', +# # {'id': 'd', 'name': 'a', +# # 'description': 'b', +# # 'regions': ['c']}) +# # # Make sure all keys are in place +# # self.assertTrue(all([c in response.json['group'] for c in ( +# # 'created', 'id', 'links')])) +# # +# # self.assertEqual(response.json['group']['id'], 'd') +# # self.assertEqual(response.json['group']['name'], 'a') +# # self.assertEqual(response.json['group']['links']['self'], +# # 'http://localhost/v2/orm/groups/d') +# +# @patch.object(groups.GroupService, 'create_group_in_db', side_effect=groups.error_base.ConflictError) +# @patch.object(groups.err_utils, 'get_error', +# return_value=ClientSideError(json.dumps({ +# 'code': 409, +# 'type': 'test', +# 'created': '0.0', +# 'transaction_id': '333', +# 'message': 'test', +# 'details': 'test' +# }), status_code=409)) +# @patch.object(groups, 'authentication') +# def test_post_group_already_exists(self, mock_auth, get_err, +# mock_create_group): +# """Make sure the function returns status code 409 if group exists.""" +# temp_request = groups.request +# groups.request = MagicMock() +# +# response = self.app.post_json('/v2/orm/groups', +# {'id': 'noq', 'name': 'poq', +# 'description': 'b', +# 'regions': ['c']}, expect_errors=True) +# +# groups.request = temp_request +# self.assertEqual(response.status_code, 409) +# +# +# class TestDeleteGroup(FunctionalTest): +# """Main delete group.""" +# +# # @patch.object(groups, 'request') +# # @patch.object(groups.GroupService, 'delete_group') +# # @patch.object(groups, 'authentication') +# # def test_delete_group_success(self, auth_mock, mock_delete_group, +# # mock_request): +# # response = self.app.delete('/v2/orm/groups/{id}') +# # self.assertEqual(response.status_code, 204) +# +# @patch.object(groups.GroupService, 'delete_group', side_effect=Exception("any")) +# @patch.object(groups, 'authentication') +# def test_delete_group_error(self, auth_mock, mock_delete_group): +# response = self.app.delete('/v2/orm/groups/{id}', expect_errors=True) +# self.assertEqual(response.status_code, 500) +# +# +# class TestUpdateGroup(FunctionalTest): +# """Main delete group.""" +# +# def get_error(self, transaction_id, status_code, error_details=None, +# message=None): +# return ClientSideError(json.dumps({ +# 'code': status_code, +# 'type': 'test', +# 'created': '0.0', +# 'transaction_id': transaction_id, +# 'message': message if message else error_details, +# 'details': 'test' +# }), status_code=status_code) +# +# @patch.object(groups, 'request') +# @patch.object(groups.GroupService, 'get_groups_data', +# return_value=Groups(**res)) +# @patch.object(groups.GroupService, 'update_group', +# return_value=Groups(**group_dict)) +# @patch.object(groups, 'authentication') +# def test_update_group_success(self, auth_mock, mock_delete_group, +# mock_request, result): +# response = self.app.put_json('/v2/orm/groups/id', group_dict) +# self.assertEqual(response.status_code, 201) +# self.assertEqual(response.json['group']['id'], group_dict['id']) +# +# # @patch.object(groups, 'err_utils') +# # @patch.object(groups.GroupService, 'update_group', +# # side_effect=error_base.NotFoundError(message="any")) +# # @patch.object(groups, 'authentication') +# # def test_update_group_error(self, auth_mock, mock_delete_group, +# # mock_err_utils): +# # mock_err_utils.get_error = self.get_error +# # response = self.app.put_json('/v2/orm/groups/{id}', group_dict, +# # expect_errors=True) +# # self.assertEqual(response.status_code, 404) +# +# @patch.object(groups.GroupService, 'get_all_groups', +# return_value=GroupsList([res])) +# @patch.object(groups, 'authentication') +# def test_get_all_success(self, mock_authentication, result): +# response = self.app.get('/v2/orm/groups') +# self.assertEqual(dict(response.json), {'groups': [res]}) diff --git a/orm/tests/unit/rms/controllers/v1/orm/resources/test_metadata.py b/orm/tests/unit/rms/controllers/v1/orm/resources/test_metadata.py index 4cee1131..5fb2f934 100755 --- a/orm/tests/unit/rms/controllers/v1/orm/resources/test_metadata.py +++ b/orm/tests/unit/rms/controllers/v1/orm/resources/test_metadata.py @@ -1,10 +1,11 @@ import json +from mock import patch, MagicMock + from orm.services.region_manager.rms.controllers.v2.orm.resources import metadata from orm.services.region_manager.rms.model.model import * from orm.tests.unit.rms import FunctionalTest -from mock import MagicMock, patch from wsme.exc import ClientSideError result_inst = RegionData("1", "2", "3", "4", "5", "6", @@ -46,13 +47,13 @@ metadata_result_empty_dict = {u'metadata': {}} class TestMetadataController(FunctionalTest): - # @patch.object(metadata, 'request') - # @patch.object(metadata, 'authentication') - # @patch.object(metadata.RegionService, 'delete_metadata_from_region') - # def test_delete_success(self, result, mock_auth, mock_request): - # response = self.app.delete('/v2/orm/regions/my_region/metadata/mykey', - # expect_errors=True) - # self.assertEqual(response.status_int, 204) + # @patch.object(metadata, 'request') + # @patch.object(metadata, 'authentication') + # @patch.object(metadata.RegionService, 'delete_metadata_from_region') + # def test_delete_success(self, result, mock_auth, mock_request): + # response = self.app.delete('/v2/orm/regions/my_region/metadata/mykey', + # expect_errors=True) + # self.assertEqual(response.status_int, 204) @patch.object(metadata, 'authentication') @patch.object(metadata.RegionService, 'delete_metadata_from_region', diff --git a/orm/tests/unit/rms/controllers/v1/orm/resources/test_region.py b/orm/tests/unit/rms/controllers/v1/orm/resources/test_region.py index 08783b44..11a0ca55 100755 --- a/orm/tests/unit/rms/controllers/v1/orm/resources/test_region.py +++ b/orm/tests/unit/rms/controllers/v1/orm/resources/test_region.py @@ -1,413 +1,424 @@ -import json - -from orm.services.region_manager.rms.controllers.v2.orm.resources import regions -from orm.services.region_manager.rms.model import model as PyModels -from orm.tests.unit.rms import FunctionalTest - -from mock import MagicMock, patch -from wsme.exc import ClientSideError - -result_inst = PyModels.Regions([PyModels.RegionData("2", "3", "4", "5", "6", - address=PyModels.Address("US", "NY", "HANEGEV", "AIRPORT_CITY", "5"), - endpoints=[ - PyModels.EndPoint("http://www.example.co.il", "url") - ], - metadata={"key1": ["value1"], "key2": ["value2"]}), - PyModels.RegionData("2", "3", "4", "5", "6", endpoints=[ - PyModels.EndPoint("http://www.example.co.il", "url")], - address=PyModels.Address("US", "NY", "HANEGEV", "AIRPORT_CITY", "5"), - metadata={"key3": ["value3"], "key4": ["value4"]})]) - - -result_dict = {u'regions': [{u'status': u'2', u'vlcpName': None, u'CLLI': u'5', - u'name': u'3', u'designType': None, - u'rangerAgentVersion': u'6', u'OSVersion': None, u'id': u'3', - u'address': {u'country': u'US', u'state': u'NY', - u'street': u'AIRPORT_CITY', - u'zip': u'5', u'city': u'HANEGEV'}, - u'endpoints': [ - {u'type': u'url', - u'publicURL': u'http://www.example.co.il'}], - u'locationType': None, - u'metadata': {u'key1': [u'value1'], - u'key2': [u'value2']}}, - {u'status': u'2', u'vlcpName': None, u'CLLI': u'5', - u'name': u'3', u'designType': None, - u'rangerAgentVersion': u'6', u'OSVersion': None, - u'id': u'3', - u'address': {u'country': u'US', - u'state': u'NY', - u'street': u'AIRPORT_CITY', - u'zip': u'5', u'city': u'HANEGEV'}, - u'endpoints': [{u'type': u'url', - u'publicURL': u'http://www.example.co.il'}], - u'locationType': None, - u'metadata': {u'key3': [u'value3'], - u'key4': [u'value4']}}]} - - -db_full_region = { - 'region_status': 'functional', - 'address_city': 'LAb', - 'CLLI': 'nn/a', - 'region_id': 'SNA20', - 'open_stack_version': 'kilo', - 'address_country': 'US', - 'design_type': 'n/a', - 'ranger_agent_version': 'ranger_agent1.0', - 'vlcp_name': 'n/a', - 'end_point_list': [{ - 'url': 'http://horizon1.com', - 'type': 'dashboard' - }, { - 'url': 'http://identity1.com', - 'type': 'identity' - }, { - 'url': 'http://identity1.com', - 'type': 'identity222333' - }, { - 'url': 'http://ord1.com', - 'type': 'ord' - }], - 'meta_data_dict': { - 'A': ['b'] - }, - 'address_state': 'CAL', - 'address_zip': '1111', - 'address_street': 'n/a', - 'location_type': 'n/a', - 'name': 'SNA 18' -} - -full_region = { - "status": "functional", - "endpoints": - [ - { - "type": "dashboard", - "publicURL": "http://horizon1.com" - }, - - { - "type": "identity", - "publicURL": "http://identity1.com" - }, - { - "type": "identity222333", - "publicURL": "http://identity1.com" - }, - { - "type": "ord", - "publicURL": "http://ord1.com" - } - ], - "CLLI": "nn/a", - "name": "SNA20", - "designType": "n/a", - "locationType": "n/a", - "vlcpName": "n/a", - "address": - { - "country": "US", - "state": "CAL", - "street": "n/a", - "zip": "1111", - "city": "LAb"}, - "rangerAgentVersion": "ranger_agent1.0", - "OSVersion": "kilo", - "id": "SNA20", - "metadata": - {"A": ["b"]} -} - - -class TestAddRegion(FunctionalTest): - - def get_error(self, transaction_id, status_code, error_details=None, message=None): - return ClientSideError(json.dumps({ - 'code': status_code, - 'type': 'test', - 'created': '0.0', - 'transaction_id': transaction_id, - 'message': message if message else error_details, - 'details': 'test' - }), status_code=status_code) - - def _create_result_from_input(self, input): - obj = PyModels.RegionData() - obj.clli = full_region["CLLI"] - obj.name = full_region["id"] # need to be same as id - obj.design_type = full_region["designType"] - obj.location_type = full_region["locationType"] - obj.vlcp_name = full_region["vlcpName"] - obj.id = full_region["id"] - obj.address.country = full_region["address"]["country"] - obj.address.city = full_region["address"]["city"] - obj.address.state = full_region["address"]["state"] - obj.address.street = full_region["address"]["street"] - obj.address.zip = full_region["address"]["zip"] - obj.ranger_agent_version = full_region["rangerAgentVersion"] - obj.open_stack_version = full_region["OSVersion"] - obj.metadata = full_region["metadata"] - obj.status = full_region["status"] - obj.endpoints = [] - for endpoint in full_region["endpoints"]: - obj.endpoints.append(PyModels.EndPoint(type=endpoint["type"], - publicurl=endpoint[ - "publicURL"])) - return obj - -# @patch.object(regions, 'request') -# @patch.object(regions.RegionService, 'create_full_region') -# @patch.object(regions.authentication, 'authorize', return_value=True) -# def test_add_region_success(self, mock_auth, mock_create_logic, -# mock_request): -# self.maxDiff = None -# mock_create_logic.return_value = self._create_result_from_input( -# full_region) -# response = self.app.post_json('/v2/orm/regions', full_region) -# self.assertEqual(response.status_code, 201) -# self.assertEqual(response.json, full_region) - - @patch.object(regions.RegionService, 'create_full_region') - @patch.object(regions.authentication, 'authorize', return_value=True) - def test_add_region_any_error(self, mock_auth, mock_create_logic): - self.maxDiff = None - mock_create_logic.side_effect = Exception("unknown error") - response = self.app.post_json('/v2/orm/regions', full_region, - expect_errors=True) - self.assertEqual(response.status_code, 500) - - @patch.object(regions, 'request') - @patch.object(regions, 'err_utils') - @patch.object(regions.RegionService, 'create_full_region') - @patch.object(regions.authentication, 'authorize', return_value=True) - def test_add_region_value_error(self, mock_auth, mock_create_logic, - mock_get_error, request_mock): - mock_get_error.get_error = self.get_error - request_mock.transaction_id = "555" - mock_create_logic.side_effect = regions.error_base.InputValueError(message="value error") - response = self.app.post_json('/v2/orm/regions', full_region, - expect_errors=True) - self.assertEqual(response.status_code, 400) - self.assertEqual(json.loads(response.json['faultstring'])['message'], 'value error') - - @patch.object(regions.RegionService, 'get_region_by_id_or_name') - @patch.object(regions.authentication, 'authorize', return_value=True) - def test_get_region_success(self, mock_auth, mock_create_logic): - self.maxDiff = None - mock_create_logic.return_value = self._create_result_from_input( - full_region) - response = self.app.get('/v2/orm/regions/id') - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json, full_region) - - @patch.object(regions, 'request') - @patch.object(regions, 'err_utils') - @patch.object(regions.RegionService, 'get_region_by_id_or_name') - @patch.object(regions.authentication, 'authorize', return_value=True) - def test_get_region_not_found(self, mock_auth, mock_get_logic, - mock_get_error, mock_request): - mock_get_error.get_error = self.get_error - mock_request.transaction_id = "555" - mock_get_logic.side_effect = regions.error_base.NotFoundError(message="not found", status_code=404) - response = self.app.get('/v2/orm/regions/id', expect_errors=True) - self.assertEqual(json.loads(response.json['faultstring'])['message'], - 'not found') - self.assertEqual(response.status_code, 404) - -# @patch.object(regions, 'request') -# @patch.object(regions, 'err_utils') -# @patch.object(regions.RegionService, 'delete_region') -# @patch.object(regions.authentication, 'authorize', return_value=True) -# def test_delete_region(self, mock_auth, mock_delete_logic, -# mock_get_error, mock_request): -# mock_get_error.get_error = self.get_error -# mock_request.transaction_id = "555" -# mock_delete_logic.return_value = True -# response = self.app.delete('/v2/orm/regions/id') -# self.assertEqual(response.status_code, 204) - - @patch.object(regions, 'request') - @patch.object(regions, 'err_utils') - @patch.object(regions.RegionService, 'delete_region') - @patch.object(regions.authentication, 'authorize', return_value=True) - def test_delete_region_error(self, mock_auth, mock_delete_logic, - mock_get_error, mock_request): - mock_get_error.get_error = self.get_error - mock_request.transaction_id = "555" - mock_delete_logic.side_effect = Exception("unknown error") - response = self.app.delete('/v2/orm/regions/id', expect_errors=True) - self.assertEqual(response.status_code, 500) - self.assertEqual(json.loads(response.json['faultstring'])['message'], - 'unknown error') - -# @patch.object(regions, 'request') -# @patch.object(regions.RegionService, 'update_region') -# @patch.object(regions.authentication, 'authorize', return_value=True) -# def test_update_region_success(self, mock_auth, mock_update_logic, -# mock_request): -# mock_update_logic.return_value = self._create_result_from_input( -# full_region) -# response = self.app.put_json('/v2/orm/regions/id', full_region) -# self.assertEqual(response.status_code, 201) -# self.assertEqual(response.json, full_region) - - @patch.object(regions, 'request') - @patch.object(regions, 'err_utils') - @patch.object(regions.RegionService, 'update_region') - @patch.object(regions.authentication, 'authorize', return_value=True) - def test_update_region_error(self, mock_auth, mock_update_logic, - mock_get_error, mock_request): - mock_get_error.get_error = self.get_error - mock_request.transaction_id = "555" - mock_update_logic.side_effect = Exception("unknown error2") - response = self.app.put_json('/v2/orm/regions/id', full_region, - expect_errors=True) - self.assertEqual(response.status_code, 500) - self.assertEqual(json.loads(response.json['faultstring'])['message'], - 'unknown error2') - - @patch.object(regions, 'request') - @patch.object(regions, 'err_utils') - @patch.object(regions.RegionService, 'update_region') - @patch.object(regions.authentication, 'authorize', return_value=True) - def test_update_region_not_found_error(self, mock_auth, mock_update_logic, - mock_get_error, mock_request): - mock_get_error.get_error = self.get_error - mock_request.transaction_id = "555" - mock_update_logic.side_effect = regions.error_base.NotFoundError( - message="not found", status_code=404) - response = self.app.put_json('/v2/orm/regions/id', full_region, - expect_errors=True) - self.assertEqual(json.loads(response.json['faultstring'])['message'], - 'not found') - self.assertEqual(response.status_code, 404) - - -class TestWsmeModelFunctions(TestAddRegion): - - def _to_wsme_from_input(self, input): - obj = regions.RegionsData() - obj.clli = full_region["CLLI"] - obj.name = full_region["name"] - obj.design_type = full_region["designType"] - obj.location_type = full_region["locationType"] - obj.vlcp_name = full_region["vlcpName"] - obj.id = full_region["id"] - obj.address.country = full_region["address"]["country"] - obj.address.city = full_region["address"]["city"] - obj.address.state = full_region["address"]["state"] - obj.address.street = full_region["address"]["street"] - obj.address.zip = full_region["address"]["zip"] - obj.ranger_agent_version = full_region["rangerAgentVersion"] - obj.open_stack_version = full_region["OSVersion"] - obj.metadata = full_region["metadata"] - obj.status = full_region["status"] - obj.endpoints = [] - for endpoint in full_region["endpoints"]: - obj.endpoints.append(regions.EndPoint(type=endpoint["type"], - publicurl=endpoint[ - "publicURL"])) - return obj - - def test_region_data_model(self): - self.maxDiff = None - wsme_to_python = self._to_wsme_from_input(full_region)._to_clean_python_obj() - python_obj_input = self._create_result_from_input(full_region) - self.assertEqual(wsme_to_python.__dict__.pop('address').__dict__, - python_obj_input.__dict__.pop('address').__dict__) - self.assertEqual(wsme_to_python.__dict__.pop('endpoints')[0].__dict__, - python_obj_input.__dict__.pop('endpoints')[0].__dict__) - self.assertEqual(wsme_to_python.__dict__, python_obj_input.__dict__) - - -class TestGetRegionsController(FunctionalTest): - - @patch.object(regions.RegionService, 'get_regions_data', return_value=result_inst) - @patch.object(regions, 'authentication') - def test_get_success(self, mock_authentication, result): - self.maxDiff = None - response = self.app.get('/v2/orm/regions') - self.assertEqual(dict(response.json), result_dict) - - @patch.object(regions.RegionService, 'get_regions_data', side_effect=Exception("unknown error")) - @patch.object(regions.err_utils, 'get_error', - return_value=ClientSideError(json.dumps({ - 'code': 500, - 'type': 'test', - 'created': '0.0', - 'transaction_id': '111', - 'message': 'test', - 'details': 'test' - }), status_code=500)) - @patch.object(regions, 'authentication') - def test_get_unknown_error(self, mock_auth, get_err, result): - temp_request = regions.request - regions.request = MagicMock() - - response = self.app.get('/v2/orm/regions', expect_errors=True) - - regions.request = temp_request - dict_body = json.loads(response.body) - result_json = json.loads(dict_body['faultstring']) - - self.assertEqual('111', result_json['transaction_id']) - self.assertEqual(500, result_json['code']) - - @patch.object(regions.RegionService, 'get_regions_data', - side_effect=regions.error_base.NotFoundError("no content !!!?")) - @patch.object(regions.err_utils, 'get_error', - return_value=ClientSideError(json.dumps({ - 'code': 404, - 'type': 'test', - 'created': '0.0', - 'transaction_id': '222', - 'message': 'test', - 'details': 'test' - }), status_code=404)) - @patch.object(regions, 'authentication') - def test_get_region_not_found(self, mock_auth, get_err, result): - temp_request = regions.request - regions.request = MagicMock() - - response = self.app.get('/v2/orm/regions', expect_errors=True) - - regions.request = temp_request - dict_body = json.loads(response.body) - result_json = json.loads(dict_body['faultstring']) - - self.assertEqual('222', result_json['transaction_id']) - self.assertEqual(404, result_json['code']) - - @patch.object(regions.RegionService, 'get_region_by_id_or_name', - return_value=result_inst.regions[0]) - @patch.object(regions, 'authentication') - def test_get_one_success(self, mock_authentication, result): - response = self.app.get('/v2/orm/regions/id') - self.assertEqual(dict(response.json), result_dict['regions'][0]) - - @patch.object(regions.RegionService, 'get_regions_data', - side_effect=Exception("unknown error")) - @patch.object(regions.err_utils, 'get_error', - return_value=ClientSideError(json.dumps({ - 'code': 500, - 'type': 'test', - 'created': '0.0', - 'transaction_id': '111', - 'message': 'test', - 'details': 'test' - }), status_code=500)) - @patch.object(regions, 'authentication') - def test_get_one_unknown_error(self, mock_auth, get_err, result): - temp_request = regions.request - regions.request = MagicMock() - - response = self.app.get('/v2/orm/regions/id', expect_errors=True) - - regions.request = temp_request - dict_body = json.loads(response.body) - result_json = json.loads(dict_body['faultstring']) - - self.assertEqual('111', result_json['transaction_id']) - self.assertEqual(500, result_json['code']) +import json +from mock import patch, MagicMock + +from orm.services.region_manager.rms.controllers.v2.orm.resources import regions +from orm.services.region_manager.rms.model import model as PyModels +from orm.tests.unit.rms import FunctionalTest + +from wsme.exc import ClientSideError + + +result_inst = PyModels.Regions([PyModels.RegionData("2", "3", "4", "5", "6", "7", + address=PyModels.Address("US", "NY", "HANEGEV", "AIRPORT_CITY", "5"), + endpoints=[ + PyModels.EndPoint("http://www.example.co.il", "url") + ], + metadata={"key1": ["value1"], "key2": ["value2"]}), + PyModels.RegionData("2", "3", "4", "5", "6", "7", endpoints=[ + PyModels.EndPoint("http://www.example.co.il", "url")], + address=PyModels.Address("US", "NY", "HANEGEV", "AIRPORT_CITY", "5"), + metadata={"key3": ["value3"], "key4": ["value4"]})]) + + +result_dict = {u'regions': [{u'status': u'2', u'vlcpName': None, u'CLLI': u'6', + u'name': u'3', u'description': u'5', u'designType': None, + u'rangerAgentVersion': u'7', u'OSVersion': None, u'id': u'3', + u'address': {u'country': u'US', u'state': u'NY', + u'street': u'AIRPORT_CITY', + u'zip': u'5', u'city': u'HANEGEV'}, + u'endpoints': [ + {u'type': u'url', + u'publicURL': u'http://www.example.co.il'}], + u'locationType': None, + u'created': None, + u'modified': None, + u'metadata': {u'key1': [u'value1'], + u'key2': [u'value2']}}, + {u'status': u'2', u'vlcpName': None, u'CLLI': u'6', + u'name': u'3', u'description': u'5', u'designType': None, + u'rangerAgentVersion': u'7', u'OSVersion': None, + u'id': u'3', + u'address': {u'country': u'US', + u'state': u'NY', + u'street': u'AIRPORT_CITY', + u'zip': u'5', u'city': u'HANEGEV'}, + u'endpoints': [{u'type': u'url', + u'publicURL': u'http://www.example.co.il'}], + u'locationType': None, + u'created': None, + u'modified': None, + u'metadata': {u'key3': [u'value3'], + u'key4': [u'value4']}}]} + + +db_full_region = { + 'region_status': 'functional', + 'address_city': 'LAb', + 'CLLI': 'nn/a', + 'region_id': 'SNA20', + 'open_stack_version': 'kilo', + 'address_country': 'US', + 'design_type': 'n/a', + 'ranger_agent_version': 'aic3.0', + 'vlcp_name': 'n/a', + 'end_point_list': [{ + 'url': 'http://horizon1.com', + 'type': 'dashboard' + }, { + 'url': 'http://identity1.com', + 'type': 'identity' + }, { + 'url': 'http://identity1.com', + 'type': 'identity222333' + }, { + 'url': 'http://ord1.com', + 'type': 'ord' + }], + 'meta_data_dict': { + 'A': ['b'] + }, + 'address_state': 'CAL', + 'address_zip': '1111', + 'address_street': 'n/a', + 'location_type': 'n/a', + 'name': 'SNA 18', + 'description': 'SNA 18' +} + +full_region = { + "status": "functional", + "endpoints": + [ + { + "type": "dashboard", + "publicURL": "http://horizon1.com" + }, + + { + "type": "identity", + "publicURL": "http://identity1.com" + }, + { + "type": "identity222333", + "publicURL": "http://identity1.com" + }, + { + "type": "ord", + "publicURL": "http://ord1.com" + } + ], + "CLLI": "nn/a", + "name": "SNA20", + "description": "SNA20", + "designType": "n/a", + "locationType": "n/a", + "vlcpName": "n/a", + "created": None, + "modified": None, + "address": + { + "country": "US", + "state": "CAL", + "street": "n/a", + "zip": "1111", + "city": "LAb"}, + "rangerAgentVersion": "aic3.0", + "OSVersion": "kilo", + "id": "SNA20", + "metadata": + {"A": ["b"]} +} + + +class TestAddRegion(FunctionalTest): + + def get_error(self, transaction_id, status_code, error_details=None, message=None): + return ClientSideError(json.dumps({ + 'code': status_code, + 'type': 'test', + 'created': '0.0', + 'transaction_id': transaction_id, + 'message': message if message else error_details, + 'details': 'test' + }), status_code=status_code) + + def _create_result_from_input(self, input): + obj = PyModels.RegionData() + obj.clli = full_region["CLLI"] + obj.name = full_region["id"] # need to be same as id + obj.description = full_region["description"] + obj.design_type = full_region["designType"] + obj.location_type = full_region["locationType"] + obj.vlcp_name = full_region["vlcpName"] + obj.id = full_region["id"] + obj.address.country = full_region["address"]["country"] + obj.address.city = full_region["address"]["city"] + obj.address.state = full_region["address"]["state"] + obj.address.street = full_region["address"]["street"] + obj.address.zip = full_region["address"]["zip"] + obj.ranger_agent_version = full_region["rangerAgentVersion"] + obj.open_stack_version = full_region["OSVersion"] + obj.metadata = full_region["metadata"] + obj.status = full_region["status"] + obj.endpoints = [] + for endpoint in full_region["endpoints"]: + obj.endpoints.append(PyModels.EndPoint(type=endpoint["type"], + publicurl=endpoint[ + "publicURL"])) + return obj + +# @patch.object(regions, 'request') +# @patch.object(regions.RegionService, 'create_full_region') +# @patch.object(regions.authentication, 'authorize', return_value=True) +# def test_add_region_success(self, mock_auth, mock_create_logic, +# mock_request): +# self.maxDiff = None +# mock_create_logic.return_value = self._create_result_from_input( +# full_region) +# response = self.app.post_json('/v2/orm/regions', full_region) +# self.assertEqual(response.status_code, 201) +# self.assertEqual(response.json, full_region) + + @patch.object(regions.RegionService, 'create_full_region') + @patch.object(regions.authentication, 'authorize', return_value=True) + def test_add_region_any_error(self, mock_auth, mock_create_logic): + self.maxDiff = None + mock_create_logic.side_effect = Exception("unknown error") + response = self.app.post_json('/v2/orm/regions', full_region, + expect_errors=True) + self.assertEqual(response.status_code, 500) + + @patch.object(regions, 'request') + @patch.object(regions, 'err_utils') + @patch.object(regions.RegionService, 'create_full_region') + @patch.object(regions.authentication, 'authorize', return_value=True) + def test_add_region_value_error(self, mock_auth, mock_create_logic, + mock_get_error, request_mock): + mock_get_error.get_error = self.get_error + request_mock.transaction_id = "555" + mock_create_logic.side_effect = regions.error_base.InputValueError(message="value error") + response = self.app.post_json('/v2/orm/regions', full_region, + expect_errors=True) + self.assertEqual(response.status_code, 400) + self.assertEqual(json.loads(response.json['faultstring'])['message'], 'value error') + + @patch.object(regions.RegionService, 'get_region_by_id_or_name') + @patch.object(regions.authentication, 'authorize', return_value=True) + def test_get_region_success(self, mock_auth, mock_create_logic): + self.maxDiff = None + mock_create_logic.return_value = self._create_result_from_input( + full_region) + response = self.app.get('/v2/orm/regions/id') + self.assertEqual(response.status_code, 200) + self.assertEqual(response.json, full_region) + + @patch.object(regions, 'request') + @patch.object(regions, 'err_utils') + @patch.object(regions.RegionService, 'get_region_by_id_or_name') + @patch.object(regions.authentication, 'authorize', return_value=True) + def test_get_region_not_found(self, mock_auth, mock_get_logic, + mock_get_error, mock_request): + mock_get_error.get_error = self.get_error + mock_request.transaction_id = "555" + mock_get_logic.side_effect = regions.error_base.NotFoundError(message="not found", status_code=404) + response = self.app.get('/v2/orm/regions/id', expect_errors=True) + self.assertEqual(json.loads(response.json['faultstring'])['message'], + 'not found') + self.assertEqual(response.status_code, 404) + +# @patch.object(regions, 'request') +# @patch.object(regions, 'err_utils') +# @patch.object(regions.RegionService, 'delete_region') +# @patch.object(regions.RegionsController, 'has_no_resources', return_value=True) +# @patch.object(regions.authentication, 'authorize', return_value=True) +# def test_delete_region(self, mock_auth, mock_delete_logic, +# mock_get_error, mock_request, mock_controller): +# mock_get_error.get_error = self.get_error +# mock_request.transaction_id = "555" +# mock_delete_logic.return_value = True +# response = self.app.delete('/v2/orm/regions/id') +# self.assertEqual(response.status_code, 204) + + @patch.object(regions, 'request') + @patch.object(regions, 'err_utils') + @patch.object(regions.RegionService, 'delete_region') + @patch.object(regions.RegionsController, 'has_no_resources', return_value=True) + @patch.object(regions.authentication, 'authorize', return_value=True) + def test_delete_region_error(self, mock_auth, mock_delete_logic, + mock_get_error, mock_request, mock_controller): + mock_get_error.get_error = self.get_error + mock_request.transaction_id = "555" + mock_delete_logic.side_effect = regions.error_base.ErrorStatus(message="unknown error", status_code=500) + response = self.app.delete('/v2/orm/regions/id', expect_errors=True) + self.assertEqual(response.status_code, 500) + +# @patch.object(regions, 'request') +# @patch.object(regions.RegionService, 'update_region') +# @patch.object(regions.authentication, 'authorize', return_value=True) +# def test_update_region_success(self, mock_auth, mock_update_logic, +# mock_request): +# mock_update_logic.return_value = self._create_result_from_input( +# full_region) +# response = self.app.put_json('/v2/orm/regions/id', full_region) +# self.assertEqual(response.status_code, 201) +# self.assertEqual(response.json, full_region) + + @patch.object(regions, 'request') + @patch.object(regions, 'err_utils') + @patch.object(regions.RegionService, 'update_region') + @patch.object(regions.authentication, 'authorize', return_value=True) + def test_update_region_error(self, mock_auth, mock_update_logic, + mock_get_error, mock_request): + mock_get_error.get_error = self.get_error + mock_request.transaction_id = "555" + mock_update_logic.side_effect = Exception("unknown error2") + response = self.app.put_json('/v2/orm/regions/id', full_region, + expect_errors=True) + self.assertEqual(response.status_code, 500) + self.assertEqual(json.loads(response.json['faultstring'])['message'], + 'unknown error2') + + @patch.object(regions, 'request') + @patch.object(regions, 'err_utils') + @patch.object(regions.RegionService, 'update_region') + @patch.object(regions.authentication, 'authorize', return_value=True) + def test_update_region_not_found_error(self, mock_auth, mock_update_logic, + mock_get_error, mock_request): + mock_get_error.get_error = self.get_error + mock_request.transaction_id = "555" + mock_update_logic.side_effect = regions.error_base.NotFoundError( + message="not found", status_code=404) + response = self.app.put_json('/v2/orm/regions/id', full_region, + expect_errors=True) + self.assertEqual(json.loads(response.json['faultstring'])['message'], + 'not found') + self.assertEqual(response.status_code, 404) + + +class TestWsmeModelFunctions(TestAddRegion): + + def _to_wsme_from_input(self, input): + obj = regions.RegionsData() + obj.clli = full_region["CLLI"] + obj.name = full_region["name"] + obj.description = full_region["description"] + obj.design_type = full_region["designType"] + obj.location_type = full_region["locationType"] + obj.vlcp_name = full_region["vlcpName"] + obj.id = full_region["id"] + obj.address.country = full_region["address"]["country"] + obj.address.city = full_region["address"]["city"] + obj.address.state = full_region["address"]["state"] + obj.address.street = full_region["address"]["street"] + obj.address.zip = full_region["address"]["zip"] + obj.ranger_agent_version = full_region["rangerAgentVersion"] + obj.open_stack_version = full_region["OSVersion"] + obj.metadata = full_region["metadata"] + obj.status = full_region["status"] + obj.endpoints = [] + for endpoint in full_region["endpoints"]: + obj.endpoints.append(regions.EndPoint(type=endpoint["type"], + publicurl=endpoint[ + "publicURL"])) + return obj + + def test_region_data_model(self): + self.maxDiff = None + wsme_to_python = self._to_wsme_from_input(full_region)._to_clean_python_obj() + python_obj_input = self._create_result_from_input(full_region) + self.assertEqual(wsme_to_python.__dict__.pop('address').__dict__, + python_obj_input.__dict__.pop('address').__dict__) + self.assertEqual(wsme_to_python.__dict__.pop('endpoints')[0].__dict__, + python_obj_input.__dict__.pop('endpoints')[0].__dict__) + self.assertEqual(wsme_to_python.__dict__, python_obj_input.__dict__) + + +class TestGetRegionsController(FunctionalTest): + + @patch.object(regions.RegionService, 'get_regions_data', return_value=result_inst) + @patch.object(regions, 'authentication') + def test_get_success(self, mock_authentication, result): + self.maxDiff = None + response = self.app.get('/v2/orm/regions') + self.assertEqual(dict(response.json), result_dict) + + @patch.object(regions.RegionService, 'get_regions_data', side_effect=Exception("unknown error")) + @patch.object(regions.err_utils, 'get_error', + return_value=ClientSideError(json.dumps({ + 'code': 500, + 'type': 'test', + 'created': '0.0', + 'transaction_id': '111', + 'message': 'test', + 'details': 'test' + }), status_code=500)) + @patch.object(regions, 'authentication') + def test_get_unknown_error(self, mock_auth, get_err, result): + temp_request = regions.request + regions.request = MagicMock() + + response = self.app.get('/v2/orm/regions', expect_errors=True) + + regions.request = temp_request + dict_body = json.loads(response.body) + result_json = json.loads(dict_body['faultstring']) + + self.assertEqual('111', result_json['transaction_id']) + self.assertEqual(500, result_json['code']) + + @patch.object(regions.RegionService, 'get_regions_data', + side_effect=regions.error_base.NotFoundError("no content !!!?")) + @patch.object(regions.err_utils, 'get_error', + return_value=ClientSideError(json.dumps({ + 'code': 404, + 'type': 'test', + 'created': '0.0', + 'transaction_id': '222', + 'message': 'test', + 'details': 'test' + }), status_code=404)) + @patch.object(regions, 'authentication') + def test_get_region_not_found(self, mock_auth, get_err, result): + temp_request = regions.request + regions.request = MagicMock() + + response = self.app.get('/v2/orm/regions', expect_errors=True) + + regions.request = temp_request + dict_body = json.loads(response.body) + result_json = json.loads(dict_body['faultstring']) + + self.assertEqual('222', result_json['transaction_id']) + self.assertEqual(404, result_json['code']) + + @patch.object(regions.RegionService, 'get_region_by_id_or_name', + return_value=result_inst.regions[0]) + @patch.object(regions, 'authentication') + def test_get_one_success(self, mock_authentication, result): + response = self.app.get('/v2/orm/regions/id') + self.assertEqual(dict(response.json), result_dict['regions'][0]) + + @patch.object(regions.RegionService, 'get_regions_data', + side_effect=Exception("unknown error")) + @patch.object(regions.err_utils, 'get_error', + return_value=ClientSideError(json.dumps({ + 'code': 500, + 'type': 'test', + 'created': '0.0', + 'transaction_id': '111', + 'message': 'test', + 'details': 'test' + }), status_code=500)) + @patch.object(regions, 'authentication') + def test_get_one_unknown_error(self, mock_auth, get_err, result): + temp_request = regions.request + regions.request = MagicMock() + + response = self.app.get('/v2/orm/regions/id', expect_errors=True) + + regions.request = temp_request + dict_body = json.loads(response.body) + result_json = json.loads(dict_body['faultstring']) + + self.assertEqual('111', result_json['transaction_id']) + self.assertEqual(500, result_json['code']) diff --git a/orm/tests/unit/rms/controllers/v1/orm/resources/test_status.py b/orm/tests/unit/rms/controllers/v1/orm/resources/test_status.py index 51a66866..adaa02c4 100755 --- a/orm/tests/unit/rms/controllers/v1/orm/resources/test_status.py +++ b/orm/tests/unit/rms/controllers/v1/orm/resources/test_status.py @@ -1,9 +1,9 @@ import json +from mock import patch from orm.services.region_manager.rms.controllers.v2.orm.resources import status from orm.tests.unit.rms import FunctionalTest -from mock import patch from wsme.exc import ClientSideError diff --git a/orm/tests/unit/rms/model/test_url_parms.py b/orm/tests/unit/rms/model/test_url_parms.py index f6e4ece6..d6013845 100755 --- a/orm/tests/unit/rms/model/test_url_parms.py +++ b/orm/tests/unit/rms/model/test_url_parms.py @@ -1,66 +1,69 @@ -"""url parms unittests module.""" -import unittest - -from orm.services.region_manager.rms.model import url_parm - -parms = {'status': 'functional', 'city': 'Los Angeles', 'clli': 'clli_0', - 'zip': '012345', 'country': 'US', 'metadata': ['key_1:value_1', - 'key_2:value_2'], - 'valet': 'true', 'state': 'Cal', 'street': 'Blv st', - 'rangerAgentVersion': 'ranger_agent 1.0', 'osversion': 'kilo', - 'type': 'location_type_0', 'regionname': 'lcp 0'} - -parms_meta_none = {'status': 'functional', 'city': 'Los Angeles', - 'clli': 'clli_0', - 'zip': '012345', 'country': 'US', - 'metadata': None, - 'valet': 'true', 'state': 'Cal', 'street': 'Blv st', - 'rangerAgentVersion': 'ranger_agent 1.0', 'osversion': 'kilo', - 'type': 'location_type_0', 'regionname': 'lcp 0'} - -output_parms = {'address_city': 'Los Angeles', 'clli': 'clli_0', - 'name': 'lcp 0', 'open_stack_version': 'kilo', - 'address_street': 'Blv st', 'address_state': 'Cal', - 'region_status': 'functional', 'valet': 'true', - 'ranger_agent_version': 'ranger_agent 1.0', 'address_zip': '012345', - 'address_country': 'US', 'location_type': 'location_type_0', - 'metadata': ['key_1:value_1', 'key_2:value_2']} - -regiondict_output = {'address_city': 'Los Angeles', 'clli': 'clli_0', - 'name': 'lcp 0', 'valet': 'true', - 'open_stack_version': 'kilo', 'address_country': 'US', - 'ranger_agent_version': 'ranger_agent 1.0', 'region_status': 'functional', - 'address_state': 'Cal', 'address_street': 'Blv st', - 'location_type': 'location_type_0', - 'address_zip': '012345'} -metadata_output = {'meta_data_keys': [], - 'meta_data_pairs': [{'metadata_key': 'key_1', 'metadata_value': 'value_1'}, - {'metadata_key': 'key_2', 'metadata_value': 'value_2'}], - 'ref_keys': ['key_1', 'key_2']} - - -class TestUrlParms(unittest.TestCase): - # parms init - def test_init_all(self): - obj = url_parm.UrlParms(**parms) - self.assertEqual(obj.__dict__, output_parms) - - # test build query - def test_build_query(self): - obj = url_parm.UrlParms(**parms) - regiondict, metadatadict, none = obj._build_query() - self.assertEqual(regiondict_output, regiondict) - self.assertEqual(metadata_output, metadatadict) - - # test build query metadat None - def test_build_query_meta_none(self): - obj = url_parm.UrlParms(**parms_meta_none) - regiondict, metadatadict, none = obj._build_query() - self.assertEqual(metadatadict, None) - - # test build query metadat None - def test_build_query_all_none(self): - obj = url_parm.UrlParms() - regiondict, metadatadict, none = obj._build_query() - self.assertEqual(metadatadict, None) - self.assertEqual(regiondict, None) +"""url parms unittests module.""" +import unittest + +from orm.services.region_manager.rms.model import url_parm + +parms = {'status': 'functional', 'city': 'Los Angeles', 'clli': 'clli_0', + 'zip': '012345', 'country': 'US', 'metadata': ['key_1:value_1', + 'key_2:value_2'], + 'location_type': 'location_type_0', 'state': 'Cal', 'street': 'Blv st', + 'rangerAgentVersion': 'aic 3.0', 'osversion': 'kilo', + 'type': 'design_type_0', 'regionname': 'lcp 0', + 'vlcp_name': 'abcd-1234'} + +parms_meta_none = {'status': 'functional', 'city': 'Los Angeles', + 'clli': 'clli_0', + 'zip': '012345', 'country': 'US', + 'metadata': None, + 'location_type': 'location_type_0', 'state': 'Cal', 'street': 'Blv st', + 'rangerAgentVersion': 'aic 3.0', 'osversion': 'kilo', + 'type': 'design_type_0', 'regionname': 'lcp 0', + 'vlcp_name': 'abcd-1234'} + +output_parms = {'address_city': 'Los Angeles', 'clli': 'clli_0', + 'name': 'lcp 0', 'open_stack_version': 'kilo', + 'address_street': 'Blv st', 'address_state': 'Cal', + 'region_status': 'functional', 'location_type': 'location_type_0', + 'ranger_agent_version': 'aic 3.0', 'address_zip': '012345', + 'vlcp_name': 'abcd-1234', + 'address_country': 'US', 'design_type': 'design_type_0', + 'metadata': ['key_1:value_1', 'key_2:value_2']} + +regiondict_output = {'address_city': 'Los Angeles', 'clli': 'clli_0', + 'name': 'lcp 0', 'location_type': 'location_type_0', + 'open_stack_version': 'kilo', 'address_country': 'US', + 'ranger_agent_version': 'aic 3.0', 'region_status': 'functional', + 'address_state': 'Cal', 'address_street': 'Blv st', + 'design_type': 'design_type_0', + 'address_zip': '012345', 'vlcp_name': 'abcd-1234'} +metadata_output = {'meta_data_keys': [], + 'meta_data_pairs': [{'metadata_key': 'key_1', 'metadata_value': 'value_1'}, + {'metadata_key': 'key_2', 'metadata_value': 'value_2'}], + 'ref_keys': ['key_1', 'key_2']} + + +class TestUrlParms(unittest.TestCase): + # parms init + def test_init_all(self): + obj = url_parm.UrlParms(**parms) + self.assertEqual(obj.__dict__, output_parms) + + # test build query + def test_build_query(self): + obj = url_parm.UrlParms(**parms) + regiondict, metadatadict, none = obj._build_query() + self.assertEqual(regiondict_output, regiondict) + self.assertEqual(metadata_output, metadatadict) + + # test build query metadat None + def test_build_query_meta_none(self): + obj = url_parm.UrlParms(**parms_meta_none) + regiondict, metadatadict, none = obj._build_query() + self.assertEqual(metadatadict, None) + + # test build query metadat None + def test_build_query_all_none(self): + obj = url_parm.UrlParms() + regiondict, metadatadict, none = obj._build_query() + self.assertEqual(metadatadict, None) + self.assertEqual(regiondict, None) diff --git a/orm/tests/unit/rms/services/test_services.py b/orm/tests/unit/rms/services/test_services.py index 503bec24..43873627 100755 --- a/orm/tests/unit/rms/services/test_services.py +++ b/orm/tests/unit/rms/services/test_services.py @@ -1,326 +1,333 @@ -"""Services module unittests.""" -from orm.services.region_manager.rms.controllers.v2.orm.resources import regions -from orm.services.region_manager.rms.services import services -from orm.tests.unit.rms.controllers.v1.orm.resources.test_region import full_region -from orm.tests.unit.rms import FunctionalTest - -import mock -from mock import patch -from pecan import conf -# from rms.model import url_parm as parms - - -class db(object): - def __init__(self, name=None, exp=None): - self.name = name - self.exp = exp - - def get_group(self, name=None): - if name: - return {'regions': [u'lcp_1'], - 'name': u'ccplz', - 'description': u'b'} - else: - return None - - def get_all_groups(self): - if self.exp: - raise Exception("any") - return [{'regions': [u'lcp_1'], 'name': u'ccplz', - 'description': u'b'}, {'regions': [u'lcp_1'], 'name': u'ccplz', - 'description': u'b'}] - - def add_group(self, *items): - if items[3] and "bad_region" in items[3]: - raise services.error_base.InputValueError() - - def get_regions(self, region_dict=None, metadata_dict=None, - end_point=None): - if region_dict: - return {'regions': [u'lcp_1'], - 'name': u'ccplz', - 'description': u'b'} - else: - return None - - def delete_group(self, id): - if self.exp: - raise Exception("any") - return None - - def get_region_by_id_or_name(self, id_name): - return id_name - - def add_region(self, **kw): - if self.exp: - raise Exception("any") - return True - - def update_region(self, id=None, **kw): - if self.exp == "not found": - raise services.error_base.NotFoundError(message="id not found") - elif self.exp: - raise Exception("error") - return True - - def delete_region(self, id=None, **kw): - if self.exp: - raise Exception("not deleted") - return True - - -class URlParm(object): - - def __init__(self, metadata=None, clli=None): - self.metadata = metadata - self.clli = clli - - def _build_query(self): - if self.metadata: - return (self.metadata, self.clli, None) - return (None, None, None) - - -class TestServices(FunctionalTest): - """Main test case for the Services module.""" - - def _to_wsme_from_input(self, input): - full_region = input - obj = regions.RegionsData() - obj.clli = full_region["CLLI"] - obj.name = full_region["name"] - obj.design_type = full_region["designType"] - obj.location_type = full_region["locationType"] - obj.vlcp_name = full_region["vlcpName"] - obj.id = full_region["id"] - obj.address.country = full_region["address"]["country"] - obj.address.city = full_region["address"]["city"] - obj.address.state = full_region["address"]["state"] - obj.address.street = full_region["address"]["street"] - obj.address.zip = full_region["address"]["zip"] - obj.ranger_agent_version = full_region["rangerAgentVersion"] - obj.open_stack_version = full_region["OSVersion"] - obj.metadata = full_region["metadata"] - obj.status = full_region["status"] - obj.endpoints = [] - for endpoint in full_region["endpoints"]: - obj.endpoints.append(regions.EndPoint(type=endpoint["type"], - publicurl=endpoint[ - "publicURL"])) - return obj - - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db()) - def test_get_groups_data(self, mock_db_get_group): - services.get_groups_data('ccplz') - - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db(exp=True)) - def test_get_all_groups_data_err(self, mock_db_get_group): - with self.assertRaises(Exception) as exp: - services.get_all_groups() - - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db()) - def test_get_all_groups_data(self, mock_db_get_group): - services.get_all_groups() - - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db()) - def test_delete_group(self, mock_db_get_group): - services.delete_group('id') - - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db(exp=True)) - def test_delete_group_err(self, mock_db_get_group): - with self.assertRaises(Exception) as exp: - services.delete_group('id') - - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db()) - def test_get_groups_empty_data(self, mock_db_get_group): - self.assertRaises(services.error_base.NotFoundError, - services.get_groups_data, None) - - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db()) - def test_get_regions_empty_data(self, mock_db_get_group): - url_parm = URlParm() - self.assertRaises(services.error_base.NotFoundError, - services.get_regions_data, url_parm) - - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db()) - def test_get_regions_data(self, mock_db_get_group): - url_parm = URlParm(metadata="key,value", clli="any") - services.get_regions_data(url_parm) - - @patch.object(services.data_manager_factory, 'get_data_manager') - def test_create_group_in_db_success(self, mock_get_data_manager): - """Make sure that no exception is raised.""" - services.create_group_in_db('d', 'a', 'b', ['c']) - - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db()) - def test_create_group_in_db_not_valid_regions(self, mock_get_data_manager): - """Make sure that no exception is raised.""" - with self.assertRaises(services.error_base.NotFoundError) as exp: - services.create_group_in_db('d', 'a', 'b', ['bad_region']) - - @patch.object(services.data_manager_factory, 'get_data_manager') - def test_create_group_in_db_duplicate_entry(self, mock_get_data_manager): - """Make sure that the expected exception is raised if group exists.""" - my_manager = mock.MagicMock() - my_manager.add_group = mock.MagicMock( - side_effect=services.error_base.ConflictError( - 'test')) - mock_get_data_manager.return_value = my_manager - self.assertRaises(services.error_base.ConflictError, - services.create_group_in_db, 'd', 'a', 'b', ['c']) - - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db()) - def test_get_region_by_id_or_name(self, mock_data_manager_factory): - result = services.get_region_by_id_or_name({"test1": "test1"}) - self.assertEqual(result, {"test1": "test1"}) - - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db()) - def test_get_region_by_id_or_name_no_content(self, - mock_data_manager_factory): - self.assertRaises(services.error_base.NotFoundError, - services.get_region_by_id_or_name, None) - - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=Exception("any")) - def test_get_region_by_id_or_name_500(self, mock_data_manager_factory): - self.assertRaises(Exception, services.get_region_by_id_or_name, "id") - - @patch.object(services, 'get_region_by_id_or_name', - return_value={"a": "b"}) - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db()) - def test_create_region_success(self, mock_db_get_group, - mock_get_region_id_name): - result = services.create_full_region(self._to_wsme_from_input(full_region)) - self.assertEqual(result, {"a": "b"}) - - @patch.object(services, 'get_region_by_id_or_name', - return_value={"a": "b"}) - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db()) - def test_create_region_duplicate(self, mock_db_create_region, - mock_get_region_id_name): - duplicate = mock.MagicMock() - duplicate.side_effect = services.base_data_manager.DuplicateEntryError() - mock_db_create_region.return_value.add_region = duplicate - with self.assertRaises(services.error_base.ConflictError) as exp: - result = services.create_full_region( - self._to_wsme_from_input(full_region)) - - @patch.object(services, 'get_region_by_id_or_name', - return_value={"a": "b"}) - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db()) - def test_create_region_validate_status_error(self, mock_db_get_group, - mock_get_region_id_name): - orig_status = full_region['status'] - full_region['status'] = "123" - allowed_status = conf.region_options.allowed_status_values[:] - with self.assertRaises(services.error_base.InputValueError) as exp: - result = services.create_full_region(self._to_wsme_from_input(full_region)) - test_ok = str(allowed_status) in exp.expected.message - self.assertEqual(test_ok, True) - full_region['status'] = orig_status - - @patch.object(services, 'get_region_by_id_or_name', - return_value={"a": "b"}) - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db()) - def test_create_region_validate_endpoints_error(self, mock_db_get_group, - mock_get_region_id_name): - message = "" - endpoints_types_must_have = conf.region_options.endpoints_types_must_have[:] - orig_endpoint = full_region['endpoints'] - full_region['endpoints'] = [ - { - "type": "dashboards", - "publicURL": "http://horizon1.com" - }] - try: - result = services.create_full_region( - self._to_wsme_from_input(full_region)) - except services.error_base.InputValueError as exp: - message = exp.message - full_region['endpoints'] = orig_endpoint - self.assertEqual(str(endpoints_types_must_have) in str(message), True) - - @patch.object(services, 'get_region_by_id_or_name', - return_value={"a": "b"}) - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db(exp=True)) - def test_create_region_validate_any_error(self, mock_db_get_group, - mock_get_region_id_name): - message = None - try: - result = services.create_full_region( - self._to_wsme_from_input(full_region)) - except Exception as exp: - message = exp.message - self.assertEqual(message, "any") - - @patch.object(services, 'get_region_by_id_or_name', - return_value={"a": "b"}) - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db()) - def test_update_region_success(self, mock_db_get_group, - mock_get_region_id_name): - result = services.update_region('id', - self._to_wsme_from_input(full_region)) - self.assertEqual(result, {"a": "b"}) - - @patch.object(services, 'get_region_by_id_or_name', - return_value={"a": "b"}) - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db(exp=True)) - def test_update_region_error(self, mock_db_get_group, - mock_get_region_id_name): - try: - result = services.update_region('id', - self._to_wsme_from_input(full_region)) - except Exception as exp: - message = exp.message - self.assertEqual(message, "error") - - @patch.object(services, 'get_region_by_id_or_name', - return_value={"a": "b"}) - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db(exp="not found")) - def test_update_region_notfound_error(self, mock_db_get_group, - mock_get_region_id_name): - try: - result = services.update_region('id', - self._to_wsme_from_input(full_region)) - except services.error_base.NotFoundError as exp: - message = exp.message - self.assertEqual(message, "id not found") - - @patch.object(services, 'get_region_by_id_or_name', - return_value={"a": "b"}) - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db(exp=True)) - def test_delete_region_error(self, mock_db_get_group, - mock_get_region_id_name): - try: - result = services.delete_region(self._to_wsme_from_input(full_region)) - except Exception as exp: - message = exp.message - self.assertEqual(message, "not deleted") - - @patch.object(services, 'get_region_by_id_or_name', - return_value={"a": "b"}) - @patch.object(services.data_manager_factory, 'get_data_manager', - return_value=db()) - def test_delete_region_success(self, mock_db_get_group, - mock_get_region_id_name): - result = services.delete_region(self._to_wsme_from_input(full_region)) +"""Services module unittests.""" +import mock +from mock import patch +from pecan import conf + +from orm.services.region_manager.rms.controllers.v2.orm.resources import groups +from orm.services.region_manager.rms.controllers.v2.orm.resources import regions +from orm.services.region_manager.rms.services import services +from orm.tests.unit.rms.controllers.v1.orm.resources.test_region import full_region +from orm.tests.unit.rms import FunctionalTest + + +class db(object): + def __init__(self, name=None, exp=None): + self.name = name + self.exp = exp + + def get_group(self, name=None): + if name: + return {'regions': [u'lcp_1'], + 'name': u'ccplz', + 'description': u'b'} + else: + return None + + def get_all_groups(self): + if self.exp: + raise Exception("any") + return [{'regions': [u'lcp_1'], 'name': u'ccplz', + 'description': u'b'}, {'regions': [u'lcp_1'], 'name': u'ccplz', + 'description': u'b'}] + + def add_group(self, *items): + if items[3] and "bad_region" in items[3]: + raise services.error_base.InputValueError() + + def get_regions(self, region_dict=None, metadata_dict=None, + end_point=None): + if region_dict: + return {'regions': [u'lcp_1'], + 'name': u'ccplz', + 'description': u'b'} + else: + return None + + def delete_group(self, id): + if self.exp: + raise Exception("any") + return None + + def get_region_by_id_or_name(self, id_name): + return id_name + + def add_region(self, **kw): + if self.exp: + raise Exception("any") + return True + + def update_region(self, id=None, **kw): + if self.exp == "not found": + raise services.error_base.NotFoundError(message="id not found") + elif self.exp: + raise Exception("error") + return True + + def delete_region(self, id=None, **kw): + if self.exp: + raise Exception("not deleted") + return True + + +class URlParm(object): + + def __init__(self, metadata=None, clli=None): + self.metadata = metadata + self.clli = clli + + def _build_query(self): + if self.metadata: + return (self.metadata, self.clli, None) + return (None, None, None) + + +class TestServices(FunctionalTest): + """Main test case for the Services module.""" + + def _to_wsme_from_input(self, input): + full_region = input + obj = regions.RegionsData() + obj.clli = full_region["CLLI"] + obj.name = full_region["name"] + obj.design_type = full_region["designType"] + obj.location_type = full_region["locationType"] + obj.vlcp_name = full_region["vlcpName"] + obj.id = full_region["id"] + obj.address.country = full_region["address"]["country"] + obj.address.city = full_region["address"]["city"] + obj.address.state = full_region["address"]["state"] + obj.address.street = full_region["address"]["street"] + obj.address.zip = full_region["address"]["zip"] + obj.ranger_agent_version = full_region["rangerAgentVersion"] + obj.open_stack_version = full_region["OSVersion"] + obj.metadata = full_region["metadata"] + obj.status = full_region["status"] + obj.endpoints = [] + for endpoint in full_region["endpoints"]: + obj.endpoints.append(regions.EndPoint(type=endpoint["type"], + publicurl=endpoint[ + "publicURL"])) + return obj + + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db()) + def test_get_groups_data(self, mock_db_get_group): + services.get_groups_data('ccplz') + + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db(exp=True)) + def test_get_all_groups_data_err(self, mock_db_get_group): + with self.assertRaises(Exception) as exp: + services.get_all_groups() + + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db()) + def test_get_all_groups_data(self, mock_db_get_group): + services.get_all_groups() + + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db()) + def test_delete_group(self, mock_db_get_group): + services.delete_group('id') + + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db(exp=True)) + def test_delete_group_err(self, mock_db_get_group): + with self.assertRaises(Exception) as exp: + services.delete_group('id') + + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db()) + def test_get_groups_empty_data(self, mock_db_get_group): + self.assertRaises(services.error_base.NotFoundError, + services.get_groups_data, None) + + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db()) + def test_get_regions_empty_data(self, mock_db_get_group): + url_parm = URlParm() + self.assertRaises(services.error_base.NotFoundError, + services.get_regions_data, url_parm) + + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db()) + def test_get_regions_data(self, mock_db_get_group): + url_parm = URlParm(metadata="key,value", clli="any") + services.get_regions_data(url_parm) + + @patch.object(services.data_manager_factory, 'get_data_manager') + def test_create_group_in_db_success(self, mock_get_data_manager): + services.create_group_in_db(groups.Groups('d', 'd', 'b', ['c'])) + + @patch.object(services.data_manager_factory, 'get_data_manager') + def test_create_group_no_name_or_id(self, mock_get_data_manager): + with self.assertRaises(services.error_base.InputValueError) as exp: + services.create_group_in_db(groups.Groups('', '', 'b', ['c'])) + + @patch.object(services.data_manager_factory, 'get_data_manager') + def test_create_group_no_description(self, mock_get_data_manager): + with self.assertRaises(services.error_base.InputValueError) as exp: + services.create_group_in_db(groups.Groups('d', 'a', '', ['c'])) + + @patch.object(services.data_manager_factory, 'get_data_manager', return_value=db()) + def test_create_group_in_db_not_valid_regions(self, mock_get_data_manager): + with self.assertRaises(services.error_base.InputValueError) as exp: + services.create_group_in_db(groups.Groups('d', 'd', 'b', + ['bad_region'])) + + @patch.object(services.data_manager_factory, 'get_data_manager') + def test_create_group_in_db_duplicate_entry(self, mock_get_data_manager): + my_manager = mock.MagicMock() + my_manager.add_group = mock.MagicMock( + side_effect=services.error_base.ConflictError( + 'test')) + mock_get_data_manager.return_value = my_manager + with self.assertRaises(services.error_base.ConflictError) as exp: + services.create_group_in_db(groups.Groups('d', 'd', 'b', ['c'])) + + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db()) + def test_get_region_by_id_or_name(self, mock_data_manager_factory): + result = services.get_region_by_id_or_name({"test1": "test1"}) + self.assertEqual(result, {"test1": "test1"}) + + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db()) + def test_get_region_by_id_or_name_no_content(self, + mock_data_manager_factory): + self.assertRaises(services.error_base.NotFoundError, + services.get_region_by_id_or_name, None) + + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=Exception("any")) + def test_get_region_by_id_or_name_500(self, mock_data_manager_factory): + self.assertRaises(Exception, services.get_region_by_id_or_name, "id") + + @patch.object(services, 'get_region_by_id_or_name', + return_value={"a": "b"}) + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db()) + def test_create_region_success(self, mock_db_get_group, + mock_get_region_id_name): + result = services.create_full_region(self._to_wsme_from_input(full_region)) + self.assertEqual(result, {"a": "b"}) + + @patch.object(services, 'get_region_by_id_or_name', + return_value={"a": "b"}) + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db()) + def test_create_region_duplicate(self, mock_db_create_region, + mock_get_region_id_name): + duplicate = mock.MagicMock() + duplicate.side_effect = services.base_data_manager.DuplicateEntryError() + mock_db_create_region.return_value.add_region = duplicate + with self.assertRaises(services.error_base.ConflictError) as exp: + result = services.create_full_region( + self._to_wsme_from_input(full_region)) + + @patch.object(services, 'get_region_by_id_or_name', + return_value={"a": "b"}) + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db()) + def test_create_region_validate_status_error(self, mock_db_get_group, + mock_get_region_id_name): + orig_status = full_region['status'] + full_region['status'] = "123" + allowed_status = conf.region_options.allowed_status_values[:] + with self.assertRaises(services.error_base.InputValueError) as exp: + result = services.create_full_region(self._to_wsme_from_input(full_region)) + test_ok = str(allowed_status) in exp.expected.message + self.assertEqual(test_ok, True) + full_region['status'] = orig_status + + @patch.object(services, 'get_region_by_id_or_name', + return_value={"a": "b"}) + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db()) + def test_create_region_validate_endpoints_error(self, mock_db_get_group, + mock_get_region_id_name): + message = "" + endpoints_types_must_have = conf.region_options.endpoints_types_must_have[:] + orig_endpoint = full_region['endpoints'] + full_region['endpoints'] = [ + { + "type": "dashboards", + "publicURL": "http://horizon1.com" + }] + try: + result = services.create_full_region( + self._to_wsme_from_input(full_region)) + except services.error_base.InputValueError as exp: + message = exp.message + full_region['endpoints'] = orig_endpoint + self.assertEqual(str(endpoints_types_must_have) in str(message), True) + + @patch.object(services, 'get_region_by_id_or_name', + return_value={"a": "b"}) + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db(exp=True)) + def test_create_region_validate_any_error(self, mock_db_get_group, + mock_get_region_id_name): + message = None + try: + result = services.create_full_region( + self._to_wsme_from_input(full_region)) + except Exception as exp: + message = exp.message + self.assertEqual(message, "any") + + @patch.object(services, 'get_region_by_id_or_name', + return_value={"a": "b"}) + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db()) + def test_update_region_success(self, mock_db_get_group, + mock_get_region_id_name): + result = services.update_region('id', + self._to_wsme_from_input(full_region)) + self.assertEqual(result, {"a": "b"}) + + @patch.object(services, 'get_region_by_id_or_name', + return_value={"a": "b"}) + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db(exp=True)) + def test_update_region_error(self, mock_db_get_group, + mock_get_region_id_name): + try: + result = services.update_region('id', + self._to_wsme_from_input(full_region)) + except Exception as exp: + message = exp.message + self.assertEqual(message, "error") + + @patch.object(services, 'get_region_by_id_or_name', + return_value={"a": "b"}) + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db(exp="not found")) + def test_update_region_notfound_error(self, mock_db_get_group, + mock_get_region_id_name): + try: + result = services.update_region('id', + self._to_wsme_from_input(full_region)) + except services.error_base.NotFoundError as exp: + message = exp.message + self.assertEqual(message, "id not found") + + @patch.object(services, 'get_region_by_id_or_name', + return_value={"a": "b"}) + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db(exp=True)) + def test_delete_region_error(self, mock_db_get_group, + mock_get_region_id_name): + try: + result = services.delete_region(self._to_wsme_from_input(full_region)) + except Exception as exp: + message = exp.message + self.assertEqual(message, "not deleted") + + @patch.object(services, 'get_region_by_id_or_name', + return_value={"a": "b"}) + @patch.object(services.data_manager_factory, 'get_data_manager', + return_value=db()) + def test_delete_region_success(self, mock_db_get_group, + mock_get_region_id_name): + result = services.delete_region(self._to_wsme_from_input(full_region)) diff --git a/orm/tests/unit/rms/storage/my_sql/test_data_manager.py b/orm/tests/unit/rms/storage/my_sql/test_data_manager.py index 64363543..6644f989 100755 --- a/orm/tests/unit/rms/storage/my_sql/test_data_manager.py +++ b/orm/tests/unit/rms/storage/my_sql/test_data_manager.py @@ -1,11 +1,11 @@ import unittest -from orm.services.region_manager.rms.services import error_base -from orm.services.region_manager.rms.storage.base_data_manager import DuplicateEntryError -from orm.services.region_manager.rms.storage.my_sql import data_manager, data_models - import mock +from orm.services.region_manager.rms.services import error_base +from orm.services.region_manager.rms.storage.my_sql import data_manager, data_models +from orm.services.region_manager.rms.storage.base_data_manager import DuplicateEntryError + end_point_list = [{"type": "ord", "url": "http://ord.com"}] @@ -74,7 +74,7 @@ class TestDataManager(unittest.TestCase): """Test that no exception is raised when calling add_status_record.""" my_data_manager = data_manager.DataManager("url", "", "") my_data_manager.add_region("reg1", "region1", "a_state", "a_country", - "a_city", "a_street", "a_zip", "a_status", "ranger_agent_ver", + "a_city", "a_street", "a_zip", "a_status", "aic_ver", "os_ver", "design_type", "loc_type", "vlcp", "clli", end_point_list, meta_data_dict, "a_desc") @@ -84,7 +84,7 @@ class TestDataManager(unittest.TestCase): my_data_manager = data_manager.DataManager("url", "", "") with self.assertRaises(DuplicateEntryError): my_data_manager.add_region("reg1", "region1", "a_state", "a_country", - "a_city", "a_street", "a_zip", "a_status", "ranger_agent_ver", + "a_city", "a_street", "a_zip", "a_status", "aic_ver", "os_ver", "design_type", "loc_type", "vlcp", "clli", [], {}, "a_desc") @@ -168,7 +168,7 @@ class TestDataManager(unittest.TestCase): my_data_manager.update_region("reg1", "region1", "region_name", "a_state", "a_country", "a_city", "a_street", "a_zip", "a_status", - "ranger_agent_ver", + "aic_ver", "os_ver", "design_type", "loc_type", "vlcp", "clli", end_point_list, meta_data_dict, "a_desc") @@ -179,12 +179,12 @@ class TestDataManager(unittest.TestCase): def test_update_region_region_not_found(self, mock_engine_facade): """Test that NotFoundError is raised when calling update_region.""" my_data_manager = data_manager.DataManager("url", "", "") - self.assertRaises(error_base.NotFoundError, + self.assertRaises(data_manager.error_base.NotFoundError, my_data_manager.update_region, "reg1", "region1", "region_name", "a_state", "a_country", "a_city", "a_street", "a_zip", "a_status", - "ranger_agent_ver", + "aic_ver", "os_ver", "design_type", "loc_type", "vlcp", "clli", end_point_list, meta_data_dict, "a_desc") @@ -201,7 +201,7 @@ class TestDataManager(unittest.TestCase): "region_name", "a_state", "a_country", "a_city", "a_street", "a_zip", "a_status", - "ranger_agent_ver", + "aic_ver", "os_ver", "design_type", "loc_type", "vlcp", "clli", end_point_list, meta_data_dict, "a_desc") @@ -250,7 +250,7 @@ class TestDataManager(unittest.TestCase): query=QueryObject(ret=None))) def test_update_region_meta_data_region_not_found(self, mock_db_session): my_data_manager = data_manager.DataManager("url", "", "") - self.assertRaises(error_base.NotFoundError, + self.assertRaises(data_manager.error_base.NotFoundError, my_data_manager.update_region_meta_data, 'region', {'meta': 'data'}) @@ -264,7 +264,7 @@ class TestDataManager(unittest.TestCase): query=QueryObject(ret=None))) def test_delete_region_metadata_region_not_found(self, mock_db_session): my_data_manager = data_manager.DataManager("url", "", "") - self.assertRaises(error_base.NotFoundError, + self.assertRaises(data_manager.error_base.NotFoundError, my_data_manager.delete_region_metadata, 'region', {'meta': 'data'}) @@ -278,7 +278,7 @@ class TestDataManager(unittest.TestCase): query=QueryObject(ret=None))) def test_update_region_status_region_not_found(self, mock_db_session): my_data_manager = data_manager.DataManager("url", "", "") - self.assertRaises(error_base.NotFoundError, + self.assertRaises(data_manager.error_base.NotFoundError, my_data_manager.update_region_status, 'region', 'status') diff --git a/orm/tests/unit/rms/storage/test_data_manager_factory.py b/orm/tests/unit/rms/storage/test_data_manager_factory.py index a313ef35..92a5d7ad 100644 --- a/orm/tests/unit/rms/storage/test_data_manager_factory.py +++ b/orm/tests/unit/rms/storage/test_data_manager_factory.py @@ -1,10 +1,8 @@ +from mock import patch import unittest from orm.services.region_manager.rms.storage import data_manager_factory from orm.services.region_manager.rms.storage.my_sql import data_manager -from orm.services.region_manager.rms.storage.my_sql.data_manager import DataManager - -from mock import patch class StorageFactoryTests(unittest.TestCase): @@ -13,7 +11,7 @@ class StorageFactoryTests(unittest.TestCase): @patch.object(data_manager, 'db_session') def test_get_data_manager(self, conf_mock, db_session_mock): """ Check the returned object from get_region_resource_id_status_connection - is instance of DataManager + is instance of DataManager """ obj = data_manager_factory.get_data_manager() - self.assertIsInstance(obj, DataManager) + self.assertIsInstance(obj, data_manager.DataManager) diff --git a/orm/tests/unit/rms/test_configuration.py b/orm/tests/unit/rms/test_configuration.py index 518fb815..895f34ec 100755 --- a/orm/tests/unit/rms/test_configuration.py +++ b/orm/tests/unit/rms/test_configuration.py @@ -1,16 +1,15 @@ -"""Get configuration module unittests.""" -from orm.services.region_manager.rms.controllers import configuration as root -from orm.tests.unit.rms import FunctionalTest - -from mock import patch - - -class TestGetConfiguration(FunctionalTest): - """Main get configuration test case.""" - - @patch.object(root.utils, 'report_config', return_value='12345') - @patch.object(root, 'authentication') - def test_get_configuration_success(self, mock_authentication, input): - """Test get_configuration returns the expected value on success.""" - response = self.app.get('/configuration') - self.assertEqual(response.json, '12345') +"""Get configuration module unittests.""" +from mock import patch +from orm.services.region_manager.rms.controllers import configuration as root +from orm.tests.unit.rms import FunctionalTest + + +class TestGetConfiguration(FunctionalTest): + """Main get configuration test case.""" + + @patch.object(root.utils, 'report_config', return_value='12345') + @patch.object(root, 'authentication') + def test_get_configuration_success(self, mock_authentication, input): + """Test get_configuration returns the expected value on success.""" + response = self.app.get('/configuration') + self.assertEqual(response.json, '12345') diff --git a/orm/tests/unit/rms/test_logs.py b/orm/tests/unit/rms/test_logs.py index f7100d01..882b6f70 100755 --- a/orm/tests/unit/rms/test_logs.py +++ b/orm/tests/unit/rms/test_logs.py @@ -1,13 +1,13 @@ import json import logging +from mock import patch, MagicMock +from wsme.exc import ClientSideError + import orm.services.region_manager.rms.controllers.logs as logs from orm.services.region_manager.rms.controllers.logs import LogsController as logs_controller from orm.tests.unit.rms import FunctionalTest -from mock import MagicMock, patch -from wsme.exc import ClientSideError - class TestGetConfiguration(FunctionalTest): diff --git a/orm/tests/unit/rms/tests_lcp_controller.py b/orm/tests/unit/rms/tests_lcp_controller.py index 553c1242..727aed0c 100755 --- a/orm/tests/unit/rms/tests_lcp_controller.py +++ b/orm/tests/unit/rms/tests_lcp_controller.py @@ -1,13 +1,16 @@ -import json +from mock import patch, MagicMock +from wsme.exc import ClientSideError from orm.services.region_manager.rms.controllers import lcp_controller -from orm.services.region_manager.rms.model.model import EndPoint, RegionData, Regions +from orm.services.region_manager.rms.model.model import RegionData, Regions, EndPoint from orm.services.region_manager.rms.services.error_base import NotFoundError from orm.services.region_manager.rms.services import services + +import json + + from orm.tests.unit.rms import FunctionalTest -from mock import MagicMock, patch -from wsme.exc import ClientSideError TEST_REGIONS_DATA = [ { @@ -16,7 +19,7 @@ TEST_REGIONS_DATA = [ "ORD_EP": "http://ord1.com", "horizon_EP": "http://horizon1.com", "design_type": "n/a", - "AIC_version": "ranger_agent1.0", + "ranger_agent_version": "aic3.0", "id": "SNA1", "OS_version": "kilo", "keystone_EP": "http://identity1.com", @@ -29,7 +32,7 @@ TEST_REGIONS_DATA = [ "ORD_EP": "http://ord2.com", "horizon_EP": "http://horizon2.com", "design_type": "n/a", - "AIC_version": "ranger_agent1.5", + "ranger_agent_version": "aic3.5", "id": "SNA2", "OS_version": "kilo", "keystone_EP": "http://identity2.com", @@ -55,15 +58,15 @@ end_points_1 = [end_point_ord_1, end_point_identity_1, end_point_horizon_1] end_points_2 = [end_point_ord_2, end_point_identity_2, end_point_horizon_2] region_data_sna1 = RegionData(status="functional", id="SNA1", name="SNA 1", - clli="n/a", ranger_agent_version="ranger_agent1.0", design_type="n/a", + clli="n/a", ranger_agent_version="aic3.0", design_type="n/a", location_type="n/a", vlcp_name="n/a", open_stack_version="kilo", endpoints=end_points_1) region_data_sna2 = RegionData(status="down", id="SNA2", name="SNA 2", - clli="n/a", ranger_agent_version="ranger_agent1.5", design_type="n/a", + clli="n/a", ranger_agent_version="aic3.5", design_type="n/a", location_type="n/a", vlcp_name="n/a", open_stack_version="kilo", endpoints=end_points_2) region_data_no_endpoints = RegionData(status="functional", id="SNA2", name="SNA 2", - clli="n/a", ranger_agent_version="ranger_agent1.5", design_type="n/a", + clli="n/a", ranger_agent_version="aic3.5", design_type="n/a", location_type="n/a", vlcp_name="n/a", open_stack_version="kilo") regions_mock = Regions([region_data_sna1, region_data_sna2]) diff --git a/orm/tests/unit/rms/utils/test_authentication.py b/orm/tests/unit/rms/utils/test_authentication.py index 6f7fb58e..d5b28a43 100755 --- a/orm/tests/unit/rms/utils/test_authentication.py +++ b/orm/tests/unit/rms/utils/test_authentication.py @@ -1,81 +1,80 @@ -"""Authentication utilities module unittests.""" -from orm.services.region_manager.rms.utils import authentication -from orm.tests.unit.rms import FunctionalTest - -import mock - - -class TestGetConfiguration(FunctionalTest): - """Main authentication test case.""" - - @mock.patch.object(authentication.policy, 'authorize') - @mock.patch.object(authentication, '_get_keystone_ep') - @mock.patch.object(authentication, '_is_authorization_enabled') - def test_authorize_success(self, mock_iae, mock_gke, mock_authorize): - request = mock.MagicMock() - action = 'test:test' - - # Success when authentication is disabled - mock_iae.return_value = False - authentication.authorize(request, action) - - # Success when authentication is enabled - mock_iae.return_value = True - authentication.authorize(request, action) - - def mock_authorize_no_keystone(self, *args, **kwargs): - self.assertIsNone(kwargs['keystone_ep']) - - @mock.patch.object(authentication, 'policy') - @mock.patch.object(authentication, '_get_keystone_ep') - @mock.patch.object(authentication, '_is_authorization_enabled') - def test_authorize_gke_failed(self, mock_iae, mock_gke, mock_policy): - request = mock.MagicMock() - action = 'test:test' - - # Success when authentication is disabled - mock_iae.return_value = False - authentication.authorize(request, action) - - # Success when authentication is enabled - mock_iae.return_value = True - authentication.authorize(request, action) - - @mock.patch.object(authentication, 'policy') - @mock.patch.object(authentication, '_get_keystone_ep', - side_effect=ValueError('test')) - @mock.patch.object(authentication, '_is_authorization_enabled', - return_value=True) - def test_authorize_gke_failed(self, mock_iae, mock_gke, mock_policy): - request = mock.MagicMock() - action = 'test:test' - - mock_policy.authorize = self.mock_authorize_no_keystone - authentication.authorize(request, action) - - def test_is_authorization_enabled(self): - app_conf = mock.MagicMock() - - app_conf.authentication.enabled = True - self.assertTrue(authentication._is_authorization_enabled(app_conf)) - - app_conf.authentication.enabled = False - self.assertFalse(authentication._is_authorization_enabled(app_conf)) - - @mock.patch.object(authentication.RegionService, - 'get_region_by_id_or_name') - def test_get_keystone_ep_success(self, mock_grbion): - region = mock.MagicMock() - keystone_ep = mock.MagicMock() - keystone_ep.type = 'identity' - keystone_ep.publicurl = 'test' - region.endpoints = [keystone_ep] - mock_grbion.return_value = region - - self.assertEqual(authentication._get_keystone_ep('region'), - keystone_ep.publicurl) - - @mock.patch.object(authentication.RegionService, - 'get_region_by_id_or_name') - def test_get_keystone_ep_no_keystone_ep(self, mock_grbion): - self.assertIsNone(authentication._get_keystone_ep('region')) +"""Authentication utilities module unittests.""" +import mock +from orm.services.region_manager.rms.utils import authentication +from orm.tests.unit.rms import FunctionalTest + + +class TestGetConfiguration(FunctionalTest): + """Main authentication test case.""" + + @mock.patch.object(authentication.policy, 'authorize') + @mock.patch.object(authentication, 'get_keystone_ep') + @mock.patch.object(authentication, '_is_authorization_enabled') + def test_authorize_success(self, mock_iae, mock_gke, mock_authorize): + request = mock.MagicMock() + action = 'test:test' + + # Success when authentication is disabled + mock_iae.return_value = False + authentication.authorize(request, action) + + # Success when authentication is enabled + mock_iae.return_value = True + authentication.authorize(request, action) + + def mock_authorize_no_keystone(self, *args, **kwargs): + self.assertIsNone(kwargs['keystone_ep']) + + @mock.patch.object(authentication, 'policy') + @mock.patch.object(authentication, 'get_keystone_ep') + @mock.patch.object(authentication, '_is_authorization_enabled') + def test_authorize_gke_failed(self, mock_iae, mock_gke, mock_policy): + request = mock.MagicMock() + action = 'test:test' + + # Success when authentication is disabled + mock_iae.return_value = False + authentication.authorize(request, action) + + # Success when authentication is enabled + mock_iae.return_value = True + authentication.authorize(request, action) + + @mock.patch.object(authentication, 'policy') + @mock.patch.object(authentication, 'get_keystone_ep', + side_effect=ValueError('test')) + @mock.patch.object(authentication, '_is_authorization_enabled', + return_value=True) + def test_authorize_gke_failed(self, mock_iae, mock_gke, mock_policy): + request = mock.MagicMock() + action = 'test:test' + + mock_policy.authorize = self.mock_authorize_no_keystone + authentication.authorize(request, action) + + def test_is_authorization_enabled(self): + app_conf = mock.MagicMock() + + app_conf.authentication.enabled = True + self.assertTrue(authentication._is_authorization_enabled(app_conf)) + + app_conf.authentication.enabled = False + self.assertFalse(authentication._is_authorization_enabled(app_conf)) + + @mock.patch.object(authentication.RegionService, + 'get_region_by_id_or_name') + def test_get_keystone_ep_success(self, mock_grbion): + region = mock.MagicMock() + keystone_ep = mock.MagicMock() + keystone_ep.type = 'identity' + keystone_ep.publicurl = 'test' + region.endpoints = [keystone_ep] + mock_grbion.return_value = region + + self.assertEqual(authentication.get_keystone_ep('region'), + keystone_ep.publicurl) + + @mock.patch.object(authentication.RegionService, + 'get_region_by_id_or_name') + def test_get_keystone_ep_no_keystone_ep(self, mock_grbion): + self.assertIsNone(authentication.get_keystone_ep('region'))