network: pass info in env if hook version is 1

Unblocks #2013.
Unblocks #2015.
Closes #1766.

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
This commit is contained in:
Christian Brauner 2017-12-12 13:30:54 +01:00
parent 18b3b9c17f
commit 14a7b0f98a
No known key found for this signature in database
GPG Key ID: 8EB056D53EECB12D
6 changed files with 281 additions and 89 deletions

View File

@ -308,9 +308,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<title>Init ID</title> <title>Init ID</title>
<para> <para>
Sets the UID/GID to use for the init system, and subsequent commands. 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 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) Defaults to: UID(0), GID(0)
</para> </para>
@ -608,7 +608,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term> <term>
<option>lxc.net.[i].ipv6.address</option> <option>lxc.net.[i].ipv6.address</option>
@ -651,15 +650,56 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<para> <para>
Add a configuration option to specify a script to be Add a configuration option to specify a script to be
executed after creating and configuring the network used executed after creating and configuring the network used
from the host side. The following arguments are passed from the host side.
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.
</para> </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> <para>
Standard output from the script is logged at debug level. Standard output from the script is logged at debug level.
Standard error is not logged, but can be captured by the Standard error is not logged, but can be captured by the
@ -676,15 +716,56 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<para> <para>
Add a configuration option to specify a script to be Add a configuration option to specify a script to be
executed before destroying the network used from the executed before destroying the network used from the
host side. The following arguments are passed to the host side.
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.
</para> </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> <para>
Standard output from the script is logged at debug level. Standard output from the script is logged at debug level.
Standard error is not logged, but can be captured by the Standard error is not logged, but can be captured by the

View File

@ -339,10 +339,9 @@ static int run_buffer(char *buffer)
return 0; return 0;
} }
static int run_script_argv(const char *name, unsigned int hook_version, int run_script_argv(const char *name, unsigned int hook_version,
const char *section, const char *script, const char *section, const char *script,
const char *hookname, const char *lxcpath, const char *hookname, char **argsin)
char **argsin)
{ {
int buf_pos, i, ret; int buf_pos, i, ret;
char *buffer; char *buffer;
@ -405,6 +404,59 @@ static int run_script_argv(const char *name, unsigned int hook_version,
return -1; return -1;
} }
TRACE("Set environment variable: LXC_HOOK_SECTION=%s", section); 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++) { for (i = 0; argsin && argsin[i]; i++) {
@ -3099,7 +3151,7 @@ int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath
remount_all_slave(); 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); ERROR("failed to run pre-mount hooks for container '%s'.", name);
return -1; return -1;
} }
@ -3208,13 +3260,13 @@ int lxc_setup(struct lxc_handler *handler)
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); ERROR("failed to run mount hooks for container '%s'.", name);
return -1; return -1;
} }
if (lxc_conf->autodev > 0) { 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); ERROR("failed to run autodev hooks for container '%s'.", name);
return -1; return -1;
} }
@ -3292,7 +3344,7 @@ int lxc_setup(struct lxc_handler *handler)
} }
int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf, int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf,
const char *lxcpath, char *argv[]) char *argv[])
{ {
struct lxc_list *it; struct lxc_list *it;
int which = -1; int which = -1;
@ -3325,7 +3377,7 @@ int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf,
char *hook = it->elem; char *hook = it->elem;
ret = run_script_argv(name, conf->hooks_version, "lxc", hook, ret = run_script_argv(name, conf->hooks_version, "lxc", hook,
hookname, lxcpath, argv); hookname, argv);
if (ret < 0) if (ret < 0)
return -1; return -1;
} }

View File

