blob: 52ccfa960143dac6cdc228498b8b5a58c00b7bd3 [file] [log] [blame]
Sean Dague556add52013-07-19 14:28:44 -04001# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
Attila Fazekasa23f5002012-10-23 19:32:45 +020013import re
Matthew Treinisha83a16e2012-12-07 13:44:02 -050014import time
15
David Kranz968f1b32015-06-18 16:58:18 -040016from oslo_log import log as logging
Matthew Treinish96e9e882014-06-09 18:37:19 -040017
Sean Dague86bd8422013-12-20 09:56:44 -050018from tempest import config
Ken'ichi Ohmichid25a1a32017-03-01 13:40:35 -080019from tempest.lib.common.utils.linux import remote_client
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050020import tempest.lib.exceptions
Daryl Walleck98e66dd2012-06-21 04:58:39 -050021
Sean Dague86bd8422013-12-20 09:56:44 -050022CONF = config.CONF
23
David Kranz968f1b32015-06-18 16:58:18 -040024LOG = logging.getLogger(__name__)
25
Daryl Walleck6b9b2882012-04-08 21:43:39 -050026
Ken'ichi Ohmichid25a1a32017-03-01 13:40:35 -080027class RemoteClient(remote_client.RemoteClient):
Andrea Frittoli (andreaf)5f5e4fc2016-04-29 16:00:17 -050028
Ken'ichi Ohmichid25a1a32017-03-01 13:40:35 -080029 # TODO(oomichi): Make this class deprecated after migrating
30 # necessary methods to tempest.lib and cleaning
31 # unnecessary methods up from this class.
Andrea Frittoli (andreaf)5f5e4fc2016-04-29 16:00:17 -050032 def __init__(self, ip_address, username, password=None, pkey=None,
33 server=None, servers_client=None):
34 """Executes commands in a VM over ssh
35
36 :param ip_address: IP address to ssh to
37 :param username: ssh username
38 :param password: ssh password (optional)
39 :param pkey: ssh public key (optional)
40 :param server: server dict, used for debugging purposes
41 :param servers_client: servers client, used for debugging purposes
42 """
Ken'ichi Ohmichid25a1a32017-03-01 13:40:35 -080043 super(RemoteClient, self).__init__(
44 ip_address, username, password=password, pkey=pkey,
45 server=server, servers_client=servers_client,
46 ssh_timeout=CONF.validation.ssh_timeout,
47 connect_timeout=CONF.validation.connect_timeout,
48 console_output_enabled=CONF.compute_feature_enabled.console_output,
49 ssh_shell_prologue=CONF.validation.ssh_shell_prologue,
50 ping_count=CONF.validation.ping_count,
51 ping_size=CONF.validation.ping_size)
Daryl Walleck6b9b2882012-04-08 21:43:39 -050052
Emily Hugenbruch877811f2017-03-24 14:32:03 -040053 # Note that this method will not work on SLES11 guests, as they do
54 # not support the TYPE column on lsblk
Evgeny Antyshev4894a912016-11-21 12:17:18 +000055 def get_disks(self):
56 # Select root disk devices as shown by lsblk
57 command = 'lsblk -lb --nodeps'
Elena Ezhova91db24e2014-02-28 20:47:10 +040058 output = self.exec_command(command)
Evgeny Antyshev4894a912016-11-21 12:17:18 +000059 selected = []
60 pos = None
61 for l in output.splitlines():
62 if pos is None and l.find("TYPE") > 0:
63 pos = l.find("TYPE")
64 # Show header line too
65 selected.append(l)
66 # lsblk lists disk type in a column right-aligned with TYPE
Masayuki Igawa0a5d6062017-03-27 12:22:33 +090067 elif pos is not None and pos > 0 and l[pos:pos + 4] == "disk":
Evgeny Antyshev4894a912016-11-21 12:17:18 +000068 selected.append(l)
69
Masayuki Igawa0a5d6062017-03-27 12:22:33 +090070 if selected:
71 return "\n".join(selected)
72 else:
shangxiaobj284d3112017-08-13 23:37:34 -070073 msg = "'TYPE' column is required but the output doesn't have it: "
Masayuki Igawa0a5d6062017-03-27 12:22:33 +090074 raise tempest.lib.exceptions.TempestException(msg + output)
Daryl Walleck98e66dd2012-06-21 04:58:39 -050075
76 def get_boot_time(self):
Vincent Untz3c0b5b92014-01-18 10:56:00 +010077 cmd = 'cut -f1 -d. /proc/uptime'
Elena Ezhova91db24e2014-02-28 20:47:10 +040078 boot_secs = self.exec_command(cmd)
Vincent Untz3c0b5b92014-01-18 10:56:00 +010079 boot_time = time.time() - int(boot_secs)
80 return time.localtime(boot_time)
Attila Fazekasa23f5002012-10-23 19:32:45 +020081
82 def write_to_console(self, message):
83 message = re.sub("([$\\`])", "\\\\\\\\\\1", message)
84 # usually to /dev/ttyS0
85 cmd = 'sudo sh -c "echo \\"%s\\" >/dev/console"' % message
Elena Ezhova91db24e2014-02-28 20:47:10 +040086 return self.exec_command(cmd)
Yair Fried5f670ab2013-12-09 09:26:51 +020087
Yair Friedbc46f592015-11-18 16:29:34 +020088 def get_mac_address(self, nic=""):
89 show_nic = "show {nic} ".format(nic=nic) if nic else ""
90 cmd = "ip addr %s| awk '/ether/ {print $2}'" % show_nic
91 return self.exec_command(cmd).strip().lower()
Yair Fried3097dc12014-01-26 08:46:43 +020092
Evgeny Antyshev9b77ae52016-02-16 09:48:57 +000093 def get_nic_name_by_mac(self, address):
94 cmd = "ip -o link | awk '/%s/ {print $2}'" % address
95 nic = self.exec_command(cmd)
James Pagea9366272017-06-09 12:05:09 +010096 return nic.strip().strip(":").split('@')[0].lower()
Evgeny Antyshev9b77ae52016-02-16 09:48:57 +000097
98 def get_nic_name_by_ip(self, address):
Evgeny Antyshevf58ab6d2015-04-15 08:23:05 +000099 cmd = "ip -o addr | awk '/%s/ {print $2}'" % address
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200100 nic = self.exec_command(cmd)
James Pagea9366272017-06-09 12:05:09 +0100101 return nic.strip().strip(":").split('@')[0].lower()
Yair Fried413bf2d2014-11-19 17:07:11 +0200102
Yair Fried413bf2d2014-11-19 17:07:11 +0200103 def get_dns_servers(self):
104 cmd = 'cat /etc/resolv.conf'
105 resolve_file = self.exec_command(cmd).strip().split('\n')
106 entries = (l.split() for l in resolve_file)
107 dns_servers = [l[1] for l in entries
108 if len(l) and l[0] == 'nameserver']
109 return dns_servers
110
Yair Fried413bf2d2014-11-19 17:07:11 +0200111 def _renew_lease_udhcpc(self, fixed_ip=None):
112 """Renews DHCP lease via udhcpc client. """
113 file_path = '/var/run/udhcpc.'
Evgeny Antyshev9b77ae52016-02-16 09:48:57 +0000114 nic_name = self.get_nic_name_by_ip(fixed_ip)
Yair Fried413bf2d2014-11-19 17:07:11 +0200115 pid = self.exec_command('cat {path}{nic}.pid'.
116 format(path=file_path, nic=nic_name))
117 pid = pid.strip()
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800118 cmd = 'sudo /bin/kill -{sig} {pid}'.format(pid=pid, sig='USR1')
119 self.exec_command(cmd)
Yair Fried413bf2d2014-11-19 17:07:11 +0200120
121 def _renew_lease_dhclient(self, fixed_ip=None):
122 """Renews DHCP lease via dhclient client. """
Itzik Brownffb14022015-03-23 17:03:55 +0200123 cmd = "sudo /sbin/dhclient -r && sudo /sbin/dhclient"
Yair Fried413bf2d2014-11-19 17:07:11 +0200124 self.exec_command(cmd)
125
Ken'ichi Ohmichi4e337852017-03-01 12:04:23 -0800126 def renew_lease(self, fixed_ip=None, dhcp_client='udhcpc'):
Yair Fried413bf2d2014-11-19 17:07:11 +0200127 """Wrapper method for renewing DHCP lease via given client
128
129 Supporting:
130 * udhcpc
131 * dhclient
132 """
133 # TODO(yfried): add support for dhcpcd
Takashi NATSUME6d5a2b42015-09-08 11:27:49 +0900134 supported_clients = ['udhcpc', 'dhclient']
Takashi NATSUME6d5a2b42015-09-08 11:27:49 +0900135 if dhcp_client not in supported_clients:
Matthew Treinish4217a702016-10-07 17:27:11 -0400136 raise tempest.lib.exceptions.InvalidConfiguration(
137 '%s DHCP client unsupported' % dhcp_client)
Yair Fried413bf2d2014-11-19 17:07:11 +0200138 if dhcp_client == 'udhcpc' and not fixed_ip:
139 raise ValueError("need to set 'fixed_ip' for udhcpc client")
Joe Gordon28788b42015-02-25 12:42:37 -0800140 return getattr(self, '_renew_lease_' + dhcp_client)(fixed_ip=fixed_ip)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300141
142 def mount(self, dev_name, mount_path='/mnt'):
143 cmd_mount = 'sudo mount /dev/%s %s' % (dev_name, mount_path)
144 self.exec_command(cmd_mount)
145
146 def umount(self, mount_path='/mnt'):
147 self.exec_command('sudo umount %s' % mount_path)
148
149 def make_fs(self, dev_name, fs='ext4'):
150 cmd_mkfs = 'sudo /usr/sbin/mke2fs -t %s /dev/%s' % (fs, dev_name)
Sean Dague57c66552016-02-08 08:51:13 -0500151 try:
152 self.exec_command(cmd_mkfs)
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -0500153 except tempest.lib.exceptions.SSHExecCommandFailed:
Sean Dague57c66552016-02-08 08:51:13 -0500154 LOG.error("Couldn't mke2fs")
155 cmd_why = 'sudo ls -lR /dev'
Jordan Pittier525ec712016-12-07 17:51:26 +0100156 LOG.info("Contents of /dev: %s", self.exec_command(cmd_why))
Sean Dague57c66552016-02-08 08:51:13 -0500157 raise