Merge diverged code

Change-Id: I7a88d9bec69371bec1004572a4fa87cdfbbf1f28
This commit is contained in:
Nicholas Jones 2018-04-27 14:18:18 -05:00 committed by nj762h
parent 2eddcd66c6
commit dac751d04b
145 changed files with 5375 additions and 3096 deletions

View File

@ -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')

View File

@ -1,6 +1,5 @@
"""Token utility module.""" """Token utility module."""
import logging import logging
import requests import requests
from orm.common.client.keystone.mock_keystone.keystoneclient import exceptions 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.client.keystone.mock_keystone.keystoneclient.v3 import client as v3_client
from orm.common.orm_common.utils import dictator from orm.common.orm_common.utils import dictator
from pecan import request
_verify = False _verify = False
OK_CODE = 200 OK_CODE = 200
@ -96,6 +97,10 @@ def get_token_user(token, conf, lcp_id=None, keystone_ep=None):
try: try:
token_info = keystone.tokens.validate(token) token_info = keystone.tokens.validate(token)
logger.debug('User token found in Keystone') 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) return TokenUser(token_info)
# Other exceptions raised by validate() are critical errors, # Other exceptions raised by validate() are critical errors,
# so instead of returning False, we'll just let them propagate # so instead of returning False, we'll just let them propagate

View File

@ -1,5 +1,4 @@
import logging import logging
from pecan.hooks import PecanHook from pecan.hooks import PecanHook
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@ -10,7 +10,7 @@ class ResourceProviderRegister:
# Maps resource names to a provider # Maps resource names to a provider
self.resource_providers = {} 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: if provider is None:
# Give a partial usable as a decorator # Give a partial usable as a decorator
return partial( return partial(

View File

@ -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 api_error_utils as err_utils
from orm.common.orm_common.utils import dictator from orm.common.orm_common.utils import dictator
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
registered_checks = {} registered_checks = {}
@ -214,22 +215,19 @@ class RoleCheck(Check):
"""Check that there is a matching role in the ``user`` object.""" """Check that there is a matching role in the ``user`` object."""
def __call__(self, target, user, enforcer): def __call__(self, target, user, enforcer):
try: logger.debug('Checking against policy role:{}'.format(self.match))
logger.debug('Checking role:{}'.format(self.match))
result = any( result = any(
[role['name'] == self.match for role in user.user['roles']]) [role['name'] == self.match for role in user.user['roles']])
logger.debug('Role check result: {}'.format(result)) logger.debug('Role check result: {}'.format(result))
if not result: if not result:
logger.info( logger.info(
'INFO|CON{}AUTH001|Not allowed to perform this operation,' 'INFO|CON{}AUTH001|Not allowed to perform this operation,'
' user:{} does not have role:{}'.format( ' user:{} does not have role:{}'.format(
dictator.get('service_name', 'ORM'), dictator.get('service_name', 'ORM'),
user.user['name'], self.match)) user.user['name'], self.match))
raise err_utils.get_error('N/A', status_code=403)
return result return result
except Exception:
logger.debug('Invalid user, failing role check')
raise
@register('user') @register('user')

View File

@ -22,6 +22,7 @@ import six
import _checks import _checks
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -210,7 +211,7 @@ def _parse_check(rule):
try: try:
kind, match = rule.split(':', 1) kind, match = rule.split(':', 1)
except Exception: 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 # If the rule is invalid, we'll fail closed
return _checks.FalseCheck() return _checks.FalseCheck()
@ -220,7 +221,7 @@ def _parse_check(rule):
elif None in _checks.registered_checks: elif None in _checks.registered_checks:
return _checks.registered_checks[None](kind, match) return _checks.registered_checks[None](kind, match)
else: else:
LOG.error('No handler for matches of kind %s', kind) LOG.error(('No handler for matches of kind %s'), kind)
return _checks.FalseCheck() return _checks.FalseCheck()
@ -336,7 +337,7 @@ def _parse_text_rule(rule):
return state.result return state.result
except ValueError: except ValueError:
# Couldn't parse the rule # Couldn't parse the rule
LOG.exception('Failed to understand rule %s', rule) LOG.exception(('Failed to understand rule %s'), rule)
# Fail closed # Fail closed
return _checks.FalseCheck() return _checks.FalseCheck()

View File

@ -131,6 +131,10 @@ def authorize(action, request, app_conf, keystone_ep=None):
token_to_validate = request.headers.get('X-Auth-Token') token_to_validate = request.headers.get('X-Auth-Token')
lcp_id = request.headers.get('X-Auth-Region') lcp_id = request.headers.get('X-Auth-Region')
keystone_ep = keystone_ep if keystone_ep else (
request.headers.get('Keystone-Endpoint'))
try: try:
if _is_authorization_enabled(app_conf): if _is_authorization_enabled(app_conf):
try: try:

View File

@ -219,7 +219,9 @@ import logging
import os import os
import _parser import _parser
from orm.common.orm_common.utils import api_error_utils as err_utils
from oslo_config import cfg from oslo_config import cfg
from oslo_policy import _checks from oslo_policy import _checks
from oslo_policy._i18n import _ from oslo_policy._i18n import _
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
@ -525,9 +527,6 @@ class Enforcer(object):
# If it is False, raise the exception if requested # If it is False, raise the exception if requested
if do_raise and not result: if do_raise and not result:
if exc: raise err_utils.get_error('N/A', status_code=403)
raise exc(*args, **kwargs)
raise PolicyNotAuthorized(rule, target, creds)
return result return result

View File

View File

@ -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"}'))

View File

@ -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])

View File

@ -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')

View File