@ -412,7 +412,7 @@ extern struct lxc_conf *current_config;
#endif #endif
extern int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf, 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 int detect_shared_rootfs(void);
extern struct lxc_conf *lxc_conf_init(void); extern struct lxc_conf *lxc_conf_init(void);
extern void lxc_conf_free(struct lxc_conf *conf); extern void lxc_conf_free(struct lxc_conf *conf);
@ -457,6 +457,9 @@ extern unsigned long add_required_remount_flags(const char *s, const char *d,
unsigned long flags); unsigned long flags);
extern int run_script(const char *name, const char *section, const char *script, 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 in_caplist(int cap, struct lxc_list *caps);
extern int setup_sysctl_parameters(struct lxc_list *sysctls); extern int setup_sysctl_parameters(struct lxc_list *sysctls);
extern int lxc_clear_sysctls(struct lxc_conf *c, const char *key); extern int lxc_clear_sysctls(struct lxc_conf *c, const char *key);

View File

@ -2746,7 +2746,7 @@ static bool container_destroy(struct lxc_container *c,
SYSERROR("Failed to set environment variable for console log"); SYSERROR("Failed to set environment variable for console log");
/* End of environment variable setup for hooks */ /* 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); ERROR("Failed to execute clone hook for \"%s\"", c->name);
goto out; goto out;
} }
@ -3458,7 +3458,7 @@ static int clone_update_rootfs(struct clone_update_data *data)
SYSERROR("failed to set environment variable for rootfs mount"); 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); ERROR("Error executing clone hook for %s", c->name);
storage_put(bdev); storage_put(bdev);
return -1; return -1;

View File

@ -204,9 +204,17 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
} }
if (netdev->upscript) { if (netdev->upscript) {
err = run_script(handler->name, "net", netdev->upscript, "up", char *argv[] = {
"veth", veth1, (char*) NULL); "veth",
if (err) 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; goto out_delete;
} }
@ -254,9 +262,16 @@ static int instantiate_macvlan(struct lxc_handler *handler, struct lxc_netdev *n
} }
if (netdev->upscript) { if (netdev->upscript) {
err = run_script(handler->name, "net", netdev->upscript, "up", char *argv[] = {
"macvlan", netdev->link, (char*) NULL); "macvlan",
if (err) netdev->link,
NULL,
};
err = run_script_argv(handler->name,
handler->conf->hooks_version, "net",
netdev->upscript, "up", argv);
if (err < 0)
goto on_error; goto on_error;
} }
@ -323,6 +338,13 @@ static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netd
static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev) 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') { if (netdev->link[0] == '\0') {
ERROR("No link for physical interface specified"); ERROR("No link for physical interface specified");
return -1; return -1;
@ -346,27 +368,34 @@ static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netd
*/ */
netdev->priv.phys_attr.ifindex = netdev->ifindex; netdev->priv.phys_attr.ifindex = netdev->ifindex;
if (netdev->upscript) { if (!netdev->upscript)
int err; return 0;
err = run_script(handler->name, "net", netdev->upscript,
"up", "phys", netdev->link, (char*) NULL); ret = run_script_argv(handler->name, handler->conf->hooks_version,
if (err) "net", netdev->upscript, "up", argv);
return -1; if (ret < 0)
} return -1;
return 0; return 0;
} }
static int instantiate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev) static int instantiate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
{ {
int ret;
char *argv[] = {
"empty",
NULL,
};
netdev->ifindex = 0; netdev->ifindex = 0;
if (netdev->upscript) { if (!netdev->upscript)
int err; return 0;
err = run_script(handler->name, "net", netdev->upscript,
"up", "empty", (char*) NULL); ret = run_script_argv(handler->name, handler->conf->hooks_version,
if (err) "net", netdev->upscript, "up", argv);
return -1; if (ret < 0)
} return -1;
return 0; return 0;
} }
@ -387,34 +416,48 @@ static instantiate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
static int shutdown_veth(struct lxc_handler *handler, struct lxc_netdev *netdev) static int shutdown_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
{ {
char *veth1; int ret;
int err; char *argv[] = {
"veth",
netdev->link,
NULL,
NULL,
};
if (!netdev->downscript)
return 0;
if (netdev->priv.veth_attr.pair[0] != '\0') if (netdev->priv.veth_attr.pair[0] != '\0')
veth1 = netdev->priv.veth_attr.pair; argv[2] = netdev->priv.veth_attr.pair;
else 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; return 0;
} }
static int shutdown_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev) 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; return 0;
} }
@ -425,27 +468,40 @@ static int shutdown_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
static int shutdown_phys(struct lxc_handler *handler, struct lxc_netdev *netdev) 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; return 0;
} }
static int shutdown_empty(struct lxc_handler *handler, struct lxc_netdev *netdev) 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; return 0;
} }

View File

@ -668,7 +668,7 @@ int lxc_init(const char *name, struct lxc_handler *handler)
TRACE("set environment variables"); 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); ERROR("Failed to run lxc.hook.pre-start for container \"%s\".", name);
goto out_aborting; goto out_aborting;
} }
@ -767,9 +767,9 @@ void lxc_fini(const char *name, struct lxc_handler *handler)
SYSERROR("Failed to set environment variable: LXC_TARGET=stop."); SYSERROR("Failed to set environment variable: LXC_TARGET=stop.");
if (handler->conf->hooks_version == 0) 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 else
rc = run_lxc_hooks(name, "stop", handler->conf, handler->lxcpath, NULL); rc = run_lxc_hooks(name, "stop", handler->conf, NULL);
while (namespace_count--) while (namespace_count--)
free(namespaces[namespace_count]); free(namespaces[namespace_count]);
@ -792,7 +792,7 @@ void lxc_fini(const char *name, struct lxc_handler *handler)
handler->conf->maincmd_fd = -1; 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); ERROR("Failed to run lxc.hook.post-stop for container \"%s\".", name);
if (handler->conf->reboot) { if (handler->conf->reboot) {
WARN("Container will be stopped instead of rebooted."); WARN("Container will be stopped instead of rebooted.");
@ -1053,7 +1053,7 @@ static int do_start(void *data)
if (lxc_seccomp_load(handler->conf) != 0) if (lxc_seccomp_load(handler->conf) != 0)
goto out_warn_father; 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); ERROR("Failed to run lxc.hook.start for container \"%s\".", handler->name);
goto out_warn_father; goto out_warn_father;
} }
@ -1513,7 +1513,7 @@ static int lxc_spawn(struct lxc_handler *handler)
SYSERROR("Failed to set environment variable: LXC_PID=%s.", pidstr); SYSERROR("Failed to set environment variable: LXC_PID=%s.", pidstr);
/* Run any host-side start hooks */ /* 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); ERROR("Failed to run lxc.hook.start-host for container \"%s\".", name);
return -1; return -1;
} }