From 554c0309797eca83b8b3fa4c98767b7ae8468555 Mon Sep 17 00:00:00 2001 From: Cedric Hombourger Date: Thu, 9 Apr 2026 14:49:41 +0200 Subject: [PATCH] feat(power/qemu): generate/use a virtual machine UUID SMBIOS can expose a unique machine identifier for the Operating System to identify the machine it is running on. Make the qemu power controller generate/use a machine ID and pass it over to qemu via the -uuid option. Signed-off-by: Cedric Hombourger --- .github/wordlist.txt | 1 + configs/qemu.ini | 1 + docs/config.rst | 5 +++++ mtda/power/qemu.py | 30 ++++++++++++++++++++++++++++++ 4 files changed, 37 insertions(+) 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: