nspawn: make the hostname of the container explicitly configurable with a new --hostn...
authorLennart Poettering <lennart@poettering.net>
Mon, 7 May 2018 16:37:32 +0000 (18:37 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 17 May 2018 18:46:45 +0000 (20:46 +0200)
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.

man/systemd-nspawn.xml
man/systemd.nspawn.xml
src/nspawn/nspawn-gperf.gperf
src/nspawn/nspawn-settings.c
src/nspawn/nspawn-settings.h
src/nspawn/nspawn.c

index c6b027c..16d65d2 100644 (file)
       </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>
 
         <listitem><para>Set the specified UUID for the container. The
index 6bd7b33..3f8c325 100644 (file)
         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>
 
index 58184d4..f7d2e1a 100644 (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
index 19bf1d4..3757380 100644 (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;
+}
index 0e6ce61..3d3ee4c 100644 (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);
index 8ba8e73..7357576 100644 (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);