Skip to content

Commit 0683678

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 0683678

25 files changed

+85
-127
lines changed

tests/framework/utils.py

Lines changed: 5 additions & 7 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()
@@ -441,7 +440,7 @@ def assert_seccomp_level(pid, seccomp_level):
441440

442441
def run_guest_cmd(ssh_connection, cmd, expected, use_json=False):
443442
"""Runs a shell command at the remote accessible via SSH"""
444-
_, stdout, stderr = ssh_connection.check_output(cmd)
443+
_, stdout, stderr = ssh_connection.run(cmd)
445444
assert stderr == ""
446445
stdout = stdout if not use_json else json.loads(stdout)
447446
assert stdout == expected
@@ -625,20 +624,19 @@ 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):
633631
"""Check for filesystem corruption inside a microVM."""
634632
if disk_fmt == "squashfs":
635633
return
636-
ssh_connection.check_output(f"fsck.{disk_fmt} -n {disk}")
634+
ssh_connection.run(f"fsck.{disk_fmt} -n {disk}")
637635

638636

639637
def check_entropy(ssh_connection):
640638
"""Check that we can get random numbers from /dev/hwrng"""
641-
ssh_connection.check_output("dd if=/dev/hwrng of=/dev/null bs=4096 count=1")
639+
ssh_connection.run("dd if=/dev/hwrng of=/dev/null bs=4096 count=1")
642640

643641

644642
@retry(wait=wait_fixed(0.5), stop=stop_after_attempt(5), reraise=True)

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: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414
from framework import utils
1515

1616

17+
class SSHConnectionException(Exception):
18+
"""
19+
Specific exception for ssh errors
20+
"""
21+
pass
22+
23+
1724
class SSHConnection:
1825
"""
1926
SSHConnection encapsulates functionality for microVM SSH interaction.
@@ -58,13 +65,7 @@ def __init__(self, netns, ssh_key: Path, host, user, *, on_error=None):
5865
# _init_connection loops until it can connect to the guest
5966
# dumping debug state on every iteration is not useful or wanted, so
6067
# 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
68+
self._init_connection()
6869

6970
self._on_error = on_error
7071

@@ -79,7 +80,7 @@ def remote_path(self, path):
7980

8081
def _scp(self, path1, path2, options):
8182
"""Copy files to/from the VM using scp."""
82-
self._exec(["scp", *options, path1, path2], check=True)
83+
self._exec(["scp", *options, path1, path2])
8384

8485
def scp_put(self, local_path, remote_path, recursive=False):
8586
"""Copy files to the VM using scp."""
@@ -96,7 +97,7 @@ def scp_get(self, remote_path, local_path, recursive=False):
9697
self._scp(self.remote_path(remote_path), local_path, opts)
9798

9899
@retry(
99-
retry=retry_if_exception_type(ChildProcessError),
100+
retry=retry_if_exception_type(SSHConnectionException),
100101
wait=wait_fixed(0.5),
101102
stop=stop_after_attempt(20),
102103
reraise=True,
@@ -109,11 +110,12 @@ def _init_connection(self):
109110
We'll keep trying to execute a remote command that can't fail
110111
(`/bin/true`), until we get a successful (0) exit code.
111112
"""
112-
self.check_output("true", timeout=100, debug=True)
113+
self.run("true", timeout=100, debug=True)
113114

114-
def run(self, cmd_string, timeout=None, *, check=False, debug=False):
115+
def run(self, cmd_string, timeout=None, *, check=True, debug=False):
115116
"""
116117
Execute the command passed as a string in the ssh context.
118+
By default raises an exception on non-zero return code of remote command.
117119
118120
If `debug` is set, pass `-vvv` to `ssh`. Note that this will clobber stderr.
119121
"""
@@ -124,11 +126,7 @@ def run(self, cmd_string, timeout=None, *, check=False, debug=False):
124126

125127
return self._exec(command, timeout, check=check)
126128

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):
129+
def _exec(self, cmd, timeout=None, check=True):
132130
"""Private function that handles the ssh client invocation."""
133131
if self.netns is not None:
134132
cmd = ["ip", "netns", "exec", self.netns] + cmd

tests/integration_tests/functional/test_balloon.py

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,39 +41,20 @@ 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):
6452
"""Tell the guest, over ssh, to dirty `amount` pages of memory."""
65-
logger = logging.getLogger("make_guest_dirty_memory")
66-
6753
lower_ssh_oom_chance(ssh_connection)
6854

6955
cmd = f"/usr/local/bin/fillmem {amount_mib}"
7056
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)
57+
ssh_connection.run(cmd, timeout=1.0)
7758
except TimeoutExpired:
7859
# It's ok if this expires. Sometimes the SSH connection
7960
# gets killed by the OOM killer *after* the fillmem program
@@ -558,4 +539,4 @@ def test_memory_scrub(microvm_factory, guest_kernel, rootfs):
558539
# Wait for the deflate to complete.
559540
_ = get_stable_rss_mem_by_pid(firecracker_pid)
560541

561-
microvm.ssh.check_output("/usr/local/bin/readmem {} {}".format(60, 1))
542+
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)

tests/integration_tests/functional/test_kvm_ptp.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def test_kvm_ptp(uvm_plain_any):
1818
vm.add_net_iface()
1919
vm.start()
2020

21-
vm.ssh.check_output("[ -c /dev/ptp0 ]")
21+
vm.ssh.run("[ -c /dev/ptp0 ]")
2222

2323
# phc_ctl[14515.127]: clock time is 1697545854.728335694 or Tue Oct 17 12:30:54 2023
24-
vm.ssh.check_output("phc_ctl /dev/ptp0 -- get")
24+
vm.ssh.run("phc_ctl /dev/ptp0 -- get")

0 commit comments

Comments
 (0)