Skip to content

Commit ed45e17

Browse files
committed
refactor(tests): always check ssh output
Ssh connection failure should be considered an error by default. In order to unify handling of this case, move check for non zero return code into the function itself. Because of this `check_output` method is not needed anymore and was removed. Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent 81bae9f commit ed45e17

25 files changed

+80
-113
lines changed

tests/framework/microvm.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,14 +1003,13 @@ def thread_backtraces(self):
10031003
)
10041004
return "\n".join(backtraces)
10051005

1006-
def _dump_debug_information(self, exc: Exception):
1006+
def _dump_debug_information(self):
10071007
"""
10081008
Dumps debug information about this microvm
10091009
10101010
Used for example when running a command inside the guest via `SSHConnection.check_output` fails.
10111011
"""
10121012
print(
1013-
f"Failure executing command via SSH in microVM: {exc}\n\n"
10141013
f"Firecracker logs:\n{self.log_data}\n"
10151014
f"Thread backtraces:\n{self.thread_backtraces}"
10161015
)

tests/framework/utils.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -350,8 +350,7 @@ def get_free_mem_ssh(ssh_connection):
350350
:param ssh_connection: connection to the guest
351351
:return: available mem column output of 'free'
352352
"""
353-
_, stdout, stderr = ssh_connection.run("cat /proc/meminfo | grep MemAvailable")
354-
assert stderr == ""
353+
_, stdout, _ = ssh_connection.run("cat /proc/meminfo | grep MemAvailable")
355354

356355
# Split "MemAvailable: 123456 kB" and validate it
357356
meminfo_data = stdout.split()
@@ -625,8 +624,7 @@ def guest_run_fio_iteration(ssh_connection, iteration):
625624
--output /tmp/fio{} > /dev/null &""".format(
626625
iteration
627626
)
628-
exit_code, _, stderr = ssh_connection.run(fio)
629-
assert exit_code == 0, stderr
627+
ssh_connection.run(fio)
630628

631629

632630
def check_filesystem(ssh_connection, disk_fmt, disk):

tests/framework/utils_iperf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def spawn_iperf3_client(self, client_idx, client_mode_flag):
119119
.build()
120120
)
121121

122-
return self._microvm.ssh.check_output(cmd).stdout
122+
return self._microvm.ssh.run(cmd).stdout
123123

124124
def host_command(self, port_offset):
125125
"""Builds the command used for spawning an iperf3 server on the host"""

tests/framework/utils_vsock.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def start_guest_echo_server(vm):
100100
Returns a UDS path to connect to the server.
101101
"""
102102
cmd = f"nohup socat VSOCK-LISTEN:{ECHO_SERVER_PORT},backlog=128,reuseaddr,fork EXEC:'/bin/cat' > /dev/null 2>&1 &"
103-
vm.ssh.check_output(cmd)
103+
vm.ssh.run(cmd)
104104

105105
# Give the server time to initialise
106106
time.sleep(1)
@@ -214,8 +214,7 @@ def _copy_vsock_data_to_guest(ssh_connection, blob_path, vm_blob_path, vsock_hel
214214
# Copy the data file and a vsock helper to the guest.
215215

216216
cmd = "mkdir -p /tmp/vsock"
217-
ecode, _, _ = ssh_connection.run(cmd)
218-
assert ecode == 0, "Failed to set up tmpfs drive on the guest."
217+
ssh_connection.run(cmd)
219218

220219
ssh_connection.scp_put(vsock_helper, "/tmp/vsock_helper")
221220
ssh_connection.scp_put(blob_path, vm_blob_path)

tests/host_tools/network.py

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,7 @@ def __init__(self, netns, ssh_key: Path, host, user, *, on_error=None):
5858
# _init_connection loops until it can connect to the guest
5959
# dumping debug state on every iteration is not useful or wanted, so
6060
# only dump it once if _all_ iterations fail.
61-
try:
62-
self._init_connection()
63-
except Exception as exc:
64-
if on_error:
65-
on_error(exc)
66-
67-
raise
61+
self._init_connection()
6862

6963
self._on_error = on_error
7064

@@ -79,7 +73,7 @@ def remote_path(self, path):
7973

8074
def _scp(self, path1, path2, options):
8175
"""Copy files to/from the VM using scp."""
82-
self._exec(["scp", *options, path1, path2], check=True)
76+
self._exec(["scp", *options, path1, path2])
8377

8478
def scp_put(self, local_path, remote_path, recursive=False):
8579
"""Copy files to the VM using scp."""
@@ -96,7 +90,7 @@ def scp_get(self, remote_path, local_path, recursive=False):
9690
self._scp(self.remote_path(remote_path), local_path, opts)
9791

9892
@retry(
99-
retry=retry_if_exception_type(ChildProcessError),
93+
retry=retry_if_exception_type(AssertionError),
10094
wait=wait_fixed(0.5),
10195
stop=stop_after_attempt(20),
10296
reraise=True,
@@ -109,11 +103,12 @@ def _init_connection(self):
109103
We'll keep trying to execute a remote command that can't fail
110104
(`/bin/true`), until we get a successful (0) exit code.
111105
"""
112-
self.check_output("true", timeout=100, debug=True)
106+
self.run("true", timeout=100, debug=True)
113107

