blob: 35e5c311d9fa2799f021b7d1de6e0f7543c1730f [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:
65 cmd += "-c 'echo %s' &" % msg
66 else:
67 cmd += "-e echo %s &" % msg
Slawek Kaplonskiaf83e832020-02-05 12:11:54 +010068 else:
Slawek Kaplonskifd4141f2020-03-14 14:34:00 +010069 cmd += "< /dev/zero &"
Slawek Kaplonskiaf83e832020-02-05 12:11:54 +010070 return cmd
71
72
73def get_ncat_client_cmd(ip_address, port, protocol):
74 udp = ''
75 if protocol.lower() == neutron_lib_constants.PROTO_NAME_UDP:
76 udp = '-u'
77 cmd = 'echo "knock knock" | nc '
78 ncat_version = get_ncat_version()
79 if ncat_version > distutils.version.StrictVersion('7.60'):
80 cmd += '-z '
81 cmd += '-w 1 %(udp)s %(host)s %(port)s' % {
82 'udp': udp, 'host': ip_address, 'port': port}
83 return cmd
84
85
Itzik Browne67ebb52016-05-15 05:34:41 +000086class BaseTempestTestCase(base_api.BaseNetworkTest):
Itzik Browne67ebb52016-05-15 05:34:41 +000087
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +000088 def create_server(self, flavor_ref, image_ref, key_name, networks,
Roee Agiman6a0a18a2017-11-16 11:51:56 +020089 **kwargs):
Itzik Brownbac51dc2016-10-31 12:25:04 +000090 """Create a server using tempest lib
Brian Haleyaee61ac2018-10-09 20:00:27 -040091
Itzik Brownbac51dc2016-10-31 12:25:04 +000092 All the parameters are the ones used in Compute API
Roee Agiman6a0a18a2017-11-16 11:51:56 +020093 * - Kwargs that require admin privileges
Itzik Brownbac51dc2016-10-31 12:25:04 +000094
95 Args:
96 flavor_ref(str): The flavor of the server to be provisioned.
97 image_ref(str): The image of the server to be provisioned.
98 key_name(str): SSH key to to be used to connect to the
99 provisioned server.
100 networks(list): List of dictionaries where each represent
101 an interface to be attached to the server. For network
102 it should be {'uuid': network_uuid} and for port it should
103 be {'port': port_uuid}
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200104 kwargs:
Itzik Brownbac51dc2016-10-31 12:25:04 +0000105 name(str): Name of the server to be provisioned.
106 security_groups(list): List of dictionaries where
107 the keys is 'name' and the value is the name of
108 the security group. If it's not passed the default
109 security group will be used.
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200110 availability_zone(str)*: The availability zone that
111 the instance will be in.
112 You can request a specific az without actually creating one,
113 Just pass 'X:Y' where X is the default availability
114 zone, and Y is the compute host name.
Itzik Brownbac51dc2016-10-31 12:25:04 +0000115 """
116
Jakub Libosvarffd9b912017-11-16 09:54:14 +0000117 kwargs.setdefault('name', data_utils.rand_name('server-test'))
Itzik Brownbac51dc2016-10-31 12:25:04 +0000118
Jakub Libosvarffd9b912017-11-16 09:54:14 +0000119 # We cannot use setdefault() here because caller could have passed
120 # security_groups=None and we don't want to pass None to
121 # client.create_server()
122 if not kwargs.get('security_groups'):
123 kwargs['security_groups'] = [{'name': 'default'}]
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200124
Jakub Libosvarffd9b912017-11-16 09:54:14 +0000125 client = self.os_primary.servers_client
126 if kwargs.get('availability_zone'):
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200127 client = self.os_admin.servers_client
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200128
Jakub Libosvarffd9b912017-11-16 09:54:14 +0000129 server = client.create_server(
130 flavorRef=flavor_ref,
131 imageRef=image_ref,
132 key_name=key_name,
133 networks=networks,
134 **kwargs)
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000135
136 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200137 waiters.wait_for_server_termination,
138 client,
139 server['server']['id'])
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000140 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200141 client.delete_server,
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000142 server['server']['id'])
Itzik Browne67ebb52016-05-15 05:34:41 +0000143 return server
144
145 @classmethod
Jens Harbott54357632017-11-21 11:47:06 +0000146 def create_secgroup_rules(cls, rule_list, secgroup_id=None,
147 client=None):
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200148 client = client or cls.os_primary.network_client
Itzik Browne67ebb52016-05-15 05:34:41 +0000149 if not secgroup_id:
150 sgs = client.list_security_groups()['security_groups']
151 for sg in sgs:
152 if sg['name'] == constants.DEFAULT_SECURITY_GROUP:
153 secgroup_id = sg['id']
154 break
155
Itzik Brown1ef813a2016-06-06 12:56:21 +0000156 for rule in rule_list:
157 direction = rule.pop('direction')
158 client.create_security_group_rule(
159 direction=direction,
160 security_group_id=secgroup_id,
161 **rule)
162
163 @classmethod
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200164 def create_loginable_secgroup_rule(cls, secgroup_id=None,
165 client=None):
Itzik Brown1ef813a2016-06-06 12:56:21 +0000166 """This rule is intended to permit inbound ssh
167
168 Allowing ssh traffic traffic from all sources, so no group_id is
169 provided.
170 Setting a group_id would only permit traffic from ports
171 belonging to the same security group.
172 """
Federico Ressi4c590d72018-10-10 14:01:08 +0200173 return cls.create_security_group_rule(
174 security_group_id=secgroup_id,
175 client=client,
176 protocol=neutron_lib_constants.PROTO_NAME_TCP,
177 direction=neutron_lib_constants.INGRESS_DIRECTION,
178 port_range_min=22,
179 port_range_max=22)
Itzik Browne67ebb52016-05-15 05:34:41 +0000180
181 @classmethod
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200182 def create_pingable_secgroup_rule(cls, secgroup_id=None,
183 client=None):
Federico Ressi4c590d72018-10-10 14:01:08 +0200184 """This rule is intended to permit inbound ping
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900185
Federico Ressi4c590d72018-10-10 14:01:08 +0200186 """
187 return cls.create_security_group_rule(
188 security_group_id=secgroup_id, client=client,
189 protocol=neutron_lib_constants.PROTO_NAME_ICMP,
190 direction=neutron_lib_constants.INGRESS_DIRECTION)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900191
192 @classmethod
Genadi Chereshnyac0411e92016-07-11 16:59:42 +0300193 def create_router_by_client(cls, is_admin=False, **kwargs):
194 kwargs.update({'router_name': data_utils.rand_name('router'),
195 'admin_state_up': True,
196 'external_network_id': CONF.network.public_network_id})
197 if not is_admin:
198 router = cls.create_router(**kwargs)
199 else:
200 router = cls.create_admin_router(**kwargs)
Alex Stafeyevc4d9c352016-12-12 04:13:33 -0500201 LOG.debug("Created router %s", router['name'])
Itzik Browne67ebb52016-05-15 05:34:41 +0000202 cls.routers.append(router)
203 return router
204
Federico Ressibf877c82018-08-22 08:36:37 +0200205 @removals.remove(version='Stein',
206 message="Please use create_floatingip method instead of "
207 "create_and_associate_floatingip.")
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200208 def create_and_associate_floatingip(self, port_id, client=None):
209 client = client or self.os_primary.network_client
Federico Ressibf877c82018-08-22 08:36:37 +0200210 return self.create_floatingip(port_id=port_id, client=client)
Itzik Browne67ebb52016-05-15 05:34:41 +0000211
Hongbin Lu965b03d2018-04-25 22:32:30 +0000212 def create_interface(cls, server_id, port_id, client=None):
213 client = client or cls.os_primary.interfaces_client
214 body = client.create_interface(server_id, port_id=port_id)
215 return body['interfaceAttachment']
216
217 def delete_interface(cls, server_id, port_id, client=None):
218 client = client or cls.os_primary.interfaces_client
219 client.delete_interface(server_id, port_id=port_id)
220
Brian Haleyd11f4ec2019-08-13 12:09:57 -0400221 def setup_network_and_server(self, router=None, server_name=None,
222 network=None, **kwargs):
Genadi Chereshnyac0411e92016-07-11 16:59:42 +0300223 """Create network resources and a server.
Itzik Brownbac51dc2016-10-31 12:25:04 +0000224
225 Creating a network, subnet, router, keypair, security group
226 and a server.
227 """
Assaf Mullerd54ae6c2018-05-31 11:38:00 -0400228 self.network = network or self.create_network()
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000229 LOG.debug("Created network %s", self.network['name'])
230 self.subnet = self.create_subnet(self.network)
231 LOG.debug("Created subnet %s", self.subnet['id'])
Itzik Brown1ef813a2016-06-06 12:56:21 +0000232
Brian Haleyf86ac2e2017-06-21 10:43:50 -0400233 secgroup = self.os_primary.network_client.create_security_group(
Chandan Kumarc125fd12017-11-15 19:41:01 +0530234 name=data_utils.rand_name('secgroup'))
Alex Stafeyevc4d9c352016-12-12 04:13:33 -0500235 LOG.debug("Created security group %s",
236 secgroup['security_group']['name'])
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000237 self.security_groups.append(secgroup['security_group'])
Genadi Chereshnyac0411e92016-07-11 16:59:42 +0300238 if not router:
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000239 router = self.create_router_by_client(**kwargs)
240 self.create_router_interface(router['id'], self.subnet['id'])
241 self.keypair = self.create_keypair()
242 self.create_loginable_secgroup_rule(
Itzik Brownbac51dc2016-10-31 12:25:04 +0000243 secgroup_id=secgroup['security_group']['id'])
Assaf Muller92fdc782018-05-31 10:32:47 -0400244
245 server_kwargs = {
246 'flavor_ref': CONF.compute.flavor_ref,
247 'image_ref': CONF.compute.image_ref,
248 'key_name': self.keypair['name'],
249 'networks': [{'uuid': self.network['id']}],
250 'security_groups': [{'name': secgroup['security_group']['name']}],
251 }
252 if server_name is not None:
253 server_kwargs['name'] = server_name
254
255 self.server = self.create_server(**server_kwargs)
Federico Ressie7417b72018-05-30 05:50:58 +0200256 self.wait_for_server_active(self.server['server'])
Jakub Libosvar1345d9d2017-06-09 13:59:05 +0000257 self.port = self.client.list_ports(network_id=self.network['id'],
258 device_id=self.server[
259 'server']['id'])['ports'][0]
Federico Ressibf877c82018-08-22 08:36:37 +0200260 self.fip = self.create_floatingip(port=self.port)
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500261
Eduardo Olivares3eb12282020-05-29 16:43:31 +0200262 def check_connectivity(self, host, ssh_user, ssh_key,
263 servers=None, ssh_timeout=None):
264 ssh_client = ssh.Client(host, ssh_user,
265 pkey=ssh_key, timeout=ssh_timeout)
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500266 try:
267 ssh_client.test_connection_auth()
268 except lib_exc.SSHTimeout as ssh_e:
269 LOG.debug(ssh_e)
270 self._log_console_output(servers)
Rodolfo Alonso Hernandez4849f002020-01-16 16:01:10 +0000271 self._log_local_network_status()
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500272 raise
273
274 def _log_console_output(self, servers=None):
275 if not CONF.compute_feature_enabled.console_output:
276 LOG.debug('Console output not supported, cannot log')
277 return
278 if not servers:
Brian Haleyf86ac2e2017-06-21 10:43:50 -0400279 servers = self.os_primary.servers_client.list_servers()
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500280 servers = servers['servers']
281 for server in servers:
Slawek Kaplonskicff79232020-03-03 14:12:18 +0100282 # NOTE(slaweq): sometimes servers are passed in dictionary with
283 # "server" key as first level key and in other cases it may be that
284 # it is just the "inner" dict without "server" key. Lets try to
285 # handle both cases
286 server = server.get("server") or server
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500287 try:
288 console_output = (
Brian Haleyf86ac2e2017-06-21 10:43:50 -0400289 self.os_primary.servers_client.get_console_output(
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500290 server['id'])['output'])
291 LOG.debug('Console output for %s\nbody=\n%s',
292 server['id'], console_output)
293 except lib_exc.NotFound:
294 LOG.debug("Server %s disappeared(deleted) while looking "
295 "for the console log", server['id'])
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900296
Rodolfo Alonso Hernandez4849f002020-01-16 16:01:10 +0000297 def _log_local_network_status(self):
298 local_routes = ip_utils.IPCommand().list_routes()
299 LOG.debug('Local routes:\n%s', '\n'.join(str(r) for r in local_routes))
300 arp_table = ip_utils.arp_table()
301 LOG.debug('Local ARP table:\n%s', '\n'.join(str(r) for r in arp_table))
302
LIU Yulong68ab2452019-05-18 10:19:49 +0800303 def _check_remote_connectivity(self, source, dest, count,
304 should_succeed=True,
Assaf Muller92fdc782018-05-31 10:32:47 -0400305 nic=None, mtu=None, fragmentation=True,
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100306 timeout=None, pattern=None):
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900307 """check ping server via source ssh connection
308
309 :param source: RemoteClient: an ssh connection from which to ping
310 :param dest: and IP to ping against
LIU Yulong68ab2452019-05-18 10:19:49 +0800311 :param count: Number of ping packet(s) to send
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900312 :param should_succeed: boolean should ping succeed or not
313 :param nic: specific network interface to ping from
Genadi Chereshnya6d10c6e2017-07-05 11:34:20 +0300314 :param mtu: mtu size for the packet to be sent
315 :param fragmentation: Flag for packet fragmentation
LIU Yulong68ab2452019-05-18 10:19:49 +0800316 :param timeout: Timeout for all ping packet(s) to succeed
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100317 :param pattern: hex digits included in ICMP messages
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900318 :returns: boolean -- should_succeed == ping
319 :returns: ping is false if ping failed
320 """
LIU Yulong68ab2452019-05-18 10:19:49 +0800321 def ping_host(source, host, count,
Genadi Chereshnya6d10c6e2017-07-05 11:34:20 +0300322 size=CONF.validation.ping_size, nic=None, mtu=None,
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100323 fragmentation=True, pattern=None):
Assaf Muller92fdc782018-05-31 10:32:47 -0400324 IP_VERSION_4 = neutron_lib_constants.IP_VERSION_4
325 IP_VERSION_6 = neutron_lib_constants.IP_VERSION_6
326
327 # Use 'ping6' for IPv6 addresses, 'ping' for IPv4 and hostnames
328 ip_version = (
329 IP_VERSION_6 if netaddr.valid_ipv6(host) else IP_VERSION_4)
330 cmd = (
331 'ping6' if ip_version == IP_VERSION_6 else 'ping')
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900332 if nic:
333 cmd = 'sudo {cmd} -I {nic}'.format(cmd=cmd, nic=nic)
Genadi Chereshnya6d10c6e2017-07-05 11:34:20 +0300334 if mtu:
335 if not fragmentation:
336 cmd += ' -M do'
337 size = str(net_utils.get_ping_payload_size(
Assaf Muller92fdc782018-05-31 10:32:47 -0400338 mtu=mtu, ip_version=ip_version))
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100339 if pattern:
340 cmd += ' -p {pattern}'.format(pattern=pattern)
Maciej Józefczyk3c324e02020-03-16 10:52:08 +0000341 cmd += ' -c{0} -W{0} -s{1} {2}'.format(count, size, host)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900342 return source.exec_command(cmd)
343
344 def ping_remote():
345 try:
LIU Yulong68ab2452019-05-18 10:19:49 +0800346 result = ping_host(source, dest, count, nic=nic, mtu=mtu,
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100347 fragmentation=fragmentation,
348 pattern=pattern)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900349
350 except lib_exc.SSHExecCommandFailed:
351 LOG.warning('Failed to ping IP: %s via a ssh connection '
352 'from: %s.', dest, source.host)
353 return not should_succeed
354 LOG.debug('ping result: %s', result)
Assaf Muller92fdc782018-05-31 10:32:47 -0400355
356 if validators.validate_ip_address(dest) is None:
357 # Assert that the return traffic was from the correct
358 # source address.
359 from_source = 'from %s' % dest
360 self.assertIn(from_source, result)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900361 return should_succeed
362
Assaf Muller92fdc782018-05-31 10:32:47 -0400363 return test_utils.call_until_true(
364 ping_remote, timeout or CONF.validation.ping_timeout, 1)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900365
366 def check_remote_connectivity(self, source, dest, should_succeed=True,
Slawek Kaplonskib07251f2018-05-16 12:21:50 +0200367 nic=None, mtu=None, fragmentation=True,
LIU Yulong68ab2452019-05-18 10:19:49 +0800368 servers=None, timeout=None,
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100369 ping_count=CONF.validation.ping_count,
370 pattern=None):
Slawek Kaplonskib07251f2018-05-16 12:21:50 +0200371 try:
372 self.assertTrue(self._check_remote_connectivity(
LIU Yulong68ab2452019-05-18 10:19:49 +0800373 source, dest, ping_count, should_succeed, nic, mtu,
374 fragmentation,
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100375 timeout=timeout, pattern=pattern))
Slawek Kaplonskib07251f2018-05-16 12:21:50 +0200376 except lib_exc.SSHTimeout as ssh_e:
377 LOG.debug(ssh_e)
378 self._log_console_output(servers)
379 raise
380 except AssertionError:
381 self._log_console_output(servers)
382 raise
Chandan Kumarc125fd12017-11-15 19:41:01 +0530383
384 def ping_ip_address(self, ip_address, should_succeed=True,
385 ping_timeout=None, mtu=None):
386 # the code is taken from tempest/scenario/manager.py in tempest git
387 timeout = ping_timeout or CONF.validation.ping_timeout
388 cmd = ['ping', '-c1', '-w1']
389
390 if mtu:
391 cmd += [
392 # don't fragment
393 '-M', 'do',
394 # ping receives just the size of ICMP payload
395 '-s', str(net_utils.get_ping_payload_size(mtu, 4))
396 ]
397 cmd.append(ip_address)
398
399 def ping():
400 proc = subprocess.Popen(cmd,
401 stdout=subprocess.PIPE,
402 stderr=subprocess.PIPE)
403 proc.communicate()
404
405 return (proc.returncode == 0) == should_succeed
406
407 caller = test_utils.find_test_caller()
408 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
409 ' expected result is %(should_succeed)s', {
410 'caller': caller, 'ip': ip_address, 'timeout': timeout,
411 'should_succeed':
412 'reachable' if should_succeed else 'unreachable'
413 })
414 result = test_utils.call_until_true(ping, timeout, 1)
Manjeet Singh Bhatia8bbf8992019-03-04 11:59:57 -0800415
416 # To make sure ping_ip_address called by test works
417 # as expected.
418 self.assertTrue(result)
419
Chandan Kumarc125fd12017-11-15 19:41:01 +0530420 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
421 'ping result is %(result)s', {
422 'caller': caller, 'ip': ip_address, 'timeout': timeout,
423 'result': 'expected' if result else 'unexpected'
424 })
425 return result
Federico Ressie7417b72018-05-30 05:50:58 +0200426
427 def wait_for_server_status(self, server, status, client=None, **kwargs):
428 """Waits for a server to reach a given status.
429
430 :param server: mapping having schema {'id': <server_id>}
431 :param status: string status to wait for (es: 'ACTIVE')
432 :param clien: servers client (self.os_primary.servers_client as
433 default value)
434 """
435
436 client = client or self.os_primary.servers_client
437 waiters.wait_for_server_status(client, server['id'], status, **kwargs)
438
439 def wait_for_server_active(self, server, client=None):
440 """Waits for a server to reach active status.
441
442 :param server: mapping having schema {'id': <server_id>}
443 :param clien: servers client (self.os_primary.servers_client as
444 default value)
445 """
446 self.wait_for_server_status(
447 server, constants.SERVER_STATUS_ACTIVE, client)
Jakub Libosvar031fd5a2019-07-15 16:10:07 +0000448
449 def check_servers_hostnames(self, servers, log_errors=True):
450 """Compare hostnames of given servers with their names."""
451 try:
452 for server in servers:
453 kwargs = {}
454 try:
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200455 kwargs['port'] = (
456 server['port_forwarding_tcp']['external_port'])
Jakub Libosvar031fd5a2019-07-15 16:10:07 +0000457 except KeyError:
458 pass
459 ssh_client = ssh.Client(
460 self.fip['floating_ip_address'],
461 CONF.validation.image_ssh_user,
462 pkey=self.keypair['private_key'],
463 **kwargs)
464 self.assertIn(server['name'],
465 ssh_client.exec_command('hostname'))
466 except lib_exc.SSHTimeout as ssh_e:
467 LOG.debug(ssh_e)
468 if log_errors:
469 self._log_console_output(servers)
470 raise
471 except AssertionError as assert_e:
472 LOG.debug(assert_e)
473 if log_errors:
474 self._log_console_output(servers)
475 raise
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200476
Slawek Kaplonskifd4141f2020-03-14 14:34:00 +0100477 def ensure_nc_listen(self, ssh_client, port, protocol, echo_msg=None,
478 servers=None):
479 """Ensure that nc server listening on the given TCP/UDP port is up.
480
481 Listener is created always on remote host.
482 """
483 def spawn_and_check_process():
484 self.nc_listen(ssh_client, port, protocol, echo_msg, servers)
485 return utils.process_is_running(ssh_client, "nc")
486
487 utils.wait_until_true(spawn_and_check_process)
488
489 def nc_listen(self, ssh_client, port, protocol, echo_msg=None,
490 servers=None):
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200491 """Create nc server listening on the given TCP/UDP port.
492
493 Listener is created always on remote host.
494 """
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200495 try:
Slawek Kaplonskiaf83e832020-02-05 12:11:54 +0100496 return ssh_client.execute_script(
497 get_ncat_server_cmd(port, protocol, echo_msg),
498 become_root=True)
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200499 except lib_exc.SSHTimeout as ssh_e:
500 LOG.debug(ssh_e)
Slawek Kaplonskifd4141f2020-03-14 14:34:00 +0100501 self._log_console_output(servers)
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200502 raise
503
504 def nc_client(self, ip_address, port, protocol):
505 """Check connectivity to TCP/UDP port at host via nc.
506
507 Client is always executed locally on host where tests are executed.
508 """
Slawek Kaplonskiaf83e832020-02-05 12:11:54 +0100509 cmd = get_ncat_client_cmd(ip_address, port, protocol)
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200510 result = shell.execute_local_command(cmd)
511 self.assertEqual(0, result.exit_status)
512 return result.stdout