Try to register all service clients

Accumulate all exceptions from service client registrations,
and raise them together at the end, so in case more than one
service client has issues, we provide a full error report.

Change-Id: I902cfdea0af371dfa222a9bbf41edc4ea2765926
This commit is contained in:
Andrea Frittoli (andreaf) 2016-08-08 10:34:31 +01:00 committed by Andrea Frittoli
parent c7a403debd
commit ff50cc5b52
3 changed files with 72 additions and 5 deletions

View File

@ -44,6 +44,9 @@ class TempestException(Exception):
def __str__(self): def __str__(self):
return self._error_string return self._error_string
def __repr__(self):
return self._error_string
class RestClientException(TempestException, class RestClientException(TempestException,
testtools.TestCase.failureException): testtools.TestCase.failureException):

View File

@ -17,10 +17,12 @@
import copy import copy
import importlib import importlib
import inspect import inspect
import sys
import warnings import warnings
from debtcollector import removals from debtcollector import removals
from oslo_log import log as logging from oslo_log import log as logging
import testtools
from tempest.lib import auth from tempest.lib import auth
from tempest.lib.common.utils import misc from tempest.lib.common.utils import misc
@ -85,6 +87,7 @@ def available_modules():
extra_service_versions = set([]) extra_service_versions = set([])
_tempest_modules = set(tempest_modules()) _tempest_modules = set(tempest_modules())
plugin_services = ClientsRegistry().get_service_clients() plugin_services = ClientsRegistry().get_service_clients()
name_conflicts = []
for plugin_name in plugin_services: for plugin_name in plugin_services:
plug_service_versions = set([x['service_version'] for x in plug_service_versions = set([x['service_version'] for x in
plugin_services[plugin_name]]) plugin_services[plugin_name]])
@ -96,8 +99,8 @@ def available_modules():
'claimed by another one' % (plugin_name, 'claimed by another one' % (plugin_name,
extra_service_versions & extra_service_versions &
plug_service_versions)) plug_service_versions))
raise exceptions.PluginRegistrationException( name_conflicts.append(exceptions.PluginRegistrationException(
name=plugin_name, detailed_error=detailed_error) name=plugin_name, detailed_error=detailed_error))
# NOTE(andreaf) Once all tempest clients are stable, the following # NOTE(andreaf) Once all tempest clients are stable, the following
# if will have to be removed. # if will have to be removed.
if not plug_service_versions.isdisjoint( if not plug_service_versions.isdisjoint(
@ -107,9 +110,14 @@ def available_modules():
'claimed by a Tempest one' % (plugin_name, 'claimed by a Tempest one' % (plugin_name,
_tempest_internal_modules() & _tempest_internal_modules() &
plug_service_versions)) plug_service_versions))
raise exceptions.PluginRegistrationException( name_conflicts.append(exceptions.PluginRegistrationException(
name=plugin_name, detailed_error=detailed_error) name=plugin_name, detailed_error=detailed_error))
extra_service_versions |= plug_service_versions extra_service_versions |= plug_service_versions
if name_conflicts:
LOG.error(
'Failed to list available modules due to name conflicts: %s',
name_conflicts)
raise testtools.MultipleExceptions(*name_conflicts)
return _tempest_modules | extra_service_versions return _tempest_modules | extra_service_versions
@ -375,6 +383,7 @@ class ServiceClients(object):
# Register service clients from the registry (__tempest__ and plugins) # Register service clients from the registry (__tempest__ and plugins)
clients_registry = ClientsRegistry() clients_registry = ClientsRegistry()
plugin_service_clients = clients_registry.get_service_clients() plugin_service_clients = clients_registry.get_service_clients()
registration_errors = []
for plugin in plugin_service_clients: for plugin in plugin_service_clients:
service_clients = plugin_service_clients[plugin] service_clients = plugin_service_clients[plugin]
# Each plugin returns a list of service client parameters # Each plugin returns a list of service client parameters
@ -385,10 +394,12 @@ class ServiceClients(object):
try: try:
self.register_service_client_module(**service_client) self.register_service_client_module(**service_client)
except Exception: except Exception:
registration_errors.append(sys.exc_info())
LOG.exception( LOG.exception(
'Failed to register service client from plugin %s ' 'Failed to register service client from plugin %s '
'with parameters %s', plugin, service_client) 'with parameters %s', plugin, service_client)
raise if registration_errors:
raise testtools.MultipleExceptions(*registration_errors)
def register_service_client_module(self, name, service_version, def register_service_client_module(self, name, service_version,
module_path, client_names, **kwargs): module_path, client_names, **kwargs):

View File

@ -16,6 +16,7 @@ import types
import fixtures import fixtures
import mock import mock
import six
import testtools import testtools
from tempest.lib import auth from tempest.lib import auth
@ -258,6 +259,58 @@ class TestServiceClients(base.TestCase):
clients.ServiceClients(creds, identity_uri=uri, clients.ServiceClients(creds, identity_uri=uri,
client_parameters=params) client_parameters=params)
def test___init___plugin_service_clients_cannot_load(self):
creds = fake_credentials.FakeKeystoneV3Credentials()
uri = 'fake_uri'
fake_service_clients = {
'service1': [{'name': 'client1',
'service_version': 'client1.v1',
'module_path': 'I cannot load this',
'client_names': ['SomeClient1']}],
'service2': [{'name': 'client2',
'service_version': 'client2.v1',
'module_path': 'This neither',
'client_names': ['SomeClient1']}]}
msg = "(?=.*{0})(?=.*{1})".format(
*[x[1][0]['module_path'] for x in six.iteritems(
fake_service_clients)])
self.useFixture(fixtures.MockPatchObject(
clients.ClientsRegistry(), 'get_service_clients',
return_value=fake_service_clients))
with testtools.ExpectedException(
testtools.MultipleExceptions, value_re=msg):
clients.ServiceClients(creds, identity_uri=uri)
def test___init___plugin_service_clients_name_conflict(self):
creds = fake_credentials.FakeKeystoneV3Credentials()
uri = 'fake_uri'
fake_service_clients = {
'serviceA': [{'name': 'client1',
'service_version': 'client1.v1',
'module_path': 'fake_path_1',
'client_names': ['SomeClient1']}],
'serviceB': [{'name': 'client1',
'service_version': 'client1.v2',
'module_path': 'fake_path_2',
'client_names': ['SomeClient2']}],
'serviceC': [{'name': 'client1',
'service_version': 'client1.v1',
'module_path': 'fake_path_2',
'client_names': ['SomeClient1']}],
'serviceD': [{'name': 'client1',
'service_version': 'client1.v2',
'module_path': 'fake_path_2',
'client_names': ['SomeClient2']}]}
msg = "(?=.*{0})(?=.*{1})".format(
*[x[1][0]['service_version'] for x in six.iteritems(
fake_service_clients)])
self.useFixture(fixtures.MockPatchObject(
clients.ClientsRegistry(), 'get_service_clients',
return_value=fake_service_clients))
with testtools.ExpectedException(
testtools.MultipleExceptions, value_re=msg):
clients.ServiceClients(creds, identity_uri=uri)
def _get_manager(self, init_region='fake_region'): def _get_manager(self, init_region='fake_region'):
# Get a manager to invoke _setup_parameters on # Get a manager to invoke _setup_parameters on
creds = fake_credentials.FakeKeystoneV2Credentials() creds = fake_credentials.FakeKeystoneV2Credentials()