From: Zbigniew Jędrzejewski-Szmek Date: Fri, 8 May 2026 07:23:09 +0000 (+0200) Subject: report-basic: expose os-release fields as metrics X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e27c382bf0c840bb0c7c3ea9cfe4c69034a57fa8;p=thirdparty%2Fsystemd.git report-basic: expose os-release fields as metrics Add io.systemd.Basic.OSRelease metric families that reports select fields from os-release. $ cat /etc/os-release NAME="Fedora Linux" VERSION="45 (Cloud Edition Prerelease)" RELEASE_TYPE=development ID=fedora VERSION_ID=45 VERSION_CODENAME="" PRETTY_NAME="Fedora Linux 45 (Cloud Edition Prerelease)" ANSI_COLOR="0;38;2;60;110;180" LOGO=fedora-logo-icon CPE_NAME="cpe:/o:fedoraproject:fedora:45" HOME_URL="https://fedoraproject.org/" DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/rawhide/" SUPPORT_URL="https://ask.fedoraproject.org/" BUG_REPORT_URL="https://bugzilla.redhat.com/" REDHAT_BUGZILLA_PRODUCT="Fedora" REDHAT_BUGZILLA_PRODUCT_VERSION=rawhide REDHAT_SUPPORT_PRODUCT="Fedora" REDHAT_SUPPORT_PRODUCT_VERSION=rawhide SUPPORT_END=2027-11-24 VARIANT="Cloud Edition" VARIANT_ID=cloud $ varlinkctl call --more ./build/systemd-report-basic io.systemd.Metrics.List {} | jq --seq -c ... {"name":"io.systemd.Basic.OSRelease.NAME","value":"Fedora Linux 44 (Workstation Edition)"} {"name":"io.systemd.Basic.OSRelease.ID","value":"fedora"} {"name":"io.systemd.Basic.OSRelease.CPE_NAME","value":"cpe:/o:fedoraproject:fedora:44"} {"name":"io.systemd.Basic.OSRelease.VARIANT_ID","value":"workstation"} {"name":"io.systemd.Basic.OSRelease.VERSION_ID","value":"44"} {"name":"io.systemd.Basic.OSRelease.SUPPORT_END","value":"2027-05-19"} I picked the fields that contain useful information about the specific version/image/variant/experiment/flavour of the system. Also, either NAME or PRETTY_NAME is included. This one is intended for human readers to be able to identify the OS version easily. --- diff --git a/src/report/report-basic.c b/src/report/report-basic.c index 11ecb7b45c6..772a5d9f742 100644 --- a/src/report/report-basic.c +++ b/src/report/report-basic.c @@ -9,7 +9,9 @@ #include "alloc-util.h" #include "architecture.h" #include "hostname-setup.h" +#include "log.h" #include "metrics.h" +#include "os-util.h" #include "report-basic.h" #include "virt.h" @@ -98,6 +100,71 @@ static int machine_id_generate(const MetricFamily *mf, sd_varlink *link, void *u /* fields= */ NULL); } +enum { + FIELD_PRETTY_NAME, + FIELD_NAME, + FIELD_ID, + FIELD_CPE_NAME, + FIELD_VARIANT_ID, + FIELD_VERSION_ID, + FIELD_BUILD_ID, + FIELD_IMAGE_VERSION, + FIELD_IMAGE_ID, + FIELD_SUPPORT_END, + FIELD_EXPERIMENT, + FIELD_SYSEXT_LEVEL, + FIELD_CONFEXT_LEVEL, + _FIELD_MAX, +}; + +static int os_release_generate(const MetricFamily mf[static _FIELD_MAX - 1], sd_varlink *link, void *userdata) { + char* values[_FIELD_MAX] = {}; + CLEANUP_ELEMENTS(values, free_many_charp); + int r; + + assert(mf && mf->name); + assert(link); + + r = parse_os_release(NULL, + "PRETTY_NAME", &values[FIELD_PRETTY_NAME], + "NAME", &values[FIELD_NAME], + "ID", &values[FIELD_ID], + "CPE_NAME", &values[FIELD_CPE_NAME], + "VARIANT_ID", &values[FIELD_VARIANT_ID], + "VERSION_ID", &values[FIELD_VERSION_ID], + "BUILD_ID", &values[FIELD_BUILD_ID], + "IMAGE_VERSION", &values[FIELD_IMAGE_VERSION], + "IMAGE_ID", &values[FIELD_IMAGE_ID], + "SUPPORT_END", &values[FIELD_SUPPORT_END], + "EXPERIMENT", &values[FIELD_EXPERIMENT], + "SYSEXT_LEVEL", &values[FIELD_SYSEXT_LEVEL], + "CONFEXT_LEVEL", &values[FIELD_CONFEXT_LEVEL]); + if (r < 0) { + log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, + "Failed to read os-release file, ignoring: %m"); + return 0; + } + + for (size_t i = 1; i < _FIELD_MAX; i++) { + const char *v = values[i]; + if (i == FIELD_NAME && values[FIELD_PRETTY_NAME]) + v = values[FIELD_PRETTY_NAME]; /* Prefer PRETTY_NAME to NAME */ + + if (v) { + r = metric_build_send_string( + mf + i - 1, + 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); @@ -114,6 +181,14 @@ static int virtualization_generate(const MetricFamily *mf, sd_varlink *link, voi /* fields= */ NULL); } +#define OS_RELEASE_STANDARD_FIELD(name) \ + { \ + METRIC_IO_SYSTEMD_BASIC_PREFIX "OSRelease." name, \ + "Operating system identification (" name "= field from os-release)", \ + METRIC_FAMILY_TYPE_STRING, \ + .generate = NULL, \ + } + static const MetricFamily metric_family_table[] = { /* Keep entries ordered alphabetically */ { @@ -146,6 +221,24 @@ static const MetricFamily metric_family_table[] = { METRIC_FAMILY_TYPE_STRING, .generate = machine_id_generate, }, + { + METRIC_IO_SYSTEMD_BASIC_PREFIX "OSRelease.NAME", + "Operating system human-readable name (PRETTY_NAME= or NAME= field from os-release)", + METRIC_FAMILY_TYPE_STRING, + .generate = os_release_generate, + }, + OS_RELEASE_STANDARD_FIELD("ID"), + OS_RELEASE_STANDARD_FIELD("CPE_NAME"), + OS_RELEASE_STANDARD_FIELD("VARIANT_ID"), + OS_RELEASE_STANDARD_FIELD("VERSION_ID"), + OS_RELEASE_STANDARD_FIELD("BUILD_ID"), + OS_RELEASE_STANDARD_FIELD("IMAGE_VERSION"), + OS_RELEASE_STANDARD_FIELD("IMAGE_ID"), + OS_RELEASE_STANDARD_FIELD("SUPPORT_END"), + OS_RELEASE_STANDARD_FIELD("EXPERIMENT"), + OS_RELEASE_STANDARD_FIELD("SYSEXT_LEVEL"), + OS_RELEASE_STANDARD_FIELD("CONFEXT_LEVEL"), + /* Keep those ↑ in sync with os_release_generate(). */ { METRIC_IO_SYSTEMD_BASIC_PREFIX "Virtualization", "Virtualization type", diff --git a/test/units/TEST-74-AUX-UTILS.report.sh b/test/units/TEST-74-AUX-UTILS.report.sh index 61d2b10d0b7..0669f5587f0 100755 --- a/test/units/TEST-74-AUX-UTILS.report.sh +++ b/test/units/TEST-74-AUX-UTILS.report.sh @@ -57,6 +57,10 @@ varlinkctl list-methods /run/systemd/report/io.systemd.Basic varlinkctl --more call /run/systemd/report/io.systemd.Basic io.systemd.Metrics.List {} varlinkctl --more call /run/systemd/report/io.systemd.Basic io.systemd.Metrics.Describe {} +id1="$(varlinkctl call --more /run/systemd/report/io.systemd.Basic io.systemd.Metrics.List {} | jq --seq -r 'select(.name == "io.systemd.Basic.OSRelease.ID") | .value')" +id2="$(. /etc/os-release; echo "$ID")" +[ "$id1" = "$id2" ] + # 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)