nspawn: always setup machine id

We check /etc/machine-id of the container and if it is already populated
we use value from there, possibly ignoring value of --uuid option from
the command line. When dealing with R/O image we setup transient machine
id.

Once we determined machine id of the container, we use this value for
registration with systemd-machined and we also export it via
container_uuid environment variable.

As registration with systemd-machined is done by the main nspawn process
we communicate container machine id established by setup_machine_id from
outer child to the main process by unix domain socket. Similarly to PID
of inner child.
This commit is contained in:
Michal Sekletar 2016-04-08 13:22:54 +02:00
parent 710a8858a9
commit e01ff70a77
4 changed files with 87 additions and 31 deletions

View File

@ -3028,7 +3028,9 @@ systemd_nspawn_SOURCES = \
src/core/mount-setup.c \ src/core/mount-setup.c \
src/core/mount-setup.h \ src/core/mount-setup.h \
src/core/loopback-setup.c \ src/core/loopback-setup.c \
src/core/loopback-setup.h src/core/loopback-setup.h \
src/core/machine-id-setup.c \
src/core/machine-id-setup.h
nodist_systemd_nspawn_SOURCES = \ nodist_systemd_nspawn_SOURCES = \
src/nspawn/nspawn-gperf.c src/nspawn/nspawn-gperf.c

2
TODO
View File

@ -564,8 +564,6 @@ Features:
- to allow "linking" of nspawn containers, extend --network-bridge= so - to allow "linking" of nspawn containers, extend --network-bridge= so
that it can dynamically create bridge interfaces that are refcounted that it can dynamically create bridge interfaces that are refcounted
by the containers on them. For each group of containers to link together by the containers on them. For each group of containers to link together
- refuses to boot containers without /etc/machine-id (OK?), and with empty
/etc/machine-id (not OK).
- nspawn -x should support ephemeral instances of gpt images - nspawn -x should support ephemeral instances of gpt images
- emulate /dev/kmsg using CUSE and turn off the syslog syscall - emulate /dev/kmsg using CUSE and turn off the syslog syscall
with seccomp. That should provide us with a useful log buffer that with seccomp. That should provide us with a useful log buffer that

View File

@ -355,7 +355,9 @@
<listitem><para>Set the specified UUID for the container. The <listitem><para>Set the specified UUID for the container. The
init system will initialize init system will initialize
<filename>/etc/machine-id</filename> from this if this file is <filename>/etc/machine-id</filename> from this if this file is
not set yet. </para></listitem> not set yet. Note that this option takes effect only if
<filename>/etc/machine-id</filename> in the container is
unpopulated.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>

View File

