blob: 85d048addcbe1e3ca8b4589f103a80edd4565862 [file] [log] [blame]
Itzik Browne67ebb52016-05-15 05:34:41 +00001# Copyright 2016 Red Hat, Inc.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
Slawek Kaplonskiaf83e832020-02-05 12:11:54 +010015import distutils
16import re
Chandan Kumarc125fd12017-11-15 19:41:01 +053017import subprocess
Itzik Browne67ebb52016-05-15 05:34:41 +000018
Federico Ressibf877c82018-08-22 08:36:37 +020019from debtcollector import removals
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090020import netaddr
Assaf Muller92fdc782018-05-31 10:32:47 -040021from neutron_lib.api import validators
22from neutron_lib import constants as neutron_lib_constants
Alex Stafeyevc4d9c352016-12-12 04:13:33 -050023from oslo_log import log
Genadi Chereshnya6d10c6e2017-07-05 11:34:20 +030024from tempest.common.utils import net_utils
Itzik Browne67ebb52016-05-15 05:34:41 +000025from tempest.common import waiters
Itzik Browne67ebb52016-05-15 05:34:41 +000026from tempest.lib.common.utils import data_utils
YAMAMOTO Takashi25935722017-01-23 15:34:11 +090027from tempest.lib.common.utils import test_utils
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -050028from tempest.lib import exceptions as lib_exc
Itzik Browne67ebb52016-05-15 05:34:41 +000029
Chandan Kumar667d3d32017-09-22 12:24:06 +053030from neutron_tempest_plugin.api import base as base_api
Rodolfo Alonso Hernandez4849f002020-01-16 16:01:10 +000031from neutron_tempest_plugin.common import ip as ip_utils
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +020032from neutron_tempest_plugin.common import shell
Chandan Kumar667d3d32017-09-22 12:24:06 +053033from neutron_tempest_plugin.common import ssh
Slawek Kaplonskifd4141f2020-03-14 14:34:00 +010034from neutron_tempest_plugin.common import utils
Chandan Kumar667d3d32017-09-22 12:24:06 +053035from neutron_tempest_plugin import config
Slawek Kaplonskiaf83e832020-02-05 12:11:54 +010036from neutron_tempest_plugin import exceptions
Chandan Kumar667d3d32017-09-22 12:24:06 +053037from neutron_tempest_plugin.scenario import constants
Itzik Browne67ebb52016-05-15 05:34:41 +000038
39CONF = config.CONF
Itzik Browne67ebb52016-05-15 05:34:41 +000040
Alex Stafeyevc4d9c352016-12-12 04:13:33 -050041LOG = log.getLogger(__name__)
42
Itzik Browne67ebb52016-05-15 05:34:41 +000043
Slawek Kaplonskiaf83e832020-02-05 12:11:54 +010044def get_ncat_version(ssh_client=None):
45 cmd = "ncat --version 2>&1"
46 try:
47 version_result = shell.execute(cmd, ssh_client=ssh_client).stdout
48 except exceptions.ShellCommandFailed:
49 m = None
50 else:
51 m = re.match(r"Ncat: Version ([\d.]+) *.", version_result)
52 # NOTE(slaweq): by default lets assume we have ncat 7.60 which is in Ubuntu
53 # 18.04 which is used on u/s gates
54 return distutils.version.StrictVersion(m.group(1) if m else '7.60')
55
56
Slawek Kaplonskifd4141f2020-03-14 14:34:00 +010057def get_ncat_server_cmd(port, protocol, msg=None):
Slawek Kaplonskiaf83e832020-02-05 12:11:54 +010058 udp = ''
59 if protocol.lower() == neutron_lib_constants.PROTO_NAME_UDP:
60 udp = '-u'
61 cmd = "nc %(udp)s -p %(port)s -lk " % {
62 'udp': udp, 'port': port}
Slawek Kaplonskifd4141f2020-03-14 14:34:00 +010063 if msg:
64 if CONF.neutron_plugin_options.default_image_is_advanced:
Flavio Fernandesb056ac22020-07-01 14:57:13 -040065 cmd += "-c 'echo %s' " % msg
Slawek Kaplonskifd4141f2020-03-14 14:34:00 +010066 else:
Flavio Fernandesb056ac22020-07-01 14:57:13 -040067 cmd += "-e echo %s " % msg
68 cmd += "< /dev/zero &{0}sleep 0.1{0}".format('\n')
Slawek Kaplonskiaf83e832020-02-05 12:11:54 +010069 return cmd
70
71
72def get_ncat_client_cmd(ip_address, port, protocol):
73 udp = ''
74 if protocol.lower() == neutron_lib_constants.PROTO_NAME_UDP:
75 udp = '-u'
76 cmd = 'echo "knock knock" | nc '
77 ncat_version = get_ncat_version()
78 if ncat_version > distutils.version.StrictVersion('7.60'):
79 cmd += '-z '
80 cmd += '-w 1 %(udp)s %(host)s %(port)s' % {
81 'udp': udp, 'host': ip_address, 'port': port}
82 return cmd
83
84
Itzik Browne67ebb52016-05-15 05:34:41 +000085class BaseTempestTestCase(base_api.BaseNetworkTest):
Itzik Browne67ebb52016-05-15 05:34:41 +000086
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +000087 def create_server(self, flavor_ref, image_ref, key_name, networks,
Roee Agiman6a0a18a2017-11-16 11:51:56 +020088 **kwargs):
Itzik Brownbac51dc2016-10-31 12:25:04 +000089 """Create a server using tempest lib
Brian Haleyaee61ac2018-10-09 20:00:27 -040090
Itzik Brownbac51dc2016-10-31 12:25:04 +000091 All the parameters are the ones used in Compute API
Roee Agiman6a0a18a2017-11-16 11:51:56 +020092 * - Kwargs that require admin privileges
Itzik Brownbac51dc2016-10-31 12:25:04 +000093
94 Args:
95 flavor_ref(str): The flavor of the server to be provisioned.
96 image_ref(str): The image of the server to be provisioned.
97 key_name(str): SSH key to to be used to connect to the
98 provisioned server.
99 networks(list): List of dictionaries where each represent
100 an interface to be attached to the server. For network
101 it should be {'uuid': network_uuid} and for port it should
102 be {'port': port_uuid}
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200103 kwargs:
Itzik Brownbac51dc2016-10-31 12:25:04 +0000104 name(str): Name of the server to be provisioned.
105 security_groups(list): List of dictionaries where
106 the keys is 'name' and the value is the name of
107 the security group. If it's not passed the default
108 security group will be used.
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200109 availability_zone(str)*: The availability zone that
110 the instance will be in.
111 You can request a specific az without actually creating one,
112 Just pass 'X:Y' where X is the default availability
113 zone, and Y is the compute host name.
Itzik Brownbac51dc2016-10-31 12:25:04 +0000114 """
115
Jakub Libosvarffd9b912017-11-16 09:54:14 +0000116 kwargs.setdefault('name', data_utils.rand_name('server-test'))
Itzik Brownbac51dc2016-10-31 12:25:04 +0000117
Jakub Libosvarffd9b912017-11-16 09:54:14 +0000118 # We cannot use setdefault() here because caller could have passed
119 # security_groups=None and we don't want to pass None to
120 # client.create_server()
121 if not kwargs.get('security_groups'):
122 kwargs['security_groups'] = [{'name': 'default'}]
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200123
Jakub Libosvarffd9b912017-11-16 09:54:14 +0000124 client = self.os_primary.servers_client
125 if kwargs.get('availability_zone'):
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200126 client = self.os_admin.servers_client
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200127
Jakub Libosvarffd9b912017-11-16 09:54:14 +0000128 server = client.create_server(
129 flavorRef=flavor_ref,
130 imageRef=image_ref,
131 key_name=key_name,
132 networks=networks,
133 **kwargs)
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000134
135 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200136 waiters.wait_for_server_termination,
137 client,
138 server['server']['id'])
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000139 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200140 client.delete_server,
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000141 server['server']['id'])
Itzik Browne67ebb52016-05-15 05:34:41 +0000142 return server
143
144 @classmethod
Jens Harbott54357632017-11-21 11:47:06 +0000145 def create_secgroup_rules(cls, rule_list, secgroup_id=None,
146 client=None):
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200147 client = client or cls.os_primary.network_client
Itzik Browne67ebb52016-05-15 05:34:41 +0000148 if not secgroup_id:
149 sgs = client.list_security_groups()['security_groups']
150 for sg in sgs:
151 if sg['name'] == constants.DEFAULT_SECURITY_GROUP:
152 secgroup_id = sg['id']
153 break
154
Itzik Brown1ef813a2016-06-06 12:56:21 +0000155 for rule in rule_list:
156 direction = rule.pop('direction')
157 client.create_security_group_rule(
158 direction=direction,
159 security_group_id=secgroup_id,
160 **rule)
161
162 @classmethod
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200163 def create_loginable_secgroup_rule(cls, secgroup_id=None,
164 client=None):
Itzik Brown1ef813a2016-06-06 12:56:21 +0000165 """This rule is intended to permit inbound ssh
166
167 Allowing ssh traffic traffic from all sources, so no group_id is
168 provided.
169 Setting a group_id would only permit traffic from ports
170 belonging to the same security group.
171 """
Federico Ressi4c590d72018-10-10 14:01:08 +0200172 return cls.create_security_group_rule(
173 security_group_id=secgroup_id,
174 client=client,
175 protocol=neutron_lib_constants.PROTO_NAME_TCP,
176 direction=neutron_lib_constants.INGRESS_DIRECTION,
177 port_range_min=22,
178 port_range_max=22)
Itzik Browne67ebb52016-05-15 05:34:41 +0000179
180 @classmethod
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200181 def create_pingable_secgroup_rule(cls, secgroup_id=None,
182 client=None):
Federico Ressi4c590d72018-10-10 14:01:08 +0200183 """This rule is intended to permit inbound ping
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900184
Federico Ressi4c590d72018-10-10 14:01:08 +0200185 """
186 return cls.create_security_group_rule(
187 security_group_id=secgroup_id, client=client,
188 protocol=neutron_lib_constants.PROTO_NAME_ICMP,
189 direction=neutron_lib_constants.INGRESS_DIRECTION)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900190
191 @classmethod
Genadi Chereshnyac0411e92016-07-11 16:59:42 +0300192 def create_router_by_client(cls, is_admin=False, **kwargs):
193 kwargs.update({'router_name': data_utils.rand_name('router'),
194 'admin_state_up': True,
195 'external_network_id': CONF.network.public_network_id})
196 if not is_admin:
197 router = cls.create_router(**kwargs)
198 else:
199 router = cls.create_admin_router(**kwargs)
Alex Stafeyevc4d9c352016-12-12 04:13:33 -0500200 LOG.debug("Created router %s", router['name'])
Itzik Browne67ebb52016-05-15 05:34:41 +0000201 cls.routers.append(router)
202 return router
203
Federico Ressibf877c82018-08-22 08:36:37 +0200204 @removals.remove(version='Stein',
205 message="Please use create_floatingip method instead of "
206 "create_and_associate_floatingip.")
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200207 def create_and_associate_floatingip(self, port_id, client=None):
208 client = client or self.os_primary.network_client
Federico Ressibf877c82018-08-22 08:36:37 +0200209 return self.create_floatingip(port_id=port_id, client=client)
Itzik Browne67ebb52016-05-15 05:34:41 +0000210
Hongbin Lu965b03d2018-04-25 22:32:30 +0000211 def create_interface(cls, server_id, port_id, client=None):
212 client = client or cls.os_primary.interfaces_client
213 body = client.create_interface(server_id, port_id=port_id)
214 return body['interfaceAttachment']
215
216 def delete_interface(cls, server_id, port_id, client=None):
217 client = client or cls.os_primary.interfaces_client
218 client.delete_interface(server_id, port_id=port_id)
219
Brian Haleyd11f4ec2019-08-13 12:09:57 -0400220 def setup_network_and_server(self, router=None, server_name=None,
221 network=None, **kwargs):
Genadi Chereshnyac0411e92016-07-11 16:59:42 +0300222 """Create network resources and a server.
Itzik Brownbac51dc2016-10-31 12:25:04 +0000223
224 Creating a network, subnet, router, keypair, security group
225 and a server.
226 """
Assaf Mullerd54ae6c2018-05-31 11:38:00 -0400227 self.network = network or self.create_network()
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000228 LOG.debug("Created network %s", self.network['name'])
229 self.subnet = self.create_subnet(self.network)
230 LOG.debug("Created subnet %s", self.subnet['id'])
Itzik Brown1ef813a2016-06-06 12:56:21 +0000231
Brian Haleyf86ac2e2017-06-21 10:43:50 -0400232 secgroup = self.os_primary.network_client.create_security_group(
Chandan Kumarc125fd12017-11-15 19:41:01 +0530233 name=data_utils.rand_name('secgroup'))
Alex Stafeyevc4d9c352016-12-12 04:13:33 -0500234 LOG.debug("Created security group %s",
235 secgroup['security_group']['name'])
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000236 self.security_groups.append(secgroup['security_group'])
Genadi Chereshnyac0411e92016-07-11 16:59:42 +0300237 if not router:
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000238 router = self.create_router_by_client(**kwargs)
239 self.create_router_interface(router['id'], self.subnet['id'])
240 self.keypair = self.create_keypair()
241 self.create_loginable_secgroup_rule(
Itzik Brownbac51dc2016-10-31 12:25:04 +0000242 secgroup_id=secgroup['security_group']['id'])
Assaf Muller92fdc782018-05-31 10:32:47 -0400243
244 server_kwargs = {
245 'flavor_ref': CONF.compute.flavor_ref,
246 'image_ref': CONF.compute.image_ref,
247 'key_name': self.keypair['name'],
248 'networks': [{'uuid': self.network['id']}],
249 'security_groups': [{'name': secgroup['security_group']['name']}],
250 }
251 if server_name is not None:
252 server_kwargs['name'] = server_name
253
254 self.server = self.create_server(**server_kwargs)
Federico Ressie7417b72018-05-30 05:50:58 +0200255 self.wait_for_server_active(self.server['server'])
Jakub Libosvar1345d9d2017-06-09 13:59:05 +0000256 self.port = self.client.list_ports(network_id=self.network['id'],
257 device_id=self.server[
258 'server']['id'])['ports'][0]
Federico Ressibf877c82018-08-22 08:36:37 +0200259 self.fip = self.create_floatingip(port=self.port)
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500260
Eduardo Olivares3eb12282020-05-29 16:43:31 +0200261 def check_connectivity(self, host, ssh_user, ssh_key,
262 servers=None, ssh_timeout=None):
263 ssh_client = ssh.Client(host, ssh_user,
264 pkey=ssh_key, timeout=ssh_timeout)
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500265 try:
266 ssh_client.test_connection_auth()
267 except lib_exc.SSHTimeout as ssh_e:
268 LOG.debug(ssh_e)
269 self._log_console_output(servers)
Rodolfo Alonso Hernandez4849f002020-01-16 16:01:10 +0000270 self._log_local_network_status()
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500271 raise
272
273 def _log_console_output(self, servers=None):
274 if not CONF.compute_feature_enabled.console_output:
275 LOG.debug('Console output not supported, cannot log')
276 return
277 if not servers:
Brian Haleyf86ac2e2017-06-21 10:43:50 -0400278 servers = self.os_primary.servers_client.list_servers()
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500279 servers = servers['servers']
280 for server in servers:
Slawek Kaplonskicff79232020-03-03 14:12:18 +0100281 # NOTE(slaweq): sometimes servers are passed in dictionary with
282 # "server" key as first level key and in other cases it may be that
283 # it is just the "inner" dict without "server" key. Lets try to
284 # handle both cases
285 server = server.get("server") or server
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500286 try:
287 console_output = (
Brian Haleyf86ac2e2017-06-21 10:43:50 -0400288 self.os_primary.servers_client.get_console_output(
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500289 server['id'])['output'])
290 LOG.debug('Console output for %s\nbody=\n%s',
291 server['id'], console_output)
292 except lib_exc.NotFound:
293 LOG.debug("Server %s disappeared(deleted) while looking "
294 "for the console log", server['id'])
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900295
Rodolfo Alonso Hernandez4849f002020-01-16 16:01:10 +0000296 def _log_local_network_status(self):
Slawek Kaplonski8033af72020-05-05 12:01:37 +0200297 self._log_ns_network_status()
298 for ns_name in ip_utils.IPCommand().list_namespaces():
299 self._log_ns_network_status(ns_name=ns_name)
300
301 def _log_ns_network_status(self, ns_name=None):
302 local_ips = ip_utils.IPCommand(namespace=ns_name).list_addresses()
303 LOG.debug('Namespace %s; IP Addresses:\n%s',
304 ns_name, '\n'.join(str(r) for r in local_ips))
305 local_routes = ip_utils.IPCommand(namespace=ns_name).list_routes()
306 LOG.debug('Namespace %s; Local routes:\n%s',
307 ns_name, '\n'.join(str(r) for r in local_routes))
Rodolfo Alonso Hernandez4849f002020-01-16 16:01:10 +0000308 arp_table = ip_utils.arp_table()
Slawek Kaplonski8033af72020-05-05 12:01:37 +0200309 LOG.debug('Namespace %s; Local ARP table:\n%s',
310 ns_name, '\n'.join(str(r) for r in arp_table))
Rodolfo Alonso Hernandez4849f002020-01-16 16:01:10 +0000311
LIU Yulong68ab2452019-05-18 10:19:49 +0800312 def _check_remote_connectivity(self, source, dest, count,
313 should_succeed=True,
Assaf Muller92fdc782018-05-31 10:32:47 -0400314 nic=None, mtu=None, fragmentation=True,
Roman Safronov12663cf2020-07-27 13:11:07 +0300315 timeout=None, pattern=None,
316 forbid_packet_loss=False):
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900317 """check ping server via source ssh connection
318
319 :param source: RemoteClient: an ssh connection from which to ping
320 :param dest: and IP to ping against
LIU Yulong68ab2452019-05-18 10:19:49 +0800321 :param count: Number of ping packet(s) to send
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900322 :param should_succeed: boolean should ping succeed or not
323 :param nic: specific network interface to ping from
Genadi Chereshnya6d10c6e2017-07-05 11:34:20 +0300324 :param mtu: mtu size for the packet to be sent
325 :param fragmentation: Flag for packet fragmentation
LIU Yulong68ab2452019-05-18 10:19:49 +0800326 :param timeout: Timeout for all ping packet(s) to succeed
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100327 :param pattern: hex digits included in ICMP messages
Roman Safronov12663cf2020-07-27 13:11:07 +0300328 :param forbid_packet_loss: forbid or allow some lost packets
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900329 :returns: boolean -- should_succeed == ping
330 :returns: ping is false if ping failed
331 """
LIU Yulong68ab2452019-05-18 10:19:49 +0800332 def ping_host(source, host, count,
Genadi Chereshnya6d10c6e2017-07-05 11:34:20 +0300333 size=CONF.validation.ping_size, nic=None, mtu=None,
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100334 fragmentation=True, pattern=None):
Assaf Muller92fdc782018-05-31 10:32:47 -0400335 IP_VERSION_4 = neutron_lib_constants.IP_VERSION_4
336 IP_VERSION_6 = neutron_lib_constants.IP_VERSION_6
337
338 # Use 'ping6' for IPv6 addresses, 'ping' for IPv4 and hostnames
339 ip_version = (
340 IP_VERSION_6 if netaddr.valid_ipv6(host) else IP_VERSION_4)
341 cmd = (
342 'ping6' if ip_version == IP_VERSION_6 else 'ping')
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900343 if nic:
344 cmd = 'sudo {cmd} -I {nic}'.format(cmd=cmd, nic=nic)
Genadi Chereshnya6d10c6e2017-07-05 11:34:20 +0300345 if mtu:
346 if not fragmentation:
347 cmd += ' -M do'
348 size = str(net_utils.get_ping_payload_size(
Assaf Muller92fdc782018-05-31 10:32:47 -0400349 mtu=mtu, ip_version=ip_version))
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100350 if pattern:
351 cmd += ' -p {pattern}'.format(pattern=pattern)
Maciej Józefczyk3c324e02020-03-16 10:52:08 +0000352 cmd += ' -c{0} -W{0} -s{1} {2}'.format(count, size, host)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900353 return source.exec_command(cmd)
354
355 def ping_remote():
356 try:
LIU Yulong68ab2452019-05-18 10:19:49 +0800357 result = ping_host(source, dest, count, nic=nic, mtu=mtu,
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100358 fragmentation=fragmentation,
359 pattern=pattern)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900360
361 except lib_exc.SSHExecCommandFailed:
362 LOG.warning('Failed to ping IP: %s via a ssh connection '
363 'from: %s.', dest, source.host)
364 return not should_succeed
365 LOG.debug('ping result: %s', result)
Assaf Muller92fdc782018-05-31 10:32:47 -0400366
Roman Safronov12663cf2020-07-27 13:11:07 +0300367 if forbid_packet_loss and ' 0% packet loss' not in result:
368 LOG.debug('Packet loss detected')
369 return not should_succeed
370
Assaf Muller92fdc782018-05-31 10:32:47 -0400371 if validators.validate_ip_address(dest) is None:
372 # Assert that the return traffic was from the correct
373 # source address.
374 from_source = 'from %s' % dest
375 self.assertIn(from_source, result)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900376 return should_succeed
377
Assaf Muller92fdc782018-05-31 10:32:47 -0400378 return test_utils.call_until_true(
379 ping_remote, timeout or CONF.validation.ping_timeout, 1)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900380
381 def check_remote_connectivity(self, source, dest, should_succeed=True,
Slawek Kaplonskib07251f2018-05-16 12:21:50 +0200382 nic=None, mtu=None, fragmentation=True,
LIU Yulong68ab2452019-05-18 10:19:49 +0800383 servers=None, timeout=None,
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100384 ping_count=CONF.validation.ping_count,
Roman Safronov12663cf2020-07-27 13:11:07 +0300385 pattern=None, forbid_packet_loss=False):
Slawek Kaplonskib07251f2018-05-16 12:21:50 +0200386 try:
387 self.assertTrue(self._check_remote_connectivity(
LIU Yulong68ab2452019-05-18 10:19:49 +0800388 source, dest, ping_count, should_succeed, nic, mtu,
389 fragmentation,
Roman Safronov12663cf2020-07-27 13:11:07 +0300390 timeout=timeout, pattern=pattern,
391 forbid_packet_loss=forbid_packet_loss))
Slawek Kaplonskib07251f2018-05-16 12:21:50 +0200392 except lib_exc.SSHTimeout as ssh_e:
393 LOG.debug(ssh_e)
394 self._log_console_output(servers)
Slawek Kaplonski8033af72020-05-05 12:01:37 +0200395 self._log_local_network_status()
Slawek Kaplonskib07251f2018-05-16 12:21:50 +0200396 raise
397 except AssertionError:
398 self._log_console_output(servers)
Slawek Kaplonski8033af72020-05-05 12:01:37 +0200399 self._log_local_network_status()
Slawek Kaplonskib07251f2018-05-16 12:21:50 +0200400 raise
Chandan Kumarc125fd12017-11-15 19:41:01 +0530401
402 def ping_ip_address(self, ip_address, should_succeed=True,
403 ping_timeout=None, mtu=None):
404 # the code is taken from tempest/scenario/manager.py in tempest git
405 timeout = ping_timeout or CONF.validation.ping_timeout
406 cmd = ['ping', '-c1', '-w1']
407
408 if mtu:
409 cmd += [
410 # don't fragment
411 '-M', 'do',
412 # ping receives just the size of ICMP payload
413 '-s', str(net_utils.get_ping_payload_size(mtu, 4))
414 ]
415 cmd.append(ip_address)
416
417 def ping():
418 proc = subprocess.Popen(cmd,
419 stdout=subprocess.PIPE,
420 stderr=subprocess.PIPE)
421 proc.communicate()
422
423 return (proc.returncode == 0) == should_succeed
424
425 caller = test_utils.find_test_caller()
426 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
427 ' expected result is %(should_succeed)s', {
428 'caller': caller, 'ip': ip_address, 'timeout': timeout,
429 'should_succeed':
430 'reachable' if should_succeed else 'unreachable'
431 })
432 result = test_utils.call_until_true(ping, timeout, 1)
Manjeet Singh Bhatia8bbf8992019-03-04 11:59:57 -0800433
434 # To make sure ping_ip_address called by test works
435 # as expected.
436 self.assertTrue(result)
437
Chandan Kumarc125fd12017-11-15 19:41:01 +0530438 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
439 'ping result is %(result)s', {
440 'caller': caller, 'ip': ip_address, 'timeout': timeout,
441 'result': 'expected' if result else 'unexpected'
442 })
443 return result
Federico Ressie7417b72018-05-30 05:50:58 +0200444
445 def wait_for_server_status(self, server, status, client=None, **kwargs):
446 """Waits for a server to reach a given status.
447
448 :param server: mapping having schema {'id': <server_id>}
449 :param status: string status to wait for (es: 'ACTIVE')
450 :param clien: servers client (self.os_primary.servers_client as
451 default value)
452 """
453
454 client = client or self.os_primary.servers_client
455 waiters.wait_for_server_status(client, server['id'], status, **kwargs)
456
457 def wait_for_server_active(self, server, client=None):
458 """Waits for a server to reach active status.
459
460 :param server: mapping having schema {'id': <server_id>}
461 :param clien: servers client (self.os_primary.servers_client as
462 default value)
463 """
464 self.wait_for_server_status(
465 server, constants.SERVER_STATUS_ACTIVE, client)
Jakub Libosvar031fd5a2019-07-15 16:10:07 +0000466
nfridmand8969542020-06-02 14:59:09 +0300467 def check_servers_hostnames(self, servers, timeout=None, log_errors=True):
Jakub Libosvar031fd5a2019-07-15 16:10:07 +0000468 """Compare hostnames of given servers with their names."""
469 try:
470 for server in servers:
471 kwargs = {}
nfridmand8969542020-06-02 14:59:09 +0300472 if timeout:
473 kwargs['timeout'] = timeout
Jakub Libosvar031fd5a2019-07-15 16:10:07 +0000474 try:
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200475 kwargs['port'] = (
476 server['port_forwarding_tcp']['external_port'])
Jakub Libosvar031fd5a2019-07-15 16:10:07 +0000477 except KeyError:
478 pass
479 ssh_client = ssh.Client(
480 self.fip['floating_ip_address'],
481 CONF.validation.image_ssh_user,
482 pkey=self.keypair['private_key'],
483 **kwargs)
484 self.assertIn(server['name'],
485 ssh_client.exec_command('hostname'))
486 except lib_exc.SSHTimeout as ssh_e:
487 LOG.debug(ssh_e)
488 if log_errors:
489 self._log_console_output(servers)
Slawek Kaplonski8033af72020-05-05 12:01:37 +0200490 self._log_local_network_status()
Jakub Libosvar031fd5a2019-07-15 16:10:07 +0000491 raise
492 except AssertionError as assert_e:
493 LOG.debug(assert_e)
494 if log_errors:
495 self._log_console_output(servers)
Slawek Kaplonski8033af72020-05-05 12:01:37 +0200496 self._log_local_network_status()
Jakub Libosvar031fd5a2019-07-15 16:10:07 +0000497 raise
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200498
Slawek Kaplonskifd4141f2020-03-14 14:34:00 +0100499 def ensure_nc_listen(self, ssh_client, port, protocol, echo_msg=None,
500 servers=None):
501 """Ensure that nc server listening on the given TCP/UDP port is up.
502
503 Listener is created always on remote host.
504 """
505 def spawn_and_check_process():
506 self.nc_listen(ssh_client, port, protocol, echo_msg, servers)
507 return utils.process_is_running(ssh_client, "nc")
508
509 utils.wait_until_true(spawn_and_check_process)
510
511 def nc_listen(self, ssh_client, port, protocol, echo_msg=None,
512 servers=None):
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200513 """Create nc server listening on the given TCP/UDP port.
514
515 Listener is created always on remote host.
516 """
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200517 try:
Slawek Kaplonskiaf83e832020-02-05 12:11:54 +0100518 return ssh_client.execute_script(
519 get_ncat_server_cmd(port, protocol, echo_msg),
Flavio Fernandesb056ac22020-07-01 14:57:13 -0400520 become_root=True, combine_stderr=True)
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200521 except lib_exc.SSHTimeout as ssh_e:
522 LOG.debug(ssh_e)
Slawek Kaplonskifd4141f2020-03-14 14:34:00 +0100523 self._log_console_output(servers)
Slawek Kaplonski8033af72020-05-05 12:01:37 +0200524 self._log_local_network_status()
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200525 raise
526
527 def nc_client(self, ip_address, port, protocol):
528 """Check connectivity to TCP/UDP port at host via nc.
529
530 Client is always executed locally on host where tests are executed.
531 """
Slawek Kaplonskiaf83e832020-02-05 12:11:54 +0100532 cmd = get_ncat_client_cmd(ip_address, port, protocol)
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200533 result = shell.execute_local_command(cmd)
534 self.assertEqual(0, result.exit_status)
535 return result.stdout