blob: c443347b754d5207712fd156d0018ff48e04fa3d [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
16import pkg_resources
17import random
Adam Harwellcd72b562018-05-07 11:37:22 -070018import requests
Jude Cross986e3f52017-07-24 14:57:20 -070019import shlex
20import six
21import string
22import subprocess
23import tempfile
Adam Harwellcd72b562018-05-07 11:37:22 -070024import time
Jude Cross986e3f52017-07-24 14:57:20 -070025
26from 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
33
34from octavia_tempest_plugin import clients
35from octavia_tempest_plugin.common import constants as const
36from octavia_tempest_plugin.tests import validators
37from octavia_tempest_plugin.tests import waiters
38
39CONF = config.CONF
40LOG = logging.getLogger(__name__)
41
42
43class LoadBalancerBaseTest(test.BaseTestCase):
44 """Base class for load balancer tests."""
45
46 # Setup cls.os_roles_lb_member. cls.os_primary, cls.os_roles_lb_member,
47 # and cls.os_roles_lb_admin credentials.
48 credentials = ['admin', 'primary',
49 ['lb_member', CONF.load_balancer.member_role],
50 ['lb_member2', CONF.load_balancer.member_role],
51 ['lb_admin', CONF.load_balancer.admin_role]]
52
53 client_manager = clients.ManagerV2
Adam Harwelle029af22018-05-24 17:13:28 -070054 webserver1_response = 1
55 webserver2_response = 5
Michael Johnsondfd818a2018-08-21 20:54:54 -070056 used_ips = []
Jude Cross986e3f52017-07-24 14:57:20 -070057
58 @classmethod
59 def skip_checks(cls):
60 """Check if we should skip all of the children tests."""
61 super(LoadBalancerBaseTest, cls).skip_checks()
62
63 service_list = {
64 'load_balancer': CONF.service_available.load_balancer,
65 }
66
67 live_service_list = {
68 'compute': CONF.service_available.nova,
69 'image': CONF.service_available.glance,
70 'neutron': CONF.service_available.neutron
71 }
72
73 if not CONF.load_balancer.test_with_noop:
74 service_list.update(live_service_list)
75
76 for service, available in service_list.items():
77 if not available:
zhangzs2a6cf672018-11-10 16:13:11 +080078 skip_msg = ("{0} skipped as {1} service is not "
Jude Cross986e3f52017-07-24 14:57:20 -070079 "available.".format(cls.__name__, service))
80 raise cls.skipException(skip_msg)
81
82 # We must be able to reach our VIP and instances
83 if not (CONF.network.project_networks_reachable
84 or CONF.network.public_network_id):
85 msg = ('Either project_networks_reachable must be "true", or '
86 'public_network_id must be defined.')
87 raise cls.skipException(msg)
88
89 @classmethod
90 def setup_credentials(cls):
91 """Setup test credentials and network resources."""
92 # Do not auto create network resources
93 cls.set_network_resources()
94 super(LoadBalancerBaseTest, cls).setup_credentials()
95
96 @classmethod
97 def setup_clients(cls):
98 """Setup client aliases."""
99 super(LoadBalancerBaseTest, cls).setup_clients()
100 cls.lb_mem_float_ip_client = cls.os_roles_lb_member.floating_ips_client
101 cls.lb_mem_keypairs_client = cls.os_roles_lb_member.keypairs_client
102 cls.lb_mem_net_client = cls.os_roles_lb_member.networks_client
103 cls.lb_mem_ports_client = cls.os_roles_lb_member.ports_client
104 cls.lb_mem_routers_client = cls.os_roles_lb_member.routers_client
105 cls.lb_mem_SG_client = cls.os_roles_lb_member.security_groups_client
106 cls.lb_mem_SGr_client = (
107 cls.os_roles_lb_member.security_group_rules_client)
108 cls.lb_mem_servers_client = cls.os_roles_lb_member.servers_client
109 cls.lb_mem_subnet_client = cls.os_roles_lb_member.subnets_client
110 cls.mem_lb_client = cls.os_roles_lb_member.loadbalancer_client
Jude Crossfbbd2b42017-08-09 15:21:04 -0700111 cls.mem_listener_client = cls.os_roles_lb_member.listener_client
Adam Harwell8ffce3e2018-05-01 21:18:44 -0700112 cls.mem_pool_client = cls.os_roles_lb_member.pool_client
Adam Harwellde3e0542018-05-03 18:21:06 -0700113 cls.mem_member_client = cls.os_roles_lb_member.member_client
Adam Harwell60ed9d92018-05-10 13:23:13 -0700114 cls.mem_healthmonitor_client = (
115 cls.os_roles_lb_member.healthmonitor_client)
Adam Harwell446f8be2018-05-24 16:51:03 -0700116 cls.mem_l7policy_client = cls.os_roles_lb_member.l7policy_client
Adam Harwelle029af22018-05-24 17:13:28 -0700117 cls.mem_l7rule_client = cls.os_roles_lb_member.l7rule_client
Adam Harwelldfc11ee2018-05-30 09:38:55 -0700118 cls.mem_amphora_client = cls.os_roles_lb_member.amphora_client
Jude Cross986e3f52017-07-24 14:57:20 -0700119
120 @classmethod
121 def resource_setup(cls):
122 """Setup resources needed by the tests."""
123 super(LoadBalancerBaseTest, cls).resource_setup()
124
125 conf_lb = CONF.load_balancer
126
Michael Johnsondfd818a2018-08-21 20:54:54 -0700127 cls.api_version = cls.mem_lb_client.get_max_api_version()
128
Jude Cross986e3f52017-07-24 14:57:20 -0700129 if conf_lb.test_subnet_override and not conf_lb.test_network_override:
130 raise exceptions.InvalidConfiguration(
131 "Configuration value test_network_override must be "
132 "specified if test_subnet_override is used.")
133
134 show_subnet = cls.lb_mem_subnet_client.show_subnet
135 if CONF.load_balancer.test_with_noop:
136 cls.lb_member_vip_net = {'id': uuidutils.generate_uuid()}
137 cls.lb_member_vip_subnet = {'id': uuidutils.generate_uuid()}
138 cls.lb_member_1_net = {'id': uuidutils.generate_uuid()}
139 cls.lb_member_1_subnet = {'id': uuidutils.generate_uuid()}
140 cls.lb_member_2_net = {'id': uuidutils.generate_uuid()}
141 cls.lb_member_2_subnet = {'id': uuidutils.generate_uuid()}
142 if CONF.load_balancer.test_with_ipv6:
Michael Johnson5a16ad32018-10-18 14:49:11 -0700143 cls.lb_member_vip_ipv6_net = {'id': uuidutils.generate_uuid()}
Jude Cross986e3f52017-07-24 14:57:20 -0700144 cls.lb_member_vip_ipv6_subnet = {'id':
145 uuidutils.generate_uuid()}
146 cls.lb_member_1_ipv6_subnet = {'id': uuidutils.generate_uuid()}
147 cls.lb_member_2_ipv6_subnet = {'id': uuidutils.generate_uuid()}
148 return
149 elif CONF.load_balancer.test_network_override:
150 if conf_lb.test_subnet_override:
151 override_subnet = show_subnet(conf_lb.test_subnet_override)
152 else:
153 override_subnet = None
154
155 show_net = cls.lb_mem_net_client.show_network
156 override_network = show_net(conf_lb.test_network_override)
157 override_network = override_network.get('network')
158
159 cls.lb_member_vip_net = override_network
160 cls.lb_member_vip_subnet = override_subnet
161 cls.lb_member_1_net = override_network
162 cls.lb_member_1_subnet = override_subnet
163 cls.lb_member_2_net = override_network
164 cls.lb_member_2_subnet = override_subnet
165
166 if (CONF.load_balancer.test_with_ipv6 and
167 conf_lb.test_IPv6_subnet_override):
168 override_ipv6_subnet = show_subnet(
169 conf_lb.test_IPv6_subnet_override)
170 cls.lb_member_vip_ipv6_subnet = override_ipv6_subnet
171 cls.lb_member_1_ipv6_subnet = override_ipv6_subnet
172 cls.lb_member_2_ipv6_subnet = override_ipv6_subnet
173 else:
174 cls.lb_member_vip_ipv6_subnet = None
175 cls.lb_member_1_ipv6_subnet = None
176 cls.lb_member_2_ipv6_subnet = None
177 else:
178 cls._create_networks()
179
180 LOG.debug('Octavia Setup: lb_member_vip_net = {}'.format(
181 cls.lb_member_vip_net[const.ID]))
182 if cls.lb_member_vip_subnet:
183 LOG.debug('Octavia Setup: lb_member_vip_subnet = {}'.format(
184 cls.lb_member_vip_subnet[const.ID]))
185 LOG.debug('Octavia Setup: lb_member_1_net = {}'.format(
186 cls.lb_member_1_net[const.ID]))
187 if cls.lb_member_1_subnet:
188 LOG.debug('Octavia Setup: lb_member_1_subnet = {}'.format(
189 cls.lb_member_1_subnet[const.ID]))
190 LOG.debug('Octavia Setup: lb_member_2_net = {}'.format(
191 cls.lb_member_2_net[const.ID]))
192 if cls.lb_member_2_subnet:
193 LOG.debug('Octavia Setup: lb_member_2_subnet = {}'.format(
194 cls.lb_member_2_subnet[const.ID]))
Michael Johnson124ba8b2018-08-30 16:06:05 -0700195 if CONF.load_balancer.test_with_ipv6:
196 if cls.lb_member_vip_ipv6_subnet:
197 LOG.debug('Octavia Setup: lb_member_vip_ipv6_subnet = '
198 '{}'.format(cls.lb_member_vip_ipv6_subnet[const.ID]))
199 if cls.lb_member_1_ipv6_subnet:
200 LOG.debug('Octavia Setup: lb_member_1_ipv6_subnet = {}'.format(
201 cls.lb_member_1_ipv6_subnet[const.ID]))
202 if cls.lb_member_2_ipv6_subnet:
203 LOG.debug('Octavia Setup: lb_member_2_ipv6_subnet = {}'.format(
204 cls.lb_member_2_ipv6_subnet[const.ID]))
Jude Cross986e3f52017-07-24 14:57:20 -0700205
Jude Cross986e3f52017-07-24 14:57:20 -0700206 @classmethod
207 def _create_networks(cls):
208 """Creates networks, subnets, and routers used in tests.
209
210 The following are expected to be defined and available to the tests:
211 cls.lb_member_vip_net
212 cls.lb_member_vip_subnet
213 cls.lb_member_vip_ipv6_subnet (optional)
214 cls.lb_member_1_net
215 cls.lb_member_1_subnet
216 cls.lb_member_1_ipv6_subnet (optional)
217 cls.lb_member_2_net
218 cls.lb_member_2_subnet
219 cls.lb_member_2_ipv6_subnet (optional)
220 """
221
222 # Create tenant VIP network
223 network_kwargs = {
224 'name': data_utils.rand_name("lb_member_vip_network")}
225 if CONF.network_feature_enabled.port_security:
226 # Note: Allowed Address Pairs requires port security
227 network_kwargs['port_security_enabled'] = True
228 result = cls.lb_mem_net_client.create_network(**network_kwargs)
229 cls.lb_member_vip_net = result['network']
230 LOG.info('lb_member_vip_net: {}'.format(cls.lb_member_vip_net))
231 cls.addClassResourceCleanup(
232 waiters.wait_for_not_found,
233 cls.lb_mem_net_client.delete_network,
234 cls.lb_mem_net_client.show_network,
235 cls.lb_member_vip_net['id'])
236
237 # Create tenant VIP subnet
238 subnet_kwargs = {
239 'name': data_utils.rand_name("lb_member_vip_subnet"),
240 'network_id': cls.lb_member_vip_net['id'],
241 'cidr': CONF.load_balancer.vip_subnet_cidr,
242 'ip_version': 4}
243 result = cls.lb_mem_subnet_client.create_subnet(**subnet_kwargs)
244 cls.lb_member_vip_subnet = result['subnet']
245 LOG.info('lb_member_vip_subnet: {}'.format(cls.lb_member_vip_subnet))
246 cls.addClassResourceCleanup(
247 waiters.wait_for_not_found,
248 cls.lb_mem_subnet_client.delete_subnet,
249 cls.lb_mem_subnet_client.show_subnet,
250 cls.lb_member_vip_subnet['id'])
251
252 # Create tenant VIP IPv6 subnet
253 if CONF.load_balancer.test_with_ipv6:
Michael Johnson5a16ad32018-10-18 14:49:11 -0700254 # See if ipv6-public-subnet exists and use it if so.
255 pub_ipv6_subnet = cls.os_admin.subnets_client.list_subnets(
256 name='ipv6-public-subnet')['subnets']
257
258 if len(pub_ipv6_subnet) == 1:
259 cls.lb_member_vip_ipv6_subnet = pub_ipv6_subnet[0]
260 cls.lb_member_vip_ipv6_net = {
261 'id': pub_ipv6_subnet[0]['network_id']}
262 else:
263 subnet_kwargs = {
264 'name': data_utils.rand_name("lb_member_vip_ipv6_subnet"),
265 'network_id': cls.lb_member_vip_net['id'],
266 'cidr': CONF.load_balancer.vip_ipv6_subnet_cidr,
267 'ip_version': 6}
268 result = cls.lb_mem_subnet_client.create_subnet(
269 **subnet_kwargs)
270 cls.lb_member_vip_ipv6_subnet = result['subnet']
271 cls.addClassResourceCleanup(
272 waiters.wait_for_not_found,
273 cls.lb_mem_subnet_client.delete_subnet,
274 cls.lb_mem_subnet_client.show_subnet,
275 cls.lb_member_vip_ipv6_subnet['id'])
Jude Cross986e3f52017-07-24 14:57:20 -0700276 LOG.info('lb_member_vip_ipv6_subnet: {}'.format(
277 cls.lb_member_vip_ipv6_subnet))
Jude Cross986e3f52017-07-24 14:57:20 -0700278
279 # Create tenant member 1 network
280 network_kwargs = {
281 'name': data_utils.rand_name("lb_member_1_network")}
282 if CONF.network_feature_enabled.port_security:
283 if CONF.load_balancer.enable_security_groups:
284 network_kwargs['port_security_enabled'] = True
285 else:
286 network_kwargs['port_security_enabled'] = False
287 result = cls.lb_mem_net_client.create_network(**network_kwargs)
288 cls.lb_member_1_net = result['network']
289 LOG.info('lb_member_1_net: {}'.format(cls.lb_member_1_net))
290 cls.addClassResourceCleanup(
291 waiters.wait_for_not_found,
292 cls.lb_mem_net_client.delete_network,
293 cls.lb_mem_net_client.show_network,
294 cls.lb_member_1_net['id'])
295
296 # Create tenant member 1 subnet
297 subnet_kwargs = {
298 'name': data_utils.rand_name("lb_member_1_subnet"),
299 'network_id': cls.lb_member_1_net['id'],
300 'cidr': CONF.load_balancer.member_1_ipv4_subnet_cidr,
301 'ip_version': 4}
302 result = cls.lb_mem_subnet_client.create_subnet(**subnet_kwargs)
303 cls.lb_member_1_subnet = result['subnet']
304 LOG.info('lb_member_1_subnet: {}'.format(cls.lb_member_1_subnet))
305 cls.addClassResourceCleanup(
306 waiters.wait_for_not_found,
307 cls.lb_mem_subnet_client.delete_subnet,
308 cls.lb_mem_subnet_client.show_subnet,
309 cls.lb_member_1_subnet['id'])
310
311 # Create tenant member 1 ipv6 subnet
312 if CONF.load_balancer.test_with_ipv6:
313 subnet_kwargs = {
314 'name': data_utils.rand_name("lb_member_1_ipv6_subnet"),
315 'network_id': cls.lb_member_1_net['id'],
316 'cidr': CONF.load_balancer.member_1_ipv6_subnet_cidr,
317 'ip_version': 6}
318 result = cls.lb_mem_subnet_client.create_subnet(**subnet_kwargs)
Michael Johnsonbf916df2018-10-17 10:59:28 -0700319 cls.lb_member_1_subnet_prefix = (
320 CONF.load_balancer.member_1_ipv6_subnet_cidr.rpartition('/')[2]
321 )
322 assert(cls.lb_member_1_subnet_prefix.isdigit())
Jude Cross986e3f52017-07-24 14:57:20 -0700323 cls.lb_member_1_ipv6_subnet = result['subnet']
324 LOG.info('lb_member_1_ipv6_subnet: {}'.format(
325 cls.lb_member_1_ipv6_subnet))
326 cls.addClassResourceCleanup(
327 waiters.wait_for_not_found,
328 cls.lb_mem_subnet_client.delete_subnet,
329 cls.lb_mem_subnet_client.show_subnet,
330 cls.lb_member_1_ipv6_subnet['id'])
331
332 # Create tenant member 2 network
333 network_kwargs = {
334 'name': data_utils.rand_name("lb_member_2_network")}
335 if CONF.network_feature_enabled.port_security:
336 if CONF.load_balancer.enable_security_groups:
337 network_kwargs['port_security_enabled'] = True
338 else:
339 network_kwargs['port_security_enabled'] = False
340 result = cls.lb_mem_net_client.create_network(**network_kwargs)
341 cls.lb_member_2_net = result['network']
342 LOG.info('lb_member_2_net: {}'.format(cls.lb_member_2_net))
343 cls.addClassResourceCleanup(
344 waiters.wait_for_not_found,
345 cls.lb_mem_net_client.delete_network,
346 cls.lb_mem_net_client.show_network,
347 cls.lb_member_2_net['id'])
348
349 # Create tenant member 2 subnet
350 subnet_kwargs = {
351 'name': data_utils.rand_name("lb_member_2_subnet"),
352 'network_id': cls.lb_member_2_net['id'],
353 'cidr': CONF.load_balancer.member_2_ipv4_subnet_cidr,
354 'ip_version': 4}
355 result = cls.lb_mem_subnet_client.create_subnet(**subnet_kwargs)
356 cls.lb_member_2_subnet = result['subnet']
357 LOG.info('lb_member_2_subnet: {}'.format(cls.lb_member_2_subnet))
358 cls.addClassResourceCleanup(
359 waiters.wait_for_not_found,
360 cls.lb_mem_subnet_client.delete_subnet,
361 cls.lb_mem_subnet_client.show_subnet,
362 cls.lb_member_2_subnet['id'])
363
364 # Create tenant member 2 ipv6 subnet
365 if CONF.load_balancer.test_with_ipv6:
366 subnet_kwargs = {
367 'name': data_utils.rand_name("lb_member_2_ipv6_subnet"),
368 'network_id': cls.lb_member_2_net['id'],
369 'cidr': CONF.load_balancer.member_2_ipv6_subnet_cidr,
370 'ip_version': 6}
371 result = cls.lb_mem_subnet_client.create_subnet(**subnet_kwargs)
Michael Johnsonbf916df2018-10-17 10:59:28 -0700372 cls.lb_member_2_subnet_prefix = (
373 CONF.load_balancer.member_2_ipv6_subnet_cidr.rpartition('/')[2]
374 )
375 assert(cls.lb_member_2_subnet_prefix.isdigit())
Jude Cross986e3f52017-07-24 14:57:20 -0700376 cls.lb_member_2_ipv6_subnet = result['subnet']
377 LOG.info('lb_member_2_ipv6_subnet: {}'.format(
378 cls.lb_member_2_ipv6_subnet))
379 cls.addClassResourceCleanup(
380 waiters.wait_for_not_found,
381 cls.lb_mem_subnet_client.delete_subnet,
382 cls.lb_mem_subnet_client.show_subnet,
383 cls.lb_member_2_ipv6_subnet['id'])
384
Adam Harwellcd72b562018-05-07 11:37:22 -0700385 @classmethod
Michael Johnson07c9a632018-06-07 13:27:42 -0700386 def _setup_lb_network_kwargs(cls, lb_kwargs, ip_version=None,
387 use_fixed_ip=False):
Adam Harwell60ed9d92018-05-10 13:23:13 -0700388 if not ip_version:
389 ip_version = 6 if CONF.load_balancer.test_with_ipv6 else 4
Michael Johnson5a16ad32018-10-18 14:49:11 -0700390 if cls.lb_member_vip_subnet or cls.lb_member_vip_ipv6_subnet:
Adam Harwellcd72b562018-05-07 11:37:22 -0700391 ip_index = data_utils.rand_int_id(start=10, end=100)
Michael Johnsondfd818a2018-08-21 20:54:54 -0700392 while ip_index in cls.used_ips:
393 ip_index = data_utils.rand_int_id(start=10, end=100)
394 cls.used_ips.append(ip_index)
Adam Harwellcd72b562018-05-07 11:37:22 -0700395 if ip_version == 4:
Adam Harwellcd72b562018-05-07 11:37:22 -0700396 subnet_id = cls.lb_member_vip_subnet[const.ID]
Michael Johnson5a16ad32018-10-18 14:49:11 -0700397 if CONF.load_balancer.test_with_noop:
398 lb_vip_address = '198.18.33.33'
399 else:
400 subnet = cls.os_admin.subnets_client.show_subnet(subnet_id)
401 network = ipaddress.IPv4Network(subnet['subnet']['cidr'])
402 lb_vip_address = str(network[ip_index])
Adam Harwellcd72b562018-05-07 11:37:22 -0700403 else:
Adam Harwellcd72b562018-05-07 11:37:22 -0700404 subnet_id = cls.lb_member_vip_ipv6_subnet[const.ID]
Michael Johnson5a16ad32018-10-18 14:49:11 -0700405 if CONF.load_balancer.test_with_noop:
406 lb_vip_address = '2001:db8:33:33:33:33:33:33'
407 else:
408 subnet = cls.os_admin.subnets_client.show_subnet(subnet_id)
409 network = ipaddress.IPv6Network(subnet['subnet']['cidr'])
410 lb_vip_address = str(network[ip_index])
Adam Harwellcd72b562018-05-07 11:37:22 -0700411 lb_kwargs[const.VIP_SUBNET_ID] = subnet_id
Michael Johnson07c9a632018-06-07 13:27:42 -0700412 if use_fixed_ip:
413 lb_kwargs[const.VIP_ADDRESS] = lb_vip_address
Adam Harwellcd72b562018-05-07 11:37:22 -0700414 if CONF.load_balancer.test_with_noop:
415 lb_kwargs[const.VIP_NETWORK_ID] = (
416 cls.lb_member_vip_net[const.ID])
417 else:
418 lb_kwargs[const.VIP_NETWORK_ID] = cls.lb_member_vip_net[const.ID]
419 lb_kwargs[const.VIP_SUBNET_ID] = None
420
421
422class LoadBalancerBaseTestWithCompute(LoadBalancerBaseTest):
423 @classmethod
424 def resource_setup(cls):
425 super(LoadBalancerBaseTestWithCompute, cls).resource_setup()
426 # If validation is disabled in this cloud, we won't be able to
427 # start the webservers, so don't even boot them.
428 if not CONF.validation.run_validation:
429 return
430
431 # Create a keypair for the webservers
432 keypair_name = data_utils.rand_name('lb_member_keypair')
433 result = cls.lb_mem_keypairs_client.create_keypair(
434 name=keypair_name)
435 cls.lb_member_keypair = result['keypair']
436 LOG.info('lb_member_keypair: {}'.format(cls.lb_member_keypair))
437 cls.addClassResourceCleanup(
438 waiters.wait_for_not_found,
439 cls.lb_mem_keypairs_client.delete_keypair,
440 cls.lb_mem_keypairs_client.show_keypair,
441 keypair_name)
442
443 if (CONF.load_balancer.enable_security_groups and
444 CONF.network_feature_enabled.port_security):
445 # Set up the security group for the webservers
446 SG_name = data_utils.rand_name('lb_member_SG')
447 cls.lb_member_sec_group = (
448 cls.lb_mem_SG_client.create_security_group(
449 name=SG_name)['security_group'])
450 cls.addClassResourceCleanup(
451 waiters.wait_for_not_found,
452 cls.lb_mem_SG_client.delete_security_group,
453 cls.lb_mem_SG_client.show_security_group,
454 cls.lb_member_sec_group['id'])
455
456 # Create a security group rule to allow 80-81 (test webservers)
457 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
458 direction='ingress',
459 security_group_id=cls.lb_member_sec_group['id'],
460 protocol='tcp',
461 ethertype='IPv4',
462 port_range_min=80,
463 port_range_max=81)['security_group_rule']
464 cls.addClassResourceCleanup(
465 waiters.wait_for_not_found,
466 cls.lb_mem_SGr_client.delete_security_group_rule,
467 cls.lb_mem_SGr_client.show_security_group_rule,
468 SGr['id'])
469 # Create a security group rule to allow 22 (ssh)
470 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
471 direction='ingress',
472 security_group_id=cls.lb_member_sec_group['id'],
473 protocol='tcp',
474 ethertype='IPv4',
475 port_range_min=22,
476 port_range_max=22)['security_group_rule']
477 cls.addClassResourceCleanup(
478 waiters.wait_for_not_found,
479 cls.lb_mem_SGr_client.delete_security_group_rule,
480 cls.lb_mem_SGr_client.show_security_group_rule,
481 SGr['id'])
482 if CONF.load_balancer.test_with_ipv6:
483 # Create a security group rule to allow 80-81 (test webservers)
484 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
485 direction='ingress',
486 security_group_id=cls.lb_member_sec_group['id'],
487 protocol='tcp',
488 ethertype='IPv6',
489 port_range_min=80,
490 port_range_max=81)['security_group_rule']
491 cls.addClassResourceCleanup(
492 waiters.wait_for_not_found,
493 cls.lb_mem_SGr_client.delete_security_group_rule,
494 cls.lb_mem_SGr_client.show_security_group_rule,
495 SGr['id'])
496 # Create a security group rule to allow 22 (ssh)
497 SGr = cls.lb_mem_SGr_client.create_security_group_rule(
498 direction='ingress',
499 security_group_id=cls.lb_member_sec_group['id'],
500 protocol='tcp',
501 ethertype='IPv6',
502 port_range_min=22,
503 port_range_max=22)['security_group_rule']
504 cls.addClassResourceCleanup(
505 waiters.wait_for_not_found,
506 cls.lb_mem_SGr_client.delete_security_group_rule,
507 cls.lb_mem_SGr_client.show_security_group_rule,
508 SGr['id'])
509
510 LOG.info('lb_member_sec_group: {}'.format(cls.lb_member_sec_group))
511
512 # Create webserver 1 instance
513 server_details = cls._create_webserver('lb_member_webserver1',
514 cls.lb_member_1_net)
515
516 cls.lb_member_webserver1 = server_details['server']
517 cls.webserver1_ip = server_details.get('ipv4_address')
518 cls.webserver1_ipv6 = server_details.get('ipv6_address')
519 cls.webserver1_public_ip = server_details['public_ipv4_address']
520
521 LOG.debug('Octavia Setup: lb_member_webserver1 = {}'.format(
522 cls.lb_member_webserver1[const.ID]))
523 LOG.debug('Octavia Setup: webserver1_ip = {}'.format(
524 cls.webserver1_ip))
525 LOG.debug('Octavia Setup: webserver1_ipv6 = {}'.format(
526 cls.webserver1_ipv6))
527 LOG.debug('Octavia Setup: webserver1_public_ip = {}'.format(
528 cls.webserver1_public_ip))
529
530 # Create webserver 2 instance
531 server_details = cls._create_webserver('lb_member_webserver2',
532 cls.lb_member_2_net)
533
534 cls.lb_member_webserver2 = server_details['server']
535 cls.webserver2_ip = server_details.get('ipv4_address')
536 cls.webserver2_ipv6 = server_details.get('ipv6_address')
537 cls.webserver2_public_ip = server_details['public_ipv4_address']
538
539 LOG.debug('Octavia Setup: lb_member_webserver2 = {}'.format(
540 cls.lb_member_webserver2[const.ID]))
541 LOG.debug('Octavia Setup: webserver2_ip = {}'.format(
542 cls.webserver2_ip))
543 LOG.debug('Octavia Setup: webserver2_ipv6 = {}'.format(
544 cls.webserver2_ipv6))
545 LOG.debug('Octavia Setup: webserver2_public_ip = {}'.format(
546 cls.webserver2_public_ip))
547
Michael Johnsonbf916df2018-10-17 10:59:28 -0700548 if CONF.load_balancer.test_with_ipv6:
549 # Enable the IPv6 nic in webserver 1
550 cls._enable_ipv6_nic_webserver(
551 cls.webserver1_public_ip, cls.lb_member_keypair['private_key'],
552 cls.webserver1_ipv6, cls.lb_member_1_subnet_prefix)
553
554 # Enable the IPv6 nic in webserver 2
555 cls._enable_ipv6_nic_webserver(
556 cls.webserver2_public_ip, cls.lb_member_keypair['private_key'],
557 cls.webserver2_ipv6, cls.lb_member_2_subnet_prefix)
558
Adam Harwellcd72b562018-05-07 11:37:22 -0700559 # Set up serving on webserver 1
560 cls._install_start_webserver(cls.webserver1_public_ip,
Adam Harwelle029af22018-05-24 17:13:28 -0700561 cls.lb_member_keypair['private_key'],
562 cls.webserver1_response)
Adam Harwellcd72b562018-05-07 11:37:22 -0700563
564 # Validate webserver 1
Adam Harwelle029af22018-05-24 17:13:28 -0700565 cls._validate_webserver(cls.webserver1_public_ip,
566 cls.webserver1_response)
Adam Harwellcd72b562018-05-07 11:37:22 -0700567
568 # Set up serving on webserver 2
569 cls._install_start_webserver(cls.webserver2_public_ip,
Adam Harwelle029af22018-05-24 17:13:28 -0700570 cls.lb_member_keypair['private_key'],
571 cls.webserver2_response)
Adam Harwellcd72b562018-05-07 11:37:22 -0700572
573 # Validate webserver 2
Adam Harwelle029af22018-05-24 17:13:28 -0700574 cls._validate_webserver(cls.webserver2_public_ip,
575 cls.webserver2_response)
Adam Harwellcd72b562018-05-07 11:37:22 -0700576
577 @classmethod
578 def _create_networks(cls):
579 super(LoadBalancerBaseTestWithCompute, cls)._create_networks()
Jude Cross986e3f52017-07-24 14:57:20 -0700580 # Create a router for the subnets (required for the floating IP)
581 router_name = data_utils.rand_name("lb_member_router")
582 result = cls.lb_mem_routers_client.create_router(
583 name=router_name, admin_state_up=True,
584 external_gateway_info=dict(
585 network_id=CONF.network.public_network_id))
586 cls.lb_member_router = result['router']
587 LOG.info('lb_member_router: {}'.format(cls.lb_member_router))
588 cls.addClassResourceCleanup(
589 waiters.wait_for_not_found,
590 cls.lb_mem_routers_client.delete_router,
591 cls.lb_mem_routers_client.show_router,
592 cls.lb_member_router['id'])
593
594 # Add VIP subnet to router
595 cls.lb_mem_routers_client.add_router_interface(
596 cls.lb_member_router['id'],
597 subnet_id=cls.lb_member_vip_subnet['id'])
598 cls.addClassResourceCleanup(
599 waiters.wait_for_not_found,
600 cls.lb_mem_routers_client.remove_router_interface,
601 cls.lb_mem_routers_client.remove_router_interface,
602 cls.lb_member_router['id'],
603 subnet_id=cls.lb_member_vip_subnet['id'])
604
605 # Add member subnet 1 to router
606 cls.lb_mem_routers_client.add_router_interface(
607 cls.lb_member_router['id'],
608 subnet_id=cls.lb_member_1_subnet['id'])
609 cls.addClassResourceCleanup(
610 waiters.wait_for_not_found,
Jude Cross986e3f52017-07-24 14:57:20 -0700611 cls.lb_mem_routers_client.remove_router_interface,
612 cls.lb_mem_routers_client.remove_router_interface,
613 cls.lb_member_router['id'], subnet_id=cls.lb_member_1_subnet['id'])
614
615 # Add member subnet 2 to router
616 cls.lb_mem_routers_client.add_router_interface(
617 cls.lb_member_router['id'],
618 subnet_id=cls.lb_member_2_subnet['id'])
619 cls.addClassResourceCleanup(
620 waiters.wait_for_not_found,
621 cls.lb_mem_routers_client.remove_router_interface,
622 cls.lb_mem_routers_client.remove_router_interface,
623 cls.lb_member_router['id'], subnet_id=cls.lb_member_2_subnet['id'])
624
625 @classmethod
626 def _create_webserver(cls, name, network):
627 """Creates a webserver with two ports.
628
629 webserver_details dictionary contains:
630 server - The compute server object
631 ipv4_address - The IPv4 address for the server (optional)
632 ipv6_address - The IPv6 address for the server (optional)
633 public_ipv4_address - The publicly accessible IPv4 address for the
634 server, this may be a floating IP (optional)
635
636 :param name: The name of the server to create.
637 :param network: The network to boot the server on.
638 :returns: webserver_details dictionary.
639 """
640 server_kwargs = {
641 'name': data_utils.rand_name(name),
642 'flavorRef': CONF.compute.flavor_ref,
643 'imageRef': CONF.compute.image_ref,
644 'key_name': cls.lb_member_keypair['name']}
645 if (CONF.load_balancer.enable_security_groups and
646 CONF.network_feature_enabled.port_security):
647 server_kwargs['security_groups'] = [
648 {'name': cls.lb_member_sec_group['name']}]
649 if not CONF.load_balancer.disable_boot_network:
650 server_kwargs['networks'] = [{'uuid': network['id']}]
651
652 # Replace the name for clouds that have limitations
653 if CONF.load_balancer.random_server_name_length:
654 r = random.SystemRandom()
655 server_kwargs['name'] = "m{}".format("".join(
656 [r.choice(string.ascii_uppercase + string.digits)
657 for _ in range(
658 CONF.load_balancer.random_server_name_length - 1)]
659 ))
660 if CONF.load_balancer.availability_zone:
661 server_kwargs['availability_zone'] = (
662 CONF.load_balancer.availability_zone)
663
664 server = cls.lb_mem_servers_client.create_server(
665 **server_kwargs)['server']
666 cls.addClassResourceCleanup(
667 waiters.wait_for_not_found,
668 cls.lb_mem_servers_client.delete_server,
669 cls.lb_mem_servers_client.show_server,
670 server['id'])
671 server = waiters.wait_for_status(
672 cls.lb_mem_servers_client.show_server,
673 server['id'], 'status', 'ACTIVE',
674 CONF.load_balancer.build_interval,
675 CONF.load_balancer.build_timeout,
676 root_tag='server')
677 webserver_details = {'server': server}
678 LOG.info('Created server: {}'.format(server))
679
680 addresses = server['addresses']
681 if CONF.load_balancer.disable_boot_network:
682 instance_network = addresses.values()[0]
683 else:
684 instance_network = addresses[network['name']]
685 for addr in instance_network:
686 if addr['version'] == 4:
687 webserver_details['ipv4_address'] = addr['addr']
688 if addr['version'] == 6:
689 webserver_details['ipv6_address'] = addr['addr']
690
691 if CONF.validation.connect_method == 'floating':
692 result = cls.lb_mem_ports_client.list_ports(
693 network_id=network['id'],
694 mac_address=instance_network[0]['OS-EXT-IPS-MAC:mac_addr'])
695 port_id = result['ports'][0]['id']
696 result = cls.lb_mem_float_ip_client.create_floatingip(
697 floating_network_id=CONF.network.public_network_id,
698 port_id=port_id)
699 floating_ip = result['floatingip']
700 LOG.info('webserver1_floating_ip: {}'.format(floating_ip))
701 cls.addClassResourceCleanup(
702 waiters.wait_for_not_found,
703 cls.lb_mem_float_ip_client.delete_floatingip,
704 cls.lb_mem_float_ip_client.show_floatingip,
705 floatingip_id=floating_ip['id'])
706 webserver_details['public_ipv4_address'] = (
707 floating_ip['floating_ip_address'])
708 else:
709 webserver_details['public_ipv4_address'] = (
710 instance_network[0]['addr'])
711
712 return webserver_details
713
714 @classmethod
Adam Harwellcd72b562018-05-07 11:37:22 -0700715 def _install_start_webserver(cls, ip_address, ssh_key, start_id):
716 local_file = pkg_resources.resource_filename(
717 'octavia_tempest_plugin.contrib.httpd', 'httpd.bin')
718 dest_file = '/dev/shm/httpd.bin'
719
720 linux_client = remote_client.RemoteClient(
721 ip_address, CONF.validation.image_ssh_user, pkey=ssh_key)
722 linux_client.validate_authentication()
723
724 with tempfile.NamedTemporaryFile() as key:
725 key.write(ssh_key.encode('utf-8'))
726 key.flush()
727 cmd = ("scp -v -o UserKnownHostsFile=/dev/null "
728 "-o StrictHostKeyChecking=no "
729 "-o ConnectTimeout={0} -o ConnectionAttempts={1} "
730 "-i {2} {3} {4}@{5}:{6}").format(
731 CONF.load_balancer.scp_connection_timeout,
732 CONF.load_balancer.scp_connection_attempts,
733 key.name, local_file, CONF.validation.image_ssh_user,
734 ip_address, dest_file)
735 args = shlex.split(cmd)
736 subprocess_args = {'stdout': subprocess.PIPE,
737 'stderr': subprocess.STDOUT,
738 'cwd': None}
739 proc = subprocess.Popen(args, **subprocess_args)
740 stdout, stderr = proc.communicate()
741 if proc.returncode != 0:
742 raise exceptions.CommandFailed(proc.returncode, cmd,
743 stdout, stderr)
744 linux_client.exec_command('sudo screen -d -m {0} -port 80 '
745 '-id {1}'.format(dest_file, start_id))
746 linux_client.exec_command('sudo screen -d -m {0} -port 81 '
747 '-id {1}'.format(dest_file, start_id + 1))
748
Michael Johnsonbf916df2018-10-17 10:59:28 -0700749 # Cirros does not configure the assigned IPv6 address by default
750 # so enable it manually like tempest does here:
751 # tempest/scenario/test_netowrk_v6.py turn_nic6_on()
752 @classmethod
753 def _enable_ipv6_nic_webserver(cls, ip_address, ssh_key,
754 ipv6_address, ipv6_prefix):
755 linux_client = remote_client.RemoteClient(
756 ip_address, CONF.validation.image_ssh_user, pkey=ssh_key)
757 linux_client.validate_authentication()
758
759 linux_client.exec_command('sudo ip address add {0}/{1} dev '
760 'eth0'.format(ipv6_address, ipv6_prefix))
761
Adam Harwellcd72b562018-05-07 11:37:22 -0700762 @classmethod
Jude Cross986e3f52017-07-24 14:57:20 -0700763 def _validate_webserver(cls, ip_address, start_id):
764 URL = 'http://{0}'.format(ip_address)
765 validators.validate_URL_response(URL, expected_body=str(start_id))
766 URL = 'http://{0}:81'.format(ip_address)
767 validators.validate_URL_response(URL, expected_body=str(start_id + 1))
768
Adam Harwellcd72b562018-05-07 11:37:22 -0700769 def _wait_for_lb_functional(self, vip_address):
770 session = requests.Session()
771 start = time.time()
772
773 while time.time() - start < CONF.load_balancer.build_timeout:
774 try:
775 session.get("http://{0}".format(vip_address), timeout=2)
776 time.sleep(1)
777 return
778 except Exception:
779 LOG.warning('Server is not passing initial traffic. Waiting.')
780 time.sleep(1)
781 LOG.error('Server did not begin passing traffic within the timeout '
782 'period. Failing test.')
783 raise Exception()
784
Adam Harwelle029af22018-05-24 17:13:28 -0700785 def check_members_balanced(self, vip_address, traffic_member_count=2):
Adam Harwellcd72b562018-05-07 11:37:22 -0700786 session = requests.Session()
787 response_counts = {}
788
Michael Johnson5a16ad32018-10-18 14:49:11 -0700789 if ipaddress.ip_address(vip_address).version == 6:
790 vip_address = '[{}]'.format(vip_address)
791
Adam Harwellcd72b562018-05-07 11:37:22 -0700792 self._wait_for_lb_functional(vip_address)
793
794 # Send a number requests to lb vip
795 for i in range(20):
796 try:
797 r = session.get('http://{0}'.format(vip_address),
798 timeout=2)
799
800 if r.content in response_counts:
801 response_counts[r.content] += 1
802 else:
803 response_counts[r.content] = 1
804
805 except Exception:
806 LOG.exception('Failed to send request to loadbalancer vip')
807 raise Exception('Failed to connect to lb')
808
809 LOG.debug('Loadbalancer response totals: %s', response_counts)
810 # Ensure the correct number of members
Adam Harwell60ed9d92018-05-10 13:23:13 -0700811 self.assertEqual(traffic_member_count, len(response_counts))
Adam Harwellcd72b562018-05-07 11:37:22 -0700812
813 # Ensure both members got the same number of responses
814 self.assertEqual(1, len(set(response_counts.values())))
Adam Harwelle029af22018-05-24 17:13:28 -0700815
816 def assertConsistentResponse(self, response, url, method='GET', repeat=10,
817 redirect=False, timeout=2, **kwargs):
818 """Assert that a request to URL gets the expected response.
819
820 :param response: Expected response in format (status_code, content).
821 :param url: The URL to request.
822 :param method: The HTTP method to use (GET, POST, PUT, etc)
823 :param repeat: How many times to test the response.
824 :param data: Optional data to send in the request.
825 :param headers: Optional headers to send in the request.
826 :param cookies: Optional cookies to send in the request.
827 :param redirect: Is the request a redirect? If true, assume the passed
828 content should be the next URL in the chain.
Carlos Goncalvesc451ff92018-12-19 19:11:53 +0100829 :param timeout: Optional seconds to wait for the server to send data.
830
Adam Harwelle029af22018-05-24 17:13:28 -0700831 :return: boolean success status
832
833 :raises: testtools.matchers.MismatchError
834 """
835 session = requests.Session()
836 response_code, response_content = response
837
838 for i in range(0, repeat):
839 req = session.request(method, url, allow_redirects=not redirect,
840 timeout=timeout, **kwargs)
841 if response_code:
842 self.assertEqual(response_code, req.status_code)
843 if redirect:
844 self.assertTrue(req.is_redirect)
Carlos Goncalvesc451ff92018-12-19 19:11:53 +0100845 self.assertEqual(response_content,
846 session.get_redirect_target(req))
Adam Harwelle029af22018-05-24 17:13:28 -0700847 elif response_content:
848 self.assertEqual(six.text_type(response_content), req.text)