#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"
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);
.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 */
{
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)",
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)