Jay Pipes | 051075a | 2012-04-28 17:39:37 -0400 | [diff] [blame] | 1 | # vim: tabstop=4 shiftwidth=4 softtabstop=4 |
| 2 | |
| 3 | # Copyright 2012 OpenStack, LLC |
| 4 | # All Rights Reserved. |
| 5 | # |
| 6 | # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 7 | # not use this file except in compliance with the License. You may obtain |
| 8 | # a copy of the License at |
| 9 | # |
| 10 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | # |
| 12 | # Unless required by applicable law or agreed to in writing, software |
| 13 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 14 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 15 | # License for the specific language governing permissions and limitations |
| 16 | # under the License. |
| 17 | |
| 18 | import logging |
| 19 | |
| 20 | # Default client libs |
Brian Waldon | c9b99a2 | 2012-09-10 09:24:35 -0700 | [diff] [blame] | 21 | import glanceclient |
Maru Newby | dec13ec | 2012-08-30 11:19:17 -0700 | [diff] [blame] | 22 | import keystoneclient.v2_0.client |
| 23 | import novaclient.client |
Dan Prince | bff5223 | 2012-10-10 11:40:55 -0400 | [diff] [blame] | 24 | try: |
| 25 | import quantumclient.v2_0.client |
| 26 | except ImportError: |
| 27 | pass |
Jay Pipes | 051075a | 2012-04-28 17:39:37 -0400 | [diff] [blame] | 28 | |
| 29 | import tempest.config |
| 30 | from tempest import exceptions |
| 31 | # Tempest REST Fuzz testing client libs |
Matthew Treinish | a83a16e | 2012-12-07 13:44:02 -0500 | [diff] [blame] | 32 | from tempest.services.compute.json import console_output_client |
| 33 | from tempest.services.compute.json import extensions_client |
| 34 | from tempest.services.compute.json import flavors_client |
| 35 | from tempest.services.compute.json import floating_ips_client |
| 36 | from tempest.services.compute.json import images_client |
| 37 | from tempest.services.compute.json import keypairs_client |
| 38 | from tempest.services.compute.json import limits_client |
| 39 | from tempest.services.compute.json import quotas_client |
| 40 | from tempest.services.compute.json import security_groups_client |
| 41 | from tempest.services.compute.json import servers_client |
| 42 | from tempest.services.compute.json import volumes_extensions_client |
Jay Pipes | 051075a | 2012-04-28 17:39:37 -0400 | [diff] [blame] | 43 | from tempest.services.network.json import network_client |
Rohit Karajgi | dd47d7e | 2012-07-31 04:11:01 -0700 | [diff] [blame] | 44 | from tempest.services.volume.json import volumes_client |
Jay Pipes | 051075a | 2012-04-28 17:39:37 -0400 | [diff] [blame] | 45 | |
| 46 | NetworkClient = network_client.NetworkClient |
Mauro S. M. Rodrigues | 6e37324 | 2012-08-27 18:59:19 -0400 | [diff] [blame] | 47 | ImagesClient = images_client.ImagesClientJSON |
Tiago Mello | eda03b5 | 2012-08-22 23:47:29 -0300 | [diff] [blame] | 48 | FlavorsClient = flavors_client.FlavorsClientJSON |
Dan Smith | cf8fab6 | 2012-08-14 08:03:48 -0700 | [diff] [blame] | 49 | ServersClient = servers_client.ServersClientJSON |
Matthew Treinish | 3363446 | 2012-08-16 16:51:23 -0400 | [diff] [blame] | 50 | LimitsClient = limits_client.LimitsClientJSON |
Tiago Mello | 89126c3 | 2012-08-27 11:14:03 -0300 | [diff] [blame] | 51 | ExtensionsClient = extensions_client.ExtensionsClientJSON |
Vincent Hou | 22f03c7 | 2012-08-24 17:55:13 +0800 | [diff] [blame] | 52 | FloatingIPsClient = floating_ips_client.FloatingIPsClientJSON |
Vincent Hou | ead03dc | 2012-08-24 21:35:11 +0800 | [diff] [blame] | 53 | SecurityGroupsClient = security_groups_client.SecurityGroupsClientJSON |
Mauro S. M. Rodrigues | a636f53 | 2012-08-21 11:07:53 -0400 | [diff] [blame] | 54 | KeyPairsClient = keypairs_client.KeyPairsClientJSON |
Matthew Treinish | 4e08690 | 2012-08-17 17:52:22 -0400 | [diff] [blame] | 55 | VolumesExtensionsClient = volumes_extensions_client.VolumesExtensionsClientJSON |
Matthew Treinish | 9854d5b | 2012-09-20 10:22:13 -0400 | [diff] [blame] | 56 | VolumesClient = volumes_client.VolumesClientJSON |
rajalakshmi-ganesan | d793d69 | 2012-12-25 12:54:50 +0530 | [diff] [blame] | 57 | ConsoleOutputsClient = console_output_client.ConsoleOutputsClientJSON |
Rohit Karajgi | 07599c5 | 2012-11-02 05:35:16 -0700 | [diff] [blame] | 58 | QuotasClient = quotas_client.QuotasClient |
Jay Pipes | 051075a | 2012-04-28 17:39:37 -0400 | [diff] [blame] | 59 | |
| 60 | LOG = logging.getLogger(__name__) |
| 61 | |
| 62 | |
| 63 | class Manager(object): |
| 64 | |
| 65 | """ |
| 66 | Base manager class |
| 67 | |
| 68 | Manager objects are responsible for providing a configuration object |
| 69 | and a client object for a test case to use in performing actions. |
| 70 | """ |
| 71 | |
| 72 | def __init__(self): |
| 73 | self.config = tempest.config.TempestConfig() |
Maru Newby | dec13ec | 2012-08-30 11:19:17 -0700 | [diff] [blame] | 74 | self.client_attr_names = [] |
Jay Pipes | 051075a | 2012-04-28 17:39:37 -0400 | [diff] [blame] | 75 | |
| 76 | |
| 77 | class FuzzClientManager(Manager): |
| 78 | |
| 79 | """ |
| 80 | Manager class that indicates the client provided by the manager |
| 81 | is a fuzz-testing client that Tempest contains. These fuzz-testing |
| 82 | clients are used to be able to throw random or invalid data at |
| 83 | an endpoint and check for appropriate error messages returned |
| 84 | from the endpoint. |
| 85 | """ |
| 86 | pass |
| 87 | |
| 88 | |
Maru Newby | dec13ec | 2012-08-30 11:19:17 -0700 | [diff] [blame] | 89 | class DefaultClientManager(Manager): |
Jay Pipes | 051075a | 2012-04-28 17:39:37 -0400 | [diff] [blame] | 90 | |
| 91 | """ |
Maru Newby | dec13ec | 2012-08-30 11:19:17 -0700 | [diff] [blame] | 92 | Manager that provides the default clients to access the various |
| 93 | OpenStack APIs. |
Jay Pipes | 051075a | 2012-04-28 17:39:37 -0400 | [diff] [blame] | 94 | """ |
| 95 | |
| 96 | NOVACLIENT_VERSION = '2' |
| 97 | |
| 98 | def __init__(self): |
Maru Newby | dec13ec | 2012-08-30 11:19:17 -0700 | [diff] [blame] | 99 | super(DefaultClientManager, self).__init__() |
| 100 | self.compute_client = self._get_compute_client() |
| 101 | self.image_client = self._get_image_client() |
| 102 | self.identity_client = self._get_identity_client() |
| 103 | self.network_client = self._get_network_client() |
| 104 | self.client_attr_names = [ |
| 105 | 'compute_client', |
| 106 | 'image_client', |
| 107 | 'identity_client', |
| 108 | 'network_client', |
Zhongyue Luo | 30a563f | 2012-09-30 23:43:50 +0900 | [diff] [blame] | 109 | ] |
Maru Newby | dec13ec | 2012-08-30 11:19:17 -0700 | [diff] [blame] | 110 | |
| 111 | def _get_compute_client(self, username=None, password=None, |
| 112 | tenant_name=None): |
| 113 | # Novaclient will not execute operations for anyone but the |
| 114 | # identified user, so a new client needs to be created for |
| 115 | # each user that operations need to be performed for. |
| 116 | if not username: |
| 117 | username = self.config.compute.username |
| 118 | if not password: |
| 119 | password = self.config.compute.password |
| 120 | if not tenant_name: |
| 121 | tenant_name = self.config.compute.tenant_name |
Jay Pipes | 051075a | 2012-04-28 17:39:37 -0400 | [diff] [blame] | 122 | |
| 123 | if None in (username, password, tenant_name): |
Maru Newby | dec13ec | 2012-08-30 11:19:17 -0700 | [diff] [blame] | 124 | msg = ("Missing required credentials for compute client. " |
Jay Pipes | 051075a | 2012-04-28 17:39:37 -0400 | [diff] [blame] | 125 | "username: %(username)s, password: %(password)s, " |
| 126 | "tenant_name: %(tenant_name)s") % locals() |
| 127 | raise exceptions.InvalidConfiguration(msg) |
| 128 | |
| 129 | # Novaclient adds a /tokens/ part to the auth URL automatically |
| 130 | auth_url = self.config.identity.auth_url.rstrip('tokens') |
| 131 | |
| 132 | client_args = (username, password, tenant_name, auth_url) |
| 133 | |
| 134 | # Create our default Nova client to use in testing |
Jay Pipes | 444c3e6 | 2012-10-04 19:26:35 -0400 | [diff] [blame] | 135 | service_type = self.config.compute.catalog_type |
Maru Newby | dec13ec | 2012-08-30 11:19:17 -0700 | [diff] [blame] | 136 | return novaclient.client.Client(self.NOVACLIENT_VERSION, |
Zhongyue Luo | 79d8d36 | 2012-09-25 13:49:27 +0800 | [diff] [blame] | 137 | *client_args, |
| 138 | service_type=service_type, |
| 139 | no_cache=True) |
Jay Pipes | 051075a | 2012-04-28 17:39:37 -0400 | [diff] [blame] | 140 | |
Maru Newby | dec13ec | 2012-08-30 11:19:17 -0700 | [diff] [blame] | 141 | def _get_image_client(self): |
Brian Waldon | c9b99a2 | 2012-09-10 09:24:35 -0700 | [diff] [blame] | 142 | keystone = self._get_identity_client() |
| 143 | token = keystone.auth_token |
| 144 | endpoint = keystone.service_catalog.url_for(service_type='image', |
| 145 | endpoint_type='publicURL') |
| 146 | return glanceclient.Client('1', endpoint=endpoint, token=token) |
Maru Newby | dec13ec | 2012-08-30 11:19:17 -0700 | [diff] [blame] | 147 | |
Maru Newby | 81f07a0 | 2012-09-05 20:21:19 -0700 | [diff] [blame] | 148 | def _get_identity_client(self, username=None, password=None, |
| 149 | tenant_name=None): |
Maru Newby | dec13ec | 2012-08-30 11:19:17 -0700 | [diff] [blame] | 150 | # This identity client is not intended to check the security |
Maru Newby | 81f07a0 | 2012-09-05 20:21:19 -0700 | [diff] [blame] | 151 | # of the identity service, so use admin credentials by default. |
| 152 | if not username: |
| 153 | username = self.config.identity_admin.username |
| 154 | if not password: |
| 155 | password = self.config.identity_admin.password |
| 156 | if not tenant_name: |
| 157 | tenant_name = self.config.identity_admin.tenant_name |
Maru Newby | dec13ec | 2012-08-30 11:19:17 -0700 | [diff] [blame] | 158 | |
| 159 | if None in (username, password, tenant_name): |
| 160 | msg = ("Missing required credentials for identity client. " |
| 161 | "username: %(username)s, password: %(password)s, " |
| 162 | "tenant_name: %(tenant_name)s") % locals() |
| 163 | raise exceptions.InvalidConfiguration(msg) |
| 164 | |
| 165 | auth_url = self.config.identity.auth_url.rstrip('tokens') |
| 166 | |
| 167 | return keystoneclient.v2_0.client.Client(username=username, |
| 168 | password=password, |
| 169 | tenant_name=tenant_name, |
David Kranz | 21d95da | 2012-09-28 11:47:53 -0400 | [diff] [blame] | 170 | auth_url=auth_url) |
Maru Newby | dec13ec | 2012-08-30 11:19:17 -0700 | [diff] [blame] | 171 | |
| 172 | def _get_network_client(self): |
Maru Newby | b72f37c | 2012-12-14 02:17:06 +0000 | [diff] [blame] | 173 | # The intended configuration is for the network client to have |
| 174 | # admin privileges and indicate for whom resources are being |
| 175 | # created via a 'tenant_id' parameter. This will often be |
| 176 | # preferable to authenticating as a specific user because |
| 177 | # working with certain resources (public routers and networks) |
| 178 | # often requires admin privileges anyway. |
| 179 | username = self.config.network_admin.username |
| 180 | password = self.config.network_admin.password |
| 181 | tenant_name = self.config.network_admin.tenant_name |
Maru Newby | dec13ec | 2012-08-30 11:19:17 -0700 | [diff] [blame] | 182 | |
| 183 | if None in (username, password, tenant_name): |
| 184 | msg = ("Missing required credentials for network client. " |
| 185 | "username: %(username)s, password: %(password)s, " |
| 186 | "tenant_name: %(tenant_name)s") % locals() |
| 187 | raise exceptions.InvalidConfiguration(msg) |
| 188 | |
| 189 | auth_url = self.config.identity.auth_url.rstrip('tokens') |
| 190 | |
| 191 | return quantumclient.v2_0.client.Client(username=username, |
| 192 | password=password, |
| 193 | tenant_name=tenant_name, |
| 194 | auth_url=auth_url) |
Jay Pipes | 051075a | 2012-04-28 17:39:37 -0400 | [diff] [blame] | 195 | |
| 196 | |
| 197 | class ComputeFuzzClientManager(FuzzClientManager): |
| 198 | |
| 199 | """ |
| 200 | Manager that uses the Tempest REST client that can send |
| 201 | random or invalid data at the OpenStack Compute API |
| 202 | """ |
| 203 | |
| 204 | def __init__(self, username=None, password=None, tenant_name=None): |
| 205 | """ |
| 206 | We allow overriding of the credentials used within the various |
| 207 | client classes managed by the Manager object. Left as None, the |
| 208 | standard username/password/tenant_name is used. |
| 209 | |
| 210 | :param username: Override of the username |
| 211 | :param password: Override of the password |
| 212 | :param tenant_name: Override of the tenant name |
| 213 | """ |
| 214 | super(ComputeFuzzClientManager, self).__init__() |
| 215 | |
| 216 | # If no creds are provided, we fall back on the defaults |
| 217 | # in the config file for the Compute API. |
| 218 | username = username or self.config.compute.username |
| 219 | password = password or self.config.compute.password |
| 220 | tenant_name = tenant_name or self.config.compute.tenant_name |
| 221 | |
| 222 | if None in (username, password, tenant_name): |
| 223 | msg = ("Missing required credentials. " |
| 224 | "username: %(username)s, password: %(password)s, " |
| 225 | "tenant_name: %(tenant_name)s") % locals() |
| 226 | raise exceptions.InvalidConfiguration(msg) |
| 227 | |
| 228 | auth_url = self.config.identity.auth_url |
| 229 | |
| 230 | if self.config.identity.strategy == 'keystone': |
| 231 | client_args = (self.config, username, password, auth_url, |
| 232 | tenant_name) |
| 233 | else: |
| 234 | client_args = (self.config, username, password, auth_url) |
| 235 | |
| 236 | self.servers_client = ServersClient(*client_args) |
| 237 | self.flavors_client = FlavorsClient(*client_args) |
| 238 | self.images_client = ImagesClient(*client_args) |
| 239 | self.limits_client = LimitsClient(*client_args) |
| 240 | self.extensions_client = ExtensionsClient(*client_args) |
| 241 | self.keypairs_client = KeyPairsClient(*client_args) |
| 242 | self.security_groups_client = SecurityGroupsClient(*client_args) |
| 243 | self.floating_ips_client = FloatingIPsClient(*client_args) |
Rohit Karajgi | dd47d7e | 2012-07-31 04:11:01 -0700 | [diff] [blame] | 244 | self.volumes_extensions_client = VolumesExtensionsClient(*client_args) |
Jay Pipes | 051075a | 2012-04-28 17:39:37 -0400 | [diff] [blame] | 245 | self.volumes_client = VolumesClient(*client_args) |
| 246 | self.console_outputs_client = ConsoleOutputsClient(*client_args) |
Rohit Karajgi | 07599c5 | 2012-11-02 05:35:16 -0700 | [diff] [blame] | 247 | self.quotas_client = QuotasClient(*client_args) |
Jay Pipes | 051075a | 2012-04-28 17:39:37 -0400 | [diff] [blame] | 248 | self.network_client = NetworkClient(*client_args) |
| 249 | |
| 250 | |
| 251 | class ComputeFuzzClientAltManager(Manager): |
| 252 | |
| 253 | """ |
| 254 | Manager object that uses the alt_XXX credentials for its |
| 255 | managed client objects |
| 256 | """ |
| 257 | |
| 258 | def __init__(self): |
| 259 | conf = tempest.config.TempestConfig() |
| 260 | super(ComputeFuzzClientAltManager, self).__init__( |
rajalakshmi-ganesan | d793d69 | 2012-12-25 12:54:50 +0530 | [diff] [blame] | 261 | conf.compute.alt_username, |
| 262 | conf.compute.alt_password, |
| 263 | conf.compute.alt_tenant_name) |
Jay Pipes | 051075a | 2012-04-28 17:39:37 -0400 | [diff] [blame] | 264 | |
| 265 | |
| 266 | class ComputeFuzzClientAdminManager(Manager): |
| 267 | |
| 268 | """ |
| 269 | Manager object that uses the alt_XXX credentials for its |
| 270 | managed client objects |
| 271 | """ |
| 272 | |
| 273 | def __init__(self): |
| 274 | conf = tempest.config.TempestConfig() |
| 275 | super(ComputeFuzzClientAdminManager, self).__init__( |
rajalakshmi-ganesan | d793d69 | 2012-12-25 12:54:50 +0530 | [diff] [blame] | 276 | conf.compute_admin.username, |
| 277 | conf.compute_admin.password, |
| 278 | conf.compute_admin.tenant_name) |