report: implement facts interface

This commit is contained in:
Yaping Li
2026-04-01 15:34:45 +02:00
committed by Zbigniew Jędrzejewski-Szmek
parent e11158af38
commit f60d5985e5
11 changed files with 636 additions and 13 deletions
+1
View File
@@ -70,6 +70,7 @@ libcore_sources = files(
'varlink-execute.c',
'varlink-manager.c',
'varlink-metrics.c',
'varlink-facts.c',
'varlink-unit.c',
)
+142
View File
@@ -0,0 +1,142 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <sys/utsname.h>
#include "sd-id128.h"
#include "sd-json.h"
#include "sd-varlink.h"
#include "alloc-util.h"
#include "architecture.h"
#include "facts.h"
#include "hostname-setup.h"
#include "varlink-facts.h"
#include "virt.h"
static int architecture_generate(FactFamilyContext *context, void *userdata) {
assert(context);
return fact_build_send_string(
context,
/* object= */ NULL,
architecture_to_string(uname_architecture()));
}
static int boot_id_generate(FactFamilyContext *context, void *userdata) {
sd_id128_t id;
int r;
assert(context);
r = sd_id128_get_boot(&id);
if (r < 0)
return r;
return fact_build_send_string(
context,
/* object= */ NULL,
SD_ID128_TO_STRING(id));
}
static int hostname_generate(FactFamilyContext *context, void *userdata) {
_cleanup_free_ char *hostname = NULL;
int r;
assert(context);
r = gethostname_full(GET_HOSTNAME_ALLOW_LOCALHOST | GET_HOSTNAME_FALLBACK_DEFAULT, &hostname);
if (r < 0)
return r;
return fact_build_send_string(
context,
/* object= */ NULL,
hostname);
}
static int kernel_version_generate(FactFamilyContext *context, void *userdata) {
struct utsname u;
assert(context);
assert_se(uname(&u) >= 0);
return fact_build_send_string(
context,
/* object= */ NULL,
u.release);
}
static int machine_id_generate(FactFamilyContext *context, void *userdata) {
sd_id128_t id;
int r;
assert(context);
r = sd_id128_get_machine(&id);
if (r < 0)
return r;
return fact_build_send_string(
context,
/* object= */ NULL,
SD_ID128_TO_STRING(id));
}
static int virtualization_generate(FactFamilyContext *context, void *userdata) {
Virtualization v;
assert(context);
v = detect_virtualization();
if (v < 0)
return v;
return fact_build_send_string(
context,
/* object= */ NULL,
virtualization_to_string(v));
}
const FactFamily fact_family_table[] = {
/* Keep facts ordered alphabetically */
{
.name = FACT_IO_SYSTEMD_MANAGER_PREFIX "Architecture",
.description = "CPU architecture",
.generate = architecture_generate,
},
{
.name = FACT_IO_SYSTEMD_MANAGER_PREFIX "BootID",
.description = "Current boot ID",
.generate = boot_id_generate,
},
{
.name = FACT_IO_SYSTEMD_MANAGER_PREFIX "Hostname",
.description = "System hostname",
.generate = hostname_generate,
},
{
.name = FACT_IO_SYSTEMD_MANAGER_PREFIX "KernelVersion",
.description = "Kernel version",
.generate = kernel_version_generate,
},
{
.name = FACT_IO_SYSTEMD_MANAGER_PREFIX "MachineID",
.description = "Machine ID",
.generate = machine_id_generate,
},
{
.name = FACT_IO_SYSTEMD_MANAGER_PREFIX "Virtualization",
.description = "Virtualization type",
.generate = virtualization_generate,
},
{}
};
int vl_method_describe_facts(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return facts_method_describe(fact_family_table, link, parameters, flags, userdata);
}
int vl_method_list_facts(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
return facts_method_list(fact_family_table, link, parameters, flags, userdata);
}
+9
View File
@@ -0,0 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "core-forward.h"
#define FACT_IO_SYSTEMD_MANAGER_PREFIX "io.systemd.Manager."
int vl_method_list_facts(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
int vl_method_describe_facts(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
+16 -1
View File
@@ -5,6 +5,7 @@
#include "constants.h"
#include "errno-util.h"
#include "manager.h"
#include "facts.h"
#include "metrics.h"
#include "path-util.h"
#include "pidref.h"
@@ -12,6 +13,7 @@
#include "unit.h"
#include "varlink.h"
#include "varlink-dynamic-user.h"
#include "varlink-facts.h"
#include "varlink-io.systemd.ManagedOOM.h"
#include "varlink-io.systemd.Manager.h"
#include "varlink-io.systemd.Unit.h"
@@ -433,16 +435,29 @@ int manager_setup_varlink_server(Manager *m) {
}
int manager_setup_varlink_metrics_server(Manager *m) {
int r;
assert(m);
sd_varlink_server_flags_t flags = SD_VARLINK_SERVER_INHERIT_USERDATA;
if (MANAGER_IS_SYSTEM(m))
flags |= SD_VARLINK_SERVER_ACCOUNT_UID;
return metrics_setup_varlink_server(&m->metrics_varlink_server, flags,
r = metrics_setup_varlink_server(&m->metrics_varlink_server, flags,
m->event, EVENT_PRIORITY_IPC,
vl_method_list_metrics, vl_method_describe_metrics,
m);
if (r < 0)
return r;
if (r > 0) {
/* Server newly created — also register facts interface on it */
int q = facts_add_to_varlink_server(m->metrics_varlink_server,
vl_method_list_facts, vl_method_describe_facts);
if (q < 0)
return q;
}
return r;
}
static int varlink_server_listen_many_idempotent_sentinel(
+223 -12
View File
@@ -41,6 +41,8 @@ STATIC_DESTRUCTOR_REGISTER(arg_matches, strv_freep);
typedef enum Action {
ACTION_LIST,
ACTION_DESCRIBE,
ACTION_LIST_FACTS,
ACTION_DESCRIBE_FACTS,
_ACTION_MAX,
_ACTION_INVALID = -EINVAL,
} Action;
@@ -213,7 +215,7 @@ static Verdict metrics_verdict(LinkInfo *li, sd_json_variant *metric) {
return VERDICT_MATCH;
}
static int metrics_on_query_reply(
static int on_query_reply(
sd_varlink *link,
sd_json_variant *parameters,
const char *error_id,
@@ -288,14 +290,20 @@ static int metrics_call(Context *context, const char *name, const char *path) {
if (r < 0)
return log_error_errno(r, "Failed to attach varlink connection to event loop: %m");
r = sd_varlink_bind_reply(vl, metrics_on_query_reply);
r = sd_varlink_bind_reply(vl, on_query_reply);
if (r < 0)
return log_error_errno(r, "Failed to bind reply callback: %m");
const char *method = context->action == ACTION_LIST ? "io.systemd.Metrics.List" : "io.systemd.Metrics.Describe";
r = sd_varlink_observe(vl,
method,
/* parameters= */ NULL);
const char *method;
switch (context->action) {
case ACTION_LIST: method = "io.systemd.Metrics.List"; break;
case ACTION_DESCRIBE: method = "io.systemd.Metrics.Describe"; break;
case ACTION_LIST_FACTS: method = "io.systemd.Facts.List"; break;
case ACTION_DESCRIBE_FACTS: method = "io.systemd.Facts.Describe"; break;
default: assert_not_reached();
}
r = sd_varlink_observe(vl, method, /* parameters= */ NULL);
if (r < 0)
return log_error_errno(r, "Failed to issue %s() call: %m", method);
@@ -308,7 +316,6 @@ static int metrics_call(Context *context, const char *name, const char *path) {
.link = sd_varlink_ref(vl),
.name = strdup(name),
};
if (!li->name)
return log_oom();
@@ -426,6 +433,105 @@ static int metrics_output_describe(Context *context, Table **ret) {
return 0;
}
static int facts_output_list(Context *context, Table **ret) {
int r;
assert(context);
_cleanup_(table_unrefp) Table *table = table_new("family", "object", "value");
if (!table)
return log_oom();
table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
table_set_sort(table, (size_t) 0, (size_t) 1, (size_t) 2);
FOREACH_ARRAY(m, context->metrics, context->n_metrics) {
struct {
const char *name;
const char *object;
sd_json_variant *value;
} d = {};
static const sd_json_dispatch_field dispatch_table[] = {
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, voffsetof(d, name), SD_JSON_MANDATORY },
{ "object", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, voffsetof(d, object), 0 },
{ "value", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_variant_noref, voffsetof(d, value), SD_JSON_MANDATORY },
{}
};
r = sd_json_dispatch(*m, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &d);
if (r < 0) {
_cleanup_free_ char *t = NULL;
int k = sd_json_variant_format(*m, /* flags= */ 0, &t);
if (k < 0)
return log_error_errno(k, "Failed to format JSON: %m");
log_warning_errno(r, "Cannot parse fact, skipping: %s", t);
continue;
}
r = table_add_many(
table,
TABLE_STRING, d.name,
TABLE_STRING, d.object,
TABLE_JSON, d.value,
TABLE_SET_WEIGHT, 50U);
if (r < 0)
return table_log_add_error(r);
}
*ret = TAKE_PTR(table);
return 0;
}
static int facts_output_describe(Context *context, Table **ret) {
int r;
assert(context);
_cleanup_(table_unrefp) Table *table = table_new("family", "description");
if (!table)
return log_oom();
table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
table_set_sort(table, (size_t) 0, (size_t) 1);
FOREACH_ARRAY(m, context->metrics, context->n_metrics) {
struct {
const char *name;
const char *description;
} d = {};
static const sd_json_dispatch_field dispatch_table[] = {
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, voffsetof(d, name), SD_JSON_MANDATORY },
{ "description", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, voffsetof(d, description), 0 },
{}
};
r = sd_json_dispatch(*m, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &d);
if (r < 0) {
_cleanup_free_ char *t = NULL;
int k = sd_json_variant_format(*m, /* flags= */ 0, &t);
if (k < 0)
return log_error_errno(k, "Failed to format JSON: %m");
log_warning_errno(r, "Cannot parse fact description, skipping: %s", t);
continue;
}
r = table_add_many(
table,
TABLE_STRING, d.name,
TABLE_STRING, d.description,
TABLE_SET_WEIGHT, 50U);
if (r < 0)
return table_log_add_error(r);
}
*ret = TAKE_PTR(table);
return 0;
}
static int metrics_output(Context *context) {
int r;
@@ -444,8 +550,12 @@ static int metrics_output(Context *context) {
return log_error_errno(r, "Failed to write JSON: %m");
}
if (context->n_metrics == 0 && arg_legend)
log_info("No metrics collected.");
if (context->n_metrics == 0 && arg_legend) {
if (IN_SET(context->action, ACTION_LIST_FACTS, ACTION_DESCRIBE_FACTS))
log_info("No facts collected.");
else
log_info("No metrics collected.");
}
return 0;
}
@@ -461,6 +571,14 @@ static int metrics_output(Context *context) {
r = metrics_output_describe(context, &table);
break;
case ACTION_LIST_FACTS:
r = facts_output_list(context, &table);
break;
case ACTION_DESCRIBE_FACTS:
r = facts_output_describe(context, &table);
break;
default:
assert_not_reached();
}
@@ -474,10 +592,12 @@ static int metrics_output(Context *context) {
}
if (arg_legend && !sd_json_format_enabled(arg_json_format_flags)) {
bool is_facts = IN_SET(context->action, ACTION_LIST_FACTS, ACTION_DESCRIBE_FACTS);
if (table_isempty(table))
printf("No metrics available.\n");
printf("No %s available.\n", is_facts ? "facts" : "metrics");
else
printf("\n%zu metrics listed.\n", table_get_rows(table) - 1);
printf("\n%zu %s listed.\n", table_get_rows(table) - 1, is_facts ? "facts" : "metrics");
}
return 0;
@@ -659,6 +779,92 @@ static int verb_metrics(int argc, char *argv[], uintptr_t data, void *userdata)
return 0;
}
static int verb_facts(int argc, char *argv[], uintptr_t _data, void *userdata) {
Action action;
int r;
assert(argc >= 1);
assert(argv);
/* Enable JSON-SEQ mode here, since we'll dump a large series of JSON objects */
arg_json_format_flags |= SD_JSON_FORMAT_SEQ;
if (streq_ptr(argv[0], "facts"))
action = ACTION_LIST_FACTS;
else {
assert(streq_ptr(argv[0], "describe-facts"));
action = ACTION_DESCRIBE_FACTS;
}
r = parse_metrics_matches(argv + 1);
if (r < 0)
return r;
_cleanup_(context_done) Context context = {
.action = action,
};
size_t n_skipped_sources = 0;
_cleanup_free_ DirectoryEntries *de = NULL;
_cleanup_free_ char *sources_path = NULL;
r = readdir_sources(&sources_path, &de);
if (r < 0)
return r;
if (r > 0) {
r = sd_event_default(&context.event);
if (r < 0)
return log_error_errno(r, "Failed to get event loop: %m");
r = sd_event_set_signal_exit(context.event, true);
if (r < 0)
return log_error_errno(r, "Failed to enable exit on SIGINT/SIGTERM: %m");
FOREACH_ARRAY(i, de->entries, de->n_entries) {
struct dirent *d = *i;
if (set_size(context.link_infos) >= METRICS_LINKS_MAX) {
n_skipped_sources++;
break;
}
_cleanup_free_ char *p = path_join(sources_path, d->d_name);
if (!p)
return log_oom();
(void) metrics_call(&context, d->d_name, p);
}
}
if (set_isempty(context.link_infos)) {
if (arg_legend)
log_info("No facts sources found.");
} else {
assert(context.event);
r = sd_event_loop(context.event);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
r = metrics_output(&context);
if (r < 0)
return r;
}
if (n_skipped_sources > 0)
return log_warning_errno(SYNTHETIC_ERRNO(EUCLEAN),
"Too many facts sources, only %u sources contacted, %zu sources skipped.",
set_size(context.link_infos), n_skipped_sources);
if (context.n_invalid_metrics > 0)
return log_warning_errno(SYNTHETIC_ERRNO(EUCLEAN),
"%zu facts are not valid.",
context.n_invalid_metrics);
if (context.n_skipped_metrics > 0)
return log_warning_errno(SYNTHETIC_ERRNO(EUCLEAN),
"Too many facts, only %zu facts collected, %zu facts skipped.",
context.n_metrics, context.n_skipped_metrics);
return 0;
}
static int verb_list_sources(int argc, char *argv[], uintptr_t _data, void *userdata) {
int r;
@@ -723,11 +929,14 @@ static int help(void) {
return log_oom();
printf("%1$s [OPTIONS...] COMMAND ...\n"
"\n%5$sAcquire metrics from local sources.%6$s\n"
"\n%5$sAcquire metrics and facts from local sources.%6$s\n"
"\n%3$sCommands:%4$s\n"
" metrics [MATCH...] Acquire list of metrics and their values\n"
" describe-metrics [MATCH...]\n"
" Describe available metrics\n"
" facts [MATCH...] Acquire list of facts and their values\n"
" describe-facts [MATCH...]\n"
" Describe available facts\n"
" list-sources Show list of known metrics sources\n"
"\n%3$sOptions:%4$s\n"
" -h --help Show this help\n"
@@ -831,6 +1040,8 @@ static int report_main(int argc, char *argv[]) {
{ "help", VERB_ANY, 1, 0, verb_help },
{ "metrics", VERB_ANY, VERB_ANY, 0, verb_metrics, ACTION_LIST },
{ "describe-metrics", VERB_ANY, VERB_ANY, 0, verb_metrics, ACTION_DESCRIBE },
{ "facts", VERB_ANY, VERB_ANY, 0, verb_facts, ACTION_LIST_FACTS },
{ "describe-facts", VERB_ANY, VERB_ANY, 0, verb_facts, ACTION_DESCRIBE_FACTS },
{ "list-sources", VERB_ANY, 1, 0, verb_list_sources },
{}
};
+150
View File
@@ -0,0 +1,150 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "facts.h"
#include "json-util.h"
#include "log.h"
#include "varlink-io.systemd.Facts.h"
#include "varlink-util.h"
int facts_add_to_varlink_server(
sd_varlink_server *server,
sd_varlink_method_t vl_method_list_cb,
sd_varlink_method_t vl_method_describe_cb) {
int r;
assert(server);
assert(vl_method_list_cb);
assert(vl_method_describe_cb);
r = sd_varlink_server_add_interface(server, &vl_interface_io_systemd_Facts);
if (r < 0)
return log_debug_errno(r, "Failed to add varlink facts interface to varlink server: %m");
r = sd_varlink_server_bind_method_many(
server,
"io.systemd.Facts.List", vl_method_list_cb,
"io.systemd.Facts.Describe", vl_method_describe_cb);
if (r < 0)
return log_debug_errno(r, "Failed to register varlink facts methods: %m");
return 0;
}
static int fact_family_build_json(const FactFamily *ff, sd_json_variant **ret) {
assert(ff);
return sd_json_buildo(
ret,
SD_JSON_BUILD_PAIR_STRING("name", ff->name),
SD_JSON_BUILD_PAIR_STRING("description", ff->description));
}
int facts_method_describe(
const FactFamily fact_family_table[],
sd_varlink *link,
sd_json_variant *parameters,
sd_varlink_method_flags_t flags,
void *userdata) {
int r;
assert(fact_family_table);
assert(link);
assert(parameters);
assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE));
r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL);
if (r != 0)
return r;
r = sd_varlink_set_sentinel(link, "io.systemd.Facts.NoSuchFact");
if (r < 0)
return r;
for (const FactFamily *ff = fact_family_table; ff && ff->name; ff++) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
r = fact_family_build_json(ff, &v);
if (r < 0)
return log_debug_errno(r, "Failed to describe fact family '%s': %m", ff->name);
r = sd_varlink_reply(link, v);
if (r < 0)
return log_debug_errno(r, "Failed to send varlink reply: %m");
}
return 0;
}
int facts_method_list(
const FactFamily fact_family_table[],
sd_varlink *link,
sd_json_variant *parameters,
sd_varlink_method_flags_t flags,
void *userdata) {
int r;
assert(fact_family_table);
assert(link);
assert(parameters);
assert(FLAGS_SET(flags, SD_VARLINK_METHOD_MORE));
r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL);
if (r != 0)
return r;
r = sd_varlink_set_sentinel(link, "io.systemd.Facts.NoSuchFact");
if (r < 0)
return r;
FactFamilyContext ctx = { .link = link };
for (const FactFamily *ff = fact_family_table; ff && ff->name; ff++) {
assert(ff->generate);
ctx.fact_family = ff;
r = ff->generate(&ctx, userdata);
if (r < 0)
return log_debug_errno(
r, "Failed to list facts for fact family '%s': %m", ff->name);
}
return 0;
}
static int fact_build_send(FactFamilyContext *context, const char *object, sd_json_variant *value) {
assert(context);
assert(value);
assert(context->link);
assert(context->fact_family);
return sd_varlink_replybo(context->link,
SD_JSON_BUILD_PAIR_STRING("name", context->fact_family->name),
JSON_BUILD_PAIR_STRING_NON_EMPTY("object", object),
SD_JSON_BUILD_PAIR("value", SD_JSON_BUILD_VARIANT(value)));
}
int fact_build_send_string(FactFamilyContext *context, const char *object, const char *value) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
int r;
assert(value);
r = sd_json_variant_new_string(&v, value);
if (r < 0)
return log_debug_errno(r, "Failed to allocate JSON string: %m");
return fact_build_send(context, object, v);
}
int fact_build_send_unsigned(FactFamilyContext *context, const char *object, uint64_t value) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
int r;
r = sd_json_variant_new_unsigned(&v, value);
if (r < 0)
return log_debug_errno(r, "Failed to allocate JSON unsigned: %m");
return fact_build_send(context, object, v);
}
+31
View File
@@ -0,0 +1,31 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "shared-forward.h"
typedef struct FactFamily FactFamily;
typedef struct FactFamilyContext {
const FactFamily *fact_family;
sd_varlink *link;
} FactFamilyContext;
typedef int (*fact_family_generate_func_t)(FactFamilyContext *ffc, void *userdata);
typedef struct FactFamily {
const char *name;
const char *description;
fact_family_generate_func_t generate;
} FactFamily;
/* Add io.systemd.Facts interface + methods to an existing varlink server */
int facts_add_to_varlink_server(
sd_varlink_server *server,
sd_varlink_method_t vl_method_list_cb,
sd_varlink_method_t vl_method_describe_cb);
int facts_method_describe(const FactFamily fact_family_table[], sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
int facts_method_list(const FactFamily fact_family_table[], sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
int fact_build_send_string(FactFamilyContext *context, const char *object, const char *value);
int fact_build_send_unsigned(FactFamilyContext *context, const char *object, uint64_t value);
+2
View File
@@ -77,6 +77,7 @@ shared_sources = files(
'exit-status.c',
'extension-util.c',
'factory-reset.c',
'facts.c',
'fdset.c',
'fido2-util.c',
'find-esp.c',
@@ -205,6 +206,7 @@ shared_sources = files(
'varlink-io.systemd.BootControl.c',
'varlink-io.systemd.Credentials.c',
'varlink-io.systemd.FactoryReset.c',
'varlink-io.systemd.Facts.c',
'varlink-io.systemd.Hostname.c',
'varlink-io.systemd.Import.c',
'varlink-io.systemd.InstanceMetadata.c',
+36
View File
@@ -0,0 +1,36 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-varlink-idl.h"
#include "varlink-io.systemd.Facts.h"
static SD_VARLINK_DEFINE_ERROR(NoSuchFact);
static SD_VARLINK_DEFINE_METHOD_FULL(
List,
SD_VARLINK_REQUIRES_MORE,
SD_VARLINK_FIELD_COMMENT("Fact family name, e.g. io.systemd.Manager.Hostname"),
SD_VARLINK_DEFINE_OUTPUT(name, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Fact object name"),
SD_VARLINK_DEFINE_OUTPUT(object, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Fact value"),
SD_VARLINK_DEFINE_OUTPUT(value, SD_VARLINK_ANY, 0));
static SD_VARLINK_DEFINE_METHOD_FULL(
Describe,
SD_VARLINK_REQUIRES_MORE,
SD_VARLINK_FIELD_COMMENT("Fact family name"),
SD_VARLINK_DEFINE_OUTPUT(name, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Fact family description"),
SD_VARLINK_DEFINE_OUTPUT(description, SD_VARLINK_STRING, 0));
SD_VARLINK_DEFINE_INTERFACE(
io_systemd_Facts,
"io.systemd.Facts",
SD_VARLINK_INTERFACE_COMMENT("Facts APIs"),
SD_VARLINK_SYMBOL_COMMENT("Method to get a list of facts and their values"),
&vl_method_List,
SD_VARLINK_SYMBOL_COMMENT("Method to get the fact families"),
&vl_method_Describe,
SD_VARLINK_SYMBOL_COMMENT("No such fact found"),
&vl_error_NoSuchFact);
+6
View File
@@ -0,0 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-varlink-idl.h"
extern const sd_varlink_interface vl_interface_io_systemd_Facts;
+20
View File
@@ -35,3 +35,23 @@ varlinkctl info /run/systemd/report/io.systemd.Network
varlinkctl list-methods /run/systemd/report/io.systemd.Network
varlinkctl --more call /run/systemd/report/io.systemd.Network io.systemd.Metrics.List {}
varlinkctl --more call /run/systemd/report/io.systemd.Network io.systemd.Metrics.Describe {}
# Test facts verbs
"$REPORT" facts
"$REPORT" facts -j
"$REPORT" facts --no-legend
"$REPORT" describe-facts
"$REPORT" describe-facts -j
"$REPORT" describe-facts --no-legend
# Test facts with match filters
"$REPORT" facts io
"$REPORT" facts io.systemd piff
"$REPORT" facts piff
"$REPORT" describe-facts io
"$REPORT" describe-facts io.systemd piff
"$REPORT" describe-facts piff
# Test facts via direct Varlink call on existing socket
varlinkctl --more call /run/systemd/report/io.systemd.Manager io.systemd.Facts.List {}
varlinkctl --more call /run/systemd/report/io.systemd.Manager io.systemd.Facts.Describe {}