mirror of
https://github.com/systemd/systemd.git
synced 2024-12-23 21:35:11 +03:00
Merge pull request #32709 from bluca/machined_ssh
machined: add GetMachineSSHInfo method and varlink interface to register machines
This commit is contained in:
commit
867e2987a2
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
171
src/machine/machine-varlink.c
Normal file
171
src/machine/machine-varlink.c
Normal 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);
|
||||
}
|
6
src/machine/machine-varlink.h
Normal file
6
src/machine/machine-varlink.h
Normal 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);
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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',
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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',
|
||||
|
22
src/shared/varlink-io.systemd.Machine.c
Normal file
22
src/shared/varlink-io.systemd.Machine.c
Normal 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);
|
6
src/shared/varlink-io.systemd.Machine.h
Normal file
6
src/shared/varlink-io.systemd.Machine.h
Normal 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;
|
Loading…
Reference in New Issue
Block a user