Hi Gerd, On 5/20/19 2:47 PM, Gerd Hoffmann wrote: > Add a bunch of helpers to talk to the guest using the > serial console. > > Also drop the hard-coded -serial parameter for the vm > so QEMUMachine.set_console() actually works. > > Signed-off-by: Gerd Hoffmann <kra...@redhat.com> > Tested-by: Thomas Huth <th...@redhat.com> > --- > tests/vm/basevm.py | 85 ++++++++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 82 insertions(+), 3 deletions(-) > > diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py > index 465c7b80d011..17281eaf99e4 100755 > --- a/tests/vm/basevm.py > +++ b/tests/vm/basevm.py > @@ -2,10 +2,11 @@ > # > # VM testing base class > # > -# Copyright 2017 Red Hat Inc. > +# Copyright 2017-2019 Red Hat Inc. > # > # Authors: > # Fam Zheng <f...@redhat.com> > +# Gerd Hoffmann <kra...@redhat.com> > # > # This code is licensed under the GPL version 2 or later. See > # the COPYING file in the top-level directory. > @@ -13,7 +14,9 @@ > > from __future__ import print_function > import os > +import re > import sys > +import socket > import logging > import time > import datetime > @@ -79,8 +82,7 @@ class BaseVM(object): > "-cpu", "max", > "-netdev", "user,id=vnet,hostfwd=:127.0.0.1:0-:22", > "-device", "virtio-net-pci,netdev=vnet", > - "-vnc", "127.0.0.1:0,to=20", > - "-serial", "file:%s" % os.path.join(self._tmpdir, "serial.out")] > + "-vnc", "127.0.0.1:0,to=20"] > if vcpus and vcpus > 1: > self._args += ["-smp", "%d" % vcpus] > if kvm_available(self.arch): > @@ -161,6 +163,8 @@ class BaseVM(object): > logging.debug("QEMU args: %s", " ".join(args)) > qemu_bin = os.environ.get("QEMU", "qemu-system-" + self.arch) > guest = QEMUMachine(binary=qemu_bin, args=args) > + guest.set_machine('pc')
This line broke another series I'm working on, I suggest amending: -- >8 -- --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -154,7 +154,7 @@ class BaseVM(object): "-device", "virtio-blk,drive=%s,serial=%s,bootindex=1" % (name, name)] - def boot(self, img, extra_args=[]): + def boot(self, img, machine='pc', extra_args=[]): args = self._args + [ "-device", "VGA", "-drive", "file=%s,if=none,id=drive0,cache=writeback" % img, @@ -163,7 +163,7 @@ class BaseVM(object): logging.debug("QEMU args: %s", " ".join(args)) qemu_bin = os.environ.get("QEMU", "qemu-system-" + self.arch) guest = QEMUMachine(binary=qemu_bin, args=args) - guest.set_machine('pc') + guest.set_machine(machine) guest.set_console() try: guest.launch() --- Anyway I can do it in a separate patch too, so: Reviewed-by: Philippe Mathieu-Daudé <phi...@redhat.com> Tested-by: Philippe Mathieu-Daudé <phi...@redhat.com> > + guest.set_console() > try: > guest.launch() > except: > @@ -183,6 +187,81 @@ class BaseVM(object): > raise Exception("Cannot find ssh port from 'info usernet':\n%s" > % \ > usernet_info) > > + def console_init(self, timeout = 120): > + vm = self._guest > + vm.console_socket.settimeout(timeout) > + > + def console_log(self, text): > + for line in re.split("[\r\n]", text): > + # filter out terminal escape sequences > + line = re.sub("\x1b\[[0-9;?]*[a-zA-Z]", "", line) > + line = re.sub("\x1b\([0-9;?]*[a-zA-Z]", "", line) > + # replace unprintable chars > + line = re.sub("\x1b", "<esc>", line) > + line = re.sub("[\x00-\x1f]", ".", line) > + if line == "": > + continue > + # log console line > + sys.stderr.write("con recv: %s\n" % line) > + > + def console_wait(self, expect): > + vm = self._guest > + output = "" > + while True: > + try: > + chars = vm.console_socket.recv(1024) > + except socket.timeout: > + sys.stderr.write("console: *** read timeout ***\n") > + sys.stderr.write("console: waiting for: '%s'\n" % expect) > + sys.stderr.write("console: line buffer:\n") > + sys.stderr.write("\n") > + self.console_log(output.rstrip()) > + sys.stderr.write("\n") > + raise > + output += chars.decode("latin1") > + if expect in output: > + break > + if "\r" in output or "\n" in output: > + lines = re.split("[\r\n]", output) > + output = lines.pop() > + if self.debug: > + self.console_log("\n".join(lines)) > + if self.debug: > + self.console_log(output) > + > + def console_send(self, command): > + vm = self._guest > + if self.debug: > + logline = re.sub("\n", "<enter>", command) > + logline = re.sub("[\x00-\x1f]", ".", logline) > + sys.stderr.write("con send: %s\n" % logline) > + for char in list(command): > + vm.console_socket.send(char.encode("utf-8")) > + time.sleep(0.01) > + > + def console_wait_send(self, wait, command): > + self.console_wait(wait) > + self.console_send(command) > + > + def console_ssh_init(self, prompt, user, pw): > + sshkey_cmd = "echo '%s' > .ssh/authorized_keys\n" % > SSH_PUB_KEY.rstrip() > + self.console_wait_send("login:", "%s\n" % user) > + self.console_wait_send("Password:", "%s\n" % pw) > + self.console_wait_send(prompt, "mkdir .ssh\n") > + self.console_wait_send(prompt, sshkey_cmd) > + self.console_wait_send(prompt, "chmod 755 .ssh\n") > + self.console_wait_send(prompt, "chmod 644 > .ssh/authorized_keys\n") > + > + def console_sshd_config(self, prompt): > + self.console_wait(prompt) > + self.console_send("echo 'PermitRootLogin yes' >> > /etc/ssh/sshd_config\n") > + for var in self.envvars: > + self.console_wait(prompt) > + self.console_send("echo 'AcceptEnv %s' >> > /etc/ssh/sshd_config\n" % var) > + > + def print_step(self, text): > + sys.stderr.write("### %s ...\n" % text) > + > def wait_ssh(self, seconds=300): > starttime = datetime.datetime.now() > endtime = starttime + datetime.timedelta(seconds=seconds) >