Skip to content

Commit 774d599

Browse files
committed
test: add Microvm.ssh.Popen command
This returns a Popen object instead of waiting for the command to finish. It may be useful when we need to incrementally read the output of a long running process in the guest, without having to use screen. Signed-off-by: Pablo Barbáchano <[email protected]>
1 parent 4f8c689 commit 774d599

File tree

1 file changed

+30
-12
lines changed

1 file changed

+30
-12
lines changed

tests/host_tools/network.py

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import ipaddress
66
import random
77
import string
8+
import subprocess
89
from dataclasses import dataclass, field
910
from pathlib import Path
1011

@@ -54,9 +55,14 @@ def __init__(self, netns, ssh_key: Path, host, user):
5455

5556
self._init_connection()
5657

58+
@property
59+
def user_host(self):
60+
"""remote address for in SSH format <user>@<IP>"""
61+
return f"{self.user}@{self.host}"
62+
5763
def remote_path(self, path):
5864
"""Convert a path to remote"""
59-
return f"{self.user}@{self.host}:{path}"
65+
return f"{self.user_host}:{path}"
6066

6167
def _scp(self, path1, path2, options):
6268
"""Copy files to/from the VM using scp."""
@@ -98,21 +104,12 @@ def run(self, cmd_string, timeout=None, *, check=False, debug=False):
98104
99105
If `debug` is set, pass `-vvv` to `ssh`. Note that this will clobber stderr.
100106
"""
101-
command = [
102-
"ssh",
103-
*self.options,
104-
f"{self.user}@{self.host}",
105-
cmd_string,
106-
]
107+
command = ["ssh", *self.options, self.user_host, cmd_string]
107108

108109
if debug:
109110
command.insert(1, "-vvv")
110111

111-
return self._exec(
112-
command,
113-
timeout,
114-
check=check,
115-
)
112+
return self._exec(command, timeout, check=check)
116113

117114
def check_output(self, cmd_string, timeout=None, *, debug=False):
118115
"""Same as `run`, but raises an exception on non-zero return code of remote command"""
@@ -125,6 +122,27 @@ def _exec(self, cmd, timeout=None, check=False):
125122

126123
return utils.run_cmd(cmd, check=check, timeout=timeout)
127124

125+
# pylint:disable=invalid-name
126+
def Popen(
127+
self,
128+
cmd: str,
129+
stdin=subprocess.DEVNULL,
130+
stdout=subprocess.PIPE,
131+
stderr=subprocess.PIPE,
132+
**kwargs,
133+
) -> subprocess.Popen:
134+
"""Execute the command in the guest and return a Popen object.
135+
136+
pop = uvm.ssh.Popen("while true; do echo $(date -Is) $RANDOM; sleep 1; done")
137+
pop.stdout.read(16)
138+
"""
139+
cmd = ["ssh", *self.options, self.user_host, cmd]
140+
if self.netns is not None:
141+
cmd = ["ip", "netns", "exec", self.netns] + cmd
142+
return subprocess.Popen(
143+
cmd, stdin=stdin, stdout=stdout, stderr=stderr, **kwargs
144+
)
145+
128146

129147
def mac_from_ip(ip_address):
130148
"""Create a MAC address based on the provided IP.

0 commit comments

Comments
 (0)