Compare commits
6 Commits
fdbf54bd9d
...
1dc7dd847b
Author | SHA1 | Date |
---|---|---|
Ivan Kruglov | 1dc7dd847b | |
Ivan Kruglov | 76ad48f9a5 | |
Ivan Kruglov | 95adf8a563 | |
Ivan Kruglov | 4fb0dabd92 | |
Ivan Kruglov | c0e92dec76 | |
Ivan Kruglov | c3065654c8 |
|
@ -14,6 +14,7 @@
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "pidref.h"
|
#include "pidref.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
|
#include "signal-util.h"
|
||||||
#include "socket-util.h"
|
#include "socket-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "varlink-util.h"
|
#include "varlink-util.h"
|
||||||
|
@ -188,3 +189,127 @@ int vl_method_register(sd_varlink *link, sd_json_variant *parameters, sd_varlink
|
||||||
|
|
||||||
return sd_varlink_reply(link, NULL);
|
return sd_varlink_reply(link, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lookup_machine_by_name(sd_varlink *link, Manager *manager, const char *machine_name, Machine **ret_machine) {
|
||||||
|
assert(ret_machine);
|
||||||
|
|
||||||
|
if (!machine_name)
|
||||||
|
return sd_varlink_error_invalid_parameter_name(link, "name");
|
||||||
|
|
||||||
|
if (!hostname_is_valid(machine_name, /* flags= */ VALID_HOSTNAME_DOT_HOST))
|
||||||
|
return sd_varlink_error_invalid_parameter_name(link, "name");
|
||||||
|
|
||||||
|
Machine *machine = hashmap_get(manager->machines, machine_name);
|
||||||
|
if (!machine)
|
||||||
|
return sd_varlink_error(link, "io.systemd.Machine.NoSuchMachine", NULL);
|
||||||
|
|
||||||
|
*ret_machine = machine;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vl_method_unregister_internal(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||||
|
Machine *machine = ASSERT_PTR(userdata);
|
||||||
|
Manager *manager = machine->manager;
|
||||||
|
assert(manager);
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = varlink_verify_polkit_async(
|
||||||
|
link,
|
||||||
|
manager->bus,
|
||||||
|
"org.freedesktop.machine1.manage-machines",
|
||||||
|
(const char**) STRV_MAKE("name", machine->name,
|
||||||
|
"verb", "unregister"),
|
||||||
|
&manager->polkit_registry);
|
||||||
|
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = machine_finalize(machine);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return sd_varlink_reply(link, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vl_method_terminate_internal(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||||
|
Machine *machine = ASSERT_PTR(userdata);
|
||||||
|
Manager *manager = machine->manager;
|
||||||
|
assert(manager);
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = varlink_verify_polkit_async(
|
||||||
|
link,
|
||||||
|
manager->bus,
|
||||||
|
"org.freedesktop.machine1.manage-machines",
|
||||||
|
(const char**) STRV_MAKE("name", machine->name,
|
||||||
|
"verb", "terminate"),
|
||||||
|
&manager->polkit_registry);
|
||||||
|
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = machine_stop(machine);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return sd_varlink_reply(link, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vl_method_kill(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||||
|
Manager *manager = ASSERT_PTR(userdata);
|
||||||
|
|
||||||
|
const char *machine_name = NULL;
|
||||||
|
const char *swho = NULL;
|
||||||
|
KillWhom whom;
|
||||||
|
int32_t signo;
|
||||||
|
|
||||||
|
const sd_json_dispatch_field dispatch_table[] = {
|
||||||
|
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&machine_name), SD_JSON_MANDATORY },
|
||||||
|
{ "who", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&swho), 0 },
|
||||||
|
{ "signal", SD_JSON_VARIANT_INTEGER, sd_json_dispatch_int32, PTR_TO_SIZE(&signo), SD_JSON_MANDATORY },
|
||||||
|
VARLINK_DISPATCH_POLKIT_FIELD,
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
int r;
|
||||||
|
assert(parameters);
|
||||||
|
|
||||||
|
r = sd_varlink_dispatch(link, parameters, dispatch_table, 0);
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
Machine *machine = NULL;
|
||||||
|
r = lookup_machine_by_name(link, manager, machine_name, &machine);
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
assert(machine);
|
||||||
|
|
||||||
|
if (isempty(swho)) {
|
||||||
|
whom = KILL_ALL;
|
||||||
|
} else {
|
||||||
|
whom = kill_whom_from_string(swho);
|
||||||
|
if (whom < 0)
|
||||||
|
return sd_varlink_error_invalid_parameter_name(link, "who");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SIGNAL_VALID(signo))
|
||||||
|
return sd_varlink_error_invalid_parameter_name(link, "signal");
|
||||||
|
|
||||||
|
r = varlink_verify_polkit_async(
|
||||||
|
link,
|
||||||
|
manager->bus,
|
||||||
|
"org.freedesktop.machine1.manage-machines",
|
||||||
|
(const char**) STRV_MAKE("name", machine->name,
|
||||||
|
"verb", "kill"),
|
||||||
|
&manager->polkit_registry);
|
||||||
|
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = machine_kill(machine, whom, signo);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return sd_varlink_reply(link, NULL);
|
||||||
|
}
|
||||||
|
|
|
@ -2,5 +2,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "sd-varlink.h"
|
#include "sd-varlink.h"
|
||||||
|
#include "machine.h"
|
||||||
|
|
||||||
|
int lookup_machine_by_name(sd_varlink *link, Manager *manager, const char *machine_name, Machine **ret_machine);
|
||||||
|
|
||||||
|
typedef int (*vl_method_handler_t) (sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) ;
|
||||||
int vl_method_register(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
|
int vl_method_register(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
|
||||||
|
int vl_method_unregister_internal(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
|
||||||
|
int vl_method_terminate_internal(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
|
||||||
|
int vl_method_kill(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
#include "sd-varlink.h"
|
#include "sd-varlink.h"
|
||||||
|
#include "varlink-internal.h"
|
||||||
|
|
||||||
|
#include "bus-polkit.h"
|
||||||
#include "format-util.h"
|
#include "format-util.h"
|
||||||
#include "hostname-util.h"
|
#include "hostname-util.h"
|
||||||
#include "json-util.h"
|
#include "json-util.h"
|
||||||
#include "machine-varlink.h"
|
#include "machine-varlink.h"
|
||||||
#include "machined-varlink.h"
|
#include "machined-varlink.h"
|
||||||
#include "mkdir.h"
|
#include "mkdir.h"
|
||||||
|
#include "process-util.h"
|
||||||
|
#include "cgroup-util.h"
|
||||||
#include "socket-util.h"
|
#include "socket-util.h"
|
||||||
#include "user-util.h"
|
#include "user-util.h"
|
||||||
#include "varlink-io.systemd.Machine.h"
|
#include "varlink-io.systemd.Machine.h"
|
||||||
|
@ -433,13 +437,12 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (mn) {
|
if (mn) {
|
||||||
if (!hostname_is_valid(mn, /* flags= */ VALID_HOSTNAME_DOT_HOST))
|
Machine *machine = NULL;
|
||||||
return sd_varlink_error_invalid_parameter_name(link, "name");
|
r = lookup_machine_by_name(link, m, mn, &machine);
|
||||||
|
if (r != 0)
|
||||||
Machine *machine = hashmap_get(m->machines, mn);
|
return r;
|
||||||
if (!machine)
|
|
||||||
return sd_varlink_error(link, "io.systemd.Machine.NoSuchMachine", NULL);
|
|
||||||
|
|
||||||
|
assert(machine);
|
||||||
return list_machine_one(link, machine, /* more= */ false);
|
return list_machine_one(link, machine, /* more= */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,6 +466,110 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
||||||
return sd_varlink_error(link, "io.systemd.Machine.NoSuchMachine", NULL);
|
return sd_varlink_error(link, "io.systemd.Machine.NoSuchMachine", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vl_method_get(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t 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), SD_JSON_MANDATORY },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(parameters);
|
||||||
|
|
||||||
|
r = sd_varlink_dispatch(link, parameters, dispatch_table, 0);
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
Machine *machine = NULL;
|
||||||
|
r = lookup_machine_by_name(link, m, mn, &machine);
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
assert(machine);
|
||||||
|
return list_machine_one(link, machine, /* more= */ false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vl_method_get_by_pid(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||||
|
Manager *m = ASSERT_PTR(userdata);
|
||||||
|
|
||||||
|
int r;
|
||||||
|
pid_t pid = 0;
|
||||||
|
assert_cc(sizeof(pid_t) == sizeof(uint32_t));
|
||||||
|
assert(parameters);
|
||||||
|
|
||||||
|
const sd_json_dispatch_field dispatch_table[] = {
|
||||||
|
{ "pid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint32, PTR_TO_SIZE(&pid), SD_JSON_MANDATORY },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
r = sd_varlink_dispatch(link, parameters, dispatch_table, 0);
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (pid == 0) {
|
||||||
|
int pidfd = sd_varlink_get_peer_pidfd(link);
|
||||||
|
if (pidfd < 0)
|
||||||
|
return pidfd;
|
||||||
|
|
||||||
|
r = pidfd_get_pid(pidfd, &pid);
|
||||||
|
if (r < 0)
|
||||||
|
return varlink_log_errno(link, r, "Failed to acquire pid of peer: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid <= 0)
|
||||||
|
return sd_varlink_error_invalid_parameter_name(link, "pid");
|
||||||
|
|
||||||
|
Machine *machine = hashmap_get(m->machine_leaders, PID_TO_PTR(pid));
|
||||||
|
if (!machine) {
|
||||||
|
_cleanup_free_ char *unit = NULL;
|
||||||
|
r = cg_pid_get_unit(pid, &unit);
|
||||||
|
if (r >= 0)
|
||||||
|
machine = hashmap_get(m->machine_units, unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!machine)
|
||||||
|
return sd_varlink_error(link, "io.systemd.Machine.NoSuchMachine", NULL);
|
||||||
|
|
||||||
|
return list_machine_one(link, machine, /* more= */ false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lookup_machine_and_call_method(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata, vl_method_handler_t method) {
|
||||||
|
Manager *manager = ASSERT_PTR(userdata);
|
||||||
|
|
||||||
|
const char *machine_name = NULL;
|
||||||
|
const sd_json_dispatch_field dispatch_table[] = {
|
||||||
|
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&machine_name), SD_JSON_MANDATORY },
|
||||||
|
VARLINK_DISPATCH_POLKIT_FIELD,
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
int r;
|
||||||
|
assert(parameters);
|
||||||
|
|
||||||
|
r = sd_varlink_dispatch(link, parameters, dispatch_table, 0);
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
Machine *machine = NULL;
|
||||||
|
r = lookup_machine_by_name(link, manager, machine_name, &machine);
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
assert(machine);
|
||||||
|
return method(link, parameters, flags, machine);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vl_method_unregister(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||||
|
return lookup_machine_and_call_method(link, parameters, flags, userdata, vl_method_unregister_internal);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vl_method_terminate(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||||
|
return lookup_machine_and_call_method(link, parameters, flags, userdata, vl_method_terminate_internal);
|
||||||
|
}
|
||||||
|
|
||||||
static int manager_varlink_init_userdb(Manager *m) {
|
static int manager_varlink_init_userdb(Manager *m) {
|
||||||
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *s = NULL;
|
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *s = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
@ -526,7 +633,12 @@ static int manager_varlink_init_machine(Manager *m) {
|
||||||
r = sd_varlink_server_bind_method_many(
|
r = sd_varlink_server_bind_method_many(
|
||||||
s,
|
s,
|
||||||
"io.systemd.Machine.Register", vl_method_register,
|
"io.systemd.Machine.Register", vl_method_register,
|
||||||
"io.systemd.Machine.List", vl_method_list);
|
"io.systemd.Machine.Unregister", vl_method_unregister,
|
||||||
|
"io.systemd.Machine.Terminate", vl_method_terminate,
|
||||||
|
"io.systemd.Machine.Kill", vl_method_kill,
|
||||||
|
"io.systemd.Machine.List", vl_method_list,
|
||||||
|
"io.systemd.Machine.Get", vl_method_get,
|
||||||
|
"io.systemd.Machine.GetByPID", vl_method_get_by_pid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to register varlink methods: %m");
|
return log_error_errno(r, "Failed to register varlink methods: %m");
|
||||||
|
|
||||||
|
|
|
@ -28,30 +28,64 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
|
||||||
SD_VARLINK_FIELD_COMMENT("Timestamp in µs in the CLOCK_MONOTONIC clock"),
|
SD_VARLINK_FIELD_COMMENT("Timestamp in µs in the CLOCK_MONOTONIC clock"),
|
||||||
SD_VARLINK_DEFINE_FIELD(monotonic, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
|
SD_VARLINK_DEFINE_FIELD(monotonic, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
|
||||||
|
|
||||||
|
#define SD_VARLINK_MACHINE_OUTPUT_FIELDS \
|
||||||
|
SD_VARLINK_FIELD_COMMENT("Name of the machine"), \
|
||||||
|
SD_VARLINK_DEFINE_OUTPUT(name, SD_VARLINK_STRING, 0), \
|
||||||
|
SD_VARLINK_FIELD_COMMENT("128bit ID identifying this machine, formatted in hexadecimal"), \
|
||||||
|
SD_VARLINK_DEFINE_OUTPUT(id, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), \
|
||||||
|
SD_VARLINK_FIELD_COMMENT("Name of the software that registered this machine"), \
|
||||||
|
SD_VARLINK_DEFINE_OUTPUT(service, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), \
|
||||||
|
SD_VARLINK_FIELD_COMMENT("The class of this machine"), \
|
||||||
|
SD_VARLINK_DEFINE_OUTPUT(class, SD_VARLINK_STRING, 0), \
|
||||||
|
SD_VARLINK_FIELD_COMMENT("Leader process PID of this machine"), \
|
||||||
|
SD_VARLINK_DEFINE_OUTPUT(leader, SD_VARLINK_INT, SD_VARLINK_NULLABLE), \
|
||||||
|
SD_VARLINK_FIELD_COMMENT("Root directory of this machine, if known, relative to host file system"), \
|
||||||
|
SD_VARLINK_DEFINE_OUTPUT(rootDirectory, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), \
|
||||||
|
SD_VARLINK_FIELD_COMMENT("The service manager unit this machine resides in"), \
|
||||||
|
SD_VARLINK_DEFINE_OUTPUT(unit, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), \
|
||||||
|
SD_VARLINK_FIELD_COMMENT("Timestamp when the machine was activated"), \
|
||||||
|
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(timestamp, Timestamp, SD_VARLINK_NULLABLE), \
|
||||||
|
SD_VARLINK_FIELD_COMMENT("AF_VSOCK CID of the machine if known and applicable"), \
|
||||||
|
SD_VARLINK_DEFINE_OUTPUT(vSockCid, SD_VARLINK_INT, SD_VARLINK_NULLABLE), \
|
||||||
|
SD_VARLINK_FIELD_COMMENT("SSH address to connect to"), \
|
||||||
|
SD_VARLINK_DEFINE_OUTPUT(sshAddress, SD_VARLINK_STRING, SD_VARLINK_NULLABLE)
|
||||||
|
|
||||||
|
static SD_VARLINK_DEFINE_METHOD(
|
||||||
|
Unregister,
|
||||||
|
SD_VARLINK_FIELD_COMMENT("The name of a machine to unregister."),
|
||||||
|
SD_VARLINK_DEFINE_INPUT(name, SD_VARLINK_STRING, 0));
|
||||||
|
|
||||||
|
static SD_VARLINK_DEFINE_METHOD(
|
||||||
|
Terminate,
|
||||||
|
SD_VARLINK_FIELD_COMMENT("The name of a machine to terminate."),
|
||||||
|
SD_VARLINK_DEFINE_INPUT(name, SD_VARLINK_STRING, 0));
|
||||||
|
|
||||||
|
static SD_VARLINK_DEFINE_METHOD(
|
||||||
|
Kill,
|
||||||
|
SD_VARLINK_FIELD_COMMENT("The name of a machine to sends signal to"),
|
||||||
|
SD_VARLINK_DEFINE_INPUT(name, SD_VARLINK_STRING, 0),
|
||||||
|
SD_VARLINK_FIELD_COMMENT("Who should receive the signal"),
|
||||||
|
SD_VARLINK_DEFINE_INPUT(who, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||||
|
SD_VARLINK_FIELD_COMMENT("Signal to send"),
|
||||||
|
SD_VARLINK_DEFINE_INPUT(signal, SD_VARLINK_INT, 0));
|
||||||
|
|
||||||
static SD_VARLINK_DEFINE_METHOD(
|
static SD_VARLINK_DEFINE_METHOD(
|
||||||
List,
|
List,
|
||||||
SD_VARLINK_FIELD_COMMENT("If non-null the name of a running machine to report details on. If null/unspecified enumerates all running machines."),
|
SD_VARLINK_FIELD_COMMENT("If non-null the name of a running machine to report details on. If null/unspecified enumerates all running machines."),
|
||||||
SD_VARLINK_DEFINE_INPUT(name, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
SD_VARLINK_DEFINE_INPUT(name, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||||
SD_VARLINK_FIELD_COMMENT("Name of the machine"),
|
SD_VARLINK_MACHINE_OUTPUT_FIELDS);
|
||||||
SD_VARLINK_DEFINE_OUTPUT(name, SD_VARLINK_STRING, 0),
|
|
||||||
SD_VARLINK_FIELD_COMMENT("128bit ID identifying this machine, formatted in hexadecimal"),
|
static SD_VARLINK_DEFINE_METHOD(
|
||||||
SD_VARLINK_DEFINE_OUTPUT(id, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
Get,
|
||||||
SD_VARLINK_FIELD_COMMENT("Name of the software that registered this machine"),
|
SD_VARLINK_FIELD_COMMENT("The name of a running machine to report details on."),
|
||||||
SD_VARLINK_DEFINE_OUTPUT(service, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
SD_VARLINK_DEFINE_INPUT(name, SD_VARLINK_STRING, 0),
|
||||||
SD_VARLINK_FIELD_COMMENT("The class of this machine"),
|
SD_VARLINK_MACHINE_OUTPUT_FIELDS);
|
||||||
SD_VARLINK_DEFINE_OUTPUT(class, SD_VARLINK_STRING, 0),
|
|
||||||
SD_VARLINK_FIELD_COMMENT("Leader process PID of this machine"),
|
static SD_VARLINK_DEFINE_METHOD(
|
||||||
SD_VARLINK_DEFINE_OUTPUT(leader, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
GetByPID,
|
||||||
SD_VARLINK_FIELD_COMMENT("Root directory of this machine, if known, relative to host file system"),
|
SD_VARLINK_FIELD_COMMENT("The PID of a running machine to report details on."),
|
||||||
SD_VARLINK_DEFINE_OUTPUT(rootDirectory, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
SD_VARLINK_DEFINE_INPUT(pid, SD_VARLINK_INT, 0),
|
||||||
SD_VARLINK_FIELD_COMMENT("The service manager unit this machine resides in"),
|
SD_VARLINK_MACHINE_OUTPUT_FIELDS);
|
||||||
SD_VARLINK_DEFINE_OUTPUT(unit, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
|
||||||
SD_VARLINK_FIELD_COMMENT("Timestamp when the machine was activated"),
|
|
||||||
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(timestamp, Timestamp, SD_VARLINK_NULLABLE),
|
|
||||||
SD_VARLINK_FIELD_COMMENT("AF_VSOCK CID of the machine if known and applicable"),
|
|
||||||
SD_VARLINK_DEFINE_OUTPUT(vSockCid, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
|
||||||
SD_VARLINK_FIELD_COMMENT("SSH address to connect to"),
|
|
||||||
SD_VARLINK_DEFINE_OUTPUT(sshAddress, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
|
|
||||||
|
|
||||||
static SD_VARLINK_DEFINE_ERROR(NoSuchMachine);
|
static SD_VARLINK_DEFINE_ERROR(NoSuchMachine);
|
||||||
static SD_VARLINK_DEFINE_ERROR(MachineExists);
|
static SD_VARLINK_DEFINE_ERROR(MachineExists);
|
||||||
|
@ -62,8 +96,17 @@ SD_VARLINK_DEFINE_INTERFACE(
|
||||||
SD_VARLINK_SYMBOL_COMMENT("A timestamp object consisting of both CLOCK_REALTIME and CLOCK_MONOTONIC timestamps"),
|
SD_VARLINK_SYMBOL_COMMENT("A timestamp object consisting of both CLOCK_REALTIME and CLOCK_MONOTONIC timestamps"),
|
||||||
&vl_type_Timestamp,
|
&vl_type_Timestamp,
|
||||||
&vl_method_Register,
|
&vl_method_Register,
|
||||||
|
&vl_method_Unregister,
|
||||||
|
SD_VARLINK_SYMBOL_COMMENT("Terminate virtual machine, killing its processes"),
|
||||||
|
&vl_method_Terminate,
|
||||||
|
SD_VARLINK_SYMBOL_COMMENT("Send a UNIX signal to the machine's processes"),
|
||||||
|
&vl_method_Kill,
|
||||||
SD_VARLINK_SYMBOL_COMMENT("List running machines"),
|
SD_VARLINK_SYMBOL_COMMENT("List running machines"),
|
||||||
&vl_method_List,
|
&vl_method_List,
|
||||||
|
SD_VARLINK_SYMBOL_COMMENT("Get running machine"),
|
||||||
|
&vl_method_Get,
|
||||||
|
SD_VARLINK_SYMBOL_COMMENT("Get running machine by PID"),
|
||||||
|
&vl_method_GetByPID,
|
||||||
SD_VARLINK_SYMBOL_COMMENT("No matching machine currently running"),
|
SD_VARLINK_SYMBOL_COMMENT("No matching machine currently running"),
|
||||||
&vl_error_NoSuchMachine,
|
&vl_error_NoSuchMachine,
|
||||||
&vl_error_MachineExists);
|
&vl_error_MachineExists);
|
||||||
|
|
|
@ -47,12 +47,21 @@ trap 'kill $PID' EXIT
|
||||||
# We need to wait for the sleep process asynchronously in order to allow
|
# We need to wait for the sleep process asynchronously in order to allow
|
||||||
# bash to process signals
|
# bash to process signals
|
||||||
sleep infinity &
|
sleep infinity &
|
||||||
|
|
||||||
|
# notify that the process is ready
|
||||||
|
touch /ready
|
||||||
|
|
||||||
PID=$!
|
PID=$!
|
||||||
while :; do
|
while :; do
|
||||||
wait || :
|
wait || :
|
||||||
done
|
done
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
rm -f /var/lib/machines/long-running/ready
|
||||||
machinectl start long-running
|
machinectl start long-running
|
||||||
|
# !!!! DO NOT REMOVE THIS TEST
|
||||||
|
# The test makes sure that the long-running's init script has enough time to start and registered signal traps
|
||||||
|
timeout 10 bash -c "until test -e /var/lib/machines/long-running/ready; do sleep .5; done"
|
||||||
|
|
||||||
machinectl
|
machinectl
|
||||||
machinectl --no-pager --help
|
machinectl --no-pager --help
|
||||||
|
@ -222,6 +231,3 @@ done
|
||||||
(! machinectl read-only container1 "")
|
(! machinectl read-only container1 "")
|
||||||
(! machinectl read-only container1 foo)
|
(! machinectl read-only container1 foo)
|
||||||
(! machinectl read-only container1 -- -1)
|
(! machinectl read-only container1 -- -1)
|
||||||
|
|
||||||
varlinkctl --more call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{}'
|
|
||||||
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{"name":".host"}'
|
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
|
||||||
|
set -eux
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
# shellcheck source=test/units/util.sh
|
||||||
|
. "$(dirname "$0")"/util.sh
|
||||||
|
|
||||||
|
export PAGER=
|
||||||
|
|
||||||
|
at_exit() {
|
||||||
|
machinectl status long-running >/dev/null && machinectl kill --signal=KILL long-running
|
||||||
|
mountpoint -q /var/lib/machines && timeout 10 sh -c "until umount /var/lib/machines; do sleep .5; done"
|
||||||
|
}
|
||||||
|
|
||||||
|
trap at_exit EXIT
|
||||||
|
|
||||||
|
systemctl service-log-level systemd-machined debug
|
||||||
|
systemctl service-log-level systemd-importd debug
|
||||||
|
|
||||||
|
# Mount temporary directory over /var/lib/machines to not pollute the image
|
||||||
|
mkdir -p /var/lib/machines
|
||||||
|
mount --bind "$(mktemp --tmpdir=/var/tmp -d)" /var/lib/machines
|
||||||
|
|
||||||
|
# Create one "long running" container with some basic signal handling
|
||||||
|
create_dummy_container /var/lib/machines/long-running
|
||||||
|
cat >/var/lib/machines/long-running/sbin/init <<\EOF
|
||||||
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
PID=0
|
||||||
|
|
||||||
|
trap "touch /trap" TRAP
|
||||||
|
trap 'kill $PID' EXIT
|
||||||
|
|
||||||
|
# We need to wait for the sleep process asynchronously in order to allow
|
||||||
|
# bash to process signals
|
||||||
|
sleep infinity &
|
||||||
|
|
||||||
|
# notify that the process is ready
|
||||||
|
touch /ready
|
||||||
|
|
||||||
|
PID=$!
|
||||||
|
while :; do
|
||||||
|
wait || :
|
||||||
|
done
|
||||||
|
EOF
|
||||||
|
|
||||||
|
machine_start() {
|
||||||
|
machinectl status long-running >/dev/null && return 0 || true
|
||||||
|
|
||||||
|
rm -f /var/lib/machines/long-running/ready
|
||||||
|
# sometime `machinectl start` returns 1 and then do a success
|
||||||
|
machinectl start long-running || machinectl start long-running
|
||||||
|
# !!!! DO NOT REMOVE THIS TEST
|
||||||
|
# The test makes sure that the long-running's init script has enough time to start and registered signal traps
|
||||||
|
timeout 30 bash -c "until test -e /var/lib/machines/long-running/ready; do sleep .5; done"
|
||||||
|
}
|
||||||
|
|
||||||
|
machine_start
|
||||||
|
|
||||||
|
# test io.systemd.Machine.List
|
||||||
|
varlinkctl --more call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{}' | grep 'long-running'
|
||||||
|
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.List '{"name":"long-running"}'
|
||||||
|
|
||||||
|
# test io.systemd.Machine.Get
|
||||||
|
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Get '{"name":"long-running"}'
|
||||||
|
|
||||||
|
# test io.systemd.Machine.GetByPID
|
||||||
|
pid=$(varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Get '{"name":"long-running"}' | jq .leader)
|
||||||
|
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Get '{"name":"long-running"}' > /tmp/expected
|
||||||
|
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.GetByPID '{"pid":'$pid'}' > /tmp/got
|
||||||
|
diff -u /tmp/expected /tmp/got
|
||||||
|
|
||||||
|
# test io.systemd.Machine.Kill
|
||||||
|
# sending TRAP signal
|
||||||
|
rm -f /var/lib/machines/long-running/trap
|
||||||
|
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Kill '{"name":"long-running", "who": "leader", "signal": 5}'
|
||||||
|
timeout 30 bash -c "until test -e /var/lib/machines/long-running/trap; do sleep .5; done"
|
||||||
|
|
||||||
|
# sending KILL signal
|
||||||
|
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Kill '{"name":"long-running", "signal": 9}'
|
||||||
|
timeout 30 bash -c "while varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Get '{\"name\":\"long-running\"}'; do sleep 0.5; done"
|
||||||
|
|
||||||
|
# test io.systemd.Machine.Terminate
|
||||||
|
machine_start
|
||||||
|
varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Terminate '{"name":"long-running"}'
|
||||||
|
timeout 120 bash -c "while varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Get '{\"name\":\"long-running\"}'; do sleep 0.5; done"
|
Loading…
Reference in New Issue