blob: b998b9bc34fcd88e925be423841f9d25b7ee6e65 [file] [log] [blame]
Jude Cross986e3f52017-07-24 14:57:20 -07001# Copyright 2018 Rackspace US Inc. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# 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, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15import ipaddress
Michael Johnsonbaf12e02020-10-27 16:10:28 -070016import os
Jude Cross986e3f52017-07-24 14:57:20 -070017import random
Gregory Thiemongea2c234e2021-11-02 17:08:29 +010018import re
Jude Cross986e3f52017-07-24 14:57:20 -070019import shlex
Jude Cross986e3f52017-07-24 14:57:20 -070020import string
21import subprocess
22import tempfile
23
Michael Johnsonbaf12e02020-10-27 16:10:28 -070024from cryptography.hazmat.primitives import serialization
Gregory Thiemongeb0da4f32022-02-04 08:58:06 +010025from oslo_config import cfg
Jude Cross986e3f52017-07-24 14:57:20 -070026from oslo_log import log as logging
27from oslo_utils import uuidutils
28from tempest import config
29from tempest.lib.common.utils import data_utils
30from tempest.lib.common.utils.linux import remote_client
Jude Cross986e3f52017-07-24 14:57:20 -070031from tempest.lib import exceptions
32from tempest import test
Michael Johnson04dc5cb2019-01-20 11:03:50 -080033import tenacity
Jude Cross986e3f52017-07-24 14:57:20 -070034
Michael Johnsonbaf12e02020-10-27 16:10:28 -070035from octavia_tempest_plugin.common import cert_utils
Jude Cross986e3f52017-07-24 14:57:20 -070036from octavia_tempest_plugin.common import constants as const
Ilya Bumarskovcea9b6b2023-03-16 14:12:09 +040037from octavia_tempest_plugin import config as config_octavia
Michael Johnson6006de72021-02-21 01:42:39 +000038from octavia_tempest_plugin.tests import RBAC_tests
Jude Cross986e3f52017-07-24 14:57:20 -070039from octavia_tempest_plugin.tests import validators
40from octavia_tempest_plugin.tests import waiters
41
42CONF = config.CONF
43LOG = logging.getLogger(__name__)
44
Gregory Thiemonge29d17902019-04-30 15:06:17 +020045
Michael Johnson6006de72021-02-21 01:42:39 +000046class LoadBalancerBaseTest(validators.ValidatorsMixin,
47 RBAC_tests.RBACTestsMixin, test.BaseTestCase):
Jude Cross986e3f52017-07-24 14:57:20 -070048 """Base class for load balancer tests."""
49
Gregory Thiemonge3497f6c2021-04-19 21:33:13 +020050 if CONF.load_balancer.RBAC_test_type == const.OWNERADMIN:
51 credentials = [
52 'admin', 'primary', ['lb_admin', CONF.load_balancer.admin_role],
53 ['lb_member', CONF.load_balancer.member_role],
54 ['lb_member2', CONF.load_balancer.member_role]]
Michael Johnson6dac8ff2023-03-09 00:04:37 +000055 elif CONF.load_balancer.RBAC_test_type == const.KEYSTONE_DEFAULT_ROLES:
Michael Johnson6006de72021-02-21 01:42:39 +000056 credentials = [
Michael Johnson6dac8ff2023-03-09 00:04:37 +000057 'admin', 'primary',
58 ['lb_admin', CONF.load_balancer.admin_role, 'admin'],
Michael Johnson6006de72021-02-21 01:42:39 +000059 ['lb_observer', CONF.load_balancer.observer_role, 'reader'],
60 ['lb_global_observer', CONF.load_balancer.global_observer_role,
61 'reader'],
62 ['lb_member', CONF.load_balancer.member_role, 'member'],
63 ['lb_member2', CONF.load_balancer.member_role, 'member'],
64 ['lb_member_not_default_member', CONF.load_balancer.member_role]]
65 else:
66 credentials = [
67 'admin', 'primary', ['lb_admin', CONF.load_balancer.admin_role],
68 ['lb_observer', CONF.load_balancer.observer_role, 'reader'],
69 ['lb_global_observer', CONF.load_balancer.global_observer_role,
70 'reader'],
Michael Johnson9e9f5262023-01-18 17:59:17 +000071 # Note: Some projects are now requiring the 'member' role by
72 # default (nova for example) so make sure our creds have this role
73 ['lb_member', CONF.load_balancer.member_role, 'member'],
74 ['lb_member2', CONF.load_balancer.member_role, 'member']]
Michael Johnson6006de72021-02-21 01:42:39 +000075
76 # If scope enforcement is enabled, add in the system scope credentials.
77 # The project scope is already handled by the above credentials.
78 if CONF.enforce_scope.octavia:
79 credentials.extend(['system_admin', 'system_reader'])
80
81 # A tuple of credentials that will be allocated by tempest using the
82 # 'credentials' list above. These are used to build RBAC test lists.
83 allocated_creds = []
84 for cred in credentials:
85 if isinstance(cred, list):
86 allocated_creds.append('os_roles_' + cred[0])
87 else:
88 allocated_creds.append('os_' + cred)
89 # Tests shall not mess with the list of allocated credentials
90 allocated_credentials = tuple(allocated_creds)
Jude Cross986e3f52017-07-24 14:57:20 -070091
Adam Harwelle029af22018-05-24 17:13:28 -070092 webserver1_response = 1
93 webserver2_response = 5
Michael Johnsondfd818a2018-08-21 20:54:54 -070094 used_ips = []
Jude Cross986e3f52017-07-24 14:57:20 -070095
Michael Johnson89bdbcd2020-03-19 15:59:19 -070096 SRC_PORT_NUMBER_MIN = 32768
97 SRC_PORT_NUMBER_MAX = 61000
Gregory Thiemonge29d17902019-04-30 15:06:17 +020098 src_port_number = SRC_PORT_NUMBER_MIN
99
Jude Cross986e3f52017-07-24 14:57:20 -0700100 @classmethod
101 def skip_checks(cls):
102 """Check if we should skip all of the children tests."""
103 super(LoadBalancerBaseTest, cls).skip_checks()
104
105 service_list = {
106 'load_balancer': CONF.service_available.load_balancer,
107 }
108
109 live_service_list = {
110 'compute': CONF.service_available.nova,
111 'image': CONF.service_available.glance,
112 'neutron': CONF.service_available.neutron
113 }
114
115 if not CONF.load_balancer.test_with_noop:
116 service_list.update(live_service_list)
117
118 for service, available in service_list.items():
119 if not available:
zhangzs2a6cf672018-11-10 16:13:11 +0800120 skip_msg = ("{0} skipped as {1} service is not "
Jude Cross986e3f52017-07-24 14:57:20 -0700121 "available.".format(cls.__name__, service))
122 raise cls.skipException(skip_msg)
123
124 # We must be able to reach our VIP and instances
125 if not (CONF.network.project_networks_reachable
126 or CONF.network.public_network_id):
127 msg = ('Either project_networks_reachable must be "true", or '
128 'public_network_id must be defined.')
129 raise cls.skipException(msg)
130
131 @classmethod
132 def setup_credentials(cls):
133 """Setup test credentials and network resources."""
134 # Do not auto create network resources
135 cls.set_network_resources()
136 super(LoadBalancerBaseTest, cls).setup_credentials()
137
Bas de Bruijne530a88a2022-12-15 11:12:45 -0400138 if not CONF.load_balancer.log_user_roles:
139 return
140
Michael Johnson6006de72021-02-21 01:42:39 +0000141 # Log the user roles for this test run
142 role_name_cache = {}
143 for cred in cls.credentials:
144 user_roles = []
145 if isinstance(cred, list):
146 user_name = cred[0]
147 cred_obj = getattr(cls, 'os_roles_' + cred[0])
148 else:
149 user_name = cred
150 cred_obj = getattr(cls, 'os_' + cred)
151 params = {'user.id': cred_obj.credentials.user_id,
152 'project.id': cred_obj.credentials.project_id}
153 roles = cls.os_admin.role_assignments_client.list_role_assignments(
154 **params)['role_assignments']
155 for role in roles:
156 role_id = role['role']['id']
157 try:
158 role_name = role_name_cache[role_id]
159 except KeyError:
160 role_name = cls.os_admin.roles_v3_client.show_role(
161 role_id)['role']['name']
162 role_name_cache[role_id] = role_name
163 user_roles.append([role_name, role['scope']])
164 LOG.info("User %s has roles: %s", user_name, user_roles)
165
Jude Cross986e3f52017-07-24 14:57:20 -0700166 @classmethod
167 def setup_clients(cls):
168 """Setup client aliases."""
169 super(LoadBalancerBaseTest, cls).setup_clients()
Michael Johnson29d8e612021-06-23 16:16:12 +0000170 lb_admin_prefix = cls.os_roles_lb_admin.load_balancer_v2
Jude Cross986e3f52017-07-24 14:57:20 -0700171 cls.lb_mem_float_ip_client = cls.os_roles_lb_member.floating_ips_client
172 cls.lb_mem_keypairs_client = cls.os_roles_lb_member.keypairs_client
173 cls.lb_mem_net_client = cls.os_roles_lb_member.networks_client
174 cls.lb_mem_ports_client = cls.os_roles_lb_member.ports_client
175 cls.lb_mem_routers_client = cls.os_roles_lb_member.routers_client
176 cls.lb_mem_SG_client = cls.os_roles_lb_member.security_groups_client
177 cls.lb_mem_SGr_client = (
178 cls.os_roles_lb_member.security_group_rules_client)
179 cls.lb_mem_servers_client = cls.os_roles_lb_member.servers_client
180 cls.lb_mem_subnet_client = cls.os_roles_lb_member.subnets_client
Michael Johnson29d8e612021-06-23 16:16:12 +0000181 cls.mem_lb_client = (
182 cls.os_roles_lb_member.load_balancer_v2.LoadbalancerClient())
183 cls.mem_listener_client = (
184 cls.os_roles_lb_member.load_balancer_v2.ListenerClient())
185 cls.mem_pool_client = (
186 cls.os_roles_lb_member.load_balancer_v2.PoolClient())
187 cls.mem_member_client = (
188 cls.os_roles_lb_member.load_balancer_v2.MemberClient())
Adam Harwell60ed9d92018-05-10 13:23:13 -0700189 cls.mem_healthmonitor_client = (
Michael Johnson29d8e612021-06-23 16:16:12 +0000190 cls.os_roles_lb_member.load_balancer_v2.HealthMonitorClient())
191 cls.mem_l7policy_client = (
192 cls.os_roles_lb_member.load_balancer_v2.L7PolicyClient())
193 cls.mem_l7rule_client = (
194 cls.os_roles_lb_member.load_balancer_v2.L7RuleClient())
195 cls.lb_admin_amphora_client = lb_admin_prefix.AmphoraClient()
Michael Johnsonaff2e862019-01-11 16:38:00 -0800196 cls.lb_admin_flavor_profile_client = (
Michael Johnson29d8e612021-06-23 16:16:12 +0000197 lb_admin_prefix.FlavorProfileClient())
198 cls.lb_admin_flavor_client = lb_admin_prefix.FlavorClient()
199 cls.mem_flavor_client = (
200 cls.os_roles_lb_member.load_balancer_v2.FlavorClient())
201 cls.mem_provider_client = (
202 cls.os_roles_lb_member.load_balancer_v2.ProviderClient())
Carlos Goncalvesc2e12162019-02-14 23:57:44 +0100203 cls.os_admin_servers_client = cls.os_admin.servers_client
Gregory Thiemonge54225ad2021-02-04 15:25:17 +0100204 cls.os_admin_routers_client = cls.os_admin.routers_client
205 cls.os_admin_subnetpools_client = cls.os_admin.subnetpools_client
Adam Harwellc2aa20c2019-11-20 11:15:07 -0800206 cls.lb_admin_flavor_capabilities_client = (
Michael Johnson29d8e612021-06-23 16:16:12 +0000207 lb_admin_prefix.FlavorCapabilitiesClient())
Adam Harwellc2aa20c2019-11-20 11:15:07 -0800208 cls.lb_admin_availability_zone_capabilities_client = (
Michael Johnson29d8e612021-06-23 16:16:12 +0000209 lb_admin_prefix.AvailabilityZoneCapabilitiesClient())
Adam Harwellc2aa20c2019-11-20 11:15:07 -0800210 cls.lb_admin_availability_zone_profile_client = (
Michael Johnson29d8e612021-06-23 16:16:12 +0000211 lb_admin_prefix.AvailabilityZoneProfileClient())
Adam Harwellc2aa20c2019-11-20 11:15:07 -0800212 cls.lb_admin_availability_zone_client = (
Michael Johnson29d8e612021-06-23 16:16:12 +0000213 lb_admin_prefix.AvailabilityZoneClient())
Adam Harwellc2aa20c2019-11-20 11:15:07 -0800214 cls.mem_availability_zone_client = (
Michael Johnson29d8e612021-06-23 16:16:12 +0000215 cls.os_roles_lb_member.load_balancer_v2.AvailabilityZoneClient())
Jude Cross986e3f52017-07-24 14:57:20 -0700216
217 @classmethod
218 def resource_setup(cls):
219 """Setup resources needed by the tests."""
220 super(LoadBalancerBaseTest, cls).resource_setup()
221
222 conf_lb = CONF.load_balancer
223
Michael Johnsondfd818a2018-08-21 20:54:54 -0700224 cls.api_version = cls.mem_lb_client.get_max_api_version()
225
Jude Cross986e3f52017-07-24 14:57:20 -0700226 if conf_lb.test_subnet_override and not conf_lb.test_network_override:
227 raise exceptions.InvalidConfiguration(
228 "Configuration value test_network_override must be "
229 "specified if test_subnet_override is used.")
230
Michael Johnson6a9236a2020-08-04 23:54:54 +0000231 # TODO(johnsom) Remove this
Maciej Józefczykb6df5f82019-12-10 10:12:30 +0000232 # Get loadbalancing algorithms supported by provider driver.
233 try:
234 algorithms = const.SUPPORTED_LB_ALGORITHMS[
235 CONF.load_balancer.provider]
236 except KeyError:
237 algorithms = const.SUPPORTED_LB_ALGORITHMS['default']
238 # Set default algorithm as first from the list.
239 cls.lb_algorithm = algorithms[0]
240
Jude Cross986e3f52017-07-24 14:57:20 -0700241 show_subnet = cls.lb_mem_subnet_client.show_subnet
242 if CONF.load_balancer.test_with_noop:
243 cls.lb_member_vip_net = {'id': uuidutils.generate_uuid()}
244 cls.lb_member_vip_subnet = {'id': uuidutils.generate_uuid()}
245 cls.lb_member_1_net = {'id': uuidutils.generate_uuid()}
246 cls.lb_member_1_subnet = {'id': uuidutils.generate_uuid()}
247 cls.lb_member_2_net = {'id': uuidutils.generate_uuid()}
248 cls.lb_member_2_subnet = {'id': uuidutils.generate_uuid()}
249 if CONF.load_balancer.test_with_ipv6:
Michael Johnson5a16ad32018-10-18 14:49:11 -0700250 cls.lb_member_vip_ipv6_net = {'id': uuidutils.generate_uuid()}
Jude Cross986e3f52017-07-24 14:57:20 -0700251 cls.lb_member_vip_ipv6_subnet = {'id':
252 uuidutils.generate_uuid()}
253 cls.lb_member_1_ipv6_subnet = {'id': uuidutils.generate_uuid()}
254 cls.lb_member_2_ipv6_subnet = {'id': uuidutils.generate_uuid()}
Michael Johnson590fbe12019-07-03 14:30:01 -0700255 cls.lb_member_vip_ipv6_subnet_stateful = True
Jude Cross986e3f52017-07-24 14:57:20 -0700256 return
257 elif CONF.load_balancer.test_network_override:
258 if conf_lb.test_subnet_override:
259 override_subnet = show_subnet(conf_lb.test_subnet_override)
260 else:
261 override_subnet = None
262
263 show_net = cls.lb_mem_net_client.show_network
264 override_network = show_net(conf_lb.test_network_override)
265 override_network = override_network.get('network')
266
267 cls.lb_member_vip_net = override_network
268 cls.lb_member_vip_subnet = override_subnet
269 cls.lb_member_1_net = override_network
270 cls.lb_member_1_subnet = override_subnet
271 cls.lb_member_2_net = override_network
272 cls.lb_member_2_subnet = override_subnet
273
274 if (CONF.load_balancer.test_with_ipv6 and
Michael Polenchuk4beb66b2022-01-18 15:44:56 +0400275 conf_lb.test_ipv6_subnet_override):
Jude Cross986e3f52017-07-24 14:57:20 -0700276 override_ipv6_subnet = show_subnet(
Michael Polenchuk4beb66b2022-01-18 15:44:56 +0400277 conf_lb.test_ipv6_subnet_override)
Jude Cross986e3f52017-07-24 14:57:20 -0700278 cls.lb_member_vip_ipv6_subnet = override_ipv6_subnet
279 cls.lb_member_1_ipv6_subnet = override_ipv6_subnet
280 cls.lb_member_2_ipv6_subnet = override_ipv6_subnet
Michael Johnson590fbe12019-07-03 14:30:01 -0700281 cls.lb_member_vip_ipv6_subnet_stateful = False
282 if (override_ipv6_subnet[0]['ipv6_address_mode'] ==
283 'dhcpv6-stateful'):
284 cls.lb_member_vip_ipv6_subnet_stateful = True
Jude Cross986e3f52017-07-24 14:57:20 -0700285 else:
286 cls.lb_member_vip_ipv6_subnet = None
287 cls.lb_member_1_ipv6_subnet = None
288 cls.lb_member_2_ipv6_subnet = None
289 else:
290 cls._create_networks()
291
292 LOG.debug('Octavia Setup: lb_member_vip_net = {}'.format(
293 cls.lb_member_vip_net[const.ID]))
294 if cls.lb_member_vip_subnet:
295 LOG.debug('Octavia Setup: lb_member_vip_subnet = {}'.format(
296 cls.lb_member_vip_subnet[const.ID]))
297 LOG.debug('Octavia Setup: lb_member_1_net = {}'.format(
298 cls.lb_member_1_net[const.ID]))
299 if cls.lb_member_1_subnet:
300 LOG.debug('Octavia Setup: lb_member_1_subnet = {}'.format(
301 cls.lb_member_1_subnet[const.ID]))
302 LOG.debug('Octavia Setup: lb_member_2_net = {}'.format(
303 cls.lb_member_2_net[const.ID]))
304 if cls.lb_member_2_subnet:
305 LOG.debug('Octavia Setup: lb_member_2_subnet = {}'.format(
306 cls.lb_member_2_subnet[const.ID]))
Michael Johnson124ba8b2018-08-30 16:06:05 -0700307 if CONF.load_balancer.test_with_ipv6:
308 if cls.lb_member_vip_ipv6_subnet:
309 LOG.debug('Octavia Setup: lb_member_vip_ipv6_subnet = '
310 '{}'.format(cls.lb_member_vip_ipv6_subnet[const.ID]))
311 if cls.lb_member_1_ipv6_subnet:
312 LOG.debug('Octavia Setup: lb_member_1_ipv6_subnet = {}'.format(
313 cls.lb_member_1_ipv6_subnet[const.ID]))
314 if cls.lb_member_2_ipv6_subnet:
315 LOG.debug('Octavia Setup: lb_member_2_ipv6_subnet = {}'.format(
316 cls.lb_member_2_ipv6_subnet[const.ID]))
Jude Cross986e3f52017-07-24 14:57:20 -0700317
Jude Cross986e3f52017-07-24 14:57:20 -0700318 @classmethod
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800319 # Neutron can be slow to clean up ports from the subnets/networks.
320 # Retry this delete a few times if we get a "Conflict" error to give
321 # neutron time to fully cleanup the ports.
322 @tenacity.retry(
323 retry=tenacity.retry_if_exception_type(exceptions.Conflict),
324 wait=tenacity.wait_incrementing(
Vasyl Saienko0d5a4f42021-05-12 16:30:26 +0300325 const.RETRY_INITIAL_DELAY, const.RETRY_BACKOFF, const.RETRY_MAX),
326 stop=tenacity.stop_after_attempt(const.RETRY_ATTEMPTS))
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800327 def _logging_delete_network(cls, net_id):
328 try:
329 cls.lb_mem_net_client.delete_network(net_id)
330 except Exception:
331 LOG.error('Unable to delete network {}. Active ports:'.format(
332 net_id))
333 LOG.error(cls.lb_mem_ports_client.list_ports())
334 raise
335
336 @classmethod
337 # Neutron can be slow to clean up ports from the subnets/networks.
338 # Retry this delete a few times if we get a "Conflict" error to give
339 # neutron time to fully cleanup the ports.
340 @tenacity.retry(
341 retry=tenacity.retry_if_exception_type(exceptions.Conflict),
342 wait=tenacity.wait_incrementing(
Vasyl Saienko0d5a4f42021-05-12 16:30:26 +0300343 const.RETRY_INITIAL_DELAY, const.RETRY_BACKOFF, const.RETRY_MAX),
344 stop=tenacity.stop_after_attempt(const.RETRY_ATTEMPTS))
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800345 def _logging_delete_subnet(cls, subnet_id):
346 try:
347 cls.lb_mem_subnet_client.delete_subnet(subnet_id)
348 except Exception:
349 LOG.error('Unable to delete subnet {}. Active ports:'.format(
350 subnet_id))
351 LOG.error(cls.lb_mem_ports_client.list_ports())
352 raise
353
354 @classmethod
Jude Cross986e3f52017-07-24 14:57:20 -0700355 def _create_networks(cls):
356 """Creates networks, subnets, and routers used in tests.
357
358 The following are expected to be defined and available to the tests:
359 cls.lb_member_vip_net
360 cls.lb_member_vip_subnet
361 cls.lb_member_vip_ipv6_subnet (optional)
362 cls.lb_member_1_net
363 cls.lb_member_1_subnet
364 cls.lb_member_1_ipv6_subnet (optional)
365 cls.lb_member_2_net
366 cls.lb_member_2_subnet
367 cls.lb_member_2_ipv6_subnet (optional)
368 """
369
370 # Create tenant VIP network
371 network_kwargs = {
372 'name': data_utils.rand_name("lb_member_vip_network")}
373 if CONF.network_feature_enabled.port_security:
Andreas Jaeger4215b702020-03-28 20:13:46 +0100374 # Note: Allowed Address Pairs requires port security
375 network_kwargs['port_security_enabled'] = True
Jude Cross986e3f52017-07-24 14:57:20 -0700376 result = cls.lb_mem_net_client.create_network(**network_kwargs)
377 cls.lb_member_vip_net = result['network']
378 LOG.info('lb_member_vip_net: {}'.format(cls.lb_member_vip_net))
379 cls.addClassResourceCleanup(
380 waiters.wait_for_not_found,
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800381 cls._logging_delete_network,
Jude Cross986e3f52017-07-24 14:57:20 -0700382 cls.lb_mem_net_client.show_network,
383 cls.lb_member_vip_net['id'])
384
385 # Create tenant VIP subnet
386 subnet_kwargs = {
387 'name': data_utils.rand_name("lb_member_vip_subnet"),
388 'network_id': cls.lb_member_vip_net['id'],
389 'cidr': CONF.load_balancer.vip_subnet_cidr,
390 'ip_version': 4}
391 result = cls.lb_mem_subnet_client.create_subnet(**subnet_kwargs)
392 cls.lb_member_vip_subnet = result['subnet']
393 LOG.info('lb_member_vip_subnet: {}'.format(cls.lb_member_vip_subnet))
394 cls.addClassResourceCleanup(
395 waiters.wait_for_not_found,
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800396 cls._logging_delete_subnet,
Jude Cross986e3f52017-07-24 14:57:20 -0700397 cls.lb_mem_subnet_client.show_subnet,
398 cls.lb_member_vip_subnet['id'])
399
400 # Create tenant VIP IPv6 subnet
401 if CONF.load_balancer.test_with_ipv6:
Michael Johnson590fbe12019-07-03 14:30:01 -0700402 cls.lb_member_vip_ipv6_subnet_stateful = False
Gregory Thiemonge54225ad2021-02-04 15:25:17 +0100403 cls.lb_member_vip_ipv6_subnet_use_subnetpool = False
404 subnet_kwargs = {
405 'name': data_utils.rand_name("lb_member_vip_ipv6_subnet"),
406 'network_id': cls.lb_member_vip_net['id'],
407 'ip_version': 6}
408
409 # Use a CIDR from devstack's default IPv6 subnetpool if it exists,
410 # the subnetpool's cidr is routable from the devstack node
411 # through the default router
412 subnetpool_name = CONF.load_balancer.default_ipv6_subnetpool
413 if subnetpool_name:
414 subnetpool = cls.os_admin_subnetpools_client.list_subnetpools(
415 name=subnetpool_name)['subnetpools']
416 if len(subnetpool) == 1:
417 subnetpool = subnetpool[0]
418 subnet_kwargs['subnetpool_id'] = subnetpool['id']
419 cls.lb_member_vip_ipv6_subnet_use_subnetpool = True
420
421 if 'subnetpool_id' not in subnet_kwargs:
422 subnet_kwargs['cidr'] = (
423 CONF.load_balancer.vip_ipv6_subnet_cidr)
424
425 result = cls.lb_mem_subnet_client.create_subnet(
426 **subnet_kwargs)
427 cls.lb_member_vip_ipv6_net = cls.lb_member_vip_net
428 cls.lb_member_vip_ipv6_subnet = result['subnet']
429 cls.addClassResourceCleanup(
430 waiters.wait_for_not_found,
431 cls._logging_delete_subnet,
432 cls.lb_mem_subnet_client.show_subnet,
433 cls.lb_member_vip_ipv6_subnet['id'])
Carlos Goncalves84af48c2019-07-25 15:51:30 +0200434
Jude Cross986e3f52017-07-24 14:57:20 -0700435 LOG.info('lb_member_vip_ipv6_subnet: {}'.format(
436 cls.lb_member_vip_ipv6_subnet))
Jude Cross986e3f52017-07-24 14:57:20 -0700437
438 # Create tenant member 1 network
439 network_kwargs = {
440 'name': data_utils.rand_name("lb_member_1_network")}
441 if CONF.network_feature_enabled.port_security:
442 if CONF.load_balancer.enable_security_groups:
443 network_kwargs['port_security_enabled'] = True
444 else:
445 network_kwargs['port_security_enabled'] = False
446 result = cls.lb_mem_net_client.create_network(**network_kwargs)
447 cls.lb_member_1_net = result['network']
448 LOG.info('lb_member_1_net: {}'.format(cls.lb_member_1_net))
449 cls.addClassResourceCleanup(
450 waiters.wait_for_not_found,
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800451 cls._logging_delete_network,
Jude Cross986e3f52017-07-24 14:57:20 -0700452 cls.lb_mem_net_client.show_network,
453 cls.lb_member_1_net['id'])
454
455 # Create tenant member 1 subnet
456 subnet_kwargs = {
457 'name': data_utils.rand_name("lb_member_1_subnet"),
458 'network_id': cls.lb_member_1_net['id'],
459 'cidr': CONF.load_balancer.member_1_ipv4_subnet_cidr,
460 'ip_version': 4}
461 result = cls.lb_mem_subnet_client.create_subnet(**subnet_kwargs)
462 cls.lb_member_1_subnet = result['subnet']
463 LOG.info('lb_member_1_subnet: {}'.format(cls.lb_member_1_subnet))
464 cls.addClassResourceCleanup(
465 waiters.wait_for_not_found,
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800466 cls._logging_delete_subnet,
Jude Cross986e3f52017-07-24 14:57:20 -0700467 cls.lb_mem_subnet_client.show_subnet,
468 cls.lb_member_1_subnet['id'])
469
470 # Create tenant member 1 ipv6 subnet
471 if CONF.load_balancer.test_with_ipv6:
472 subnet_kwargs = {
473 'name': data_utils.rand_name("lb_member_1_ipv6_subnet"),
474 'network_id': cls.lb_member_1_net['id'],
475 'cidr': CONF.load_balancer.member_1_ipv6_subnet_cidr,
476 'ip_version': 6}
477 result = cls.lb_mem_subnet_client.create_subnet(**subnet_kwargs)
Michael Johnsonbf916df2018-10-17 10:59:28 -0700478 cls.lb_member_1_subnet_prefix = (
479 CONF.load_balancer.member_1_ipv6_subnet_cidr.rpartition('/')[2]
480 )
481 assert(cls.lb_member_1_subnet_prefix.isdigit())
Jude Cross986e3f52017-07-24 14:57:20 -0700482 cls.lb_member_1_ipv6_subnet = result['subnet']
483 LOG.info('lb_member_1_ipv6_subnet: {}'.format(
484 cls.lb_member_1_ipv6_subnet))
485 cls.addClassResourceCleanup(
486 waiters.wait_for_not_found,
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800487 cls._logging_delete_subnet,
Jude Cross986e3f52017-07-24 14:57:20 -0700488 cls.lb_mem_subnet_client.show_subnet,
489 cls.lb_member_1_ipv6_subnet['id'])
490
491 # Create tenant member 2 network
492 network_kwargs = {
493 'name': data_utils.rand_name("lb_member_2_network")}
494 if CONF.network_feature_enabled.port_security:
495 if CONF.load_balancer.enable_security_groups:
496 network_kwargs['port_security_enabled'] = True
497 else:
498 network_kwargs['port_security_enabled'] = False
499 result = cls.lb_mem_net_client.create_network(**network_kwargs)
500 cls.lb_member_2_net = result['network']
501 LOG.info('lb_member_2_net: {}'.format(cls.lb_member_2_net))
502 cls.addClassResourceCleanup(
503 waiters.wait_for_not_found,
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800504 cls._logging_delete_network,
Jude Cross986e3f52017-07-24 14:57:20 -0700505 cls.lb_mem_net_client.show_network,
506 cls.lb_member_2_net['id'])
507
508 # Create tenant member 2 subnet
509 subnet_kwargs = {
510 'name': data_utils.rand_name("lb_member_2_subnet"),
511 'network_id': cls.lb_member_2_net['id'],
512 'cidr': CONF.load_balancer.member_2_ipv4_subnet_cidr,
513 'ip_version': 4}
514 result = cls.lb_mem_subnet_client.create_subnet(**subnet_kwargs)
515 cls.lb_member_2_subnet = result['subnet']
516 LOG.info('lb_member_2_subnet: {}'.format(cls.lb_member_2_subnet))
517 cls.addClassResourceCleanup(
518 waiters.wait_for_not_found,
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800519 cls._logging_delete_subnet,
Jude Cross986e3f52017-07-24 14:57:20 -0700520 cls.lb_mem_subnet_client.show_subnet,
521 cls.lb_member_2_subnet['id'])
522
523 # Create tenant member 2 ipv6 subnet
524 if CONF.load_balancer.test_with_ipv6:
525 subnet_kwargs = {
526 'name': data_utils.rand_name("lb_member_2_ipv6_subnet"),
527 'network_id': cls.lb_member_2_net['id'],
528 'cidr': CONF.load_balancer.member_2_ipv6_subnet_cidr,
529 'ip_version': 6}
530 result = cls.lb_mem_subnet_client.create_subnet(**subnet_kwargs)
Michael Johnsonbf916df2018-10-17 10:59:28 -0700531 cls.lb_member_2_subnet_prefix = (
532 CONF.load_balancer.member_2_ipv6_subnet_cidr.rpartition('/')[2]
533 )
534 assert(cls.lb_member_2_subnet_prefix.isdigit())
Jude Cross986e3f52017-07-24 14:57:20 -0700535 cls.lb_member_2_ipv6_subnet = result['subnet']
536 LOG.info('lb_member_2_ipv6_subnet: {}'.format(
537 cls.lb_member_2_ipv6_subnet))
538 cls.addClassResourceCleanup(
539 waiters.wait_for_not_found,
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800540 cls._logging_delete_subnet,
Jude Cross986e3f52017-07-24 14:57:20 -0700541 cls.lb_mem_subnet_client.show_subnet,
542 cls.lb_member_2_ipv6_subnet['id'])
543
Adam Harwellcd72b562018-05-07 11:37:22 -0700544 @classmethod
Michael Johnson07c9a632018-06-07 13:27:42 -0700545 def _setup_lb_network_kwargs(cls, lb_kwargs, ip_version=None,
546 use_fixed_ip=False):
Adam Harwell60ed9d92018-05-10 13:23:13 -0700547 if not ip_version:
548 ip_version = 6 if CONF.load_balancer.test_with_ipv6 else 4
Michael Johnson5a16ad32018-10-18 14:49:11 -0700549 if cls.lb_member_vip_subnet or cls.lb_member_vip_ipv6_subnet:
Adam Harwellcd72b562018-05-07 11:37:22 -0700550 ip_index = data_utils.rand_int_id(start=10, end=100)
Michael Johnsondfd818a2018-08-21 20:54:54 -0700551 while ip_index in cls.used_ips:
552 ip_index = data_utils.rand_int_id(start=10, end=100)
553 cls.used_ips.append(ip_index)
Adam Harwellcd72b562018-05-07 11:37:22 -0700554 if ip_version == 4:
Adam Harwellcd72b562018-05-07 11:37:22 -0700555 subnet_id = cls.lb_member_vip_subnet[const.ID]
Michael Johnson5a16ad32018-10-18 14:49:11 -0700556 if CONF.load_balancer.test_with_noop:
557 lb_vip_address = '198.18.33.33'
558 else:
559 subnet = cls.os_admin.subnets_client.show_subnet(subnet_id)
560 network = ipaddress.IPv4Network(subnet['subnet']['cidr'])
561 lb_vip_address = str(network[ip_index])
Adam Harwellcd72b562018-05-07 11:37:22 -0700562 else:
Adam Harwellcd72b562018-05-07 11:37:22 -0700563 subnet_id = cls.lb_member_vip_ipv6_subnet[const.ID]
Michael Johnson5a16ad32018-10-18 14:49:11 -0700564 if CONF.load_balancer.test_with_noop:
565 lb_vip_address = '2001:db8:33:33:33:33:33:33'
566 else:
567 subnet = cls.os_admin.subnets_client.show_subnet(subnet_id)
568 network = ipaddress.IPv6Network(subnet['subnet']['cidr'])
569 lb_vip_address = str(network[ip_index])
Michael Johnson590fbe12019-07-03 14:30:01 -0700570 # If the subnet is IPv6 slaac or dhcpv6-stateless
571 # neutron does not allow a fixed IP
572 if not cls.lb_member_vip_ipv6_subnet_stateful:
573 use_fixed_ip = False
Adam Harwellcd72b562018-05-07 11:37:22 -0700574 lb_kwargs[const.VIP_SUBNET_ID] = subnet_id
Michael Johnson07c9a632018-06-07 13:27:42 -0700575 if use_fixed_ip:
576 lb_kwargs[const.VIP_ADDRESS] = lb_vip_address
Adam Harwellcd72b562018-05-07 11:37:22 -0700577 if CONF.load_balancer.test_with_noop:
578 lb_kwargs[const.VIP_NETWORK_ID] = (
579 cls.lb_member_vip_net[const.ID])
Carlos Goncalvesbb238552020-01-15 10:10:55 +0000580 if ip_version == 6:
581 lb_kwargs[const.VIP_ADDRESS] = lb_vip_address
Adam Harwellcd72b562018-05-07 11:37:22 -0700582 else:
583 lb_kwargs[const.VIP_NETWORK_ID] = cls.lb_member_vip_net[const.ID]
584 lb_kwargs[const.VIP_SUBNET_ID] = None
585
Gregory Thiemongeece5ab42020-10-29 08:46:05 +0100586 def _validate_listener_protocol(self, protocol, raise_if_unsupported=True):
587 if (protocol == const.SCTP and
588 not self.mem_listener_client.is_version_supported(
589 self.api_version, '2.23')):
590 if raise_if_unsupported:
591 raise self.skipException('SCTP listener protocol '
592 'is only available on Octavia '
593 'API version 2.23 or newer.')
594 return False
595 return True
596
ibumarskovc5063922020-09-03 18:21:29 +0400597 @classmethod
598 def check_tf_compatibility(cls, protocol=None, algorithm=None):
599 # TungstenFabric supported protocols and algorithms
600 tf_protocols = [const.HTTP, const.HTTPS, const.TCP, const.UDP,
601 const.TERMINATED_HTTPS]
602 tf_algorithms = [const.LB_ALGORITHM_ROUND_ROBIN,
603 const.LB_ALGORITHM_LEAST_CONNECTIONS,
604 const.LB_ALGORITHM_SOURCE_IP]
605
606 if algorithm and algorithm not in tf_algorithms:
607 raise cls.skipException(
608 'TungstenFabric does not support {} algorithm.'
609 ''.format(algorithm))
610 if protocol and protocol not in tf_protocols:
611 raise cls.skipException(
612 'TungstenFabric does not support {} protocol.'
613 ''.format(protocol))
614
615 @classmethod
616 def _tf_create_listener(cls, name, proto, port, lb_id):
617 listener_kwargs = {
618 const.NAME: name,
619 const.PROTOCOL: proto,
620 const.PROTOCOL_PORT: port,
621 const.LOADBALANCER_ID: lb_id,
622 }
623 listener = cls.mem_listener_client.create_listener(**listener_kwargs)
624 return listener
625
626 @classmethod
627 def _tf_get_free_port(cls, lb_id):
628 port = 8081
629 lb = cls.mem_lb_client.show_loadbalancer(lb_id)
630 listeners = lb[const.LISTENERS]
631 if not listeners:
632 return port
633 ports = [cls.mem_listener_client.show_listener(x[const.ID])[
634 const.PROTOCOL_PORT] for x in listeners]
635 while port in ports:
636 port = port + 1
637 return port
638
Adam Harwellcd72b562018-05-07 11:37:22 -0700639
640class LoadBalancerBaseTestWithCompute(LoadBalancerBaseTest):
641 @classmethod
Gregory Thiemongeb0da4f32022-02-04 08:58:06 +0100642 def remote_client_args(cls):
643 # In case we're using octavia-tempest-plugin with old tempest releases
644 # (for instance on stable/train) that don't support ssh_key_type, catch
645 # the exception and don't pass any argument
646 args = {}
647 try:
648 args['ssh_key_type'] = CONF.validation.ssh_key_type
649 except cfg.NoSuchOptError:
650 pass
651 return args
652
653 @classmethod
Adam Harwellcd72b562018-05-07 11:37:22 -0700654 def resource_setup(cls):
655 super(LoadBalancerBaseTestWithCompute, cls).resource_setup()
656 # If validation is disabled in this cloud, we won't be able to
657 # start the webservers, so don't even boot them.
658 if not CONF.validation.run_validation:
659 return
660
661 # Create a keypair for the webservers
662 keypair_name = data_utils.rand_name('lb_member_keypair')
663 result = cls.lb_mem_keypairs_client.create_keypair(
664 name=keypair_name)
665 cls.lb_member_keypair = result['keypair']
666 LOG.info('lb_member_keypair: {}'.format(cls.lb_member_keypair))
667 cls.addClassResourceCleanup(
668 waiters.wait_for_not_found,
669 cls.lb_mem_keypairs_client.delete_keypair,
670 cls.lb_mem_keypairs_client.show_keypair,
671 keypair_name)
672
673 if (CONF.load_balancer.enable_security_groups and
674 CONF.network_feature_enabled.port_security):
675 # Set up the security group for the webservers
676 SG_name = data_utils.rand_name('lb_member_SG')
677 cls.lb_member_sec_group = (
678 cls.lb_mem_SG_client.create_security_group(
679 name=SG_name)['security_group'])
680 cls.addClassResourceCleanup(
681 waiters.wait_for_not_found,
682 cls.lb_mem_SG_client.delete_security_group,
683 cls.lb_mem_SG_client.show_security_group,
684 cls.lb_member_sec_group['id'])
685
686 # Create a security group rule to allow 80-81 (test webservers)
687 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
688 direction='ingress',
689 security_group_id=cls.lb_member_sec_group['id'],
690 protocol='tcp',
691 ethertype='IPv4',
692 port_range_min=80,
693 port_range_max=81)['security_group_rule']
694 cls.addClassResourceCleanup(
695 waiters.wait_for_not_found,
696 cls.lb_mem_SGr_client.delete_security_group_rule,
697 cls.lb_mem_SGr_client.show_security_group_rule,
698 SGr['id'])
Gregory Thiemonge29d17902019-04-30 15:06:17 +0200699 # Create a security group rule to allow UDP 80-81 (test webservers)
700 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
701 direction='ingress',
702 security_group_id=cls.lb_member_sec_group['id'],
703 protocol='udp',
704 ethertype='IPv4',
705 port_range_min=80,
706 port_range_max=81)['security_group_rule']
707 cls.addClassResourceCleanup(
708 waiters.wait_for_not_found,
709 cls.lb_mem_SGr_client.delete_security_group_rule,
710 cls.lb_mem_SGr_client.show_security_group_rule,
711 SGr['id'])
Michael Johnson74b6f2f2020-10-29 15:11:39 -0700712 # Create a security group rule to allow 443 (test webservers)
713 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
714 direction='ingress',
715 security_group_id=cls.lb_member_sec_group['id'],
716 protocol='tcp',
717 ethertype='IPv4',
718 port_range_min=443,
719 port_range_max=443)['security_group_rule']
720 cls.addClassResourceCleanup(
721 waiters.wait_for_not_found,
722 cls.lb_mem_SGr_client.delete_security_group_rule,
723 cls.lb_mem_SGr_client.show_security_group_rule,
724 SGr['id'])
Michael Johnson031ecca2020-10-29 16:45:32 -0700725 # Create a security group rule to allow 9443 (test webservers)
726 # Used in the pool backend encryption client authentication tests
727 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
728 direction='ingress',
729 security_group_id=cls.lb_member_sec_group['id'],
730 protocol='tcp',
731 ethertype='IPv4',
732 port_range_min=9443,
733 port_range_max=9443)['security_group_rule']
734 cls.addClassResourceCleanup(
735 waiters.wait_for_not_found,
736 cls.lb_mem_SGr_client.delete_security_group_rule,
737 cls.lb_mem_SGr_client.show_security_group_rule,
738 SGr['id'])
Gregory Thiemonge29d17902019-04-30 15:06:17 +0200739 # Create a security group rule to allow UDP 9999 (test webservers)
740 # Port 9999 is used to illustrate health monitor ERRORs on closed
741 # ports.
742 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
743 direction='ingress',
744 security_group_id=cls.lb_member_sec_group['id'],
745 protocol='udp',
746 ethertype='IPv4',
747 port_range_min=9999,
748 port_range_max=9999)['security_group_rule']
749 cls.addClassResourceCleanup(
750 waiters.wait_for_not_found,
751 cls.lb_mem_SGr_client.delete_security_group_rule,
752 cls.lb_mem_SGr_client.show_security_group_rule,
753 SGr['id'])
Adam Harwellcd72b562018-05-07 11:37:22 -0700754 # Create a security group rule to allow 22 (ssh)
755 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
756 direction='ingress',
757 security_group_id=cls.lb_member_sec_group['id'],
758 protocol='tcp',
759 ethertype='IPv4',
760 port_range_min=22,
761 port_range_max=22)['security_group_rule']
762 cls.addClassResourceCleanup(
763 waiters.wait_for_not_found,
764 cls.lb_mem_SGr_client.delete_security_group_rule,
765 cls.lb_mem_SGr_client.show_security_group_rule,
766 SGr['id'])
767 if CONF.load_balancer.test_with_ipv6:
768 # Create a security group rule to allow 80-81 (test webservers)
769 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
770 direction='ingress',
771 security_group_id=cls.lb_member_sec_group['id'],
772 protocol='tcp',
773 ethertype='IPv6',
774 port_range_min=80,
775 port_range_max=81)['security_group_rule']
776 cls.addClassResourceCleanup(
777 waiters.wait_for_not_found,
778 cls.lb_mem_SGr_client.delete_security_group_rule,
779 cls.lb_mem_SGr_client.show_security_group_rule,
780 SGr['id'])
Gregory Thiemonge29d17902019-04-30 15:06:17 +0200781 # Create a security group rule to allow UDP 80-81 (test
782 # webservers)
783 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
784 direction='ingress',
785 security_group_id=cls.lb_member_sec_group['id'],
786 protocol='udp',
787 ethertype='IPv6',
788 port_range_min=80,
789 port_range_max=81)['security_group_rule']
790 cls.addClassResourceCleanup(
791 waiters.wait_for_not_found,
792 cls.lb_mem_SGr_client.delete_security_group_rule,
793 cls.lb_mem_SGr_client.show_security_group_rule,
794 SGr['id'])
Michael Johnson74b6f2f2020-10-29 15:11:39 -0700795 # Create a security group rule to allow 443 (test webservers)
796 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
797 direction='ingress',
798 security_group_id=cls.lb_member_sec_group['id'],
799 protocol='tcp',
800 ethertype='IPv6',
801 port_range_min=443,
802 port_range_max=443)['security_group_rule']
803 cls.addClassResourceCleanup(
804 waiters.wait_for_not_found,
805 cls.lb_mem_SGr_client.delete_security_group_rule,
806 cls.lb_mem_SGr_client.show_security_group_rule,
807 SGr['id'])
Michael Johnson031ecca2020-10-29 16:45:32 -0700808 # Create a security group rule to allow 9443 (test webservers)
809 # Used in the pool encryption client authentication tests
810 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
811 direction='ingress',
812 security_group_id=cls.lb_member_sec_group['id'],
813 protocol='tcp',
814 ethertype='IPv6',
815 port_range_min=9443,
816 port_range_max=9443)['security_group_rule']
817 cls.addClassResourceCleanup(
818 waiters.wait_for_not_found,
819 cls.lb_mem_SGr_client.delete_security_group_rule,
820 cls.lb_mem_SGr_client.show_security_group_rule,
821 SGr['id'])
Adam Harwellcd72b562018-05-07 11:37:22 -0700822 # Create a security group rule to allow 22 (ssh)
823 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
824 direction='ingress',
825 security_group_id=cls.lb_member_sec_group['id'],
826 protocol='tcp',
827 ethertype='IPv6',
828 port_range_min=22,
829 port_range_max=22)['security_group_rule']
830 cls.addClassResourceCleanup(
831 waiters.wait_for_not_found,
832 cls.lb_mem_SGr_client.delete_security_group_rule,
833 cls.lb_mem_SGr_client.show_security_group_rule,
834 SGr['id'])
835
836 LOG.info('lb_member_sec_group: {}'.format(cls.lb_member_sec_group))
837
Michael Johnsonbaf12e02020-10-27 16:10:28 -0700838 # Setup backend member reencryption PKI
839 cls._create_backend_reencryption_pki()
840
Adam Harwellcd72b562018-05-07 11:37:22 -0700841 # Create webserver 1 instance
842 server_details = cls._create_webserver('lb_member_webserver1',
843 cls.lb_member_1_net)
844
845 cls.lb_member_webserver1 = server_details['server']
846 cls.webserver1_ip = server_details.get('ipv4_address')
847 cls.webserver1_ipv6 = server_details.get('ipv6_address')
848 cls.webserver1_public_ip = server_details['public_ipv4_address']
849
850 LOG.debug('Octavia Setup: lb_member_webserver1 = {}'.format(
851 cls.lb_member_webserver1[const.ID]))
852 LOG.debug('Octavia Setup: webserver1_ip = {}'.format(
853 cls.webserver1_ip))
854 LOG.debug('Octavia Setup: webserver1_ipv6 = {}'.format(
855 cls.webserver1_ipv6))
856 LOG.debug('Octavia Setup: webserver1_public_ip = {}'.format(
857 cls.webserver1_public_ip))
858
859 # Create webserver 2 instance
860 server_details = cls._create_webserver('lb_member_webserver2',
861 cls.lb_member_2_net)
862
863 cls.lb_member_webserver2 = server_details['server']
864 cls.webserver2_ip = server_details.get('ipv4_address')
865 cls.webserver2_ipv6 = server_details.get('ipv6_address')
866 cls.webserver2_public_ip = server_details['public_ipv4_address']
867
868 LOG.debug('Octavia Setup: lb_member_webserver2 = {}'.format(
869 cls.lb_member_webserver2[const.ID]))
870 LOG.debug('Octavia Setup: webserver2_ip = {}'.format(
871 cls.webserver2_ip))
872 LOG.debug('Octavia Setup: webserver2_ipv6 = {}'.format(
873 cls.webserver2_ipv6))
874 LOG.debug('Octavia Setup: webserver2_public_ip = {}'.format(
875 cls.webserver2_public_ip))
876
Ilya Bumarskovcea9b6b2023-03-16 14:12:09 +0400877 if (CONF.load_balancer.test_with_ipv6 and not
878 config_octavia.is_tungstenfabric_backend_enabled()):
Michael Johnsonbf916df2018-10-17 10:59:28 -0700879 # Enable the IPv6 nic in webserver 1
880 cls._enable_ipv6_nic_webserver(
881 cls.webserver1_public_ip, cls.lb_member_keypair['private_key'],
882 cls.webserver1_ipv6, cls.lb_member_1_subnet_prefix)
883
884 # Enable the IPv6 nic in webserver 2
885 cls._enable_ipv6_nic_webserver(
886 cls.webserver2_public_ip, cls.lb_member_keypair['private_key'],
887 cls.webserver2_ipv6, cls.lb_member_2_subnet_prefix)
888
Adam Harwellcd72b562018-05-07 11:37:22 -0700889 # Set up serving on webserver 1
890 cls._install_start_webserver(cls.webserver1_public_ip,
Adam Harwelle029af22018-05-24 17:13:28 -0700891 cls.lb_member_keypair['private_key'],
892 cls.webserver1_response)
Adam Harwellcd72b562018-05-07 11:37:22 -0700893
894 # Validate webserver 1
Adam Harwelle029af22018-05-24 17:13:28 -0700895 cls._validate_webserver(cls.webserver1_public_ip,
896 cls.webserver1_response)
Adam Harwellcd72b562018-05-07 11:37:22 -0700897
Gregory Thiemonge29d17902019-04-30 15:06:17 +0200898 # Validate udp server 1
899 cls._validate_udp_server(cls.webserver1_public_ip,
900 cls.webserver1_response)
901
Adam Harwellcd72b562018-05-07 11:37:22 -0700902 # Set up serving on webserver 2
903 cls._install_start_webserver(cls.webserver2_public_ip,
Adam Harwelle029af22018-05-24 17:13:28 -0700904 cls.lb_member_keypair['private_key'],
Michael Johnsonbaf12e02020-10-27 16:10:28 -0700905 cls.webserver2_response, revoke_cert=True)
Adam Harwellcd72b562018-05-07 11:37:22 -0700906
907 # Validate webserver 2
Adam Harwelle029af22018-05-24 17:13:28 -0700908 cls._validate_webserver(cls.webserver2_public_ip,
909 cls.webserver2_response)
Adam Harwellcd72b562018-05-07 11:37:22 -0700910
Gregory Thiemonge29d17902019-04-30 15:06:17 +0200911 # Validate udp server 2
912 cls._validate_udp_server(cls.webserver2_public_ip,
913 cls.webserver2_response)
914
Adam Harwellcd72b562018-05-07 11:37:22 -0700915 @classmethod
916 def _create_networks(cls):
917 super(LoadBalancerBaseTestWithCompute, cls)._create_networks()
Jude Cross986e3f52017-07-24 14:57:20 -0700918 # Create a router for the subnets (required for the floating IP)
919 router_name = data_utils.rand_name("lb_member_router")
920 result = cls.lb_mem_routers_client.create_router(
921 name=router_name, admin_state_up=True,
922 external_gateway_info=dict(
923 network_id=CONF.network.public_network_id))
924 cls.lb_member_router = result['router']
925 LOG.info('lb_member_router: {}'.format(cls.lb_member_router))
926 cls.addClassResourceCleanup(
927 waiters.wait_for_not_found,
928 cls.lb_mem_routers_client.delete_router,
929 cls.lb_mem_routers_client.show_router,
930 cls.lb_member_router['id'])
931
932 # Add VIP subnet to router
933 cls.lb_mem_routers_client.add_router_interface(
934 cls.lb_member_router['id'],
935 subnet_id=cls.lb_member_vip_subnet['id'])
936 cls.addClassResourceCleanup(
937 waiters.wait_for_not_found,
938 cls.lb_mem_routers_client.remove_router_interface,
939 cls.lb_mem_routers_client.remove_router_interface,
940 cls.lb_member_router['id'],
941 subnet_id=cls.lb_member_vip_subnet['id'])
942
Gregory Thiemonge54225ad2021-02-04 15:25:17 +0100943 if (CONF.load_balancer.test_with_ipv6 and
944 CONF.load_balancer.default_router and
945 cls.lb_member_vip_ipv6_subnet_use_subnetpool):
946
947 router_name = CONF.load_balancer.default_router
948 # if lb_member_vip_ipv6_subnet uses devstack's subnetpool,
949 # plug the subnet into the default router
950 router = cls.os_admin.routers_client.list_routers(
951 name=router_name)['routers']
952
953 if len(router) == 1:
954 router = router[0]
955
956 # Add IPv6 VIP subnet to router1
957 cls.os_admin_routers_client.add_router_interface(
958 router['id'],
959 subnet_id=cls.lb_member_vip_ipv6_subnet['id'])
960 cls.addClassResourceCleanup(
961 waiters.wait_for_not_found,
962 cls.os_admin_routers_client.remove_router_interface,
963 cls.os_admin_routers_client.remove_router_interface,
964 router['id'],
965 subnet_id=cls.lb_member_vip_ipv6_subnet['id'])
966
Jude Cross986e3f52017-07-24 14:57:20 -0700967 # Add member subnet 1 to router
968 cls.lb_mem_routers_client.add_router_interface(
969 cls.lb_member_router['id'],
970 subnet_id=cls.lb_member_1_subnet['id'])
971 cls.addClassResourceCleanup(
972 waiters.wait_for_not_found,
Jude Cross986e3f52017-07-24 14:57:20 -0700973 cls.lb_mem_routers_client.remove_router_interface,
974 cls.lb_mem_routers_client.remove_router_interface,
975 cls.lb_member_router['id'], subnet_id=cls.lb_member_1_subnet['id'])
976
977 # Add member subnet 2 to router
978 cls.lb_mem_routers_client.add_router_interface(
979 cls.lb_member_router['id'],
980 subnet_id=cls.lb_member_2_subnet['id'])
981 cls.addClassResourceCleanup(
982 waiters.wait_for_not_found,
983 cls.lb_mem_routers_client.remove_router_interface,
984 cls.lb_mem_routers_client.remove_router_interface,
985 cls.lb_member_router['id'], subnet_id=cls.lb_member_2_subnet['id'])
986
987 @classmethod
988 def _create_webserver(cls, name, network):
989 """Creates a webserver with two ports.
990
991 webserver_details dictionary contains:
992 server - The compute server object
993 ipv4_address - The IPv4 address for the server (optional)
994 ipv6_address - The IPv6 address for the server (optional)
995 public_ipv4_address - The publicly accessible IPv4 address for the
996 server, this may be a floating IP (optional)
997
998 :param name: The name of the server to create.
999 :param network: The network to boot the server on.
1000 :returns: webserver_details dictionary.
1001 """
1002 server_kwargs = {
1003 'name': data_utils.rand_name(name),
1004 'flavorRef': CONF.compute.flavor_ref,
1005 'imageRef': CONF.compute.image_ref,
1006 'key_name': cls.lb_member_keypair['name']}
1007 if (CONF.load_balancer.enable_security_groups and
1008 CONF.network_feature_enabled.port_security):
1009 server_kwargs['security_groups'] = [
1010 {'name': cls.lb_member_sec_group['name']}]
1011 if not CONF.load_balancer.disable_boot_network:
1012 server_kwargs['networks'] = [{'uuid': network['id']}]
1013
1014 # Replace the name for clouds that have limitations
1015 if CONF.load_balancer.random_server_name_length:
1016 r = random.SystemRandom()
1017 server_kwargs['name'] = "m{}".format("".join(
1018 [r.choice(string.ascii_uppercase + string.digits)
1019 for _ in range(
1020 CONF.load_balancer.random_server_name_length - 1)]
1021 ))
1022 if CONF.load_balancer.availability_zone:
1023 server_kwargs['availability_zone'] = (
1024 CONF.load_balancer.availability_zone)
1025
1026 server = cls.lb_mem_servers_client.create_server(
1027 **server_kwargs)['server']
1028 cls.addClassResourceCleanup(
1029 waiters.wait_for_not_found,
1030 cls.lb_mem_servers_client.delete_server,
1031 cls.lb_mem_servers_client.show_server,
1032 server['id'])
1033 server = waiters.wait_for_status(
1034 cls.lb_mem_servers_client.show_server,
1035 server['id'], 'status', 'ACTIVE',
1036 CONF.load_balancer.build_interval,
1037 CONF.load_balancer.build_timeout,
1038 root_tag='server')
1039 webserver_details = {'server': server}
1040 LOG.info('Created server: {}'.format(server))
1041
1042 addresses = server['addresses']
1043 if CONF.load_balancer.disable_boot_network:
1044 instance_network = addresses.values()[0]
1045 else:
1046 instance_network = addresses[network['name']]
1047 for addr in instance_network:
1048 if addr['version'] == 4:
1049 webserver_details['ipv4_address'] = addr['addr']
1050 if addr['version'] == 6:
1051 webserver_details['ipv6_address'] = addr['addr']
1052
1053 if CONF.validation.connect_method == 'floating':
1054 result = cls.lb_mem_ports_client.list_ports(
1055 network_id=network['id'],
1056 mac_address=instance_network[0]['OS-EXT-IPS-MAC:mac_addr'])
1057 port_id = result['ports'][0]['id']
Ilya Bumarskovcea9b6b2023-03-16 14:12:09 +04001058 if config_octavia.is_tungstenfabric_backend_enabled():
1059 port = result['ports'][0]
1060 fixed_ip = None
1061 for ip in port["fixed_ips"]:
1062 if (type(ipaddress.ip_address(ip["ip_address"])) is
1063 ipaddress.IPv4Address):
1064 fixed_ip = ip["ip_address"]
1065 break
1066 assert fixed_ip is not None, (f"Port doesn't have ipv4 "
1067 f"address: {port['fixed_ips']}")
1068 result = cls.lb_mem_float_ip_client.create_floatingip(
1069 floating_network_id=CONF.network.public_network_id,
1070 port_id=port_id,
1071 fixed_ip_address=fixed_ip)
1072 else:
1073 result = cls.lb_mem_float_ip_client.create_floatingip(
1074 floating_network_id=CONF.network.public_network_id,
1075 port_id=port_id)
Jude Cross986e3f52017-07-24 14:57:20 -07001076 floating_ip = result['floatingip']
1077 LOG.info('webserver1_floating_ip: {}'.format(floating_ip))
1078 cls.addClassResourceCleanup(
1079 waiters.wait_for_not_found,
1080 cls.lb_mem_float_ip_client.delete_floatingip,
1081 cls.lb_mem_float_ip_client.show_floatingip,
1082 floatingip_id=floating_ip['id'])
1083 webserver_details['public_ipv4_address'] = (
1084 floating_ip['floating_ip_address'])
1085 else:
1086 webserver_details['public_ipv4_address'] = (
1087 instance_network[0]['addr'])
1088
1089 return webserver_details
1090
1091 @classmethod
Gregory Thiemongea2c234e2021-11-02 17:08:29 +01001092 def _get_openssh_version(cls):
1093 p = subprocess.Popen(["ssh", "-V"],
1094 stdout=subprocess.PIPE,
1095 stderr=subprocess.PIPE)
1096 output = p.communicate()[1]
1097
1098 try:
1099 m = re.match(r"OpenSSH_(\d+)\.(\d+)", output.decode('utf-8'))
1100 version_maj = int(m.group(1))
1101 version_min = int(m.group(2))
1102 return version_maj, version_min
1103 except Exception:
1104 return None, None
1105
1106 @classmethod
1107 def _need_scp_protocol(cls):
1108 # When using scp >= 8.7, force the use of the SCP protocol,
1109 # the new default (SFTP protocol) doesn't work with
1110 # cirros VMs.
1111 ssh_version = cls._get_openssh_version()
1112 LOG.debug("ssh_version = {}".format(ssh_version))
1113 return (ssh_version[0] > 8 or
1114 (ssh_version[0] == 8 and ssh_version[1] >= 7))
1115
1116 @classmethod
Michael Johnsonbaf12e02020-10-27 16:10:28 -07001117 def _install_start_webserver(cls, ip_address, ssh_key, start_id,
1118 revoke_cert=False):
Michael Johnson27357352020-11-13 13:55:09 -08001119 local_file = CONF.load_balancer.test_server_path
Adam Harwellcd72b562018-05-07 11:37:22 -07001120
1121 linux_client = remote_client.RemoteClient(
Ade Leed0ea4062021-09-06 15:33:27 -04001122 ip_address, CONF.validation.image_ssh_user, pkey=ssh_key,
Gregory Thiemongeb0da4f32022-02-04 08:58:06 +01001123 **cls.remote_client_args())
Adam Harwellcd72b562018-05-07 11:37:22 -07001124 linux_client.validate_authentication()
1125
1126 with tempfile.NamedTemporaryFile() as key:
1127 key.write(ssh_key.encode('utf-8'))
1128 key.flush()
Gregory Thiemongea2c234e2021-11-02 17:08:29 +01001129 ssh_extra_args = (
1130 "-o PubkeyAcceptedKeyTypes=+ssh-rsa")
1131 if cls._need_scp_protocol():
1132 ssh_extra_args += " -O"
Adam Harwellcd72b562018-05-07 11:37:22 -07001133 cmd = ("scp -v -o UserKnownHostsFile=/dev/null "
Gregory Thiemongea2c234e2021-11-02 17:08:29 +01001134 "{7} "
Adam Harwellcd72b562018-05-07 11:37:22 -07001135 "-o StrictHostKeyChecking=no "
1136 "-o ConnectTimeout={0} -o ConnectionAttempts={1} "
1137 "-i {2} {3} {4}@{5}:{6}").format(
1138 CONF.load_balancer.scp_connection_timeout,
1139 CONF.load_balancer.scp_connection_attempts,
1140 key.name, local_file, CONF.validation.image_ssh_user,
Gregory Thiemongea2c234e2021-11-02 17:08:29 +01001141 ip_address, const.TEST_SERVER_BINARY,
1142 ssh_extra_args)
Adam Harwellcd72b562018-05-07 11:37:22 -07001143 args = shlex.split(cmd)
1144 subprocess_args = {'stdout': subprocess.PIPE,
1145 'stderr': subprocess.STDOUT,
1146 'cwd': None}
1147 proc = subprocess.Popen(args, **subprocess_args)
1148 stdout, stderr = proc.communicate()
1149 if proc.returncode != 0:
1150 raise exceptions.CommandFailed(proc.returncode, cmd,
1151 stdout, stderr)
Gregory Thiemongef72a8862019-08-06 17:25:42 +02001152
Michael Johnsonbaf12e02020-10-27 16:10:28 -07001153 cls._load_member_pki_content(ip_address, key,
1154 revoke_cert=revoke_cert)
1155
Gregory Thiemongef72a8862019-08-06 17:25:42 +02001156 # Enabling memory overcommit allows to run golang static binaries
1157 # compiled with a recent golang toolchain (>=1.11). Those binaries
1158 # allocate a large amount of virtual memory at init time, and this
1159 # allocation fails in tempest's nano flavor (64MB of RAM)
1160 # (golang issue reported in https://github.com/golang/go/issues/28114,
1161 # follow-up: https://github.com/golang/go/issues/28081)
1162 # TODO(gthiemonge): Remove this call when golang issue is resolved.
1163 linux_client.exec_command('sudo sh -c "echo 1 > '
1164 '/proc/sys/vm/overcommit_memory"')
1165
Michael Johnsonbaf12e02020-10-27 16:10:28 -07001166 # The initial process also supports HTTPS and HTTPS with client auth
1167 linux_client.exec_command(
1168 'sudo screen -d -m {0} -port 80 -id {1} -https_port 443 -cert {2} '
1169 '-key {3} -https_client_auth_port 9443 -client_ca {4}'.format(
1170 const.TEST_SERVER_BINARY, start_id, const.TEST_SERVER_CERT,
1171 const.TEST_SERVER_KEY, const.TEST_SERVER_CLIENT_CA))
1172
Adam Harwellcd72b562018-05-07 11:37:22 -07001173 linux_client.exec_command('sudo screen -d -m {0} -port 81 '
Michael Johnsonbaf12e02020-10-27 16:10:28 -07001174 '-id {1}'.format(const.TEST_SERVER_BINARY,
1175 start_id + 1))
Adam Harwellcd72b562018-05-07 11:37:22 -07001176
Michael Johnsonbf916df2018-10-17 10:59:28 -07001177 # Cirros does not configure the assigned IPv6 address by default
1178 # so enable it manually like tempest does here:
1179 # tempest/scenario/test_netowrk_v6.py turn_nic6_on()
1180 @classmethod
1181 def _enable_ipv6_nic_webserver(cls, ip_address, ssh_key,
1182 ipv6_address, ipv6_prefix):
1183 linux_client = remote_client.RemoteClient(
Ade Leed0ea4062021-09-06 15:33:27 -04001184 ip_address, CONF.validation.image_ssh_user, pkey=ssh_key,
Gregory Thiemongeb0da4f32022-02-04 08:58:06 +01001185 **cls.remote_client_args())
Michael Johnsonbf916df2018-10-17 10:59:28 -07001186 linux_client.validate_authentication()
1187
1188 linux_client.exec_command('sudo ip address add {0}/{1} dev '
1189 'eth0'.format(ipv6_address, ipv6_prefix))
1190
Adam Harwellcd72b562018-05-07 11:37:22 -07001191 @classmethod
Jude Cross986e3f52017-07-24 14:57:20 -07001192 def _validate_webserver(cls, ip_address, start_id):
1193 URL = 'http://{0}'.format(ip_address)
Michael Johnson89bdbcd2020-03-19 15:59:19 -07001194 cls.validate_URL_response(URL, expected_body=str(start_id))
Jude Cross986e3f52017-07-24 14:57:20 -07001195 URL = 'http://{0}:81'.format(ip_address)
Michael Johnson89bdbcd2020-03-19 15:59:19 -07001196 cls.validate_URL_response(URL, expected_body=str(start_id + 1))
Jude Cross986e3f52017-07-24 14:57:20 -07001197
Gregory Thiemonge29d17902019-04-30 15:06:17 +02001198 @classmethod
1199 def _validate_udp_server(cls, ip_address, start_id):
Michael Johnson89bdbcd2020-03-19 15:59:19 -07001200 res = cls.make_udp_request(ip_address, 80)
Gregory Thiemonge29d17902019-04-30 15:06:17 +02001201 if res != str(start_id):
1202 raise Exception("Response from test server doesn't match the "
1203 "expected value ({0} != {1}).".format(
1204 res, str(start_id)))
1205
Michael Johnson89bdbcd2020-03-19 15:59:19 -07001206 res = cls.make_udp_request(ip_address, 81)
Gregory Thiemonge29d17902019-04-30 15:06:17 +02001207 if res != str(start_id + 1):
1208 raise Exception("Response from test server doesn't match the "
1209 "expected value ({0} != {1}).".format(
1210 res, str(start_id + 1)))
Michael Johnsonbaf12e02020-10-27 16:10:28 -07001211
1212 @classmethod
1213 def _create_backend_reencryption_pki(cls):
1214 # Create a CA self-signed cert and key for the member test servers
1215 cls.member_ca_cert, cls.member_ca_key = (
1216 cert_utils.generate_ca_cert_and_key())
1217
1218 LOG.debug('Member CA Cert: %s', cls.member_ca_cert.public_bytes(
1219 serialization.Encoding.PEM))
1220 LOG.debug('Member CA private Key: %s', cls.member_ca_key.private_bytes(
1221 encoding=serialization.Encoding.PEM,
1222 format=serialization.PrivateFormat.TraditionalOpenSSL,
1223 encryption_algorithm=serialization.NoEncryption()))
1224 LOG.debug('Member CA public Key: %s',
1225 cls.member_ca_key.public_key().public_bytes(
1226 encoding=serialization.Encoding.PEM,
1227 format=serialization.PublicFormat.SubjectPublicKeyInfo))
1228
1229 # Create the member client authentication CA
1230 cls.member_client_ca_cert, member_client_ca_key = (
1231 cert_utils.generate_ca_cert_and_key())
1232
1233 # Create client cert and key
1234 cls.member_client_cn = uuidutils.generate_uuid()
1235 cls.member_client_cert, cls.member_client_key = (
1236 cert_utils.generate_client_cert_and_key(
1237 cls.member_client_ca_cert, member_client_ca_key,
1238 cls.member_client_cn))
1239 # Note: We are not revoking a client cert here as we don't need to
1240 # test the backend web server CRL checking.
1241
1242 @classmethod
1243 def _load_member_pki_content(cls, ip_address, ssh_key, revoke_cert=False):
1244 # Create webserver certificate and key
1245 cert, key = cert_utils.generate_server_cert_and_key(
1246 cls.member_ca_cert, cls.member_ca_key, ip_address)
1247
1248 LOG.debug('%s Cert: %s', ip_address, cert.public_bytes(
1249 serialization.Encoding.PEM))
1250 LOG.debug('%s private Key: %s', ip_address, key.private_bytes(
1251 encoding=serialization.Encoding.PEM,
1252 format=serialization.PrivateFormat.TraditionalOpenSSL,
1253 encryption_algorithm=serialization.NoEncryption()))
1254 public_key = key.public_key()
1255 LOG.debug('%s public Key: %s', ip_address, public_key.public_bytes(
1256 encoding=serialization.Encoding.PEM,
1257 format=serialization.PublicFormat.SubjectPublicKeyInfo))
1258
1259 # Create a CRL with a revoked certificate
1260 if revoke_cert:
1261 # Create a CRL with webserver 2 revoked
1262 cls.member_crl = cert_utils.generate_certificate_revocation_list(
1263 cls.member_ca_cert, cls.member_ca_key, cert)
1264
1265 # Load the certificate, key, and client CA certificate into the
1266 # test server.
1267 with tempfile.TemporaryDirectory() as tmpdir:
1268 os.umask(0)
1269 files_to_send = []
1270 cert_filename = os.path.join(tmpdir, const.CERT_PEM)
1271 files_to_send.append(cert_filename)
1272 with open(os.open(cert_filename, os.O_CREAT | os.O_WRONLY,
1273 0o700), 'w') as fh:
1274 fh.write(cert.public_bytes(
1275 serialization.Encoding.PEM).decode('utf-8'))
1276 fh.flush()
1277 key_filename = os.path.join(tmpdir, const.KEY_PEM)
1278 files_to_send.append(key_filename)
1279 with open(os.open(key_filename, os.O_CREAT | os.O_WRONLY,
1280 0o700), 'w') as fh:
1281 fh.write(key.private_bytes(
1282 encoding=serialization.Encoding.PEM,
1283 format=serialization.PrivateFormat.TraditionalOpenSSL,
1284 encryption_algorithm=serialization.NoEncryption()).decode(
1285 'utf-8'))
1286 fh.flush()
1287 client_ca_filename = os.path.join(tmpdir, const.CLIENT_CA_PEM)
1288 files_to_send.append(client_ca_filename)
1289 with open(os.open(client_ca_filename, os.O_CREAT | os.O_WRONLY,
1290 0o700), 'w') as fh:
1291 fh.write(cls.member_client_ca_cert.public_bytes(
1292 serialization.Encoding.PEM).decode('utf-8'))
1293 fh.flush()
1294
1295 # For security, we don't want to use a shell that can glob
1296 # the file names, so iterate over them.
1297 subprocess_args = {'stdout': subprocess.PIPE,
1298 'stderr': subprocess.STDOUT,
1299 'cwd': None}
Gregory Thiemongea2c234e2021-11-02 17:08:29 +01001300 ssh_extra_args = (
1301 "-o PubkeyAcceptedKeyTypes=+ssh-rsa")
1302 if cls._need_scp_protocol():
1303 ssh_extra_args += " -O"
Michael Johnsonbaf12e02020-10-27 16:10:28 -07001304 cmd = ("scp -v -o UserKnownHostsFile=/dev/null "
Gregory Thiemongea2c234e2021-11-02 17:08:29 +01001305 "{9} "
Michael Johnsonbaf12e02020-10-27 16:10:28 -07001306 "-o StrictHostKeyChecking=no "
1307 "-o ConnectTimeout={0} -o ConnectionAttempts={1} "
1308 "-i {2} {3} {4} {5} {6}@{7}:{8}").format(
1309 CONF.load_balancer.scp_connection_timeout,
1310 CONF.load_balancer.scp_connection_attempts,
1311 ssh_key.name, cert_filename, key_filename, client_ca_filename,
Gregory Thiemongea2c234e2021-11-02 17:08:29 +01001312 CONF.validation.image_ssh_user, ip_address, const.DEV_SHM_PATH,
1313 ssh_extra_args)
Michael Johnsonbaf12e02020-10-27 16:10:28 -07001314 args = shlex.split(cmd)
1315 proc = subprocess.Popen(args, **subprocess_args)
1316 stdout, stderr = proc.communicate()
1317 if proc.returncode != 0:
1318 raise exceptions.CommandFailed(proc.returncode, cmd,
1319 stdout, stderr)