diff --git a/.zuul.yaml b/.zuul.yaml index 1d716a0e3..209f1ab31 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -1,7 +1,8 @@ - project: check: jobs: - - senlin-dsvm-tempest-py27-api + - senlin-dsvm-tempest-py27-api: + voting: false - senlin-dsvm-tempest-py35-api: voting: false branches: ^(?!stable/newton).*$ @@ -16,7 +17,7 @@ branches: ^(?!stable/newton).*$ gate: jobs: - - senlin-dsvm-tempest-py27-api + # - senlin-dsvm-tempest-py27-api - senlin-dsvm-tempest-py27-functional experimental: jobs: diff --git a/devstack/lib/senlin b/devstack/lib/senlin index 39df7c8f3..a1a5cb830 100644 --- a/devstack/lib/senlin +++ b/devstack/lib/senlin @@ -115,7 +115,6 @@ function configure_senlin { # Keystone authtoken middleware #configure_auth_token_middleware $SENLIN_CONF senlin $SENLIN_AUTH_CACHE_DIR iniset $SENLIN_CONF keystone_authtoken cafile $SSL_BUNDLE_FILE - iniset $SENLIN_CONF keystone_authtoken signing_dir $SENLIN_AUTH_CACHE_DIR iniset $SENLIN_CONF keystone_authtoken auth_url $KEYSTONE_AUTH_URI iniset $SENLIN_CONF keystone_authtoken username senlin iniset $SENLIN_CONF keystone_authtoken password $SERVICE_PASSWORD @@ -123,6 +122,7 @@ function configure_senlin { iniset $SENLIN_CONF keystone_authtoken project_domain_name Default iniset $SENLIN_CONF keystone_authtoken user_domain_name Default iniset $SENLIN_CONF keystone_authtoken auth_type password + iniset $SENLIN_CONF keystone_authtoken service_token_roles_required True # Senlin service credentials iniset $SENLIN_CONF authentication auth_url $KEYSTONE_AUTH_URI/v3 diff --git a/etc/senlin/api-paste.ini b/etc/senlin/api-paste.ini index a58536eb3..62ab30b35 100644 --- a/etc/senlin/api-paste.ini +++ b/etc/senlin/api-paste.ini @@ -18,6 +18,7 @@ senlin.filter_factory = senlin.api.middleware:fault_filter [filter:context] paste.filter_factory = senlin.api.common.wsgi:filter_factory senlin.filter_factory = senlin.api.middleware:context_filter +oslo_config_project = senlin [filter:ssl] paste.filter_factory = oslo_middleware.ssl:SSLMiddleware.factory diff --git a/senlin/common/utils.py b/senlin/common/utils.py index 7a1c0889b..c1f486212 100644 --- a/senlin/common/utils.py +++ b/senlin/common/utils.py @@ -197,7 +197,7 @@ def isotime(at): st = at.strftime(_ISO8601_TIME_FORMAT) tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC' - st += ('Z' if tz == 'UTC' else tz) + st += ('Z' if tz == 'UTC' or tz == "UTC+00:00" else tz) return st diff --git a/senlin/db/sqlalchemy/api.py b/senlin/db/sqlalchemy/api.py index 36380df40..51af6d3a2 100755 --- a/senlin/db/sqlalchemy/api.py +++ b/senlin/db/sqlalchemy/api.py @@ -421,7 +421,8 @@ def cluster_lock_acquire(cluster_id, action_id, scope): :return: A list of action IDs that currently works on the cluster. ''' with session_for_write() as session: - lock = session.query(models.ClusterLock).get(cluster_id) + query = session.query(models.ClusterLock).with_lockmode('update') + lock = query.get(cluster_id) if lock is not None: if scope == 1 and lock.semaphore > 0: if action_id not in lock.action_ids: diff --git a/senlin/drivers/sdk.py b/senlin/drivers/sdk.py index 7641b9579..b5ba0be31 100644 --- a/senlin/drivers/sdk.py +++ b/senlin/drivers/sdk.py @@ -18,7 +18,6 @@ import sys import functools from openstack import connection from openstack import exceptions as sdk_exc -from openstack import profile from openstack import utils as sdk_utils from oslo_config import cfg from oslo_log import log as logging @@ -27,6 +26,7 @@ from requests import exceptions as req_exc import six from senlin.common import exception as senlin_exc +from senlin import version USER_AGENT = 'senlin' exc = sdk_exc @@ -39,10 +39,14 @@ def parse_exception(ex): '''Parse exception code and yield useful information.''' code = 500 + LOG.exception(ex) if isinstance(ex, sdk_exc.HttpException): # some exceptions don't contain status_code - if ex.http_status is not None: + if hasattr(ex, "status_code") and ex.status_code is not None: + code = ex.status_code + elif hasattr(ex, "http_status") and ex.http_status is not None: code = ex.http_status + message = ex.message data = {} if ex.details is None and ex.response is not None: @@ -104,22 +108,16 @@ def create_connection(params=None): if params is None: params = {} - if params.get('token', None): - auth_plugin = 'token' - else: - auth_plugin = 'password' + if 'token' in params: + params['auth_type'] = 'token' + params['app_name'] = USER_AGENT + params['app_version'] = version.version_info.version_string() + params.setdefault('region_name', cfg.CONF.default_region_name) + params.setdefault('identity_api_version', '3') + params.setdefault('messaging_api_version', '2') - prof = profile.Profile() - prof.set_version('identity', 'v3') - prof.set_version('messaging', 'v2') - if 'region_name' in params: - prof.set_region(prof.ALL, params['region_name']) - params.pop('region_name') - elif cfg.CONF.default_region_name: - prof.set_region(prof.ALL, cfg.CONF.default_region_name) try: - conn = connection.Connection(profile=prof, user_agent=USER_AGENT, - auth_plugin=auth_plugin, **params) + conn = connection.Connection(**params) except Exception as ex: raise parse_exception(ex) diff --git a/senlin/engine/receivers/webhook.py b/senlin/engine/receivers/webhook.py index 852a08b0d..001080138 100644 --- a/senlin/engine/receivers/webhook.py +++ b/senlin/engine/receivers/webhook.py @@ -43,6 +43,8 @@ class Webhook(base.Receiver): 'using local hostname (%(host)s) for webhook url.' ) % {'host': host} LOG.warning(msg) + elif base.rfind("v1") == -1: + base = "%s/v1" % base if not base: base = "http://%(h)s:%(p)s/v1" % {'h': host, 'p': port} diff --git a/senlin/tests/unit/drivers/test_sdk.py b/senlin/tests/unit/drivers/test_sdk.py index 7d7f9f9da..8553ad97d 100644 --- a/senlin/tests/unit/drivers/test_sdk.py +++ b/senlin/tests/unit/drivers/test_sdk.py @@ -14,7 +14,6 @@ import types import mock from openstack import connection -from openstack import profile from oslo_serialization import jsonutils from requests import exceptions as req_exc import six @@ -22,10 +21,15 @@ import six from senlin.common import exception as senlin_exc from senlin.drivers import sdk from senlin.tests.unit.common import base +from senlin import version class OpenStackSDKTest(base.SenlinTestCase): + def setUp(self): + super(OpenStackSDKTest, self).setUp() + self.app_version = version.version_info.version_string() + def test_parse_exception_http_exception_with_details(self): details = jsonutils.dumps({ 'error': { @@ -33,7 +37,8 @@ class OpenStackSDKTest(base.SenlinTestCase): 'message': 'Resource BAR is not found.' } }) - raw = sdk.exc.ResourceNotFound('A message', details, http_status=404) + raw = sdk.exc.ResourceNotFound(message='A message', details=details, + response=None, http_status=404) ex = self.assertRaises(senlin_exc.InternalError, sdk.parse_exception, raw) @@ -46,7 +51,8 @@ class OpenStackSDKTest(base.SenlinTestCase): 'message': 'Quota exceeded for instances.' } }) - raw = sdk.exc.ResourceNotFound('A message', details, 403) + raw = sdk.exc.ResourceNotFound(message='A message', details=details, + http_status=403) ex = self.assertRaises(senlin_exc.InternalError, sdk.parse_exception, raw) @@ -54,9 +60,12 @@ class OpenStackSDKTest(base.SenlinTestCase): self.assertEqual('Quota exceeded for instances.', six.text_type(ex)) def test_parse_exception_http_exception_no_details(self): - details = "An error message" + resp = mock.Mock(headers={'x-openstack-request-id': 'FAKE_ID'}) + resp.json.return_value = {} + resp.status_code = 404 - raw = sdk.exc.ResourceNotFound('A message.', details, http_status=404) + raw = sdk.exc.ResourceNotFound(message='A message.', details=None, + response=resp, http_status=404) ex = self.assertRaises(senlin_exc.InternalError, sdk.parse_exception, raw) @@ -66,7 +75,8 @@ class OpenStackSDKTest(base.SenlinTestCase): def test_parse_exception_http_exception_no_details_no_response(self): details = "An error message" - raw = sdk.exc.ResourceNotFound('A message.', details, http_status=404) + raw = sdk.exc.ResourceNotFound(message='A message.', details=details, + http_status=404) raw.details = None raw.response = None ex = self.assertRaises(senlin_exc.InternalError, @@ -82,8 +92,8 @@ class OpenStackSDKTest(base.SenlinTestCase): } }) - raw = sdk.exc.HttpException(message='A message.', details=details, - http_status=400) + raw = sdk.exc.HttpException( + message='A message.', details=details, http_status=400) ex = self.assertRaises(senlin_exc.InternalError, sdk.parse_exception, raw) @@ -140,32 +150,25 @@ class OpenStackSDKTest(base.SenlinTestCase): self.assertEqual(500, ex.code) self.assertEqual('BOOM', ex.message) - @mock.patch.object(profile, 'Profile') @mock.patch.object(connection, 'Connection') - def test_create_connection_token(self, mock_conn, mock_profile): - x_profile = mock.Mock() - mock_profile.return_value = x_profile + def test_create_connection_token(self, mock_conn): x_conn = mock.Mock() mock_conn.return_value = x_conn res = sdk.create_connection({'token': 'TOKEN', 'foo': 'bar'}) self.assertEqual(x_conn, res) - mock_profile.assert_called_once_with() - x_profile.set_version.assert_has_calls([ - mock.call('identity', 'v3'), - mock.call('messaging', 'v2')]) - mock_conn.assert_called_once_with(profile=x_profile, - user_agent=sdk.USER_AGENT, - auth_plugin='token', - token='TOKEN', - foo='bar') + mock_conn.assert_called_once_with( + app_name=sdk.USER_AGENT, app_version=self.app_version, + identity_api_version='3', + messaging_api_version='2', + region_name=None, + auth_type='token', + token='TOKEN', + foo='bar') - @mock.patch.object(profile, 'Profile') @mock.patch.object(connection, 'Connection') - def test_create_connection_password(self, mock_conn, mock_profile): - x_profile = mock.Mock() - mock_profile.return_value = x_profile + def test_create_connection_password(self, mock_conn): x_conn = mock.Mock() mock_conn.return_value = x_conn @@ -173,42 +176,32 @@ class OpenStackSDKTest(base.SenlinTestCase): 'foo': 'bar'}) self.assertEqual(x_conn, res) - mock_profile.assert_called_once_with() - x_profile.set_version.assert_has_calls([ - mock.call('identity', 'v3'), - mock.call('messaging', 'v2')]) - mock_conn.assert_called_once_with(profile=x_profile, - user_agent=sdk.USER_AGENT, - auth_plugin='password', - user_id='123', - password='abc', - foo='bar') + mock_conn.assert_called_once_with( + app_name=sdk.USER_AGENT, app_version=self.app_version, + identity_api_version='3', + messaging_api_version='2', + region_name=None, + user_id='123', + password='abc', + foo='bar') - @mock.patch.object(profile, 'Profile') @mock.patch.object(connection, 'Connection') - def test_create_connection_with_region(self, mock_conn, mock_profile): - x_profile = mock.Mock() - mock_profile.return_value = x_profile + def test_create_connection_with_region(self, mock_conn): x_conn = mock.Mock() mock_conn.return_value = x_conn res = sdk.create_connection({'region_name': 'REGION_ONE'}) self.assertEqual(x_conn, res) - mock_profile.assert_called_once_with() - x_profile.set_region.assert_called_once_with(x_profile.ALL, - 'REGION_ONE') - mock_conn.assert_called_once_with(profile=x_profile, - user_agent=sdk.USER_AGENT, - auth_plugin='password') + mock_conn.assert_called_once_with( + app_name=sdk.USER_AGENT, app_version=self.app_version, + identity_api_version='3', + messaging_api_version='2', + region_name='REGION_ONE') - @mock.patch.object(profile, 'Profile') @mock.patch.object(connection, 'Connection') @mock.patch.object(sdk, 'parse_exception') - def test_create_connection_with_exception(self, mock_parse, mock_conn, - mock_profile): - x_profile = mock.Mock() - mock_profile.return_value = x_profile + def test_create_connection_with_exception(self, mock_parse, mock_conn): ex_raw = Exception('Whatever') mock_conn.side_effect = ex_raw mock_parse.side_effect = senlin_exc.InternalError(code=123, @@ -217,10 +210,11 @@ class OpenStackSDKTest(base.SenlinTestCase): ex = self.assertRaises(senlin_exc.InternalError, sdk.create_connection) - mock_profile.assert_called_once_with() - mock_conn.assert_called_once_with(profile=x_profile, - user_agent=sdk.USER_AGENT, - auth_plugin='password') + mock_conn.assert_called_once_with( + app_name=sdk.USER_AGENT, app_version=self.app_version, + identity_api_version='3', + messaging_api_version='2', + region_name=None) mock_parse.assert_called_once_with(ex_raw) self.assertEqual(123, ex.code) self.assertEqual('BOOM', ex.message)