blob: 144ef600e06aa6987633cc35444dba7f65d143ce [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
67 elif pos > 0 and l[pos:pos + 4] == "disk":
68 selected.append(l)
69
70 return "\n".join(selected)
Daryl Walleck98e66dd2012-06-21 04:58:39 -050071
72 def get_boot_time(self):
Vincent Untz3c0b5b92014-01-18 10:56:00 +010073 cmd = 'cut -f1 -d. /proc/uptime'
Elena Ezhova91db24e2014-02-28 20:47:10 +040074 boot_secs = self.exec_command(cmd)
Vincent Untz3c0b5b92014-01-18 10:56:00 +010075 boot_time = time.time() - int(boot_secs)
76 return time.localtime(boot_time)
Attila Fazekasa23f5002012-10-23 19:32:45 +020077
78 def write_to_console(self, message):
79 message = re.sub("([$\\`])", "\\\\\\\\\\1", message)
80 # usually to /dev/ttyS0
81 cmd = 'sudo sh -c "echo \\"%s\\" >/dev/console"' % message
Elena Ezhova91db24e2014-02-28 20:47:10 +040082 return self.exec_command(cmd)
Yair Fried5f670ab2013-12-09 09:26:51 +020083
Yair Friedbc46f592015-11-18 16:29:34 +020084 def set_mac_address(self, nic, address):
Ken'ichi Ohmichi126fe982017-03-17 10:41:44 -070085 self.exec_command("sudo ip link set %s down" % nic)
Yair Friedbc46f592015-11-18 16:29:34 +020086 cmd = "sudo ip link set dev {0} address {1}".format(nic, address)
87 self.exec_command(cmd)
Ken'ichi Ohmichi126fe982017-03-17 10:41:44 -070088 self.exec_command("sudo ip link set %s up" % nic)
Yair Friedbc46f592015-11-18 16:29:34 +020089
90 def get_mac_address(self, nic=""):
91 show_nic = "show {nic} ".format(nic=nic) if nic else ""
92 cmd = "ip addr %s| awk '/ether/ {print $2}'" % show_nic
93 return self.exec_command(cmd).strip().lower()
Yair Fried3097dc12014-01-26 08:46:43 +020094
Evgeny Antyshev9b77ae52016-02-16 09:48:57 +000095 def get_nic_name_by_mac(self, address):
96 cmd = "ip -o link | awk '/%s/ {print $2}'" % address
97 nic = self.exec_command(cmd)
98 return nic.strip().strip(":").lower()
99
100 def get_nic_name_by_ip(self, address):
Evgeny Antyshevf58ab6d2015-04-15 08:23:05 +0000101 cmd = "ip -o addr | awk '/%s/ {print $2}'" % address
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200102 nic = self.exec_command(cmd)
103 return nic.strip().strip(":").lower()
Yair Fried413bf2d2014-11-19 17:07:11 +0200104
Yair Fried413bf2d2014-11-19 17:07:11 +0200105 def get_dns_servers(self):
106 cmd = 'cat /etc/resolv.conf'
107 resolve_file = self.exec_command(cmd).strip().split('\n')
108 entries = (l.split() for l in resolve_file)
109 dns_servers = [l[1] for l in entries
110 if len(l) and l[0] == 'nameserver']
111 return dns_servers
112
Yair Fried413bf2d2014-11-19 17:07:11 +0200113 def _renew_lease_udhcpc(self, fixed_ip=None):
114 """Renews DHCP lease via udhcpc client. """
115 file_path = '/var/run/udhcpc.'
Evgeny Antyshev9b77ae52016-02-16 09:48:57 +0000116 nic_name = self.get_nic_name_by_ip(fixed_ip)
Yair Fried413bf2d2014-11-19 17:07:11 +0200117 pid = self.exec_command('cat {path}{nic}.pid'.
118 format(path=file_path, nic=nic_name))
119 pid = pid.strip()
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800120 cmd = 'sudo /bin/kill -{sig} {pid}'.format(pid=pid, sig='USR1')
121 self.exec_command(cmd)
Yair Fried413bf2d2014-11-19 17:07:11 +0200122
123 def _renew_lease_dhclient(self, fixed_ip=None):
124 """Renews DHCP lease via dhclient client. """
Itzik Brownffb14022015-03-23 17:03:55 +0200125 cmd = "sudo /sbin/dhclient -r && sudo /sbin/dhclient"
Yair Fried413bf2d2014-11-19 17:07:11 +0200126 self.exec_command(cmd)
127
Ken'ichi Ohmichi4e337852017-03-01 12:04:23 -0800128 def renew_lease(self, fixed_ip=None, dhcp_client='udhcpc'):
Yair Fried413bf2d2014-11-19 17:07:11 +0200129 """Wrapper method for renewing DHCP lease via given client
130
131 Supporting:
132 * udhcpc
133 * dhclient
134 """
135 # TODO(yfried): add support for dhcpcd
Takashi NATSUME6d5a2b42015-09-08 11:27:49 +0900136 supported_clients = ['udhcpc', 'dhclient']
Takashi NATSUME6d5a2b42015-09-08 11:27:49 +0900137 if dhcp_client not in supported_clients:
Matthew Treinish4217a702016-10-07 17:27:11 -0400138 raise tempest.lib.exceptions.InvalidConfiguration(
139 '%s DHCP client unsupported' % dhcp_client)
Yair Fried413bf2d2014-11-19 17:07:11 +0200140 if dhcp_client == 'udhcpc' and not fixed_ip:
141 raise ValueError("need to set 'fixed_ip' for udhcpc client")
Joe Gordon28788b42015-02-25 12:42:37 -0800142 return getattr(self, '_renew_lease_' + dhcp_client)(fixed_ip=fixed_ip)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300143
144 def mount(self, dev_name, mount_path='/mnt'):
145 cmd_mount = 'sudo mount /dev/%s %s' % (dev_name, mount_path)
146 self.exec_command(cmd_mount)
147
148 def umount(self, mount_path='/mnt'):
149 self.exec_command('sudo umount %s' % mount_path)
150
151 def make_fs(self, dev_name, fs='ext4'):
152 cmd_mkfs = 'sudo /usr/sbin/mke2fs -t %s /dev/%s' % (fs, dev_name)
Sean Dague57c66552016-02-08 08:51:13 -0500153 try:
154 self.exec_command(cmd_mkfs)
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -0500155 except tempest.lib.exceptions.SSHExecCommandFailed:
Sean Dague57c66552016-02-08 08:51:13 -0500156 LOG.error("Couldn't mke2fs")
157 cmd_why = 'sudo ls -lR /dev'
Jordan Pittier525ec712016-12-07 17:51:26 +0100158 LOG.info("Contents of /dev: %s", self.exec_command(cmd_why))
Sean Dague57c66552016-02-08 08:51:13 -0500159 raise