From 0431d3f0f2f5e11e12d8f932ccdb50c1861cc1c0 Mon Sep 17 00:00:00 2001 From: Rich Megginson Date: Nov 15 2021 19:56:42 +0000 Subject: [PATCH 1/4] use the output of -device ? to look for supported devices The method of using `-device $NAME -S -monitor stdio` does not work on all supported platforms (EL7), and does not work correctly on Fedora 34 and later. Instead, grab and parse the output of `qemucmd -device ? 2>&1` and look for matching `name "$NAME",`. --- diff --git a/inventory/standard-inventory-qcow2 b/inventory/standard-inventory-qcow2 index ad3a2f7..261eb2b 100755 --- a/inventory/standard-inventory-qcow2 +++ b/inventory/standard-inventory-qcow2 @@ -7,6 +7,7 @@ # Bruno Goncalves import os +import re import fmf import sys import json @@ -339,6 +340,22 @@ def fmf_get(path, default=None): return value +qemu_device_output = "" +def qemu_supports_device(qemu_path, device): + global qemu_device_output + if not qemu_device_output: + rc = subprocess.run( + [qemu_path, "-device", "?"], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + check=True, + encoding="utf-8", + universal_newlines=True, + ) + qemu_device_output = rc.stdout + return re.search(r'^name "%s",' % device, qemu_device_output, re.M) is not None + + def start_qemu(image, cloudinit, skip_missing_device, portrange=(2222, 5555)): for _ in range(10): port = random.randint(*portrange) @@ -412,24 +429,14 @@ def start_qemu(image, cloudinit, skip_missing_device, portrange=(2222, 5555)): qemu_path = which(qemu_cmd) if qemu_path: break + # Try to probe virtio-rng device: # virtio-rng-pci: https://wiki.qemu.org/Features/VirtIORNG virtio_rng = [] - cmd_tmpl = "echo quit | %s -device %%s -S -monitor stdio" % ( - " ".join([qemu_path] + qemu_common_params) - ) for x in ["virtio-rng", "virtio-rng-pci", "virtio-rng-ccw"]: - try: - subprocess.check_call( - cmd_tmpl % x, - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - shell=True - ) + if qemu_supports_device(qemu_path, x): virtio_rng = ["-device", x] break - except subprocess.CalledProcessError: - pass if virtio_rng: logger.info("qemu-kvm is using %s device" % virtio_rng[1]) # check for supported devices @@ -437,18 +444,8 @@ def start_qemu(image, cloudinit, skip_missing_device, portrange=(2222, 5555)): # - value is the name used by qemu supported_devices = {"nvme": "nvme", "scsi": "virtio-scsi-pci"} - cmd_tmpl = "echo quit | %s -device %%s -S -monitor stdio" % ( - " ".join([qemu_path] + qemu_common_params) - ) for name, qemu_name in list(supported_devices.items()): - try: - subprocess.check_call( - cmd_tmpl % qemu_name, - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - shell=True - ) - except subprocess.CalledProcessError: + if not qemu_supports_device(qemu_path, qemu_name): del supported_devices[name] # Assemble QEMU command with its parameters: From 9d2941ef2fcbd2efdc1ec3222e887761216cafc6 Mon Sep 17 00:00:00 2001 From: Rich Megginson Date: Jan 11 2022 20:49:00 +0000 Subject: [PATCH 2/4] support py2 - do not use f string --- diff --git a/inventory/standard-inventory-qcow2 b/inventory/standard-inventory-qcow2 index 261eb2b..52d65e0 100755 --- a/inventory/standard-inventory-qcow2 +++ b/inventory/standard-inventory-qcow2 @@ -237,7 +237,7 @@ def inv_list(opts): else: hostalias = None hostalias = image_to_alias(subject, hostalias, opts.use_basename) - logger.info(f"image {subject} alias {hostalias}") + logger.info("image %s alias %s", subject, hostalias) host_vars = inv_host(opts, subject, hostalias) if host_vars: hosts.append(hostalias) From 2455260bd9ef4ffe80a88372ac181c56a76f6b73 Mon Sep 17 00:00:00 2001 From: Rich Megginson Date: Jan 11 2022 21:23:50 +0000 Subject: [PATCH 3/4] add support for TEST_ISOMAKER and isomaker lookup --- diff --git a/README.md b/README.md index 1134b09..244d54f 100644 --- a/README.md +++ b/README.md @@ -223,5 +223,12 @@ platforms does not support NVMe. By default, the script will issue an error if you attempt to use an unsupported device. Use this flag to skip missing devices, with a warning. +## TEST_ISOMAKER + +Some systems use `/usr/bin/genisoimage`, some use other ones. By default, the +script will look for `/usr/bin/genisoimage` and a few others. This will +usually do the right thing. If you want to force the script to use a specific +one, use `TEST_ISOMAKER=/usr/bin/xorriso` for example. + [1]: https://fedoraproject.org/wiki/CI/Metadata [2]: http://fmf.readthedocs.io/ diff --git a/inventory/standard-inventory-qcow2 b/inventory/standard-inventory-qcow2 index 52d65e0..7c3da4e 100755 --- a/inventory/standard-inventory-qcow2 +++ b/inventory/standard-inventory-qcow2 @@ -526,7 +526,7 @@ def inv_host(opts, image, hostalias): f.write(BOOTCMD_SSHD_USEDNS_NO) # Create our cloud init so we can log in cloudinit = os.path.join(directory, "cloud-init.iso") - subprocess.check_call(["/usr/bin/genisoimage", "-input-charset", "utf-8", + subprocess.check_call([opts.isomaker, "-input-charset", "utf-8", "-volid", "cidata", "-joliet", "-rock", "-quiet", "-output", cloudinit, userdata, metadata], stdout=null) logger.info("Launching virtual machine for {0}".format(image)) @@ -739,6 +739,7 @@ def main(): parser.add_argument("--hostalias", default=shlex.split(os.environ.get("TEST_HOSTALIASES", "")), action="append", help=help_hostalias()) parser.add_argument("--sshd-usedns-no", default=bool(distutils.util.strtobool(os.environ.get("TEST_SSHD_USEDNS_NO", "False"))), action="store_true", help=help_sshd_usedns_no()) parser.add_argument("--skip-missing-device", default=bool(distutils.util.strtobool(os.environ.get("TEST_SKIP_MISSING_DEVICE", "False"))), action="store_true", help=help_skip_missing_device()) + parser.add_argument("--isomaker", default=os.environ.get("TEST_ISOMAKER"), help="Command to use to create ISO images - will look for /usr/bin/genisoimage and others by default") parser.add_argument("subjects", nargs="*", default=shlex.split(os.environ.get("TEST_SUBJECTS", ""))) opts = parser.parse_args() # Send logs to common logfile for all default provisioners. @@ -760,6 +761,11 @@ def main(): ansible_bin = functools.reduce(which, ansibles) if not ansible_bin: raise Exception("Fail to find ansible.") + isomakers = ["/usr/bin/genisoimage", "/usr/bin/mkisofs", "/usr/bin/xorriso"] + if not opts.isomaker: + opts.isomaker = functools.reduce(which, isomakers) + if not opts.isomaker: + raise Exception("Failed to find one of {0} for creating ISO images".format(str(isomakers))) logger.info("Path to ansible: %s", ansible_bin) if opts.host: data = inv_host(opts, opts.host, opts.hostalias) From 63e2370e41c791053c810d1702ca4c321e2b0f4e Mon Sep 17 00:00:00 2001 From: Rich Megginson Date: Jan 11 2022 22:01:06 +0000 Subject: [PATCH 4/4] support py2 - use subprocess.check_output --- diff --git a/inventory/standard-inventory-qcow2 b/inventory/standard-inventory-qcow2 index 7c3da4e..09d5c97 100755 --- a/inventory/standard-inventory-qcow2 +++ b/inventory/standard-inventory-qcow2 @@ -344,15 +344,12 @@ qemu_device_output = "" def qemu_supports_device(qemu_path, device): global qemu_device_output if not qemu_device_output: - rc = subprocess.run( + rc = subprocess.check_output( [qemu_path, "-device", "?"], - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - check=True, - encoding="utf-8", universal_newlines=True, ) - qemu_device_output = rc.stdout + qemu_device_output = rc return re.search(r'^name "%s",' % device, qemu_device_output, re.M) is not None