diff --git a/NEWS b/NEWS index c5686b929f..f5846c5456 100644 --- a/NEWS +++ b/NEWS @@ -77,6 +77,13 @@ CHANGES WITH 262: should be provisioned as far as possible without ever blocking on a prompt. + Changes in systemd-hostnamed: + + * The Describe() method (for both D-Bus and Varlink) now exposes the + parsed machine tag list as a new MachineTags field, so that Varlink + clients no longer need to parse the raw TAGS= line out of + MachineInformationData themselves. + Changes in systemd-networkd: * A new IPv4ProxyARPAddress= setting has been added to the [Network] diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index 98ade098a7..2784697ab5 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -2013,6 +2013,12 @@ static int build_describe_response(Context *c, bool privileged, sd_json_variant (void) load_os_release_pairs(/* root= */ NULL, &os_release_pairs); (void) load_env_file_pairs(/* f= */ NULL, etc_machine_info(), &machine_info_pairs); + /* Silently drop any invalid tags that might have been written into the file by hand */ + _cleanup_strv_free_ char **tags = NULL; + r = machine_tags_from_string(c->data[PROP_TAGS], /* graceful= */ true, &tags); + if (r < 0) + log_warning_errno(r, "Failed to parse machine tags '%s', ignoring: %m", strnull(c->data[PROP_TAGS])); + r = sd_json_buildo( &v, SD_JSON_BUILD_PAIR_STRING("Hostname", hn ?: dhn), @@ -2037,6 +2043,7 @@ static int build_describe_response(Context *c, bool privileged, sd_json_variant SD_JSON_BUILD_PAIR_STRING("OperatingSystemImageID", c->data[PROP_OS_IMAGE_ID]), SD_JSON_BUILD_PAIR_STRING("OperatingSystemImageVersion", c->data[PROP_OS_IMAGE_VERSION]), SD_JSON_BUILD_PAIR("MachineInformationData", JSON_BUILD_STRV_ENV_PAIR(machine_info_pairs)), + SD_JSON_BUILD_PAIR_STRV("MachineTags", tags), SD_JSON_BUILD_PAIR_STRING("HardwareVendor", vendor ?: c->data[PROP_HARDWARE_VENDOR]), SD_JSON_BUILD_PAIR_STRING("HardwareModel", model ?: c->data[PROP_HARDWARE_MODEL]), SD_JSON_BUILD_PAIR_STRING("HardwareSerial", serial), diff --git a/src/shared/varlink-io.systemd.Hostname.c b/src/shared/varlink-io.systemd.Hostname.c index ca7b2b534b..2e2564c738 100644 --- a/src/shared/varlink-io.systemd.Hostname.c +++ b/src/shared/varlink-io.systemd.Hostname.c @@ -50,6 +50,8 @@ static SD_VARLINK_DEFINE_METHOD( SD_VARLINK_DEFINE_OUTPUT(OperatingSystemImageVersion, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("The full contents of /etc/machine-info, as an array of 'KEY=VALUE' strings."), SD_VARLINK_DEFINE_OUTPUT(MachineInformationData, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY), + SD_VARLINK_FIELD_COMMENT("The machine tags, from the TAGS= field of /etc/machine-info with any invalid tags filtered out. Empty if none are configured."), + SD_VARLINK_DEFINE_OUTPUT(MachineTags, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY), SD_VARLINK_FIELD_COMMENT("The hardware vendor of this system. Null if not known."), SD_VARLINK_DEFINE_OUTPUT(HardwareVendor, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("The hardware model of this system. Null if not known."), diff --git a/test/units/TEST-71-HOSTNAME.sh b/test/units/TEST-71-HOSTNAME.sh index c1238f83a8..3563f9ae00 100755 --- a/test/units/TEST-71-HOSTNAME.sh +++ b/test/units/TEST-71-HOSTNAME.sh @@ -488,6 +488,24 @@ testcase_tags() { # Invalid tags are refused. (! varlinkctl call /run/systemd/io.systemd.Hostname io.systemd.Hostname.SetTags '{"add":["in valid"]}') + # Describe() exposes the parsed tag list as MachineTags, on both transports. + varlinkctl call /run/systemd/io.systemd.Hostname io.systemd.Hostname.SetTags '{"set":["foo","bar"]}' + assert_eq "$(varlinkctl call /run/systemd/io.systemd.Hostname io.systemd.Hostname.Describe '{}' | jq --compact-output .MachineTags)" '["bar","foo"]' + assert_eq "$(busctl call --json=short org.freedesktop.hostname1 /org/freedesktop/hostname1 org.freedesktop.hostname1 Describe | jq --compact-output '.data[0] | fromjson | .MachineTags')" '["bar","foo"]' + assert_eq "$(busctl get-property org.freedesktop.hostname1 /org/freedesktop/hostname1 org.freedesktop.hostname1 Tags)" 'as 2 "bar" "foo"' + # The field is an empty list if no tags are configured (as with the D-Bus Tags property). + varlinkctl call /run/systemd/io.systemd.Hostname io.systemd.Hostname.SetTags '{"set":[]}' + assert_eq "$(varlinkctl call /run/systemd/io.systemd.Hostname io.systemd.Hostname.Describe '{}' | jq --compact-output .MachineTags)" "[]" + assert_eq "$(busctl call --json=short org.freedesktop.hostname1 /org/freedesktop/hostname1 org.freedesktop.hostname1 Describe | jq --compact-output '.data[0] | fromjson | .MachineTags')" "[]" + assert_eq "$(busctl get-property org.freedesktop.hostname1 /org/freedesktop/hostname1 org.freedesktop.hostname1 Tags)" 'as 0' + # Invalid tags edited into /etc/machine-info by hand are gracefully dropped from MachineTags + # and D-Bus's Tags property, while MachineInformationData still carries the raw TAGS= line. + echo 'TAGS=good:-invalid' >/etc/machine-info + assert_eq "$(varlinkctl call /run/systemd/io.systemd.Hostname io.systemd.Hostname.Describe '{}' | jq --compact-output .MachineTags)" '["good"]' + assert_eq "$(busctl call --json=short org.freedesktop.hostname1 /org/freedesktop/hostname1 org.freedesktop.hostname1 Describe | jq --compact-output '.data[0] | fromjson | .MachineTags')" '["good"]' + assert_eq "$(busctl get-property org.freedesktop.hostname1 /org/freedesktop/hostname1 org.freedesktop.hostname1 Tags)" 'as 1 "good"' + assert_eq "$(varlinkctl call /run/systemd/io.systemd.Hostname io.systemd.Hostname.Describe '{}' | jq --raw-output '.MachineInformationData[] | select(startswith("TAGS="))')" "TAGS=good:-invalid" + hostnamectl tags "" }