114-
def run(self, cmd_string, timeout=None, *, check=False, debug=False):
108+
def run(self, cmd_string, timeout=None, *, check=True, debug=False):
115109
"""
116110
Execute the command passed as a string in the ssh context.
111+
By default raises an exception on non-zero return code of remote command.
117112
118113
If `debug` is set, pass `-vvv` to `ssh`. Note that this will clobber stderr.
119114
"""
@@ -124,22 +119,29 @@ def run(self, cmd_string, timeout=None, *, check=False, debug=False):
124119

125120
return self._exec(command, timeout, check=check)
126121

127-
def check_output(self, cmd_string, timeout=None, *, debug=False):
128-
"""Same as `run`, but raises an exception on non-zero return code of remote command"""
129-
return self.run(cmd_string, timeout, check=True, debug=debug)
130-
131-
def _exec(self, cmd, timeout=None, check=False):
122+
def _exec(self, cmd, timeout=None, check=True):
132123
"""Private function that handles the ssh client invocation."""
133124
if self.netns is not None:
134125
cmd = ["ip", "netns", "exec", self.netns] + cmd
135126

136-
try:
137-
return utils.run_cmd(cmd, check=check, timeout=timeout)
138-
except Exception as exc:
127+
rc, stdout, stderr = utils.run_cmd(cmd, timeout=timeout)
128+
129+
if not check:
130+
return rc, stdout, stderr
131+
132+
if rc != 0:
133+
print(
134+
f"SSH command {cmd} exited with non zero error code: {rc}\n"
135+
f"stdout: {stdout}\n"
136+
f"stderr: {stderr}\n"
137+
)
138+
139139
if self._on_error:
140-
self._on_error(exc)
140+
self._on_error()
141+
142+
assert False
141143

142-
raise
144+
return rc, stdout, stderr
143145

