nspawn: make the hostname of the container explicitly configurable with a new --hostname= switch

Previously, the container's hostname was exclusively initialized from
the machine name configured with --machine=, i.e. the internal name and
the external name used for and by the container was synchronized. This
adds a new option --hostname= that optionally allows the internal name
to deviate from the external name.

This new option is mainly useful to ultimately implement the OCI runtime
spec directly in nspawn, but it might be useful on its own for some
other usecases too.
This commit is contained in:
Lennart Poettering 2018-05-07 18:37:32 +02:00
parent 5a4ff98840
commit 3a9530e5f1
6 changed files with 90 additions and 5 deletions

View File

@ -373,6 +373,22 @@
instead.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--hostname=</option></term>
<listitem><para>Controls the hostname to set within the container, if different from the machine name. Expects
a valid hostname as argument. If this option is used, the kernel hostname of the container will be set to this
value, otherwise it will be initialized to the machine name as controlled by the <option>--machine=</option>
option described above. The machine name is used for various aspect of identification of the container from the
outside, the kernel hostname configurable with this option is useful for the container to identify itself from
the inside. It is usually a good idea to keep both forms of identification synchronized, in order to avoid
confusion. It is hence recommended to avoid usage of this option, and use <option>--machine=</option>
exclusively. Note that regardless whether the container's hostname is initialized from the name set with
<option>--hostname=</option> or the one set with <option>--machine=</option>, the container can later override
its kernel hostname freely on its own as well.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--uuid=</option></term>

View File

@ -302,6 +302,15 @@
details.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Hostname=</varname></term>
<listitem><para>Configures the kernel hostname set for the container. This is equivalent to the
<option>--hostname=</option> command line switch, and takes the same argument. See
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
details.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -49,6 +49,7 @@ Exec.LimitMSGQUEUE, config_parse_rlimit, RLIMIT_MSGQUEUE, of
Exec.LimitNICE, config_parse_rlimit, RLIMIT_NICE, offsetof(Settings, rlimit)
Exec.LimitRTPRIO, config_parse_rlimit, RLIMIT_RTPRIO, offsetof(Settings, rlimit)
Exec.LimitRTTIME, config_parse_rlimit, RLIMIT_RTTIME, offsetof(Settings, rlimit)
Exec.Hostname, config_parse_hostname, 0, offsetof(Settings, hostname)
Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only)
Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode)
Files.Bind, config_parse_bind, 0, 0

View File

