diff --git a/.github/wordlist.txt b/.github/wordlist.txt index 9e2e098a..8e10b617 100644 --- a/.github/wordlist.txt +++ b/.github/wordlist.txt @@ -133,6 +133,7 @@ unmuted uncomment Uptime usb +UUID vdc VDC VLC diff --git a/configs/qemu.ini b/configs/qemu.ini index 530ebf8a..f69e15fc 100644 --- a/configs/qemu.ini +++ b/configs/qemu.ini @@ -51,6 +51,7 @@ storage.0.size=16 #storage.1=/var/lib/mtda/extra-ssd.img #storage.1.size=16 watchdog=i6300esb +#uuid=11111111-2222-3333-4444-555555555555 # --------------------------------------------------------------------------- # Shared Storage settings diff --git a/docs/config.rst b/docs/config.rst index cfae26e0..26426d77 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -369,6 +369,11 @@ The following settings are supported: * ``swtpm``: string [optional] Path to the ``swtpm`` binary to support emulation of a TPM device. +* ``uuid``: string [optional] + UUID to assign to the QEMU/KVM virtual machine (passed via ``-uuid``). + When not set, a UUID is automatically generated and persisted in + ``/var/lib/mtda/qemu-uuid`` so the same value is reused across restarts. + * ``watchdog``: string [optional] Name of the watchdog driver provided by QEMU/KVM for the selected machine. diff --git a/mtda/power/qemu.py b/mtda/power/qemu.py index b190e444..05e0334e 100644 --- a/mtda/power/qemu.py +++ b/mtda/power/qemu.py @@ -20,6 +20,7 @@ import threading import time import multiprocessing +import uuid # Local imports from mtda.power.controller import PowerController @@ -47,6 +48,7 @@ def __init__(self, mtda): self.pidOfSwTpm = None self.pidOfWebsockify = None self.swtpm = "/usr/bin/swtpm" + self.uuid = None self.watchdog = None self.websockify = "/usr/bin/websockify" @@ -79,6 +81,11 @@ def configure(self, conf): self.swtpm = os.path.realpath(conf['swtpm']) elif os.path.exists(self.swtpm) is False: self.swtpm = None + if 'uuid' in conf: + try: + self.uuid = str(uuid.UUID(conf['uuid'])) + except ValueError: + raise ValueError(f"invalid UUID: {conf['uuid']}") if 'watchdog' in conf: self.watchdog = conf['watchdog'] n = 0 @@ -221,6 +228,29 @@ def start(self): if self.watchdog is not None: options += f" -device {self.watchdog},id=watchdog0" + # UUID option + vm_uuid = self.uuid + if vm_uuid is None: + uuid_file = "/var/lib/mtda/qemu-uuid" + if os.path.exists(uuid_file): + with open(uuid_file, "r") as f: + data = f.read().strip() + try: + vm_uuid = str(uuid.UUID(data)) + except ValueError: + self.mtda.debug(1, "power.qemu.start(): " + f"invalid UUID in {uuid_file}, " + "generating a new one") + vm_uuid = None + if not vm_uuid: + vm_uuid = str(uuid.uuid4()) + os.makedirs("/var/lib/mtda", exist_ok=True) + with open(uuid_file, "w") as f: + f.write(vm_uuid + "\n") + self.mtda.debug(2, "power.qemu.start(): " + f"generated UUID {vm_uuid}") + options += f" -uuid {vm_uuid}" + # swtpm options if self.swtpm is not None: with tempfile.NamedTemporaryFile() as pidfile: