Skip to contentSkip to conversation

python-next patches for 2020-05-31

GIT PULL Applied Philippe Mathieu-Daudé 2 participants 27 messages May 31, 2020 – Jun 1, 2020 KVM

lore
Share & tools
lore
#0 lore raw

The following changes since commit c86274bc2e34295764fb44c2aef3cf29623f9b4b:

Merge remote-tracking branch 'remotes/stsquad/tags/pull-testing-tcg-plugins=
-270520-1' into staging (2020-05-29 17:41:45 +0100)

are available in the Git repository at:

https://gitlab.com/philmd/qemu.git tags/python-next-20200531

for you to fetch changes up to 1c80c87c8c2489e4318c93c844aa29bc1d014146:

tests/acceptance: refactor boot_linux to allow code reuse (2020-05-31 18:25=
:31 +0200)

----------------------------------------------------------------
Python queue:

* migration acceptance test fix
* introduce pylintrc & flake8 config
* various cleanups (Python3, style)
* vm-test can set QEMU_LOCAL=3D1 to use locally built binaries
* refactored BootLinuxBase & LinuxKernelTest acceptance classes

https://gitlab.com/philmd/qemu/pipelines/151323210
https://travis-ci.org/github/philmd/qemu/builds/693157969

----------------------------------------------------------------

Dr. David Alan Gilbert (1):
tests/acceptance/migration.py: Wait for both sides

John Snow (11):
scripts/qmp: Fix shebang and imports
python: remove more instances of sys.version_info python/qemu/machine: remove logging configuration python/qemu: delint and add pylintrc python/qemu: delint; add flake8 config python/qemu: remove Python2 style super() calls python/qemu: fix socket.makefile() typing python/qemu: Adjust traceback typing python/qemu/qmp: use True/False for non/blocking modes python/qemu/qmp: assert sockfile is not None python/qemu/qtest: Check before accessing _qtest

Pavel Dovgaluk (3):
tests/acceptance: allow console interaction with specific VMs tests/acceptance: refactor boot_linux_console test to allow code reuse tests/acceptance: refactor boot_linux to allow code reuse

Philippe Mathieu-Daud=C3=A9 (6):
scripts/qemugdb: Remove shebang header scripts/qemu-gdb: Use Python 3 interpreter
scripts/qmp: Use Python 3 interpreter scripts/kvm/vmxcap: Use Python 3 interpreter and add pseudo-main() scripts/modules/module_block: Use Python 3 interpreter & add
pseudo-main
tests/migration/guestperf: Use Python 3 interpreter

Robert Foley (3):
tests/vm: Pass --debug through for vm-boot-ssh tests/vm: Add ability to select QEMU from current build tests/vm: allow wait_ssh() to specify command

Vladimir Sementsov-Ogievskiy (1):
python/qemu/machine: add kill() method

 python/qemu/.flake8                       |  2 +
 python/qemu/accel.py                      |  9 ++-
 python/qemu/machine.py                    | 44 +++++++-----
 python/qemu/pylintrc                      | 58 ++++++++++++++++
 python/qemu/qmp.py                        | 29 +++++---
 python/qemu/qtest.py                      | 83 +++++++++++++++--------
 scripts/analyze-migration.py              |  5 --
 scripts/decodetree.py                     | 25 +++----
 scripts/kvm/vmxcap                        |  7 +-
 scripts/modules/module_block.py           | 29 ++++----
 scripts/qemu-gdb.py                       |  4 +-
 scripts/qemugdb/__init__.py               |  3 +-
 scripts/qemugdb/aio.py                    |  3 +-
 scripts/qemugdb/coroutine.py              |  3 +-
 scripts/qemugdb/mtree.py                  |  4 +-
 scripts/qemugdb/tcg.py                    |  1 -
 scripts/qemugdb/timers.py                 |  1 -
 scripts/qmp/qmp                           |  4 +-
 scripts/qmp/qmp-shell                     |  3 -
 scripts/qmp/qom-fuse                      |  4 +-
 scripts/qmp/qom-get                       |  6 +-
 scripts/qmp/qom-list                      |  6 +-
 scripts/qmp/qom-set                       |  6 +-
 scripts/qmp/qom-tree                      |  6 +-
 tests/acceptance/avocado_qemu/__init__.py | 13 ++--
 tests/acceptance/boot_linux.py            | 49 +++++++------
 tests/acceptance/boot_linux_console.py    | 21 +++---
 tests/acceptance/migration.py             |  4 ++
 tests/docker/docker.py                    |  5 +-
 tests/migration/guestperf-batch.py        |  2 +-
 tests/migration/guestperf-plot.py         |  2 +-
 tests/migration/guestperf.py              |  2 +-
 tests/qemu-iotests/nbd-fault-injector.py  |  5 +-
 tests/vm/Makefile.include                 |  5 ++
 tests/vm/basevm.py                        | 42 ++++++++----
 35 files changed, 317 insertions(+), 178 deletions(-)
 create mode 100644 python/qemu/.flake8
 create mode 100644 python/qemu/pylintrc

--=20
2.21.3

#1 lore raw

[PULL 01/25] scripts/qemugdb: Remove shebang header

From: Philippe Mathieu-Daudé <[email protected]>

These scripts are loaded as plugin by GDB (and they don't have any __main__ entry point). Remove the shebang header.

Message-Id: <[email protected]>

---
 scripts/qemugdb/__init__.py  | 3 +--
 scripts/qemugdb/aio.py       | 3 +--
 scripts/qemugdb/coroutine.py | 3 +--
 scripts/qemugdb/mtree.py     | 4 +---
 scripts/qemugdb/tcg.py       | 1 -
 scripts/qemugdb/timers.py    | 1 -
 6 files changed, 4 insertions(+), 11 deletions(-)
scripts/qemugdb/__init__.py +1 -2
index 969f552b26..da8ff612e5 100644
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-
+#
 # GDB debugging support
 #
 # Copyright (c) 2015 Linaro Ltd
scripts/qemugdb/aio.py +1 -2
index 2ba00c4444..d7c1ba0c28 100644
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-
+#
 # GDB debugging support: aio/iohandler debug
 #
 # Copyright (c) 2015 Red Hat, Inc.
scripts/qemugdb/coroutine.py +1 -2
index 41e079d0e2..db61389022 100644
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-
+#
 # GDB debugging support
 #
 # Copyright 2012 Red Hat, Inc. and/or its affiliates
scripts/qemugdb/mtree.py +1 -3
index 3030a60d3f..8fe42c3c12 100644
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-
+#
 # GDB debugging support
 #
 # Copyright 2012 Red Hat, Inc. and/or its affiliates
@@ -84,4 +83,3 @@ def print_item(self, ptr, offset = gdb.Value(0), level = 0):
         while not isnull(subregion):
             self.print_item(subregion, addr, level)
             subregion = subregion['subregions_link']['tqe_next']
-
scripts/qemugdb/tcg.py +0 -1
index 18880fc9a7..16c03c06a9 100644
@@ -1,4 +1,3 @@
-#!/usr/bin/python
 # -*- coding: utf-8 -*-
 #
 # GDB debugging support, TCG status
scripts/qemugdb/timers.py +0 -1
index f0e132d27a..46537b27cf 100644
@@ -1,4 +1,3 @@
-#!/usr/bin/python
 # -*- coding: utf-8 -*-
 # GDB debugging support
 #
Signature · 1 line
2.21.3
#2 lore raw

[PULL 02/25] scripts/qemu-gdb: Use Python 3 interpreter

In reply to Philippe Mathieu-Daudé

From: Philippe Mathieu-Daudé <[email protected]>

Message-Id: <[email protected]>

---
 scripts/qemu-gdb.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
scripts/qemu-gdb.py +2 -2
index f2a305c42e..e0bfa7b5a4 100644
@@ -1,5 +1,5 @@
-#!/usr/bin/python
-
+#!/usr/bin/env python3
+#
 # GDB debugging support
 #
 # Copyright 2012 Red Hat, Inc. and/or its affiliates
Signature · 1 line
2.21.3
#3 lore raw

[PULL 03/25] scripts/qmp: Use Python 3 interpreter

In reply to Philippe Mathieu-Daudé

From: Philippe Mathieu-Daudé <[email protected]>

Message-Id: <[email protected]>

---
 scripts/qmp/qom-get  | 2 +-
 scripts/qmp/qom-list | 2 +-
 scripts/qmp/qom-set  | 2 +-
 scripts/qmp/qom-tree | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)
scripts/qmp/qom-get +1 -1
index 007b4cd442..7c5ede91bb 100755
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 ##
 # QEMU Object Model test tools
 #
scripts/qmp/qom-list +1 -1
index 03bda3446b..bb68fd65d4 100755
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 ##
 # QEMU Object Model test tools
 #
scripts/qmp/qom-set +1 -1
index c37fe78b00..19881d85e9 100755
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 ##
 # QEMU Object Model test tools
 #
scripts/qmp/qom-tree +1 -1
index 1c8acf61e7..fa91147a03 100755
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 ##
 # QEMU Object Model test tools
 #
Signature · 1 line
2.21.3
#4 lore raw

[PULL 04/25] scripts/kvm/vmxcap: Use Python 3 interpreter and add pseudo-main()

In reply to Philippe Mathieu-Daudé

Message-Id: <[email protected]>

---
 scripts/kvm/vmxcap | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
scripts/kvm/vmxcap +4 -3
index 971ed0e721..6fe66d5f57 100755
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 #
 # tool for querying VMX capabilities
 #
@@ -275,5 +275,6 @@ controls = [
         ),
     ]
 
-for c in controls:
-    c.show()
+if __name__ == '__main__':
+    for c in controls:
+        c.show()
Signature · 1 line
2.21.3
#5 lore raw

[PULL 05/25] scripts/modules/module_block: Use Python 3 interpreter & add pseudo-main

In reply to Philippe Mathieu-Daudé

Message-Id: <[email protected]>

---
 scripts/modules/module_block.py | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)
scripts/modules/module_block.py +15 -14
index f23191fac1..1109df827d 100644
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 #
 # Module information generator
 #
