Skip to content

Commit e65dc81

Browse files
committed
vm: drop paramiko
And replace with ssh/scp binaries. This is probably more robust than paramiko.
1 parent d7c2d65 commit e65dc81

File tree

1 file changed

+34
-44
lines changed

1 file changed

+34
-44
lines changed

vmtest/vm.py

Lines changed: 34 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,17 @@
1212
from io import StringIO
1313

1414
import boto3
15-
import paramiko
1615
from botocore.exceptions import ClientError
17-
from paramiko.client import AutoAddPolicy, SSHClient
18-
from scp import SCPClient
1916
from vmtest.util import get_free_port, wait_ssh_ready
2017

2118
AWS_REGION = "us-east-1"
2219

23-
# XXX: find better way to control this
24-
if os.environ.get("OSBUILD_TEST_QEMU_VERBOSE"):
25-
logging.getLogger("paramiko").setLevel(logging.DEBUG)
26-
logging.getLogger("paramiko").addHandler(logging.StreamHandler(sys.stderr))
20+
21+
_non_interactive_ssh = [
22+
"-o", "UserKnownHostsFile=/dev/null",
23+
"-o" "StrictHostKeyChecking=no",
24+
"-o", "BatchMode=yes"
25+
]
2726

2827

2928
class VM(abc.ABC):
@@ -54,50 +53,41 @@ def force_stop(self):
5453
Stop the VM and clean up any resources that were created when setting up and starting the machine.
5554
"""
5655

57-
def _get_ssh_transport(self, user, password="", keyfile=None):
58-
if not self.running():
59-
self.start()
60-
client = SSHClient()
61-
client.set_missing_host_key_policy(AutoAddPolicy)
62-
# workaround, see https://github.com/paramiko/paramiko/issues/2048
63-
pkey = None
64-
if keyfile:
65-
for klass in paramiko.key_classes:
66-
try:
67-
pkey = klass.from_private_key_file(keyfile)
68-
break
69-
except paramiko.ssh_exception.SSHException:
70-
continue
71-
if pkey is None:
72-
raise RuntimeError(f"cannot load {keyfile}, tried {paramiko.key_classes}")
73-
client.connect(
74-
self._address, self._ssh_port,
75-
user, password, pkey=pkey,
76-
allow_agent=False, look_for_keys=False)
77-
return client.get_transport()
78-
7956
def run(self, cmd, user, password="", keyfile=None):
8057
"""
8158
Run a command on the VM via SSH using the provided credentials.
8259
"""
83-
tr = self._get_ssh_transport(user, password, keyfile)
84-
chan = tr.open_session()
85-
chan.get_pty()
86-
chan.exec_command(cmd)
87-
stdout_f = chan.makefile()
60+
if not self.running():
61+
self.start()
62+
ssh_cmd = ["ssh", "-p", str(self._ssh_port)] + _non_interactive_ssh
63+
if keyfile:
64+
ssh_cmd.extend(["-i", keyfile])
65+
if password:
66+
ssh_cmd = ["sshpass", "-p", password] + ssh_cmd
67+
ssh_cmd.append(f"{user}@{self._address}")
68+
ssh_cmd.append(cmd)
8869
output = StringIO()
89-
while True:
90-
out = stdout_f.readline()
91-
if not out:
92-
break
93-
self._log(out)
94-
output.write(out)
95-
exit_status = stdout_f.channel.recv_exit_status()
96-
return exit_status, output.getvalue()
70+
with subprocess.Popen(
71+
ssh_cmd,
72+
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
73+
text=True, bufsize=1,
74+
) as p:
75+
for out in p.stdout:
76+
self._log(out)
77+
output.write(out)
78+
return p.returncode, output
9779

9880
def scp(self, src, dst, user, password="", keyfile=None):
99-
with SCPClient(self._get_ssh_transport(user, password, keyfile)) as scp:
100-
scp.put(src, dst)
81+
if not self.running():
82+
self.start()
83+
scp_cmd = ["scp", "-P", str(self._ssh_port)] + _non_interactive_ssh
84+
if keyfile:
85+
scp_cmd.extend(["-i", keyfile])
86+
if password:
87+
scp_cmd = ["sshpass", "-p", password] + scp_cmd
88+
scp_cmd.append(src)
89+
scp_cmd.append(f"{user}@{self._address}:{dst}")
90+
subprocess.check_call(scp_cmd)
10191

10292
@abc.abstractmethod
10393
def running(self):

0 commit comments

Comments
 (0)