Beispiel #1
0
def setup_fixture(obj: FixtureType,
                  fixture_id: typing.Any = None,
                  manager: 'FixtureManager' = None,
                  alternative: FixtureType = None) \
        -> F:
    """I setups registered fixture

    """
    if alternative is None:
        objs = [obj]
    else:
        objs = [obj, alternative]
    with _exception.handle_multiple_exceptions(
            handle_exception=handle_setup_error):
        errors = []
        for _obj in objs:
            fixture: F = typing.cast(
                F, get_fixture(_obj, fixture_id=fixture_id, manager=manager))
            try:
                fixture.setUp()
                break
            except testtools.MultipleExceptions:
                errors.append(sys.exc_info())
        else:
            raise testtools.MultipleExceptions(*errors)

    return fixture
Beispiel #2
0
def available_modules():
    """Set of service client modules available in Tempest and plugins

    Set of stable service clients from Tempest and service clients exposed
    by plugins. This set of available modules can be used for automatic
    configuration.

    :raise PluginRegistrationException: if a plugin exposes a service_version
        already defined by Tempest or another plugin.

    Examples::

        from tempest import config
        params = {}
        for service_version in available_modules():
            service = service_version.split('.')[0]
            params[service] = config.service_client_config(service)
        service_clients = ServiceClients(creds, identity_uri,
                                         client_parameters=params)
    """
    extra_service_versions = set([])
    _tempest_modules = set(tempest_modules())
    plugin_services = ClientsRegistry().get_service_clients()
    name_conflicts = []
    for plugin_name in plugin_services:
        plug_service_versions = set(
            [x['service_version'] for x in plugin_services[plugin_name]])
        # If a plugin exposes a duplicate service_version raise an exception
        if plug_service_versions:
            if not plug_service_versions.isdisjoint(extra_service_versions):
                detailed_error = (
                    'Plugin %s is trying to register a service %s already '
                    'claimed by another one' %
                    (plugin_name,
                     extra_service_versions & plug_service_versions))
                name_conflicts.append(
                    exceptions.PluginRegistrationException(
                        name=plugin_name, detailed_error=detailed_error))
            # NOTE(andreaf) Once all tempest clients are stable, the following
            # if will have to be removed.
            if not plug_service_versions.isdisjoint(
                    _tempest_internal_modules()):
                detailed_error = (
                    'Plugin %s is trying to register a service %s already '
                    'claimed by a Tempest one' %
                    (plugin_name,
                     _tempest_internal_modules() & plug_service_versions))
                name_conflicts.append(
                    exceptions.PluginRegistrationException(
                        name=plugin_name, detailed_error=detailed_error))
        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
Beispiel #3
0
def load_private_key(filename: str, password: str = None) -> paramiko.PKey:
    errors: typing.List[tobiko.ExceptionInfo] = []
    for key_class in KEY_CLASSES:
        try:
            pkey: paramiko.PKey = key_class.from_private_key_file(
                filename=filename, password=password)
        except (paramiko.SSHException, ValueError):
            errors.append(tobiko.exc_info())
        else:
            LOG.debug(f'Key file loaded: {filename} (key_class={key_class})')
            return pkey

    cause = testtools.MultipleExceptions(*errors)
    raise LoadPrivateKeyError(filename=filename) from cause
Beispiel #4
0
    def resource_cleanup(cls):
        """Class level resource cleanup for test cases.

        Resource cleanup processes the stack of cleanups produced by
        `addClassResourceCleanup` and then cleans up validation resources
        if any were provisioned.

        All cleanups are processed whatever the outcome. Exceptions are
        accumulated and re-raised as a `MultipleExceptions` at the end.

        In most cases test cases won't need to override `resource_cleanup`,
        but if they do they must invoke `resource_cleanup` on super.

        Example::

            class TestWithReallyComplexCleanup(test.BaseTestCase):

                @classmethod
                def resource_setup(cls):
                    # provision resource A
                    cls.addClassResourceCleanup(delete_resource, A)
                    # provision resource B
                    cls.addClassResourceCleanup(delete_resource, B)

                @classmethod
                def resource_cleanup(cls):
                    # It's possible to override resource_cleanup but in most
                    # cases it shouldn't be required. Nothing that may fail
                    # should be executed before the call to super since it
                    # might cause resource leak in case of error.
                    super(TestWithReallyComplexCleanup, cls).resource_cleanup()
                    # At this point test credentials are still available but
                    # anything from the cleanup stack has been already deleted.
        """
        cls.__resource_cleaup_called = True
        cleanup_errors = []
        while cls._class_cleanups:
            try:
                fn, args, kwargs = cls._class_cleanups.pop()
                fn(*args, **kwargs)
            except Exception:
                cleanup_errors.append(sys.exc_info())
        if cleanup_errors:
            raise testtools.MultipleExceptions(*cleanup_errors)
Beispiel #5
0
    def get_credentials(self) -> typing.Optional[KeystoneCredentials]:
        errors = []
        for fixture in self.fixtures:
            try:
                credentials = tobiko.setup_fixture(fixture).credentials
            except Exception as ex:
                LOG.debug("Error getting credentials from %r: %s",
                          tobiko.get_fixture_name(fixture), ex)
                errors.append(tobiko.exc_info())
                continue

            if credentials:
                LOG.info("Got default credentials from fixture %r: %r",
                         fixture, credentials)
                return credentials
            else:
                LOG.debug('Got no credentials from %r', fixture)

        if len(errors) == 1:
            errors[0].reraise()
        elif errors:
            raise testtools.MultipleExceptions(errors)

        raise NoSuchCredentialsError(fixtures=self.fixtures)