@ -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())
'''

View File

@ -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))

View File

@ -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)

View File

@ -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"})

View File

@ -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')

View File

@ -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'))

View File

@ -1,5 +1,4 @@
import json import json
from orm.common.orm_common.utils import utils from orm.common.orm_common.utils import utils
from wsme.exc import ClientSideError from wsme.exc import ClientSideError
@ -40,7 +39,7 @@ error_message = {
404: {'message': 'The specific transaction was not found', 'type': 'Not Found'}, 404: {'message': 'The specific transaction was not found', 'type': 'Not Found'},
405: {'message': 'This method is not allowed', 'type': 'Method Not Allowed'}, 405: {'message': 'This method is not allowed', 'type': 'Method Not Allowed'},
409: {'message': 'Current resource is busy', 'type': 'Conflict'}, 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'}, 409.2: {'message': 'Customer name already exists', 'type': 'Conflict'},
500: {'message': 'Server error occurred', 'type': 'Internal Server Error'} 500: {'message': 'Server error occurred', 'type': 'Internal Server Error'}
} }

View File

@ -1,9 +1,8 @@
import logging import logging
import time
import requests
from pecan import conf from pecan import conf
import requests
import string
import time
# from orm_common.logger import get_logger # 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') 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): def is_region_group_exist(group_name):
""" function to check whether region group exists """ function to check whether region group exists
returns 200 for ok and None for error returns 200 for ok and None for error

View File

@ -0,0 +1,9 @@
class Error(Exception):
pass
class ErrorStatus(Error):
def __init__(self, status_code, message=""):
self.message = message

View File

@ -34,44 +34,28 @@ def _check_conf_initialization():
'pass pecan coniguration') 'pass pecan coniguration')
def make_uuid(): def create_or_validate_uuid(uuid, uuid_type):
""" function to request new uuid from uuid_generator rest service """ function to:
1) request new uuid from uuid_generator rest service
2) validate a uuid if one is being set
returns uuid string returns uuid string
""" """
_check_conf_initialization() _check_conf_initialization()
url = conf.api.uuid_server.base + conf.api.uuid_server.uuids url = conf.api.uuid_server.base + conf.api.uuid_server.uuids
try: if not uuid:
logger.debug('Requesting new UUID from URL: {}'.format(url)) logger.debug('Requesting new UUID from URL: {}'.format(url))
resp = requests.post(url, verify=conf.verify) else:
except requests.exceptions.ConnectionError as exp: logger.debug('Creating UUID: {}, using URL: {}'.format(uuid, url))
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
try: try:
logger.debug('Creating UUID: {}, using URL: {}'.format(uuid, url)) resp = requests.post(url, data={'uuid': uuid, 'uuid_type': uuid_type},
resp = requests.post(url, data={'uuid': uuid}, verify=conf.verify) verify=conf.verify)
except requests.exceptions.ConnectionError as exp: except requests.exceptions.ConnectionError as exp:
nagios = 'CON{}UUIDGEN001'.format(conf.server.name.upper()) 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' exp.message = 'connection error: Failed to get uuid: unable to connect to server'
raise raise
except Exception as e: except Exception as e:
@ -79,7 +63,9 @@ def create_existing_uuid(uuid):
return None return None
if resp.status_code == 400: 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() resp = resp.json()
return resp['uuid'] return resp['uuid']
@ -110,6 +96,7 @@ def make_transid():
else: else:
return None return None
audit_setup = False audit_setup = False

View File

@ -1,49 +1,99 @@
import config as conf import config as conf
import json import json
import logging import logging
import os import os
import subprocess
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def _get_regions(customer): def _get_cms_regions(customer):
regions = [] regions = []
try: try:
customer_json = json.loads(customer) customer_json = json.loads(customer)
if 'regions' not in customer_json: if 'regions' not in customer_json:
raise Exception("got bad response from orm cli ") raise Exception("got bad response from orm cli ")
for region in customer_json['regions']: for region in customer_json['regions']:
regions.append(region['name']) regions.append(region['name'])
except Exception as exp: except Exception as exp:
raise Exception("got bad response from orm cli {}".format(exp.message)) raise Exception("got bad response from orm cli {}".format(exp.message))
message = "got no regions from orm cli" message = "got no regions from orm cli"
if regions: if regions:
message = "got regions from orm cli --{}--".format(regions) message = "got regions from orm cli --{}--".format(regions)
log.debug(message) log.debug(message)
return regions return regions
def _build_get_customer_cli_command(resource_id): def _get_flavor_regions(flavor):
cli_command = """get_customer %s""" % resource_id regions = []
log.debug('cli command {}'.format(cli_command))
return cli_command try:
flavor_json = json.loads(flavor)
if 'regions' not in flavor_json['flavor']:
def _get_customer_regions(cli_command, service): raise Exception("got bad response from orm cli ")
client_header = service.upper() for region in flavor_json['flavor']['regions']:
log.debug("get customer with cli") regions.append(region['name'])
os.chdir(conf.cli_dir) except Exception as exp:
cwd = os.getcwd() raise Exception("got bad response from orm cli {}".format(exp.message))
customer = os.popen('./orm %s %s ' % (service.lower(), cli_command))
log.debug("got cusmer with cli ... check if got regions") message = "got no regions from orm cli"
return _get_regions(customer.read()) if regions:
message = "got regions from orm cli --{}--".format(regions)
log.debug(message)
def get_resource_regions(resource_id, service): return regions
log.debug("---ORM CLI---")
regions = None
if service.upper() == 'CMS': def _get_image_regions(image):
regions = _get_customer_regions( regions = []
_build_get_customer_cli_command(resource_id), service) try:
return regions 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)

View File

@ -1,25 +1,38 @@
"""config module.""" """config module."""
# db configs # db configs
sql_user = 'root' sql_user = 'root'
sql_password = 'stack' sql_password = 'xxxxxxxxxxx'
sql_server = '127.0.0.1' sql_server = '127.0.0.1'
sql_port = '3306' sql_port = '3306'
# cms configs # cms configs
customer_table_name = "customer" customer_table_name = "customer"
customer_region_table_name = "customer_region" customer_tbl_column = "uuid"
cms_db_name = "orm_cms_db" customer_region_table_name = "customer_region"
cms_db_name = "orm_cms_db"
# cli configs # fms configs
cli_dir = '../ormcli' flavor_table_name = "flavor"
flavor_tbl_column = "id"
# rds configs flavor_region_table_name = "flavor_region"
rds_db_name = 'orm_rds' fms_db_name = "orm_fms_db"
resource_status_table_name = 'resource_status'
# ims configs
# sot configs image_table_name = "image"
local_repository_path = '/opt/app/orm/ORM' image_tbl_column = "id"
file_name_format = 's_{}.yml' image_region_table_name = "image_region"
relative_path_format = '/{}/hot/{}/{}' 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/{}/{}'

View File

@ -1,130 +1,215 @@
import config as conf import config as conf
import logging import logging
import sqlalchemy import sqlalchemy
log = logging.getLogger(__name__)
log = logging.getLogger(__name__)
db_engines = {}
db_engines = {}
def _db_create_engine(db_name):
global db_engines
def _db_create_engine(db_name): if db_name not in db_engines:
global db_engines db_address = 'mysql://{}:{}@{}:{}/{}'.format(conf.sql_user,
if db_name not in db_engines: conf.sql_password,
db_address = 'mysql://{}:{}@{}:{}/{}'.format(conf.sql_user, conf.sql_server,
conf.sql_password, conf.sql_port,
conf.sql_server, db_name)
conf.sql_port, db_engines[db_name] = sqlalchemy.create_engine(db_address)
db_name) return db_engines
log.debug("DB:--- db address {}".format(db_address))
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
def _run_query(query, db_name): table_col = conf.customer_tbl_column
db_engines = _db_create_engine(db_name) table_name = conf.customer_table_name
connection = db_engines[db_name].connect() region_table_name = conf.customer_region_table_name
try:
sqlres = connection.execute(query) elif service.upper() == 'FMS':
except Exception as exp: db_name = conf.fms_db_name
sqlres = None table_col = conf.flavor_tbl_column
log.error("fail to delete resource {}".format(exp)) table_name = conf.flavor_table_name
finally: region_table_name = conf.flavor_region_table_name
# close the connection
connection.close() elif service.upper() == 'IMS':
# db_engines[db_name].dispose() db_name = conf.ims_db_name
return sqlres table_col = conf.image_tbl_column
table_name = conf.image_table_name
region_table_name = conf.image_region_table_name
def _build_delet_resource_status_query(resource_id, table_name):
query = ''' return db_name, table_name, table_col, region_table_name
DELETE from %s
WHERE resource_id = '%s'
''' % (table_name, resource_id) def _run_query(query, db_name):
return query db_engines = _db_create_engine(db_name)
connection = db_engines[db_name].connect()
try:
def _build_delete_resource_query(resource_id, table_name): sqlres = connection.execute(query)
query = ''' except Exception as exp:
DELETE from %s sqlres = None
WHERE %s.uuid = '%s' log.error("fail to delete resource {}".format(exp))
''' % (table_name, table_name, resource_id) finally:
return query # close the connection
connection.close()
# db_engines[db_name].dispose()
def _build_get_resource_regions_query(resource_id, table_name): return sqlres
query = '''
select region_id from %s
WHERE customer_id = '%s' and region_id != '-1' def _build_delet_resource_status_query(resource_id, table_name):
''' % (table_name, resource_id) query = '''
return query DELETE from %s
WHERE resource_id = '%s'
''' % (table_name, resource_id)
def _build_get_resource_id_query(resource_id, table_name): return query
query = '''
select * from %s
WHERE %s.uuid = '%s' def _build_delete_image_metadata(resource_id, image_metadata_table,
''' % (table_name, table_name, resource_id) resource_table):
return query query = '''
DELETE from %s
WHERE image_meta_data_id in
def remove_cms_resource(resource_id): (SELECT id from %s where resource_id = '%s')
query = _build_delete_resource_query(resource_id, conf.customer_table_name) ''' % (image_metadata_table, resource_table, resource_id)
log.debug("DB---: deleting customer, query {}".format(query)) return query
_run_query(query, conf.cms_db_name)
return
def _build_delete_resource_query(resource_id, table_col, table_name):
query = '''
def remove_rds_resource_status(resource_id): DELETE from %s
query = _build_delet_resource_status_query(resource_id, WHERE %s.%s = '%s'
conf.resource_status_table_name) ''' % (table_name, table_name, table_col, resource_id)
log.debug("DB---: deleting resource status, query {}".format(query)) return query
_run_query(query, conf.rds_db_name)
return
def _build_get_cms_regions_query(resource_id, table_name):
query = '''
def remove_ims_resource(resource_id): select region_id from %s
return WHERE customer_id = '%s' and region_id != '-1'
''' % (table_name, resource_id)
return query
def remove_fms_resource(resource_id):
return
def _build_get_fms_regions_query(resource_id, table_name):
query = '''
def get_cms_db_resource_regions(resource_id): select region_name from %s
regions = None WHERE flavor_internal_id = '%s'
query = _build_get_resource_id_query(resource_id, conf.customer_table_name) ''' % (table_name, resource_id)
result = _run_query(query, conf.cms_db_name) return query
if not result.rowcount > 0:
raise Exception('resource {} not found'.format(resource_id))
resource_internal_id = result.first().__getitem__('id') def _build_get_ims_regions_query(resource_id, table_name):
log.debug("got resource internal id {}".format(resource_internal_id)) query = '''
# from resource id get regions select region_name from %s
query = _build_get_resource_regions_query(resource_internal_id, WHERE image_id = '%s'
conf.customer_region_table_name) ''' % (table_name, resource_id)
log.debug(query) return query
result = _run_query(query, conf.cms_db_name)
if result.rowcount > 0:
regions = result.fetchall() def _build_get_resource_id_query(resource_id, table_col, table_name):
return regions query = '''
select * from %s
WHERE %s.%s = '%s'
def get_ims_db_resource_regions(resource_id): ''' % (table_name, table_name, table_col, resource_id)
return return query
def get_fms_db_resource_regions(resource_id): def remove_resource_id(resource_id, service):
return 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)
def get_rds_db_resource_status(resource_id): log.debug("DB---: deleting {}, query {}".format(resource_type, query))
return _run_query(query, db_name)
return
def remove_resource_db(resource_id, service):
if service == 'CMS': def remove_rds_resource_status(resource_id):
log.debug( query = _build_delet_resource_status_query(resource_id,
"cleaning {} db for resource {}".format(service, resource_id)) conf.resource_status_table_name)
remove_cms_resource(resource_id) log.debug("DB---: deleting resource status, query {}".format(query))
return _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

View File

@ -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()

View File

@ -1,25 +1,25 @@
import config as conf import config as conf
import fnmatch import fnmatch
import os import os
def _get_resource_file_path(): def _get_resource_file_path():
file_path = conf.local_repository_path file_path = conf.local_repository_path
return file_path return file_path
def _find_file(resource_id): def _find_file(resource_id):
file_name = conf.file_name_format.format(resource_id) file_name = conf.file_name_format.format(resource_id)
folder_to_search = _get_resource_file_path(resource_id) folder_to_search = _get_resource_file_path()
matches = [] matches = []
for root, dirnames, filenames in os.walk(folder_to_search): for root, dirnames, filenames in os.walk(folder_to_search):
for filename in fnmatch.filter(filenames, file_name): for filename in fnmatch.filter(filenames, file_name):
matches.append(os.path.join(root, filename)) matches.append(os.path.join(root, filename))
return matches return matches
def check_yaml_exist(resource_id): def check_yaml_exist(resource_id):
files = _find_file(resource_id) files = _find_file(resource_id)
if files: if files:
return files return files
return None return None

View File

@ -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: 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: Use of -h will produce the following help:
./regionator.py -h ./regionator.py -h
usage: regionator [-h] [--flavor_dir FLAVOR_DIR] [--host HOST] usage: regionator [-h] regions [series]
[--cli_command CLI_COMMAND] [--regions REGIONS]
batch add region to flavor batch add region to flavor
positional arguments:
regions <comma-separated regions to add, e.g. region1,region2>
series <comma-separated flavor series to add, e.g. nd,gv>
optional arguments: optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit
--flavor_dir FLAVOR_DIR
<JSON flavor directory, default: ./flavor_dir>
--host HOST <orm host ip>
--cli_command CLI_COMMAND
<path to cli command>
--regions REGIONS <comma-separated regions to add, e.g. region1,region2>

View File

@ -29,7 +29,7 @@ def sh(harg, file_name):
print '>> Starting: ' + cmd print '>> Starting: ' + cmd
start = time.time() start = time.time()
output = '' output = ''
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, p = subprocess.Popen(cmd.split(), shell=False, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT)
for line in iter(p.stdout.readline, b''): for line in iter(p.stdout.readline, b''):
out = line.rstrip() out = line.rstrip()

View File

@ -30,7 +30,7 @@ def get_region_list(regions):
REGION_NAME = region REGION_NAME = region
res, output = sh('get_region') res, output = sh('get_region')
if not res: if not res:
result_region = ast.literal_eval(output) result_region = json.loads(output)
result.append({'name': result_region['name'], result.append({'name': result_region['name'],
'designType': result_region['designType']}) 'designType': result_region['designType']})
else: else:
@ -44,9 +44,9 @@ def create_command(cli_command):
if cli_command == 'add_region': if cli_command == 'add_region':
cmd = 'python %s fms add_region %s %s' % (CLI_PATH, FID, FILE_NAME,) cmd = 'python %s fms add_region %s %s' % (CLI_PATH, FID, FILE_NAME,)
elif cli_command == 'get_flavor': 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': 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: else:
raise ValueError('Received an unknown command: %s' % (cli_command,)) raise ValueError('Received an unknown command: %s' % (cli_command,))
@ -79,7 +79,7 @@ def sh(cli_command):
start = time.time() start = time.time()
output = '' output = ''
errpat = re.compile('error', re.I) 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''): for line in iter(p.stdout.readline, b''):
out = line.rstrip() out = line.rstrip()
print(">>> " + out) print(">>> " + out)

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python
from os.path import isfile, join
import argparse import argparse
import json import json
import os import os
from os.path import isfile, join
import re import re
import subprocess import subprocess
import tempfile import tempfile
@ -29,7 +29,9 @@ def sh(cmd):
start = time.time() start = time.time()
output = '' output = ''
errpat = re.compile('error', re.I) 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) stderr=subprocess.STDOUT)
for line in iter(p.stdout.readline, b''): for line in iter(p.stdout.readline, b''):
out = line.rstrip() out = line.rstrip()

View File

@ -1,9 +1,9 @@
#!/usr/bin/env python #!/usr/bin/env python
from os.path import isfile, join
import argparse import argparse
import ast import ast
import json import json
import os import os
from os.path import isfile, join
import re import re
import subprocess import subprocess
import tempfile import tempfile
@ -29,7 +29,7 @@ def sh(cmd):
start = time.time() start = time.time()
output = '' output = ''
errpat = re.compile('error', re.I) 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''): for line in iter(p.stdout.readline, b''):
out = line.rstrip() out = line.rstrip()
print(">>> " + out) print(">>> " + out)
@ -74,7 +74,7 @@ os.close(fh)
img_dict = {} img_dict = {}
# harg = '--orm-base-url %s' % args.host if args.host else '' # harg = '--orm-base-url %s' % args.host if args.host else ''
res, output = sh( res, output = sh(
'%s ims %s list_images test ' % (CLI_PATH, '')) 'python %s ims %s list_images test ' % (CLI_PATH, ''))
if not res: if not res:
images = ast.literal_eval(output) images = ast.literal_eval(output)
for img in images['images']: for img in images['images']:
@ -90,9 +90,10 @@ if not res:
if image_name in img_dict: if image_name in img_dict:
image_id = img_dict[image_name] image_id = img_dict[image_name]
print 'image_id: ' + image_id 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)) CLI_PATH, image_id, file_name))
else: 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) os.unlink(file_name)

View File

@ -2,7 +2,6 @@
import argparse import argparse
import cli_common import cli_common
import config import config
import orm.base_config as base_config
import os import os
import requests import requests
@ -44,7 +43,7 @@ def add_to_parser(service_sub):
parser.add_argument('-v', '--verbose', help='show details', parser.add_argument('-v', '--verbose', help='show details',
action="store_true") action="store_true")
parser.add_argument('-f', '--faceless', parser.add_argument('-f', '--faceless',
help='run without authentication', help=argparse.SUPPRESS,
default=False, default=False,
action="store_true") action="store_true")
subparsers = parser.add_subparsers(dest='subcmd', subparsers = parser.add_subparsers(dest='subcmd',
@ -112,11 +111,16 @@ def add_to_parser(service_sub):
parser_delete_region = subparsers.add_parser('delete_region', parser_delete_region = subparsers.add_parser('delete_region',
help='[<"X-RANGER-Client" ' help='[<"X-RANGER-Client" '
'header>] <customer id> ' 'header>] '
'[--force_delete] '
'<customer id> '
'<region id>') '<region id>')
parser_delete_region.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_delete_region.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
parser_delete_region.add_argument('custid', type=str, help='<customer id>') parser_delete_region.add_argument('custid', type=str, help='<customer id>')
parser_delete_region.add_argument('regionid', type=str, help='<region id>') parser_delete_region.add_argument('regionid', type=str, help='<region id>')
parser_delete_region.add_argument('--force_delete',
help='force delete region',
action="store_true")
# add user # add user
parser_add_user = subparsers.add_parser('add_user', parser_add_user = subparsers.add_parser('add_user',
@ -216,11 +220,8 @@ def add_to_parser(service_sub):
help='<user id>') help='<user id>')
# add metadata # add metadata
h1, h2, h3 = \ h1, h2, h3 = ('[<"X-RANGER-Client" header>]', '<customer id>',
'[<"X-RANGER-Client" header>]', '<customer id>', '<data file ' \ '<data file with metadata(s) JSON>')
'with ' \
'metadata(' \
's) JSON>'
parser_add_metadata = subparsers.add_parser('add_metadata', parser_add_metadata = subparsers.add_parser('add_metadata',
help='%s %s %s' % (h1, h2, h3)) help='%s %s %s' % (h1, h2, h3))
parser_add_metadata.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_add_metadata.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
@ -230,11 +231,8 @@ def add_to_parser(service_sub):
help=h3) help=h3)
# replace metadata # replace metadata
h1, h2, h3 = \ h1, h2, h3 = ('[<"X-RANGER-Client" header>]', '<customer id>',
'[<"X-RANGER-Client" header>]', '<customer id>', '<data file ' \ '<data file with metadata(s) JSON>')
'with ' \
'metadata(' \
's) JSON>'
parser_replace_metadata = subparsers.add_parser('replace_metadata', parser_replace_metadata = subparsers.add_parser('replace_metadata',
help='%s %s %s' % ( help='%s %s %s' % (
h1, h2, h3)) h1, h2, h3))
@ -247,16 +245,16 @@ def add_to_parser(service_sub):
help=h3) help=h3)
# get customer # get customer
h1, h2 = '[<"X-RANGER-Client" header>]', '<customer id or customer name>'
parser_get_customer = subparsers.add_parser('get_customer', parser_get_customer = subparsers.add_parser('get_customer',
help='[<"X-RANGER-Client" ' help='%s %s' % (h1, h2))
'header>] <customer id>')
parser_get_customer.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_get_customer.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
parser_get_customer.add_argument('custid', type=str, help='<customer id>') parser_get_customer.add_argument('custid', type=str, help=h2)
# list customers # list customers
h1 = '[<"X-RANGER-Client" header>]' h1 = '[<"X-RANGER-Client" header>]'
h2 = '[--region <name>] [--user <name>] [--metadata <key:value>]' \ h2 = '[--region <name>] [--user <name>] [--metadata <key:value>]' \
' [starts_with <name>] [contains <name>]' ' [--starts_with <name>] [--contains <name>]'
parser_list_customer = subparsers.add_parser('list_customers', parser_list_customer = subparsers.add_parser('list_customers',
help='%s %s' % (h1, h2)) help='%s %s' % (h1, h2))
parser_list_customer.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) parser_list_customer.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
@ -288,7 +286,9 @@ def cmd_details(args):
elif args.subcmd == 'replace_region': elif args.subcmd == 'replace_region':
return requests.put, '/%s/regions' % args.custid return requests.put, '/%s/regions' % args.custid
elif args.subcmd == 'delete_region': 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': elif args.subcmd == 'add_user':
return requests.post, '/%s/regions/%s/users' % ( return requests.post, '/%s/regions/%s/users' % (
args.custid, args.regionid) args.custid, args.regionid)
@ -353,12 +353,12 @@ def get_token(timeout, args, host):
globals()[argument] = configuration_value globals()[argument] = configuration_value
else: else:
message = ('ERROR: {} for token generation was not supplied. ' message = ('ERROR: {} for token generation was not supplied. '
'Please use its command-line ' 'Please use its command-line argument or '
'argument or environment variable.'.format(argument)) 'environment variable.'.format(argument))
print message print message
raise cli_common.MissingArgumentError(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) auth_region)
if keystone_ep is None: if keystone_ep is None:
raise ConnectionError( raise ConnectionError(
@ -386,7 +386,7 @@ def get_token(timeout, args, host):
def get_environment_variable(argument): def get_environment_variable(argument):
# The rules are: all caps, underscores instead of dashes and prefixed # The rules are: all caps, underscores instead of dashes and prefixed
environment_variable = 'RANGER_{}'.format( environment_variable = 'AIC_ORM_{}'.format(
argument.replace('-', '_').upper()) argument.replace('-', '_').upper())
return os.environ.get(environment_variable) return os.environ.get(environment_variable)
@ -394,7 +394,7 @@ def get_environment_variable(argument):
def run(args): def run(args):
host = args.orm_base_url if args.orm_base_url else config.orm_base_url 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 '{}' data = args.datafile.read() if 'datafile' in args else '{}'
timeout = args.timeout if args.timeout else 10 timeout = args.timeout if args.timeout else 10
@ -429,7 +429,7 @@ def run(args):
try: try:
resp = rest_cmd(url, timeout=timeout, data=data, headers=headers, resp = rest_cmd(url, timeout=timeout, data=data, headers=headers,
verify=False) verify=config.verify)
except Exception as e: except Exception as e:
print e print e
exit(1) exit(1)

View File

@ -2,7 +2,6 @@
import argparse import argparse
import cli_common import cli_common
import config import config
import orm.base_config as base_config
import os import os
import requests import requests
@ -42,7 +41,7 @@ def add_to_parser(service_sub):
parser.add_argument('-v', '--verbose', help='show details', parser.add_argument('-v', '--verbose', help='show details',
action="store_true") action="store_true")
parser.add_argument('-f', '--faceless', parser.add_argument('-f', '--faceless',
help='run without authentication', help=argparse.SUPPRESS,
default=False, default=False,
action="store_true") action="store_true")
subparsers = parser.add_subparsers(dest='subcmd', subparsers = parser.add_subparsers(dest='subcmd',
@ -126,7 +125,7 @@ def add_to_parser(service_sub):
h1, h2, h3 = ('[<"X-RANGER-Client" header>]', '<flavor id>', h1, h2, h3 = ('[<"X-RANGER-Client" header>]', '<flavor id>',
'<extra_spec key name>',) '<extra_spec key name>',)
parser_delete_extra_spec = subparsers.add_parser('delete_extra_spec', parser_delete_extra_spec = subparsers.add_parser('delete_extra_spec',
help='%s%s%s' % ( help='%s %s %s' % (
h1, h2, h3)) h1, h2, h3))
parser_delete_extra_spec.add_argument('client', parser_delete_extra_spec.add_argument('client',
**cli_common.ORM_CLIENT_KWARGS) **cli_common.ORM_CLIENT_KWARGS)
@ -136,7 +135,7 @@ def add_to_parser(service_sub):
h1, h2, h3 = ('[<"X-RANGER-Client" header>]', '<flavor id>', h1, h2, h3 = ('[<"X-RANGER-Client" header>]', '<flavor id>',
'<datafile with extra_specs json>',) '<datafile with extra_specs json>',)
parser_add_extra_specs = subparsers.add_parser('add_extra_specs', parser_add_extra_specs = subparsers.add_parser('add_extra_specs',
help='%s%s%s' % ( help='%s %s %s' % (
h1, h2, h3)) h1, h2, h3))
parser_add_extra_specs.add_argument('client', parser_add_extra_specs.add_argument('client',
**cli_common.ORM_CLIENT_KWARGS) **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('client', **cli_common.ORM_CLIENT_KWARGS)
parser_delete_flavor.add_argument('flavorid', type=str, help=h2) parser_delete_flavor.add_argument('flavorid', type=str, help=h2)
h1, h2 = '[<"X-RANGER-Client" header>]', '<flavor id or flavor_name>' h1, h2 = '[<"X-RANGER-Client" header>]', '<flavor id or flavor name>'
parser_get_flavor = subparsers.add_parser('get_flavor', parser_get_flavor = subparsers.add_parser('get_flavor',
help='%s %s' % (h1, h2)) help='%s %s' % (h1, h2))
parser_get_flavor.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) 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>]', h1, h2 = ('[<"X-RANGER-Client" header>]',
'[--visibility <public|private>] [--region <name>] [--tenant ' '[--visibility <public|private>] [--region <name>] [--tenant '
'<id>] [--series {gv,nv,ns,nd,ss}] [--alias <alias>]') '<id>] [--series {gv,nv,ns,nd,ss}] [--alias <alias>] '
'[--vm_type <vm_type>] [--vnf_name <vnf_name>]')
parser_list_flavor = subparsers.add_parser('list_flavors', parser_list_flavor = subparsers.add_parser('list_flavors',
help='%s %s' % (h1, h2)) help='%s %s' % (h1, h2))
parser_list_flavor.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) 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, parser_list_flavor.add_argument('--series', type=str,
choices=['gv', 'nv', 'ns', 'nd', 'ss']) choices=['gv', 'nv', 'ns', 'nd', 'ss'])
parser_list_flavor.add_argument('--alias', type=str, help='flavor alias') 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 # region for flavor
h1, h2, h3 = ('[<"X-RANGER-Client" header>]', '<flavor id>', h1, h2, h3 = ('[<"X-RANGER-Client" header>]', '<flavor id>',
@ -185,13 +187,17 @@ def add_to_parser(service_sub):
parser_add_region.add_argument('datafile', type=argparse.FileType('r'), parser_add_region.add_argument('datafile', type=argparse.FileType('r'),
help=h3) help=h3)
h1, h2, h3 = '[<"X-RANGER-Client" header>]', '<flavor id>', '<region id>' h1, h2, h3 = '[<"X-RANGER-Client" header>] [--force_delete]', \
'<flavor id>', '<region id>'
parser_delete_region = subparsers.add_parser('delete_region', parser_delete_region = subparsers.add_parser('delete_region',
help='%s %s %s' % ( help='%s %s %s' % (
h1, h2, h3)) h1, h2, h3))
parser_delete_region.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) 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('flavorid', type=str, help=h2)
parser_delete_region.add_argument('regionid', type=str, help=h3) 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 # tenant for flavor
h1, h2, h3 = ('[<"X-RANGER-Client" header>]', '<flavor id>', h1, h2, h3 = ('[<"X-RANGER-Client" header>]', '<flavor id>',
@ -236,8 +242,8 @@ def cmd_details(args):
elif args.subcmd == 'get_tags': elif args.subcmd == 'get_tags':
return requests.get, '/%s/tags' % args.flavorid return requests.get, '/%s/tags' % args.flavorid
elif args.subcmd == 'delete_region': elif args.subcmd == 'delete_region':
return requests.delete, '/%s/regions/%s' % ( return requests.delete, '/%s/regions/%s/%s' % (
args.flavorid, args.regionid) args.flavorid, args.regionid, args.force_delete)
elif args.subcmd == 'add_tenant': elif args.subcmd == 'add_tenant':
return requests.post, '/%s/tenants' % args.flavorid return requests.post, '/%s/tenants' % args.flavorid
elif args.subcmd == 'delete_tenant': elif args.subcmd == 'delete_tenant':
@ -266,6 +272,10 @@ def cmd_details(args):
param += '%stenant=%s' % (preparm(param), args.tenant) param += '%stenant=%s' % (preparm(param), args.tenant)
if args.series: if args.series:
param += '%sseries=%s' % (preparm(param), 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: if args.starts_with:
param += '%sstarts_with=%s' % (preparm(param), args.starts_with) param += '%sstarts_with=%s' % (preparm(param), args.starts_with)
if args.contains: if args.contains:
@ -300,12 +310,12 @@ def get_token(timeout, args, host):
globals()[argument] = configuration_value globals()[argument] = configuration_value
else: else:
message = ('ERROR: {} for token generation was not supplied. ' message = ('ERROR: {} for token generation was not supplied. '
'Please use its command-line ' 'Please use its command-line argument or '
'argument or environment variable.'.format(argument)) 'environment variable.'.format(argument))
print message print message
raise cli_common.MissingArgumentError(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) auth_region)
if keystone_ep is None: if keystone_ep is None:
raise ConnectionError( raise ConnectionError(
@ -333,7 +343,7 @@ def get_token(timeout, args, host):
def get_environment_variable(argument): def get_environment_variable(argument):
# The rules are: all caps, underscores instead of dashes and prefixed # The rules are: all caps, underscores instead of dashes and prefixed
environment_variable = 'RANGER_{}'.format( environment_variable = 'AIC_ORM_{}'.format(
argument.replace('-', '_').upper()) argument.replace('-', '_').upper())
return os.environ.get(environment_variable) return os.environ.get(environment_variable)
@ -341,7 +351,7 @@ def get_environment_variable(argument):
def run(args): def run(args):
host = args.orm_base_url if args.orm_base_url else config.orm_base_url 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 '{}' data = args.datafile.read() if 'datafile' in args else '{}'
timeout = args.timeout if args.timeout else 10 timeout = args.timeout if args.timeout else 10
@ -375,7 +385,7 @@ def run(args):
timeout, data, headers, rest_cmd.__name__, url)) timeout, data, headers, rest_cmd.__name__, url))
try: try:
resp = rest_cmd(url, timeout=timeout, data=data, headers=headers, resp = rest_cmd(url, timeout=timeout, data=data, headers=headers,
verify=False) verify=config.verify)
except Exception as e: except Exception as e:
print e print e
exit(1) exit(1)

View File

@ -1,11 +1,11 @@
#!/usr/bin/python #!/usr/bin/python
import argparse import argparse
import cli_common
import config import config
import orm.base_config as base_config
import os import os
import requests import requests
from orm.orm_client.ormcli import cli_common
class ResponseError(Exception): class ResponseError(Exception):
pass pass
@ -42,7 +42,7 @@ def add_to_parser(service_sub):
parser.add_argument('-v', '--verbose', help='show details', parser.add_argument('-v', '--verbose', help='show details',
action="store_true") action="store_true")
parser.add_argument('-f', '--faceless', parser.add_argument('-f', '--faceless',
help='run without authentication', help=argparse.SUPPRESS,
default=False, default=False,
action="store_true") action="store_true")
subparsers = parser.add_subparsers(dest='subcmd', 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) parser_delete_image.add_argument('imageid', type=str, help=h2)
# get images # get images
h1, h2 = '[<"X-RANGER-Client" header>]', '<image id>' h1, h2 = '[<"X-RANGER-Client" header>]', '<image id or image name>'
parser_get_image = subparsers.add_parser('get_image', parser_get_image = subparsers.add_parser('get_image',
help='%s %s' % (h1, h2)) help='%s %s' % (h1, h2))
parser_get_image.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) 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') parser_list_images.add_argument('--customer', type=str, help='customer id')
# activate/deactivate image # activate/deactivate image
h1, h2 = '[<"X-RANGER-Client" header>]', '<image id>' h1, h2, h3 = '[<"X-RANGER-Client" header>]', '<image id>', \
parser_enable = subparsers.add_parser('enable', '<data file with true/false JSON>'
help='%s %s' % (h1, h2)) parser_enable_image = subparsers.add_parser('enabled',
parser_enable.add_argument('client', **cli_common.ORM_CLIENT_KWARGS) help='%s %s %s' % (h1, h2, h3))
parser_enable.add_argument('imageid', type=str, help=h2) parser_enable_image.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
parser_enable_image.add_argument('imageid', type=str, help=h2)
parser_disable = subparsers.add_parser('disable', parser_enable_image.add_argument('datafile',
help='%s %s' % (h1, h2)) type=argparse.FileType('r'),
help=h3)
parser_disable.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
parser_disable.add_argument('imageid', type=str, help=h2)
# region for image # region for image
h1, h2, h3 = '[<"X-RANGER-Client" header>]', '<image id>', \ h1, h2, h3 = '[<"X-RANGER-Client" header>]', '<image id>', \
@ -128,7 +126,8 @@ def add_to_parser(service_sub):
type=argparse.FileType('r'), type=argparse.FileType('r'),
help=h3) help=h3)
h1, h2, h3 = '[<"X-RANGER-Client" header>]', '<image id>', '<region id>' h1, h2, h3 = '[<"X-RANGER-Client" header>] [--force_delete]', \
'<image id>', '<region id>'
parser_delete_region = subparsers.add_parser('delete_region', parser_delete_region = subparsers.add_parser('delete_region',
help='%s %s %s' % (h1, help='%s %s %s' % (h1,
h2, 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('client', **cli_common.ORM_CLIENT_KWARGS)
parser_delete_region.add_argument('imageid', type=str, help=h2) 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('regionid', type=str, help=h3)
parser_delete_region.add_argument('--force_delete',
help='force delete region',
action="store_true")
# customer for image # customer for image
h1, h2, h3 = '[<"X-RANGER-Client" header>]', '<image id>', \ h1, h2, h3 = '[<"X-RANGER-Client" header>]', '<image id>', \
@ -200,12 +202,12 @@ def get_token(timeout, args, host):
globals()[argument] = configuration_value globals()[argument] = configuration_value
else: else:
message = ('ERROR: {} for token generation was not supplied. ' message = ('ERROR: {} for token generation was not supplied. '
'Please use its command-line ' 'Please use its command-line argument or '
'argument or environment variable.'.format(argument)) 'environment variable.'.format(argument))
print message print message
raise cli_common.MissingArgumentError(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) auth_region)
if keystone_ep is None: if keystone_ep is None:
raise ConnectionError( raise ConnectionError(
@ -236,40 +238,40 @@ def preparm(p):
def cmd_details(args): def cmd_details(args):
data = args.datafile.read() if 'datafile' in args else '{}'
if args.subcmd == 'create_image': if args.subcmd == 'create_image':
cmd, url = requests.post, '' return requests.post, ''
elif args.subcmd == 'update_image': elif args.subcmd == 'update_image':
cmd, url = requests.put, '/%s' % args.imageid return requests.put, '/%s' % args.imageid
elif args.subcmd == 'delete_image': elif args.subcmd == 'delete_image':
cmd, url = requests.delete, '/%s' % args.imageid return requests.delete, '/%s' % args.imageid
# activate/deactivate image # activate/deactivate image
elif args.subcmd in ('enable', 'disable'): elif args.subcmd == 'enabled':
cmd, url = requests.put, '/%s/enabled' % args.imageid return requests.put, '/%s/enabled' % args.imageid
data = '{"enabled": %s}' % ('true' if args.subcmd == 'enable' else
'false')
# image regions # image regions
elif args.subcmd == 'add_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': 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': elif args.subcmd == 'delete_region':
cmd, url = requests.delete, '/%s/regions/%s' % (args.imageid, return requests.delete, '/%s/regions/%s/%s' % (args.imageid,
args.regionid) args.regionid,
args.force_delete)
# image customers # image customers
elif args.subcmd == 'add_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': 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': elif args.subcmd == 'delete_customer':
cmd, url = requests.delete, '/%s/customers/%s' % (args.imageid, return requests.delete, '/%s/customers/%s' % (args.imageid,
args.customerid) args.customer)
# list images # list images
elif args.subcmd == 'get_image': elif args.subcmd == 'get_image':
cmd, url = requests.get, '/%s' % args.imageid return requests.get, '/%s' % args.imageid
elif args.subcmd == 'list_images': elif args.subcmd == 'list_images':
param = '' param = ''
if args.visibility: if args.visibility:
@ -281,26 +283,22 @@ def cmd_details(args):
if args.customer: if args.customer:
param += '%scustomer=%s' % (preparm(param), param += '%scustomer=%s' % (preparm(param),
args.customer) args.customer)
cmd, url = requests.get, '/%s' % param return requests.get, '/%s' % param
return cmd, url, data
def cmd_data(args): def cmd_data(args):
# This is a special case where api has a payload needed but the CLI is # 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 # seperated into 2 different commands. In this case we need to set the
# payload. # payload.
if args.subcmd == 'enable': if args.subcmd == 'enabled':
return "{\n \"enabled\": true\n}" return "{\n \"enabled\": true\n}"
elif args.subcmd == 'disable':
return "{\n \"enabled\": false\n}"
else: else:
return args.datafile.read() if 'datafile' in args else '{}' return args.datafile.read() if 'datafile' in args else '{}'
def get_environment_variable(argument): def get_environment_variable(argument):
# The rules are: all caps, underscores instead of dashes and prefixed # The rules are: all caps, underscores instead of dashes and prefixed
environment_variable = 'RANGER_{}'.format( environment_variable = 'AIC_ORM_{}'.format(
argument.replace('-', '_').upper()) argument.replace('-', '_').upper())
return os.environ.get(environment_variable) return os.environ.get(environment_variable)
@ -308,10 +306,11 @@ def get_environment_variable(argument):
def run(args): def run(args):
host = args.orm_base_url if args.orm_base_url else config.orm_base_url 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 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 url = '%s:%d/v1/orm/images' % (host, port,) + cmd_url
if args.faceless: if args.faceless:
auth_token = auth_region = requester = client = '' auth_token = auth_region = requester = client = ''
@ -343,7 +342,7 @@ def run(args):
url)) url))
try: try:
resp = rest_cmd(url, timeout=timeout, data=data, headers=headers, resp = rest_cmd(url, timeout=timeout, data=data, headers=headers,
verify=False) verify=config.verify)
except Exception as e: except Exception as e:
print e print e
exit(1) exit(1)

View File

@ -1,9 +1,9 @@
#!/usr/bin/python #!/usr/bin/python
import argparse import argparse
import cmscli from orm.orm_client.ormcli import cmscli
import fmscli from orm.orm_client.ormcli import fmscli
import imscli from orm.orm_client.ormcli import imscli
import rmscli from orm.orm_client.ormcli import rmscli
import sys import sys

View File

@ -2,7 +2,6 @@
import argparse import argparse
import cli_common import cli_common
import config import config
import orm.base_config as base_config
import os import os
import requests import requests
@ -35,50 +34,61 @@ def add_to_parser(service_sub):
parser.add_argument('--orm-base-url', type=str, help='ORM base URL', parser.add_argument('--orm-base-url', type=str, help='ORM base URL',
default=get_environment_variable('orm-base-url')) default=get_environment_variable('orm-base-url'))
parser.add_argument('--tracking_id', type=str, help='tracking id') 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, parser.add_argument('--timeout', type=int,
help='request timeout in seconds (default: 10)') help='request timeout in seconds (default: 10)')
parser.add_argument('-v', '--verbose', help='show details', parser.add_argument('-v', '--verbose', help='show details',
action="store_true") action="store_true")
parser.add_argument('-f', '--faceless', parser.add_argument('-f', '--faceless',
help='run without authentication', help=argparse.SUPPRESS,
default=False, default=False,
action="store_true") action="store_true")
subparsers = parser.add_subparsers(dest='subcmd', subparsers = parser.add_subparsers(dest='subcmd',
metavar='<subcommand> [-h] <args>') metavar='<subcommand> [-h] <args>')
clnt_hdr = '[<"X-RANGER-Client" header>] '
# get group # get group
h1 = '<group_id>' h1 = '<group_id>'
parser_get_group = subparsers.add_parser('get_group', help=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 # get all groups
parser_list_groups = subparsers.add_parser('list_groups', help="") parser_list_groups = subparsers.add_parser('list_groups', help="")
parser_list_groups.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
# create group # create group
h1 = '<group json file>' h1 = '<data file group json file>'
parser_create_group = subparsers.add_parser('create_group', help=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'), parser_create_group.add_argument('datafile', type=argparse.FileType('r'),
help=h1) help='<data file with new group JSON>')
# update group # update group
h1, h2 = '<group json file>', '<group_id>' h1, h2 = '<group_id>', '<group json file>'
parser_update_group = subparsers.add_parser('update_group', 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('group_id', help=h2)
parser_update_group.add_argument('datafile', type=argparse.FileType('r'), parser_update_group.add_argument('datafile', type=argparse.FileType('r'),
help=h1) help='<data file with updated group '
'JSON>')
# delete group # delete group
h1 = '<group id>' h1 = '<group id>'
parser_delete_group = subparsers.add_parser('delete_group', 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) parser_delete_group.add_argument('group_id', type=str, help=h1)
# get region # get region
h1, h2 = '<region_name_or_id>', '[--use_version <api version>]' h1, h2 = '<region_name_or_id>', '[--use_version <api version>]'
parser_get_region = subparsers.add_parser('get_region', parser_get_region = subparsers.add_parser('get_region',
help='%s %s' % (h1, h2)) 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, parser_get_region.add_argument('--use_version', type=int,
help='<api version to use (1 or 2)>') help='<api version to use (1 or 2)>')
parser_get_region.add_argument('region_name_or_id', type=str, help=h1) 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 # update region
h1, h2 = '<region_id>', '<full region json file>' h1, h2 = '<region_id>', '<full region json file>'
parser_update_region = subparsers.add_parser('update_region', 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('region_id', type=str, help=h1)
parser_update_region.add_argument('datafile', type=argparse.FileType('r'), parser_update_region.add_argument('datafile', type=argparse.FileType('r'),
help=h2) help='<data file with updated region '
'JSON>')
# create region # create region
h1 = '<full region json file>' h1 = '<full region json file>'
parser_create_region = subparsers.add_parser('create_region', 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'), parser_create_region.add_argument('datafile', type=argparse.FileType('r'),
help=h2) help='<data file with new region JSON>')
# delete region # delete region
h1 = '<region id>' h1 = '<region id>'
parser_delete_region = subparsers.add_parser('delete_region', 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) parser_delete_region.add_argument('region_id', type=str, help=h1)
# list regions # list regions
parser_list_region = subparsers.add_parser('list_regions', parser_list_region = subparsers.add_parser('list_regions',
help='\ help='\
[--use_version <api version>] [--type <type>] [--status <status>]\ [--use_version <api version>] [--type <type>][--status <status>]\
[--metadata <metadata>] [--aicversion <aicversion>][--clli <clli>]\ [--metadata <metadata>] [--aicversion <aicversion>][--clli <clli>]\
[--regionname <regionname>] [--osversion <osversion>] [--valet <valet>]\ [--regionname <regionname>] [--osversion <osversion>]\
[--location_type <location_type>]\
[--state <state>] [--country <country>] [--city <city>] [--street <street>]\ [--state <state>] [--country <country>] [--city <city>] [--street <street>]\
[--zip <zip>] [--vlcp_name <vlcp_name>]') [--zip <zip>] [--vlcp_name <vlcp_name>]')
parser_list_region.add_argument('client', **cli_common.ORM_CLIENT_KWARGS)
parser_list_region.add_argument('--use_version', type=int, parser_list_region.add_argument('--use_version', type=int,
help='<api version to use>') help='<api version to use>')
parser_list_region.add_argument('--type', type=str, help='<type>') parser_list_region.add_argument('--type', type=str, help='<type>')
@ -125,7 +142,8 @@ def add_to_parser(service_sub):
help='<regionname>') help='<regionname>')
parser_list_region.add_argument('--osversion', type=str, parser_list_region.add_argument('--osversion', type=str,
help='<osversion>') help='<osversion>')
parser_list_region.add_argument('--valet', type=str, help='<valet>') parser_list_region.add_argument('--location_type', type=str,
help='<location_type>')
parser_list_region.add_argument('--state', type=str, help='<state>') parser_list_region.add_argument('--state', type=str, help='<state>')
parser_list_region.add_argument('--country', type=str, help='<country>') parser_list_region.add_argument('--country', type=str, help='<country>')
parser_list_region.add_argument('--city', type=str, help='<city>') parser_list_region.add_argument('--city', type=str, help='<city>')
@ -137,7 +155,9 @@ def add_to_parser(service_sub):
# add metadata to region # add metadata to region
h1, h2 = '<region_id>', '<metadata json file>' h1, h2 = '<region_id>', '<metadata json file>'
parser_add_metadata = subparsers.add_parser('add_metadata', 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('region_id', type=str, help=h1)
parser_add_metadata.add_argument('datafile', type=argparse.FileType('r'), parser_add_metadata.add_argument('datafile', type=argparse.FileType('r'),
help=h2) help=h2)
@ -145,7 +165,10 @@ def add_to_parser(service_sub):
# update region's metadata # update region's metadata
h1, h2 = '<region_id>', '<metadata json file>' h1, h2 = '<region_id>', '<metadata json file>'
parser_update_metadata = subparsers.add_parser('update_metadata', 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('region_id', type=str, help=h1)
parser_update_metadata.add_argument('datafile', parser_update_metadata.add_argument('datafile',
type=argparse.FileType('r'), type=argparse.FileType('r'),
@ -153,7 +176,10 @@ def add_to_parser(service_sub):
# delete metadata key from region # delete metadata key from region
h1, h2 = '<region id>', '<metadata key>' h1, h2 = '<region id>', '<metadata key>'
parser_delete_metadata = subparsers.add_parser('delete_metadata', 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('region_id', type=str, help=h1)
parser_delete_metadata.add_argument('metadata_key', type=str, help=h2) parser_delete_metadata.add_argument('metadata_key', type=str, help=h2)
@ -161,12 +187,15 @@ def add_to_parser(service_sub):
h1 = '<region id>' h1 = '<region id>'
parser_get_metadata = subparsers.add_parser('get_metadata', parser_get_metadata = subparsers.add_parser('get_metadata',
help='%s' % (h1)) 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) parser_get_metadata.add_argument('region_id', type=str, help=h1)
# update region's status # update region's status
h1, h2 = '<region_id>', '<status>' h1, h2 = '<region_id>', '<status>'
parser_update_status = subparsers.add_parser('update_status', 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('region_id', type=str, help=h1)
parser_update_status.add_argument('status', type=str, help=h2) parser_update_status.add_argument('status', type=str, help=h2)
@ -198,12 +227,12 @@ def get_token(timeout, args, host):
globals()[argument] = configuration_value globals()[argument] = configuration_value
else: else:
message = ('ERROR: {} for token generation was not supplied. ' message = ('ERROR: {} for token generation was not supplied. '
'Please use its command-line ' 'Please use its command-line argument or '
'argument or environment variable.'.format(argument)) 'environment variable.'.format(argument))
print message print message
raise cli_common.MissingArgumentError(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) auth_region)
if keystone_ep is None: if keystone_ep is None:
raise ConnectionError( raise ConnectionError(
@ -259,8 +288,9 @@ def cmd_details(args):
param += '%sregionname=%s' % (preparm(param), args.regionname) param += '%sregionname=%s' % (preparm(param), args.regionname)
if args.osversion: if args.osversion:
param += '%sosversion=%s' % (preparm(param), args.osversion) param += '%sosversion=%s' % (preparm(param), args.osversion)
if args.valet: if args.location_type:
param += '%svalet=%s' % (preparm(param), args.valet) param += '%slocation_type=%s' % (preparm(param),
args.location_type)
if args.state: if args.state:
param += '%sstate=%s' % (preparm(param), args.state) param += '%sstate=%s' % (preparm(param), args.state)
if args.country: if args.country:
@ -306,7 +336,7 @@ def get_path(args):
def get_environment_variable(argument): def get_environment_variable(argument):
# The rules are: all caps, underscores instead of dashes and prefixed # The rules are: all caps, underscores instead of dashes and prefixed
environment_variable = 'RANGER_{}'.format( environment_variable = 'AIC_ORM_{}'.format(
argument.replace('-', '_').upper()) argument.replace('-', '_').upper())
return os.environ.get(environment_variable) return os.environ.get(environment_variable)
@ -315,12 +345,16 @@ def get_environment_variable(argument):
def run(args): def run(args):
url_path = get_path(args) url_path = get_path(args)
host = args.orm_base_url if args.orm_base_url else config.orm_base_url 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 '{}' data = args.datafile.read() if 'datafile' in args else '{}'
timeout = args.timeout if args.timeout else 10 timeout = args.timeout if args.timeout else 10
rest_cmd, cmd_url = cmd_details(args) rest_cmd, cmd_url = cmd_details(args)
url = '%s:%d/%s' % (host, port, url_path) + cmd_url 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 = '' auth_token = auth_region = requester = client = ''
else: else:
try: try:
@ -361,7 +395,7 @@ def run(args):
url)) url))
try: try:
resp = rest_cmd(url, data=data, timeout=timeout, headers=headers, resp = rest_cmd(url, data=data, timeout=timeout, headers=headers,
verify=False) verify=config.verify)
except Exception as e: except Exception as e:
print e print e
exit(1) exit(1)

View File

@ -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

View File

@ -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

View File

@ -1,11 +1,9 @@
"""app module.""" """app module."""
import logging import logging
import os
from orm.services.audit_trail_manager.audit_server import model from orm.services.audit_trail_manager.audit_server import model
from orm.services.audit_trail_manager.audit_server.storage import factory from orm.services.audit_trail_manager.audit_server.storage import factory
from pecan.commands import CommandRunner
from pecan import make_app from pecan import make_app
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -26,11 +24,3 @@ def setup_app(config):
logger.info('Starting Audit...') logger.info('Starting Audit...')
return app 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'])

View File

@ -88,9 +88,16 @@ class RegionController(rest.RestController):
return result return result
@wsexpose(None, str, str, status_code=204) @wsexpose(None, str, str, str, status_code=204)
def delete(self, customer_id, region_id): def delete(self, customer_id, region_id, force_delete='False'):
LOG.info("RegionController - Delete Region (delete) customer id {0} region_id: {1}".format(customer_id, region_id))
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') authentication.authorize(request, 'customers:delete_region')
try: try:
customer_logic = CustomerLogic() customer_logic = CustomerLogic()

View File

@ -52,18 +52,15 @@ class CustomerController(rest.RestController):
authentication.authorize(request, 'customers:create') authentication.authorize(request, 'customers:create')
try: try:
uuid = None uuid = None
if not customer.custId: if not customer.uuid:
uuid = utils.make_uuid() customer.uuid = None
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))
customer_logic = CustomerLogic() 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: try:
result = customer_logic.create_customer(customer, uuid, request.transaction_id) result = customer_logic.create_customer(customer, uuid, request.transaction_id)
except oslo_db.exception.DBDuplicateEntry as exception: except oslo_db.exception.DBDuplicateEntry as exception:
@ -121,19 +118,25 @@ class CustomerController(rest.RestController):
return result return result
@wsexpose(CustomerSummaryResponse, str, str, str, str, [str], @wsexpose(CustomerSummaryResponse, str, str, str, str, [str], int, int,
rest_content_types='json') rest_content_types='json')
def get_all(self, region=None, user=None, starts_with=None, 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") LOG.info("CustomerController - GetCustomerlist")
authentication.authorize(request, 'customers:get_all') 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: try:
customer_logic = CustomerLogic() customer_logic = CustomerLogic()
result = customer_logic.get_customer_list_by_criteria(region, user, result = customer_logic.get_customer_list_by_criteria(region, user,
starts_with, starts_with,
contains, contains,
metadata) metadata,
start,
limit)
return result return result
except ErrorStatus as exception: except ErrorStatus as exception:
LOG.log_exception("CustomerController - Failed to GetCustomerlist", 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, raise err_utils.get_error(request.transaction_id,
status_code=500, status_code=500,
error_details=exception.message) 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

View File

@ -161,11 +161,19 @@ class UserController(rest.RestController):
status_code=404) status_code=404)
except Exception as exception: except Exception as exception:
result = UserResultWrapper(transaction_id="Users Not Added", users=[]) if exception.inner_exception.orig[0] == 1452:
LOG.log_exception("UserController - Failed to Add Users (post)", exception) result = UserResultWrapper(transaction_id="Users Not Added", users=[])
raise err_utils.get_error(request.transaction_id, LOG.log_exception("UserController - Failed to Add Users (post)", exception)
status_code=500, LOG.log_exception("Region specified must be added to customer first.", exception)
error_details=str(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 return result
@ -225,6 +233,7 @@ class UserController(rest.RestController):
except ErrorStatus as exception: except ErrorStatus as exception:
LOG.log_exception("DefaultUserController - Failed to delete users", exception) LOG.log_exception("DefaultUserController - Failed to delete users", exception)
raise err_utils.get_error(request.transaction_id, raise err_utils.get_error(request.transaction_id,
message=exception.message,
status_code=exception.status_code) status_code=exception.status_code)
except LookupError as exception: except LookupError as exception:

View File

@ -86,20 +86,20 @@ class DataManager(object):
cms_users = self.session.query(CmsUser) cms_users = self.session.query(CmsUser)
return cms_users.all() 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 = self.session.query(Customer).filter(
Customer.id == customer_id) Customer.id == customer_id)
return customer.first() 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) customer = self.session.query(Customer).filter(Customer.uuid == uuid)
return customer.first() 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) customer = self.session.query(Customer).filter(Customer.name == name)
return customer.first() 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( customer = self.session.query(Customer).filter(
or_(Customer.uuid == cust, or_(Customer.uuid == cust,
Customer.name == cust)) Customer.name == cust))

View File

@ -42,7 +42,7 @@ class CustomerRecord:
raise raise
def delete_by_primary_key(self, customer_id): 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 return result
def read_by_primary_key(self): def read_by_primary_key(self):
@ -69,13 +69,23 @@ class CustomerRecord:
raise raise
def get_customer_id_from_uuid(self, uuid): 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: if result:
return int(result) return int(result)
else: else:
return None 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): def delete_customer_by_uuid(self, uuid):
try: try:
result = self.session.query(Customer).filter( result = self.session.query(Customer).filter(

View File

@ -68,7 +68,7 @@ class CustomerRegionRecord:
'region with the region name {0} not found'.format( 'region with the region name {0} not found'.format(
region_name)) region_name))
result = self.session.connection().execute( 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() self.session.flush()
if result.rowcount == 0: if result.rowcount == 0:

View File

@ -27,7 +27,7 @@ class RegionRecord:
@region.setter @region.setter
def region(self, region): def region(self, region):
self.__regionn = region self.__region = region
def insert(self, region): def insert(self, region):
try: try:
@ -37,7 +37,7 @@ class RegionRecord:
raise raise
def get_region_id_from_name(self, region_name): 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: if result is not None:
return int(result) return int(result)
return result return result

View File

@ -61,8 +61,19 @@ class UserRoleRecord:
if user_id is None: if user_id is None:
raise NotFound("user %s is not found" % user_query) 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)) if region_id == -1:
print "num records deleted: " + str(result.rowcount) 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 return result
def delete_all_users_from_region(self, customer_id, region_id): def delete_all_users_from_region(self, customer_id, region_id):
@ -75,9 +86,19 @@ class UserRoleRecord:
if isinstance(region_id, basestring): if isinstance(region_id, basestring):
region_record = RegionRecord(self.session) region_record = RegionRecord(self.session)
region_id = region_record.get_region_id_from_name(region_id) 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( result = self.session.connection().execute(delete_query)
"delete from user_role where customer_id = {} and region_id = {}".format(customer_id, region_id))
print "num records deleted: " + str(result.rowcount) print "num records deleted: " + str(result.rowcount)
return result return result

View File

@ -1,31 +1,32 @@
{ {
"default": "!", "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": "role:admin and tenant:admin or role:admin and tenant:services",
"admin_or_admin_support_or_admin_viewer": "rule:admin or rule:admin_support or rule:admin_viewer", "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", "admin_or_support": "rule:admin or rule:admin_support",
"customers:get_all": "rule:admin_or_admin_support_or_admin_viewer", "admin_or_support_or_viewer": "rule:admin or rule:admin_support or rule:admin_viewer",
"customers:create": "rule:admin_or_admin_support",
"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:update": "rule:admin",
"customers:delete": "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:update_region": "rule:admin",
"customers:delete_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:update_region_user": "rule:admin",
"customers:delete_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:update_default_user": "rule:admin",
"customers:delete_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:update_metadata": "rule:admin",
"customers:enable": "rule:admin" "customers:enable": "rule:admin"

View File

@ -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, from orm.common.orm_common.utils.cross_api_utils import (get_regions_of_group,
set_utils_conf) set_utils_conf)
from orm.services.customer_manager.cms_rest.data.data_manager import DataManager 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.logger import get_logger
from orm.services.customer_manager.cms_rest.logic.error_base import (DuplicateEntryError, ErrorStatus, from orm.services.customer_manager.cms_rest.logic.error_base import (DuplicateEntryError, ErrorStatus,
NotFound) NotFound)
@ -20,49 +20,35 @@ LOG = get_logger(__name__)
class CustomerLogic(object): class CustomerLogic(object):
def build_full_customer(self, customer, uuid, datamanager): 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) sql_customer = datamanager.add_customer(customer, uuid)
for key, value in customer.metadata.iteritems(): for key, value in customer.metadata.iteritems():
metadata = CustomerMetadata(field_key=key, field_value=value) metadata = CustomerMetadata(field_key=key, field_value=value)
sql_customer.customer_metadata.append(metadata) 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 = [] default_users_requested = customer.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_region_users =\
self.add_default_user_db(datamanager, default_users_requested, [], sql_customer_id)
default_quotas = [] default_quotas = []
for quota in customer.defaultQuotas: 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) default_quotas.append(sql_quota)
for sql_user in default_region_users: self.add_regions_to_db(customer.regions, sql_customer_id, datamanager, 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)
return sql_customer return sql_customer
def add_regions_to_db(self, regions, sql_customer_id, datamanager, default_users=[]): def add_regions_to_db(self, regions, sql_customer_id, datamanager, default_users=[]):
for region in regions: 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) sql_region = datamanager.add_region(region)
try: try:
@ -73,9 +59,8 @@ class CustomerLogic(object):
'Error, duplicate entry, region ' + region.name + ' already associated with customer') 'Error, duplicate entry, region ' + region.name + ' already associated with customer')
raise ex raise ex
for user_role in users_roles: self.add_user_and_roles_to_db(region.users, default_users,
datamanager.add_user_role(user_role[0].id, user_role[1].id, sql_customer_id, sql_region.id, datamanager)
sql_customer_id, sql_region.id)
for quota in region.quotas: for quota in region.quotas:
datamanager.add_quota(sql_customer_id, sql_region.id, quota) datamanager.add_quota(sql_customer_id, sql_region.id, quota)
@ -91,20 +76,76 @@ class CustomerLogic(object):
# datamanager.add_quota(sql_customer_id, # datamanager.add_quota(sql_customer_id,
# sql_region.id, quota) # sql_region.id, quota)
def add_user_and_roles_to_db(self, users, default_users, datamanager): def add_default_user_db(self, datamanager, default_users_requested, existing_default_users_roles, sql_customer_id):
users_roles = [] default_region_users = []
for user in users: default_users_dic = {}
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))
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): def create_customer(self, customer, uuid, transaction_id):
datamanager = DataManager() datamanager = DataManager()
@ -113,7 +154,6 @@ class CustomerLogic(object):
sql_customer = self.build_full_customer(customer, uuid, datamanager) sql_customer = self.build_full_customer(customer, uuid, datamanager)
customer_result_wrapper = build_response(uuid, transaction_id, 'create') 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: if sql_customer.customer_customer_regions and len(sql_customer.customer_customer_regions) > 1:
customer_dict = sql_customer.get_proxy_dict() customer_dict = sql_customer.get_proxy_dict()
for region in customer_dict["regions"]: for region in customer_dict["regions"]:
@ -150,7 +190,6 @@ class CustomerLogic(object):
sql_customer = self.build_full_customer(customer, customer_uuid, sql_customer = self.build_full_customer(customer, customer_uuid,
datamanager) datamanager)
sql_customer = self.add_default_users_to_empty_regions(sql_customer)
new_customer_dict = sql_customer.get_proxy_dict() new_customer_dict = sql_customer.get_proxy_dict()
new_customer_dict["regions"] = self.resolve_regions_actions(old_customer_dict["regions"], new_customer_dict["regions"] = self.resolve_regions_actions(old_customer_dict["regions"],
new_customer_dict["regions"]) new_customer_dict["regions"])
@ -202,11 +241,19 @@ class CustomerLogic(object):
if region_id is None: if region_id is None:
raise ErrorStatus(404, "region {} not found".format(region_name)) 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_record = datamanager.get_record('customer')
customer = customer_record.read_customer(customer_id) 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() timestamp = utils.get_time_human()
datamanager.flush() # i want to get any exception created by this insert datamanager.flush() # i want to get any exception created by this insert
RdsProxy.send_customer(customer, transaction_id, "PUT") RdsProxy.send_customer(customer, transaction_id, "PUT")
@ -256,29 +303,12 @@ class CustomerLogic(object):
LOG.log_exception("Failed to replace_default_users", exception) LOG.log_exception("Failed to replace_default_users", exception)
raise 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): def delete_users(self, customer_uuid, region_id, user_id, transaction_id):
datamanager = DataManager() datamanager = DataManager()
try: try:
user_role_record = datamanager.get_record('user_role') 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: if customer is None:
raise ErrorStatus(404, "customer {} does not exist".format(customer_uuid)) raise ErrorStatus(404, "customer {} does not exist".format(customer_uuid))
@ -286,13 +316,24 @@ class CustomerLogic(object):
region_id, region_id,
user_id) user_id)
if result.rowcount == 0: 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") RdsProxy.send_customer(customer, transaction_id, "PUT")
datamanager.commit() datamanager.commit()
print "User {0} from region {1} in customer {2} deleted".format( LOG.info("User {0} from region {1} in customer {2} deleted".
user_id, region_id, customer_uuid) format(user_id, region_id, customer_uuid))
except NotFound as e: except NotFound as e:
datamanager.rollback() datamanager.rollback()
LOG.log_exception("Failed to delete_users, user not found", LOG.log_exception("Failed to delete_users, user not found",
@ -318,10 +359,25 @@ class CustomerLogic(object):
if customer_id is None: if customer_id is None:
raise ErrorStatus(404, "customer {} does not exist".format(customer_uuid)) 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_record = datamanager.get_record('customer')
customer = customer_record.read_customer(customer_id) 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() timestamp = utils.get_time_human()
datamanager.flush() # i want to get any exception created by this insert 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): def delete_default_users(self, customer_uuid, user_id, transaction_id):
datamanager = DataManager() datamanager = DataManager()
try: try:
customer = datamanager.get_cusomer_by_uuid(customer_uuid) customer = datamanager.get_customer_by_uuid(customer_uuid)
if customer is None: if customer is None:
raise ErrorStatus(404, "customer {} does not exist".format(customer_uuid)) 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, result = user_role_record.delete_user_from_region(customer_uuid,
'DEFAULT', 'DEFAULT',
user_id) user_id)
if result.rowcount == 0: 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() datamanager.commit()
print "User {0} from region {1} in customer {2} deleted".format( LOG.info("User {0} from region {1} in customer {2} deleted".
user_id, 'DEFAULT', customer_uuid) format(user_id, 'DEFAULT', customer_uuid))
except NotFound as e: except NotFound as e:
datamanager.rollback() datamanager.rollback()
LOG.log_exception("Failed to delete_users, user not found", LOG.log_exception("Failed to delete_users, user not found",
e.message) e.message)
raise NotFound("Failed to delete users, %s not found" % raise NotFound("Failed to delete user(s), %s not found" %
e.message) e.message)
except Exception as exp: except Exception as exp:
@ -412,11 +471,26 @@ class CustomerLogic(object):
raise ErrorStatus(404, raise ErrorStatus(404,
"customer with id {} does not exist".format( "customer with id {} does not exist".format(
customer_uuid)) customer_uuid))
self.add_regions_to_db(regions, customer_id, datamanager)
sql_customer = customer_record.read_customer_by_uuid(customer_uuid) 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() new_customer_dict = sql_customer.get_proxy_dict()
for region in new_customer_dict["regions"]: for region in new_customer_dict["regions"]:
@ -427,9 +501,7 @@ class CustomerLogic(object):
region["action"] = "modify" region["action"] = "modify"
timestamp = utils.get_time_human() 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") RdsProxy.send_customer_dict(new_customer_dict, transaction_id, "POST")
datamanager.commit()
base_link = '{0}{1}/'.format(conf.server.host_ip, base_link = '{0}{1}/'.format(conf.server.host_ip,
pecan.request.path) pecan.request.path)
@ -462,16 +534,23 @@ class CustomerLogic(object):
"customer with id {} does not exist".format( "customer with id {} does not exist".format(
customer_id)) customer_id))
old_customer_dict = old_sql_customer.get_proxy_dict() 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) datamanager.session.expire(old_sql_customer)
customer_region.delete_all_regions_for_customer(customer_id) 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() 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() new_customer_dict = new_sql_customer.get_proxy_dict()
datamanager.flush() # i want to get any exception created by this insert datamanager.flush() # i want to get any exception created by this insert
@ -496,12 +575,15 @@ class CustomerLogic(object):
datamanager.rollback() datamanager.rollback()
raise exp 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() datamanager = DataManager()
try: try:
customer_region = datamanager.get_record('customer_region') 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: if sql_customer is None:
raise ErrorStatus(404, raise ErrorStatus(404,
"customer with id {} does not exist".format( "customer with id {} does not exist".format(
@ -509,36 +591,42 @@ class CustomerLogic(object):
customer_dict = sql_customer.get_proxy_dict() customer_dict = sql_customer.get_proxy_dict()
customer_region.delete_region_for_customer(customer_id, region_id) 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 if on_success_by_rds:
datamanager.flush() 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) RdsProxy.send_customer_dict(customer_dict, transaction_id, "PUT")
if region: if force_delete:
if region.type == 'group': datamanager.commit()
set_utils_conf(conf)
regions = get_regions_of_group(region.name)
else: else:
regions = [region_id] datamanager.rollback()
for region in customer_dict['regions']:
if region['name'] in regions:
region['action'] = 'delete'
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: except Exception as exp:
datamanager.rollback() datamanager.rollback()
raise raise
finally:
datamanager.close()
def get_customer(self, customer): def get_customer(self, customer):
datamanager = DataManager() 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: if not sql_customer:
raise ErrorStatus(404, 'customer: {0} not found'.format(customer)) raise ErrorStatus(404, 'customer: {0} not found'.format(customer))
@ -564,24 +652,28 @@ class CustomerLogic(object):
return ret_customer return ret_customer
def get_customer_list_by_criteria(self, region, user, starts_with, contains, def get_customer_list_by_criteria(self, region, user, starts_with, contains,
metadata): metadata, start=0, limit=0):
datamanager = DataManager() datamanager = DataManager()
customer_record = datamanager.get_record('customer') customer_record = datamanager.get_record('customer')
sql_customers = customer_record.get_customers_by_criteria(region=region, sql_customers = customer_record.get_customers_by_criteria(region=region,
user=user, user=user,
starts_with=starts_with, starts_with=starts_with,
contains=contains, contains=contains,
metadata=metadata) metadata=metadata,
start=start,
limit=limit)
response = CustomerSummaryResponse() response = CustomerSummaryResponse()
for sql_customer in sql_customers: if sql_customers:
# get aggregate status for each customer uuids = ','.join(str("\'" + sql_customer.uuid + "\'")
customer_status = RdsProxy.get_status(sql_customer.uuid) for sql_customer in sql_customers if sql_customer and sql_customer.uuid)
customer = CustomerSummary.from_db_model(sql_customer) resource_status_dict = customer_record.get_customers_status_by_uuids(uuids)
if customer_status.status_code == 200:
customer.status = customer_status.json()['status']
response.customers.append(customer)
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 return response
def enable(self, customer_uuid, enabled, transaction_id): 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.flush() # get any exception created by this action
datamanager.commit() datamanager.commit()
customer_result_wrapper = build_response(customer_uuid, transaction_id, 'update')
return customer_result_wrapper
except Exception as exp: except Exception as exp:
datamanager.rollback() datamanager.rollback()
raise exp 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): def delete_customer_by_uuid(self, customer_id):
datamanager = DataManager() datamanager = DataManager()
@ -633,9 +710,7 @@ class CustomerLogic(object):
sql_customer = customer_record.read_customer_by_uuid(customer_id) sql_customer = customer_record.read_customer_by_uuid(customer_id)
if sql_customer is None: if sql_customer is None:
# The customer does not exist, so the delete operation is raise ErrorStatus(404, "Customer '{0}' not found".format(customer_id))
# considered successful
return
real_regions = sql_customer.get_real_customer_regions() real_regions = sql_customer.get_real_customer_regions()
if len(real_regions) > 0: if len(real_regions) > 0:
@ -706,7 +781,7 @@ def build_response(customer_uuid, transaction_id, context):
link_elements = request.url.split('/') link_elements = request.url.split('/')
base_link = '/'.join(link_elements) base_link = '/'.join(link_elements)
if context == 'create': if context == 'create':
base_link += customer_uuid base_link = base_link + '/' + customer_uuid
timestamp = utils.get_time_human() timestamp = utils.get_time_human()
customer_result_wrapper = CustomerResultWrapper( customer_result_wrapper = CustomerResultWrapper(

View File

@ -112,17 +112,19 @@ class Network(Model):
subnets = wsme.wsattr(wsme.types.text, mandatory=True) subnets = wsme.wsattr(wsme.types.text, mandatory=True)
security_groups = wsme.wsattr(wsme.types.text, mandatory=False, name="security-groups") 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") 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") health_monitors = wsme.wsattr(wsme.types.text, mandatory=False, name="health-monitors")
member = wsme.wsattr(wsme.types.text, mandatory=False) members = wsme.wsattr(wsme.types.text, mandatory=False)
nat_instance = wsme.wsattr(wsme.types.text, mandatory=False, name="nat-instance") 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") 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='', def __init__(self, floating_ips='', networks='', ports='', routers='',
subnets='', security_groups=None, security_group_rules=None, subnets='', security_groups=None, security_group_rules=None,
health_monitor='', member='', nat_instance='', health_monitors='', members='', nat_instance='',
pool='', route_table='', vip=''): pools='', route_table='', vips='', loadbalancer='', listener=''):
"""Create a new Network instance. """Create a new Network instance.
:param floating_ips: num of floating_ips :param floating_ips: num of floating_ips
@ -132,12 +134,14 @@ class Network(Model):
:param subnets: num of subnets :param subnets: num of subnets
:param security_groups: security groups :param security_groups: security groups
:param security_group_rules: security group rules :param security_group_rules: security group rules
:param health_monitor: :param health_monitors:
:param member: :param members:
:param nat_instance: :param nat_instance:
:param pool: :param pools:
:param route_table: :param route_table:
:param vip: :param vips:
:param loadbalancer:
:param listener:
""" """
self.floating_ips = floating_ips self.floating_ips = floating_ips
self.networks = networks self.networks = networks
@ -153,17 +157,18 @@ class Network(Model):
else: else:
self.security_group_rules = security_group_rules self.security_group_rules = security_group_rules
self.health_monitor = health_monitor self.health_monitors = health_monitors
self.member = member self.members = members
self.nat_instance = nat_instance self.nat_instance = nat_instance
self.pool = pool self.pools = pools
self.route_table = route_table self.route_table = route_table
self.vip = vip self.vips = vips
self.loadbalancer = loadbalancer
self.listener = listener
class Quota(Model): class Quota(Model):
"""network model the customer """network model the customer
""" """
compute = wsme.wsattr([Compute], mandatory=False) compute = wsme.wsattr([Compute], mandatory=False)
storage = wsme.wsattr([Storage], mandatory=False) storage = wsme.wsattr([Storage], mandatory=False)
@ -183,7 +188,6 @@ class Quota(Model):
class User(Model): class User(Model):
"""user model the customer """user model the customer
""" """
id = wsme.wsattr(wsme.types.text, mandatory=True) id = wsme.wsattr(wsme.types.text, mandatory=True)
role = wsme.wsattr([str]) role = wsme.wsattr([str])
@ -200,7 +204,6 @@ class User(Model):
class Region(Model): class Region(Model):
"""network model the customer """network model the customer
""" """
name = wsme.wsattr(wsme.types.text, mandatory=True) name = wsme.wsattr(wsme.types.text, mandatory=True)
type = wsme.wsattr(wsme.types.text, default="single", mandatory=False) type = wsme.wsattr(wsme.types.text, default="single", mandatory=False)
@ -232,7 +235,6 @@ class Region(Model):
class Customer(Model): class Customer(Model):
"""customer entity with all it's related data """customer entity with all it's related data
""" """
description = wsme.wsattr(wsme.types.text, mandatory=True) description = wsme.wsattr(wsme.types.text, mandatory=True)
enabled = wsme.wsattr(bool, mandatory=True) enabled = wsme.wsattr(bool, mandatory=True)

View File

@ -88,3 +88,8 @@ create table if not exists user_role
foreign key (role_id) references cms_role(id), foreign key (role_id) references cms_role(id),
index region_id (region_id), index region_id (region_id),
index user_id (user_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);

View File

@ -78,14 +78,16 @@ SELECT q.*, qfd.* FROM quota_field_detail qfd
DELIMITER ;; DELIMITER ;;
# account for the old procedure name in DROP PROCEDURE before the name change
DROP PROCEDURE IF EXISTS add_regoion_type ;; 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 BEGIN
-- add a column safely -- add a column safely
IF NOT EXISTS( (SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() IF NOT EXISTS( (SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE()
AND COLUMN_NAME='type' AND TABLE_NAME='region') ) THEN 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 ELSE
UPDATE region set type = "single" where id = -1; UPDATE region set type = "single" where id = -1;
END IF; END IF;
@ -96,7 +98,7 @@ BEGIN
END ;; END ;;
CALL add_regoion_type() ;; CALL add_region_type() ;;
DELIMITER ; DELIMITER ;

View File

@ -886,17 +886,17 @@ definitions:
type: string type: string
security_group_rules: security_group_rules:
type: string type: string
health_monitor: health_monitors:
type: string type: string
member: members:
type: string type: string
nat_instance: nat_instance:
type: string type: string
pool: pools:
type: string type: string
route_table: route_table:
type: string type: string
vip: vips:
type: string type: string
Quota: Quota:

View File

@ -153,3 +153,19 @@ authentication = {
"keystone_version": "2.0", "keystone_version": "2.0",
"policy_file": config.fms['policy_file'], "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']
}

View File

@ -1,11 +1,10 @@
import os
from orm.common.orm_common.policy import policy 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.data import wsme
from orm.services.flavor_manager.fms_rest.logger import get_logger from orm.services.flavor_manager.fms_rest.logger import get_logger
from orm.services.flavor_manager.fms_rest.utils import authentication from orm.services.flavor_manager.fms_rest.utils import authentication
from pecan.commands import CommandRunner from pecan.commands import CommandRunner
from pecan import make_app from pecan import make_app
logger = get_logger(__name__) logger = get_logger(__name__)
@ -27,8 +26,8 @@ def setup_app(config):
def main(): 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 = CommandRunner()
runner.run(['serve', path + '/config.py']) runner.run(['serve', '../config.py'])
if __name__ == "__main__":
main()

View File

@ -2,6 +2,7 @@ from __future__ import absolute_import
from orm.common.orm_common.injector import injector 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 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.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.regions import RegionController
from orm.services.flavor_manager.fms_rest.controllers.v1.orm.flavors.tags import TagsController 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.logic.error_base import ErrorStatus
from orm.services.flavor_manager.fms_rest.utils import authentication 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 from wsmeext.pecan import wsexpose
di = injector.get_di() di = injector.get_di()
@ -31,21 +32,17 @@ class FlavorController(rest.RestController):
@wsexpose(FlavorWrapper, body=FlavorWrapper, rest_content_types='json', status_code=201) @wsexpose(FlavorWrapper, body=FlavorWrapper, rest_content_types='json', status_code=201)
def post(self, flavors): def post(self, flavors):
flavor_logic, utils = di.resolver.unpack(FlavorController) flavor_logic, utils = di.resolver.unpack(FlavorController)
uuid = "FailedToGetFromUUIDGen" uuid = ""
LOG.info("FlavorController - Createflavor: " + str(flavors)) LOG.info("FlavorController - Createflavor: " + str(flavors))
authentication.authorize(request, 'flavor:create') authentication.authorize(request, 'flavor:create')
common_utils.set_utils_conf(conf)
try: try:
try:
if not flavors.flavor.id: uuid = common_utils.create_or_validate_uuid(flavors.flavor.id, 'fmsId')
uuid = utils.make_uuid() except TypeError:
else: LOG.error("UUID already exists")
try: raise ErrorStatus(409, 'UUID already exists')
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')
result = flavor_logic.create_flavor(flavors, uuid, request.transaction_id) result = flavor_logic.create_flavor(flavors, uuid, request.transaction_id)
@ -106,17 +103,20 @@ class FlavorController(rest.RestController):
status_code=500, status_code=500,
error_details=str(exception)) 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, 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) flavor_logic, utils = di.resolver.unpack(FlavorController)
LOG.info("FlavorController - GetFlavorlist") LOG.info("FlavorController - GetFlavorlist")
authentication.authorize(request, 'flavor:get_all') authentication.authorize(request, 'flavor:get_all')
try: try:
result = flavor_logic.get_flavor_list_by_params(visibility, region, 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 return result
except ErrorStatus as exception: except ErrorStatus as exception:
LOG.log_exception("FlavorController - Failed to GetFlavorlist", exception) LOG.log_exception("FlavorController - Failed to GetFlavorlist", exception)

View File

@ -1,5 +1,6 @@
from __future__ import absolute_import from __future__ import absolute_import
from orm.common.orm_common.injector import injector 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 api_error_utils as err_utils
from orm.services.flavor_manager.fms_rest.data.wsme.models import RegionWrapper from orm.services.flavor_manager.fms_rest.data.wsme.models import RegionWrapper
@ -49,23 +50,30 @@ class RegionController(rest.RestController):
status_code=500, status_code=500,
error_details=str(exception)) error_details=str(exception))
@wsexpose(None, str, str, rest_content_types='json', status_code=204) @wsexpose(None, str, str, str, rest_content_types='json', status_code=204)
def delete(self, flavor_id, region_name): 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) 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') authentication.authorize(request, 'flavor:delete_flavor_region')
try: 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, event_details = 'Flavor {} region {} deleted'.format(flavor_id,
region_name) region_name)
utils.audit_trail('delete region', request.transaction_id, utils.audit_trail('delete region', request.transaction_id,
request.headers, flavor_id, request.headers, flavor_id,
event_details=event_details) event_details=event_details)
except ErrorStatus as exception: except ErrorStatus as exception:
LOG.log_exception("RegionController - Failed to delete region", exception) LOG.log_exception("RegionController - Failed to delete region", exception)

View File

@ -24,7 +24,6 @@ LOG = logging.getLogger(__name__)
# event handling # event handling
def on_before_flush(session, flush_context, instances): def on_before_flush(session, flush_context, instances):
LOG.info("on_before_flush:", str(flush_context))
for model in session.new: for model in session.new:
if hasattr(model, "validate"): if hasattr(model, "validate"):
model.validate("new") model.validate("new")

View File

@ -31,9 +31,9 @@ class FMSBaseModel(models.ModelBase):
class Flavor(Base, FMSBaseModel): 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 defined as SqlAlchemy model map to a table
""" '''
__tablename__ = "flavor" __tablename__ = "flavor"
internal_id = Column(BigInteger, primary_key=True) internal_id = Column(BigInteger, primary_key=True)
@ -187,7 +187,7 @@ class Flavor(Base, FMSBaseModel):
self.add_tags(flavor_tags) self.add_tags(flavor_tags)
except Exception as exception: 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) str(flavor_tags), str(self)), exception)
raise raise
@ -196,7 +196,7 @@ class Flavor(Base, FMSBaseModel):
LOG.debug("remove all tags from flavor {}".format(str(self))) LOG.debug("remove all tags from flavor {}".format(str(self)))
self.flavor_tags = [] self.flavor_tags = []
except Exception as exception: 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 raise
def remove_tag(self, tag_name): def remove_tag(self, tag_name):
@ -239,6 +239,7 @@ class Flavor(Base, FMSBaseModel):
raise raise
def remove_tenant(self, tenant_id): def remove_tenant(self, tenant_id):
deleted_flag = False
assert isinstance(tenant_id, basestring) assert isinstance(tenant_id, basestring)
try: try:
LOG.debug("remove tenants {0} from flavor {1}".format(tenant_id, 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): for tenant in reversed(self.flavor_tenants):
if tenant.tenant_id == tenant_id: if tenant.tenant_id == tenant_id:
self.flavor_tenants.remove(tenant) 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: except Exception as exception:
LOG.log_exception( LOG.log_exception(
@ -292,10 +299,9 @@ class Flavor(Base, FMSBaseModel):
deleted_flag = True deleted_flag = True
if not deleted_flag: if not deleted_flag:
# no need to raise in delete not found raise ErrorStatus(404,
LOG.debug( "extra spec {0} does not exist for flavor id {1}".format(
"Failed to remove extra_spec {0} from flavor id {1}".format( extra_spec_key_name, str(self.id)))
extra_spec_key_name, str(self.id)))
except ErrorStatus as e: except ErrorStatus as e:
raise 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) "Failed to remove extra_spec {0} from flavor {1}".format(extra_spec_key_name, str(self)), exception)
raise 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): def validate(self, type):
''' type can be "new" or "dirty" - comes from event ''' type can be "new" or "dirty" - comes from event
''' '''
@ -456,8 +402,8 @@ class FlavorTag(Base, FMSBaseModel):
) )
def __str__(self): def __str__(self):
tag = "\"{0}\":\"{1}\"".format(self.key_name, self.key_value) tags = "\"{0}\":\"{1}\"".format(self.key_name, self.key_value)
return tag return tags
''' '''

