Merge pull request #32709 from bluca/machined_ssh

machined: add GetMachineSSHInfo method and varlink interface to register machines
This commit is contained in:
Luca Boccassi 2024-05-08 14:37:55 +02:00 committed by GitHub
commit 867e2987a2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 432 additions and 34 deletions

View file

@ -89,6 +89,9 @@ node /org/freedesktop/machine1 {
in i signal);
GetMachineAddresses(in s name,
out a(iay) addresses);
GetMachineSSHInfo(in s name,
out s ssh_address,
out s ssh_private_key_path);
GetMachineOSRelease(in s name,
out a{ss} fields);
@org.freedesktop.systemd1.Privileged("true")
@ -230,6 +233,8 @@ node /org/freedesktop/machine1 {
<variablelist class="dbus-method" generated="True" extra-ref="GetMachineAddresses()"/>
<variablelist class="dbus-method" generated="True" extra-ref="GetMachineSSHInfo()"/>
<variablelist class="dbus-method" generated="True" extra-ref="GetMachineOSRelease()"/>
<variablelist class="dbus-method" generated="True" extra-ref="OpenMachinePTY()"/>
@ -378,6 +383,10 @@ node /org/freedesktop/machine1 {
<constant>AF_INET6</constant>) and a byte array containing the addresses. This is only supported for
containers that make use of network namespacing.</para>
<para><function>GetMachineSSHInfo()</function> retrieves the SSH information of a machine. This method
returns two strings, the SSH address which can be used to tell SSH where to connect, and the path
to the SSH private key required for the connection to succeed.</para>
<para><function>GetMachineOSRelease()</function> retrieves the OS release information of a
container. This method returns an array of key value pairs read from the
<citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> file in
@ -459,6 +468,8 @@ node /org/freedesktop/machine1/machine/rawhide {
Kill(in s who,
in i signal);
GetAddresses(out a(iay) addresses);
GetSSHInfo(out s ssh_address,
out s ssh_private_key_path);
GetOSRelease(out a{ss} fields);
GetUIDShift(out u shift);
OpenPTY(out h pty,
@ -507,6 +518,12 @@ node /org/freedesktop/machine1/machine/rawhide {
readonly s RootDirectory = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly ai NetworkInterfaces = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly u VSockCID = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s SSHAddress = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s SSHPrivateKeyPath = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s State = '...';
};
@ -548,6 +565,8 @@ node /org/freedesktop/machine1/machine/rawhide {
<variablelist class="dbus-method" generated="True" extra-ref="GetAddresses()"/>
<variablelist class="dbus-method" generated="True" extra-ref="GetSSHInfo()"/>
<variablelist class="dbus-method" generated="True" extra-ref="GetOSRelease()"/>
<variablelist class="dbus-method" generated="True" extra-ref="GetUIDShift()"/>
@ -590,6 +609,12 @@ node /org/freedesktop/machine1/machine/rawhide {
<variablelist class="dbus-property" generated="True" extra-ref="NetworkInterfaces"/>
<variablelist class="dbus-property" generated="True" extra-ref="VSockCID"/>
<variablelist class="dbus-property" generated="True" extra-ref="SSHAddress"/>
<variablelist class="dbus-property" generated="True" extra-ref="SSHPrivateKeyPath"/>
<variablelist class="dbus-property" generated="True" extra-ref="State"/>
<!--End of Autogenerated section-->
@ -601,9 +626,9 @@ node /org/freedesktop/machine1/machine/rawhide {
take the same arguments as <function>TerminateMachine()</function> and
<function>KillMachine()</function> on the Manager interface, respectively.</para>
<para><function>GetAddresses()</function> and <function>GetOSRelease()</function> get the IP address and OS
release information from the machine. These methods take the same arguments as
<function>GetMachineAddresses()</function> and <function>GetMachineOSRelease()</function> of the
<para><function>GetAddresses()</function>, <function>GetSSHInfo()</function> and <function>GetOSRelease()</function> get the IP address,
SSH connection and OS release information from the machine. These methods take the same arguments as
<function>GetMachineAddresses()</function>, <function>GetMachineSSHInfo()</function> and <function>GetMachineOSRelease()</function> of the
Manager interface, respectively.</para>
</refsect2>
@ -636,6 +661,15 @@ node /org/freedesktop/machine1/machine/rawhide {
towards the container, the VM or the host. For details about this information see the description of
<function>CreateMachineWithNetwork()</function> above.</para>
<para><varname>VSockCID</varname> is the VSOCK CID of the VM if it is known, or
<constant>VMADDR_CID_ANY</constant> otherwise.</para>
<para><varname>SSHAddress</varname> is the address of the VM in a format <command>ssh</command> can understand
if it is known or the empty string.</para>
<para><varname>SSHPrivateKeyPath</varname> is the path to the SSH private key of the VM if it is known
or the empty string.</para>
<para><varname>State</varname> is the state of the machine and is one of <literal>opening</literal>,
<literal>running</literal>, or <literal>closing</literal>. Note that the state machine is not considered
part of the API and states might be removed or added without this being considered API breakage.
@ -675,11 +709,14 @@ $ gdbus introspect --system \
<title>The Manager Object</title>
<para><function>CopyFromMachineWithFlags()</function> and
<function>CopyToMachineWithFlags()</function> were added in version 252.</para>
<para><function>GetMachineSSHInfo()</function> was added in version 256.</para>
</refsect2>
<refsect2>
<title>Machine Objects</title>
<para><function>CopyFromWithFlags()</function> and
<function>CopyToWithFlags()</function> were added in version 252.</para>
<para><function>GetSSHInfo()</function>, <varname>VSockCID</varname>, <varname>SSHAddress</varname>
and <varname>SSHPrivateKeyPath</varname> were added in version 256.</para>
</refsect2>
</refsect1>
</refentry>

View file

@ -100,10 +100,12 @@
<para>The daemon provides both a C library interface
(which is shared with <citerefentry><refentrytitle>systemd-logind.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>)
as well as a D-Bus interface.
as well as a D-Bus interface and a Varlink interface.
The library interface may be used to introspect and watch the state of virtual machines/containers.
The bus interface provides the same but in addition may also be used to register or terminate
machines.
machines. The Varlink interface may be used to register machines with optional extensions, e.g. with an
SSH key / address; it can be queried with
<command>varlinkctl introspect /run/systemd/machine/io.systemd.Machine io.systemd.Machine</command>.
For more information please consult
<citerefentry><refentrytitle>sd-login</refentrytitle><manvolnum>3</manvolnum></citerefentry>
and

View file

@ -347,6 +347,27 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd
return sd_bus_send(NULL, reply, NULL);
}
int bus_machine_method_get_ssh_info(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
Machine *m = ASSERT_PTR(userdata);
int r;
assert(message);
r = sd_bus_message_new_method_return(message, &reply);
if (r < 0)
return r;
if (!m->ssh_address || !m->ssh_private_key_path)
return -ENOENT;
r = sd_bus_message_append(reply, "ss", m->ssh_address, m->ssh_private_key_path);
if (r < 0)
return r;
return sd_bus_send(NULL, reply, NULL);
}
#define EXIT_NOT_FOUND 2
int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@ -1261,6 +1282,9 @@ static const sd_bus_vtable machine_vtable[] = {
SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("VSockCID", "u", NULL, offsetof(Machine, vsock_cid), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SSHAddress", "s", NULL, offsetof(Machine, ssh_address), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SSHPrivateKeyPath", "s", NULL, offsetof(Machine, ssh_private_key_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
SD_BUS_METHOD("Terminate",
@ -1278,6 +1302,11 @@ static const sd_bus_vtable machine_vtable[] = {
SD_BUS_RESULT("a(iay)", addresses),
bus_machine_method_get_addresses,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("GetSSHInfo",
SD_BUS_NO_ARGS,
SD_BUS_RESULT("s", ssh_address, "s", ssh_private_key_path),
bus_machine_method_get_ssh_info,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("GetOSRelease",
SD_BUS_NO_ARGS,
SD_BUS_RESULT("a{ss}", fields),

View file

@ -19,6 +19,7 @@ int bus_machine_method_unregister(sd_bus_message *message, void *userdata, sd_bu
int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_machine_method_get_ssh_info(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error);

View file

@ -0,0 +1,171 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <limits.h>
#include "sd-id128.h"
#include "hostname-util.h"
#include "json.h"
#include "machine-varlink.h"
#include "machine.h"
#include "path-util.h"
#include "pidref.h"
#include "process-util.h"
#include "socket-util.h"
#include "string-util.h"
#include "varlink.h"
static JSON_DISPATCH_ENUM_DEFINE(dispatch_machine_class, MachineClass, machine_class_from_string);
static int machine_name(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
char **m = ASSERT_PTR(userdata);
const char *hostname;
int r;
assert(variant);
if (!json_variant_is_string(variant))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
hostname = json_variant_string(variant);
if (!hostname_is_valid(hostname, /* flags= */ 0))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Invalid machine name");
r = free_and_strdup(m, hostname);
if (r < 0)
return json_log_oom(variant, flags);
return 0;
}
static int machine_leader(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
PidRef *leader = ASSERT_PTR(userdata);
_cleanup_(pidref_done) PidRef temp = PIDREF_NULL;
uint64_t k;
int r;
if (!json_variant_is_unsigned(variant))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an integer.", strna(name));
k = json_variant_unsigned(variant);
if (k > PID_T_MAX || !pid_is_valid(k))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid PID.", strna(name));
if (k == 1)
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid leader PID.", strna(name));
r = pidref_set_pid(&temp, k);
if (r < 0)
return json_log(variant, flags, r, "Failed to pin process " PID_FMT ": %m", leader->pid);
pidref_done(leader);
*leader = TAKE_PIDREF(temp);
return 0;
}
static int machine_ifindices(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
Machine *m = ASSERT_PTR(userdata);
_cleanup_free_ int *netif = NULL;
size_t n_netif, k = 0;
assert(variant);
if (!json_variant_is_array(variant))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name));
n_netif = json_variant_elements(variant);
netif = new(int, n_netif);
if (!netif)
return json_log_oom(variant, flags);
JsonVariant *i;
JSON_VARIANT_ARRAY_FOREACH(i, variant) {
uint64_t b;
if (!json_variant_is_unsigned(i))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Element %zu of JSON field '%s' is not an unsigned integer.", k, strna(name));
b = json_variant_unsigned(i);
if (b > INT_MAX || b <= 0)
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Invalid network interface index %"PRIu64, b);
netif[k++] = (int) b;
}
assert(k == n_netif);
free_and_replace(m->netif, netif);
m->n_netif = n_netif;
return 0;
}
static int machine_cid(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
unsigned cid, *c = ASSERT_PTR(userdata);
assert(variant);
if (!json_variant_is_unsigned(variant))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
cid = json_variant_unsigned(variant);
if (!VSOCK_CID_IS_REGULAR(cid))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a regular VSOCK CID.", strna(name));
*c = cid;
return 0;
}
int vl_method_register(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
Manager *manager = ASSERT_PTR(userdata);
_cleanup_(machine_freep) Machine *machine = NULL;
int r;
static const JsonDispatch dispatch_table[] = {
{ "name", JSON_VARIANT_STRING, machine_name, offsetof(Machine, name), JSON_MANDATORY },
{ "id", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(Machine, id), 0 },
{ "service", JSON_VARIANT_STRING, json_dispatch_string, offsetof(Machine, service), 0 },
{ "class", JSON_VARIANT_STRING, dispatch_machine_class, offsetof(Machine, class), JSON_MANDATORY },
{ "leader", JSON_VARIANT_UNSIGNED, machine_leader, offsetof(Machine, leader), 0 },
{ "rootDirectory", JSON_VARIANT_STRING, json_dispatch_absolute_path, offsetof(Machine, root_directory), 0 },
{ "ifIndices", JSON_VARIANT_ARRAY, machine_ifindices, 0, 0 },
{ "vsockCid", JSON_VARIANT_UNSIGNED, machine_cid, offsetof(Machine, vsock_cid), 0 },
{ "sshAddress", JSON_VARIANT_STRING, json_dispatch_string, offsetof(Machine, ssh_address), JSON_SAFE },
{ "sshPrivateKeyPath", JSON_VARIANT_STRING, json_dispatch_absolute_path, offsetof(Machine, ssh_private_key_path), 0 },
{}
};
r = machine_new(_MACHINE_CLASS_INVALID, NULL, &machine);
if (r < 0)
return r;
r = varlink_dispatch(link, parameters, dispatch_table, machine);
if (r != 0)
return r;
if (!pidref_is_set(&machine->leader)) {
r = varlink_get_peer_pidref(link, &machine->leader);
if (r < 0)
return r;
}
r = machine_link(manager, machine);
if (r < 0)
return r;
r = cg_pidref_get_unit(&machine->leader, &machine->unit);
if (r < 0)
return r;
r = machine_start(machine, NULL, NULL);
if (r < 0)
return r;
/* the manager will free this machine */
TAKE_PTR(machine);
return varlink_reply(link, NULL);
}

View file

@ -0,0 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "varlink.h"
int vl_method_register(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata);

View file

@ -27,24 +27,21 @@
#include "path-util.h"
#include "process-util.h"
#include "serialize.h"
#include "socket-util.h"
#include "special.h"
#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
#include "terminal-util.h"
#include "tmpfile-util.h"
#include "uid-range.h"
#include "unit-name.h"
#include "user-util.h"
DEFINE_TRIVIAL_CLEANUP_FUNC(Machine*, machine_free);
int machine_new(Manager *manager, MachineClass class, const char *name, Machine **ret) {
int machine_new(MachineClass class, const char *name, Machine **ret) {
_cleanup_(machine_freep) Machine *m = NULL;
int r;
assert(manager);
assert(class < _MACHINE_CLASS_MAX);
assert(name);
assert(ret);
/* Passing class == _MACHINE_CLASS_INVALID here is fine. It
@ -57,27 +54,46 @@ int machine_new(Manager *manager, MachineClass class, const char *name, Machine
*m = (Machine) {
.leader = PIDREF_NULL,
.vsock_cid = VMADDR_CID_ANY,
};
m->name = strdup(name);
if (!m->name)
return -ENOMEM;
if (class != MACHINE_HOST) {
m->state_file = path_join("/run/systemd/machines", m->name);
if (!m->state_file)
if (name) {
m->name = strdup(name);
if (!m->name)
return -ENOMEM;
}
m->class = class;
r = hashmap_put(manager->machines, m->name, m);
*ret = TAKE_PTR(m);
return 0;
}
int machine_link(Manager *manager, Machine *machine) {
int r;
assert(manager);
assert(machine);
if (machine->manager)
return -EEXIST;
if (!machine->name)
return -EINVAL;
if (machine->class != MACHINE_HOST) {
char *temp = path_join("/run/systemd/machines", machine->name);
if (!temp)
return -ENOMEM;
free_and_replace(machine->state_file, temp);
}
r = hashmap_put(manager->machines, machine->name, machine);
if (r < 0)
return r;
m->manager = manager;
machine->manager = manager;
*ret = TAKE_PTR(m);
return 0;
}
@ -93,11 +109,9 @@ Machine* machine_free(Machine *m) {
LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
}
machine_release_unit(m);
free(m->scope_job);
if (m->manager) {
machine_release_unit(m);
(void) hashmap_remove(m->manager->machines, m->name);
if (m->manager->host_machine == m)
@ -113,10 +127,13 @@ Machine* machine_free(Machine *m) {
sd_bus_message_unref(m->create_message);
free(m->name);
free(m->scope_job);
free(m->state_file);
free(m->service);
free(m->root_directory);
free(m->netif);
free(m->ssh_address);
free(m->ssh_private_key_path);
return mfree(m);
}

View file

@ -62,12 +62,17 @@ struct Machine {
int *netif;
size_t n_netif;
unsigned vsock_cid;
char *ssh_address;
char *ssh_private_key_path;
LIST_HEAD(Operation, operations);
LIST_FIELDS(Machine, gc_queue);
};
int machine_new(Manager *manager, MachineClass class, const char *name, Machine **ret);
int machine_new(MachineClass class, const char *name, Machine **ret);
int machine_link(Manager *manager, Machine *machine);
Machine* machine_free(Machine *m);
bool machine_may_gc(Machine *m, bool drop_not_started);
void machine_add_to_gc_queue(Machine *m);
@ -78,6 +83,8 @@ int machine_save(Machine *m);
int machine_load(Machine *m);
int machine_kill(Machine *m, KillWho who, int signo);
DEFINE_TRIVIAL_CLEANUP_FUNC(Machine*, machine_free);
void machine_release_unit(Machine *m);
MachineState machine_get_state(Machine *u);

View file

@ -462,6 +462,10 @@ static int method_get_machine_addresses(sd_bus_message *message, void *userdata,
return redirect_method_to_machine(message, userdata, error, bus_machine_method_get_addresses);
}
static int method_get_machine_ssh_info(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return redirect_method_to_machine(message, userdata, error, bus_machine_method_get_ssh_info);
}
static int method_get_machine_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return redirect_method_to_machine(message, userdata, error, bus_machine_method_get_os_release);
}
@ -1067,6 +1071,11 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_RESULT("a(iay)", addresses),
method_get_machine_addresses,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("GetMachineSSHInfo",
SD_BUS_ARGS("s", name),
SD_BUS_RESULT("s", ssh_address, "s", ssh_private_key_path),
method_get_machine_ssh_info,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("GetMachineOSRelease",
SD_BUS_ARGS("s", name),
SD_BUS_RESULT("a{ss}", fields),
@ -1498,9 +1507,13 @@ int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
machine = hashmap_get(m->machines, name);
if (!machine) {
r = machine_new(m, _MACHINE_CLASS_INVALID, name, &machine);
r = machine_new(_MACHINE_CLASS_INVALID, name, &machine);
if (r < 0)
return r;
r = machine_link(m, machine);
if (r < 0)
return 0;
}
if (_machine)

View file

@ -1,10 +1,12 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "format-util.h"
#include "machine-varlink.h"
#include "machined-varlink.h"
#include "mkdir.h"
#include "user-util.h"
#include "varlink.h"
#include "varlink-io.systemd.Machine.h"
#include "varlink-io.systemd.UserDatabase.h"
typedef struct LookupParameters {
@ -378,13 +380,13 @@ static int vl_method_get_memberships(Varlink *link, JsonVariant *parameters, Var
return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL);
}
int manager_varlink_init(Manager *m) {
static int manager_varlink_init_userdb(Manager *m) {
_cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
int r;
assert(m);
if (m->varlink_server)
if (m->varlink_userdb_server)
return 0;
r = varlink_server_new(&s, VARLINK_SERVER_ACCOUNT_UID|VARLINK_SERVER_INHERIT_USERDATA);
@ -415,12 +417,64 @@ int manager_varlink_init(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to attach varlink connection to event loop: %m");
m->varlink_server = TAKE_PTR(s);
m->varlink_userdb_server = TAKE_PTR(s);
return 0;
}
static int manager_varlink_init_machine(Manager *m) {
_cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
int r;
assert(m);
if (m->varlink_machine_server)
return 0;
r = varlink_server_new(&s, VARLINK_SERVER_ROOT_ONLY|VARLINK_SERVER_INHERIT_USERDATA);
if (r < 0)
return log_error_errno(r, "Failed to allocate varlink server object: %m");
varlink_server_set_userdata(s, m);
r = varlink_server_add_interface(s, &vl_interface_io_systemd_Machine);
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);
if (r < 0)
return log_error_errno(r, "Failed to register varlink methods: %m");
(void) mkdir_p("/run/systemd/machine", 0755);
r = varlink_server_listen_address(s, "/run/systemd/machine/io.systemd.Machine", 0666);
if (r < 0)
return log_error_errno(r, "Failed to bind to varlink socket: %m");
r = varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0)
return log_error_errno(r, "Failed to attach varlink connection to event loop: %m");
m->varlink_machine_server = TAKE_PTR(s);
return 0;
}
int manager_varlink_init(Manager *m) {
int r;
r = manager_varlink_init_userdb(m);
if (r < 0)
return r;
r = manager_varlink_init_machine(m);
if (r < 0)
return r;
return 0;
}
void manager_varlink_done(Manager *m) {
assert(m);
m->varlink_server = varlink_server_unref(m->varlink_server);
m->varlink_userdb_server = varlink_server_unref(m->varlink_userdb_server);
m->varlink_machine_server = varlink_server_unref(m->varlink_machine_server);
}

View file

@ -132,10 +132,14 @@ static int manager_add_host_machine(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to open reference to PID 1: %m");
r = machine_new(m, MACHINE_HOST, ".host", &t);
r = machine_new(MACHINE_HOST, ".host", &t);
if (r < 0)
return log_error_errno(r, "Failed to create machine: %m");
r = machine_link(m, t);
if (r < 0)
return log_error_errno(r, "Failed to link machine to manager: %m");
t->leader = TAKE_PIDREF(pidref);
t->id = mid;
@ -312,7 +316,10 @@ static bool check_idle(void *userdata) {
if (m->operations)
return false;
if (varlink_server_current_connections(m->varlink_server) > 0)
if (varlink_server_current_connections(m->varlink_userdb_server) > 0)
return false;
if (varlink_server_current_connections(m->varlink_machine_server) > 0)
return false;
manager_gc(m, true);

View file

@ -40,7 +40,8 @@ struct Manager {
sd_event_source *nscd_cache_flush_event;
#endif
VarlinkServer *varlink_server;
VarlinkServer *varlink_userdb_server;
VarlinkServer *varlink_machine_server;
};
int manager_add_machine(Manager *m, const char *name, Machine **_machine);

View file

@ -3,6 +3,7 @@
libmachine_core_sources = files(
'image-dbus.c',
'machine-dbus.c',
'machine-varlink.c',
'machine.c',
'machined-core.c',
'machined-dbus.c',

View file

@ -23,6 +23,7 @@
#include "math-util.h"
#include "memory-util.h"
#include "memstream-util.h"
#include "path-util.h"
#include "set.h"
#include "string-table.h"
#include "string-util.h"
@ -5006,6 +5007,27 @@ int json_dispatch_user_group_name(const char *name, JsonVariant *variant, JsonDi
return 0;
}
int json_dispatch_absolute_path(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
const char *path;
char **p = ASSERT_PTR(userdata);
assert(variant);
if (!json_variant_is_string(variant))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
path = json_variant_string(variant);
if (!path_is_valid(path))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid path.", strna(name));
if (!path_is_absolute(path))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' must be an absolute path.", strna(name));
if (free_and_strdup(p, path) < 0)
return json_log_oom(variant, flags);
return 0;
}
int json_dispatch_id128(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
sd_id128_t *uuid = userdata;
int r;

View file

@ -425,6 +425,7 @@ int json_dispatch_int8(const char *name, JsonVariant *variant, JsonDispatchFlags
int json_dispatch_uint8(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
int json_dispatch_uid_gid(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
int json_dispatch_user_group_name(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
int json_dispatch_absolute_path(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
int json_dispatch_id128(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
int json_dispatch_unsupported(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
int json_dispatch_unbase64_iovec(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);

View file

@ -180,6 +180,7 @@ shared_sources = files(
'varlink-io.systemd.Credentials.c',
'varlink-io.systemd.Hostname.c',
'varlink-io.systemd.Journal.c',
'varlink-io.systemd.Machine.c',
'varlink-io.systemd.ManagedOOM.c',
'varlink-io.systemd.MountFileSystem.c',
'varlink-io.systemd.NamespaceResource.c',

View file

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "varlink-idl.h"
#include "varlink-io.systemd.Machine.h"
static VARLINK_DEFINE_METHOD(
Register,
VARLINK_DEFINE_INPUT(name, VARLINK_STRING, 0),
VARLINK_DEFINE_INPUT(id, VARLINK_STRING, VARLINK_NULLABLE),
VARLINK_DEFINE_INPUT(service, VARLINK_STRING, VARLINK_NULLABLE),
VARLINK_DEFINE_INPUT(class, VARLINK_STRING, 0),
VARLINK_DEFINE_INPUT(leader, VARLINK_INT, VARLINK_NULLABLE),
VARLINK_DEFINE_INPUT(rootDirectory, VARLINK_STRING, VARLINK_NULLABLE),
VARLINK_DEFINE_INPUT(ifIndices, VARLINK_INT, VARLINK_ARRAY|VARLINK_NULLABLE),
VARLINK_DEFINE_INPUT(vsockCid, VARLINK_INT, VARLINK_NULLABLE),
VARLINK_DEFINE_INPUT(sshAddress, VARLINK_STRING, VARLINK_NULLABLE),
VARLINK_DEFINE_INPUT(sshPrivateKeyPath, VARLINK_STRING, VARLINK_NULLABLE));
VARLINK_DEFINE_INTERFACE(
io_systemd_Machine,
"io.systemd.Machine",
&vl_method_Register);

View file

@ -0,0 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "varlink-idl.h"
extern const VarlinkInterface vl_interface_io_systemd_Machine;