]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
report-basic: also report /etc/machine-info fields, just like os-release fields
authorLennart Poettering <lennart@amutable.com>
Fri, 22 May 2026 03:05:51 +0000 (05:05 +0200)
committerLennart Poettering <lennart@amutable.com>
Fri, 22 May 2026 10:17:09 +0000 (12:17 +0200)
The TAGS= field is really nice to have in reports, hence make this a
thing.

src/report/report-basic.c
test/units/TEST-74-AUX-UTILS.report.sh

index 43c9cb97741490227a7bafcfc789c9a1d7928a24..f867ab3505056ad03f8bfed57bad9d4a39362705 100644 (file)
@@ -9,7 +9,9 @@
 #include "alloc-util.h"
 #include "architecture.h"
 #include "cpu-set-util.h"
+#include "env-file.h"
 #include "hostname-setup.h"
+#include "hostname-util.h"
 #include "limits-util.h"
 #include "log.h"
 #include "metrics.h"
@@ -198,6 +200,51 @@ static int os_release_generate(const MetricFamily mf[static _FIELD_MAX - 1], sd_
         return 0;
 }
 
+static int machine_info_generate(const MetricFamily *mf, sd_varlink *link, void *userdata) {
+        enum {
+                MACHINE_INFO_FIELD_PRETTY_HOSTNAME,
+                MACHINE_INFO_FIELD_DEPLOYMENT,
+                MACHINE_INFO_FIELD_LOCATION,
+                MACHINE_INFO_FIELD_TAGS,
+                _MACHINE_INFO_FIELD_MAX,
+        };
+
+        char* values[_MACHINE_INFO_FIELD_MAX] = {};
+        CLEANUP_ELEMENTS(values, free_many_charp);
+        int r;
+
+        assert(mf && mf->name);
+        assert(link);
+
+        r = parse_env_file(/* f= */ NULL, etc_machine_info(),
+                           "PRETTY_HOSTNAME", &values[MACHINE_INFO_FIELD_PRETTY_HOSTNAME],
+                           "DEPLOYMENT",      &values[MACHINE_INFO_FIELD_DEPLOYMENT],
+                           "LOCATION",        &values[MACHINE_INFO_FIELD_LOCATION],
+                           "TAGS",            &values[MACHINE_INFO_FIELD_TAGS]);
+        if (r < 0) {
+                log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
+                               "Failed to read machine-info file, ignoring: %m");
+                return 0;
+        }
+
+        for (size_t i = 0; i < _MACHINE_INFO_FIELD_MAX; i++) {
+                const char *v = values[i];
+                if (!v)
+                        continue;
+
+                r = metric_build_send_string(
+                                mf + i,
+                                link,
+                                /* object= */ NULL,
+                                v,
+                                /* fields= */ NULL);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
 static int virtualization_generate(const MetricFamily *mf, sd_varlink *link, void *userdata) {
         assert(mf && mf->name);
         assert(link);
@@ -222,6 +269,14 @@ static int virtualization_generate(const MetricFamily *mf, sd_varlink *link, voi
                 .generate = NULL,                                       \
         }
 
+#define MACHINE_INFO_STANDARD_FIELD(name)                               \
+        {                                                               \
+                METRIC_IO_SYSTEMD_BASIC_PREFIX "MachineInfo." name,     \
+                "Machine identification (" name "= field from machine-info)", \
+                METRIC_FAMILY_TYPE_STRING,                              \
+                .generate = NULL,                                       \
+        }
+
 static const MetricFamily metric_family_table[] = {
         /* Keep entries ordered alphabetically */
         {
@@ -260,6 +315,16 @@ static const MetricFamily metric_family_table[] = {
                 METRIC_FAMILY_TYPE_STRING,
                 .generate = machine_id_generate,
         },
+        {
+                METRIC_IO_SYSTEMD_BASIC_PREFIX "MachineInfo.PRETTY_HOSTNAME",
+                "Pretty hostname (PRETTY_HOSTNAME= field from machine-info)",
+                METRIC_FAMILY_TYPE_STRING,
+                .generate = machine_info_generate,
+        },
+        MACHINE_INFO_STANDARD_FIELD("DEPLOYMENT"),
+        MACHINE_INFO_STANDARD_FIELD("LOCATION"),
+        MACHINE_INFO_STANDARD_FIELD("TAGS"),
+        /* Keep those ↑ in sync with machine_info_generate(). */
         {
                 METRIC_IO_SYSTEMD_BASIC_PREFIX "OSRelease.NAME",
                 "Operating system human-readable name (PRETTY_NAME= or NAME= field from os-release)",
index d89a06cd9a9120dbd01f3588da74e03d2c173419..48bbc4841a8f555b63841947d9cc2a5943db9b72 100755 (executable)
@@ -62,6 +62,46 @@ id1="$(varlinkctl call --more /run/systemd/report/io.systemd.Basic io.systemd.Me
 id2="$(. /etc/os-release; echo "$ID")"
 [ "$id1" = "$id2" ]
 
+# test io.systemd.Basic.MachineInfo.* metrics, sourced from /etc/machine-info
+if [ -e /etc/machine-info ]; then
+    MACHINE_INFO_BACKUP="$(mktemp)"
+    cp /etc/machine-info "$MACHINE_INFO_BACKUP"
+    MACHINE_INFO_EXISTED=1
+else
+    MACHINE_INFO_EXISTED=0
+fi
+
+restore_machine_info() {
+    set +e
+    if [ "$MACHINE_INFO_EXISTED" = 1 ]; then
+        cp "$MACHINE_INFO_BACKUP" /etc/machine-info
+        rm -f "$MACHINE_INFO_BACKUP"
+    else
+        rm -f /etc/machine-info
+    fi
+    set -e
+}
+trap restore_machine_info EXIT
+
+cat >/etc/machine-info <<EOF
+PRETTY_HOSTNAME="Test Machine"
+DEPLOYMENT=test
+LOCATION="Test Lab, Rack 3"
+TAGS=foo:bar:baz
+EOF
+
+# The metric source re-reads /etc/machine-info on every call, so no service restart is needed.
+machine_info_metrics="$(varlinkctl call --more /run/systemd/report/io.systemd.Basic io.systemd.Metrics.List {})"
+machine_info_value() { echo "$machine_info_metrics" | jq --seq -r "select(.name == \"$1\") | .value"; }
+
+[ "$(machine_info_value io.systemd.Basic.MachineInfo.PRETTY_HOSTNAME)" = "Test Machine" ]
+[ "$(machine_info_value io.systemd.Basic.MachineInfo.DEPLOYMENT)" = "test" ]
+[ "$(machine_info_value io.systemd.Basic.MachineInfo.LOCATION)" = "Test Lab, Rack 3" ]
+[ "$(machine_info_value io.systemd.Basic.MachineInfo.TAGS)" = "foo:bar:baz" ]
+
+restore_machine_info
+trap - EXIT
+
 # Test HTTP upload (plain http)
 FAKE_SERVER=/usr/lib/systemd/tests/integration-tests/TEST-74-AUX-UTILS/TEST-74-AUX-UTILS.units/fake-report-server.py
 CERTDIR=$(mktemp -d)