| |
@@ -101,7 +101,7 @@
|
| |
_tempfiles = list()
|
| |
|
| |
@classmethod
|
| |
- def generate(cls):
|
| |
+ def generate(cls, supported_devices, skip_missing_device):
|
| |
"""Generate sparse files and return drive qemu options
|
| |
Returns
|
| |
-------
|
| |
@@ -127,16 +127,26 @@
|
| |
if interface is None or interface.lower() == 'virtio':
|
| |
result += ["-drive", "file=%s,media=disk,if=virtio" % drive_file.name]
|
| |
elif interface.lower() == 'nvme':
|
| |
- result += ["-device", "nvme,drive=nvme%s,serial=def%s" % (dev_id, dev_id)]
|
| |
- result += ["-drive", "file=%s,media=disk,if=none,id=nvme%s" % (drive_file.name, dev_id)]
|
| |
- dev_id += 1
|
| |
+ if 'nvme' in supported_devices:
|
| |
+ result += ["-device", "nvme,drive=nvme%s,serial=def%s" % (dev_id, dev_id)]
|
| |
+ result += ["-drive", "file=%s,media=disk,if=none,id=nvme%s" % (drive_file.name, dev_id)]
|
| |
+ dev_id += 1
|
| |
+ elif not skip_missing_device:
|
| |
+ raise Exception("Cannot use device of size '%d' - no NVMe support on this platform" % size)
|
| |
+ else:
|
| |
+ logger.warn("NVMe drive of size '%d' will be skipped - no NVMe support on this platform", size)
|
| |
elif interface.lower() == 'scsi':
|
| |
- if not scsi_device_exists:
|
| |
- result += ["-device", "virtio-scsi-pci,id=scsi0"]
|
| |
- scsi_device_exists = True
|
| |
- result += ["-device", "scsi-hd,drive=drive%s,bus=scsi0.0" % dev_id]
|
| |
- result += ["-drive", "if=none,file=%s,id=drive%s" % (drive_file.name, dev_id)]
|
| |
- dev_id += 1
|
| |
+ if 'scsi' in supported_devices:
|
| |
+ if not scsi_device_exists:
|
| |
+ result += ["-device", "virtio-scsi-pci,id=scsi0"]
|
| |
+ scsi_device_exists = True
|
| |
+ result += ["-device", "scsi-hd,drive=drive%s,bus=scsi0.0" % dev_id]
|
| |
+ result += ["-drive", "if=none,file=%s,id=drive%s" % (drive_file.name, dev_id)]
|
| |
+ dev_id += 1
|
| |
+ elif not skip_missing_device:
|
| |
+ raise Exception("Cannot use device of size '%d' - no SCSI support on this platform" % size)
|
| |
+ else:
|
| |
+ logger.warn("SCSI drive of size '%d' will be skipped - no SCSI support on this platform", size)
|
| |
|
| |
usb_drives = fmf_get(['qemu', 'usb_drive'], list())
|
| |
if usb_drives:
|
| |
@@ -329,7 +339,7 @@
|
| |
return value
|
| |
|
| |
|
| |
- def start_qemu(image, cloudinit, portrange=(2222, 5555)):
|
| |
+ def start_qemu(image, cloudinit, skip_missing_device, portrange=(2222, 5555)):
|
| |
for _ in range(10):
|
| |
port = random.randint(*portrange)
|
| |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
| |
@@ -422,6 +432,25 @@
|
| |
pass
|
| |
if virtio_rng:
|
| |
logger.info("qemu-kvm is using %s device" % virtio_rng[1])
|
| |
+ # check for supported devices
|
| |
+ # - key is the name used in provision.fmf
|
| |
+ # - 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:
|
| |
+ del supported_devices[name]
|
| |
+
|
| |
# Assemble QEMU command with its parameters:
|
| |
qemu_cmd = [
|
| |
qemu_path
|
| |
@@ -451,7 +480,7 @@
|
| |
# Log all traffic received from the guest to log_quest
|
| |
"-chardev", "file,id=pts2,path=" + log_guest
|
| |
]
|
| |
- qemu_cmd += AdditionalDrives.generate()
|
| |
+ qemu_cmd += AdditionalDrives.generate(supported_devices, skip_missing_device)
|
| |
if diagnose:
|
| |
qemu_cmd += ["-vnc", DEF_HOST + ":1,to=4095"]
|
| |
# Launch QEMU:
|
| |
@@ -510,7 +539,7 @@
|
| |
log = None
|
| |
for _ in range(0, 5):
|
| |
try:
|
| |
- proc, port, log = start_qemu(image, cloudinit)
|
| |
+ proc, port, log = start_qemu(image, cloudinit, opts.skip_missing_device)
|
| |
break
|
| |
except subprocess.CalledProcessError as cpe:
|
| |
time.sleep(1)
|
| |
@@ -674,6 +703,14 @@
|
| |
--sshd-usedns-no to configure the VM to use 'UseDNS no' instead."""
|
| |
|
| |
|
| |
+ def help_skip_missing_device():
|
| |
+ return """If you are using the same provision.fmf on multiple systems, the
|
| |
+ qemu on some systems may not support all of the specified devices. For
|
| |
+ example, qemu on many 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."""
|
| |
+
|
| |
+
|
| |
def main():
|
| |
global logger
|
| |
global diagnose
|
| |
@@ -704,6 +741,7 @@
|
| |
parser.add_argument("--use-basename", default=bool(distutils.util.strtobool(os.environ.get("TEST_USE_BASENAME", "False"))), action="store_true", help=help_hostalias())
|
| |
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("subjects", nargs="*", default=shlex.split(os.environ.get("TEST_SUBJECTS", "")))
|
| |
opts = parser.parse_args()
|
| |
# Send logs to common logfile for all default provisioners.
|
| |
Is this boolean, which takes
yes|no
?