diff --git a/etc/solum/solum.conf.sample b/etc/solum/solum.conf.sample index dd612c793..f782c0afd 100644 --- a/etc/solum/solum.conf.sample +++ b/etc/solum/solum.conf.sample @@ -708,6 +708,21 @@ #hash_algorithms=md5 +[marconi_client] + +# +# Options defined in solum.common.clients +# + +# Type of endpoint in Queue service catalog to use for +# communication with the Marconi service. (string value) +#endpoint_type=publicURL + +# If set, then the server's certificate for marconi will not +# be verified. (boolean value) +#insecure=false + + [matchmaker_ring] # diff --git a/requirements.txt b/requirements.txt index efbecfb47..f339a8081 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,6 +9,7 @@ pbr>=0.6,!=0.7,<1.0 pecan>=0.4.5 python-glanceclient>=0.13.1 python-heatclient>=0.2.9 +python-marconiclient>=0.0.2 python-neutronclient>=2.3.5,<3 python-keystoneclient>=0.9.0 python-swiftclient>=2.0.2 diff --git a/solum/common/clients.py b/solum/common/clients.py index 84ab2a095..a062b722f 100644 --- a/solum/common/clients.py +++ b/solum/common/clients.py @@ -14,6 +14,7 @@ from glanceclient import client as glanceclient from heatclient import client as heatclient +from marconiclient.queues.v1 import client as marconiclient from mistralclient.api import client as mistralclient from neutronclient.neutron import client as neutronclient from oslo.config import cfg @@ -58,6 +59,17 @@ heat_client_opts = [ help=_("If set, then the server's certificate will not " "be verified."))] +marconi_client_opts = [ + cfg.StrOpt('endpoint_type', + default='publicURL', + help=_( + 'Type of endpoint in Queue service catalog to use ' + 'for communication with the Marconi service.')), + cfg.BoolOpt('insecure', + default=False, + help=_("If set, then the server's certificate for marconi " + "will not be verified."))] + neutron_client_opts = [ cfg.StrOpt('endpoint_type', default='publicURL', @@ -99,6 +111,7 @@ mistral_client_opts = [ cfg.CONF.register_opts(glance_client_opts, group='glance_client') cfg.CONF.register_opts(heat_client_opts, group='heat_client') +cfg.CONF.register_opts(marconi_client_opts, group='marconi_client') cfg.CONF.register_opts(neutron_client_opts, group='neutron_client') cfg.CONF.register_opts(swift_client_opts, group='swift_client') cfg.CONF.register_opts(mistral_client_opts, group='mistral_client') @@ -114,6 +127,7 @@ class OpenStackClients(object): self._heat = None self._neutron = None self._swift = None + self._marconi = None self._mistral = None def url_for(self, **kwargs): @@ -134,6 +148,25 @@ class OpenStackClients(object): self._keystone = solum_keystoneclient.KeystoneClientV3(self.context) return self._keystone + @exception.wrap_keystone_exception + def marconi(self): + if self._marconi: + return self._marconi + + endpoint_type = self._get_client_option('marconi', 'endpoint_type') + endpoint_url = self.url_for(service_type='queuing', + endpoint_type=endpoint_type) + conf = {'auth_opts': + {'backend': 'keystone', + 'options': {'os_auth_token': self.auth_token, + 'os_auth_url': self.auth_url, + 'insecure': self._get_client_option( + 'marconi', 'insecure')} + } + } + self._marconi = marconiclient.Client(endpoint_url, conf=conf) + return self._marconi + @exception.wrap_keystone_exception def neutron(self): if self._neutron: diff --git a/solum/tests/common/test_clients.py b/solum/tests/common/test_clients.py index 734d1834a..7b9cb3416 100644 --- a/solum/tests/common/test_clients.py +++ b/solum/tests/common/test_clients.py @@ -12,6 +12,7 @@ from glanceclient import client as glanceclient from heatclient import client as heatclient +from marconiclient.queues.v1 import client as marconiclient from mistralclient.api import client as mistralclient import mock from neutronclient.neutron import client as neutronclient @@ -246,3 +247,54 @@ class ClientsTest(base.BaseTestCase): mistral = obj.mistral() mistral_cached = obj.mistral() self.assertEqual(mistral, mistral_cached) + + @mock.patch.object(marconiclient, 'Client') + @mock.patch.object(clients.OpenStackClients, 'url_for') + @mock.patch.object(clients.OpenStackClients, 'auth_url') + def test_clients_marconi(self, mock_auth, mock_url, mock_call): + mock_auth.__get__ = mock.Mock(return_value="keystone_url") + con = mock.MagicMock() + con.tenant = "b363706f891f48019483f8bd6503c54b" + con.auth_token = "3bcc3d3a03f44e3d8377f9247b0ad155" + con.auth_url = "keystone_url" + mock_url.return_value = "url_from_keystone" + obj = clients.OpenStackClients(con) + obj._marconi = None + obj.marconi() + conf = {'auth_opts': + {'backend': 'keystone', + 'options': + {'os_auth_token': '3bcc3d3a03f44e3d8377f9247b0ad155', + 'os_auth_url': 'keystone_url', + 'insecure': False} + } + } + mock_call.assert_called_once_with('url_from_keystone', conf=conf) + + def test_clients_marconi_noauth(self): + con = mock.MagicMock() + con.auth_token = None + con.auth_token_info = 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._marconi = None + self.assertRaises(exception.AuthorizationFailure, obj.marconi) + + @mock.patch.object(clients.OpenStackClients, 'url_for') + @mock.patch.object(clients.OpenStackClients, 'auth_url') + def test_clients_marconi_cached(self, mock_auth, mock_url): + mock_auth.__get__ = mock.Mock(return_value="keystone_url") + con = mock.MagicMock() + con.tenant = "b363706f891f48019483f8bd6503c54b" + con.auth_token = "3bcc3d3a03f44e3d8377f9247b0ad155" + mock_url.return_value = "url_from_keystone" + obj = clients.OpenStackClients(con) + obj._marconi = None + marconi = obj.marconi() + marconi_cached = obj.marconi() + self.assertEqual(marconi, marconi_cached)