Skip to content

Commit

Permalink
dmi: Add support for OpenBSD
Browse files Browse the repository at this point in the history
OpenBSD has the most important DMI data in sysctl's hw hierarchy.
Extend dmi to read those, instead of falling back to dmidecode, since
that requires setting kern.allowkmem=1
  • Loading branch information
igalic committed Dec 4, 2023
1 parent 2927d2a commit ef22ff1
Showing 1 changed file with 36 additions and 10 deletions.
46 changes: 36 additions & 10 deletions cloudinit/dmi.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@
from typing import Optional

from cloudinit import subp
from cloudinit.util import is_container, is_FreeBSD
from cloudinit.util import is_container, is_FreeBSD, is_DragonFlyBSD, is_OpenBSD

LOG = logging.getLogger(__name__)

# Path for DMI Data
DMI_SYS_PATH = "/sys/class/dmi/id"

KernelNames = namedtuple("KernelNames", ["linux", "freebsd"])
KernelNames.__new__.__defaults__ = (None, None)
KernelNames = namedtuple("KernelNames", ["linux", "freebsd", "openbsd"])
KernelNames.__new__.__defaults__ = (None, None, None)

# FreeBSD's kenv(1) and Linux /sys/class/dmi/id/* both use different names from
# dmidecode. The values are the same, and ultimately what we're interested in.
# Likewise, OpenBSD has pretty much all the things we need (use) in sysctl(8)'s
# hw hierarchy.
# These tools offer a "cheaper" way to access those values over dmidecode.
# This is our canonical translation table. If we add more tools on other
# platforms to find dmidecode's values, their keys need to be put in here.
Expand All @@ -40,22 +42,22 @@
"chassis_asset_tag", "smbios.chassis.tag"
),
"chassis-manufacturer": KernelNames(
"chassis_vendor", "smbios.chassis.maker"
"chassis_vendor", "smbios.chassis.maker", "hw.vendor"
),
"chassis-serial-number": KernelNames(
"chassis_serial", "smbios.chassis.serial"
"chassis_serial", "smbios.chassis.serial", "hw.uuid"
),
"chassis-version": KernelNames(
"chassis_version", "smbios.chassis.version"
),
"system-manufacturer": KernelNames("sys_vendor", "smbios.system.maker"),
"system-manufacturer": KernelNames("sys_vendor", "smbios.system.maker", "hw.vendor"),
"system-product-name": KernelNames(
"product_name", "smbios.system.product"
"product_name", "smbios.system.product", "hw.product"
),
"system-serial-number": KernelNames(
"product_serial", "smbios.system.serial"
"product_serial", "smbios.system.serial", "hw.uuid"
),
"system-uuid": KernelNames("product_uuid", "smbios.system.uuid"),
"system-uuid": KernelNames("product_uuid", "smbios.system.uuid", "hw.uuid"),
"system-version": KernelNames("product_version", "smbios.system.version"),
}

Expand Down Expand Up @@ -119,6 +121,27 @@ def _read_kenv(key: str) -> Optional[str]:

return None

def _read_sysctl(key: str) -> Optional[str]:
"""
Reads dmi data from OpenBSD's sysctl(8)
"""
kmap = DMIDECODE_TO_KERNEL.get(key)
if kmap is None or kmap.openbsd is None:
return None

LOG.debug("querying dmi data %s", kmap.openbsd)

try:
cmd = ["sysctl", "-qn", kmap.openbsd]
(result, _err) = subp.subp(cmd)
result = result.strip()
LOG.debug("sysctl returned '%s' for '%s'", result, kmap.openbsd)
return result
except subp.ProcessExecutionError as e:
LOG.debug("failed sysctl cmd: %s\n%s", cmd, e)

return None


def _call_dmidecode(key: str, dmidecode_path: str) -> Optional[str]:
"""
Expand Down Expand Up @@ -159,9 +182,12 @@ def read_dmi_data(key: str) -> Optional[str]:
if is_container():
return None

if is_FreeBSD():
if is_FreeBSD() or is_DragonFlyBSD():
return _read_kenv(key)

if is_OpenBSD():
return _read_sysctl(key)

syspath_value = _read_dmi_syspath(key)
if syspath_value is not None:
return syspath_value
Expand Down

0 comments on commit ef22ff1

Please sign in to comment.