144146
# pylint:disable=invalid-name
145147
def Popen(

tests/integration_tests/functional/test_balloon.py

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -41,23 +41,11 @@ def get_rss_from_pmap():
4141

4242
def lower_ssh_oom_chance(ssh_connection):
4343
"""Lure OOM away from ssh process"""
44-
logger = logging.getLogger("lower_ssh_oom_chance")
45-
4644
cmd = "cat /run/sshd.pid"
47-
exit_code, stdout, stderr = ssh_connection.run(cmd)
48-
# add something to the logs for troubleshooting
49-
if exit_code != 0:
50-
logger.error("while running: %s", cmd)
51-
logger.error("stdout: %s", stdout)
52-
logger.error("stderr: %s", stderr)
53-
45+
_, stdout, _ = ssh_connection.run(cmd)
5446
for pid in stdout.split(" "):
5547
cmd = f"choom -n -1000 -p {pid}"
56-
exit_code, stdout, stderr = ssh_connection.run(cmd)
57-
if exit_code != 0:
58-
logger.error("while running: %s", cmd)
59-
logger.error("stdout: %s", stdout)
60-
logger.error("stderr: %s", stderr)
48+
ssh_connection.run(cmd)
6149

6250

6351
def make_guest_dirty_memory(ssh_connection, amount_mib=32):
@@ -68,12 +56,7 @@ def make_guest_dirty_memory(ssh_connection, amount_mib=32):
6856

6957
cmd = f"/usr/local/bin/fillmem {amount_mib}"
7058
try:
71-
exit_code, stdout, stderr = ssh_connection.run(cmd, timeout=1.0)
72-
# add something to the logs for troubleshooting
73-
if exit_code != 0:
74-
logger.error("while running: %s", cmd)
75-
logger.error("stdout: %s", stdout)
76-
logger.error("stderr: %s", stderr)
59+
ssh_connection.run(cmd, timeout=1.0)
7760
except TimeoutExpired:
7861
# It's ok if this expires. Sometimes the SSH connection
7962
# gets killed by the OOM killer *after* the fillmem program
@@ -558,4 +541,4 @@ def test_memory_scrub(microvm_factory, guest_kernel, rootfs):
558541
# Wait for the deflate to complete.
559542
_ = get_stable_rss_mem_by_pid(firecracker_pid)
560543

561-
microvm.ssh.check_output("/usr/local/bin/readmem {} {}".format(60, 1))
544+
microvm.ssh.run("/usr/local/bin/readmem {} {}".format(60, 1))

tests/integration_tests/functional/test_cpu_features_aarch64.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def _check_cpu_features_arm(test_microvm, guest_kv, template_name=None):
5151
case CpuModel.ARM_NEOVERSE_V1, _, None:
5252
expected_cpu_features = DEFAULT_G3_FEATURES_5_10
5353

54-
_, stdout, _ = test_microvm.ssh.check_output(CPU_FEATURES_CMD)
54+
_, stdout, _ = test_microvm.ssh.run(CPU_FEATURES_CMD)
5555
flags = set(stdout.strip().split(" "))
5656
assert flags == expected_cpu_features
5757

@@ -77,7 +77,7 @@ def test_host_vs_guest_cpu_features_aarch64(uvm_nano):
7777
vm.add_net_iface()
7878
vm.start()
7979
host_feats = set(utils.check_output(CPU_FEATURES_CMD).stdout.strip().split(" "))
80-
guest_feats = set(vm.ssh.check_output(CPU_FEATURES_CMD).stdout.strip().split(" "))
80+
guest_feats = set(vm.ssh.run(CPU_FEATURES_CMD).stdout.strip().split(" "))
8181

8282
cpu_model = cpuid_utils.get_cpu_model_name()
8383
match cpu_model:

tests/integration_tests/functional/test_cpu_features_x86_64.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ def test_host_vs_guest_cpu_features_x86_64(uvm_nano):
215215
vm.add_net_iface()
216216
vm.start()
217217
host_feats = set(utils.check_output(CPU_FEATURES_CMD).stdout.strip().split(" "))
218-
guest_feats = set(vm.ssh.check_output(CPU_FEATURES_CMD).stdout.strip().split(" "))
218+
guest_feats = set(vm.ssh.run(CPU_FEATURES_CMD).stdout.strip().split(" "))
219219

220220
cpu_model = cpuid_utils.get_cpu_codename()
221221
match cpu_model:

tests/integration_tests/functional/test_drive_vhost_user.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ def _check_block_size(ssh_connection, dev_path, size):
1515
"""
1616
Checks the size of the block device.
1717
"""
18-
_, stdout, stderr = ssh_connection.run("blockdev --getsize64 {}".format(dev_path))
19-
assert stderr == ""
18+
_, stdout, _ = ssh_connection.run("blockdev --getsize64 {}".format(dev_path))
2019
assert stdout.strip() == str(size)
2120

2221

@@ -297,7 +296,7 @@ def test_config_change(microvm_factory, guest_kernel, rootfs):
297296
_check_block_size(vm.ssh, "/dev/vdb", orig_size * 1024 * 1024)
298297

299298
# Check that we can create a filesystem and mount it
300-
vm.ssh.check_output(mkfs_mount_cmd)
299+
vm.ssh.run(mkfs_mount_cmd)
301300

302301
for new_size in new_sizes:
303302
# Instruct the backend to resize the device.
@@ -312,4 +311,4 @@ def test_config_change(microvm_factory, guest_kernel, rootfs):
312311
_check_block_size(vm.ssh, "/dev/vdb", new_size * 1024 * 1024)
313312

314313
# Check that we can create a filesystem and mount it
315-
vm.ssh.check_output(mkfs_mount_cmd)
314+
vm.ssh.run(mkfs_mount_cmd)

tests/integration_tests/functional/test_drive_virtio.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ def test_patch_drive(uvm_plain_any, io_engine):
283283
# of the device, in bytes.
284284
blksize_cmd = "LSBLK_DEBUG=all lsblk -b /dev/vdb --output SIZE"
285285
size_bytes_str = "536870912" # = 512 MiB
286-
_, stdout, _ = test_microvm.ssh.check_output(blksize_cmd)
286+
_, stdout, _ = test_microvm.ssh.run(blksize_cmd)
287287
lines = stdout.split("\n")
288288
# skip "SIZE"
289289
assert lines[1].strip() == size_bytes_str
@@ -354,14 +354,12 @@ def test_flush(uvm_plain_rw, io_engine):
354354

355355

356356
def _check_block_size(ssh_connection, dev_path, size):
357-
_, stdout, stderr = ssh_connection.run("blockdev --getsize64 {}".format(dev_path))
358-
assert stderr == ""
357+
_, stdout, _ = ssh_connection.run("blockdev --getsize64 {}".format(dev_path))
359358
assert stdout.strip() == str(size)
360359

361360

362361
def _check_file_size(ssh_connection, dev_path, size):
363-
_, stdout, stderr = ssh_connection.run("stat --format=%s {}".format(dev_path))
364-
assert stderr == ""
362+
_, stdout, _ = ssh_connection.run("stat --format=%s {}".format(dev_path))
365363
assert stdout.strip() == str(size)
366364

367365

@@ -379,7 +377,5 @@ def _check_drives(test_microvm, assert_dict, keys_array):
379377

380378

381379
def _check_mount(ssh_connection, dev_path):
382-
_, _, stderr = ssh_connection.run(f"mount {dev_path} /tmp", timeout=30.0)
383-
assert stderr == ""
384-
_, _, stderr = ssh_connection.run("umount /tmp", timeout=30.0)
385-
assert stderr == ""
380+
ssh_connection.run(f"mount {dev_path} /tmp", timeout=30.0)
381+
ssh_connection.run("umount /tmp", timeout=30.0)

0 commit comments

Comments
 (0)