nithya-ganesan | 222efd7 | 2015-01-22 12:20:27 +0000 | [diff] [blame] | 1 | # Copyright (c) 2015 Hewlett-Packard Development Company, L.P. |
Andrea Frittoli | b4ec494 | 2017-09-01 18:29:45 +0100 | [diff] [blame] | 2 | # Copyright (c) 2017 IBM Corp. |
nithya-ganesan | 222efd7 | 2015-01-22 12:20:27 +0000 | [diff] [blame] | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | # you may not use this file except in compliance with the License. |
| 5 | # You may obtain a copy of the License at |
| 6 | # |
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | # |
| 9 | # Unless required by applicable law or agreed to in writing, software |
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | # See the License for the specific language governing permissions and |
| 13 | # limitations under the License. |
| 14 | |
Andrea Frittoli | 9806f2d | 2017-09-01 14:50:07 +0100 | [diff] [blame] | 15 | import fixtures |
nithya-ganesan | 222efd7 | 2015-01-22 12:20:27 +0000 | [diff] [blame] | 16 | from oslo_log import log as logging |
Andrea Frittoli | b4ec494 | 2017-09-01 18:29:45 +0100 | [diff] [blame] | 17 | from oslo_utils import excutils |
nithya-ganesan | 222efd7 | 2015-01-22 12:20:27 +0000 | [diff] [blame] | 18 | |
Ken'ichi Ohmichi | ef1c1ce | 2017-03-10 11:07:10 -0800 | [diff] [blame] | 19 | from tempest.lib.common.utils import data_utils |
Andrea Frittoli (andreaf) | db9672e | 2016-02-23 14:07:24 -0500 | [diff] [blame] | 20 | from tempest.lib import exceptions as lib_exc |
Andrea Frittoli (andreaf) | 8def7ca | 2015-05-13 14:24:19 +0100 | [diff] [blame] | 21 | |
nithya-ganesan | 222efd7 | 2015-01-22 12:20:27 +0000 | [diff] [blame] | 22 | LOG = logging.getLogger(__name__) |
| 23 | |
| 24 | |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 25 | def _network_service(clients, use_neutron): |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 26 | # Internal helper to select the right network clients |
Andrea Frittoli | 463a8a6 | 2017-08-09 16:55:33 +0100 | [diff] [blame] | 27 | if use_neutron: |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 28 | return clients.network |
Andrea Frittoli | 463a8a6 | 2017-08-09 16:55:33 +0100 | [diff] [blame] | 29 | else: |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 30 | return clients.compute |
Matthew Treinish | 861619c | 2016-06-16 17:11:49 -0400 | [diff] [blame] | 31 | |
| 32 | |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 33 | def create_ssh_security_group(clients, add_rule=False, ethertype='IPv4', |
Andrea Frittoli | 1fa7a60 | 2017-08-09 16:28:55 +0100 | [diff] [blame] | 34 | use_neutron=True): |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 35 | """Create a security group for ping/ssh testing |
| 36 | |
| 37 | Create a security group to be attached to a VM using the nova or neutron |
| 38 | clients. If rules are added, the group can be attached to a VM to enable |
| 39 | connectivity validation over ICMP and further testing over SSH. |
| 40 | |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 41 | :param clients: Instance of `tempest.lib.services.clients.ServiceClients` |
| 42 | or of a subclass of it. Resources are provisioned using clients from |
| 43 | `clients`. |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 44 | :param add_rule: Whether security group rules are provisioned or not. |
| 45 | Defaults to `False`. |
| 46 | :param ethertype: 'IPv4' or 'IPv6'. Honoured only in case neutron is used. |
| 47 | :param use_neutron: When True resources are provisioned via neutron, when |
| 48 | False resources are provisioned via nova. |
| 49 | :returns: A dictionary with the security group as returned by the API. |
| 50 | |
| 51 | Examples:: |
| 52 | |
| 53 | from tempest.common import validation_resources as vr |
| 54 | from tempest.lib import auth |
| 55 | from tempest.lib.services import clients |
| 56 | |
| 57 | creds = auth.get_credentials('http://mycloud/identity/v3', |
| 58 | username='me', project_name='me', |
| 59 | password='secret', domain_name='Default') |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 60 | osclients = clients.ServiceClients(creds, 'http://mycloud/identity/v3') |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 61 | # Security group for IPv4 tests |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 62 | sg4 = vr.create_ssh_security_group(osclients, add_rule=True) |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 63 | # Security group for IPv6 tests |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 64 | sg6 = vr.create_ssh_security_group(osclients, ethertype='IPv6', |
| 65 | add_rule=True) |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 66 | """ |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 67 | network_service = _network_service(clients, use_neutron) |
Andrea Frittoli | 463a8a6 | 2017-08-09 16:55:33 +0100 | [diff] [blame] | 68 | security_groups_client = network_service.SecurityGroupsClient() |
| 69 | security_group_rules_client = network_service.SecurityGroupRulesClient() |
| 70 | # Security Group clients for nova and neutron behave the same |
nithya-ganesan | 222efd7 | 2015-01-22 12:20:27 +0000 | [diff] [blame] | 71 | sg_name = data_utils.rand_name('securitygroup-') |
| 72 | sg_description = data_utils.rand_name('description-') |
Yaroslav Lobankov | e5cc9fb | 2015-08-07 17:30:51 +0300 | [diff] [blame] | 73 | security_group = security_groups_client.create_security_group( |
ghanshyam | b610b77 | 2015-08-24 17:29:38 +0900 | [diff] [blame] | 74 | name=sg_name, description=sg_description)['security_group'] |
Andrea Frittoli | 463a8a6 | 2017-08-09 16:55:33 +0100 | [diff] [blame] | 75 | # Security Group Rules clients require different parameters depending on |
| 76 | # the network service in use |
nithya-ganesan | 222efd7 | 2015-01-22 12:20:27 +0000 | [diff] [blame] | 77 | if add_rule: |
Andrea Frittoli | b4ec494 | 2017-09-01 18:29:45 +0100 | [diff] [blame] | 78 | try: |
| 79 | if use_neutron: |
| 80 | security_group_rules_client.create_security_group_rule( |
| 81 | security_group_id=security_group['id'], |
| 82 | protocol='tcp', |
| 83 | ethertype=ethertype, |
| 84 | port_range_min=22, |
| 85 | port_range_max=22, |
| 86 | direction='ingress') |
| 87 | security_group_rules_client.create_security_group_rule( |
| 88 | security_group_id=security_group['id'], |
| 89 | protocol='icmp', |
| 90 | ethertype=ethertype, |
| 91 | direction='ingress') |
| 92 | else: |
| 93 | security_group_rules_client.create_security_group_rule( |
| 94 | parent_group_id=security_group['id'], ip_protocol='tcp', |
| 95 | from_port=22, to_port=22) |
| 96 | security_group_rules_client.create_security_group_rule( |
| 97 | parent_group_id=security_group['id'], ip_protocol='icmp', |
| 98 | from_port=-1, to_port=-1) |
| 99 | except Exception as sgc_exc: |
| 100 | # If adding security group rules fails, we cleanup the SG before |
| 101 | # re-raising the failure up |
| 102 | with excutils.save_and_reraise_exception(): |
| 103 | try: |
| 104 | msg = ('Error while provisioning security group rules in ' |
| 105 | 'security group %s. Trying to cleanup.') |
| 106 | # The exceptions logging is already handled, so using |
| 107 | # debug here just to provide more context |
| 108 | LOG.debug(msg, sgc_exc) |
| 109 | clear_validation_resources( |
| 110 | clients, keypair=None, floating_ip=None, |
| 111 | security_group=security_group, |
| 112 | use_neutron=use_neutron) |
| 113 | except Exception as cleanup_exc: |
| 114 | msg = ('Error during cleanup of a security group. ' |
| 115 | 'The cleanup was triggered by an exception during ' |
| 116 | 'the provisioning of security group rules.\n' |
| 117 | 'Provisioning exception: %s\n' |
| 118 | 'First cleanup exception: %s') |
| 119 | LOG.exception(msg, sgc_exc, cleanup_exc) |
nithya-ganesan | 222efd7 | 2015-01-22 12:20:27 +0000 | [diff] [blame] | 120 | LOG.debug("SSH Validation resource security group with tcp and icmp " |
Jordan Pittier | 525ec71 | 2016-12-07 17:51:26 +0100 | [diff] [blame] | 121 | "rules %s created", sg_name) |
nithya-ganesan | 222efd7 | 2015-01-22 12:20:27 +0000 | [diff] [blame] | 122 | return security_group |
| 123 | |
| 124 | |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 125 | def create_validation_resources(clients, keypair=False, floating_ip=False, |
| 126 | security_group=False, |
| 127 | security_group_rules=False, |
Andrea Frittoli | 1fa7a60 | 2017-08-09 16:28:55 +0100 | [diff] [blame] | 128 | ethertype='IPv4', use_neutron=True, |
| 129 | floating_network_id=None, |
| 130 | floating_network_name=None): |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 131 | """Provision resources for VM ping/ssh testing |
| 132 | |
| 133 | Create resources required to be able to ping / ssh a virtual machine: |
| 134 | keypair, security group, security group rules and a floating IP. |
| 135 | Which of those resources are required may depend on the cloud setup and on |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 136 | the specific test and it can be controlled via the corresponding |
| 137 | arguments. |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 138 | |
| 139 | Provisioned resources are returned in a dictionary. |
| 140 | |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 141 | :param clients: Instance of `tempest.lib.services.clients.ServiceClients` |
| 142 | or of a subclass of it. Resources are provisioned using clients from |
| 143 | `clients`. |
| 144 | :param keypair: Whether to provision a keypair. Defaults to False. |
| 145 | :param floating_ip: Whether to provision a floating IP. Defaults to False. |
| 146 | :param security_group: Whether to provision a security group. Defaults to |
| 147 | False. |
| 148 | :param security_group_rules: Whether to provision security group rules. |
| 149 | Defaults to False. |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 150 | :param ethertype: 'IPv4' or 'IPv6'. Honoured only in case neutron is used. |
| 151 | :param use_neutron: When True resources are provisioned via neutron, when |
| 152 | False resources are provisioned via nova. |
| 153 | :param floating_network_id: The id of the network used to provision a |
| 154 | floating IP. Only used if a floating IP is requested and with neutron. |
| 155 | :param floating_network_name: The name of the floating IP pool used to |
| 156 | provision the floating IP. Only used if a floating IP is requested and |
| 157 | with nova-net. |
Andrea Frittoli | b4ec494 | 2017-09-01 18:29:45 +0100 | [diff] [blame] | 158 | :returns: A dictionary with the resources in the format they are returned |
| 159 | by the API. Valid keys are 'keypair', 'floating_ip' and |
| 160 | 'security_group'. |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 161 | |
| 162 | Examples:: |
| 163 | |
| 164 | from tempest.common import validation_resources as vr |
| 165 | from tempest.lib import auth |
| 166 | from tempest.lib.services import clients |
| 167 | |
| 168 | creds = auth.get_credentials('http://mycloud/identity/v3', |
| 169 | username='me', project_name='me', |
| 170 | password='secret', domain_name='Default') |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 171 | osclients = clients.ServiceClients(creds, 'http://mycloud/identity/v3') |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 172 | # Request keypair and floating IP |
| 173 | resources = dict(keypair=True, security_group=False, |
| 174 | security_group_rules=False, floating_ip=True) |
| 175 | resources = vr.create_validation_resources( |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 176 | osclients, use_neutron=True, |
| 177 | floating_network_id='4240E68E-23DA-4C82-AC34-9FEFAA24521C', |
| 178 | **resources) |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 179 | |
| 180 | # The floating IP to be attached to the VM |
| 181 | floating_ip = resources['floating_ip']['ip'] |
| 182 | """ |
nithya-ganesan | 222efd7 | 2015-01-22 12:20:27 +0000 | [diff] [blame] | 183 | # Create and Return the validation resources required to validate a VM |
Andrea Frittoli | 9f416dd | 2017-08-10 15:38:00 +0100 | [diff] [blame] | 184 | msg = ('Requested validation resources keypair %s, floating IP %s, ' |
| 185 | 'security group %s') |
| 186 | LOG.debug(msg, keypair, floating_ip, security_group) |
nithya-ganesan | 222efd7 | 2015-01-22 12:20:27 +0000 | [diff] [blame] | 187 | validation_data = {} |
Andrea Frittoli | b4ec494 | 2017-09-01 18:29:45 +0100 | [diff] [blame] | 188 | try: |
| 189 | if keypair: |
| 190 | keypair_name = data_utils.rand_name('keypair') |
| 191 | validation_data.update( |
| 192 | clients.compute.KeyPairsClient().create_keypair( |
| 193 | name=keypair_name)) |
| 194 | LOG.debug("Validation resource key %s created", keypair_name) |
| 195 | if security_group: |
| 196 | validation_data['security_group'] = create_ssh_security_group( |
| 197 | clients, add_rule=security_group_rules, |
| 198 | use_neutron=use_neutron, ethertype=ethertype) |
| 199 | if floating_ip: |
| 200 | floating_ip_client = _network_service( |
| 201 | clients, use_neutron).FloatingIPsClient() |
| 202 | if use_neutron: |
| 203 | floatingip = floating_ip_client.create_floatingip( |
| 204 | floating_network_id=floating_network_id) |
| 205 | # validation_resources['floating_ip'] has historically looked |
| 206 | # like a compute API POST /os-floating-ips response, so we need |
| 207 | # to mangle it a bit for a Neutron response with different |
| 208 | # fields. |
| 209 | validation_data['floating_ip'] = floatingip['floatingip'] |
| 210 | validation_data['floating_ip']['ip'] = ( |
| 211 | floatingip['floatingip']['floating_ip_address']) |
| 212 | else: |
| 213 | # NOTE(mriedem): The os-floating-ips compute API was deprecated |
| 214 | # in the 2.36 microversion. Any tests for CRUD operations on |
| 215 | # floating IPs using the compute API should be capped at 2.35. |
| 216 | validation_data.update(floating_ip_client.create_floating_ip( |
| 217 | pool=floating_network_name)) |
| 218 | LOG.debug("Validation resource floating IP %s created", |
| 219 | validation_data['floating_ip']) |
| 220 | except Exception as prov_exc: |
| 221 | # If something goes wrong, cleanup as much as possible before we |
| 222 | # re-raise the exception |
| 223 | with excutils.save_and_reraise_exception(): |
| 224 | if validation_data: |
| 225 | # Cleanup may fail as well |
| 226 | try: |
| 227 | msg = ('Error while provisioning validation resources %s. ' |
| 228 | 'Trying to cleanup what we provisioned so far: %s') |
| 229 | # The exceptions logging is already handled, so using |
| 230 | # debug here just to provide more context |
| 231 | LOG.debug(msg, prov_exc, str(validation_data)) |
| 232 | clear_validation_resources( |
| 233 | clients, |
| 234 | keypair=validation_data.get('keypair', None), |
| 235 | floating_ip=validation_data.get('floating_ip', None), |
| 236 | security_group=validation_data.get('security_group', |
| 237 | None), |
| 238 | use_neutron=use_neutron) |
| 239 | except Exception as cleanup_exc: |
| 240 | msg = ('Error during cleanup of validation resources. ' |
| 241 | 'The cleanup was triggered by an exception during ' |
| 242 | 'the provisioning step.\n' |
| 243 | 'Provisioning exception: %s\n' |
| 244 | 'First cleanup exception: %s') |
| 245 | LOG.exception(msg, prov_exc, cleanup_exc) |
nithya-ganesan | 222efd7 | 2015-01-22 12:20:27 +0000 | [diff] [blame] | 246 | return validation_data |
| 247 | |
| 248 | |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 249 | def clear_validation_resources(clients, keypair=None, floating_ip=None, |
| 250 | security_group=None, use_neutron=True): |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 251 | """Cleanup resources for VM ping/ssh testing |
| 252 | |
| 253 | Cleanup a set of resources provisioned via `create_validation_resources`. |
| 254 | In case of errors during cleanup, the exception is logged and the cleanup |
| 255 | process is continued. The first exception that was raised is re-raised |
| 256 | after the cleanup is complete. |
| 257 | |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 258 | :param clients: Instance of `tempest.lib.services.clients.ServiceClients` |
| 259 | or of a subclass of it. Resources are provisioned using clients from |
| 260 | `clients`. |
| 261 | :param keypair: A dictionary with the keypair to be deleted. Defaults to |
| 262 | None. |
| 263 | :param floating_ip: A dictionary with the floating_ip to be deleted. |
| 264 | Defaults to None. |
| 265 | :param security_group: A dictionary with the security_group to be deleted. |
| 266 | Defaults to None. |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 267 | :param use_neutron: When True resources are provisioned via neutron, when |
| 268 | False resources are provisioned via nova. |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 269 | |
| 270 | Examples:: |
| 271 | |
| 272 | from tempest.common import validation_resources as vr |
| 273 | from tempest.lib import auth |
| 274 | from tempest.lib.services import clients |
| 275 | |
| 276 | creds = auth.get_credentials('http://mycloud/identity/v3', |
| 277 | username='me', project_name='me', |
| 278 | password='secret', domain_name='Default') |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 279 | osclients = clients.ServiceClients(creds, 'http://mycloud/identity/v3') |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 280 | # Request keypair and floating IP |
| 281 | resources = dict(keypair=True, security_group=False, |
| 282 | security_group_rules=False, floating_ip=True) |
| 283 | resources = vr.create_validation_resources( |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 284 | osclients, validation_resources=resources, use_neutron=True, |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 285 | floating_network_id='4240E68E-23DA-4C82-AC34-9FEFAA24521C') |
| 286 | |
| 287 | # Now cleanup the resources |
| 288 | try: |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 289 | vr.clear_validation_resources(osclients, use_neutron=True, |
| 290 | **resources) |
Andrea Frittoli | 557320e | 2017-08-09 21:08:08 +0100 | [diff] [blame] | 291 | except Exception as e: |
| 292 | LOG.exception('Something went wrong during cleanup, ignoring') |
| 293 | """ |
nithya-ganesan | 222efd7 | 2015-01-22 12:20:27 +0000 | [diff] [blame] | 294 | has_exception = None |
Andrea Frittoli | 8871fca | 2017-08-10 23:43:25 +0100 | [diff] [blame] | 295 | if keypair: |
| 296 | keypair_client = clients.compute.KeyPairsClient() |
| 297 | keypair_name = keypair['name'] |
| 298 | try: |
| 299 | keypair_client.delete_keypair(keypair_name) |
| 300 | except lib_exc.NotFound: |
| 301 | LOG.warning( |
| 302 | "Keypair %s is not found when attempting to delete", |
| 303 | keypair_name |
| 304 | ) |
| 305 | except Exception as exc: |
| 306 | LOG.exception('Exception raised while deleting key %s', |
| 307 | keypair_name) |
| 308 | if not has_exception: |
| 309 | has_exception = exc |
| 310 | network_service = _network_service(clients, use_neutron) |
| 311 | if security_group: |
| 312 | security_group_client = network_service.SecurityGroupsClient() |
| 313 | sec_id = security_group['id'] |
| 314 | try: |
| 315 | security_group_client.delete_security_group(sec_id) |
| 316 | security_group_client.wait_for_resource_deletion(sec_id) |
| 317 | except lib_exc.NotFound: |
| 318 | LOG.warning("Security group %s is not found when attempting " |
| 319 | "to delete", sec_id) |
| 320 | except lib_exc.Conflict as exc: |
| 321 | LOG.exception('Conflict while deleting security ' |
| 322 | 'group %s VM might not be deleted', sec_id) |
| 323 | if not has_exception: |
| 324 | has_exception = exc |
| 325 | except Exception as exc: |
| 326 | LOG.exception('Exception raised while deleting security ' |
| 327 | 'group %s', sec_id) |
| 328 | if not has_exception: |
| 329 | has_exception = exc |
| 330 | if floating_ip: |
| 331 | floating_ip_client = network_service.FloatingIPsClient() |
| 332 | fip_id = floating_ip['id'] |
| 333 | try: |
| 334 | if use_neutron: |
| 335 | floating_ip_client.delete_floatingip(fip_id) |
| 336 | else: |
| 337 | floating_ip_client.delete_floating_ip(fip_id) |
| 338 | except lib_exc.NotFound: |
| 339 | LOG.warning('Floating ip %s not found while attempting to ' |
| 340 | 'delete', fip_id) |
| 341 | except Exception as exc: |
| 342 | LOG.exception('Exception raised while deleting ip %s', fip_id) |
| 343 | if not has_exception: |
| 344 | has_exception = exc |
nithya-ganesan | 222efd7 | 2015-01-22 12:20:27 +0000 | [diff] [blame] | 345 | if has_exception: |
| 346 | raise has_exception |
Andrea Frittoli | 9806f2d | 2017-09-01 14:50:07 +0100 | [diff] [blame] | 347 | |
| 348 | |
| 349 | class ValidationResourcesFixture(fixtures.Fixture): |
| 350 | """Fixture to provision and cleanup validation resources""" |
| 351 | |
| 352 | DICT_KEYS = ['keypair', 'security_group', 'floating_ip'] |
| 353 | |
| 354 | def __init__(self, clients, keypair=False, floating_ip=False, |
| 355 | security_group=False, security_group_rules=False, |
| 356 | ethertype='IPv4', use_neutron=True, floating_network_id=None, |
| 357 | floating_network_name=None): |
| 358 | """Create a ValidationResourcesFixture |
| 359 | |
| 360 | Create a ValidationResourcesFixture fixtures, which provisions the |
| 361 | resources required to be able to ping / ssh a virtual machine upon |
| 362 | setUp and clears them out upon cleanup. Resources are keypair, |
| 363 | security group, security group rules and a floating IP - depending |
| 364 | on the params. |
| 365 | |
| 366 | The fixture exposes a dictionary that includes provisioned resources. |
| 367 | |
| 368 | :param clients: `tempest.lib.services.clients.ServiceClients` or of a |
| 369 | subclass of it. Resources are provisioned using clients from |
| 370 | `clients`. |
| 371 | :param keypair: Whether to provision a keypair. Defaults to False. |
| 372 | :param floating_ip: Whether to provision a floating IP. |
| 373 | Defaults to False. |
| 374 | :param security_group: Whether to provision a security group. |
| 375 | Defaults to False. |
| 376 | :param security_group_rules: Whether to provision security group rules. |
| 377 | Defaults to False. |
| 378 | :param ethertype: 'IPv4' or 'IPv6'. Honoured only if neutron is used. |
| 379 | :param use_neutron: When True resources are provisioned via neutron, |
| 380 | when False resources are provisioned via nova. |
| 381 | :param floating_network_id: The id of the network used to provision a |
| 382 | floating IP. Only used if a floating IP is requested in case |
| 383 | neutron is used. |
| 384 | :param floating_network_name: The name of the floating IP pool used to |
| 385 | provision the floating IP. Only used if a floating IP is requested |
| 386 | and with nova-net. |
| 387 | :returns: A dictionary with the same keys as the input |
| 388 | `validation_resources` and the resources for values in the format |
| 389 | they are returned by the API. |
| 390 | |
| 391 | Examples:: |
| 392 | |
| 393 | from tempest.common import validation_resources as vr |
| 394 | from tempest.lib import auth |
| 395 | from tempest.lib.services import clients |
| 396 | import testtools |
| 397 | |
| 398 | |
| 399 | class TestWithVR(testtools.TestCase): |
| 400 | |
| 401 | def setUp(self): |
| 402 | creds = auth.get_credentials( |
| 403 | 'http://mycloud/identity/v3', |
| 404 | username='me', project_name='me', |
| 405 | password='secret', domain_name='Default') |
| 406 | |
| 407 | osclients = clients.ServiceClients( |
| 408 | creds, 'http://mycloud/identity/v3') |
| 409 | # Request keypair and floating IP |
| 410 | resources = dict(keypair=True, security_group=False, |
| 411 | security_group_rules=False, |
| 412 | floating_ip=True) |
| 413 | network_id = '4240E68E-23DA-4C82-AC34-9FEFAA24521C' |
| 414 | self.vr = self.useFixture(vr.ValidationResourcesFixture( |
| 415 | osclients, use_neutron=True, |
| 416 | floating_network_id=network_id, |
| 417 | **resources) |
| 418 | |
| 419 | def test_use_ip(self): |
| 420 | # The floating IP to be attached to the VM |
| 421 | floating_ip = self.vr['floating_ip']['ip'] |
| 422 | """ |
| 423 | self._clients = clients |
| 424 | self._keypair = keypair |
| 425 | self._floating_ip = floating_ip |
| 426 | self._security_group = security_group |
| 427 | self._security_group_rules = security_group_rules |
| 428 | self._ethertype = ethertype |
| 429 | self._use_neutron = use_neutron |
| 430 | self._floating_network_id = floating_network_id |
| 431 | self._floating_network_name = floating_network_name |
| 432 | self._validation_resources = None |
| 433 | |
| 434 | def _setUp(self): |
Andrea Frittoli | 9f416dd | 2017-08-10 15:38:00 +0100 | [diff] [blame] | 435 | msg = ('Requested setup of ValidationResources keypair %s, floating ' |
| 436 | 'IP %s, security group %s') |
| 437 | LOG.debug(msg, self._keypair, self._floating_ip, self._security_group) |
Andrea Frittoli | 9806f2d | 2017-09-01 14:50:07 +0100 | [diff] [blame] | 438 | self._validation_resources = create_validation_resources( |
| 439 | self._clients, keypair=self._keypair, |
| 440 | floating_ip=self._floating_ip, |
| 441 | security_group=self._security_group, |
| 442 | security_group_rules=self._security_group_rules, |
| 443 | ethertype=self._ethertype, use_neutron=self._use_neutron, |
| 444 | floating_network_id=self._floating_network_id, |
| 445 | floating_network_name=self._floating_network_name) |
| 446 | # If provisioning raises an exception we won't have anything to |
| 447 | # cleanup here, so we don't need a try-finally around provisioning |
| 448 | vr = self._validation_resources |
| 449 | self.addCleanup(clear_validation_resources, self._clients, |
Andrea Frittoli | 9f416dd | 2017-08-10 15:38:00 +0100 | [diff] [blame] | 450 | keypair=vr.get('keypair', None), |
| 451 | floating_ip=vr.get('floating_ip', None), |
| 452 | security_group=vr.get('security_group', None), |
Andrea Frittoli | 9806f2d | 2017-09-01 14:50:07 +0100 | [diff] [blame] | 453 | use_neutron=self._use_neutron) |
| 454 | |
| 455 | @property |
| 456 | def resources(self): |
| 457 | return self._validation_resources |