View File

@ -1,5 +1,6 @@
from orm.services.flavor_manager.fms_rest.data.sql_alchemy.db_models import (Flavor,
from orm.services.flavor_manager.fms_rest.data.sql_alchemy.db_models import (Flavor, FlavorRegion, FlavorRegion,
FlavorTag,
FlavorTenant) FlavorTenant)
from orm.services.flavor_manager.fms_rest.logger import get_logger from orm.services.flavor_manager.fms_rest.logger import get_logger
@ -148,6 +149,16 @@ class FlavorRecord:
LOG.log_exception(message, exception) LOG.log_exception(message, exception)
raise 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): def get_flavors_by_criteria(self, **criteria):
try: try:
@ -156,6 +167,8 @@ class FlavorRecord:
region = criteria['region'] if 'region' in criteria else None region = criteria['region'] if 'region' in criteria else None
tenant = criteria['tenant'] if 'tenant' in criteria else None tenant = criteria['tenant'] if 'tenant' in criteria else None
series = criteria['series'] if 'series' 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 starts_with = criteria['starts_with'] if 'starts_with' in criteria else None
contains = criteria['contains'] if 'contains' in criteria else None contains = criteria['contains'] if 'contains' in criteria else None
alias = criteria['alias'] if 'alias' in criteria else None alias = criteria['alias'] if 'alias' in criteria else None
@ -177,7 +190,14 @@ class FlavorRecord:
if tenant: if tenant:
query = query.join(FlavorTenant).filter(FlavorTenant.flavor_internal_id == Flavor.internal_id, query = query.join(FlavorTenant).filter(FlavorTenant.flavor_internal_id == Flavor.internal_id,
FlavorTenant.tenant_id == tenant) 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: if visibility:
query = query.filter(Flavor.visibility == visibility) query = query.filter(Flavor.visibility == visibility)

View File

@ -1,6 +1,8 @@
import wsme 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.sql_alchemy import db_models
from orm.services.flavor_manager.fms_rest.data.wsme.model import Model from orm.services.flavor_manager.fms_rest.data.wsme.model import Model
from orm.services.flavor_manager.fms_rest.logic.error_base import ErrorStatus from orm.services.flavor_manager.fms_rest.logic.error_base import ErrorStatus
@ -42,7 +44,6 @@ class ExtraSpecsWrapper(Model):
def to_db_model(self): def to_db_model(self):
extra_spec = [] extra_spec = []
for key, value in self.os_extra_specs.iteritems(): for key, value in self.os_extra_specs.iteritems():
if Flavor.ignore_extra_specs_input(key.replace(":", "____")): if Flavor.ignore_extra_specs_input(key.replace(":", "____")):
continue continue
@ -164,7 +165,6 @@ class Flavor(Model):
visibility = wsme.wsattr(wsme.types.text, mandatory=True) visibility = wsme.wsattr(wsme.types.text, mandatory=True)
tenants = wsme.wsattr(wsme.types.ArrayType(str), mandatory=False) tenants = wsme.wsattr(wsme.types.ArrayType(str), mandatory=False)
status = wsme.wsattr(wsme.types.text, 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) tag = wsme.wsattr(wsme.types.DictType(str, str), mandatory=False)
options = 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, extra_specs = wsme.wsattr(wsme.types.DictType(str, str), mandatory=False,
@ -182,7 +182,6 @@ class Flavor(Model):
swap="0", swap="0",
ephemeral="0", ephemeral="0",
extra_specs={}, extra_specs={},
tags={},
tag={}, tag={},
options={}, options={},
regions=[], regions=[],
@ -199,7 +198,7 @@ class Flavor(Model):
:param vcpus: :param vcpus:
:param disk: Disk in GB :param disk: Disk in GB
:param swap: is optional and default is 0 :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 extra_spec: key-value dictionary
:param tags: key-value dictionary :param tags: key-value dictionary
:param options: key-value dictionary :param options: key-value dictionary
@ -220,7 +219,6 @@ class Flavor(Model):
self.swap = swap self.swap = swap
self.ephemeral = "0" if not ephemeral else ephemeral self.ephemeral = "0" if not ephemeral else ephemeral
self.extra_specs = extra_specs self.extra_specs = extra_specs
self.tags = tags
self.tag = tag self.tag = tag
self.options = options self.options = options
self.regions = regions self.regions = regions
@ -232,13 +230,20 @@ class Flavor(Model):
bundle = ['b1', 'b2'] bundle = ['b1', 'b2']
numa = ['n0', 'n1'] numa = ['n0', 'n1']
vlan = ['v1', 'v2', 'v3', 'v4', 'v5', 'v6'] 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: 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(): if not self.ram.isdigit():
raise ErrorStatus(400, "ram must be a number") raise ErrorStatus(400, "ram must be a number")
if not self.vcpus.isdigit(): if not self.vcpus.isdigit():
raise ErrorStatus(400, "vcpus must be a number") 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") raise ErrorStatus(400, "disk must be a number")
if not self.swap.isdigit(): if not self.swap.isdigit():
raise ErrorStatus(400, "swap must be a number") raise ErrorStatus(400, "swap must be a number")
@ -249,20 +254,24 @@ class Flavor(Model):
if self.series not in allowed_series: if self.series not in allowed_series:
raise ErrorStatus(400, "series possible values are {}".format( raise ErrorStatus(400, "series possible values are {}".format(
allowed_series)) 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, raise ErrorStatus(400,
"ram value is out of range. Expected range is 1024(1GB)-327680(320GB) " "ram value is out of range. Expected range is 1024(1GB)-"
"and must be a multiple of 1024") "%6d(%3dGB) and must be a multiple of 1024" %
if int(self.vcpus) not in range(1, 48 + 1): (vram_limit, vram_limit / 1024))
raise ErrorStatus(400, "vcpus value is out of range. Expected range is 1-48") 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: if int(self.disk) < 0:
raise ErrorStatus(400, "disk must be a non negative number") raise ErrorStatus(400, "disk cannot be less than zero")
if int(self.ephemeral) not in range(0, 320 + 1): if int(self.ephemeral) not in range(0, ephemeral_limit + 1):
raise ErrorStatus(400, "ephemeral value is out of range. Expected range is 0-320") raise ErrorStatus(400, "ephemeral value is out of range. Expected range is 0-"
if int(self.swap) not in range(0, 327680 + 1, 1024): "%5d(%2dTB)" % (ephemeral_limit, ephemeral_limit / 1000))
if int(self.swap) not in range(0, swap_file_limit + 1, 1024):
raise ErrorStatus(400, raise ErrorStatus(400,
"swap value is out of range. Expected range is 0-327680(320GB) " "swap value is out of range. Expected range is 0-"
"and must be a multiple of 1024") "%6d(%3dGB) and must be a multiple of 1024" %
(swap_file_limit, swap_file_limit / 1024))
except ValueError: except ValueError:
raise ErrorStatus(400, "ram, vcpus, disk, ephemeral and swap must be integers") raise ErrorStatus(400, "ram, vcpus, disk, ephemeral and swap must be integers")
for symbol, value in self.extra_specs.iteritems(): for symbol, value in self.extra_specs.iteritems():
@ -284,13 +293,6 @@ class Flavor(Model):
"region type \'group\' is invalid in this " "region type \'group\' is invalid in this "
"action, \'group\' can be only in create flavor action") "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): def to_db_model(self):
flavor = db_models.Flavor() flavor = db_models.Flavor()
extra_spec = [] extra_spec = []
@ -310,7 +312,7 @@ class Flavor(Model):
if self.series: if self.series:
extra_spec.extend(self.get_extra_spec_needed()) 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 = db_models.FlavorTag()
tag.key_name = symbol tag.key_name = symbol
tag.key_value = value tag.key_value = value
@ -389,7 +391,7 @@ class Flavor(Model):
flavor.extra_specs[extra_spec.key_name] = extra_spec.key_value flavor.extra_specs[extra_spec.key_name] = extra_spec.key_value
for tag in sql_flavor.flavor_tags: 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: for option in sql_flavor.flavor_options:
flavor.options[option.key_name] = option.key_value flavor.options[option.key_name] = option.key_value
@ -406,38 +408,52 @@ class Flavor(Model):
return False return False
def get_extra_spec_needed(self): 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 = [] extra_spec_needed = []
items = conf.extra_spec_needed_table.to_dict() items = conf.extra_spec_needed_table.to_dict()
for symbol, value in items[self.series].iteritems(): for symbol, value in items[self.series].iteritems():
es = db_models.FlavorExtraSpec() es = db_models.FlavorExtraSpec()
es.key_name = symbol.replace("____", ":") es.key_name = symbol.replace("____", ":")
es.key_value = value es.key_value = value
# update extra_spec default values as needed
if self.series == "gv" and "c2" in es.key_name: if self.series == "gv" and "c2" in es.key_name:
if "c4" in self.options and self.options['c4'].lower() == "true": if "c4" in self.options and self.options['c4'].lower() == "true":
es.key_name = es.key_name.replace("c2", "c4") 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) extra_spec_needed.append(es)
options_items = self.options options_items = self.options
# check some keys if they exist in option add values to extra specs # 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 c2_c4_in = False
n0_in = False n0_in = False
for symbol, value in options_items.iteritems(): for symbol, value in options_items.iteritems():
es = db_models.FlavorExtraSpec() es = db_models.FlavorExtraSpec()
es.key_name = "aggregate_instance_extra_specs:%s" % symbol es.key_name = "aggregate_instance_extra_specs:%s" % symbol
es.key_value = "true" es.key_value = "true"
# format numa node extra spec as appropriate
if symbol == "n0" and options_items[symbol].lower() == "true": if symbol == "n0" and options_items[symbol].lower() == "true":
n0_in = True n0_in = True
es.key_value = 2 es.key_value = 2
es.key_name = "hw:numa_nodes" es.key_name = "hw:numa_nodes"
extra_spec_needed.append(es) 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 c2_c4_in = True
extra_spec_needed.append(es) extra_spec_needed.append(es)
# format vnf profile extra spec as appropriate
try: 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) extra_spec_needed.append(es)
except Exception: except Exception:
pass pass
# if c4, c2 and n0 not in options keys add these values to extra specs # if c4, c2 and n0 not in options keys add these values to extra specs
if not c2_c4_in: if not c2_c4_in:
es = db_models.FlavorExtraSpec() es = db_models.FlavorExtraSpec()
@ -449,6 +465,33 @@ class Flavor(Model):
es.key_value = 1 es.key_value = 1
es.key_name = "hw:numa_nodes" es.key_name = "hw:numa_nodes"
extra_spec_needed.append(es) 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 return extra_spec_needed
def get_as_summary_dict(self): def get_as_summary_dict(self):
@ -478,6 +521,13 @@ class Flavor(Model):
regions = get_regions_of_group(group_name) regions = get_regions_of_group(group_name)
return regions return regions
def validInt(self, check_value):
try:
int(check_value)
except ValueError:
return False
return True
class FlavorWrapper(Model): class FlavorWrapper(Model):
"""flavor model """flavor model

