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
This commit is contained in:
		@@ -16,6 +16,7 @@ from heatclient import client as heatclient
 | 
				
			|||||||
from keystoneclient.v2_0 import client as ksclient
 | 
					from keystoneclient.v2_0 import client as ksclient
 | 
				
			||||||
from oslo.config import cfg
 | 
					from oslo.config import cfg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from solum.common import exception
 | 
				
			||||||
from solum.openstack.common.gettextutils import _
 | 
					from solum.openstack.common.gettextutils import _
 | 
				
			||||||
from solum.openstack.common import log as logging
 | 
					from solum.openstack.common import log as logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -77,6 +78,7 @@ class OpenStackClients(object):
 | 
				
			|||||||
    def _get_client_option(self, client, option):
 | 
					    def _get_client_option(self, client, option):
 | 
				
			||||||
        return getattr(getattr(cfg.CONF, '%s_client' % client), option)
 | 
					        return getattr(getattr(cfg.CONF, '%s_client' % client), option)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @exception.wrap_keystone_exception
 | 
				
			||||||
    def heat(self):
 | 
					    def heat(self):
 | 
				
			||||||
        if self._heat:
 | 
					        if self._heat:
 | 
				
			||||||
            return self._heat
 | 
					            return self._heat
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,8 +20,10 @@ Includes decorator for re-raising Solum-type exceptions.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import functools
 | 
					import functools
 | 
				
			||||||
import pecan
 | 
					import pecan
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
import wsme
 | 
					import wsme
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from keystoneclient import exceptions as keystone_exceptions
 | 
				
			||||||
from oslo.config import cfg
 | 
					from oslo.config import cfg
 | 
				
			||||||
import six
 | 
					import six
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,6 +32,7 @@ from solum.openstack.common import excutils
 | 
				
			|||||||
from solum.openstack.common.gettextutils import _
 | 
					from solum.openstack.common.gettextutils import _
 | 
				
			||||||
from solum.openstack.common import log as logging
 | 
					from solum.openstack.common import log as logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LOG = logging.getLogger(__name__)
 | 
					LOG = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exc_log_opts = [
 | 
					exc_log_opts = [
 | 
				
			||||||
@@ -96,6 +99,25 @@ def wrap_controller_exception(func):
 | 
				
			|||||||
    return wrapped
 | 
					    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):
 | 
					class SolumException(Exception):
 | 
				
			||||||
    """Base Solum Exception
 | 
					    """Base Solum Exception
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -152,3 +174,7 @@ class ResourceExists(SolumException):
 | 
				
			|||||||
class NotImplemented(SolumException):
 | 
					class NotImplemented(SolumException):
 | 
				
			||||||
    msg_fmt = _("The requested operation is not implemented.")
 | 
					    msg_fmt = _("The requested operation is not implemented.")
 | 
				
			||||||
    code = 501
 | 
					    code = 501
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AuthorizationFailure(SolumException):
 | 
				
			||||||
 | 
					    msg_fmt = _("%(client)s connection failed. %(message)s")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@ import mock
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from heatclient import client as heatclient
 | 
					from heatclient import client as heatclient
 | 
				
			||||||
from solum.common import clients
 | 
					from solum.common import clients
 | 
				
			||||||
 | 
					from solum.common import exception
 | 
				
			||||||
from solum.tests import base
 | 
					from solum.tests import base
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -37,3 +38,31 @@ class ClientsTest(base.BaseTestCase):
 | 
				
			|||||||
            cert_file=None, token='3bcc3d3a03f44e3d8377f9247b0ad155',
 | 
					            cert_file=None, token='3bcc3d3a03f44e3d8377f9247b0ad155',
 | 
				
			||||||
            auth_url='keystone_url', ca_file=None, key_file=None,
 | 
					            auth_url='keystone_url', ca_file=None, key_file=None,
 | 
				
			||||||
            password=None, insecure=False)
 | 
					            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)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user