]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
machined: add simple varlink API for listing machines
authorLennart Poettering <lennart@poettering.net>
Sat, 11 May 2024 17:55:15 +0000 (19:55 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 21 Jun 2024 15:28:16 +0000 (17:28 +0200)
src/machine/machined-varlink.c
src/shared/varlink-io.systemd.Machine.c

index dc35877c497af25a7234f2fa51dcaa56590447e0..38acfe97cd7d14383166a489a9e923206ff5607b 100644 (file)
@@ -1,10 +1,12 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "format-util.h"
+#include "hostname-util.h"
 #include "json-util.h"
 #include "machine-varlink.h"
 #include "machined-varlink.h"
 #include "mkdir.h"
+#include "socket-util.h"
 #include "user-util.h"
 #include "varlink.h"
 #include "varlink-io.systemd.Machine.h"
@@ -383,6 +385,83 @@ static int vl_method_get_memberships(Varlink *link, sd_json_variant *parameters,
         return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
 }
 
+static int list_machine_one(Varlink *link, Machine *m, bool more) {
+        int r;
+
+        assert(link);
+        assert(m);
+
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
+
+        r = sd_json_buildo(
+                        &v,
+                        SD_JSON_BUILD_PAIR("name", SD_JSON_BUILD_STRING(m->name)),
+                        SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(m->id), "id", SD_JSON_BUILD_ID128(m->id)),
+                        SD_JSON_BUILD_PAIR("class", SD_JSON_BUILD_STRING(machine_class_to_string(m->class))),
+                        SD_JSON_BUILD_PAIR_CONDITION(!!m->service, "service", SD_JSON_BUILD_STRING(m->service)),
+                        SD_JSON_BUILD_PAIR_CONDITION(!!m->root_directory, "rootDirectory", SD_JSON_BUILD_STRING(m->root_directory)),
+                        SD_JSON_BUILD_PAIR_CONDITION(!!m->unit, "unit", SD_JSON_BUILD_STRING(m->unit)),
+                        SD_JSON_BUILD_PAIR_CONDITION(pidref_is_set(&m->leader), "leader", SD_JSON_BUILD_UNSIGNED(m->leader.pid)),
+                        SD_JSON_BUILD_PAIR_CONDITION(dual_timestamp_is_set(&m->timestamp), "timestamp", JSON_BUILD_DUAL_TIMESTAMP(&m->timestamp)),
+                        SD_JSON_BUILD_PAIR_CONDITION(m->vsock_cid != VMADDR_CID_ANY, "vSockCid", SD_JSON_BUILD_UNSIGNED(m->vsock_cid)),
+                        SD_JSON_BUILD_PAIR_CONDITION(!!m->ssh_address, "sshAddress", SD_JSON_BUILD_STRING(m->ssh_address)));
+        if (r < 0)
+                return r;
+
+        if (more)
+                return varlink_notify(link, v);
+
+        return varlink_reply(link, v);
+}
+
+static int vl_method_list(Varlink *link, sd_json_variant *parameters, VarlinkMethodFlags flags, void *userdata) {
+        Manager *m = ASSERT_PTR(userdata);
+        const char *mn = NULL;
+
+        const sd_json_dispatch_field dispatch_table[] = {
+                { "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&mn), 0 },
+                {}
+        };
+
+        int r;
+
+        assert(parameters);
+
+        r = varlink_dispatch(link, parameters, dispatch_table, 0);
+        if (r != 0)
+                return r;
+
+        if (mn) {
+                if (!hostname_is_valid(mn, /* flags= */ VALID_HOSTNAME_DOT_HOST))
+                        return varlink_error_invalid_parameter_name(link, "name");
+
+                Machine *machine = hashmap_get(m->machines, mn);
+                if (!machine)
+                        return varlink_error(link, "io.systemd.Machine.NoSuchMachine", NULL);
+
+                return list_machine_one(link, machine, /* more= */ false);
+        }
+
+        if (!FLAGS_SET(flags, VARLINK_METHOD_MORE))
+                return varlink_error(link, VARLINK_ERROR_EXPECTED_MORE, NULL);
+
+        Machine *previous = NULL, *i;
+        HASHMAP_FOREACH(i, m->machines) {
+                if (previous) {
+                        r = list_machine_one(link, previous, /* more= */ true);
+                        if (r < 0)
+                                return r;
+                }
+
+                previous = i;
+        }
+
+        if (previous)
+                return list_machine_one(link, previous, /* more= */ false);
+
+        return varlink_error(link, "io.systemd.Machine.NoSuchMachine", NULL);
+}
+
 static int manager_varlink_init_userdb(Manager *m) {
         _cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
         int r;
@@ -443,7 +522,10 @@ static int manager_varlink_init_machine(Manager *m) {
         if (r < 0)
                 return log_error_errno(r, "Failed to add UserDatabase interface to varlink server: %m");
 
-        r = varlink_server_bind_method(s, "io.systemd.Machine.Register", vl_method_register);
+        r = varlink_server_bind_method_many(
+                        s,
+                        "io.systemd.Machine.Register", vl_method_register,
+                        "io.systemd.Machine.List",     vl_method_list);
         if (r < 0)
                 return log_error_errno(r, "Failed to register varlink methods: %m");
 
index 2d25a345d7979b92e1fff86737996260ed953d6c..b5f8f5c0751428bf6ec171ed6caa2e136467c96d 100644 (file)
@@ -16,10 +16,49 @@ static VARLINK_DEFINE_METHOD(
                 VARLINK_DEFINE_INPUT(sshAddress,        VARLINK_STRING, VARLINK_NULLABLE),
                 VARLINK_DEFINE_INPUT(sshPrivateKeyPath, VARLINK_STRING, VARLINK_NULLABLE));
 
+static VARLINK_DEFINE_STRUCT_TYPE(
+                Timestamp,
+                VARLINK_FIELD_COMMENT("Timestamp in µs in the CLOCK_REALTIME clock (wallclock)"),
+                VARLINK_DEFINE_FIELD(realtime, VARLINK_INT, VARLINK_NULLABLE),
+                VARLINK_FIELD_COMMENT("Timestamp in µs in the CLOCK_MONOTONIC clock"),
+                VARLINK_DEFINE_FIELD(monotonic, VARLINK_INT, VARLINK_NULLABLE));
+
+static VARLINK_DEFINE_METHOD(
+                List,
+                VARLINK_FIELD_COMMENT("If non-null the name of a running machine to report details on. If null/unspecified enumerates all running machines."),
+                VARLINK_DEFINE_INPUT(name, VARLINK_STRING, VARLINK_NULLABLE),
+                VARLINK_FIELD_COMMENT("Name of the machine"),
+                VARLINK_DEFINE_OUTPUT(name, VARLINK_STRING, 0),
+                VARLINK_FIELD_COMMENT("128bit ID identifying this machine, formatted in hexadecimal"),
+                VARLINK_DEFINE_OUTPUT(id, VARLINK_STRING, VARLINK_NULLABLE),
+                VARLINK_FIELD_COMMENT("Name of the software that registered this machine"),
+                VARLINK_DEFINE_OUTPUT(service, VARLINK_STRING, VARLINK_NULLABLE),
+                VARLINK_FIELD_COMMENT("The class of this machine"),
+                VARLINK_DEFINE_OUTPUT(class, VARLINK_STRING, 0),
+                VARLINK_FIELD_COMMENT("Leader process PID of this machine"),
+                VARLINK_DEFINE_OUTPUT(leader, VARLINK_INT, VARLINK_NULLABLE),
+                VARLINK_FIELD_COMMENT("Root directory of this machine, if known, relative to host file system"),
+                VARLINK_DEFINE_OUTPUT(rootDirectory, VARLINK_STRING, VARLINK_NULLABLE),
+                VARLINK_FIELD_COMMENT("The service manager unit this machine resides in"),
+                VARLINK_DEFINE_OUTPUT(unit, VARLINK_STRING, VARLINK_NULLABLE),
+                VARLINK_FIELD_COMMENT("Timestamp when the machine was activated"),
+                VARLINK_DEFINE_OUTPUT_BY_TYPE(timestamp, Timestamp, VARLINK_NULLABLE),
+                VARLINK_FIELD_COMMENT("AF_VSOCK CID of the machine if known and applicable"),
+                VARLINK_DEFINE_OUTPUT(vSockCid, VARLINK_INT, VARLINK_NULLABLE),
+                VARLINK_FIELD_COMMENT("SSH address to connect to"),
+                VARLINK_DEFINE_OUTPUT(sshAddress, VARLINK_STRING, VARLINK_NULLABLE));
+
+static VARLINK_DEFINE_ERROR(NoSuchMachine);
 static VARLINK_DEFINE_ERROR(MachineExists);
 
 VARLINK_DEFINE_INTERFACE(
                 io_systemd_Machine,
                 "io.systemd.Machine",
+                VARLINK_SYMBOL_COMMENT("A timestamp object consisting of both CLOCK_REALTIME and CLOCK_MONOTONIC timestamps"),
+                &vl_type_Timestamp,
                 &vl_method_Register,
+                VARLINK_SYMBOL_COMMENT("List running machines"),
+                &vl_method_List,
+                VARLINK_SYMBOL_COMMENT("No matching machine currently running"),
+                &vl_error_NoSuchMachine,
                 &vl_error_MachineExists);