View File

@ -1,10 +1,11 @@
{ {
"default": "!", "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", "admin_or_support_or_viewer": "rule:admin or rule:admin_support or rule:admin_viewer",
"flavor:create": "rule:admin_or_support", "flavor:create": "rule:admin_or_support",
@ -12,9 +13,9 @@
"flavor:get_all": "rule:admin_or_support_or_viewer", "flavor:get_all": "rule:admin_or_support_or_viewer",
"flavor:delete": "rule:admin", "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: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:delete_flavor_extra_specs": "rule:admin",
"flavor:add_flavor_regions": "rule:admin_or_support", "flavor:add_flavor_regions": "rule:admin_or_support",
@ -22,7 +23,7 @@
"flavor:get_flavor_tags": "rule:admin_or_support_or_viewer", "flavor:get_flavor_tags": "rule:admin_or_support_or_viewer",
"flavor:add_flavor_tags": "rule:admin_or_support", "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:delete_flavor_tags": "rule:admin",
"flavor:add_flavor_tenants": "rule:admin_or_support", "flavor:add_flavor_tenants": "rule:admin_or_support",

View File

@ -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.sql_alchemy.db_models import FlavorRegion, FlavorTenant
from orm.services.flavor_manager.fms_rest.data.wsme.models import (ExtraSpecsWrapper, Flavor, from orm.services.flavor_manager.fms_rest.data.wsme.models import (ExtraSpecsWrapper, Flavor,
FlavorListFullResponse, FlavorWrapper, 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.services.flavor_manager.fms_rest.logic.error_base import ConflictError, ErrorStatus, NotFoundError
from orm.common.orm_common.injector import injector from orm.common.orm_common.injector import injector
from pecan import conf
LOG = get_logger(__name__) LOG = get_logger(__name__)
di = injector.get_di() di = injector.get_di()
@ -18,7 +18,6 @@ di = injector.get_di()
def create_flavor(flavor, flavor_uuid, transaction_id): def create_flavor(flavor, flavor_uuid, transaction_id):
DataManager = di.resolver.unpack(create_flavor) DataManager = di.resolver.unpack(create_flavor)
datamanager = DataManager() datamanager = DataManager()
try: try:
flavor.flavor.handle_region_groups() flavor.flavor.handle_region_groups()
flavor.flavor.validate_model("create") 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) sql_flavor = flavor_rec.get_flavor_by_id(flavor_uuid)
if sql_flavor is None: if sql_flavor is None:
# The flavor does not exist, so the delete operation is raise NotFoundError(message="Flavor '{}' not found".format(flavor_uuid))
# considered successful
return
existing_region_names = sql_flavor.get_existing_region_names() existing_region_names = sql_flavor.get_existing_region_names()
if len(existing_region_names) > 0: if len(existing_region_names) > 0:
@ -228,33 +225,43 @@ def add_regions(flavor_uuid, regions, transaction_id):
@di.dependsOn('data_manager') @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 = di.resolver.unpack(delete_region)
datamanager = DataManager() datamanager = DataManager()
try: try:
flavor_rec = datamanager.get_record('flavor') flavor_rec = datamanager.get_record('flavor')
sql_flavor = flavor_rec.get_flavor_by_id(flavor_uuid) sql_flavor = flavor_rec.get_flavor_by_id(flavor_uuid)
if not sql_flavor and on_success_by_rds:
return
if not sql_flavor: if not sql_flavor:
raise ErrorStatus(404, 'flavor id {0} not found'.format(flavor_uuid)) raise ErrorStatus(404, 'flavor id {0} not found'.format(flavor_uuid))
existing_region_names = sql_flavor.get_existing_region_names() existing_region_names = sql_flavor.get_existing_region_names()
sql_flavor.remove_region(region_name) sql_flavor.remove_region(region_name)
datamanager.flush() # i want to get any exception created by previous actions against the database datamanager.flush() # Get any exception created by previous actions against the database
send_to_rds_if_needed(sql_flavor, existing_region_names, "put", transaction_id) if on_success_by_rds:
datamanager.commit()
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: except ErrorStatus as exp:
LOG.log_exception("FlavorLogic - Failed to update flavor", exp) LOG.log_exception("FlavorLogic - Failed to update flavor", exp)
datamanager.rollback() datamanager.rollback()
raise exp raise exp
except Exception as exp: except Exception as exp:
LOG.log_exception("FlavorLogic - Failed to delete region", exp) LOG.log_exception("FlavorLogic - Failed to delete region", exp)
datamanager.rollback() datamanager.rollback()
raise exp raise exp
finally: finally:
datamanager.close() 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 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) send_to_rds_if_needed(sql_flavor, existing_region_names, "put", transaction_id)
datamanager.commit() datamanager.commit()
except NotFoundError as exp:
except ErrorStatus as exp:
LOG.log_exception("FlavorLogic - Failed to update flavor", exp)
datamanager.rollback() datamanager.rollback()
LOG.log_exception("FlavorLogic - Flavor not found", exp)
raise 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: except Exception as exp:
LOG.log_exception("FlavorLogic - Failed to delete tenant", exp) LOG.log_exception("FlavorLogic - Failed to delete tenant", exp)
datamanager.rollback() datamanager.rollback()
@ -424,8 +438,12 @@ def delete_extra_specs(flavor_id, transaction_id, extra_spec=None):
except ErrorStatus as exp: except ErrorStatus as exp:
datamanager.rollback() datamanager.rollback()
LOG.log_exception("error in adding extra specs", exp) if exp.status_code == 404:
raise 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: except Exception as exp:
datamanager.rollback() datamanager.rollback()
@ -487,8 +505,7 @@ def delete_tags(flavor_id, tag, transaction_id):
except ErrorStatus as exp: except ErrorStatus as exp:
if exp.status_code == 404: if exp.status_code == 404:
LOG.log_exception("FlavorLogic - Tag not found", exp) LOG.log_exception("FlavorLogic - Tag not found", exp)
# Do not raise an exception if the tag was not found raise
return
else: else:
LOG.log_exception("FlavorLogic - failed to delete tags", exp) LOG.log_exception("FlavorLogic - failed to delete tags", exp)
raise 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, rds_proxy = di.resolver.unpack(get_flavor_by_uuid)
datamanager = DataManager() datamanager = DataManager()
try: try:
flavor_record = datamanager.get_record('flavor') 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') @di.dependsOn('rds_proxy')
def update_region_statuses(flavor, sql_flavor): def update_region_statuses(flavor, sql_flavor):
rds_proxy = di.resolver.unpack(update_region_statuses) rds_proxy = di.resolver.unpack(update_region_statuses)
# remove the regions comes from database and return the regions which return from rds, # 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 # 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 # rds we will have a list of all regions belong to this group
flavor.regions[:] = [] flavor.regions[:] = []
resp = rds_proxy.get_status(sql_flavor.id) resp = rds_proxy.get_status(sql_flavor.id)
if resp.status_code == 200: if resp.status_code == 200:
status_resp = resp.json() rds_status_resp = resp.json()
if sql_flavor.flavor_regions and len(sql_flavor.flavor_regions) > 0: # store all regions for the flavor in the flavor_regions_list
if 'regions' in status_resp.keys(): flavor_regions_list = []
for region_status in status_resp['regions']: for region_data in sql_flavor.flavor_regions:
flavor.regions.append( flavor_regions_list.append(region_data.region_name)
Region(name=region_status['region'], type="single",
status=region_status['status'], # get region status if region in flavor_regions_list
error_message=region_status['error_msg'])) 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: 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: else:
flavor.status = "N/A" flavor.status = "N/A"
@di.dependsOn('data_manager') @di.dependsOn('data_manager')
@di.dependsOn('rds_proxy') @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, rds_proxy = di.resolver.unpack(get_flavor_list_by_params)
datamanager = DataManager() datamanager = DataManager()
@ -764,15 +793,25 @@ def get_flavor_list_by_params(visibility, region, tenant, series, starts_with, c
region=region, region=region,
tenant=tenant, tenant=tenant,
series=series, series=series,
vm_type=vm_type,
vnf_name=vnf_name,
starts_with=starts_with, starts_with=starts_with,
contains=contains, contains=contains,
alias=alias) alias=alias)
response = FlavorListFullResponse() response = FlavorListFullResponse()
for sql_flavor in sql_flavors: if sql_flavors:
flavor = Flavor.from_db_model(sql_flavor) uuids = ','.join(str("\'" + sql_flavor.id + "\'")
update_region_statuses(flavor, sql_flavor) for sql_flavor in sql_flavors if sql_flavor and sql_flavor.id)
response.flavors.append(flavor) 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: except Exception as exp:
LOG.log_exception("Fail to get_flavor_list_by_params", exp) LOG.log_exception("Fail to get_flavor_list_by_params", exp)
raise raise
@ -783,10 +822,18 @@ def get_flavor_list_by_params(visibility, region, tenant, series, starts_with, c
def calculate_name(flavor): 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, name = "{0}.c{1}r{2}d{3}".format(flavor.flavor.series, flavor.flavor.vcpus,
int(flavor.flavor.ram) / 1024, int(flavor.flavor.ram) / 1024,
flavor.flavor.disk) flavor.flavor.disk)
series = name[:2]
swap = getattr(flavor.flavor, 'swap', 0) swap = getattr(flavor.flavor, 'swap', 0)
if swap and int(swap): if swap and int(swap):
name += '{}{}'.format('s', int(swap) / 1024) name += '{}{}'.format('s', int(swap) / 1024)
@ -796,9 +843,23 @@ def calculate_name(flavor):
name += '{}{}'.format('e', ephemeral) name += '{}{}'.format('e', ephemeral)
if len(flavor.flavor.options) > 0: if len(flavor.flavor.options) > 0:
name += '.'
for key in sorted(flavor.flavor.options.iterkeys()): 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 return name
@ -833,17 +894,3 @@ def region_name_exist_in_regions(region_name, regions):
def set_regions_action(flavor_dict, action): def set_regions_action(flavor_dict, action):
for region in flavor_dict["regions"]: for region in flavor_dict["regions"]:
region["action"] = action 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!')

View File

@ -1,12 +1,10 @@
from oslo_config import cfg from orm import base_config as config
CONF = cfg.CONF
# Server Specific Configurations # Server Specific Configurations
server = { server = {
'port': CONF.uuid.port, 'port': config.uuid['port'],
'host': CONF.api.host 'host': config.orm_host
} }
# Pecan Application Configurations # Pecan Application Configurations
app = { app = {
@ -15,10 +13,9 @@ app = {
'debug': True, 'debug': True,
} }
verify = CONF.api.ssl_verify verify = config.ssl_verify
database = { database = {
'connection_string': CONF.database.connection + '/orm' 'connection_string': config.db_url + 'orm'
} }
# Custom Configurations must be in Python dictionary format:: # Custom Configurations must be in Python dictionary format::
# #

View File

@ -1,26 +1,14 @@
import os import logging
from oslo_log import log as logging
from pecan.commands import CommandRunner
from pecan import make_app from pecan import make_app
LOG = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def setup_app(config): def setup_app(config):
app_conf = dict(config.app) app_conf = dict(config.app)
app = make_app(app_conf.pop('root'), app = make_app(app_conf.pop('root'),
logging=getattr(config, 'logging', {}), logging=getattr(config, 'logging', {}),
**app_conf) **app_conf)
LOG.info('Starting uuidgen...') logger.info('Starting uuidgen...')
return app 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'])

View File

@ -1,11 +1,13 @@
import datetime import datetime
import logging import logging
import re
import uuid import uuid
from orm.services.id_generator.uuidgen.db.db_manager import DBManager
from pecan import expose, response from pecan import expose, response
from pecan.rest import RestController from pecan.rest import RestController
from orm.services.id_generator.uuidgen.db.db_manager import DBManager
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -22,8 +24,7 @@ def respond(reason, code, message):
class UUIDController(RestController): class UUIDController(RestController):
@expose(template='json') @expose(template='json')
def post(self, **kw): def post(self, **kw):
"""Method to handle POST /v1/uuids """Method to handle POST /v1/uuids - create and return a new uuid
create and return a new uuid
prameters: prameters:
uuid_type (optional) uuid_type (optional)
return: dict describing success or failure of post command return: dict describing success or failure of post command
@ -45,18 +46,23 @@ class UUIDController(RestController):
LOG.info("UUIDController.post - " + str(messageToReturn)) LOG.info("UUIDController.post - " + str(messageToReturn))
return messageToReturn return messageToReturn
if not customer_id: if not customer_id or customer_id == 'Unset':
return self.create_new_uuid(uuid_type) 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: try:
uuid_type = "custId"
db_manager = DBManager() db_manager = DBManager()
db_manager.create_uuid(customer_id, uuid_type) db_manager.create_uuid(uuid, uuid_type)
return { return {
"uuid": customer_id, "uuid": uuid,
"issued_at": datetime.datetime.utcnow().isoformat() + 'Z', "issued_at": datetime.datetime.utcnow().isoformat() + 'Z',
"uuid_type": uuid_type "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 # 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 # 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 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 response.status = 500
messageToReturn = respond("badRequest", 500, 'Database error') messageToReturn = respond("badRequest", 500, 'Database error')
LOG.error(str(messageToReturn) + "Exception: " + str(e)) LOG.error(str(messageToReturn) + "Exception: " + str(e))
return messageToReturn return messageToReturn
return { return {
"uuid": customer_id, "uuid": uuid,
"issued_at": datetime.datetime.utcnow().isoformat() + 'Z', "issued_at": datetime.datetime.utcnow().isoformat() + 'Z',
"uuid_type": uuid_type "uuid_type": uuid_type
} }

View File

@ -10,7 +10,6 @@ logger = logging.getLogger(__name__)
class DBManager(object): class DBManager(object):
def __init__(self, connection_string=None): def __init__(self, connection_string=None):
if not connection_string: if not connection_string:
connection_string = conf.database.connection_string connection_string = conf.database.connection_string

View File

@ -1,5 +1,3 @@
import os
from orm.common.orm_common.policy import policy from orm.common.orm_common.policy import policy
from orm.common.orm_common.utils.utils import set_utils_conf from orm.common.orm_common.utils.utils import set_utils_conf
from orm.services.image_manager.ims.logger import get_logger from orm.services.image_manager.ims.logger import get_logger
@ -29,8 +27,8 @@ def setup_app(config):
def main(): 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 = CommandRunner()
runner.run(['serve', path + '/config.py']) runner.run(['serve', '../config.py'])
if __name__ == "__main__":
main()

View File

@ -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)

View File

@ -43,13 +43,10 @@ class ImageController(rest.RestController):
LOG.info("ImageController - Create image: " + str(image_wrapper.image.name)) LOG.info("ImageController - Create image: " + str(image_wrapper.image.name))
image_wrapper.image.owner = request.headers.get('X-RANGER-Owner') or '' image_wrapper.image.owner = request.headers.get('X-RANGER-Owner') or ''
if not image_wrapper.image.id: try:
uuid = utils.make_uuid() uuid = utils.create_or_validate_uuid(image_wrapper.image.id, 'imsId')
else: except TypeError:
try: raise ErrorStatus(409.1, message='Image UUID already exists')
uuid = utils.create_existing_uuid(image_wrapper.id)
except TypeError:
raise ErrorStatus(409.1, message='Image UUID already exists')
try: try:
ret_image = image_logic.create_image(image_wrapper, uuid, ret_image = image_logic.create_image(image_wrapper, uuid,
@ -125,7 +122,7 @@ class ImageController(rest.RestController):
auth.authorize(request, "image:get_one") auth.authorize(request, "image:get_one")
try: 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: except ErrorStatus as exception:
LOG.log_exception("ImageController - Failed to GetImageDetails", exception) LOG.log_exception("ImageController - Failed to GetImageDetails", exception)
@ -140,14 +137,14 @@ class ImageController(rest.RestController):
error_details=str(exception)) error_details=str(exception))
@wsexpose(ImageSummaryResponse, str, str, str, rest_content_types='json') @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) image_logic, utils = di.resolver.unpack(ImageController)
auth.authorize(request, "image:list") auth.authorize(request, "image:list")
try: try:
LOG.info("ImageController - GetImagelist") 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 return result
except ErrorStatus as exception: except ErrorStatus as exception:

View File

@ -90,22 +90,28 @@ class RegionController(rest.RestController):
status_code=500, status_code=500,
error_details=exception.message) error_details=exception.message)
@wsexpose(None, str, str, rest_content_types='json', status_code=204) @wsexpose(None, str, str, str, rest_content_types='json', status_code=204)
def delete(self, image_id, region_name): 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) image_logic, utils = di.resolver.unpack(RegionController)
auth.authorize(request, "region:delete") auth.authorize(request, "region:delete")
try: 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) event_details = 'Image {} region {} deleted'.format(image_id,
region_name)
LOG.info("RegionController - region deleted: " + str(result)) utils.audit_trail('delete region', request.transaction_id,
request.headers, image_id,
event_details = 'Image {} region {} deleted'.format(image_id, event_details=event_details)
region_name)
utils.audit_trail('delete region', request.transaction_id,
request.headers, image_id,
event_details=event_details)
except ErrorStatus as exception: # include NotFoundError except ErrorStatus as exception: # include NotFoundError
LOG.log_exception("RegionController - Failed to delete region", exception) LOG.log_exception("RegionController - Failed to delete region", exception)

