blob: 7b6649483ef07efbdd9e3964607acdcc24d0db64 [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
34from neutron_tempest_plugin import config
Slawek Kaplonskiaf83e832020-02-05 12:11:54 +010035from neutron_tempest_plugin import exceptions
Chandan Kumar667d3d32017-09-22 12:24:06 +053036from neutron_tempest_plugin.scenario import constants
Itzik Browne67ebb52016-05-15 05:34:41 +000037
38CONF = config.CONF
Itzik Browne67ebb52016-05-15 05:34:41 +000039
Alex Stafeyevc4d9c352016-12-12 04:13:33 -050040LOG = log.getLogger(__name__)
41
Itzik Browne67ebb52016-05-15 05:34:41 +000042
Slawek Kaplonskiaf83e832020-02-05 12:11:54 +010043def get_ncat_version(ssh_client=None):
44 cmd = "ncat --version 2>&1"
45 try:
46 version_result = shell.execute(cmd, ssh_client=ssh_client).stdout
47 except exceptions.ShellCommandFailed:
48 m = None
49 else:
50 m = re.match(r"Ncat: Version ([\d.]+) *.", version_result)
51 # NOTE(slaweq): by default lets assume we have ncat 7.60 which is in Ubuntu
52 # 18.04 which is used on u/s gates
53 return distutils.version.StrictVersion(m.group(1) if m else '7.60')
54
55
56def get_ncat_server_cmd(port, protocol, msg):
57 udp = ''
58 if protocol.lower() == neutron_lib_constants.PROTO_NAME_UDP:
59 udp = '-u'
60 cmd = "nc %(udp)s -p %(port)s -lk " % {
61 'udp': udp, 'port': port}
62 if CONF.neutron_plugin_options.default_image_is_advanced:
63 cmd += "-c 'echo %s' &" % msg
64 else:
65 cmd += "-e echo %s &" % msg
66 return cmd
67
68
69def get_ncat_client_cmd(ip_address, port, protocol):
70 udp = ''
71 if protocol.lower() == neutron_lib_constants.PROTO_NAME_UDP:
72 udp = '-u'
73 cmd = 'echo "knock knock" | nc '
74 ncat_version = get_ncat_version()
75 if ncat_version > distutils.version.StrictVersion('7.60'):
76 cmd += '-z '
77 cmd += '-w 1 %(udp)s %(host)s %(port)s' % {
78 'udp': udp, 'host': ip_address, 'port': port}
79 return cmd
80
81
Itzik Browne67ebb52016-05-15 05:34:41 +000082class BaseTempestTestCase(base_api.BaseNetworkTest):
Itzik Browne67ebb52016-05-15 05:34:41 +000083
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +000084 def create_server(self, flavor_ref, image_ref, key_name, networks,
Roee Agiman6a0a18a2017-11-16 11:51:56 +020085 **kwargs):
Itzik Brownbac51dc2016-10-31 12:25:04 +000086 """Create a server using tempest lib
Brian Haleyaee61ac2018-10-09 20:00:27 -040087
Itzik Brownbac51dc2016-10-31 12:25:04 +000088 All the parameters are the ones used in Compute API
Roee Agiman6a0a18a2017-11-16 11:51:56 +020089 * - Kwargs that require admin privileges
Itzik Brownbac51dc2016-10-31 12:25:04 +000090
91 Args:
92 flavor_ref(str): The flavor of the server to be provisioned.
93 image_ref(str): The image of the server to be provisioned.
94 key_name(str): SSH key to to be used to connect to the
95 provisioned server.
96 networks(list): List of dictionaries where each represent
97 an interface to be attached to the server. For network
98 it should be {'uuid': network_uuid} and for port it should
99 be {'port': port_uuid}
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200100 kwargs:
Itzik Brownbac51dc2016-10-31 12:25:04 +0000101 name(str): Name of the server to be provisioned.
102 security_groups(list): List of dictionaries where
103 the keys is 'name' and the value is the name of
104 the security group. If it's not passed the default
105 security group will be used.
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200106 availability_zone(str)*: The availability zone that
107 the instance will be in.
108 You can request a specific az without actually creating one,
109 Just pass 'X:Y' where X is the default availability
110 zone, and Y is the compute host name.
Itzik Brownbac51dc2016-10-31 12:25:04 +0000111 """
112
Jakub Libosvarffd9b912017-11-16 09:54:14 +0000113 kwargs.setdefault('name', data_utils.rand_name('server-test'))
Itzik Brownbac51dc2016-10-31 12:25:04 +0000114
Jakub Libosvarffd9b912017-11-16 09:54:14 +0000115 # We cannot use setdefault() here because caller could have passed
116 # security_groups=None and we don't want to pass None to
117 # client.create_server()
118 if not kwargs.get('security_groups'):
119 kwargs['security_groups'] = [{'name': 'default'}]
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200120
Jakub Libosvarffd9b912017-11-16 09:54:14 +0000121 client = self.os_primary.servers_client
122 if kwargs.get('availability_zone'):
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200123 client = self.os_admin.servers_client
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200124
Jakub Libosvarffd9b912017-11-16 09:54:14 +0000125 server = client.create_server(
126 flavorRef=flavor_ref,
127 imageRef=image_ref,
128 key_name=key_name,
129 networks=networks,
130 **kwargs)
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000131
132 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200133 waiters.wait_for_server_termination,
134 client,
135 server['server']['id'])
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000136 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200137 client.delete_server,
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000138 server['server']['id'])
Itzik Browne67ebb52016-05-15 05:34:41 +0000139 return server
140
141 @classmethod
Jens Harbott54357632017-11-21 11:47:06 +0000142 def create_secgroup_rules(cls, rule_list, secgroup_id=None,
143 client=None):
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200144 client = client or cls.os_primary.network_client
Itzik Browne67ebb52016-05-15 05:34:41 +0000145 if not secgroup_id:
146 sgs = client.list_security_groups()['security_groups']
147 for sg in sgs:
148 if sg['name'] == constants.DEFAULT_SECURITY_GROUP:
149 secgroup_id = sg['id']
150 break
151
Itzik Brown1ef813a2016-06-06 12:56:21 +0000152 for rule in rule_list:
153 direction = rule.pop('direction')
154 client.create_security_group_rule(
155 direction=direction,
156 security_group_id=secgroup_id,
157 **rule)
158
159 @classmethod
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200160 def create_loginable_secgroup_rule(cls, secgroup_id=None,
161 client=None):
Itzik Brown1ef813a2016-06-06 12:56:21 +0000162 """This rule is intended to permit inbound ssh
163
164 Allowing ssh traffic traffic from all sources, so no group_id is
165 provided.
166 Setting a group_id would only permit traffic from ports
167 belonging to the same security group.
168 """
Federico Ressi4c590d72018-10-10 14:01:08 +0200169 return cls.create_security_group_rule(
170 security_group_id=secgroup_id,
171 client=client,
172 protocol=neutron_lib_constants.PROTO_NAME_TCP,
173 direction=neutron_lib_constants.INGRESS_DIRECTION,
174 port_range_min=22,
175 port_range_max=22)
Itzik Browne67ebb52016-05-15 05:34:41 +0000176
177 @classmethod
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200178 def create_pingable_secgroup_rule(cls, secgroup_id=None,
179 client=None):
Federico Ressi4c590d72018-10-10 14:01:08 +0200180 """This rule is intended to permit inbound ping
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900181
Federico Ressi4c590d72018-10-10 14:01:08 +0200182 """
183 return cls.create_security_group_rule(
184 security_group_id=secgroup_id, client=client,
185 protocol=neutron_lib_constants.PROTO_NAME_ICMP,
186 direction=neutron_lib_constants.INGRESS_DIRECTION)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900187
188 @classmethod
Genadi Chereshnyac0411e92016-07-11 16:59:42 +0300189 def create_router_by_client(cls, is_admin=False, **kwargs):
190 kwargs.update({'router_name': data_utils.rand_name('router'),
191 'admin_state_up': True,
192 'external_network_id': CONF.network.public_network_id})
193 if not is_admin:
194 router = cls.create_router(**kwargs)
195 else:
196 router = cls.create_admin_router(**kwargs)
Alex Stafeyevc4d9c352016-12-12 04:13:33 -0500197 LOG.debug("Created router %s", router['name'])
Itzik Browne67ebb52016-05-15 05:34:41 +0000198 cls.routers.append(router)
199 return router
200
Federico Ressibf877c82018-08-22 08:36:37 +0200201 @removals.remove(version='Stein',
202 message="Please use create_floatingip method instead of "
203 "create_and_associate_floatingip.")
Roee Agiman6a0a18a2017-11-16 11:51:56 +0200204 def create_and_associate_floatingip(self, port_id, client=None):
205 client = client or self.os_primary.network_client
Federico Ressibf877c82018-08-22 08:36:37 +0200206 return self.create_floatingip(port_id=port_id, client=client)
Itzik Browne67ebb52016-05-15 05:34:41 +0000207
Hongbin Lu965b03d2018-04-25 22:32:30 +0000208 def create_interface(cls, server_id, port_id, client=None):
209 client = client or cls.os_primary.interfaces_client
210 body = client.create_interface(server_id, port_id=port_id)
211 return body['interfaceAttachment']
212
213 def delete_interface(cls, server_id, port_id, client=None):
214 client = client or cls.os_primary.interfaces_client
215 client.delete_interface(server_id, port_id=port_id)
216
Brian Haleyd11f4ec2019-08-13 12:09:57 -0400217 def setup_network_and_server(self, router=None, server_name=None,
218 network=None, **kwargs):
Genadi Chereshnyac0411e92016-07-11 16:59:42 +0300219 """Create network resources and a server.
Itzik Brownbac51dc2016-10-31 12:25:04 +0000220
221 Creating a network, subnet, router, keypair, security group
222 and a server.
223 """
Assaf Mullerd54ae6c2018-05-31 11:38:00 -0400224 self.network = network or self.create_network()
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000225 LOG.debug("Created network %s", self.network['name'])
226 self.subnet = self.create_subnet(self.network)
227 LOG.debug("Created subnet %s", self.subnet['id'])
Itzik Brown1ef813a2016-06-06 12:56:21 +0000228
Brian Haleyf86ac2e2017-06-21 10:43:50 -0400229 secgroup = self.os_primary.network_client.create_security_group(
Chandan Kumarc125fd12017-11-15 19:41:01 +0530230 name=data_utils.rand_name('secgroup'))
Alex Stafeyevc4d9c352016-12-12 04:13:33 -0500231 LOG.debug("Created security group %s",
232 secgroup['security_group']['name'])
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000233 self.security_groups.append(secgroup['security_group'])
Genadi Chereshnyac0411e92016-07-11 16:59:42 +0300234 if not router:
Genadi Chereshnya918dd0b2017-05-17 13:02:20 +0000235 router = self.create_router_by_client(**kwargs)
236 self.create_router_interface(router['id'], self.subnet['id'])
237 self.keypair = self.create_keypair()
238 self.create_loginable_secgroup_rule(
Itzik Brownbac51dc2016-10-31 12:25:04 +0000239 secgroup_id=secgroup['security_group']['id'])
Assaf Muller92fdc782018-05-31 10:32:47 -0400240
241 server_kwargs = {
242 'flavor_ref': CONF.compute.flavor_ref,
243 'image_ref': CONF.compute.image_ref,
244 'key_name': self.keypair['name'],
245 'networks': [{'uuid': self.network['id']}],
246 'security_groups': [{'name': secgroup['security_group']['name']}],
247 }
248 if server_name is not None:
249 server_kwargs['name'] = server_name
250
251 self.server = self.create_server(**server_kwargs)
Federico Ressie7417b72018-05-30 05:50:58 +0200252 self.wait_for_server_active(self.server['server'])
Jakub Libosvar1345d9d2017-06-09 13:59:05 +0000253 self.port = self.client.list_ports(network_id=self.network['id'],
254 device_id=self.server[
255 'server']['id'])['ports'][0]
Federico Ressibf877c82018-08-22 08:36:37 +0200256 self.fip = self.create_floatingip(port=self.port)
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500257
258 def check_connectivity(self, host, ssh_user, ssh_key, servers=None):
259 ssh_client = ssh.Client(host, ssh_user, pkey=ssh_key)
260 try:
261 ssh_client.test_connection_auth()
262 except lib_exc.SSHTimeout as ssh_e:
263 LOG.debug(ssh_e)
264 self._log_console_output(servers)
Rodolfo Alonso Hernandez4849f002020-01-16 16:01:10 +0000265 self._log_local_network_status()
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500266 raise
267
268 def _log_console_output(self, servers=None):
269 if not CONF.compute_feature_enabled.console_output:
270 LOG.debug('Console output not supported, cannot log')
271 return
272 if not servers:
Brian Haleyf86ac2e2017-06-21 10:43:50 -0400273 servers = self.os_primary.servers_client.list_servers()
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500274 servers = servers['servers']
275 for server in servers:
276 try:
277 console_output = (
Brian Haleyf86ac2e2017-06-21 10:43:50 -0400278 self.os_primary.servers_client.get_console_output(
Jakub Libosvarc0c2f1d2017-01-31 12:12:21 -0500279 server['id'])['output'])
280 LOG.debug('Console output for %s\nbody=\n%s',
281 server['id'], console_output)
282 except lib_exc.NotFound:
283 LOG.debug("Server %s disappeared(deleted) while looking "
284 "for the console log", server['id'])
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900285
Rodolfo Alonso Hernandez4849f002020-01-16 16:01:10 +0000286 def _log_local_network_status(self):
287 local_routes = ip_utils.IPCommand().list_routes()
288 LOG.debug('Local routes:\n%s', '\n'.join(str(r) for r in local_routes))
289 arp_table = ip_utils.arp_table()
290 LOG.debug('Local ARP table:\n%s', '\n'.join(str(r) for r in arp_table))
291
LIU Yulong68ab2452019-05-18 10:19:49 +0800292 def _check_remote_connectivity(self, source, dest, count,
293 should_succeed=True,
Assaf Muller92fdc782018-05-31 10:32:47 -0400294 nic=None, mtu=None, fragmentation=True,
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100295 timeout=None, pattern=None):
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900296 """check ping server via source ssh connection
297
298 :param source: RemoteClient: an ssh connection from which to ping
299 :param dest: and IP to ping against
LIU Yulong68ab2452019-05-18 10:19:49 +0800300 :param count: Number of ping packet(s) to send
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900301 :param should_succeed: boolean should ping succeed or not
302 :param nic: specific network interface to ping from
Genadi Chereshnya6d10c6e2017-07-05 11:34:20 +0300303 :param mtu: mtu size for the packet to be sent
304 :param fragmentation: Flag for packet fragmentation
LIU Yulong68ab2452019-05-18 10:19:49 +0800305 :param timeout: Timeout for all ping packet(s) to succeed
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100306 :param pattern: hex digits included in ICMP messages
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900307 :returns: boolean -- should_succeed == ping
308 :returns: ping is false if ping failed
309 """
LIU Yulong68ab2452019-05-18 10:19:49 +0800310 def ping_host(source, host, count,
Genadi Chereshnya6d10c6e2017-07-05 11:34:20 +0300311 size=CONF.validation.ping_size, nic=None, mtu=None,
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100312 fragmentation=True, pattern=None):
Assaf Muller92fdc782018-05-31 10:32:47 -0400313 IP_VERSION_4 = neutron_lib_constants.IP_VERSION_4
314 IP_VERSION_6 = neutron_lib_constants.IP_VERSION_6
315
316 # Use 'ping6' for IPv6 addresses, 'ping' for IPv4 and hostnames
317 ip_version = (
318 IP_VERSION_6 if netaddr.valid_ipv6(host) else IP_VERSION_4)
319 cmd = (
320 'ping6' if ip_version == IP_VERSION_6 else 'ping')
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900321 if nic:
322 cmd = 'sudo {cmd} -I {nic}'.format(cmd=cmd, nic=nic)
Genadi Chereshnya6d10c6e2017-07-05 11:34:20 +0300323 if mtu:
324 if not fragmentation:
325 cmd += ' -M do'
326 size = str(net_utils.get_ping_payload_size(
Assaf Muller92fdc782018-05-31 10:32:47 -0400327 mtu=mtu, ip_version=ip_version))
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100328 if pattern:
329 cmd += ' -p {pattern}'.format(pattern=pattern)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900330 cmd += ' -c{0} -w{0} -s{1} {2}'.format(count, size, host)
331 return source.exec_command(cmd)
332
333 def ping_remote():
334 try:
LIU Yulong68ab2452019-05-18 10:19:49 +0800335 result = ping_host(source, dest, count, nic=nic, mtu=mtu,
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100336 fragmentation=fragmentation,
337 pattern=pattern)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900338
339 except lib_exc.SSHExecCommandFailed:
340 LOG.warning('Failed to ping IP: %s via a ssh connection '
341 'from: %s.', dest, source.host)
342 return not should_succeed
343 LOG.debug('ping result: %s', result)
Assaf Muller92fdc782018-05-31 10:32:47 -0400344
345 if validators.validate_ip_address(dest) is None:
346 # Assert that the return traffic was from the correct
347 # source address.
348 from_source = 'from %s' % dest
349 self.assertIn(from_source, result)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900350 return should_succeed
351
Assaf Muller92fdc782018-05-31 10:32:47 -0400352 return test_utils.call_until_true(
353 ping_remote, timeout or CONF.validation.ping_timeout, 1)
YAMAMOTO Takashi25935722017-01-23 15:34:11 +0900354
355 def check_remote_connectivity(self, source, dest, should_succeed=True,
Slawek Kaplonskib07251f2018-05-16 12:21:50 +0200356 nic=None, mtu=None, fragmentation=True,
LIU Yulong68ab2452019-05-18 10:19:49 +0800357 servers=None, timeout=None,
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100358 ping_count=CONF.validation.ping_count,
359 pattern=None):
Slawek Kaplonskib07251f2018-05-16 12:21:50 +0200360 try:
361 self.assertTrue(self._check_remote_connectivity(
LIU Yulong68ab2452019-05-18 10:19:49 +0800362 source, dest, ping_count, should_succeed, nic, mtu,
363 fragmentation,
Eduardo Olivaresf2b60542020-01-30 09:37:22 +0100364 timeout=timeout, pattern=pattern))
Slawek Kaplonskib07251f2018-05-16 12:21:50 +0200365 except lib_exc.SSHTimeout as ssh_e:
366 LOG.debug(ssh_e)
367 self._log_console_output(servers)
368 raise
369 except AssertionError:
370 self._log_console_output(servers)
371 raise
Chandan Kumarc125fd12017-11-15 19:41:01 +0530372
373 def ping_ip_address(self, ip_address, should_succeed=True,
374 ping_timeout=None, mtu=None):
375 # the code is taken from tempest/scenario/manager.py in tempest git
376 timeout = ping_timeout or CONF.validation.ping_timeout
377 cmd = ['ping', '-c1', '-w1']
378
379 if mtu:
380 cmd += [
381 # don't fragment
382 '-M', 'do',
383 # ping receives just the size of ICMP payload
384 '-s', str(net_utils.get_ping_payload_size(mtu, 4))
385 ]
386 cmd.append(ip_address)
387
388 def ping():
389 proc = subprocess.Popen(cmd,
390 stdout=subprocess.PIPE,
391 stderr=subprocess.PIPE)
392 proc.communicate()
393
394 return (proc.returncode == 0) == should_succeed
395
396 caller = test_utils.find_test_caller()
397 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
398 ' expected result is %(should_succeed)s', {
399 'caller': caller, 'ip': ip_address, 'timeout': timeout,
400 'should_succeed':
401 'reachable' if should_succeed else 'unreachable'
402 })
403 result = test_utils.call_until_true(ping, timeout, 1)
Manjeet Singh Bhatia8bbf8992019-03-04 11:59:57 -0800404
405 # To make sure ping_ip_address called by test works
406 # as expected.
407 self.assertTrue(result)
408
Chandan Kumarc125fd12017-11-15 19:41:01 +0530409 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
410 'ping result is %(result)s', {
411 'caller': caller, 'ip': ip_address, 'timeout': timeout,
412 'result': 'expected' if result else 'unexpected'
413 })
414 return result
Federico Ressie7417b72018-05-30 05:50:58 +0200415
416 def wait_for_server_status(self, server, status, client=None, **kwargs):
417 """Waits for a server to reach a given status.
418
419 :param server: mapping having schema {'id': <server_id>}
420 :param status: string status to wait for (es: 'ACTIVE')
421 :param clien: servers client (self.os_primary.servers_client as
422 default value)
423 """
424
425 client = client or self.os_primary.servers_client
426 waiters.wait_for_server_status(client, server['id'], status, **kwargs)
427
428 def wait_for_server_active(self, server, client=None):
429 """Waits for a server to reach active status.
430
431 :param server: mapping having schema {'id': <server_id>}
432 :param clien: servers client (self.os_primary.servers_client as
433 default value)
434 """
435 self.wait_for_server_status(
436 server, constants.SERVER_STATUS_ACTIVE, client)
Jakub Libosvar031fd5a2019-07-15 16:10:07 +0000437
438 def check_servers_hostnames(self, servers, log_errors=True):
439 """Compare hostnames of given servers with their names."""
440 try:
441 for server in servers:
442 kwargs = {}
443 try:
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200444 kwargs['port'] = (
445 server['port_forwarding_tcp']['external_port'])
Jakub Libosvar031fd5a2019-07-15 16:10:07 +0000446 except KeyError:
447 pass
448 ssh_client = ssh.Client(
449 self.fip['floating_ip_address'],
450 CONF.validation.image_ssh_user,
451 pkey=self.keypair['private_key'],
452 **kwargs)
453 self.assertIn(server['name'],
454 ssh_client.exec_command('hostname'))
455 except lib_exc.SSHTimeout as ssh_e:
456 LOG.debug(ssh_e)
457 if log_errors:
458 self._log_console_output(servers)
459 raise
460 except AssertionError as assert_e:
461 LOG.debug(assert_e)
462 if log_errors:
463 self._log_console_output(servers)
464 raise
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200465
466 def nc_listen(self, server, ssh_client, port, protocol, echo_msg):
467 """Create nc server listening on the given TCP/UDP port.
468
469 Listener is created always on remote host.
470 """
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200471 try:
Slawek Kaplonskiaf83e832020-02-05 12:11:54 +0100472 return ssh_client.execute_script(
473 get_ncat_server_cmd(port, protocol, echo_msg),
474 become_root=True)
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200475 except lib_exc.SSHTimeout as ssh_e:
476 LOG.debug(ssh_e)
477 self._log_console_output([server])
478 raise
479
480 def nc_client(self, ip_address, port, protocol):
481 """Check connectivity to TCP/UDP port at host via nc.
482
483 Client is always executed locally on host where tests are executed.
484 """
Slawek Kaplonskiaf83e832020-02-05 12:11:54 +0100485 cmd = get_ncat_client_cmd(ip_address, port, protocol)
Slawek Kaplonskic4e963e2019-09-11 22:55:34 +0200486 result = shell.execute_local_command(cmd)
487 self.assertEqual(0, result.exit_status)
488 return result.stdout