Unblocks #2013.
Unblocks #2015.
Closes #1766.
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
<title>Init ID</title>
<para>
Sets the UID/GID to use for the init system, and subsequent commands.
- Note that using a non-root uid when booting a system container will
+ Note that using a non-root UID when booting a system container will
likely not work due to missing privileges. Setting the UID/GID is mostly
- useful when running application container.
+ useful when running application containers.
Defaults to: UID(0), GID(0)
</para>
</listitem>
</varlistentry>
-
<varlistentry>
<term>
<option>lxc.net.[i].ipv6.address</option>
<para>
Add a configuration option to specify a script to be
executed after creating and configuring the network used
- from the host side. The following arguments are passed
- to the script: container name and config section name
- (net) Additional arguments depend on the config section
- employing a script hook; the following are used by the
- network system: execution context (up), network type
- (empty/veth/macvlan/phys), Depending on the network
- type, other arguments may be passed:
- veth/macvlan/phys. And finally (host-sided) device name.
+ from the host side.
+ </para>
+
+ <para>
+ In addition to the information available to all hooks. The
+ following information is provided to the script:
+ <itemizedlist>
+ <listitem>
+ <para>
+ LXC_HOOK_TYPE: the hook type. This is either 'up' or 'down'.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ LXC_HOOK_SECTION: the section type 'net'.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ LXC_NET_TYPE: the network type. This is one of the valid
+ network types listed here (e.g. 'macvlan', 'veth').
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ LXC_NET_PARENT: the parent device on the host. This is only
+ set for network types 'mavclan', 'veth', 'phys'.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ LXC_NET_PEER: the name of the peer device on the host. This is
+ only set for 'veth' network types. Note that this information
+ is only available when <option>lxc.hook.version</option> is set
+ to 1.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ Whether this information is provided in the form of environment
+ variables or as arguments to the script depends on the value of
+ <option>lxc.hook.version</option>. If set to 1 then information is
+ provided in the form of environment variables. If set to 0
+ information is provided as arguments to the script.
</para>
+
<para>
Standard output from the script is logged at debug level.
Standard error is not logged, but can be captured by the
<para>
Add a configuration option to specify a script to be
executed before destroying the network used from the
- host side. The following arguments are passed to the
- script: container name and config section name (net)
- Additional arguments depend on the config section
- employing a script hook; the following are used by the
- network system: execution context (down), network type
- (empty/veth/macvlan/phys), Depending on the network
- type, other arguments may be passed:
- veth/macvlan/phys. And finally (host-sided) device name.
+ host side.
+ </para>
+
+ <para>
+ In addition to the information available to all hooks. The
+ following information is provided to the script:
+ <itemizedlist>
+ <listitem>
+ <para>
+ LXC_HOOK_TYPE: the hook type. This is either 'up' or 'down'.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ LXC_HOOK_SECTION: the section type 'net'.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ LXC_NET_TYPE: the network type. This is one of the valid
+ network types listed here (e.g. 'macvlan', 'veth').
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ LXC_NET_PARENT: the parent device on the host. This is only
+ set for network types 'mavclan', 'veth', 'phys'.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ LXC_NET_PEER: the name of the peer device on the host. This is
+ only set for 'veth' network types. Note that this information
+ is only available when <option>lxc.hook.version</option> is set
+ to 1.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ Whether this information is provided in the form of environment
+ variables or as arguments to the script depends on the value of
+ <option>lxc.hook.version</option>. If set to 1 then information is
+ provided in the form of environment variables. If set to 0
+ information is provided as arguments to the script.
</para>
+
<para>
Standard output from the script is logged at debug level.
Standard error is not logged, but can be captured by the
return 0;
}
-static int run_script_argv(const char *name, unsigned int hook_version,
- const char *section, const char *script,
- const char *hookname, const char *lxcpath,
- char **argsin)
+int run_script_argv(const char *name, unsigned int hook_version,
+ const char *section, const char *script,
+ const char *hookname, char **argsin)
{
int buf_pos, i, ret;
char *buffer;
return -1;
}
TRACE("Set environment variable: LXC_HOOK_SECTION=%s", section);
+
+ if (strcmp(section, "net") == 0) {
+ char *parent;
+
+ if (!argsin[0])
+ return -EINVAL;
+
+ ret = setenv("LXC_NET_TYPE", argsin[0], 1);
+ if (ret < 0) {
+ SYSERROR("Failed to set environment variable: "
+ "LXC_NET_TYPE=%s", argsin[0]);
+ return -1;
+ }
+ TRACE("Set environment variable: LXC_NET_TYPE=%s", argsin[0]);
+
+ parent = argsin[1] ? argsin[1] : "";
+
+ if (strcmp(argsin[0], "macvlan")) {
+ ret = setenv("LXC_NET_PARENT", parent, 1);
+ if (ret < 0) {
+ SYSERROR("Failed to set environment "
+ "variable: LXC_NET_PARENT=%s", parent);
+ return -1;
+ }
+ TRACE("Set environment variable: LXC_NET_PARENT=%s", parent);
+ } else if (strcmp(argsin[0], "phys")) {
+ ret = setenv("LXC_NET_PARENT", parent, 1);
+ if (ret < 0) {
+ SYSERROR("Failed to set environment "
+ "variable: LXC_NET_PARENT=%s", parent);
+ return -1;
+ }
+ TRACE("Set environment variable: LXC_NET_PARENT=%s", parent);
+ } else if (strcmp(argsin[0], "veth")) {
+ char *peer = argsin[2] ? argsin[2] : "";
+
+ ret = setenv("LXC_NET_PEER", peer, 1);
+ if (ret < 0) {
+ SYSERROR("Failed to set environment "
+ "variable: LXC_NET_PEER=%s", peer);
+ return -1;
+ }
+ TRACE("Set environment variable: LXC_NET_PEER=%s", peer);
+
+ ret = setenv("LXC_NET_PARENT", parent, 1);
+ if (ret < 0) {
+ SYSERROR("Failed to set environment "
+ "variable: LXC_NET_PARENT=%s", parent);
+ return -1;
+ }
+ TRACE("Set environment variable: LXC_NET_PARENT=%s", parent);
+ }
+ }
}
for (i = 0; argsin && argsin[i]; i++) {
remount_all_slave();
- if (run_lxc_hooks(name, "pre-mount", conf, lxcpath, NULL)) {
+ if (run_lxc_hooks(name, "pre-mount", conf, NULL)) {
ERROR("failed to run pre-mount hooks for container '%s'.", name);
return -1;
}
return -1;
}
- if (run_lxc_hooks(name, "mount", lxc_conf, lxcpath, NULL)) {
+ if (run_lxc_hooks(name, "mount", lxc_conf, NULL)) {
ERROR("failed to run mount hooks for container '%s'.", name);
return -1;
}
if (lxc_conf->autodev > 0) {
- if (run_lxc_hooks(name, "autodev", lxc_conf, lxcpath, NULL)) {
+ if (run_lxc_hooks(name, "autodev", lxc_conf, NULL)) {
ERROR("failed to run autodev hooks for container '%s'.", name);
return -1;
}
}
int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf,
- const char *lxcpath, char *argv[])
+ char *argv[])
{
struct lxc_list *it;
int which = -1;
char *hook = it->elem;
ret = run_script_argv(name, conf->hooks_version, "lxc", hook,
- hookname, lxcpath, argv);
+ hookname, argv);
if (ret < 0)
return -1;
}
#endif
extern int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf,
- const char *lxcpath, char *argv[]);
+ char *argv[]);
extern int detect_shared_rootfs(void);
extern struct lxc_conf *lxc_conf_init(void);
extern void lxc_conf_free(struct lxc_conf *conf);
unsigned long flags);
extern int run_script(const char *name, const char *section, const char *script,
...);
+extern int run_script_argv(const char *name, unsigned int hook_version,
+ const char *section, const char *script,
+ const char *hookname, char **argsin);
extern int in_caplist(int cap, struct lxc_list *caps);
extern int setup_sysctl_parameters(struct lxc_list *sysctls);
extern int lxc_clear_sysctls(struct lxc_conf *c, const char *key);
SYSERROR("Failed to set environment variable for console log");
/* End of environment variable setup for hooks */
- if (run_lxc_hooks(c->name, "destroy", conf, c->get_config_path(c), NULL)) {
+ if (run_lxc_hooks(c->name, "destroy", conf, NULL)) {
ERROR("Failed to execute clone hook for \"%s\"", c->name);
goto out;
}
SYSERROR("failed to set environment variable for rootfs mount");
}
- if (run_lxc_hooks(c->name, "clone", conf, c->get_config_path(c), hookargs)) {
+ if (run_lxc_hooks(c->name, "clone", conf, hookargs)) {
ERROR("Error executing clone hook for %s", c->name);
storage_put(bdev);
return -1;
}
if (netdev->upscript) {
- err = run_script(handler->name, "net", netdev->upscript, "up",
- "veth", veth1, (char*) NULL);
- if (err)
+ char *argv[] = {
+ "veth",
+ netdev->link,
+ "veth1",
+ NULL,
+ };
+
+ err = run_script_argv(handler->name,
+ handler->conf->hooks_version, "net",
+ netdev->upscript, "up", argv);
+ if (err < 0)
goto out_delete;
}
}
if (netdev->upscript) {
- err = run_script(handler->name, "net", netdev->upscript, "up",
- "macvlan", netdev->link, (char*) NULL);
- if (err)
+ char *argv[] = {
+ "macvlan",
+ netdev->link,
+ NULL,
+ };
+
+ err = run_script_argv(handler->name,
+ handler->conf->hooks_version, "net",
+ netdev->upscript, "up", argv);
+ if (err < 0)
goto on_error;
}
static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
+ int ret;
+ char *argv[] = {
+ "phys",
+ netdev->link,
+ NULL,
+ };
+
if (netdev->link[0] == '\0') {
ERROR("No link for physical interface specified");
return -1;
*/
netdev->priv.phys_attr.ifindex = netdev->ifindex;
- if (netdev->upscript) {
- int err;
- err = run_script(handler->name, "net", netdev->upscript,
- "up", "phys", netdev->link, (char*) NULL);
- if (err)
- return -1;
- }
+ if (!netdev->upscript)
+ return 0;
+
+ ret = run_script_argv(handler->name, handler->conf->hooks_version,
+ "net", netdev->upscript, "up", argv);
+ if (ret < 0)
+ return -1;
return 0;
}
static int instantiate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
+ int ret;
+ char *argv[] = {
+ "empty",
+ NULL,
+ };
+
netdev->ifindex = 0;
- if (netdev->upscript) {
- int err;
- err = run_script(handler->name, "net", netdev->upscript,
- "up", "empty", (char*) NULL);
- if (err)
- return -1;
- }
+ if (!netdev->upscript)
+ return 0;
+
+ ret = run_script_argv(handler->name, handler->conf->hooks_version,
+ "net", netdev->upscript, "up", argv);
+ if (ret < 0)
+ return -1;
+
return 0;
}
static int shutdown_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
- char *veth1;
- int err;
+ int ret;
+ char *argv[] = {
+ "veth",
+ netdev->link,
+ NULL,
+ NULL,
+ };
+
+ if (!netdev->downscript)
+ return 0;
if (netdev->priv.veth_attr.pair[0] != '\0')
- veth1 = netdev->priv.veth_attr.pair;
+ argv[2] = netdev->priv.veth_attr.pair;
else
- veth1 = netdev->priv.veth_attr.veth1;
+ argv[2] = netdev->priv.veth_attr.veth1;
+
+ ret = run_script_argv(handler->name,
+ handler->conf->hooks_version, "net",
+ netdev->downscript, "down", argv);
+ if (ret < 0)
+ return -1;
- if (netdev->downscript) {
- err = run_script(handler->name, "net", netdev->downscript,
- "down", "veth", veth1, (char*) NULL);
- if (err)
- return -1;
- }
return 0;
}
static int shutdown_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
- int err;
+ int ret;
+ char *argv[] = {
+ "macvlan",
+ netdev->link,
+ NULL,
+ };
+
+ if (!netdev->downscript)
+ return 0;
+
+ ret = run_script_argv(handler->name, handler->conf->hooks_version,
+ "net", netdev->downscript, "down", argv);
+ if (ret < 0)
+ return -1;
- if (netdev->downscript) {
- err = run_script(handler->name, "net", netdev->downscript,
- "down", "macvlan", netdev->link,
- (char*) NULL);
- if (err)
- return -1;
- }
return 0;
}
static int shutdown_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
- int err;
+ int ret;
+ char *argv[] = {
+ "phys",
+ netdev->link,
+ NULL,
+ };
+
+ if (!netdev->downscript)
+ return 0;
+
+ ret = run_script_argv(handler->name, handler->conf->hooks_version,
+ "net", netdev->downscript, "down", argv);
+ if (ret < 0)
+ return -1;
- if (netdev->downscript) {
- err = run_script(handler->name, "net", netdev->downscript,
- "down", "phys", netdev->link, (char*) NULL);
- if (err)
- return -1;
- }
return 0;
}
static int shutdown_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
- int err;
+ int ret;
+ char *argv[] = {
+ "empty",
+ NULL,
+ };
+
+ if (!netdev->downscript)
+ return 0;
+
+ ret = run_script_argv(handler->name, handler->conf->hooks_version,
+ "net", netdev->downscript, "down", argv);
+ if (ret < 0)
+ return -1;
- if (netdev->downscript) {
- err = run_script(handler->name, "net", netdev->downscript,
- "down", "empty", (char*) NULL);
- if (err)
- return -1;
- }
return 0;
}
TRACE("set environment variables");
- if (run_lxc_hooks(name, "pre-start", conf, handler->lxcpath, NULL)) {
+ if (run_lxc_hooks(name, "pre-start", conf, NULL)) {
ERROR("Failed to run lxc.hook.pre-start for container \"%s\".", name);
goto out_aborting;
}
SYSERROR("Failed to set environment variable: LXC_TARGET=stop.");
if (handler->conf->hooks_version == 0)
- rc = run_lxc_hooks(name, "stop", handler->conf, handler->lxcpath, namespaces);
+ rc = run_lxc_hooks(name, "stop", handler->conf, namespaces);
else
- rc = run_lxc_hooks(name, "stop", handler->conf, handler->lxcpath, NULL);
+ rc = run_lxc_hooks(name, "stop", handler->conf, NULL);
while (namespace_count--)
free(namespaces[namespace_count]);
handler->conf->maincmd_fd = -1;
}
- if (run_lxc_hooks(name, "post-stop", handler->conf, handler->lxcpath, NULL)) {
+ if (run_lxc_hooks(name, "post-stop", handler->conf, NULL)) {
ERROR("Failed to run lxc.hook.post-stop for container \"%s\".", name);
if (handler->conf->reboot) {
WARN("Container will be stopped instead of rebooted.");
if (lxc_seccomp_load(handler->conf) != 0)
goto out_warn_father;
- if (run_lxc_hooks(handler->name, "start", handler->conf, handler->lxcpath, NULL)) {
+ if (run_lxc_hooks(handler->name, "start", handler->conf, NULL)) {
ERROR("Failed to run lxc.hook.start for container \"%s\".", handler->name);
goto out_warn_father;
}
SYSERROR("Failed to set environment variable: LXC_PID=%s.", pidstr);
/* Run any host-side start hooks */
- if (run_lxc_hooks(name, "start-host", conf, handler->lxcpath, NULL)) {
+ if (run_lxc_hooks(name, "start-host", conf, NULL)) {
ERROR("Failed to run lxc.hook.start-host for container \"%s\".", name);
return -1;
}