From 4e3f6cd0cb1824c18a77df1ff5290b155bd853ad Mon Sep 17 00:00:00 2001 From: Pierre Padrixe Date: Fri, 14 Mar 2014 14:43:15 +0100 Subject: [PATCH] Add keystone exceptions wrapper for openstack clients * Added decorator which wraps keystone exceptions * Added unit tests with no auth_token and with heat client cached Change-Id: If42efe5f6806b12e7aabfd943150917a0b8f7618 --- solum/common/clients.py | 2 ++ solum/common/exception.py | 26 ++++++++++++++++++++++++++ solum/tests/common/test_clients.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/solum/common/clients.py b/solum/common/clients.py index a4b976795..822eebd8e 100644 --- a/solum/common/clients.py +++ b/solum/common/clients.py @@ -16,6 +16,7 @@ from heatclient import client as heatclient from keystoneclient.v2_0 import client as ksclient from oslo.config import cfg +from solum.common import exception from solum.openstack.common.gettextutils import _ from solum.openstack.common import log as logging @@ -77,6 +78,7 @@ class OpenStackClients(object): def _get_client_option(self, client, option): return getattr(getattr(cfg.CONF, '%s_client' % client), option) + @exception.wrap_keystone_exception def heat(self): if self._heat: return self._heat diff --git a/solum/common/exception.py b/solum/common/exception.py index d45bde72e..63a90b47e 100644 --- a/solum/common/exception.py +++ b/solum/common/exception.py @@ -20,8 +20,10 @@ Includes decorator for re-raising Solum-type exceptions. import functools import pecan +import sys import wsme +from keystoneclient import exceptions as keystone_exceptions from oslo.config import cfg import six @@ -30,6 +32,7 @@ from solum.openstack.common import excutils from solum.openstack.common.gettextutils import _ from solum.openstack.common import log as logging + LOG = logging.getLogger(__name__) exc_log_opts = [ @@ -96,6 +99,25 @@ def wrap_controller_exception(func): return wrapped +def wrap_keystone_exception(func): + """This decorator wraps keystone exception by throwing Solum specific + exceptions. + """ + @functools.wraps(func) + def wrapped(*args, **kw): + try: + return func(*args, **kw) + except keystone_exceptions.AuthorizationFailure: + raise AuthorizationFailure( + client=func.__name__, message="reason: %s" % sys.exc_info()[1]) + except keystone_exceptions.ClientException: + raise AuthorizationFailure( + client=func.__name__, + message="unexpected keystone client error occurred: %s" + % sys.exc_info()[1]) + return wrapped + + class SolumException(Exception): """Base Solum Exception @@ -152,3 +174,7 @@ class ResourceExists(SolumException): class NotImplemented(SolumException): msg_fmt = _("The requested operation is not implemented.") code = 501 + + +class AuthorizationFailure(SolumException): + msg_fmt = _("%(client)s connection failed. %(message)s") diff --git a/solum/tests/common/test_clients.py b/solum/tests/common/test_clients.py index 910927219..2079ab4aa 100644 --- a/solum/tests/common/test_clients.py +++ b/solum/tests/common/test_clients.py @@ -14,6 +14,7 @@ import mock from heatclient import client as heatclient from solum.common import clients +from solum.common import exception from solum.tests import base @@ -37,3 +38,31 @@ class ClientsTest(base.BaseTestCase): cert_file=None, token='3bcc3d3a03f44e3d8377f9247b0ad155', auth_url='keystone_url', ca_file=None, key_file=None, password=None, insecure=False) + + def test_clients_heat_noauth(self): + con = mock.MagicMock() + con.auth_token = None + con.tenant = "b363706f891f48019483f8bd6503c54b" + auth_url = mock.PropertyMock(name="auth_url", + return_value="keystone_url") + type(con).auth_url = auth_url + con.get_url_for = mock.Mock(name="get_url_for") + con.get_url_for.return_value = "url_from_keystone" + obj = clients.OpenStackClients(con) + obj._heat = None + self.assertRaises(exception.AuthorizationFailure, obj.heat) + + def test_clients_heat_cached(self): + con = mock.MagicMock() + con.tenant = "b363706f891f48019483f8bd6503c54b" + con.auth_token = "3bcc3d3a03f44e3d8377f9247b0ad155" + auth_url = mock.PropertyMock(name="auth_url", + return_value="keystone_url") + type(con).auth_url = auth_url + con.get_url_for = mock.Mock(name="get_url_for") + con.get_url_for.return_value = "url_from_keystone" + obj = clients.OpenStackClients(con) + obj._heat = None + heat = obj.heat() + heat_cached = obj.heat() + self.assertEqual(heat, heat_cached)