Beispiel #6
0
    def __init__(self,
                 credentials,
                 identity_uri,
                 region=None,
                 scope='project',
                 disable_ssl_certificate_validation=True,
                 ca_certs=None,
                 trace_requests='',
                 client_parameters=None):
        """Service Clients provider

        Instantiate a `ServiceClients` object, from a set of credentials and an
        identity URI. The identity version is inferred from the credentials
        object. Optionally auth scope can be provided.

        A few parameters can be given a value which is applied as default
        for all service clients: region, dscv, ca_certs, trace_requests.

        Parameters dscv, ca_certs and trace_requests all apply to the auth
        provider as well as any service clients provided by this manager.

        Any other client parameter should be set via ClientsRegistry.

        Client parameter used to be set via client_parameters, but this is
        deprecated, and it is actually already not honoured
        anymore: https://launchpad.net/bugs/1680915.

        The list of available parameters is defined in the service clients
        interfaces. For reference, most clients will accept 'region',
        'service', 'endpoint_type', 'build_timeout' and 'build_interval', which
        are all inherited from RestClient.

        The `config` module in Tempest exposes an helper function
        `service_client_config` that can be used to extract from configuration
        a dictionary ready to be injected in kwargs.

        Exceptions are:
        - Token clients for 'identity' must be given an 'auth_url' parameter
        - Volume client for 'volume' accepts 'default_volume_size'
        - Servers client from 'compute' accepts 'enable_instance_password'

        If Tempest configuration is used, parameters will be loaded in the
        Registry automatically for all service client (Tempest stable ones
        and plugins).

        Examples::

            identity_params = config.service_client_config('identity')
            params = {
                'identity': identity_params,
                'compute': {'region': 'region2'}}
            manager = lib_manager.Manager(
                my_creds, identity_uri, client_parameters=params)

        :param credentials: An instance of `auth.Credentials`
        :param identity_uri: URI of the identity API. This should be a
                             mandatory parameter, and it will so soon.
        :param region: Default value of region for service clients.
        :param scope: default scope for tokens produced by the auth provider
        :param disable_ssl_certificate_validation: Applies to auth and to all
                                                  service clients.
        :param ca_certs: Applies to auth and to all service clients.
        :param trace_requests: Applies to auth and to all service clients.
        :param client_parameters: Dictionary with parameters for service
            clients. Keys of the dictionary are the service client service
            name, as declared in `service_clients.available_modules()` except
            for the version. Values are dictionaries of parameters that are
            going to be passed to all clients in the service client module.
        """
        self._registered_services = set([])
        self.credentials = credentials
        self.identity_uri = identity_uri
        if not identity_uri:
            raise exceptions.InvalidCredentials(
                'ServiceClients requires a non-empty identity_uri.')
        self.region = region
        # Check if passed or default credentials are valid
        if not self.credentials.is_valid():
            raise exceptions.InvalidCredentials()
        # Get the identity classes matching the provided credentials
        # TODO(andreaf) Define a new interface in Credentials to get
        # the API version from an instance
        identity = [
            (k, auth.IDENTITY_VERSION[k][1])
            for k in auth.IDENTITY_VERSION.keys()
            if isinstance(self.credentials, auth.IDENTITY_VERSION[k][0])
        ]
        # Zero matches or more than one are both not valid.
        if len(identity) != 1:
            raise exceptions.InvalidCredentials()
        self.auth_version, auth_provider_class = identity[0]
        self.dscv = disable_ssl_certificate_validation
        self.ca_certs = ca_certs
        self.trace_requests = trace_requests
        # Creates an auth provider for the credentials
        self.auth_provider = auth_provider_class(
            self.credentials,
            self.identity_uri,
            scope=scope,
            disable_ssl_certificate_validation=self.dscv,
            ca_certs=self.ca_certs,
            trace_requests=self.trace_requests)
        # Setup some defaults for client parameters of registered services
        client_parameters = client_parameters or {}
        self.parameters = {}
        # Parameters are provided for unversioned services
        all_modules = available_modules() | _tempest_internal_modules()
        unversioned_services = set([x.split('.')[0] for x in all_modules])
        for service in unversioned_services:
            self.parameters[service] = self._setup_parameters(
                client_parameters.pop(service, {}))
        # Check that no client parameters was supplied for unregistered clients
        if client_parameters:
            raise exceptions.UnknownServiceClient(
                services=list(client_parameters.keys()))

        # Register service clients from the registry (__tempest__ and plugins)
        clients_registry = ClientsRegistry()
        plugin_service_clients = clients_registry.get_service_clients()
        registration_errors = []
        for plugin in plugin_service_clients:
            service_clients = plugin_service_clients[plugin]
            # Each plugin returns a list of service client parameters
            for service_client in service_clients:
                # NOTE(andreaf) If a plugin cannot register, stop the
                # registration process, log some details to help
                # troubleshooting, and re-raise
                try:
                    self.register_service_client_module(**service_client)
                except Exception:
                    registration_errors.append(sys.exc_info())
                    LOG.exception(
                        'Failed to register service client from plugin %s '
                        'with parameters %s', plugin, service_client)
        if registration_errors:
            raise testtools.MultipleExceptions(*registration_errors)
Beispiel #7
0
 def run():
     with tobiko.handle_multiple_exceptions(
             handle_exception=handle_exception):
         raise testtools.MultipleExceptions(a, inner, d)
Beispiel #8
0
 def run():
     with tobiko.handle_multiple_exceptions():
         raise testtools.MultipleExceptions(a, b, c)
Beispiel #9
0
 def test_handle_multiple_exceptions_with_empty_multiple_exception(self):
     with tobiko.handle_multiple_exceptions():
         raise testtools.MultipleExceptions()