View File

@ -1,25 +1,27 @@
{ {
"default": "!", "default": "!",
"admin": "role:admin",
"admin_support": "role:admin_support",
"admin_viewer": "role:admin_viewer",
"orm": "user:m01687",
"admin_or_support": "role:admin or role:admin_support", "admin": "role:admin and tenant:admin or role:admin and tenant:services",
"admin_or_support_or_viewer": "rule:admin or rule:admin_support or rule:admin_viewer", "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", "admin_or_support": "rule:admin or rule:admin_support",
"image:list": "rule:admin_or_support_or_viewer", "admin_or_support_or_viewer": "rule:admin or rule:admin_support or rule:admin_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",
"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"
} }

View File

@ -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 = image_wrapper.to_db_model()
new_image.id = image_uuid new_image.id = image_uuid
datamanager.begin_transaction()
image_rec = datamanager.get_record('image') image_rec = datamanager.get_record('image')
sql_image = image_rec.get_image_by_id(image_uuid) 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( message="Image {0} does not exist for update".format(
image_uuid)) image_uuid))
image_wrapper.validate_update(sql_image, new_image)
datamanager.begin_transaction()
new_image.owner = sql_image.owner new_image.owner = sql_image.owner
existing_regions = sql_image.get_existing_region_names() existing_regions = sql_image.get_existing_region_names()
new_image.created_at = int(sql_image.created_at) 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) sql_image = image_rec.get_image_by_id(image_uuid)
if sql_image is None: 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() image_existing_region_names = sql_image.get_existing_region_names()
if len(image_existing_region_names) > 0: if len(image_existing_region_names) > 0:
@ -254,27 +256,39 @@ def replace_regions(image_uuid, regions, transaction_id):
@di.dependsOn('data_manager') @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 = di.resolver.unpack(delete_region)
datamanager = DataManager() datamanager = DataManager()
try: try:
image_rec = datamanager.get_record('image') image_rec = datamanager.get_record('image')
sql_image = image_rec.get_image_by_id(image_uuid) sql_image = image_rec.get_image_by_id(image_uuid)
if on_success_by_rds and not sql_image:
return
if not sql_image: if not sql_image:
raise ErrorStatus(404, 'image with id: {0} not found'.format( 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() existing_region_names = sql_image.get_existing_region_names()
sql_image.remove_region(region_name) 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 # previous actions against the database
send_to_rds_if_needed(sql_image, existing_region_names, "put", if on_success_by_rds:
transaction_id) datamanager.commit()
else:
datamanager.commit() 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: except ErrorStatus as exp:
LOG.log_exception("ImageLogic - Failed to update image", 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() datamanager.rollback()
raise raise
finally:
datamanager.close()
@di.dependsOn('data_manager') @di.dependsOn('data_manager')
def add_customers(image_uuid, customers, transaction_id): 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('data_manager')
@di.dependsOn('rds_proxy') @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, rds_proxy = di.resolver.unpack(get_image_by_uuid)
datamanager = DataManager() datamanager = DataManager()
@ -407,10 +429,14 @@ def get_image_by_uuid(image_uuid):
try: try:
datamanager.begin_transaction() datamanager.begin_transaction()
image_rec = datamanager.get_record('image') 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: if not sql_image:
raise NotFoundError(status_code=404, raise NotFoundError(status_code=404,
message="Image {0} not found ".format( message="Image {0} not found ".format(
@ -428,15 +454,28 @@ def get_image_by_uuid(image_uuid):
# Get the status from RDS # Get the status from RDS
image_status = rds_proxy.get_status(image_wrapper.image.id, False) image_status = rds_proxy.get_status(image_wrapper.image.id, False)
if image_status.status_code != 200: if image_status.status_code == 404:
return image_wrapper # image not on rds resource table - applicable to images created with no region assigned
image_status = image_status.json() image_wrapper.image.status = 'no regions'
image_wrapper.image.status = image_status['status']
# update status for all regions elif image_status.status_code == 200:
for result_regions in image_wrapper.image.regions: image_status = image_status.json()
for status_region in image_status['regions']: if image_wrapper.image.regions:
if result_regions.name == status_region['region']: image_wrapper.image.status = image_status['status']
result_regions.status = status_region['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: except NotFoundError as exp:
datamanager.rollback() datamanager.rollback()
@ -452,8 +491,9 @@ def get_image_by_uuid(image_uuid):
@di.dependsOn('data_manager') @di.dependsOn('data_manager')
@di.dependsOn('rds_proxy')
def get_image_list_by_params(visibility, region, Customer): 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() datamanager = DataManager()
try: try:
@ -463,10 +503,17 @@ def get_image_list_by_params(visibility, region, Customer):
Customer=Customer) Customer=Customer)
response = ImageSummaryResponse() response = ImageSummaryResponse()
for sql_image in sql_images: if sql_images:
image = ImageSummary.from_db_model(sql_image) uuids = ','.join(str("\'" + sql_image.id + "\'")
response.images.append(image) 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 return response
except ErrorStatus as exp: except ErrorStatus as exp:
@ -518,7 +565,7 @@ def enable_image(image_uuid, int_enabled, transaction_id):
try: try:
image_rec = datamanager.get_record('image') 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: if not sql_image:
raise ErrorStatus(404, 'Image with id: {0} not found'.format( raise ErrorStatus(404, 'Image with id: {0} not found'.format(
image_uuid)) image_uuid))

View File

@ -37,8 +37,9 @@ class ImageRecord(Record):
raise raise
def get_image(self, id): def get_image(self, id):
"""function to get image by name or id"""
try: 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() return query.first()
except Exception as exception: except Exception as exception:
message = "Failed to read_image: id: {0}".format(id) message = "Failed to read_image: id: {0}".format(id)
@ -93,6 +94,16 @@ class ImageRecord(Record):
LOG.log_exception(message, exception) LOG.log_exception(message, exception)
raise 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): def create_images_by_visibility_query(self, visibility):
try: try:
query = self.session.query(Image).filter(Image.visibility == visibility) query = self.session.query(Image).filter(Image.visibility == visibility)

View File

@ -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.services.image_manager.ims.persistency.wsme.base import Model
from orm.common.orm_common.utils.cross_api_utils import (get_regions_of_group, from orm.common.orm_common.utils.cross_api_utils import (get_regions_of_group,
set_utils_conf) set_utils_conf)
from pecan import conf, request from pecan import conf
import wsme import wsme
@ -52,6 +52,7 @@ class Region(Model):
checksum = wsme.wsattr(wsme.types.text, mandatory=False) checksum = wsme.wsattr(wsme.types.text, mandatory=False)
size = wsme.wsattr(wsme.types.text, mandatory=False) size = wsme.wsattr(wsme.types.text, mandatory=False)
virtual_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='', def __init__(self, name="", type="single", status="", checksum='',
size='', virtual_size=''): size='', virtual_size=''):
@ -82,6 +83,9 @@ class Region(Model):
return region_rec return region_rec
def set_error_message(self, error_message):
self.error_message = error_message
class RegionWrapper(Model): # pragma: no cover class RegionWrapper(Model): # pragma: no cover
"""regions model """regions model
@ -133,9 +137,9 @@ class Image(Model):
owner = wsme.wsattr(wsme.types.text, mandatory=False) owner = wsme.wsattr(wsme.types.text, mandatory=False)
schema = wsme.wsattr(wsme.types.text, mandatory=False) schema = wsme.wsattr(wsme.types.text, mandatory=False)
protected = wsme.wsattr(bool, mandatory=False, default=default_protected) protected = wsme.wsattr(bool, mandatory=False, default=default_protected)
id = wsme.wsattr(wsme.types.text, mandatory=False, name='id')
# Output-only fields # Output-only fields
id = wsme.wsattr(wsme.types.text, mandatory=False)
status = wsme.wsattr(wsme.types.text, mandatory=False) status = wsme.wsattr(wsme.types.text, mandatory=False)
created_at = wsme.wsattr(wsme.types.IntegerType(minimum=0), created_at = wsme.wsattr(wsme.types.IntegerType(minimum=0),
mandatory=False, name='created-at') mandatory=False, name='created-at')
@ -214,6 +218,13 @@ class Image(Model):
self.links = links self.links = links
def validate_model(self, context=None): 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 # Validate visibility
if self.visibility == 'public' and self.customers: if self.visibility == 'public' and self.customers:
raise ErrorStatus(400, raise ErrorStatus(400,
@ -223,6 +234,9 @@ class Image(Model):
raise ErrorStatus(400, raise ErrorStatus(400,
'Visibility is private but no customers were' 'Visibility is private but no customers were'
' specified!') ' specified!')
elif self.visibility not in ["private", "public"]:
raise ErrorStatus(400,
"Image visibility can only be 'public' or 'private'")
# Validate disk format # Validate disk format
valid_disk_formats = ('ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw', 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: if self.container_format not in valid_container_formats:
raise ErrorStatus(400, 'Invalid container format! {}'.format(self.container_format)) raise ErrorStatus(400, 'Invalid container format! {}'.format(self.container_format))
# Validate min-disk and min-ram (wsme automatically converts booleans if int(self.min_ram) not in range(0, self.min_ram + 1, 1024):
# to int, and isinstance(False, int) returns True, so that is how we raise ErrorStatus(400, "mininum RAM value must be a multiple of 1024")
# 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 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": if context == "update":
for region in self.regions: for region in self.regions:
if region.type == "group": if region.type == "group":
@ -406,6 +407,32 @@ class ImageWrapper(Model):
def validate_model(self, context=None): def validate_model(self, context=None):
return self.image.validate_model(context) 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): def handle_region_group(self):
return self.image.handle_region_group() return self.image.handle_region_group()
@ -419,20 +446,26 @@ class ImageWrapper(Model):
return image 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): class ImageSummary(Model):
name = wsme.wsattr(wsme.types.text) name = wsme.wsattr(wsme.types.text)
id = wsme.wsattr(wsme.types.text) id = wsme.wsattr(wsme.types.text)
visibility = 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) Model.__init__(self)
self.name = name self.name = name
self.id = id self.id = id
self.visibility = visibility self.visibility = visibility
self.status = status
self.regions = regions
@staticmethod @staticmethod
def from_db_model(sql_image): def from_db_model(sql_image):
@ -440,6 +473,11 @@ class ImageSummary(Model):
image.id = sql_image.id image.id = sql_image.id
image.name = sql_image.name image.name = sql_image.name
image.visibility = sql_image.visibility 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 return image

View File

@ -109,7 +109,7 @@ def build_zone_response(zone):
design_type=zone.design_type, design_type=zone.design_type,
location_type=zone.location_type, location_type=zone.location_type,
vLCP_name=zone.vlcp_name, vLCP_name=zone.vlcp_name,
AIC_version=zone.ranger_agent_version, ranger_agent_version=zone.ranger_agent_version,
OS_version=zone.open_stack_version, OS_version=zone.open_stack_version,
keystone_EP=end_points_dict["identity"], keystone_EP=end_points_dict["identity"],
horizon_EP=end_points_dict["dashboard"], horizon_EP=end_points_dict["dashboard"],

View File

@ -1,6 +1,5 @@
"""rest module.""" """rest module."""
import logging import logging
import time
import wsme import wsme
from orm.common.orm_common.utils import api_error_utils as err_utils 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 orm.services.region_manager.rms.utils import authentication
from pecan import request, rest from pecan import request, rest
from wsme import types as wtypes from wsme import types as wtypes
from wsmeext.pecan import wsexpose from wsmeext.pecan import wsexpose
@ -24,8 +24,11 @@ class Groups(wtypes.DynamicBase):
name = wsme.wsattr(wtypes.text, mandatory=True) name = wsme.wsattr(wtypes.text, mandatory=True)
description = wsme.wsattr(wtypes.text, mandatory=True) description = wsme.wsattr(wtypes.text, mandatory=True)
regions = wsme.wsattr([str], 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. """init function.
:param regions: :param regions:
@ -35,6 +38,8 @@ class Groups(wtypes.DynamicBase):
self.name = name self.name = name
self.description = description self.description = description
self.regions = regions self.regions = regions
self.created = created
self.modified = modified
def _to_python_obj(self): def _to_python_obj(self):
obj = PythonModel.Groups() obj = PythonModel.Groups()
@ -42,6 +47,8 @@ class Groups(wtypes.DynamicBase):
obj.name = self.name obj.name = self.name
obj.description = self.description obj.description = self.description
obj.regions = self.regions obj.regions = self.regions
obj.created = self.created
obj.modified = self.modified
return obj return obj
@ -63,20 +70,27 @@ class OutputResource(wtypes.DynamicBase):
id = wsme.wsattr(wtypes.text, mandatory=True) id = wsme.wsattr(wtypes.text, mandatory=True)
name = 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) 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. """init function.
:param id: :param id:
:param created: :param created:
:param links: :param links:
:param created
:param modified
""" """
self.id = id self.id = id
self.name = name self.name = name
self.created = created self.description = description
self.links = links self.links = links
self.created = created
self.modified = modified
class Result(wtypes.DynamicBase): class Result(wtypes.DynamicBase):
@ -159,19 +173,17 @@ class GroupsController(rest.RestController):
try: try:
# May raise an exception which will return status code 400 # May raise an exception which will return status code 400
GroupService.create_group_in_db(group_input.id, GroupService.create_group_in_db(group_input)
group_input.name,
group_input.description,
group_input.regions)
logger.debug("Group created successfully in DB") 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 # Create the group output data with the correct timestamp and link
group = OutputResource(group_input.id, group = OutputResource(group_input.id,
group_input.name, group_input.name,
repr(int(time.time() * 1000)), group_input.description,
{'self': '{}/v2/orm/groups/{}'.format( {'self': '{}/v2/orm/groups/{}'.format(
request.application_url, request.application_url,
group_input.id)}) group_input.id)},
result.created, result.modified)
event_details = 'Region group {} {} created with regions: {}'.format( event_details = 'Region group {} {} created with regions: {}'.format(
group_input.id, group_input.name, group_input.regions) group_input.id, group_input.name, group_input.regions)
@ -207,6 +219,13 @@ class GroupsController(rest.RestController):
request.headers, group_id, request.headers, group_id,
event_details=event_details) 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: except Exception as exp:
logger.exception("fail to delete group :- {}".format(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)) logger.debug("update group - id {}".format(group_id))
result = GroupService.update_group(group, group_id) result = GroupService.update_group(group, group_id)
logger.debug("group updated to :- {}".format(result)) logger.debug("group updated to :- {}".format(result))
result = GroupService.get_groups_data(group_id)
# build result # build result
group_result = OutputResource(result.id, result.name, group_result = OutputResource(result.id, result.name,
repr(int(time.time() * 1000)), { result.description, {
'self': '{}/v2/orm/groups/{}'.format( 'self': '{}/v2/orm/groups/{}'.format(
request.application_url, request.application_url,
result.id)}) result.id)},
result.created, result.modified)
event_details = 'Region group {} {} updated with regions: {}'.format( event_details = 'Region group {} {} updated with regions: {}'.format(
group_id, group.name, group.regions) group_id, group.name, group.regions)

View File

@ -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.services import services as RegionService
from orm.services.region_manager.rms.utils import authentication from orm.services.region_manager.rms.utils import authentication
from pecan import request, rest from pecan import conf, request, rest
import wsme import wsme
from wsme import types as wtypes from wsme import types as wtypes
from wsmeext.pecan import wsexpose from wsmeext.pecan import wsexpose
@ -30,7 +30,7 @@ class Address(wtypes.DynamicBase):
def __init__(self, country=None, state=None, city=None, def __init__(self, country=None, state=None, city=None,
street=None, zip=None): street=None, zip=None):
"""Init function """init function
:param country: :param country:
:param state: :param state:
@ -83,6 +83,7 @@ class RegionsData(wtypes.DynamicBase):
status = wsme.wsattr(wtypes.text, mandatory=True) status = wsme.wsattr(wtypes.text, mandatory=True)
id = wsme.wsattr(wtypes.text, mandatory=True) id = wsme.wsattr(wtypes.text, mandatory=True)
name = wsme.wsattr(wtypes.text, mandatory=False) 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") ranger_agent_version = wsme.wsattr(wtypes.text, mandatory=True, name="rangerAgentVersion")
open_stack_version = wsme.wsattr(wtypes.text, mandatory=True, name="OSVersion") open_stack_version = wsme.wsattr(wtypes.text, mandatory=True, name="OSVersion")
clli = wsme.wsattr(wtypes.text, mandatory=True, name="CLLI") 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") design_type = wsme.wsattr(wtypes.text, mandatory=True, name="designType")
location_type = wsme.wsattr(wtypes.text, mandatory=True, name="locationType") location_type = wsme.wsattr(wtypes.text, mandatory=True, name="locationType")
vlcp_name = wsme.wsattr(wtypes.text, mandatory=True, name="vlcpName") 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, def __init__(self, status=None, id=None, name=None, description=None, clli=None,
location_type=None, vlcp_name=None, open_stack_version=None, design_type=None, location_type=None, vlcp_name=None,
address=Address(), ranger_agent_version=None, metadata={}, open_stack_version=None, address=Address(), ranger_agent_version=None,
endpoint=[EndPoint()]): metadata={}, endpoint=[EndPoint()], created=None, modified=None):
"""init function """init
:param status: :param status:
:param id: :param id:
:param name: :param name:
:param description:
:param clli: :param clli:
:param design_type: :param design_type:
:param location_type: :param location_type:
@ -111,10 +115,13 @@ class RegionsData(wtypes.DynamicBase):
:param ranger_agent_version: :param ranger_agent_version:
:param metadata: :param metadata:
:param endpoint: :param endpoint:
:param created
:param modified
""" """
self.status = status self.status = status
self.id = id self.id = id
self.name = self.id self.name = self.id
self.description = description
self.clli = clli self.clli = clli
self.ranger_agent_version = ranger_agent_version self.ranger_agent_version = ranger_agent_version
self.metadata = metadata self.metadata = metadata
@ -124,6 +131,8 @@ class RegionsData(wtypes.DynamicBase):
self.vlcp_name = vlcp_name self.vlcp_name = vlcp_name
self.address = address self.address = address
self.open_stack_version = open_stack_version self.open_stack_version = open_stack_version
self.created = created
self.modified = modified
def _to_clean_python_obj(self): def _to_clean_python_obj(self):
obj = PythonModel.RegionData() obj = PythonModel.RegionData()
@ -131,6 +140,7 @@ class RegionsData(wtypes.DynamicBase):
obj.status = self.status obj.status = self.status
obj.id = self.id obj.id = self.id
obj.name = self.id obj.name = self.id
obj.description = self.description
obj.ranger_agent_version = self.ranger_agent_version obj.ranger_agent_version = self.ranger_agent_version
obj.clli = self.clli obj.clli = self.clli
obj.metadata = self.metadata obj.metadata = self.metadata
@ -163,11 +173,53 @@ class RegionsController(rest.RestController):
metadata = RegionMetadataController() metadata = RegionMetadataController()
status = RegionStatusController() 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, @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, def get_all(self, type=None, status=None, metadata=None, rangerAgentVersion=None,
clli=None, regionname=None, osversion=None, valet=None, clli=None, regionname=None, osversion=None, location_type=None,
state=None, country=None, city=None, street=None, zip=None): state=None, country=None, city=None, street=None, zip=None,
vlcp_name=None):
"""get regions. """get regions.
:param type: query field :param type: query field
@ -177,12 +229,13 @@ class RegionsController(rest.RestController):
:param clli: query field :param clli: query field
:param regionname: query field :param regionname: query field
:param osversion: query field :param osversion: query field
:param valet: query field :param location_type: query field
:param state: query field :param state: query field
:param country: query field :param country: query field
:param city: query field :param city: query field
:param street: query field :param street: query field
:param zip: query field :param zip: query field
:param vlcp_name query field
:return: json from db :return: json from db
:exception: EntityNotFoundError 404 :exception: EntityNotFoundError 404
""" """
@ -191,8 +244,9 @@ class RegionsController(rest.RestController):
url_args = {'type': type, 'status': status, 'metadata': metadata, url_args = {'type': type, 'status': status, 'metadata': metadata,
'rangerAgentVersion': rangerAgentVersion, 'clli': clli, 'regionname': regionname, 'rangerAgentVersion': rangerAgentVersion, 'clli': clli, 'regionname': regionname,
'osversion': osversion, 'valet': valet, 'state': state, 'osversion': osversion, 'location_type': location_type, 'state': state,
'country': country, 'city': city, 'street': street, 'zip': zip} 'country': country, 'city': city, 'street': street, 'zip': zip,
'vlcp_name': vlcp_name}
logger.debug("Parameters: {}".format(str(url_args))) logger.debug("Parameters: {}".format(str(url_args)))
try: try:
@ -248,8 +302,10 @@ class RegionsController(rest.RestController):
result = RegionService.create_full_region(full_region_input) result = RegionService.create_full_region(full_region_input)
logger.debug("API: region created : {}".format(result)) logger.debug("API: region created : {}".format(result))
event_details = 'Region {} {} created: AICversion {}, OSversion {}, CLLI {}'.format( event_details = 'Region {} {} created: rangerAgentVersion {}, OSversion {}, CLLI {}'.format(
full_region_input.name, full_region_input.design_type, full_region_input.name,
full_region_input.description,
full_region_input.design_type,
full_region_input.ranger_agent_version, full_region_input.ranger_agent_version,
full_region_input.open_stack_version, full_region_input.clli) full_region_input.open_stack_version, full_region_input.clli)
utils.audit_trail('create region', request.transaction_id, 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) @wsexpose(None, str, rest_content_types='json', status_code=204)
def delete(self, region_id): def delete(self, region_id):
logger.info("Delete Region") utils.set_utils_conf(conf)
authentication.authorize(request, 'region:delete') # 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)) event_details = 'Region {} deleted'.format(region_id)
result = RegionService.delete_region(region_id) utils.audit_trail('delete region', request.transaction_id,
logger.debug("region deleted") request.headers, region_id,
event_details=event_details)
event_details = 'Region {} deleted'.format(region_id) # issue NotFoundError for "Delete Region" when group_id not found
utils.audit_trail('delete region', request.transaction_id, # which is returned by RegionService.delete_region function
request.headers, region_id, except error_base.NotFoundError as exp:
event_details=event_details) 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, raise err_utils.get_error(request.transaction_id,
status_code=500, status_code=400,
message=exp.message) message=region_resources_exist_msg)
return
@wsexpose(RegionsData, str, body=RegionsData, status_code=201, @wsexpose(RegionsData, str, body=RegionsData, status_code=201,
rest_content_types='json') rest_content_types='json')
@ -312,7 +385,7 @@ class RegionsController(rest.RestController):
result = RegionService.update_region(region_id, region) result = RegionService.update_region(region_id, region)
logger.debug("API: region {} updated".format(region_id)) 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.name, region.design_type, region.ranger_agent_version,
region.open_stack_version, region.clli) region.open_stack_version, region.clli)
utils.audit_trail('update region', request.transaction_id, utils.audit_trail('update region', request.transaction_id,

View File

@ -1,24 +1,35 @@
{ {
"default": "!", "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_one": "",
"lcp:get_all": "", "lcp:get_all": "",
"region:get_one": "", "region:get_one": "",
"region:get_all": "", "region:get_all": "",
"region:create": "rule:orm_admin", "region:create": "rule:admin_or_support",
"region:update": "rule:orm_admin", "region:update": "rule:admin",
"region:delete": "rule:orm_admin", "region:delete": "rule:admin",
"group:get_one": "", "group:get_one": "",
"group:get_all": "", "group:get_all": "",
"group:create": "rule:orm_admin", "group:create": "rule:admin_or_support",
"group:update": "rule:orm_admin", "group:update": "rule:admin",
"group:delete": "rule:orm_admin", "group:delete": "rule:admin",
"configuration:get": "rule:orm_admin",
"log:update": "rule:orm_admin", "configuration:get": "rule:admin_or_support_or_viewer",
"metadata:get": "rule:orm_admin", "log:update": "rule:admin",
"metadata:create": "rule:orm_admin",
"metadata:update": "rule:orm_admin", "metadata:get": "rule:admin_or_support_or_viewer",
"metadata:delete": "rule:orm_admin", "metadata:create": "rule:admin_or_support",
"status:put": "rule:orm_admin" "metadata:update": "rule:admin",
"metadata:delete": "rule:admin",
"status:put": "rule:admin"
} }

View File

@ -9,7 +9,7 @@ class Address(object):
def __init__(self, country=None, state=None, city=None, def __init__(self, country=None, state=None, city=None,
street=None, zip=None): street=None, zip=None):
"""init """init function
:param country: :param country:
:param state: :param state:
@ -41,15 +41,18 @@ class EndPoint(object):
class RegionData(object): class RegionData(object):
"""class method json header.""" """class method json header."""
def __init__(self, status=None, id=None, name=None, clli=None, def __init__(self, status=None, id=None, name=None, description=None,
ranger_agent_version=None, design_type=None, location_type=None, clli=None, ranger_agent_version=None, design_type=None,
location_type=None,
vlcp_name=None, open_stack_version=None, vlcp_name=None, open_stack_version=None,
address=Address(), metadata={}, endpoints=[EndPoint()]): address=Address(), metadata={}, endpoints=[EndPoint()],
"""init created=None, modified=None):
"""init function
:param status: :param status:
:param id: :param id:
:param name: :param name:
:param description:
:param clli: :param clli:
:param ranger_agent_version: :param ranger_agent_version:
:param design_type: :param design_type:
@ -59,11 +62,14 @@ class RegionData(object):
:param address: :param address:
:param metadata: :param metadata:
:param endpoints: :param endpoints:
:param created
:param modified
""" """
self.status = status self.status = status
self.id = id self.id = id
# make id and name always the same # make id and name always the same
self.name = self.id self.name = self.id
self.description = description
self.clli = clli self.clli = clli
self.ranger_agent_version = ranger_agent_version self.ranger_agent_version = ranger_agent_version
self.metadata = metadata self.metadata = metadata
@ -73,6 +79,38 @@ class RegionData(object):
self.vlcp_name = vlcp_name self.vlcp_name = vlcp_name
self.open_stack_version = open_stack_version self.open_stack_version = open_stack_version
self.address = address 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): def _validate_end_points(self, endpoints_types_must_have):
ep_duplicate = [] ep_duplicate = []
@ -99,11 +137,22 @@ class RegionData(object):
"one of {}".format(allowed_status)) "one of {}".format(allowed_status))
return 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): def _validate_model(self):
allowed_status = conf.region_options.allowed_status_values[:] allowed_status = conf.region_options.allowed_status_values[:]
endpoints_types_must_have = conf.region_options.endpoints_types_must_have[:] endpoints_types_must_have = conf.region_options.endpoints_types_must_have[:]
self._validate_status(allowed_status) self._validate_status(allowed_status)
self._validate_end_points(endpoints_types_must_have) self._validate_end_points(endpoints_types_must_have)
self._validate_name()
self._validate_fields()
return return
def _to_db_model_dict(self): def _to_db_model_dict(self):
@ -118,6 +167,7 @@ class RegionData(object):
db_model_dict = {} db_model_dict = {}
db_model_dict['region_id'] = self.id db_model_dict['region_id'] = self.id
db_model_dict['name'] = self.name db_model_dict['name'] = self.name
db_model_dict['description'] = self.description
db_model_dict['address_state'] = self.address.state db_model_dict['address_state'] = self.address.state
db_model_dict['address_country'] = self.address.country db_model_dict['address_country'] = self.address.country
db_model_dict['address_city'] = self.address.city db_model_dict['address_city'] = self.address.city
@ -132,6 +182,7 @@ class RegionData(object):
db_model_dict['clli'] = self.clli db_model_dict['clli'] = self.clli
db_model_dict['end_point_list'] = end_points db_model_dict['end_point_list'] = end_points
db_model_dict['meta_data_dict'] = self.metadata db_model_dict['meta_data_dict'] = self.metadata
return db_model_dict return db_model_dict
@ -151,7 +202,8 @@ class Groups(object):
"""main json header.""" """main json header."""
def __init__(self, id=None, name=None, def __init__(self, id=None, name=None,
description=None, regions=[]): description=None, regions=[],
created=None, modified=None):
"""init function. """init function.
:param regions: :param regions:
@ -161,6 +213,8 @@ class Groups(object):
self.name = name self.name = name
self.description = description self.description = description
self.regions = regions self.regions = regions
self.created = created
self.modified = modified
def _to_db_model_dict(self): def _to_db_model_dict(self):
db_dict = {} db_dict = {}
@ -169,12 +223,23 @@ class Groups(object):
db_dict['group_regions'] = self.regions db_dict['group_regions'] = self.regions
return db_dict 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): class GroupsWrraper(object):
"""list of groups.""" """list of groups."""
def __init__(self, groups=None): def __init__(self, groups=None):
"""init """init function
:param groups: :param groups:
""" """

