#407 use the output of -device ? to look for supported devices
Opened 3 years ago by rmeggins. Modified 3 years ago
rmeggins/standard-test-roles use-device-q-to-find-devices  into  master

file modified
+7
@@ -223,5 +223,12 @@ 

  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/

@@ -7,6 +7,7 @@ 

  #          Bruno Goncalves <bgoncalv@redhat.com>

  

  import os

+ import re

  import fmf

  import sys

  import json
@@ -236,7 +237,7 @@ 

          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)
@@ -339,6 +340,19 @@ 

      return value

  

  

+ qemu_device_output = ""

+ def qemu_supports_device(qemu_path, device):

+     global qemu_device_output

+     if not qemu_device_output:

+         rc = subprocess.check_output(

+             [qemu_path, "-device", "?"],

+             stderr=subprocess.STDOUT,

+             universal_newlines=True,

+         )

+         qemu_device_output = rc

+     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 +426,14 @@ 

          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 +441,8 @@ 

      # - 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:
@@ -529,7 +523,7 @@ 

              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))
@@ -742,6 +736,7 @@ 

      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.
@@ -763,6 +758,11 @@ 

      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)

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",.

This replaces https://pagure.io/standard-test-roles/pull-request/406

I have tested this feature on a wide variety of platforms, and it works fine. @nhosoi @spetros

This PR is ready to be merged, imo.

Are there any objections to using this method?

any further objections? Can this be merged?

3 new commits added

  • support py2 - use subprocess.check_output
  • add support for TEST_ISOMAKER and isomaker lookup
  • support py2 - do not use f string
3 years ago