diff --git a/rally/osclients.py b/rally/osclients.py index f7f799e4b6..04b935f918 100644 --- a/rally/osclients.py +++ b/rally/osclients.py @@ -429,3 +429,29 @@ class Clients(object): if service_type in consts.ServiceType: services_data[service_type] = consts.ServiceType[service_type] return services_data + + @classmethod + def register(cls, client_name, client_func): + """Add new OpenStack client dynamically. + + :param client_name: str name how client will be named in Rally clients + :param client_func: function that implememnts client spawning. + It will be added to Clients in runtime, so its + sole argument is Clients instance + Example: + >>> def supernova(self): + ... from novaclient import client as nova + ... return nova.Client("2", auth_token=self.keystone().auth_token, + ... **self._get_auth_info(password_key="key")) + ... + >>> from rally import osclients + >>> osclients.Clients.register("supernova", supernova) + >>> clients = osclients.Clients.create_from_env() + >>> clients.supernova().services.list()[:2] + [, ] + """ + if hasattr(cls, client_name): + raise ValueError( + _("Can not register client: name already exists: %s") + % client_name) + setattr(cls, client_name, cached(client_func)) diff --git a/tests/unit/test_osclients.py b/tests/unit/test_osclients.py index 3a3ee2babd..c47627e20d 100644 --- a/tests/unit/test_osclients.py +++ b/tests/unit/test_osclients.py @@ -465,3 +465,22 @@ class OSClientsTestCase(test.TestCase): "token": self.fake_keystone.auth_token} mock_murano.client.Client.assert_called_once_with("1", **kw) self.assertEqual(fake_murano, self.clients.cache["murano"]) + + @mock.patch("rally.osclients.cached") + def test_register(self, mock_cached): + client_func = mock.Mock(return_value="foo_client") + cached_client_func = mock.Mock(return_value="cached_foo_client") + mock_cached.return_value = cached_client_func + clients = osclients.Clients(mock.Mock()) + + self.assertFalse(hasattr(clients, "foo")) + + osclients.Clients.register("foo", client_func) + + mock_cached.assert_called_once_with(client_func) + self.assertEqual("cached_foo_client", clients.foo()) + self.assertEqual(cached_client_func, clients.foo) + + # Call second time with same name + self.assertRaises(ValueError, + osclients.Clients.register, "foo", client_func)