blob: 3db8b8e83e3ce5086f7b19a86aeac21ecacf6080 [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
rbubyr6c7f20d2025-03-18 14:58:39 +010016import netaddr
Michael Johnsonbaf12e02020-10-27 16:10:28 -070017import os
Jude Cross986e3f52017-07-24 14:57:20 -070018import random
Gregory Thiemongea2c234e2021-11-02 17:08:29 +010019import re
Jude Cross986e3f52017-07-24 14:57:20 -070020import shlex
Jude Cross986e3f52017-07-24 14:57:20 -070021import string
22import subprocess
23import tempfile
24
Michael Johnsonbaf12e02020-10-27 16:10:28 -070025from cryptography.hazmat.primitives import serialization
Gregory Thiemongeb0da4f32022-02-04 08:58:06 +010026from oslo_config import cfg
Jude Cross986e3f52017-07-24 14:57:20 -070027from oslo_log import log as logging
28from oslo_utils import uuidutils
29from tempest import config
30from tempest.lib.common.utils import data_utils
31from tempest.lib.common.utils.linux import remote_client
Jude Cross986e3f52017-07-24 14:57:20 -070032from tempest.lib import exceptions
33from tempest import test
Michael Johnson04dc5cb2019-01-20 11:03:50 -080034import tenacity
Jude Cross986e3f52017-07-24 14:57:20 -070035
Michael Johnsonbaf12e02020-10-27 16:10:28 -070036from octavia_tempest_plugin.common import cert_utils
Jude Cross986e3f52017-07-24 14:57:20 -070037from octavia_tempest_plugin.common import constants as const
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
rbubyr6c7f20d2025-03-18 14:58:39 +0100385 # Add allocation pool to prevent IP address conflicts with portprober
386 cidr = netaddr.IPNetwork(CONF.load_balancer.vip_subnet_cidr)
387 pool_start = ipaddress.ip_address(str(cidr[101]))
388 pool_end = ipaddress.ip_address(str(cidr[254]))
389 allocation_pools = [{'start': str(pool_start), 'end': str(pool_end)}]
390
Jude Cross986e3f52017-07-24 14:57:20 -0700391 # Create tenant VIP subnet
392 subnet_kwargs = {
393 'name': data_utils.rand_name("lb_member_vip_subnet"),
394 'network_id': cls.lb_member_vip_net['id'],
395 'cidr': CONF.load_balancer.vip_subnet_cidr,
rbubyr6c7f20d2025-03-18 14:58:39 +0100396 'ip_version': 4,
397 'allocation_pools': allocation_pools
398 }
Jude Cross986e3f52017-07-24 14:57:20 -0700399 result = cls.lb_mem_subnet_client.create_subnet(**subnet_kwargs)
400 cls.lb_member_vip_subnet = result['subnet']
401 LOG.info('lb_member_vip_subnet: {}'.format(cls.lb_member_vip_subnet))
402 cls.addClassResourceCleanup(
403 waiters.wait_for_not_found,
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800404 cls._logging_delete_subnet,
Jude Cross986e3f52017-07-24 14:57:20 -0700405 cls.lb_mem_subnet_client.show_subnet,
406 cls.lb_member_vip_subnet['id'])
407
408 # Create tenant VIP IPv6 subnet
409 if CONF.load_balancer.test_with_ipv6:
Michael Johnson590fbe12019-07-03 14:30:01 -0700410 cls.lb_member_vip_ipv6_subnet_stateful = False
Gregory Thiemonge54225ad2021-02-04 15:25:17 +0100411 cls.lb_member_vip_ipv6_subnet_use_subnetpool = False
412 subnet_kwargs = {
413 'name': data_utils.rand_name("lb_member_vip_ipv6_subnet"),
414 'network_id': cls.lb_member_vip_net['id'],
415 'ip_version': 6}
416
417 # Use a CIDR from devstack's default IPv6 subnetpool if it exists,
418 # the subnetpool's cidr is routable from the devstack node
419 # through the default router
420 subnetpool_name = CONF.load_balancer.default_ipv6_subnetpool
421 if subnetpool_name:
422 subnetpool = cls.os_admin_subnetpools_client.list_subnetpools(
423 name=subnetpool_name)['subnetpools']
424 if len(subnetpool) == 1:
425 subnetpool = subnetpool[0]
426 subnet_kwargs['subnetpool_id'] = subnetpool['id']
427 cls.lb_member_vip_ipv6_subnet_use_subnetpool = True
428
429 if 'subnetpool_id' not in subnet_kwargs:
430 subnet_kwargs['cidr'] = (
431 CONF.load_balancer.vip_ipv6_subnet_cidr)
432
433 result = cls.lb_mem_subnet_client.create_subnet(
434 **subnet_kwargs)
435 cls.lb_member_vip_ipv6_net = cls.lb_member_vip_net
436 cls.lb_member_vip_ipv6_subnet = result['subnet']
437 cls.addClassResourceCleanup(
438 waiters.wait_for_not_found,
439 cls._logging_delete_subnet,
440 cls.lb_mem_subnet_client.show_subnet,
441 cls.lb_member_vip_ipv6_subnet['id'])
Carlos Goncalves84af48c2019-07-25 15:51:30 +0200442
Jude Cross986e3f52017-07-24 14:57:20 -0700443 LOG.info('lb_member_vip_ipv6_subnet: {}'.format(
444 cls.lb_member_vip_ipv6_subnet))
Jude Cross986e3f52017-07-24 14:57:20 -0700445
446 # Create tenant member 1 network
447 network_kwargs = {
448 'name': data_utils.rand_name("lb_member_1_network")}
449 if CONF.network_feature_enabled.port_security:
450 if CONF.load_balancer.enable_security_groups:
451 network_kwargs['port_security_enabled'] = True
452 else:
453 network_kwargs['port_security_enabled'] = False
454 result = cls.lb_mem_net_client.create_network(**network_kwargs)
455 cls.lb_member_1_net = result['network']
456 LOG.info('lb_member_1_net: {}'.format(cls.lb_member_1_net))
457 cls.addClassResourceCleanup(
458 waiters.wait_for_not_found,
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800459 cls._logging_delete_network,
Jude Cross986e3f52017-07-24 14:57:20 -0700460 cls.lb_mem_net_client.show_network,
461 cls.lb_member_1_net['id'])
462
463 # Create tenant member 1 subnet
464 subnet_kwargs = {
465 'name': data_utils.rand_name("lb_member_1_subnet"),
466 'network_id': cls.lb_member_1_net['id'],
467 'cidr': CONF.load_balancer.member_1_ipv4_subnet_cidr,
468 'ip_version': 4}
469 result = cls.lb_mem_subnet_client.create_subnet(**subnet_kwargs)
470 cls.lb_member_1_subnet = result['subnet']
471 LOG.info('lb_member_1_subnet: {}'.format(cls.lb_member_1_subnet))
472 cls.addClassResourceCleanup(
473 waiters.wait_for_not_found,
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800474 cls._logging_delete_subnet,
Jude Cross986e3f52017-07-24 14:57:20 -0700475 cls.lb_mem_subnet_client.show_subnet,
476 cls.lb_member_1_subnet['id'])
477
478 # Create tenant member 1 ipv6 subnet
479 if CONF.load_balancer.test_with_ipv6:
480 subnet_kwargs = {
481 'name': data_utils.rand_name("lb_member_1_ipv6_subnet"),
482 'network_id': cls.lb_member_1_net['id'],
483 'cidr': CONF.load_balancer.member_1_ipv6_subnet_cidr,
484 'ip_version': 6}
485 result = cls.lb_mem_subnet_client.create_subnet(**subnet_kwargs)
Michael Johnsonbf916df2018-10-17 10:59:28 -0700486 cls.lb_member_1_subnet_prefix = (
487 CONF.load_balancer.member_1_ipv6_subnet_cidr.rpartition('/')[2]
488 )
489 assert(cls.lb_member_1_subnet_prefix.isdigit())
Jude Cross986e3f52017-07-24 14:57:20 -0700490 cls.lb_member_1_ipv6_subnet = result['subnet']
491 LOG.info('lb_member_1_ipv6_subnet: {}'.format(
492 cls.lb_member_1_ipv6_subnet))
493 cls.addClassResourceCleanup(
494 waiters.wait_for_not_found,
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800495 cls._logging_delete_subnet,
Jude Cross986e3f52017-07-24 14:57:20 -0700496 cls.lb_mem_subnet_client.show_subnet,
497 cls.lb_member_1_ipv6_subnet['id'])
498
499 # Create tenant member 2 network
500 network_kwargs = {
501 'name': data_utils.rand_name("lb_member_2_network")}
502 if CONF.network_feature_enabled.port_security:
503 if CONF.load_balancer.enable_security_groups:
504 network_kwargs['port_security_enabled'] = True
505 else:
506 network_kwargs['port_security_enabled'] = False
507 result = cls.lb_mem_net_client.create_network(**network_kwargs)
508 cls.lb_member_2_net = result['network']
509 LOG.info('lb_member_2_net: {}'.format(cls.lb_member_2_net))
510 cls.addClassResourceCleanup(
511 waiters.wait_for_not_found,
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800512 cls._logging_delete_network,
Jude Cross986e3f52017-07-24 14:57:20 -0700513 cls.lb_mem_net_client.show_network,
514 cls.lb_member_2_net['id'])
515
516 # Create tenant member 2 subnet
517 subnet_kwargs = {
518 'name': data_utils.rand_name("lb_member_2_subnet"),
519 'network_id': cls.lb_member_2_net['id'],
520 'cidr': CONF.load_balancer.member_2_ipv4_subnet_cidr,
521 'ip_version': 4}
522 result = cls.lb_mem_subnet_client.create_subnet(**subnet_kwargs)
523 cls.lb_member_2_subnet = result['subnet']
524 LOG.info('lb_member_2_subnet: {}'.format(cls.lb_member_2_subnet))
525 cls.addClassResourceCleanup(
526 waiters.wait_for_not_found,
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800527 cls._logging_delete_subnet,
Jude Cross986e3f52017-07-24 14:57:20 -0700528 cls.lb_mem_subnet_client.show_subnet,
529 cls.lb_member_2_subnet['id'])
530
531 # Create tenant member 2 ipv6 subnet
532 if CONF.load_balancer.test_with_ipv6:
533 subnet_kwargs = {
534 'name': data_utils.rand_name("lb_member_2_ipv6_subnet"),
535 'network_id': cls.lb_member_2_net['id'],
536 'cidr': CONF.load_balancer.member_2_ipv6_subnet_cidr,
537 'ip_version': 6}
538 result = cls.lb_mem_subnet_client.create_subnet(**subnet_kwargs)
Michael Johnsonbf916df2018-10-17 10:59:28 -0700539 cls.lb_member_2_subnet_prefix = (
540 CONF.load_balancer.member_2_ipv6_subnet_cidr.rpartition('/')[2]
541 )
542 assert(cls.lb_member_2_subnet_prefix.isdigit())
Jude Cross986e3f52017-07-24 14:57:20 -0700543 cls.lb_member_2_ipv6_subnet = result['subnet']
544 LOG.info('lb_member_2_ipv6_subnet: {}'.format(
545 cls.lb_member_2_ipv6_subnet))
546 cls.addClassResourceCleanup(
547 waiters.wait_for_not_found,
Michael Johnson04dc5cb2019-01-20 11:03:50 -0800548 cls._logging_delete_subnet,
Jude Cross986e3f52017-07-24 14:57:20 -0700549 cls.lb_mem_subnet_client.show_subnet,
550 cls.lb_member_2_ipv6_subnet['id'])
551
Adam Harwellcd72b562018-05-07 11:37:22 -0700552 @classmethod
Michael Johnson07c9a632018-06-07 13:27:42 -0700553 def _setup_lb_network_kwargs(cls, lb_kwargs, ip_version=None,
554 use_fixed_ip=False):
Adam Harwell60ed9d92018-05-10 13:23:13 -0700555 if not ip_version:
556 ip_version = 6 if CONF.load_balancer.test_with_ipv6 else 4
Michael Johnson5a16ad32018-10-18 14:49:11 -0700557 if cls.lb_member_vip_subnet or cls.lb_member_vip_ipv6_subnet:
Adam Harwellcd72b562018-05-07 11:37:22 -0700558 ip_index = data_utils.rand_int_id(start=10, end=100)
Michael Johnsondfd818a2018-08-21 20:54:54 -0700559 while ip_index in cls.used_ips:
560 ip_index = data_utils.rand_int_id(start=10, end=100)
561 cls.used_ips.append(ip_index)
Adam Harwellcd72b562018-05-07 11:37:22 -0700562 if ip_version == 4:
Adam Harwellcd72b562018-05-07 11:37:22 -0700563 subnet_id = cls.lb_member_vip_subnet[const.ID]
Michael Johnson5a16ad32018-10-18 14:49:11 -0700564 if CONF.load_balancer.test_with_noop:
565 lb_vip_address = '198.18.33.33'
566 else:
567 subnet = cls.os_admin.subnets_client.show_subnet(subnet_id)
568 network = ipaddress.IPv4Network(subnet['subnet']['cidr'])
569 lb_vip_address = str(network[ip_index])
Adam Harwellcd72b562018-05-07 11:37:22 -0700570 else:
Adam Harwellcd72b562018-05-07 11:37:22 -0700571 subnet_id = cls.lb_member_vip_ipv6_subnet[const.ID]
Michael Johnson5a16ad32018-10-18 14:49:11 -0700572 if CONF.load_balancer.test_with_noop:
573 lb_vip_address = '2001:db8:33:33:33:33:33:33'
574 else:
575 subnet = cls.os_admin.subnets_client.show_subnet(subnet_id)
576 network = ipaddress.IPv6Network(subnet['subnet']['cidr'])
577 lb_vip_address = str(network[ip_index])
Michael Johnson590fbe12019-07-03 14:30:01 -0700578 # If the subnet is IPv6 slaac or dhcpv6-stateless
579 # neutron does not allow a fixed IP
580 if not cls.lb_member_vip_ipv6_subnet_stateful:
581 use_fixed_ip = False
Adam Harwellcd72b562018-05-07 11:37:22 -0700582 lb_kwargs[const.VIP_SUBNET_ID] = subnet_id
Michael Johnson07c9a632018-06-07 13:27:42 -0700583 if use_fixed_ip:
584 lb_kwargs[const.VIP_ADDRESS] = lb_vip_address
Adam Harwellcd72b562018-05-07 11:37:22 -0700585 if CONF.load_balancer.test_with_noop:
586 lb_kwargs[const.VIP_NETWORK_ID] = (
587 cls.lb_member_vip_net[const.ID])
Carlos Goncalvesbb238552020-01-15 10:10:55 +0000588 if ip_version == 6:
589 lb_kwargs[const.VIP_ADDRESS] = lb_vip_address
Adam Harwellcd72b562018-05-07 11:37:22 -0700590 else:
591 lb_kwargs[const.VIP_NETWORK_ID] = cls.lb_member_vip_net[const.ID]
592 lb_kwargs[const.VIP_SUBNET_ID] = None
593
Gregory Thiemongeece5ab42020-10-29 08:46:05 +0100594 def _validate_listener_protocol(self, protocol, raise_if_unsupported=True):
595 if (protocol == const.SCTP and
596 not self.mem_listener_client.is_version_supported(
597 self.api_version, '2.23')):
598 if raise_if_unsupported:
599 raise self.skipException('SCTP listener protocol '
600 'is only available on Octavia '
601 'API version 2.23 or newer.')
602 return False
Gleb Zimin74102c72024-10-07 12:10:00 +0200603 if CONF.load_balancer.provider == 'tungstenfabric':
604 self.check_tf_compatibility(protocol=protocol)
Gregory Thiemongeece5ab42020-10-29 08:46:05 +0100605 return True
606
ibumarskovc5063922020-09-03 18:21:29 +0400607 @classmethod
608 def check_tf_compatibility(cls, protocol=None, algorithm=None):
609 # TungstenFabric supported protocols and algorithms
Ilya Bumarskov2b406292021-02-03 16:16:42 +0400610 tf_protocols = [const.HTTP, const.HTTPS, const.TCP,
ibumarskovc5063922020-09-03 18:21:29 +0400611 const.TERMINATED_HTTPS]
612 tf_algorithms = [const.LB_ALGORITHM_ROUND_ROBIN,
613 const.LB_ALGORITHM_LEAST_CONNECTIONS,
614 const.LB_ALGORITHM_SOURCE_IP]
615
616 if algorithm and algorithm not in tf_algorithms:
617 raise cls.skipException(
618 'TungstenFabric does not support {} algorithm.'
619 ''.format(algorithm))
620 if protocol and protocol not in tf_protocols:
621 raise cls.skipException(
622 'TungstenFabric does not support {} protocol.'
623 ''.format(protocol))
624
625 @classmethod
626 def _tf_create_listener(cls, name, proto, port, lb_id):
627 listener_kwargs = {
628 const.NAME: name,
629 const.PROTOCOL: proto,
630 const.PROTOCOL_PORT: port,
631 const.LOADBALANCER_ID: lb_id,
632 }
633 listener = cls.mem_listener_client.create_listener(**listener_kwargs)
634 return listener
635
636 @classmethod
637 def _tf_get_free_port(cls, lb_id):
638 port = 8081
639 lb = cls.mem_lb_client.show_loadbalancer(lb_id)
640 listeners = lb[const.LISTENERS]
641 if not listeners:
642 return port
643 ports = [cls.mem_listener_client.show_listener(x[const.ID])[
644 const.PROTOCOL_PORT] for x in listeners]
645 while port in ports:
646 port = port + 1
647 return port
648
Adam Harwellcd72b562018-05-07 11:37:22 -0700649
650class LoadBalancerBaseTestWithCompute(LoadBalancerBaseTest):
651 @classmethod
Gregory Thiemongeb0da4f32022-02-04 08:58:06 +0100652 def remote_client_args(cls):
653 # In case we're using octavia-tempest-plugin with old tempest releases
654 # (for instance on stable/train) that don't support ssh_key_type, catch
655 # the exception and don't pass any argument
656 args = {}
657 try:
658 args['ssh_key_type'] = CONF.validation.ssh_key_type
659 except cfg.NoSuchOptError:
660 pass
661 return args
662
663 @classmethod
Adam Harwellcd72b562018-05-07 11:37:22 -0700664 def resource_setup(cls):
665 super(LoadBalancerBaseTestWithCompute, cls).resource_setup()
666 # If validation is disabled in this cloud, we won't be able to
667 # start the webservers, so don't even boot them.
668 if not CONF.validation.run_validation:
669 return
670
671 # Create a keypair for the webservers
672 keypair_name = data_utils.rand_name('lb_member_keypair')
673 result = cls.lb_mem_keypairs_client.create_keypair(
674 name=keypair_name)
675 cls.lb_member_keypair = result['keypair']
676 LOG.info('lb_member_keypair: {}'.format(cls.lb_member_keypair))
677 cls.addClassResourceCleanup(
678 waiters.wait_for_not_found,
679 cls.lb_mem_keypairs_client.delete_keypair,
680 cls.lb_mem_keypairs_client.show_keypair,
681 keypair_name)
682
683 if (CONF.load_balancer.enable_security_groups and
684 CONF.network_feature_enabled.port_security):
685 # Set up the security group for the webservers
686 SG_name = data_utils.rand_name('lb_member_SG')
687 cls.lb_member_sec_group = (
688 cls.lb_mem_SG_client.create_security_group(
689 name=SG_name)['security_group'])
690 cls.addClassResourceCleanup(
691 waiters.wait_for_not_found,
692 cls.lb_mem_SG_client.delete_security_group,
693 cls.lb_mem_SG_client.show_security_group,
694 cls.lb_member_sec_group['id'])
695
696 # Create a security group rule to allow 80-81 (test webservers)
697 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
698 direction='ingress',
699 security_group_id=cls.lb_member_sec_group['id'],
700 protocol='tcp',
701 ethertype='IPv4',
702 port_range_min=80,
703 port_range_max=81)['security_group_rule']
704 cls.addClassResourceCleanup(
705 waiters.wait_for_not_found,
706 cls.lb_mem_SGr_client.delete_security_group_rule,
707 cls.lb_mem_SGr_client.show_security_group_rule,
708 SGr['id'])
Gregory Thiemonge29d17902019-04-30 15:06:17 +0200709 # Create a security group rule to allow UDP 80-81 (test webservers)
710 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
711 direction='ingress',
712 security_group_id=cls.lb_member_sec_group['id'],
713 protocol='udp',
714 ethertype='IPv4',
715 port_range_min=80,
716 port_range_max=81)['security_group_rule']
717 cls.addClassResourceCleanup(
718 waiters.wait_for_not_found,
719 cls.lb_mem_SGr_client.delete_security_group_rule,
720 cls.lb_mem_SGr_client.show_security_group_rule,
721 SGr['id'])
Michael Johnson74b6f2f2020-10-29 15:11:39 -0700722 # Create a security group rule to allow 443 (test webservers)
723 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
724 direction='ingress',
725 security_group_id=cls.lb_member_sec_group['id'],
726 protocol='tcp',
727 ethertype='IPv4',
728 port_range_min=443,
729 port_range_max=443)['security_group_rule']
730 cls.addClassResourceCleanup(
731 waiters.wait_for_not_found,
732 cls.lb_mem_SGr_client.delete_security_group_rule,
733 cls.lb_mem_SGr_client.show_security_group_rule,
734 SGr['id'])
Michael Johnson031ecca2020-10-29 16:45:32 -0700735 # Create a security group rule to allow 9443 (test webservers)
736 # Used in the pool backend encryption client authentication tests
737 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
738 direction='ingress',
739 security_group_id=cls.lb_member_sec_group['id'],
740 protocol='tcp',
741 ethertype='IPv4',
742 port_range_min=9443,
743 port_range_max=9443)['security_group_rule']
744 cls.addClassResourceCleanup(
745 waiters.wait_for_not_found,
746 cls.lb_mem_SGr_client.delete_security_group_rule,
747 cls.lb_mem_SGr_client.show_security_group_rule,
748 SGr['id'])
Gregory Thiemonge29d17902019-04-30 15:06:17 +0200749 # Create a security group rule to allow UDP 9999 (test webservers)
750 # Port 9999 is used to illustrate health monitor ERRORs on closed
751 # ports.
752 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
753 direction='ingress',
754 security_group_id=cls.lb_member_sec_group['id'],
755 protocol='udp',
756 ethertype='IPv4',
757 port_range_min=9999,
758 port_range_max=9999)['security_group_rule']
759 cls.addClassResourceCleanup(
760 waiters.wait_for_not_found,
761 cls.lb_mem_SGr_client.delete_security_group_rule,
762 cls.lb_mem_SGr_client.show_security_group_rule,
763 SGr['id'])
Adam Harwellcd72b562018-05-07 11:37:22 -0700764 # Create a security group rule to allow 22 (ssh)
765 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
766 direction='ingress',
767 security_group_id=cls.lb_member_sec_group['id'],
768 protocol='tcp',
769 ethertype='IPv4',
770 port_range_min=22,
771 port_range_max=22)['security_group_rule']
772 cls.addClassResourceCleanup(
773 waiters.wait_for_not_found,
774 cls.lb_mem_SGr_client.delete_security_group_rule,
775 cls.lb_mem_SGr_client.show_security_group_rule,
776 SGr['id'])
777 if CONF.load_balancer.test_with_ipv6:
778 # Create a security group rule to allow 80-81 (test webservers)
779 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
780 direction='ingress',
781 security_group_id=cls.lb_member_sec_group['id'],
782 protocol='tcp',
783 ethertype='IPv6',
784 port_range_min=80,
785 port_range_max=81)['security_group_rule']
786 cls.addClassResourceCleanup(
787 waiters.wait_for_not_found,
788 cls.lb_mem_SGr_client.delete_security_group_rule,
789 cls.lb_mem_SGr_client.show_security_group_rule,
790 SGr['id'])
Gregory Thiemonge29d17902019-04-30 15:06:17 +0200791 # Create a security group rule to allow UDP 80-81 (test
792 # webservers)
793 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
794 direction='ingress',
795 security_group_id=cls.lb_member_sec_group['id'],
796 protocol='udp',
797 ethertype='IPv6',
798 port_range_min=80,
799 port_range_max=81)['security_group_rule']
800 cls.addClassResourceCleanup(
801 waiters.wait_for_not_found,
802 cls.lb_mem_SGr_client.delete_security_group_rule,
803 cls.lb_mem_SGr_client.show_security_group_rule,
804 SGr['id'])
Michael Johnson74b6f2f2020-10-29 15:11:39 -0700805 # Create a security group rule to allow 443 (test webservers)
806 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
807 direction='ingress',
808 security_group_id=cls.lb_member_sec_group['id'],
809 protocol='tcp',
810 ethertype='IPv6',
811 port_range_min=443,
812 port_range_max=443)['security_group_rule']
813 cls.addClassResourceCleanup(
814 waiters.wait_for_not_found,
815 cls.lb_mem_SGr_client.delete_security_group_rule,
816 cls.lb_mem_SGr_client.show_security_group_rule,
817 SGr['id'])
Michael Johnson031ecca2020-10-29 16:45:32 -0700818 # Create a security group rule to allow 9443 (test webservers)
819 # Used in the pool encryption client authentication tests
820 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
821 direction='ingress',
822 security_group_id=cls.lb_member_sec_group['id'],
823 protocol='tcp',
824 ethertype='IPv6',
825 port_range_min=9443,
826 port_range_max=9443)['security_group_rule']
827 cls.addClassResourceCleanup(
828 waiters.wait_for_not_found,
829 cls.lb_mem_SGr_client.delete_security_group_rule,
830 cls.lb_mem_SGr_client.show_security_group_rule,
831 SGr['id'])
Adam Harwellcd72b562018-05-07 11:37:22 -0700832 # Create a security group rule to allow 22 (ssh)
833 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
834 direction='ingress',
835 security_group_id=cls.lb_member_sec_group['id'],
836 protocol='tcp',
837 ethertype='IPv6',
838 port_range_min=22,
839 port_range_max=22)['security_group_rule']
840 cls.addClassResourceCleanup(
841 waiters.wait_for_not_found,
842 cls.lb_mem_SGr_client.delete_security_group_rule,
843 cls.lb_mem_SGr_client.show_security_group_rule,
844 SGr['id'])
845
846 LOG.info('lb_member_sec_group: {}'.format(cls.lb_member_sec_group))
847
Michael Johnsonbaf12e02020-10-27 16:10:28 -0700848 # Setup backend member reencryption PKI
849 cls._create_backend_reencryption_pki()
850
Adam Harwellcd72b562018-05-07 11:37:22 -0700851 # Create webserver 1 instance
852 server_details = cls._create_webserver('lb_member_webserver1',
853 cls.lb_member_1_net)
854
855 cls.lb_member_webserver1 = server_details['server']
856 cls.webserver1_ip = server_details.get('ipv4_address')
857 cls.webserver1_ipv6 = server_details.get('ipv6_address')
858 cls.webserver1_public_ip = server_details['public_ipv4_address']
859
860 LOG.debug('Octavia Setup: lb_member_webserver1 = {}'.format(
861 cls.lb_member_webserver1[const.ID]))
862 LOG.debug('Octavia Setup: webserver1_ip = {}'.format(
863 cls.webserver1_ip))
864 LOG.debug('Octavia Setup: webserver1_ipv6 = {}'.format(
865 cls.webserver1_ipv6))
866 LOG.debug('Octavia Setup: webserver1_public_ip = {}'.format(
867 cls.webserver1_public_ip))
868
869 # Create webserver 2 instance
870 server_details = cls._create_webserver('lb_member_webserver2',
871 cls.lb_member_2_net)
872
873 cls.lb_member_webserver2 = server_details['server']
874 cls.webserver2_ip = server_details.get('ipv4_address')
875 cls.webserver2_ipv6 = server_details.get('ipv6_address')
876 cls.webserver2_public_ip = server_details['public_ipv4_address']
877
878 LOG.debug('Octavia Setup: lb_member_webserver2 = {}'.format(
879 cls.lb_member_webserver2[const.ID]))
880 LOG.debug('Octavia Setup: webserver2_ip = {}'.format(
881 cls.webserver2_ip))
882 LOG.debug('Octavia Setup: webserver2_ipv6 = {}'.format(
883 cls.webserver2_ipv6))
884 LOG.debug('Octavia Setup: webserver2_public_ip = {}'.format(
885 cls.webserver2_public_ip))
886
Ilya Bumarskovcea9b6b2023-03-16 14:12:09 +0400887 if (CONF.load_balancer.test_with_ipv6 and not
Gleb Zimin028d1772023-11-22 13:06:14 +0100888 config.is_tungstenfabric_backend_enabled()):
Michael Johnsonbf916df2018-10-17 10:59:28 -0700889 # Enable the IPv6 nic in webserver 1
890 cls._enable_ipv6_nic_webserver(
891 cls.webserver1_public_ip, cls.lb_member_keypair['private_key'],
892 cls.webserver1_ipv6, cls.lb_member_1_subnet_prefix)
893
894 # Enable the IPv6 nic in webserver 2
895 cls._enable_ipv6_nic_webserver(
896 cls.webserver2_public_ip, cls.lb_member_keypair['private_key'],
897 cls.webserver2_ipv6, cls.lb_member_2_subnet_prefix)
898
Adam Harwellcd72b562018-05-07 11:37:22 -0700899 # Set up serving on webserver 1
900 cls._install_start_webserver(cls.webserver1_public_ip,
Adam Harwelle029af22018-05-24 17:13:28 -0700901 cls.lb_member_keypair['private_key'],
902 cls.webserver1_response)
Adam Harwellcd72b562018-05-07 11:37:22 -0700903
904 # Validate webserver 1
Adam Harwelle029af22018-05-24 17:13:28 -0700905 cls._validate_webserver(cls.webserver1_public_ip,
906 cls.webserver1_response)
Adam Harwellcd72b562018-05-07 11:37:22 -0700907
Gregory Thiemonge29d17902019-04-30 15:06:17 +0200908 # Validate udp server 1
909 cls._validate_udp_server(cls.webserver1_public_ip,
910 cls.webserver1_response)
911
Adam Harwellcd72b562018-05-07 11:37:22 -0700912 # Set up serving on webserver 2
913 cls._install_start_webserver(cls.webserver2_public_ip,
Adam Harwelle029af22018-05-24 17:13:28 -0700914 cls.lb_member_keypair['private_key'],
Michael Johnsonbaf12e02020-10-27 16:10:28 -0700915 cls.webserver2_response, revoke_cert=True)
Adam Harwellcd72b562018-05-07 11:37:22 -0700916
917 # Validate webserver 2
Adam Harwelle029af22018-05-24 17:13:28 -0700918 cls._validate_webserver(cls.webserver2_public_ip,
919 cls.webserver2_response)
Adam Harwellcd72b562018-05-07 11:37:22 -0700920
Gregory Thiemonge29d17902019-04-30 15:06:17 +0200921 # Validate udp server 2
922 cls._validate_udp_server(cls.webserver2_public_ip,
923 cls.webserver2_response)
924
Adam Harwellcd72b562018-05-07 11:37:22 -0700925 @classmethod
926 def _create_networks(cls):
927 super(LoadBalancerBaseTestWithCompute, cls)._create_networks()
Jude Cross986e3f52017-07-24 14:57:20 -0700928 # Create a router for the subnets (required for the floating IP)
929 router_name = data_utils.rand_name("lb_member_router")
930 result = cls.lb_mem_routers_client.create_router(
931 name=router_name, admin_state_up=True,
932 external_gateway_info=dict(
933 network_id=CONF.network.public_network_id))
934 cls.lb_member_router = result['router']
935 LOG.info('lb_member_router: {}'.format(cls.lb_member_router))
936 cls.addClassResourceCleanup(
937 waiters.wait_for_not_found,
938 cls.lb_mem_routers_client.delete_router,
939 cls.lb_mem_routers_client.show_router,
940 cls.lb_member_router['id'])
941
942 # Add VIP subnet to router
943 cls.lb_mem_routers_client.add_router_interface(
944 cls.lb_member_router['id'],
945 subnet_id=cls.lb_member_vip_subnet['id'])
946 cls.addClassResourceCleanup(
947 waiters.wait_for_not_found,
948 cls.lb_mem_routers_client.remove_router_interface,
949 cls.lb_mem_routers_client.remove_router_interface,
950 cls.lb_member_router['id'],
951 subnet_id=cls.lb_member_vip_subnet['id'])
952
Gregory Thiemonge54225ad2021-02-04 15:25:17 +0100953 if (CONF.load_balancer.test_with_ipv6 and
954 CONF.load_balancer.default_router and
955 cls.lb_member_vip_ipv6_subnet_use_subnetpool):
956
957 router_name = CONF.load_balancer.default_router
958 # if lb_member_vip_ipv6_subnet uses devstack's subnetpool,
959 # plug the subnet into the default router
960 router = cls.os_admin.routers_client.list_routers(
961 name=router_name)['routers']
962
963 if len(router) == 1:
964 router = router[0]
965
966 # Add IPv6 VIP subnet to router1
967 cls.os_admin_routers_client.add_router_interface(
968 router['id'],
969 subnet_id=cls.lb_member_vip_ipv6_subnet['id'])
970 cls.addClassResourceCleanup(
971 waiters.wait_for_not_found,
972 cls.os_admin_routers_client.remove_router_interface,
973 cls.os_admin_routers_client.remove_router_interface,
974 router['id'],
975 subnet_id=cls.lb_member_vip_ipv6_subnet['id'])
976
Jude Cross986e3f52017-07-24 14:57:20 -0700977 # Add member subnet 1 to router
978 cls.lb_mem_routers_client.add_router_interface(
979 cls.lb_member_router['id'],
980 subnet_id=cls.lb_member_1_subnet['id'])
981 cls.addClassResourceCleanup(
982 waiters.wait_for_not_found,
Jude Cross986e3f52017-07-24 14:57:20 -0700983 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_1_subnet['id'])
986
987 # Add member subnet 2 to router
988 cls.lb_mem_routers_client.add_router_interface(
989 cls.lb_member_router['id'],
990 subnet_id=cls.lb_member_2_subnet['id'])
991 cls.addClassResourceCleanup(
992 waiters.wait_for_not_found,
993 cls.lb_mem_routers_client.remove_router_interface,
994 cls.lb_mem_routers_client.remove_router_interface,
995 cls.lb_member_router['id'], subnet_id=cls.lb_member_2_subnet['id'])
996
997 @classmethod
998 def _create_webserver(cls, name, network):
999 """Creates a webserver with two ports.
1000
1001 webserver_details dictionary contains:
1002 server - The compute server object
1003 ipv4_address - The IPv4 address for the server (optional)
1004 ipv6_address - The IPv6 address for the server (optional)
1005 public_ipv4_address - The publicly accessible IPv4 address for the
1006 server, this may be a floating IP (optional)
1007
1008 :param name: The name of the server to create.
1009 :param network: The network to boot the server on.
1010 :returns: webserver_details dictionary.
1011 """
1012 server_kwargs = {
1013 'name': data_utils.rand_name(name),
1014 'flavorRef': CONF.compute.flavor_ref,
1015 'imageRef': CONF.compute.image_ref,
1016 'key_name': cls.lb_member_keypair['name']}
1017 if (CONF.load_balancer.enable_security_groups and
1018 CONF.network_feature_enabled.port_security):
1019 server_kwargs['security_groups'] = [
1020 {'name': cls.lb_member_sec_group['name']}]
1021 if not CONF.load_balancer.disable_boot_network:
1022 server_kwargs['networks'] = [{'uuid': network['id']}]
1023
1024 # Replace the name for clouds that have limitations
1025 if CONF.load_balancer.random_server_name_length:
1026 r = random.SystemRandom()
1027 server_kwargs['name'] = "m{}".format("".join(
1028 [r.choice(string.ascii_uppercase + string.digits)
1029 for _ in range(
1030 CONF.load_balancer.random_server_name_length - 1)]
1031 ))
1032 if CONF.load_balancer.availability_zone:
1033 server_kwargs['availability_zone'] = (
1034 CONF.load_balancer.availability_zone)
1035
1036 server = cls.lb_mem_servers_client.create_server(
1037 **server_kwargs)['server']
1038 cls.addClassResourceCleanup(
1039 waiters.wait_for_not_found,
1040 cls.lb_mem_servers_client.delete_server,
1041 cls.lb_mem_servers_client.show_server,
1042 server['id'])
1043 server = waiters.wait_for_status(
1044 cls.lb_mem_servers_client.show_server,
1045 server['id'], 'status', 'ACTIVE',
1046 CONF.load_balancer.build_interval,
1047 CONF.load_balancer.build_timeout,
1048 root_tag='server')
1049 webserver_details = {'server': server}
1050 LOG.info('Created server: {}'.format(server))
1051
1052 addresses = server['addresses']
1053 if CONF.load_balancer.disable_boot_network:
1054 instance_network = addresses.values()[0]
1055 else:
1056 instance_network = addresses[network['name']]
1057 for addr in instance_network:
1058 if addr['version'] == 4:
1059 webserver_details['ipv4_address'] = addr['addr']
1060 if addr['version'] == 6:
1061 webserver_details['ipv6_address'] = addr['addr']
1062
1063 if CONF.validation.connect_method == 'floating':
1064 result = cls.lb_mem_ports_client.list_ports(
1065 network_id=network['id'],
1066 mac_address=instance_network[0]['OS-EXT-IPS-MAC:mac_addr'])
1067 port_id = result['ports'][0]['id']
Gleb Zimin028d1772023-11-22 13:06:14 +01001068 if config.is_tungstenfabric_backend_enabled():
Ilya Bumarskovcea9b6b2023-03-16 14:12:09 +04001069 port = result['ports'][0]
1070 fixed_ip = None
1071 for ip in port["fixed_ips"]:
1072 if (type(ipaddress.ip_address(ip["ip_address"])) is
1073 ipaddress.IPv4Address):
1074 fixed_ip = ip["ip_address"]
1075 break
1076 assert fixed_ip is not None, (f"Port doesn't have ipv4 "
1077 f"address: {port['fixed_ips']}")
1078 result = cls.lb_mem_float_ip_client.create_floatingip(
1079 floating_network_id=CONF.network.public_network_id,
1080 port_id=port_id,
1081 fixed_ip_address=fixed_ip)
1082 else:
1083 result = cls.lb_mem_float_ip_client.create_floatingip(
1084 floating_network_id=CONF.network.public_network_id,
1085 port_id=port_id)
Jude Cross986e3f52017-07-24 14:57:20 -07001086 floating_ip = result['floatingip']
1087 LOG.info('webserver1_floating_ip: {}'.format(floating_ip))
1088 cls.addClassResourceCleanup(
1089 waiters.wait_for_not_found,
1090 cls.lb_mem_float_ip_client.delete_floatingip,
1091 cls.lb_mem_float_ip_client.show_floatingip,
1092 floatingip_id=floating_ip['id'])
1093 webserver_details['public_ipv4_address'] = (
1094 floating_ip['floating_ip_address'])
1095 else:
1096 webserver_details['public_ipv4_address'] = (
1097 instance_network[0]['addr'])
1098
1099 return webserver_details
1100
1101 @classmethod
Gregory Thiemongea2c234e2021-11-02 17:08:29 +01001102 def _get_openssh_version(cls):
1103 p = subprocess.Popen(["ssh", "-V"],
1104 stdout=subprocess.PIPE,
1105 stderr=subprocess.PIPE)
1106 output = p.communicate()[1]
1107
1108 try:
1109 m = re.match(r"OpenSSH_(\d+)\.(\d+)", output.decode('utf-8'))
1110 version_maj = int(m.group(1))
1111 version_min = int(m.group(2))
1112 return version_maj, version_min
1113 except Exception:
1114 return None, None
1115
1116 @classmethod
1117 def _need_scp_protocol(cls):
1118 # When using scp >= 8.7, force the use of the SCP protocol,
1119 # the new default (SFTP protocol) doesn't work with
1120 # cirros VMs.
1121 ssh_version = cls._get_openssh_version()
1122 LOG.debug("ssh_version = {}".format(ssh_version))
1123 return (ssh_version[0] > 8 or
1124 (ssh_version[0] == 8 and ssh_version[1] >= 7))
1125
1126 @classmethod
Michael Johnsonbaf12e02020-10-27 16:10:28 -07001127 def _install_start_webserver(cls, ip_address, ssh_key, start_id,
1128 revoke_cert=False):
Michael Johnson27357352020-11-13 13:55:09 -08001129 local_file = CONF.load_balancer.test_server_path
Adam Harwellcd72b562018-05-07 11:37:22 -07001130
1131 linux_client = remote_client.RemoteClient(
Ade Leed0ea4062021-09-06 15:33:27 -04001132 ip_address, CONF.validation.image_ssh_user, pkey=ssh_key,
Gregory Thiemongeb0da4f32022-02-04 08:58:06 +01001133 **cls.remote_client_args())
Adam Harwellcd72b562018-05-07 11:37:22 -07001134 linux_client.validate_authentication()
1135
1136 with tempfile.NamedTemporaryFile() as key:
1137 key.write(ssh_key.encode('utf-8'))
1138 key.flush()
Gregory Thiemongea2c234e2021-11-02 17:08:29 +01001139 ssh_extra_args = (
1140 "-o PubkeyAcceptedKeyTypes=+ssh-rsa")
1141 if cls._need_scp_protocol():
1142 ssh_extra_args += " -O"
Adam Harwellcd72b562018-05-07 11:37:22 -07001143 cmd = ("scp -v -o UserKnownHostsFile=/dev/null "
Gregory Thiemongea2c234e2021-11-02 17:08:29 +01001144 "{7} "
Adam Harwellcd72b562018-05-07 11:37:22 -07001145 "-o StrictHostKeyChecking=no "
1146 "-o ConnectTimeout={0} -o ConnectionAttempts={1} "
1147 "-i {2} {3} {4}@{5}:{6}").format(
1148 CONF.load_balancer.scp_connection_timeout,
1149 CONF.load_balancer.scp_connection_attempts,
1150 key.name, local_file, CONF.validation.image_ssh_user,
Gregory Thiemongea2c234e2021-11-02 17:08:29 +01001151 ip_address, const.TEST_SERVER_BINARY,
1152 ssh_extra_args)
Adam Harwellcd72b562018-05-07 11:37:22 -07001153 args = shlex.split(cmd)
1154 subprocess_args = {'stdout': subprocess.PIPE,
1155 'stderr': subprocess.STDOUT,
1156 'cwd': None}
1157 proc = subprocess.Popen(args, **subprocess_args)
1158 stdout, stderr = proc.communicate()
1159 if proc.returncode != 0:
1160 raise exceptions.CommandFailed(proc.returncode, cmd,
1161 stdout, stderr)
Gregory Thiemongef72a8862019-08-06 17:25:42 +02001162
Michael Johnsonbaf12e02020-10-27 16:10:28 -07001163 cls._load_member_pki_content(ip_address, key,
1164 revoke_cert=revoke_cert)
1165
Gregory Thiemongef72a8862019-08-06 17:25:42 +02001166 # Enabling memory overcommit allows to run golang static binaries
1167 # compiled with a recent golang toolchain (>=1.11). Those binaries
1168 # allocate a large amount of virtual memory at init time, and this
1169 # allocation fails in tempest's nano flavor (64MB of RAM)
1170 # (golang issue reported in https://github.com/golang/go/issues/28114,
1171 # follow-up: https://github.com/golang/go/issues/28081)
1172 # TODO(gthiemonge): Remove this call when golang issue is resolved.
1173 linux_client.exec_command('sudo sh -c "echo 1 > '
1174 '/proc/sys/vm/overcommit_memory"')
1175
Michael Johnsonbaf12e02020-10-27 16:10:28 -07001176 # The initial process also supports HTTPS and HTTPS with client auth
1177 linux_client.exec_command(
1178 'sudo screen -d -m {0} -port 80 -id {1} -https_port 443 -cert {2} '
1179 '-key {3} -https_client_auth_port 9443 -client_ca {4}'.format(
1180 const.TEST_SERVER_BINARY, start_id, const.TEST_SERVER_CERT,
1181 const.TEST_SERVER_KEY, const.TEST_SERVER_CLIENT_CA))
1182
Adam Harwellcd72b562018-05-07 11:37:22 -07001183 linux_client.exec_command('sudo screen -d -m {0} -port 81 '
Michael Johnsonbaf12e02020-10-27 16:10:28 -07001184 '-id {1}'.format(const.TEST_SERVER_BINARY,
1185 start_id + 1))
Adam Harwellcd72b562018-05-07 11:37:22 -07001186
Michael Johnsonbf916df2018-10-17 10:59:28 -07001187 # Cirros does not configure the assigned IPv6 address by default
1188 # so enable it manually like tempest does here:
1189 # tempest/scenario/test_netowrk_v6.py turn_nic6_on()
1190 @classmethod
1191 def _enable_ipv6_nic_webserver(cls, ip_address, ssh_key,
1192 ipv6_address, ipv6_prefix):
1193 linux_client = remote_client.RemoteClient(
Ade Leed0ea4062021-09-06 15:33:27 -04001194 ip_address, CONF.validation.image_ssh_user, pkey=ssh_key,
Gregory Thiemongeb0da4f32022-02-04 08:58:06 +01001195 **cls.remote_client_args())
Michael Johnsonbf916df2018-10-17 10:59:28 -07001196 linux_client.validate_authentication()
1197
1198 linux_client.exec_command('sudo ip address add {0}/{1} dev '
1199 'eth0'.format(ipv6_address, ipv6_prefix))
1200
Adam Harwellcd72b562018-05-07 11:37:22 -07001201 @classmethod
Jude Cross986e3f52017-07-24 14:57:20 -07001202 def _validate_webserver(cls, ip_address, start_id):
1203 URL = 'http://{0}'.format(ip_address)
Michael Johnson89bdbcd2020-03-19 15:59:19 -07001204 cls.validate_URL_response(URL, expected_body=str(start_id))
Jude Cross986e3f52017-07-24 14:57:20 -07001205 URL = 'http://{0}:81'.format(ip_address)
Michael Johnson89bdbcd2020-03-19 15:59:19 -07001206 cls.validate_URL_response(URL, expected_body=str(start_id + 1))
Jude Cross986e3f52017-07-24 14:57:20 -07001207
Gregory Thiemonge29d17902019-04-30 15:06:17 +02001208 @classmethod
1209 def _validate_udp_server(cls, ip_address, start_id):
Michael Johnson89bdbcd2020-03-19 15:59:19 -07001210 res = cls.make_udp_request(ip_address, 80)
Gregory Thiemonge29d17902019-04-30 15:06:17 +02001211 if res != str(start_id):
1212 raise Exception("Response from test server doesn't match the "
1213 "expected value ({0} != {1}).".format(
1214 res, str(start_id)))
1215
Michael Johnson89bdbcd2020-03-19 15:59:19 -07001216 res = cls.make_udp_request(ip_address, 81)
Gregory Thiemonge29d17902019-04-30 15:06:17 +02001217 if res != str(start_id + 1):
1218 raise Exception("Response from test server doesn't match the "
1219 "expected value ({0} != {1}).".format(
1220 res, str(start_id + 1)))
Michael Johnsonbaf12e02020-10-27 16:10:28 -07001221
1222 @classmethod
1223 def _create_backend_reencryption_pki(cls):
1224 # Create a CA self-signed cert and key for the member test servers
1225 cls.member_ca_cert, cls.member_ca_key = (
1226 cert_utils.generate_ca_cert_and_key())
1227
1228 LOG.debug('Member CA Cert: %s', cls.member_ca_cert.public_bytes(
1229 serialization.Encoding.PEM))
1230 LOG.debug('Member CA private Key: %s', cls.member_ca_key.private_bytes(
1231 encoding=serialization.Encoding.PEM,
1232 format=serialization.PrivateFormat.TraditionalOpenSSL,
1233 encryption_algorithm=serialization.NoEncryption()))
1234 LOG.debug('Member CA public Key: %s',
1235 cls.member_ca_key.public_key().public_bytes(
1236 encoding=serialization.Encoding.PEM,
1237 format=serialization.PublicFormat.SubjectPublicKeyInfo))
1238
1239 # Create the member client authentication CA
1240 cls.member_client_ca_cert, member_client_ca_key = (
1241 cert_utils.generate_ca_cert_and_key())
1242
1243 # Create client cert and key
1244 cls.member_client_cn = uuidutils.generate_uuid()
1245 cls.member_client_cert, cls.member_client_key = (
1246 cert_utils.generate_client_cert_and_key(
1247 cls.member_client_ca_cert, member_client_ca_key,
1248 cls.member_client_cn))
1249 # Note: We are not revoking a client cert here as we don't need to
1250 # test the backend web server CRL checking.
1251
1252 @classmethod
1253 def _load_member_pki_content(cls, ip_address, ssh_key, revoke_cert=False):
1254 # Create webserver certificate and key
1255 cert, key = cert_utils.generate_server_cert_and_key(
1256 cls.member_ca_cert, cls.member_ca_key, ip_address)
1257
1258 LOG.debug('%s Cert: %s', ip_address, cert.public_bytes(
1259 serialization.Encoding.PEM))
1260 LOG.debug('%s private Key: %s', ip_address, key.private_bytes(
1261 encoding=serialization.Encoding.PEM,
1262 format=serialization.PrivateFormat.TraditionalOpenSSL,
1263 encryption_algorithm=serialization.NoEncryption()))
1264 public_key = key.public_key()
1265 LOG.debug('%s public Key: %s', ip_address, public_key.public_bytes(
1266 encoding=serialization.Encoding.PEM,
1267 format=serialization.PublicFormat.SubjectPublicKeyInfo))
1268
1269 # Create a CRL with a revoked certificate
1270 if revoke_cert:
1271 # Create a CRL with webserver 2 revoked
1272 cls.member_crl = cert_utils.generate_certificate_revocation_list(
1273 cls.member_ca_cert, cls.member_ca_key, cert)
1274
1275 # Load the certificate, key, and client CA certificate into the
1276 # test server.
1277 with tempfile.TemporaryDirectory() as tmpdir:
1278 os.umask(0)
1279 files_to_send = []
1280 cert_filename = os.path.join(tmpdir, const.CERT_PEM)
1281 files_to_send.append(cert_filename)
1282 with open(os.open(cert_filename, os.O_CREAT | os.O_WRONLY,
1283 0o700), 'w') as fh:
1284 fh.write(cert.public_bytes(
1285 serialization.Encoding.PEM).decode('utf-8'))
1286 fh.flush()
1287 key_filename = os.path.join(tmpdir, const.KEY_PEM)
1288 files_to_send.append(key_filename)
1289 with open(os.open(key_filename, os.O_CREAT | os.O_WRONLY,
1290 0o700), 'w') as fh:
1291 fh.write(key.private_bytes(
1292 encoding=serialization.Encoding.PEM,
1293 format=serialization.PrivateFormat.TraditionalOpenSSL,
1294 encryption_algorithm=serialization.NoEncryption()).decode(
1295 'utf-8'))
1296 fh.flush()
1297 client_ca_filename = os.path.join(tmpdir, const.CLIENT_CA_PEM)
1298 files_to_send.append(client_ca_filename)
1299 with open(os.open(client_ca_filename, os.O_CREAT | os.O_WRONLY,
1300 0o700), 'w') as fh:
1301 fh.write(cls.member_client_ca_cert.public_bytes(
1302 serialization.Encoding.PEM).decode('utf-8'))
1303 fh.flush()
1304
1305 # For security, we don't want to use a shell that can glob
1306 # the file names, so iterate over them.
1307 subprocess_args = {'stdout': subprocess.PIPE,
1308 'stderr': subprocess.STDOUT,
1309 'cwd': None}
Gregory Thiemongea2c234e2021-11-02 17:08:29 +01001310 ssh_extra_args = (
1311 "-o PubkeyAcceptedKeyTypes=+ssh-rsa")
1312 if cls._need_scp_protocol():
1313 ssh_extra_args += " -O"
Michael Johnsonbaf12e02020-10-27 16:10:28 -07001314 cmd = ("scp -v -o UserKnownHostsFile=/dev/null "
Gregory Thiemongea2c234e2021-11-02 17:08:29 +01001315 "{9} "
Michael Johnsonbaf12e02020-10-27 16:10:28 -07001316 "-o StrictHostKeyChecking=no "
1317 "-o ConnectTimeout={0} -o ConnectionAttempts={1} "
1318 "-i {2} {3} {4} {5} {6}@{7}:{8}").format(
1319 CONF.load_balancer.scp_connection_timeout,
1320 CONF.load_balancer.scp_connection_attempts,
1321 ssh_key.name, cert_filename, key_filename, client_ca_filename,
Gregory Thiemongea2c234e2021-11-02 17:08:29 +01001322 CONF.validation.image_ssh_user, ip_address, const.DEV_SHM_PATH,
1323 ssh_extra_args)
Michael Johnsonbaf12e02020-10-27 16:10:28 -07001324 args = shlex.split(cmd)
1325 proc = subprocess.Popen(args, **subprocess_args)
1326 stdout, stderr = proc.communicate()
1327 if proc.returncode != 0:
1328 raise exceptions.CommandFailed(proc.returncode, cmd,
1329 stdout, stderr)