@ -8,6 +8,7 @@
#include "alloc-util.h"
#include "cap-list.h"
#include "conf-parser.h"
#include "hostname-util.h"
#include "nspawn-network.h"
#include "nspawn-settings.h"
#include "parse-util.h"
@ -82,6 +83,7 @@ Settings* settings_free(Settings *s) {
strv_free(s->syscall_whitelist);
strv_free(s->syscall_blacklist);
rlimit_free_all(s->rlimit);
free(s->hostname);
strv_free(s->network_interfaces);
strv_free(s->network_macvlan);
@ -603,3 +605,31 @@ int config_parse_syscall_filter(
return 0;
}
int config_parse_hostname(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
char **s = data;
assert(rvalue);
assert(s);
if (!hostname_is_valid(rvalue, false)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid hostname, ignoring: %s", rvalue);
return 0;
}
if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
return log_oom();
return 0;
}

View File

@ -49,9 +49,10 @@ typedef enum SettingsMask {
SETTING_NOTIFY_READY = UINT64_C(1) << 14,
SETTING_PIVOT_ROOT = UINT64_C(1) << 15,
SETTING_SYSCALL_FILTER = UINT64_C(1) << 16,
SETTING_RLIMIT_FIRST = UINT64_C(1) << 17, /* we define one bit per resource limit here */
SETTING_RLIMIT_LAST = UINT64_C(1) << (17 + _RLIMIT_MAX - 1),
_SETTINGS_MASK_ALL = (UINT64_C(1) << (17 + _RLIMIT_MAX))
SETTING_HOSTNAME = UINT64_C(1) << 17,
SETTING_RLIMIT_FIRST = UINT64_C(1) << 18, /* we define one bit per resource limit here */
SETTING_RLIMIT_LAST = UINT64_C(1) << (18 + _RLIMIT_MAX - 1),
_SETTINGS_MASK_ALL = (UINT64_C(1) << (18 + _RLIMIT_MAX)) - 1
} SettingsMask;
typedef struct Settings {
@ -74,6 +75,7 @@ typedef struct Settings {
char **syscall_whitelist;
char **syscall_blacklist;
struct rlimit *rlimit[_RLIMIT_MAX];
char *hostname;
/* [Image] */
int read_only;
@ -118,3 +120,4 @@ int config_parse_boot(const char *unit, const char *filename, unsigned line, con
int config_parse_pid2(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_private_users(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_syscall_filter(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_hostname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);

View File

@ -128,7 +128,8 @@ static char *arg_pivot_root_new = NULL;
static char *arg_pivot_root_old = NULL;
static char *arg_user = NULL;
static sd_id128_t arg_uuid = {};
static char *arg_machine = NULL;
static char *arg_machine = NULL; /* The name used by the host to refer to this */
static char *arg_hostname = NULL; /* The name the payload sees by default */
static const char *arg_selinux_context = NULL;
static const char *arg_selinux_apifs_context = NULL;
static const char *arg_slice = NULL;
@ -223,6 +224,7 @@ static void help(void) {
" Pivot root to given directory in the container\n"
" -u --user=USER Run the command under specified user or uid\n"
" -M --machine=NAME Set the machine name for the container\n"
" --hostname=NAME Override the hostname for the container\n"
" --uuid=UUID Set a specific machine UUID for the container\n"
" -S --slice=SLICE Place the container in the specified slice\n"
" --property=NAME=VALUE Set scope unit property\n"
@ -443,6 +445,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_ROOT_HASH,
ARG_SYSTEM_CALL_FILTER,
ARG_RLIMIT,
ARG_HOSTNAME,
};
static const struct option options[] = {
@ -466,6 +469,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "overlay", required_argument, NULL, ARG_OVERLAY },
{ "overlay-ro", required_argument, NULL, ARG_OVERLAY_RO },
{ "machine", required_argument, NULL, 'M' },
{ "hostname", required_argument, NULL, ARG_HOSTNAME },
{ "slice", required_argument, NULL, 'S' },
{ "setenv", required_argument, NULL, 'E' },
{ "selinux-context", required_argument, NULL, 'Z' },
@ -701,6 +705,23 @@ static int parse_argv(int argc, char *argv[]) {
}
break;
case ARG_HOSTNAME:
if (isempty(optarg))
arg_hostname = mfree(arg_hostname);
else {
if (!hostname_is_valid(optarg, false)) {
log_error("Invalid hostname: %s", optarg);
return -EINVAL;
}
r = free_and_strdup(&arg_hostname, optarg);
if (r < 0)
return log_oom();
}
arg_settings_mask |= SETTING_HOSTNAME;
break;
case 'Z':
arg_selinux_context = optarg;
break;
@ -1762,7 +1783,7 @@ static int setup_hostname(void) {
if ((arg_clone_ns_flags & CLONE_NEWUTS) == 0)
return 0;
if (sethostname_idempotent(arg_machine) < 0)
if (sethostname_idempotent(arg_hostname ?: arg_machine) < 0)
return -errno;
return 0;
@ -3314,6 +3335,10 @@ static int load_settings(void) {
free_and_replace(arg_rlimit[rl], settings->rlimit[rl]);
}
if ((arg_settings_mask & SETTING_HOSTNAME) == 0 &&
settings->hostname)
free_and_replace(arg_hostname, settings->hostname);
return 0;
}
@ -4274,6 +4299,7 @@ finish:
free(arg_template);
free(arg_image);
free(arg_machine);
free(arg_hostname);
free(arg_user);
free(arg_pivot_root_new);
free(arg_pivot_root_old);