View File

@ -5,8 +5,9 @@ class UrlParms(object):
"""class method.""" """class method."""
def __init__(self, type=None, status=None, metadata=None, rangerAgentVersion=None, def __init__(self, type=None, status=None, metadata=None, rangerAgentVersion=None,
clli=None, regionname=None, osversion=None, valet=None, clli=None, regionname=None, osversion=None, location_type=None,
state=None, country=None, city=None, street=None, zip=None): state=None, country=None, city=None, street=None, zip=None,
vlcp_name=None):
"""init method. """init method.
:param type: :param type:
@ -16,15 +17,16 @@ class UrlParms(object):
:param clli: :param clli:
:param regionname: :param regionname:
:param osversion: :param osversion:
:param valet: :param location_type:
:param state: :param state:
:param country: :param country:
:param city: :param city:
:param street: :param street:
:param zip: :param zip:
:param vlcp_name:
""" """
if type: if type:
self.location_type = type self.design_type = type
if status: if status:
self.region_status = status self.region_status = status
if metadata: if metadata:
@ -37,8 +39,8 @@ class UrlParms(object):
self.name = regionname self.name = regionname
if osversion: if osversion:
self.open_stack_version = osversion self.open_stack_version = osversion
if valet: if location_type:
self.valet = valet self.location_type = location_type
if state: if state:
self.address_state = state self.address_state = state
if country: if country:
@ -49,6 +51,8 @@ class UrlParms(object):
self.address_street = street self.address_street = street
if zip: if zip:
self.address_zip = zip self.address_zip = zip
if vlcp_name:
self.vlcp_name = vlcp_name
def _build_query(self): def _build_query(self):
"""nuild db query. """nuild db query.

