From be2b25a7c66aec4c2491435a18e1a2e339872592 Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Tue, 6 Nov 2018 17:56:09 +0100 Subject: [PATCH 1/2] Have a real fixed HostID on Linux On Linux, most golang programs do not run as root (or at least, they should not), by default, the kernels uses strict permissions, so most userland programs cannot read `/sys/class/dmi/id/product_uuid`. However, programs such as Consul are relying on it to get fixed IDs, instead they have a different ID on each boot. We propose to use `/etc/machine-id` as fallback https://www.freedesktop.org/software/systemd/man/machine-id.html In order to fix this, this patch does the following: - if `/sys/class/dmi/id/product_uuid` can be read, use it for HostID - else if `/etc/machine-id` exists and has 32 chars, use it and add '-' to have the same format as product_uuid - finally, if notthing works, use the `kernel.random.boot_id` This will greatly increase the number of programs having correct behaviour when those rely on having a fixed HostID. This will fix the following issues: - https://github.com/shirou/gopsutil/issues/350 - https://github.com/hashicorp/consul/issues/4741 --- host/host_linux.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/host/host_linux.go b/host/host_linux.go index 7ca50897..29816757 100644 --- a/host/host_linux.go +++ b/host/host_linux.go @@ -73,7 +73,9 @@ func InfoWithContext(ctx context.Context) (*InfoStat, error) { } sysProductUUID := common.HostSys("class/dmi/id/product_uuid") + machineID := common.HostEtc("machine-id") switch { + // When not running as root, lib cannot read the value case common.PathExists(sysProductUUID): lines, err := common.ReadLines(sysProductUUID) if err == nil && len(lines) > 0 && lines[0] != "" { @@ -81,6 +83,14 @@ func InfoWithContext(ctx context.Context) (*InfoStat, error) { break } fallthrough + case common.PathExists(machineID): + lines, err := common.ReadLines(machineID) + if err == nil && len(lines) > 0 && len(lines[0]) == 32 { + st := lines[0] + ret.HostID = fmt.Sprintf("%s-%s-%s-%s-%s", st[0:8], st[8:12], st[12:16], st[16:20], st[20:32]) + break + } + fallthrough default: values, err := common.DoSysctrl("kernel.random.boot_id") if err == nil && len(values) == 1 && values[0] != "" { From 890eb805010a6bee6e060ee3f9415189940fb2af Mon Sep 17 00:00:00 2001 From: Pierre Souchay Date: Wed, 7 Nov 2018 00:08:23 +0100 Subject: [PATCH 2/2] Better comments for fallback on /etc/machine-id --- host/host_linux.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/host/host_linux.go b/host/host_linux.go index 29816757..2c1ac6ba 100644 --- a/host/host_linux.go +++ b/host/host_linux.go @@ -75,7 +75,8 @@ func InfoWithContext(ctx context.Context) (*InfoStat, error) { sysProductUUID := common.HostSys("class/dmi/id/product_uuid") machineID := common.HostEtc("machine-id") switch { - // When not running as root, lib cannot read the value + // In order to read this file, needs to be supported by kernel/arch and run as root + // so having fallback is important case common.PathExists(sysProductUUID): lines, err := common.ReadLines(sysProductUUID) if err == nil && len(lines) > 0 && lines[0] != "" { @@ -83,6 +84,7 @@ func InfoWithContext(ctx context.Context) (*InfoStat, error) { break } fallthrough + // Fallback on GNU Linux systems with systemd, readable by everyone case common.PathExists(machineID): lines, err := common.ReadLines(machineID) if err == nil && len(lines) > 0 && len(lines[0]) == 32 { @@ -91,6 +93,7 @@ func InfoWithContext(ctx context.Context) (*InfoStat, error) { break } fallthrough + // Not stable between reboot, but better than nothing default: values, err := common.DoSysctrl("kernel.random.boot_id") if err == nil && len(values) == 1 && values[0] != "" {