@ -64,6 +64,7 @@
#include "hostname-util.h" #include "hostname-util.h"
#include "log.h" #include "log.h"
#include "loopback-setup.h" #include "loopback-setup.h"
#include "machine-id-setup.h"
#include "machine-image.h" #include "machine-image.h"
#include "macro.h" #include "macro.h"
#include "missing.h" #include "missing.h"
@ -1375,11 +1376,11 @@ static int setup_hostname(void) {
} }
static int setup_journal(const char *directory) { static int setup_journal(const char *directory) {
sd_id128_t machine_id, this_id; sd_id128_t this_id;
_cleanup_free_ char *b = NULL, *d = NULL; _cleanup_free_ char *b = NULL, *d = NULL;
const char *etc_machine_id, *p, *q; const char *p, *q;
bool try; bool try;
char *id; char id[33];
int r; int r;
/* Don't link journals in ephemeral mode */ /* Don't link journals in ephemeral mode */
@ -1391,28 +1392,11 @@ static int setup_journal(const char *directory) {
try = arg_link_journal_try || arg_link_journal == LINK_AUTO; try = arg_link_journal_try || arg_link_journal == LINK_AUTO;
etc_machine_id = prefix_roota(directory, "/etc/machine-id");
r = read_one_line_file(etc_machine_id, &b);
if (r == -ENOENT && try)
return 0;
else if (r < 0)
return log_error_errno(r, "Failed to read machine ID from %s: %m", etc_machine_id);
id = strstrip(b);
if (isempty(id) && try)
return 0;
/* Verify validity */
r = sd_id128_from_string(id, &machine_id);
if (r < 0)
return log_error_errno(r, "Failed to parse machine ID from %s: %m", etc_machine_id);
r = sd_id128_get_machine(&this_id); r = sd_id128_get_machine(&this_id);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to retrieve machine ID: %m"); return log_error_errno(r, "Failed to retrieve machine ID: %m");
if (sd_id128_equal(machine_id, this_id)) { if (sd_id128_equal(arg_uuid, this_id)) {
log_full(try ? LOG_WARNING : LOG_ERR, log_full(try ? LOG_WARNING : LOG_ERR,
"Host and machine ids are equal (%s): refusing to link journals", id); "Host and machine ids are equal (%s): refusing to link journals", id);
if (try) if (try)
@ -1432,6 +1416,8 @@ static int setup_journal(const char *directory) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to create /var/log/journal: %m"); return log_error_errno(r, "Failed to create /var/log/journal: %m");
(void) sd_id128_to_string(arg_uuid, id);
p = strjoina("/var/log/journal/", id); p = strjoina("/var/log/journal/", id);
q = prefix_roota(directory, p); q = prefix_roota(directory, p);
@ -2201,6 +2187,38 @@ static int mount_device(const char *what, const char *where, const char *directo
#endif #endif
} }
static int setup_machine_id(const char *directory) {
int r;
const char *etc_machine_id, *t;
_cleanup_free_ char *s = NULL;
etc_machine_id = prefix_roota(directory, "/etc/machine-id");
r = read_one_line_file(etc_machine_id, &s);
if (r < 0)
return log_error_errno(r, "Failed to read machine ID from %s: %m", etc_machine_id);
t = strstrip(s);
if (!isempty(t)) {
r = sd_id128_from_string(t, &arg_uuid);
if (r < 0)
return log_error_errno(r, "Failed to parse machine ID from %s: %m", etc_machine_id);
} else {
if (sd_id128_is_null(arg_uuid)) {
r = sd_id128_randomize(&arg_uuid);
if (r < 0)
return log_error_errno(r, "Failed to generate random machine ID: %m");
}
}
r = machine_id_setup(directory, arg_uuid);
if (r < 0)
return log_error_errno(r, "Failed to setup machine ID: %m");
return 0;
}
static int mount_devices( static int mount_devices(
const char *where, const char *where,
const char *root_device, bool root_device_rw, const char *root_device, bool root_device_rw,
@ -2458,6 +2476,7 @@ static int inner_child(
FDSet *fds) { FDSet *fds) {
_cleanup_free_ char *home = NULL; _cleanup_free_ char *home = NULL;
char as_uuid[37];
unsigned n_env = 1; unsigned n_env = 1;
const char *envp[] = { const char *envp[] = {
"PATH=" DEFAULT_PATH_SPLIT_USR, "PATH=" DEFAULT_PATH_SPLIT_USR,
@ -2575,12 +2594,10 @@ static int inner_child(
(asprintf((char**)(envp + n_env++), "LOGNAME=%s", arg_user ? arg_user : "root") < 0)) (asprintf((char**)(envp + n_env++), "LOGNAME=%s", arg_user ? arg_user : "root") < 0))
return log_oom(); return log_oom();
if (!sd_id128_equal(arg_uuid, SD_ID128_NULL)) { assert(!sd_id128_equal(arg_uuid, SD_ID128_NULL));
char as_uuid[37];
if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_format_as_uuid(arg_uuid, as_uuid)) < 0) if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_format_as_uuid(arg_uuid, as_uuid)) < 0)
return log_oom(); return log_oom();
}
if (fdset_size(fds) > 0) { if (fdset_size(fds) > 0) {
r = fdset_cloexec(fds, false); r = fdset_cloexec(fds, false);
@ -2669,6 +2686,7 @@ static int outer_child(
bool interactive, bool interactive,
bool secondary, bool secondary,
int pid_socket, int pid_socket,
int uuid_socket,
int kmsg_socket, int kmsg_socket,
int rtnl_socket, int rtnl_socket,
int uid_shift_socket, int uid_shift_socket,
@ -2682,6 +2700,7 @@ static int outer_child(
assert(directory); assert(directory);
assert(console); assert(console);
assert(pid_socket >= 0); assert(pid_socket >= 0);
assert(uuid_socket >= 0);
assert(kmsg_socket >= 0); assert(kmsg_socket >= 0);
cg_unified_flush(); cg_unified_flush();
@ -2796,6 +2815,10 @@ static int outer_child(
if (r < 0) if (r < 0)
return r; return r;
r = setup_machine_id(directory);
if (r < 0)
return r;
r = setup_journal(directory); r = setup_journal(directory);
if (r < 0) if (r < 0)
return r; return r;
@ -2821,6 +2844,7 @@ static int outer_child(
return log_error_errno(errno, "Failed to fork inner child: %m"); return log_error_errno(errno, "Failed to fork inner child: %m");
if (pid == 0) { if (pid == 0) {
pid_socket = safe_close(pid_socket); pid_socket = safe_close(pid_socket);
uuid_socket = safe_close(uuid_socket);
uid_shift_socket = safe_close(uid_shift_socket); uid_shift_socket = safe_close(uid_shift_socket);
/* The inner child has all namespaces that are /* The inner child has all namespaces that are
@ -2842,7 +2866,16 @@ static int outer_child(
return -EIO; return -EIO;
} }
l = send(uuid_socket, &arg_uuid, sizeof(arg_uuid), MSG_NOSIGNAL);
if (l < 0)
return log_error_errno(errno, "Failed to send machine ID: %m");
if (l != sizeof(arg_uuid)) {
log_error("Short write while sending machine ID.");
return -EIO;
}
pid_socket = safe_close(pid_socket); pid_socket = safe_close(pid_socket);
uuid_socket = safe_close(uuid_socket);
kmsg_socket = safe_close(kmsg_socket); kmsg_socket = safe_close(kmsg_socket);
rtnl_socket = safe_close(rtnl_socket); rtnl_socket = safe_close(rtnl_socket);
@ -3318,7 +3351,8 @@ int main(int argc, char *argv[]) {
} }
for (;;) { for (;;) {
_cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 }, uid_shift_socket_pair[2] = { -1, -1 }; _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 },
pid_socket_pair[2] = { -1, -1 }, uuid_socket_pair[2] = { -1, -1 }, uid_shift_socket_pair[2] = { -1, -1 };
ContainerStatus container_status; ContainerStatus container_status;
_cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL; _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
static const struct sigaction sa = { static const struct sigaction sa = {
@ -3353,6 +3387,11 @@ int main(int argc, char *argv[]) {
goto finish; goto finish;
} }
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uuid_socket_pair) < 0) {
r = log_error_errno(errno, "Failed to create id socket pair: %m");
goto finish;
}
if (arg_userns) if (arg_userns)
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0) { if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0) {
r = log_error_errno(errno, "Failed to create uid shift socket pair: %m"); r = log_error_errno(errno, "Failed to create uid shift socket pair: %m");
@ -3393,6 +3432,7 @@ int main(int argc, char *argv[]) {
kmsg_socket_pair[0] = safe_close(kmsg_socket_pair[0]); kmsg_socket_pair[0] = safe_close(kmsg_socket_pair[0]);
rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]); rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]);
pid_socket_pair[0] = safe_close(pid_socket_pair[0]); pid_socket_pair[0] = safe_close(pid_socket_pair[0]);
uuid_socket_pair[0] = safe_close(uuid_socket_pair[0]);
uid_shift_socket_pair[0] = safe_close(uid_shift_socket_pair[0]); uid_shift_socket_pair[0] = safe_close(uid_shift_socket_pair[0]);
(void) reset_all_signal_handlers(); (void) reset_all_signal_handlers();
@ -3407,6 +3447,7 @@ int main(int argc, char *argv[]) {
interactive, interactive,
secondary, secondary,
pid_socket_pair[1], pid_socket_pair[1],
uuid_socket_pair[1],
kmsg_socket_pair[1], kmsg_socket_pair[1],
rtnl_socket_pair[1], rtnl_socket_pair[1],
uid_shift_socket_pair[1], uid_shift_socket_pair[1],
@ -3424,6 +3465,7 @@ int main(int argc, char *argv[]) {
kmsg_socket_pair[1] = safe_close(kmsg_socket_pair[1]); kmsg_socket_pair[1] = safe_close(kmsg_socket_pair[1]);
rtnl_socket_pair[1] = safe_close(rtnl_socket_pair[1]); rtnl_socket_pair[1] = safe_close(rtnl_socket_pair[1]);
pid_socket_pair[1] = safe_close(pid_socket_pair[1]); pid_socket_pair[1] = safe_close(pid_socket_pair[1]);
uuid_socket_pair[1] = safe_close(uuid_socket_pair[1]);
uid_shift_socket_pair[1] = safe_close(uid_shift_socket_pair[1]); uid_shift_socket_pair[1] = safe_close(uid_shift_socket_pair[1]);
/* Wait for the outer child. */ /* Wait for the outer child. */
@ -3448,6 +3490,18 @@ int main(int argc, char *argv[]) {
goto finish; goto finish;
} }
/* We also retrieve container UUID in case it was generated by outer child */
l = recv(uuid_socket_pair[0], &arg_uuid, sizeof(arg_uuid), 0);
if (l < 0) {
r = log_error_errno(errno, "Failed to read container machine ID: %m");
goto finish;
}
if (l != sizeof(arg_uuid)) {
log_error("Short read while reading container machined ID.");
r = EIO;
goto finish;
}
log_debug("Init process invoked as PID " PID_FMT, pid); log_debug("Init process invoked as PID " PID_FMT, pid);
if (arg_userns) { if (arg_userns) {