@@ -80,19 +80,20 @@ def print_bottom(fheader):
 #endif
 ''')
 
-# First argument: output file
-# All other arguments: modules source files (.c)
-output_file = sys.argv[1]
-with open(output_file, 'w') as fheader:
-    print_top(fheader)
+if __name__ == '__main__':
+    # First argument: output file
+    # All other arguments: modules source files (.c)
+    output_file = sys.argv[1]
+    with open(output_file, 'w') as fheader:
+        print_top(fheader)
 
-    for filename in sys.argv[2:]:
-        if os.path.isfile(filename):
-            process_file(fheader, filename)
-        else:
-            print("File " + filename + " does not exist.", file=sys.stderr)
-            sys.exit(1)
+        for filename in sys.argv[2:]:
+            if os.path.isfile(filename):
+                process_file(fheader, filename)
+            else:
+                print("File " + filename + " does not exist.", file=sys.stderr)
+                sys.exit(1)
 
-    print_bottom(fheader)
+        print_bottom(fheader)
 
-sys.exit(0)
+    sys.exit(0)
Signature · 1 line
2.21.3
#6 lore raw

[PULL 06/25] scripts/qmp: Fix shebang and imports

In reply to Philippe Mathieu-Daudé

From: John Snow <[email protected]>

There's more wrong with these scripts; They are in various stages of disrepair. That's beyond the scope of this current patchset.

This just mechanically corrects the imports and the shebangs, as part of ensuring that the python/qemu/lib refactoring didn't break anything needlessly.

Message-Id: <[email protected]>

---
 scripts/qmp/qmp      | 4 +++-
 scripts/qmp/qom-fuse | 4 +++-
 scripts/qmp/qom-get  | 4 +++-
 scripts/qmp/qom-list | 4 +++-
 scripts/qmp/qom-set  | 4 +++-
 scripts/qmp/qom-tree | 4 +++-
 6 files changed, 18 insertions(+), 6 deletions(-)
scripts/qmp/qmp +3 -1
index 0625fc2aba..8e52e4a54d 100755
@@ -11,7 +11,9 @@
 # See the COPYING file in the top-level directory.
 
 import sys, os
-from qmp import QEMUMonitorProtocol
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu.qmp import QEMUMonitorProtocol
 
 def print_response(rsp, prefix=[]):
     if type(rsp) == list:
scripts/qmp/qom-fuse +3 -1
index 6bada2c33d..5fa6b3bf64 100755
@@ -15,7 +15,9 @@ import fuse, stat
 from fuse import Fuse
 import os, posix
 from errno import *
-from qmp import QEMUMonitorProtocol
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu.qmp import QEMUMonitorProtocol
 
 fuse.fuse_python_api = (0, 2)
 
scripts/qmp/qom-get +3 -1
index 7c5ede91bb..666df71832 100755
@@ -13,7 +13,9 @@
 
 import sys
 import os
-from qmp import QEMUMonitorProtocol
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu.qmp import QEMUMonitorProtocol
 
 cmd, args = sys.argv[0], sys.argv[1:]
 socket_path = None
scripts/qmp/qom-list +3 -1
index bb68fd65d4..5074fd939f 100755
@@ -13,7 +13,9 @@
 
 import sys
 import os
-from qmp import QEMUMonitorProtocol
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu.qmp import QEMUMonitorProtocol
 
 cmd, args = sys.argv[0], sys.argv[1:]
 socket_path = None
scripts/qmp/qom-set +3 -1
index 19881d85e9..240a78187f 100755
@@ -13,7 +13,9 @@
 
 import sys
 import os
-from qmp import QEMUMonitorProtocol
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu.qmp import QEMUMonitorProtocol
 
 cmd, args = sys.argv[0], sys.argv[1:]
 socket_path = None
scripts/qmp/qom-tree +3 -1
index fa91147a03..25b0781323 100755
@@ -15,7 +15,9 @@
 
 import sys
 import os
-from qmp import QEMUMonitorProtocol
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
+from qemu.qmp import QEMUMonitorProtocol
 
 cmd, args = sys.argv[0], sys.argv[1:]
 socket_path = None
Signature · 1 line
2.21.3
#7 lore raw

[PULL 07/25] python: remove more instances of sys.version_info

In reply to Philippe Mathieu-Daudé

From: John Snow <[email protected]>

We guarantee 3.5+ everywhere; remove more dead checks. In general, try to avoid using version checks and instead prefer to attempt behavior when possible.

Message-Id: <[email protected]>

---
 scripts/analyze-migration.py             |  5 -----
 scripts/decodetree.py                    | 25 +++++++++---------------
 scripts/qmp/qmp-shell                    |  3 ---
 tests/docker/docker.py                   |  5 +++--
 tests/qemu-iotests/nbd-fault-injector.py |  5 +----
 5 files changed, 13 insertions(+), 30 deletions(-)
scripts/analyze-migration.py +0 -5
index 96a31d3974..95838cbff3 100755
@@ -25,11 +25,6 @@
 import sys
 
 
-MIN_PYTHON = (3, 2)
-if sys.version_info < MIN_PYTHON:
-    sys.exit("Python %s.%s or later is required.\n" % MIN_PYTHON)
-
-
 def mkdir_p(path):
     try:
         os.makedirs(path)
scripts/decodetree.py +9 -16
index 46ab917807..f9d204aa36 100755
@@ -75,13 +75,6 @@ def output(*args):
         output_fd.write(a)
 
 
-if sys.version_info >= (3, 4):
-    re_fullmatch = re.fullmatch
-else:
-    def re_fullmatch(pat, str):
-        return re.match('^' + pat + '$', str)
-
-
 def output_autogen():
     output('/* This file is autogenerated by scripts/decodetree.py.  */\n\n')
 
@@ -428,18 +421,18 @@ def parse_field(lineno, name, toks):
     width = 0
     func = None
     for t in toks:
-        if re_fullmatch('!function=' + re_ident, t):
+        if re.fullmatch('!function=' + re_ident, t):
             if func:
                 error(lineno, 'duplicate function')
             func = t.split('=')
             func = func[1]
             continue
 
-        if re_fullmatch('[0-9]+:s[0-9]+', t):
+        if re.fullmatch('[0-9]+:s[0-9]+', t):
             # Signed field extract
             subtoks = t.split(':s')
             sign = True
-        elif re_fullmatch('[0-9]+:[0-9]+', t):
+        elif re.fullmatch('[0-9]+:[0-9]+', t):
             # Unsigned field extract
             subtoks = t.split(':')
             sign = False
@@ -488,11 +481,11 @@ def parse_arguments(lineno, name, toks):
     flds = []
     extern = False
     for t in toks:
-        if re_fullmatch('!extern', t):
+        if re.fullmatch('!extern', t):
             extern = True
             anyextern = True
             continue
-        if not re_fullmatch(re_ident, t):
+        if not re.fullmatch(re_ident, t):
             error(lineno, 'invalid argument set token "{0}"'.format(t))
         if t in flds:
             error(lineno, 'duplicate argument "{0}"'.format(t))
@@ -621,13 +614,13 @@ def parse_generic(lineno, is_format, name, toks):
             continue
 
         # 'Foo=%Bar' imports a field with a different name.
-        if re_fullmatch(re_ident + '=%' + re_ident, t):
+        if re.fullmatch(re_ident + '=%' + re_ident, t):
             (fname, iname) = t.split('=%')
             flds = add_field_byname(lineno, flds, fname, iname)
             continue
 
         # 'Foo=number' sets an argument field to a constant value
-        if re_fullmatch(re_ident + '=[+-]?[0-9]+', t):
+        if re.fullmatch(re_ident + '=[+-]?[0-9]+', t):
             (fname, value) = t.split('=')
             value = int(value)
             flds = add_field(lineno, flds, fname, ConstField(value))
@@ -635,7 +628,7 @@ def parse_generic(lineno, is_format, name, toks):
 
         # Pattern of 0s, 1s, dots and dashes indicate required zeros,
         # required ones, or dont-cares.
-        if re_fullmatch('[01.-]+', t):
+        if re.fullmatch('[01.-]+', t):
             shift = len(t)
             fms = t.replace('0', '1')
             fms = fms.replace('.', '0')
@@ -652,7 +645,7 @@ def parse_generic(lineno, is_format, name, toks):
             fixedmask = (fixedmask << shift) | fms
             undefmask = (undefmask << shift) | ubm
         # Otherwise, fieldname:fieldwidth
-        elif re_fullmatch(re_ident + ':s?[0-9]+', t):
+        elif re.fullmatch(re_ident + ':s?[0-9]+', t):
             (fname, flen) = t.split(':')
             sign = False
             if flen[0] == 's':
scripts/qmp/qmp-shell +0 -3
index a01d31de1e..c5eef06f3f 100755
@@ -77,9 +77,6 @@ import re
 sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
 from qemu import qmp
 
-if sys.version_info[0] == 2:
-    input = raw_input
-
 class QMPCompleter(list):
     def complete(self, text, state):
         for cmd in self:
tests/docker/docker.py +3 -2
index d8268c1111..5a9735db78 100755
@@ -258,12 +258,13 @@ def _kill_instances(self, *args, **kwargs):
         return self._do_kill_instances(True)
 
     def _output(self, cmd, **kwargs):
-        if sys.version_info[1] >= 6:
+        try:
             return subprocess.check_output(self._command + cmd,
                                            stderr=subprocess.STDOUT,
                                            encoding='utf-8',
                                            **kwargs)
-        else:
+        except TypeError:
+            # 'encoding' argument was added in 3.6+
             return subprocess.check_output(self._command + cmd,
                                            stderr=subprocess.STDOUT,
                                            **kwargs).decode('utf-8')
tests/qemu-iotests/nbd-fault-injector.py +1 -4
index 588d62aebf..78f42c4214 100755
@@ -47,10 +47,7 @@
 import socket
 import struct
 import collections
-if sys.version_info.major >= 3:
-    import configparser
-else:
-    import ConfigParser as configparser
+import configparser
 
 FAKE_DISK_SIZE = 8 * 1024 * 1024 * 1024 # 8 GB
 
Signature · 1 line
2.21.3
#8 lore raw

[PULL 08/25] python/qemu/machine: add kill() method

In reply to Philippe Mathieu-Daudé

From: Vladimir Sementsov-Ogievskiy <[email protected]>

Add method to hard-kill vm, without any quit commands.

Message-Id: <[email protected]>

---
 python/qemu/machine.py | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)
python/qemu/machine.py +9 -3
index b9a98e2c86..d2f531f1b4 100644
@@ -342,7 +342,7 @@ def wait(self):
         self._load_io_log()
         self._post_shutdown()
 
-    def shutdown(self, has_quit=False):
+    def shutdown(self, has_quit=False, hard=False):
         """
         Terminate the VM and clean up
         """
@@ -354,7 +354,9 @@ def shutdown(self, has_quit=False):
             self._console_socket = None
 
         if self.is_running():
-            if self._qmp:
+            if hard:
+                self._popen.kill()
+            elif self._qmp:
                 try:
                     if not has_quit:
                         self._qmp.cmd('quit')
@@ -368,7 +370,8 @@ def shutdown(self, has_quit=False):
         self._post_shutdown()
 
         exitcode = self.exitcode()
-        if exitcode is not None and exitcode < 0:
+        if exitcode is not None and exitcode < 0 and \
+                not (exitcode == -9 and hard):
             msg = 'qemu received signal %i: %s'
             if self._qemu_full_args:
                 command = ' '.join(self._qemu_full_args)
@@ -378,6 +381,9 @@ def shutdown(self, has_quit=False):
 
         self._launched = False
 
+    def kill(self):
+        self.shutdown(hard=True)
+
     def set_qmp_monitor(self, enabled=True):
         """
         Set the QMP monitor.
Signature · 1 line
2.21.3
#9 lore raw

[PULL 09/25] python/qemu/machine: remove logging configuration

In reply to Philippe Mathieu-Daudé

From: John Snow <[email protected]>

Python 3.5 and above do not print a warning when logging is not configured. As a library, it's best practice to leave logging configuration to the client executable.

Message-Id: <[email protected]>

---
 python/qemu/machine.py | 3 ---
 1 file changed, 3 deletions(-)
python/qemu/machine.py +0 -3
index d2f531f1b4..41554de533 100644
@@ -119,9 +119,6 @@ def __init__(self, binary, args=None, wrapper=None, name=None,
         self._console_socket = None
         self._remove_files = []
 
-        # just in case logging wasn't configured by the main script:
-        logging.basicConfig()
-
     def __enter__(self):
         return self
 
Signature · 1 line
2.21.3
#10 lore raw

[PULL 10/25] python/qemu: delint and add pylintrc

In reply to Philippe Mathieu-Daudé

From: John Snow <[email protected]>

Bring our these files up to speed with pylint 2.5.0. Add a pylintrc file to formalize which pylint subset we are targeting.

The similarity ignore is there to suppress similarity reports across imports, which for typing constants, are going to trigger this report erroneously.

Message-Id: <[email protected]>

---
 python/qemu/machine.py |  6 ++---
 python/qemu/pylintrc   | 58 ++++++++++++++++++++++++++++++++++++++++++
 python/qemu/qtest.py   | 42 +++++++++++++++++++-----------
 3 files changed, 88 insertions(+), 18 deletions(-)
 create mode 100644 python/qemu/pylintrc
python/qemu/machine.py +3 -3
index 41554de533..8e4ecd1837 100644
@@ -58,7 +58,7 @@ def __init__(self, reply):
         self.reply = reply
 
 
-class QEMUMachine(object):
+class QEMUMachine:
     """
     A QEMU VM
 
@@ -239,7 +239,7 @@ def _base_args(self):
                          'chardev=mon,mode=control'])
         if self._machine is not None:
             args.extend(['-machine', self._machine])
-        for i in range(self._console_index):
+        for _ in range(self._console_index):
             args.extend(['-serial', 'null'])
         if self._console_set:
             self._console_address = os.path.join(self._sock_dir,
@@ -374,7 +374,7 @@ def shutdown(self, has_quit=False, hard=False):
                 command = ' '.join(self._qemu_full_args)
             else:
                 command = ''
-            LOG.warning(msg, -exitcode, command)
+            LOG.warning(msg, -int(exitcode), command)
 
         self._launched = False
 
python/qemu/pylintrc new file +58 -0

58 lines not on this page · raw message

python/qemu/qtest.py +27 -15

66 lines not on this page · raw message

Signature · 1 line
2.21.3
#11 lore raw

[PULL 11/25] python/qemu: delint; add flake8 config

In reply to Philippe Mathieu-Daudé

From: John Snow <[email protected]>

Mostly, ignore the "no bare except" rule, because flake8 is not contextual and cannot determine if we re-raise. Pylint can, though, so always prefer pylint for that.

Message-Id: <[email protected]>

---
 python/qemu/.flake8    |  2 ++
 python/qemu/accel.py   |  9 ++++++---
 python/qemu/machine.py | 13 +++++++++----
 python/qemu/qmp.py     |  4 ++--
 4 files changed, 19 insertions(+), 9 deletions(-)
 create mode 100644 python/qemu/.flake8
python/qemu/.flake8 new file +2 -0
new file mode 100644
index 0000000000..45d8146f3f
@@ -0,0 +1,2 @@
+[flake8]
+extend-ignore = E722  # Pylint handles this, but smarter.
\ No newline at end of file
python/qemu/accel.py +6 -3
index 36ae85791e..7fabe62920 100644
@@ -23,11 +23,12 @@
 # Mapping host architecture to any additional architectures it can
 # support which often includes its 32 bit cousin.
 ADDITIONAL_ARCHES = {
-    "x86_64" : "i386",
-    "aarch64" : "armhf",
-    "ppc64le" : "ppc64",
+    "x86_64": "i386",
+    "aarch64": "armhf",
+    "ppc64le": "ppc64",
 }
 
+
 def list_accel(qemu_bin):
     """
     List accelerators enabled in the QEMU binary.
@@ -47,6 +48,7 @@ def list_accel(qemu_bin):
     # Skip the first line which is the header.
     return [acc.strip() for acc in out.splitlines()[1:]]
 
+
 def kvm_available(target_arch=None, qemu_bin=None):
     """
     Check if KVM is available using the following heuristic:
@@ -69,6 +71,7 @@ def kvm_available(target_arch=None, qemu_bin=None):
         return False
     return True
 
+
 def tcg_available(qemu_bin):
     """
     Check if TCG is available.
python/qemu/machine.py +9 -4
index 8e4ecd1837..187790ce9e 100644
@@ -29,6 +29,7 @@
 
 LOG = logging.getLogger(__name__)
 
+
 class QEMUMachineError(Exception):
     """
     Exception called when an error in QEMUMachine happens.
@@ -62,7 +63,8 @@ class QEMUMachine:
     """
     A QEMU VM
 
-    Use this object as a context manager to ensure the QEMU process terminates::
+    Use this object as a context manager to ensure
+    the QEMU process terminates::
 
         with VM(binary) as vm:
             ...
@@ -185,8 +187,10 @@ def send_fd_scm(self, fd=None, file_path=None):
             fd_param.append(str(fd))
 
         devnull = open(os.path.devnull, 'rb')
-        proc = subprocess.Popen(fd_param, stdin=devnull, stdout=subprocess.PIPE,
-                                stderr=subprocess.STDOUT, close_fds=False)
+        proc = subprocess.Popen(
+            fd_param, stdin=devnull, stdout=subprocess.PIPE,
+            stderr=subprocess.STDOUT, close_fds=False
+        )
         output = proc.communicate()[0]
         if output:
             LOG.debug(output)
@@ -485,7 +489,8 @@ def event_wait(self, name, timeout=60.0, match=None):
 
     def events_wait(self, events, timeout=60.0):
         """
-        events_wait waits for and returns a named event from QMP with a timeout.
+        events_wait waits for and returns a named event
+        from QMP with a timeout.
 
         events: a sequence of (name, match_criteria) tuples.
                 The match criteria are optional and may be None.
python/qemu/qmp.py +2 -2
index d6c9b2f4b1..6ae7693965 100644
@@ -168,8 +168,8 @@ def accept(self, timeout=15.0):
 
         @param timeout: timeout in seconds (nonnegative float number, or
                         None). The value passed will set the behavior of the
-                        underneath QMP socket as described in [1]. Default value
-                        is set to 15.0.
+                        underneath QMP socket as described in [1].
+                        Default value is set to 15.0.
         @return QMP greeting dict
         @raise OSError on socket connection errors
         @raise QMPConnectError if the greeting is not received
Signature · 1 line
2.21.3
#12 lore raw

[PULL 12/25] python/qemu: remove Python2 style super() calls

In reply to Philippe Mathieu-Daudé

From: John Snow <[email protected]>

Use the Python3 style instead.

Message-Id: <[email protected]>

---
 python/qemu/machine.py |  2 +-
 python/qemu/qtest.py   | 15 +++++++--------
 2 files changed, 8 insertions(+), 9 deletions(-)
python/qemu/machine.py +1 -1
index 187790ce9e..95a20a17f9 100644
@@ -55,7 +55,7 @@ def __init__(self, reply):
             desc = reply["error"]["desc"]
         except KeyError:
             desc = reply
-        super(MonitorResponseError, self).__init__(desc)
+        super().__init__(desc)
         self.reply = reply
 
 
python/qemu/qtest.py +7 -8
index 53d814c064..7943487c2b 100644
@@ -101,29 +101,28 @@ def __init__(self, binary, args=None, name=None, test_dir="/var/tmp",
             name = "qemu-%d" % os.getpid()
         if sock_dir is None:
             sock_dir = test_dir
-        super(QEMUQtestMachine,
-              self).__init__(binary, args, name=name, test_dir=test_dir,
-                             socket_scm_helper=socket_scm_helper,
-                             sock_dir=sock_dir)
+        super().__init__(binary, args, name=name, test_dir=test_dir,
+                         socket_scm_helper=socket_scm_helper,
+                         sock_dir=sock_dir)
         self._qtest = None
         self._qtest_path = os.path.join(sock_dir, name + "-qtest.sock")
 
     def _base_args(self):
-        args = super(QEMUQtestMachine, self)._base_args()
+        args = super()._base_args()
         args.extend(['-qtest', 'unix:path=' + self._qtest_path,
                      '-accel', 'qtest'])
         return args
 
     def _pre_launch(self):
-        super(QEMUQtestMachine, self)._pre_launch()
+        super()._pre_launch()
         self._qtest = QEMUQtestProtocol(self._qtest_path, server=True)
 
     def _post_launch(self):
-        super(QEMUQtestMachine, self)._post_launch()
+        super()._post_launch()
         self._qtest.accept()
 
     def _post_shutdown(self):
-        super(QEMUQtestMachine, self)._post_shutdown()
+        super()._post_shutdown()
         self._remove_if_exists(self._qtest_path)
 
     def qtest(self, cmd):
Signature · 1 line
2.21.3
#13 lore raw

[PULL 13/25] python/qemu: fix socket.makefile() typing

In reply to Philippe Mathieu-Daudé

From: John Snow <[email protected]>

Note:

A bug in typeshed (https://github.com/python/typeshed/issues/3977)
misinterprets the type of makefile(). Work around this by explicitly stating that we are opening a text-mode file.

Message-Id: <[email protected]>

---
 python/qemu/qmp.py   | 10 +++++++---
 python/qemu/qtest.py | 12 ++++++++----
 2 files changed, 15 insertions(+), 7 deletions(-)
python/qemu/qmp.py +7 -3
index 6ae7693965..73d49050ed 100644
@@ -11,6 +11,10 @@
 import errno
 import socket
 import logging
+from typing import (
+    Optional,
+    TextIO,
+)
 
 
 class QMPError(Exception):
@@ -61,7 +65,7 @@ def __init__(self, address, server=False, nickname=None):
         self.__events = []
         self.__address = address
         self.__sock = self.__get_sock()
-        self.__sockfile = None
+        self.__sockfile: Optional[TextIO] = None
         self._nickname = nickname
         if self._nickname:
             self.logger = logging.getLogger('QMP').getChild(self._nickname)
@@ -157,7 +161,7 @@ def connect(self, negotiate=True):
         @raise QMPCapabilitiesError if fails to negotiate capabilities
         """
         self.__sock.connect(self.__address)
-        self.__sockfile = self.__sock.makefile()
+        self.__sockfile = self.__sock.makefile(mode='r')
         if negotiate:
             return self.__negotiate_capabilities()
         return None
@@ -180,7 +184,7 @@ def accept(self, timeout=15.0):
         """
         self.__sock.settimeout(timeout)
         self.__sock, _ = self.__sock.accept()
-        self.__sockfile = self.__sock.makefile()
+        self.__sockfile = self.__sock.makefile(mode='r')
         return self.__negotiate_capabilities()
 
     def cmd_obj(self, qmp_cmd):
python/qemu/qtest.py +8 -4
index 7943487c2b..4c88590eb0 100644
@@ -19,6 +19,7 @@
 
 import socket
 import os
+from typing import Optional, TextIO
 
 from .machine import QEMUMachine
 
@@ -40,7 +41,7 @@ class QEMUQtestProtocol:
     def __init__(self, address, server=False):
         self._address = address
         self._sock = self._get_sock()
-        self._sockfile = None
+        self._sockfile: Optional[TextIO] = None
         if server:
             self._sock.bind(self._address)
             self._sock.listen(1)
@@ -59,7 +60,7 @@ def connect(self):
         @raise socket.error on socket connection errors
         """
         self._sock.connect(self._address)
-        self._sockfile = self._sock.makefile()
+        self._sockfile = self._sock.makefile(mode='r')
 
     def accept(self):
         """
@@ -68,7 +69,7 @@ def accept(self):
         @raise socket.error on socket connection errors
         """
         self._sock, _ = self._sock.accept()
-        self._sockfile = self._sock.makefile()
+        self._sockfile = self._sock.makefile(mode='r')
 
     def cmd(self, qtest_cmd):
         """
@@ -76,6 +77,7 @@ def cmd(self, qtest_cmd):
 
         @param qtest_cmd: qtest command text to be sent
         """
+        assert self._sockfile is not None
         self._sock.sendall((qtest_cmd + "\n").encode('utf-8'))
         resp = self._sockfile.readline()
         return resp
@@ -83,7 +85,9 @@ def cmd(self, qtest_cmd):
     def close(self):
         """Close this socket."""
         self._sock.close()
-        self._sockfile.close()
+        if self._sockfile:
+            self._sockfile.close()
+            self._sockfile = None
 
     def settimeout(self, timeout):
         """Set a timeout, in seconds."""
Signature · 1 line
2.21.3
#14 lore raw

[PULL 14/25] python/qemu: Adjust traceback typing

In reply to Philippe Mathieu-Daudé

From: John Snow <[email protected]>

mypy considers it incorrect to use bool to statically return false, because it will assume that it could conceivably return True, and gives different analysis in that case. Use a None return to achieve the same effect, but make mypy happy.

Note: Pylint considers function signatures as code that might trip the duplicate-code checker. I'd rather not disable this as it does not trigger often in practice, so I'm disabling it as a one-off and filed a change request; see https://github.com/PyCQA/pylint/issues/3619

Message-Id: <[email protected]>

---
 python/qemu/machine.py |  8 ++++++--
 python/qemu/qmp.py     | 10 ++++++++--
 2 files changed, 14 insertions(+), 4 deletions(-)
python/qemu/machine.py +6 -2
index 95a20a17f9..041c615052 100644
@@ -24,6 +24,8 @@
 import shutil
 import socket
 import tempfile
+from typing import Optional, Type
+from types import TracebackType
 
 from . import qmp
 
@@ -124,9 +126,11 @@ def __init__(self, binary, args=None, wrapper=None, name=None,
     def __enter__(self):
         return self
 
-    def __exit__(self, exc_type, exc_val, exc_tb):
+    def __exit__(self,
+                 exc_type: Optional[Type[BaseException]],
+                 exc_val: Optional[BaseException],
+                 exc_tb: Optional[TracebackType]) -> None:
         self.shutdown()
-        return False
 
     def add_monitor_null(self):
         """
python/qemu/qmp.py +8 -2
index 73d49050ed..b91c9d5c1c 100644
@@ -14,7 +14,9 @@
 from typing import (
     Optional,
     TextIO,
+    Type,
 )
+from types import TracebackType
 
 
 class QMPError(Exception):
@@ -146,10 +148,14 @@ def __enter__(self):
         # Implement context manager enter function.
         return self
 
-    def __exit__(self, exc_type, exc_value, exc_traceback):
+    def __exit__(self,
+                 # pylint: disable=duplicate-code
+                 # see https://github.com/PyCQA/pylint/issues/3619
+                 exc_type: Optional[Type[BaseException]],
+                 exc_val: Optional[BaseException],
+                 exc_tb: Optional[TracebackType]) -> None:
         # Implement context manager exit function.
         self.close()
-        return False
 
     def connect(self, negotiate=True):
         """
Signature · 1 line
2.21.3
#15 lore raw

[PULL 15/25] python/qemu/qmp: use True/False for non/blocking modes

In reply to Philippe Mathieu-Daudé

From: John Snow <[email protected]>

The type system doesn't want integers.

Message-Id: <[email protected]>

---
 python/qemu/qmp.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
python/qemu/qmp.py +2 -2
index b91c9d5c1c..a634c4e26c 100644
@@ -120,14 +120,14 @@ def __get_events(self, wait=False):
         """
 
         # Check for new events regardless and pull them into the cache:
-        self.__sock.setblocking(0)
+        self.__sock.setblocking(False)
         try:
             self.__json_read()
         except OSError as err:
             if err.errno == errno.EAGAIN:
                 # No data available
                 pass
-        self.__sock.setblocking(1)
+        self.__sock.setblocking(True)
 
         # Wait for new events, if needed.
         # if wait is 0.0, this means "no wait" and is also implicitly false.
Signature · 1 line
2.21.3
#16 lore raw

[PULL 16/25] python/qemu/qmp: assert sockfile is not None

In reply to Philippe Mathieu-Daudé

From: John Snow <[email protected]>

In truth, if you don't do this, you'll just get a TypeError exception. Now, you'll get an AssertionError.

Is this tangibly better? No.
Does mypy complain less? Yes.

Message-Id: <[email protected]>

---
 python/qemu/qmp.py | 1 +
 1 file changed, 1 insertion(+)
python/qemu/qmp.py +1 -0
index a634c4e26c..e64b6b5faa 100644
@@ -94,6 +94,7 @@ def __negotiate_capabilities(self):
         raise QMPCapabilitiesError
 
     def __json_read(self, only_event=False):
+        assert self.__sockfile is not None
         while True:
             data = self.__sockfile.readline()
             if not data:
Signature · 1 line
2.21.3
#17 lore raw

[PULL 17/25] python/qemu/qtest: Check before accessing _qtest

In reply to Philippe Mathieu-Daudé

From: John Snow <[email protected]>

It can be None; so add assertions or exceptions where appropriate to guard the access accordingly.

Message-Id: <[email protected]>

---
 python/qemu/qtest.py | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)
python/qemu/qtest.py +11 -3
index 4c88590eb0..888c8bd2f6 100644
@@ -121,7 +121,8 @@ def _pre_launch(self):
         super()._pre_launch()
         self._qtest = QEMUQtestProtocol(self._qtest_path, server=True)
 
-    def _post_launch(self):
+    def _post_launch(self) -> None:
+        assert self._qtest is not None
         super()._post_launch()
         self._qtest.accept()
 
@@ -129,6 +130,13 @@ def _post_shutdown(self):
         super()._post_shutdown()
         self._remove_if_exists(self._qtest_path)
 
-    def qtest(self, cmd):
-        '''Send a qtest command to guest'''
+    def qtest(self, cmd: str) -> str:
+        """
+        Send a qtest command to the guest.
+
+        :param cmd: qtest command to send
+        :return: qtest server response
+        """
+        if self._qtest is None:
+            raise RuntimeError("qtest socket not available")
         return self._qtest.cmd(cmd)
Signature · 1 line
2.21.3
#18 lore raw

[PULL 18/25] tests/vm: Pass --debug through for vm-boot-ssh

In reply to Philippe Mathieu-Daudé

From: Robert Foley <[email protected]>

This helps debug issues that occur during the boot sequence.

Message-Id: <[email protected]>

---
 tests/vm/Makefile.include | 1 +
 1 file changed, 1 insertion(+)
tests/vm/Makefile.include +1 -0
index 74ab522c55..80f7f6bdee 100644
@@ -91,6 +91,7 @@ vm-boot-ssh-%: $(IMAGES_DIR)/%.img
 	$(call quiet-command, \
 		$(PYTHON) $(SRC_PATH)/tests/vm/$* \
 		$(if $(J),--jobs $(J)) \
+		$(if $(V)$(DEBUG), --debug) \
 		--image "$<" \
 		--interactive \
 		false, \
Signature · 1 line
2.21.3
#19 lore raw

[PULL 19/25] tests/vm: Add ability to select QEMU from current build

In reply to Philippe Mathieu-Daudé

From: Robert Foley <[email protected]>

Added a new special variable QEMU_LOCAL=1, which will indicate to take the QEMU binary from the current build.

Message-Id: <[email protected]>

---
 tests/vm/Makefile.include |  4 ++++
 tests/vm/basevm.py        | 28 +++++++++++++++++++++++-----
 2 files changed, 27 insertions(+), 5 deletions(-)
tests/vm/Makefile.include +4 -0
index 80f7f6bdee..a253aba457 100644
@@ -41,6 +41,7 @@ endif
 	@echo "    J=[0..9]*            	 - Override the -jN parameter for make commands"
 	@echo "    DEBUG=1              	 - Enable verbose output on host and interactive debugging"
 	@echo "    V=1				 - Enable verbose ouput on host and guest commands"
+	@echo "    QEMU_LOCAL=1                 - Use QEMU binary local to this build."
 	@echo "    QEMU=/path/to/qemu		 - Change path to QEMU binary"
 	@echo "    QEMU_IMG=/path/to/qemu-img	 - Change path to qemu-img tool"
 
@@ -57,6 +58,7 @@ $(IMAGES_DIR)/%.img:	$(SRC_PATH)/tests/vm/% \
 		$(PYTHON) $< \
 		$(if $(V)$(DEBUG), --debug) \
 		$(if $(GENISOIMAGE),--genisoimage $(GENISOIMAGE)) \
+		$(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
 		--image "$@" \
 		--force \
 		--build-image $@, \
@@ -71,6 +73,7 @@ vm-build-%: $(IMAGES_DIR)/%.img
 		$(if $(DEBUG), --interactive) \
 		$(if $(J),--jobs $(J)) \
 		$(if $(V),--verbose) \
+		$(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
 		--image "$<" \
 		$(if $(BUILD_TARGET),--build-target $(BUILD_TARGET)) \
 		--snapshot \
@@ -92,6 +95,7 @@ vm-boot-ssh-%: $(IMAGES_DIR)/%.img
 		$(PYTHON) $(SRC_PATH)/tests/vm/$* \
 		$(if $(J),--jobs $(J)) \
 		$(if $(V)$(DEBUG), --debug) \
+		$(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
 		--image "$<" \
 		--interactive \
 		false, \
tests/vm/basevm.py +23 -5
index a2d4054d72..5a3ce42281 100644
@@ -61,9 +61,11 @@ class BaseVM(object):
     # 4 is arbitrary, but greater than 2,
     # since we found we need to wait more than twice as long.
     tcg_ssh_timeout_multiplier = 4
-    def __init__(self, debug=False, vcpus=None, genisoimage=None):
+    def __init__(self, debug=False, vcpus=None, genisoimage=None,
+                 build_path=None):
         self._guest = None
         self._genisoimage = genisoimage
+        self._build_path = build_path
         self._tmpdir = os.path.realpath(tempfile.mkdtemp(prefix="vm-test-",
                                                          suffix=".tmp",
                                                          dir="."))
@@ -184,15 +186,15 @@ def boot(self, img, extra_args=[]):
             "-device", "virtio-blk,drive=drive0,bootindex=0"]
         args += self._data_args + extra_args
         logging.debug("QEMU args: %s", " ".join(args))
-        qemu_bin = os.environ.get("QEMU", "qemu-system-" + self.arch)
-        guest = QEMUMachine(binary=qemu_bin, args=args)
+        qemu_path = get_qemu_path(self.arch, self._build_path)
+        guest = QEMUMachine(binary=qemu_path, args=args)
         guest.set_machine('pc')
         guest.set_console()
         try:
             guest.launch()
         except:
             logging.error("Failed to launch QEMU, command line:")
-            logging.error(" ".join([qemu_bin] + args))
+            logging.error(" ".join([qemu_path] + args))
             logging.error("Log:")
             logging.error(guest.get_log())
             logging.error("QEMU version >= 2.10 is required")
@@ -391,6 +393,19 @@ def gen_cloud_init_iso(self):
 
         return os.path.join(cidir, "cloud-init.iso")
 
+def get_qemu_path(arch, build_path=None):
+    """Fetch the path to the qemu binary."""
+    # If QEMU environment variable set, it takes precedence
+    if "QEMU" in os.environ:
+        qemu_path = os.environ["QEMU"]
+    elif build_path:
+        qemu_path = os.path.join(build_path, arch + "-softmmu")
+        qemu_path = os.path.join(qemu_path, "qemu-system-" + arch)
+    else:
+        # Default is to use system path for qemu.
+        qemu_path = "qemu-system-" + arch
+    return qemu_path
+
 def parse_args(vmcls):
 
     def get_default_jobs():
@@ -421,6 +436,9 @@ def get_default_jobs():
                       help="build QEMU from source in guest")
     parser.add_option("--build-target",
                       help="QEMU build target", default="check")
+    parser.add_option("--build-path", default=None,
+                      help="Path of build directory, "\
+                           "for using build tree QEMU binary. ")
     parser.add_option("--interactive", "-I", action="store_true",
                       help="Interactively run command")
     parser.add_option("--snapshot", "-s", action="store_true",
@@ -439,7 +457,7 @@ def main(vmcls):
         logging.basicConfig(level=(logging.DEBUG if args.debug
                                    else logging.WARN))
         vm = vmcls(debug=args.debug, vcpus=args.jobs,
-                   genisoimage=args.genisoimage)
+                   genisoimage=args.genisoimage, build_path=args.build_path)
         if args.build_image:
             if os.path.exists(args.image) and not args.force:
                 sys.stderr.writelines(["Image file exists: %s\n" % args.image,
Signature · 1 line
2.21.3
#20 lore raw

[PULL 20/25] tests/vm: allow wait_ssh() to specify command

In reply to Philippe Mathieu-Daudé

From: Robert Foley <[email protected]>

This allows for waiting for completion of arbitrary commands.

Message-Id: <[email protected]>

---
 tests/vm/basevm.py | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
tests/vm/basevm.py +7 -7
index 5a3ce42281..a80b616a08 100644
@@ -320,24 +320,24 @@ def console_sshd_config(self, prompt):
     def print_step(self, text):
         sys.stderr.write("### %s ...\n" % text)
 
-    def wait_ssh(self, wait_root=False, seconds=300):
+    def wait_ssh(self, wait_root=False, seconds=300, cmd="exit 0"):
         # Allow more time for VM to boot under TCG.
         if not kvm_available(self.arch):
             seconds *= self.tcg_ssh_timeout_multiplier
         starttime = datetime.datetime.now()
         endtime = starttime + datetime.timedelta(seconds=seconds)
-        guest_up = False
+        cmd_success = False
         while datetime.datetime.now() < endtime:
-            if wait_root and self.ssh_root("exit 0") == 0:
-                guest_up = True
+            if wait_root and self.ssh_root(cmd) == 0:
+                cmd_success = True
                 break
-            elif self.ssh("exit 0") == 0:
-                guest_up = True
+            elif self.ssh(cmd) == 0:
+                cmd_success = True
                 break
             seconds = (endtime - datetime.datetime.now()).total_seconds()
             logging.debug("%ds before timeout", seconds)
             time.sleep(1)
-        if not guest_up:
+        if not cmd_success:
             raise Exception("Timeout while waiting for guest ssh")
 
     def shutdown(self):
Signature · 1 line
2.21.3
#21 lore raw

[PULL 21/25] tests/migration/guestperf: Use Python 3 interpreter

In reply to Philippe Mathieu-Daudé

Message-Id: <[email protected]>

---
 tests/migration/guestperf-batch.py | 2 +-
 tests/migration/guestperf-plot.py  | 2 +-
 tests/migration/guestperf.py       | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)
tests/migration/guestperf-batch.py +1 -1
index cb150ce804..f1e900908d 100755
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 #
 # Migration test batch comparison invokation
 #
tests/migration/guestperf-plot.py +1 -1
index d70bb7a557..907151011a 100755
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 #
 # Migration test graph plotting command
 #
tests/migration/guestperf.py +1 -1
index 99b027e8ba..ba1c4bc4ca 100755
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
 #
 # Migration test direct invokation command
 #
Signature · 1 line
2.21.3
#22 lore raw

[PULL 22/25] tests/acceptance/migration.py: Wait for both sides

In reply to Philippe Mathieu-Daudé

From: "Dr. David Alan Gilbert" <[email protected]>

When the source finishes migration the destination will still be receiving the data sent by the source, so it might not have quite finished yet, so won't quite have reached 'completed'. This lead to occasional asserts in the next few checks.

After the source has finished, check the destination as well. (We can't just switch to checking the destination, because it doesn't give a status until it has started receiving the migration).

Message-Id: <[email protected]>

---
 tests/acceptance/migration.py | 4 ++++
 1 file changed, 4 insertions(+)
tests/acceptance/migration.py +4 -0
index 0365289cda..792639cb69 100644
@@ -35,6 +35,10 @@ def assert_migration(self, src_vm, dst_vm):
                       timeout=self.timeout,
                       step=0.1,
                       args=(src_vm,))
+        wait.wait_for(self.migration_finished,
+                      timeout=self.timeout,
+                      step=0.1,
+                      args=(dst_vm,))
         self.assertEqual(src_vm.command('query-migrate')['status'], 'completed')
         self.assertEqual(dst_vm.command('query-migrate')['status'], 'completed')
         self.assertEqual(dst_vm.command('query-status')['status'], 'running')
Signature · 1 line
2.21.3
#23 lore raw

[PULL 23/25] tests/acceptance: allow console interaction with specific VMs

In reply to Philippe Mathieu-Daudé

From: Pavel Dovgalyuk <[email protected]>

Console interaction in avocado scripts was possible only with single default VM.
This patch modifies the function parameters to allow passing a specific VM as a parameter to interact with it.

Message-Id: <159073587933.20809.5122618715976660635.stgit@pasha-ThinkPad-X280>

---
 tests/acceptance/avocado_qemu/__init__.py | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)
tests/acceptance/avocado_qemu/__init__.py +8 -5
index 59e7b4f763..77d1c1d9ff 100644
@@ -69,13 +69,15 @@ def pick_default_qemu_bin(arch=None):
 
 
 def _console_interaction(test, success_message, failure_message,
-                         send_string, keep_sending=False):
+                         send_string, keep_sending=False, vm=None):
     assert not keep_sending or send_string
-    console = test.vm.console_socket.makefile()
+    if vm is None:
+        vm = test.vm
+    console = vm.console_socket.makefile()
     console_logger = logging.getLogger('console')
     while True:
         if send_string:
-            test.vm.console_socket.sendall(send_string.encode())
+            vm.console_socket.sendall(send_string.encode())
             if not keep_sending:
                 send_string = None # send only once
         msg = console.readline().strip()
@@ -115,7 +117,8 @@ def interrupt_interactive_console_until_pattern(test, success_message,
     _console_interaction(test, success_message, failure_message,
                          interrupt_string, True)
 
-def wait_for_console_pattern(test, success_message, failure_message=None):
+def wait_for_console_pattern(test, success_message, failure_message=None,
+                             vm=None):
     """
     Waits for messages to appear on the console, while logging the content
 
@@ -125,7 +128,7 @@ def wait_for_console_pattern(test, success_message, failure_message=None):
     :param success_message: if this message appears, test succeeds
     :param failure_message: if this message appears, test fails
     """
-    _console_interaction(test, success_message, failure_message, None)
+    _console_interaction(test, success_message, failure_message, None, vm=vm)
 
 def exec_command_and_wait_for_pattern(test, command,
                                       success_message, failure_message=None):
Signature · 1 line
2.21.3
#24 lore raw

[PULL 24/25] tests/acceptance: refactor boot_linux_console test to allow code reuse

In reply to Philippe Mathieu-Daudé

From: Pavel Dovgalyuk <[email protected]>

This patch splits code in BootLinuxConsole class into two different classes to allow reusing it by record/replay tests.

Message-Id: <159073588490.20809.13942096070255577558.stgit@pasha-ThinkPad-X280>

---
 tests/acceptance/boot_linux_console.py | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)
tests/acceptance/boot_linux_console.py +11 -10
index c6b06a1a13..12725d4529 100644
@@ -28,19 +28,13 @@
 except CmdNotFoundError:
     P7ZIP_AVAILABLE = False
 
-class BootLinuxConsole(Test):
-    """
-    Boots a Linux kernel and checks that the console is operational and the
-    kernel command line is properly passed from QEMU to the kernel
-    """
-
-    timeout = 90
-
+class LinuxKernelTest(Test):
     KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
 
-    def wait_for_console_pattern(self, success_message):
+    def wait_for_console_pattern(self, success_message, vm=None):
         wait_for_console_pattern(self, success_message,
-                                 failure_message='Kernel panic - not syncing')
+                                 failure_message='Kernel panic - not syncing',
+                                 vm=vm)
 
     def extract_from_deb(self, deb, path):
         """
@@ -79,6 +73,13 @@ def extract_from_rpm(self, rpm, path):
         os.chdir(cwd)
         return os.path.normpath(os.path.join(self.workdir, path))
 
+class BootLinuxConsole(LinuxKernelTest):
+    """
+    Boots a Linux kernel and checks that the console is operational and the
+    kernel command line is properly passed from QEMU to the kernel
+    """
+    timeout = 90
+
     def test_x86_64_pc(self):
         """
         :avocado: tags=arch:x86_64
Signature · 1 line
2.21.3
#25 lore raw

[PULL 25/25] tests/acceptance: refactor boot_linux to allow code reuse

In reply to Philippe Mathieu-Daudé

From: Pavel Dovgalyuk <[email protected]>

This patch moves image downloading functions to the separate class to allow reusing them from record/replay tests.

Message-Id: <159073593167.20809.17582679291556188984.stgit@pasha-ThinkPad-X280>

---
 tests/acceptance/boot_linux.py | 49 ++++++++++++++++++++--------------
 1 file changed, 29 insertions(+), 20 deletions(-)
tests/acceptance/boot_linux.py +29 -20
index 075a386300..3aa57e88b0 100644
@@ -26,22 +26,8 @@
 TCG_NOT_AVAILABLE = ACCEL_NOT_AVAILABLE_FMT % "TCG"
 
 
-class BootLinux(Test):
-    """
-    Boots a Linux system, checking for a successful initialization
-    """
-
-    timeout = 900
-    chksum = None
-
-    def setUp(self):
-        super(BootLinux, self).setUp()
-        self.vm.add_args('-smp', '2')
-        self.vm.add_args('-m', '1024')
-        self.prepare_boot()
-        self.prepare_cloudinit()
-
-    def prepare_boot(self):
+class BootLinuxBase(Test):
+    def download_boot(self):
         self.log.debug('Looking for and selecting a qemu-img binary to be '
                        'used to create the bootable snapshot image')
         # If qemu-img has been built, use it, otherwise the system wide one
@@ -60,17 +46,17 @@ def prepare_boot(self):
         if image_arch == 'ppc64':
             image_arch = 'ppc64le'
         try:
-            self.boot = vmimage.get(
+            boot = vmimage.get(
                 'fedora', arch=image_arch, version='31',
                 checksum=self.chksum,
                 algorithm='sha256',
                 cache_dir=self.cache_dirs[0],
                 snapshot_dir=self.workdir)
-            self.vm.add_args('-drive', 'file=%s' % self.boot.path)
         except:
             self.cancel('Failed to download/prepare boot image')
+        return boot.path
 
-    def prepare_cloudinit(self):
+    def download_cloudinit(self):
         self.log.info('Preparing cloudinit image')
         try:
             cloudinit_iso = os.path.join(self.workdir, 'cloudinit.iso')
@@ -81,9 +67,32 @@ def prepare_cloudinit(self):
                           # QEMU's hard coded usermode router address
                           phone_home_host='10.0.2.2',
                           phone_home_port=self.phone_home_port)
-            self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso)
         except Exception:
             self.cancel('Failed to prepared cloudinit image')
+        return cloudinit_iso
+
+class BootLinux(BootLinuxBase):
+    """
+    Boots a Linux system, checking for a successful initialization
+    """
+
+    timeout = 900
+    chksum = None
+
+    def setUp(self):
+        super(BootLinux, self).setUp()
+        self.vm.add_args('-smp', '2')
+        self.vm.add_args('-m', '1024')
+        self.prepare_boot()
+        self.prepare_cloudinit()
+
+    def prepare_boot(self):
+        path = self.download_boot()
+        self.vm.add_args('-drive', 'file=%s' % path)
+
+    def prepare_cloudinit(self):
+        cloudinit_iso = self.download_cloudinit()
+        self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso)
 
     def launch_and_wait(self):
         self.vm.set_console()
Signature · 1 line
2.21.3
#26 lore raw
In reply to Philippe Mathieu-Daudé
Quoted 18 lines · Philippe Mathieu-Daudé

The following changes since commit c86274bc2e34295764fb44c2aef3cf29623f9b4b:

Merge remote-tracking branch 'remotes/stsquad/tags/pull-testing-tcg-plugins=
-270520-1' into staging (2020-05-29 17:41:45 +0100)

are available in the Git repository at:

https://gitlab.com/philmd/qemu.git tags/python-next-20200531

for you to fetch changes up to 1c80c87c8c2489e4318c93c844aa29bc1d014146:

tests/acceptance: refactor boot_linux to allow code reuse (2020-05-31 18:25=
:31 +0200)

----------------------------------------------------------------
Python queue:

Quoted 9 lines

* migration acceptance test fix
* introduce pylintrc & flake8 config
* various cleanups (Python3, style)
* vm-test can set QEMU_LOCAL=3D1 to use locally built binaries
* refactored BootLinuxBase & LinuxKernelTest acceptance classes

https://gitlab.com/philmd/qemu/pipelines/151323210
https://travis-ci.org/github/philmd/qemu/builds/693157969

Applied, thanks.

Please update the changelog at https://wiki.qemu.org/ChangeLog/5.1
for any user-visible changes.

-- PMM