blob: 386e621a8c36987cd26d15398f285b1dd3f1089e [file] [log] [blame]
Andrea Frittoli (andreaf)23950142016-06-13 12:39:29 +01001# Copyright 2012 OpenStack Foundation
2# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
3# All Rights Reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
17from tempest.lib import auth
18from tempest.lib import exceptions
19
20
Andrea Frittoli (andreaf)de5fb0c2016-06-13 12:15:00 +010021def tempest_modules():
22 """List of service client modules available in Tempest.
23
24 Provides a list of service modules available Tempest.
25 """
26 return set(['compute', 'identity.v2', 'identity.v3', 'image.v1',
27 'image.v2', 'network', 'object-storage', 'volume.v1',
28 'volume.v2', 'volume.v3'])
29
30
31def available_modules():
32 """List of service client modules available in Tempest and plugins"""
33 # TODO(andreaf) For now this returns only tempest_modules
34 return tempest_modules()
35
36
Andrea Frittoli (andreaf)23950142016-06-13 12:39:29 +010037class ServiceClients(object):
38 """Service client provider class
39
40 The ServiceClients object provides a useful means for tests to access
41 service clients configured for a specified set of credentials.
42 It hides some of the complexity from the authorization and configuration
43 layers.
44
45 Examples:
46
47 >>> from tempest import service_clients
48 >>> johndoe = cred_provider.get_creds_by_role(['johndoe'])
Andrea Frittoli (andreaf)de5fb0c2016-06-13 12:15:00 +010049 >>> johndoe_clients = service_clients.ServiceClients(johndoe,
50 >>> identity_uri)
Andrea Frittoli (andreaf)23950142016-06-13 12:39:29 +010051 >>> johndoe_servers = johndoe_clients.servers_client.list_servers()
52
53 """
54 # NOTE(andreaf) This class does not depend on tempest configuration
55 # and its meant for direct consumption by external clients such as tempest
56 # plugins. Tempest provides a wrapper class, `clients.Manager`, that
57 # initialises this class using values from tempest CONF object. The wrapper
58 # class should only be used by tests hosted in Tempest.
59
Andrea Frittoli (andreaf)de5fb0c2016-06-13 12:15:00 +010060 def __init__(self, credentials, identity_uri, region=None, scope='project',
61 disable_ssl_certificate_validation=True, ca_certs=None,
62 trace_requests='', client_parameters=None):
Andrea Frittoli (andreaf)23950142016-06-13 12:39:29 +010063 """Service Clients provider
64
65 Instantiate a `ServiceClients` object, from a set of credentials and an
66 identity URI. The identity version is inferred from the credentials
67 object. Optionally auth scope can be provided.
Andrea Frittoli (andreaf)de5fb0c2016-06-13 12:15:00 +010068
69 A few parameters can be given a value which is applied as default
70 for all service clients: region, dscv, ca_certs, trace_requests.
71
Andrea Frittoli (andreaf)23950142016-06-13 12:39:29 +010072 Parameters dscv, ca_certs and trace_requests all apply to the auth
73 provider as well as any service clients provided by this manager.
74
Andrea Frittoli (andreaf)de5fb0c2016-06-13 12:15:00 +010075 Any other client parameter must be set via client_parameters.
76 The list of available parameters is defined in the service clients
77 interfaces. For reference, most clients will accept 'region',
78 'service', 'endpoint_type', 'build_timeout' and 'build_interval', which
79 are all inherited from RestClient.
80
81 The `config` module in Tempest exposes an helper function
82 `service_client_config` that can be used to extract from configuration
83 a dictionary ready to be injected in kwargs.
84
85 Exceptions are:
86 - Token clients for 'identity' have a very different interface
87 - Volume client for 'volume' accepts 'default_volume_size'
88 - Servers client from 'compute' accepts 'enable_instance_password'
89
90 Examples:
91
92 >>> identity_params = config.service_client_config('identity')
93 >>> params = {
94 >>> 'identity': identity_params,
95 >>> 'compute': {'region': 'region2'}}
96 >>> manager = lib_manager.Manager(
97 >>> my_creds, identity_uri, client_parameters=params)
98
Andrea Frittoli (andreaf)23950142016-06-13 12:39:29 +010099 :param credentials: An instance of `auth.Credentials`
100 :param identity_uri: URI of the identity API. This should be a
101 mandatory parameter, and it will so soon.
102 :param region: Default value of region for service clients.
103 :param scope: default scope for tokens produced by the auth provider
104 :param disable_ssl_certificate_validation Applies to auth and to all
105 service clients.
106 :param ca_certs Applies to auth and to all service clients.
107 :param trace_requests Applies to auth and to all service clients.
Andrea Frittoli (andreaf)de5fb0c2016-06-13 12:15:00 +0100108 :param client_parameters Dictionary with parameters for service
109 clients. Keys of the dictionary are the service client service
110 name, as declared in `service_clients.available_modules()` except
111 for the version. Values are dictionaries of parameters that are
112 going to be passed to all clients in the service client module.
113
114 Examples:
115
116 >>> params_service_x = {'param_name': 'param_value'}
117 >>> client_parameters = { 'service_x': params_service_x }
118
119 >>> params_service_y = config.service_client_config('service_y')
120 >>> client_parameters['service_y'] = params_service_y
121
Andrea Frittoli (andreaf)23950142016-06-13 12:39:29 +0100122 """
123 self.credentials = credentials
124 self.identity_uri = identity_uri
125 if not identity_uri:
126 raise exceptions.InvalidCredentials(
Andrea Frittoli (andreaf)de5fb0c2016-06-13 12:15:00 +0100127 'ServiceClients requires a non-empty identity_uri.')
Andrea Frittoli (andreaf)23950142016-06-13 12:39:29 +0100128 self.region = region
129 # Check if passed or default credentials are valid
130 if not self.credentials.is_valid():
131 raise exceptions.InvalidCredentials()
132 # Get the identity classes matching the provided credentials
133 # TODO(andreaf) Define a new interface in Credentials to get
134 # the API version from an instance
135 identity = [(k, auth.IDENTITY_VERSION[k][1]) for k in
136 auth.IDENTITY_VERSION.keys() if
137 isinstance(self.credentials, auth.IDENTITY_VERSION[k][0])]
138 # Zero matches or more than one are both not valid.
139 if len(identity) != 1:
140 raise exceptions.InvalidCredentials()
141 self.auth_version, auth_provider_class = identity[0]
142 self.dscv = disable_ssl_certificate_validation
143 self.ca_certs = ca_certs
144 self.trace_requests = trace_requests
145 # Creates an auth provider for the credentials
146 self.auth_provider = auth_provider_class(
147 self.credentials, self.identity_uri, scope=scope,
148 disable_ssl_certificate_validation=self.dscv,
149 ca_certs=self.ca_certs, trace_requests=self.trace_requests)
Andrea Frittoli (andreaf)de5fb0c2016-06-13 12:15:00 +0100150 # Setup some defaults for client parameters of registered services
151 client_parameters = client_parameters or {}
152 self.parameters = {}
153 # Parameters are provided for unversioned services
154 unversioned_services = set(
155 [x.split('.')[0] for x in available_modules()])
156 for service in unversioned_services:
157 self.parameters[service] = self._setup_parameters(
158 client_parameters.pop(service, {}))
159 # Check that no client parameters was supplied for unregistered clients
160 if client_parameters:
161 raise exceptions.UnknownServiceClient(
162 services=list(client_parameters.keys()))
163
164 def _setup_parameters(self, parameters):
165 """Setup default values for client parameters
166
167 Region by default is the region passed as an __init__ parameter.
168 Checks that no parameter for an unknown service is provided.
169 """
170 _parameters = {}
171 # Use region from __init__
172 if self.region:
173 _parameters['region'] = self.region
174 # Update defaults with specified parameters
175 _parameters.update(parameters)
176 # If any parameter is left, parameters for an unknown service were
177 # provided as input. Fail rather than ignore silently.
178 return _parameters