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] != "" {