summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Galić <me+github@igalic.co>2019-12-12 01:32:14 +0100
committerRyan Harper <ryan.harper@canonical.com>2019-12-11 18:32:14 -0600
commit11ef73e9500dcb325be85f8099a42d8d2e4caf95 (patch)
treee07ce0672b24d0b9aab37b668c2596841ce4b713
parent37ffa8d2bf1d56769a40fea26228b82e33ab1fff (diff)
downloadcloud-init-git-11ef73e9500dcb325be85f8099a42d8d2e4caf95.tar.gz
ds_identify: if /sys is not available use dmidecode (#42)
On non-Linux systems, `/sys` won't be available. In these cases, we can query `dmidecode(8)` directly. This PR implements a dmi_decode function to query the same fields ds-identify would otherwise read from /sys. This path is taken when /sys isn't present. In addition to adding dmidecode support, non-Linux systems also need to map in virtualization detection as systemd-detect-virt is not present; on FreeBSD, use sysctl kern.vm_guest and provide a mapping[1] between BSD values and those that match with systemd-detect-virt[2]. 1. https://github.com/freebsd/freebsd/blob/master/sys/kern/subr_param.c#L149-L157 2. https://www.freedesktop.org/software/systemd/man/systemd-detect-virt.html LP: #1852442
-rw-r--r--tests/unittests/test_ds_identify.py24
-rwxr-xr-xtools/ds-identify57
2 files changed, 77 insertions, 4 deletions
diff --git a/tests/unittests/test_ds_identify.py b/tests/unittests/test_ds_identify.py
index 12c6ae36..36d7fbbf 100644
--- a/tests/unittests/test_ds_identify.py
+++ b/tests/unittests/test_ds_identify.py
@@ -140,7 +140,8 @@ class DsIdentifyBase(CiTestCase):
{'name': 'blkid', 'out': BLKID_EFI_ROOT},
{'name': 'ovf_vmware_transport_guestinfo',
'out': 'No value found', 'ret': 1},
-
+ {'name': 'dmi_decode', 'ret': 1,
+ 'err': 'No dmidecode program. ERROR.'},
]
written = [d['name'] for d in mocks]
@@ -625,6 +626,21 @@ class TestDsIdentify(DsIdentifyBase):
self._test_ds_not_found('Ec2-E24Cloud-negative')
+class TestBSDNoSys(DsIdentifyBase):
+ """Test *BSD code paths
+
+ FreeBSD doesn't have /sys so we use dmidecode(8) here
+ It also doesn't have systemd-detect-virt(8), so we use sysctl(8) to query
+ kern.vm_guest, and optionally map it"""
+
+ def test_dmi_decode(self):
+ """Test that dmidecode(8) works on systems which don't have /sys
+
+ This will be used on *BSD systems.
+ """
+ self._test_ds_found('Hetzner-dmidecode')
+
+
class TestIsIBMProvisioning(DsIdentifyBase):
"""Test the is_ibm_provisioning method in ds-identify."""
@@ -923,6 +939,12 @@ VALID_CFG = {
'ds': 'Hetzner',
'files': {P_SYS_VENDOR: 'Hetzner\n'},
},
+ 'Hetzner-dmidecode': {
+ 'ds': 'Hetzner',
+ 'mocks': [
+ {'name': 'dmi_decode', 'ret': 0, 'RET': 'Hetzner'}
+ ],
+ },
'IBMCloud-metadata': {
'ds': 'IBMCloud',
'mocks': [
diff --git a/tools/ds-identify b/tools/ds-identify
index 20a99ee9..c93d4a77 100755
--- a/tools/ds-identify
+++ b/tools/ds-identify
@@ -179,13 +179,39 @@ debug() {
echo "$@" 1>&3
}
+dmi_decode() {
+ local sys_field="$1" dmi_field="" val=""
+ command -v dmidecode >/dev/null 2>&1 || {
+ warn "No dmidecode program. Cannot read $sys_field."
+ return 1
+ }
+ case "$1" in
+ sys_vendor) dmi_field="system-manufacturer";;
+ product_name) dmi_field="system-product-name";;
+ product_uuid) dmi_field="system-uuid";;
+ product_serial) dmi_field="system-serial-number";;
+ chassis_asset_tag) dmi_field="chassis-asset-tag";;
+ *) error "Unknown field $sys_field. Cannot call dmidecode."
+ return 1;;
+ esac
+ val=$(dmidecode --quiet "--string=$dmi_field" 2>/dev/null) || return 1
+ _RET="$val"
+}
+
get_dmi_field() {
local path="${PATH_SYS_CLASS_DMI_ID}/$1"
- if [ ! -f "$path" ] || [ ! -r "$path" ]; then
- _RET="$UNAVAILABLE"
+ _RET="$UNAVAILABLE"
+ if [ -d "${PATH_SYS_CLASS_DMI_ID}" ]; then
+ if [ -f "$path" ] && [ -r "$path" ]; then
+ read _RET < "${path}" || _RET="$ERROR"
+ return
+ fi
+ # if `/sys/class/dmi/id` exists, but not the object we're looking for,
+ # do *not* fallback to dmidecode!
return
fi
- read _RET < "${path}" || _RET="$ERROR"
+ dmi_decode "$1" || _RET="$ERROR"
+ return
}
block_dev_with_label() {
@@ -267,6 +293,31 @@ detect_virt() {
if [ $r -eq 0 ] || { [ $r -ne 0 ] && [ "$out" = "none" ]; }; then
virt="$out"
fi
+ elif [ "$DI_UNAME_KERNEL_NAME" = "FreeBSD" ]; then
+ # Map FreeBSD's vm_guest names to those systemd-detect-virt that
+ # don't match up. See
+ # https://github.com/freebsd/freebsd/blob/master/sys/kern/subr_param.c#L144-L160
+ # https://www.freedesktop.org/software/systemd/man/systemd-detect-virt.html
+ #
+ # systemd | kern.vm_guest
+ # ---------------------+---------------
+ # none | none
+ # kvm | kvm
+ # vmware | vmware
+ # microsoft | hv
+ # oracle | vbox
+ # xen | xen
+ # parallels | parallels
+ # bhyve | bhyve
+ # vm-other | generic
+ out=$(sysctl -qn kern.vm_guest 2>/dev/null) && {
+ case "$out" in
+ hv) virt="microsoft" ;;
+ vbox) virt="oracle" ;;
+ generic) "vm-other";;
+ *) virt="$out"
+ esac
+ }
fi
_RET="$virt"
}