View File

@ -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 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

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

View File

@ -79,8 +79,14 @@ def delete_region(region_id):
LOG.debug("logic:- delete region {}".format(region_id)) LOG.debug("logic:- delete region {}".format(region_id))
try: try:
db = data_manager_factory.get_data_manager() 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) db.delete_region(region_id)
LOG.debug("region deleted") LOG.debug("region deleted")
except Exception as exp: except Exception as exp:
LOG.exception("fail to delete region {}".format(exp)) LOG.exception("fail to delete region {}".format(exp))
raise raise
@ -206,8 +212,12 @@ def delete_group(group_id):
""" """
LOG.debug("delete group logic") LOG.debug("delete group logic")
try: try:
db = data_manager_factory.get_data_manager() 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)) LOG.debug("delete group id {} from db".format(group_id))
db.delete_group(group_id) db.delete_group(group_id)
@ -217,7 +227,7 @@ def delete_group(group_id):
return 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. """Create a region group in the database.
:param group_id: The ID of the group to create :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 :raise: GroupExistsError (status code 400) if the group already exists
""" """
try: try:
group = group._to_python_obj()
group._validate_model()
manager = data_manager_factory.get_data_manager() 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: except error_base.ConflictError:
LOG.exception("Group {} already exists".format(group_id)) LOG.exception("Group {} already exists".format(group.id))
raise error_base.ConflictError( raise error_base.ConflictError(
message="Group {} already exists".format(group_id)) message="Group {} already exists".format(group.id))
except error_base.InputValueError: except error_base.InputValueError as e:
LOG.exception("Some of the regions not found") LOG.exception(e.message)
raise error_base.NotFoundError( raise
message="Some of the regions not found")
def update_group(group, group_id): def update_group(group, group_id):

View File

@ -1,3 +1,4 @@
import datetime
import logging import logging
from orm.services.region_manager.rms.model import model as PythonModels from orm.services.region_manager.rms.model import model as PythonModels
@ -68,7 +69,8 @@ class DataManager(BaseDataManager):
location_type=location_type, location_type=location_type,
vlcp_name=vlcp_name, vlcp_name=vlcp_name,
clli=clli, clli=clli,
description=description) description=description,
created=datetime.datetime.now())
if end_point_list is not None: if end_point_list is not None:
for end_point in end_point_list: for end_point in end_point_list:
@ -174,6 +176,8 @@ class DataManager(BaseDataManager):
def delete_region(self, region_id): def delete_region(self, region_id):
# delete a region from `region` table and also the region's # delete a region from `region` table and also the region's
# entries from `region_meta_data` and `region_end_points` tables # entries from `region_meta_data` and `region_end_points` tables
# as well as the "group_region" table
session = self._engine_facade.get_session() session = self._engine_facade.get_session()
with session.begin(): with session.begin():
session.query(Region).filter_by(region_id=region_id).delete() session.query(Region).filter_by(region_id=region_id).delete()
@ -396,7 +400,8 @@ class DataManager(BaseDataManager):
with session.begin(): with session.begin():
session.add(Group(group_id=group_id, session.add(Group(group_id=group_id,
name=group_name, name=group_name,
description=group_description)) description=group_description,
created=datetime.datetime.now()))
session.flush() # add the groupe if not rollback session.flush() # add the groupe if not rollback
@ -408,7 +413,8 @@ class DataManager(BaseDataManager):
session.add_all(group_regions) session.add_all(group_regions)
except oslo_db.exception.DBReferenceError as e: except oslo_db.exception.DBReferenceError as e:
logger.error("Reference error: {}".format(str(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: except oslo_db.exception.DBDuplicateEntry as e:
logger.error("Duplicate entry: {}".format(str(e))) logger.error("Duplicate entry: {}".format(str(e)))
raise error_base.ConflictError("Duplicate entry error") raise error_base.ConflictError("Duplicate entry error")
@ -429,6 +435,8 @@ class DataManager(BaseDataManager):
group_model.id = a_group.group_id group_model.id = a_group.group_id
group_model.name = a_group.name group_model.name = a_group.name
group_model.description = a_group.description group_model.description = a_group.description
group_model.created = a_group.created
group_model.modified = a_group.modified
regions = [] regions = []
group_regions = session.query(GroupRegion).\ group_regions = session.query(GroupRegion).\
filter_by(group_id=a_group.group_id) filter_by(group_id=a_group.group_id)
@ -484,7 +492,9 @@ class DataManager(BaseDataManager):
if a_group is not None: if a_group is not None:
group_model = {"id": a_group.group_id, group_model = {"id": a_group.group_id,
"name": a_group.name, "name": a_group.name,
"description": a_group.description} "description": a_group.description,
"created": a_group.created,
"modified": a_group.modified}
regions = [] regions = []
group_regions = session.query(GroupRegion). \ group_regions = session.query(GroupRegion). \
filter_by(group_id=a_group.group_id) filter_by(group_id=a_group.group_id)

View File

@ -1,4 +1,7 @@
# coding: utf-8 # 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 orm.services.region_manager.rms.model.model import Address, EndPoint, RegionData
from sqlalchemy import Column, ForeignKey, Integer, String from sqlalchemy import Column, ForeignKey, Integer, String
@ -28,7 +31,9 @@ class Region(Base):
vlcp_name = Column(String(64), nullable=False) vlcp_name = Column(String(64), nullable=False)
clli = Column(String(64), nullable=False) clli = Column(String(64), nullable=False)
description = Column(String(255), 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') end_points = relationship(u'RegionEndPoint')
meta_data = relationship(u'RegionMetaData') meta_data = relationship(u'RegionMetaData')
@ -56,6 +61,7 @@ class Region(Base):
id = self.region_id id = self.region_id
name = self.name name = self.name
description = self.description
status = self.region_status status = self.region_status
clli = self.clli clli = self.clli
ranger_agent_version = self.ranger_agent_version ranger_agent_version = self.ranger_agent_version
@ -63,13 +69,17 @@ class Region(Base):
location_type = self.location_type location_type = self.location_type
vlcp_name = self.vlcp_name vlcp_name = self.vlcp_name
open_stack_version = self.open_stack_version open_stack_version = self.open_stack_version
created = self.created
modified = self.modified
address = self.address_to_wsme() 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, design_type, location_type, vlcp_name,
open_stack_version, address, open_stack_version, address,
metadata=wsme_meta_data, metadata=wsme_meta_data,
endpoints=wsme_end_points) endpoints=wsme_end_points,
created=created,
modified=modified)
class Group(Base): class Group(Base):
@ -79,12 +89,17 @@ class Group(Base):
group_id = Column(String(64), nullable=False, unique=True) group_id = Column(String(64), nullable=False, unique=True)
name = Column(String(64), nullable=False, unique=True) name = Column(String(64), nullable=False, unique=True)
description = Column(String(255), nullable=False) description = Column(String(255), nullable=False)
created = Column(DateTime(timezone=False),
default=datetime.datetime.now())
modified = Column(DateTime(timezone=False))
def __json__(self): def __json__(self):
return dict( return dict(
group_id=self.group_id, group_id=self.group_id,
name=self.name, name=self.name,
description=self.description description=self.description,
created=self.created,
modified=self.modified
) )
def to_wsme(self): def to_wsme(self):

View File

@ -9,7 +9,7 @@ from pecan import conf
logger = logging.getLogger(__name__) 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) result = RegionService.get_region_by_id_or_name(auth_region)
for ep in result.endpoints: for ep in result.endpoints:
if ep.type == 'identity': if ep.type == 'identity':
@ -25,7 +25,7 @@ def authorize(request, action):
auth_region = request.headers.get('X-Auth-Region') auth_region = request.headers.get('X-Auth-Region')
try: try:
keystone_ep = _get_keystone_ep(auth_region) keystone_ep = get_keystone_ep(auth_region)
except Exception: except Exception:
# Failed to find Keystone EP - we'll set it to None instead of failing # Failed to find Keystone EP - we'll set it to None instead of failing
# because the rule might be to let everyone pass # because the rule might be to let everyone pass

View File

@ -1,5 +1,4 @@
import logging import logging
import os
from orm.common.client.audit.audit_client.api import audit from orm.common.client.audit.audit_client.api import audit
from pecan import conf, make_app from pecan import conf, make_app
@ -63,11 +62,8 @@ def validate_sot():
def main(): 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 = CommandRunner()
runner.run(['serve', path + '/config.py']) runner.run(['serve', '../config.py'])
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -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.base import InputValueError
from orm.services.resource_distributor.rds.controllers.v1.status import get_resource 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.services import region_resource_id_status as regionResourceIdStatus
from orm.services.resource_distributor.rds.utils import utils from orm.services.resource_distributor.rds.utils import utils
from pecan import rest from pecan import rest
import wsme import wsme
from wsme import types as wtypes from wsme import types as wtypes
from wsmeext.pecan import wsexpose from wsmeext.pecan import wsexpose
@ -144,9 +145,11 @@ class Status(rest.RestController):
logger.debug("save data to database.. data :- %s" % data_to_save) logger.debug("save data to database.. data :- %s" % data_to_save)
try: try:
regionResourceIdStatus.add_status(data_to_save) regionResourceIdStatus.add_status(data_to_save)
# invoke regin data to delete on sucess
utils.invoke_delete_region(data_to_save)
# send data to ims # send data to ims
utils.post_data_to_image(data_to_save) utils.post_data_to_image(data_to_save)
except ErrorMesage as exp: except ErrorMessage as exp:
logger.error(exp.message) logger.error(exp.message)
# raise ClientSideError(status_code=400, error=exp.message) # raise ClientSideError(status_code=400, error=exp.message)
except InputError as e: except InputError as e:

View File

@ -2,7 +2,7 @@ import json
import logging import logging
import requests 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 orm.services.resource_distributor.rds.utils import authentication as AuthService
from pecan import conf from pecan import conf
@ -51,10 +51,10 @@ def send_image_metadata(meta_data, region, resource_id, action='post'):
except requests.ConnectionError as exp: except requests.ConnectionError as exp:
logger.error(exp) logger.error(exp)
logger.exception(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: if response.status_code != 200:
raise ErrorMesage( raise ErrorMessage(
"Got error from orm.services.resource_distributor.rds server, code: {0} message: {1}".format( "Got error from orm.services.resource_distributor.rds server, code: {0} message: {1}".format(
response.status_code, response.content)) response.status_code, response.content))
return return

View File

@ -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

View File

@ -1,29 +1,25 @@
"""python module.""" """python module."""
import logging import logging
import requests
from pecan import conf from pecan import conf
import requests
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
headers = {'content-type': 'application/json'} def get_rms_region(region_name):
""" function to call rms api for region info
returns 200 for ok and None for error
def get_regions(): """
logger.debug("get list of regions from rms") try:
logger.debug("rms server {0} path = {1}".format(conf.rms.base_url, headers = {
conf.rms.all_regions_path)) 'content-type': 'application/json',
}
response = requests.get(conf.rms.base_url + conf.rms.all_regions_path, rms_server_url = '%s%s/%s' % (
headers=headers, verify=conf.verify) conf.rms.base_url, conf.rms.all_regions_path, region_name)
resp = requests.get(rms_server_url, headers=headers,
if response.status_code != 200: verify=conf.verify).json()
log_message = "not able to get regions {}".format(response) return resp
log_message = log_message.replace('\n', '_').replace('\r', '_') except Exception as e:
logger.error(log_message) logger.log_exception('Failed in get_rms_region', e)
return return None
return response.json()

View File

@ -9,7 +9,7 @@ class InputError(Error):
self.value = value self.value = value
class ErrorMesage(Error): class ErrorMessage(Error):
def __init__(self, message=None): def __init__(self, message=None):
self.message = message self.message = message

View File

@ -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 region_resource_id_status as regionResourceIdStatus
from orm.services.resource_distributor.rds.services import (yaml_customer_builder, yaml_flavor_bulder, from orm.services.resource_distributor.rds.services import (yaml_customer_builder, yaml_flavor_bulder,
yaml_image_builder) 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.services.model.resource_input import ResourceData as InputData
from orm.services.resource_distributor.rds.sot import sot_factory from orm.services.resource_distributor.rds.sot import sot_factory
from orm.services.resource_distributor.rds.utils import utils, uuid_utils from orm.services.resource_distributor.rds.utils import utils, uuid_utils
from pecan import conf, request from pecan import conf, request
my_logger = logging.getLogger(__name__) my_logger = logging.getLogger(__name__)
@ -34,13 +35,13 @@ def _get_inputs_from_resource_type(jsondata,
model=jsondata, model=jsondata,
external_transaction_id=external_transaction_id) external_transaction_id=external_transaction_id)
else: else:
raise ErrorMesage("no support for resource %s" % resource_type) raise ErrorMessage("no support for resource %s" % resource_type)
return input_data return input_data
def _region_valid(region): def _region_valid(region):
if ('rms_status' in region if 'rms_status' in region and region[
and region['rms_status'] not in conf.allow_region_statuses): 'rms_status'] not in conf.allow_region_statuses:
return False return False
return True return True
@ -51,6 +52,8 @@ def _create_or_update_resource_status(input_data, target, error_msg='',
if not _region_valid(target): if not _region_valid(target):
status = 'Error' status = 'Error'
error_msg = "Not sent to ord as status equal to " + target['rms_status'] 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) my_logger.debug("save status as %s" % status)
data_to_save = dict( data_to_save = dict(
@ -137,9 +140,8 @@ def _check_resource_status(input_data):
def update_sot(input_data): def update_sot(input_data):
"""create resource.""" """create resource."""
my_logger.debug( my_logger.debug("build yaml file for %s id: %s" % (input_data.resource_type,
"build yaml file for %s id: %s" % (input_data.resource_type, input_data.resource_id))
input_data.resource_id))
targetslist = _create_data_to_sot(input_data) targetslist = _create_data_to_sot(input_data)
my_logger.debug("upload yaml to SoT") my_logger.debug("upload yaml to SoT")
_upload_to_sot(input_data.resource_id, _upload_to_sot(input_data.resource_id,
@ -168,7 +170,7 @@ def main(jsondata, external_transaction_id, resource_type, operation):
update_sot(input_data) update_sot(input_data)
except ConflictValue: except ConflictValue:
raise raise
except ErrorMesage as exp: except ErrorMessage as exp:
my_logger.error(exp.message) my_logger.error(exp.message)
my_logger.exception(exp) my_logger.exception(exp)
raise raise
@ -176,5 +178,5 @@ def main(jsondata, external_transaction_id, resource_type, operation):
my_logger.exception(e) my_logger.exception(e)
_set_all_statuses_to_error(input_data) _set_all_statuses_to_error(input_data)
my_logger.error("deleting fails ,Error : {}".format(str(e.message))) 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 return input_data.resource_id

Some files were not shown because too many files have changed in this diff Show More