[lxc-devel] [PATCH RFC] Introduce a first set of container hooks

Serge Hallyn serge.hallyn at canonical.com
Fri Jun 15 22:16:38 UTC 2012


This patch introduces support for 4 hooks.  We'd like to have 6 in
all to mirror the openvz ones (thanks to Stéphane for this info):

pre-start: in the host namespace before container mounting happens
mount: after container mounting (as per config and /var/lib/lxc/container/fstab)
       but before pivot_root
start: immediately before exec'ing init
stop: in container namespace and in chroot before shutdown
umount: after other unmounting has happened
post-stop: outside of the container

stop and umount are not implemented here because when the kernel kills
the container init, it kills the namespace.  We can probably work around
this, i.e. by keeping the /proc/pid/ns/mnt open, and using that, though
all container tasks including init would still be dead.  Is that worth
pursuing?

start also presents a bit of an issue.  openvz allows a script on the
host to be specified, apparently.  My patch requires the script or
program to exist in the container.  I'm fine with trying to do it the
openvz way, but I wasn't sure what the best way to do that was.  Openvz
(I'm told) opens the script and passes its contents to a bash in the
container.  But that limits the hooks to being only scripts.  By
requiring the hook to be in the container, we can allow any sort of
hook, and assume that any required libraries/dependencies exist
there.

Other than that with this patchset I can add

lxc.hook.pre-start = /var/lib/lxc/p1/pre-start
lxc.hook.mount = /var/lib/lxc/p1/mount
lxc.hook.start = /start
lxc.hook.post-stop = /var/lib/lxc/p1/post-stop

to my /var/lib/lxc/p1/config, and the hooks get executed as expected.
Comments on the patch, the hooks we want, and the questions raised above
would be appreciated.

Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
---
 src/lxc/conf.c    |   29 +++++++++++++++++++++++++++++
 src/lxc/conf.h    |   12 ++++++++++++
 src/lxc/confile.c |   40 ++++++++++++++++++++++++++++++++++++++++
 src/lxc/start.c   |    6 ++++++
 4 files changed, 87 insertions(+)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index e8088bb..546d9fc 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -1572,6 +1572,7 @@ static int setup_private_host_hw_addr(char *veth1)
 struct lxc_conf *lxc_conf_init(void)
 {
 	struct lxc_conf *new;
+	int i;
 
 	new = 	malloc(sizeof(*new));
 	if (!new) {
@@ -1591,6 +1592,8 @@ struct lxc_conf *lxc_conf_init(void)
 	lxc_list_init(&new->network);
 	lxc_list_init(&new->mount_list);
 	lxc_list_init(&new->caps);
+	for (i=0; i<NUM_LXC_HOOKS; i++)
+		lxc_list_init(&new->hooks[i]);
 
 	return new;
 }
@@ -2012,6 +2015,7 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
 		return -1;
 	}
 
+	HOOK(name, "mount", lxc_conf);
 	if (setup_cgroup(name, &lxc_conf->cgroup)) {
 		ERROR("failed to setup the cgroups for '%s'", name);
 		return -1;
@@ -2051,3 +2055,28 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
 
 	return 0;
 }
+
+int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf)
+{
+	int which = -1;
+	struct lxc_list *it;
+
+	if (strcmp(hook, "pre-start") == 0)
+		which = LXCHOOK_PRESTART;
+	else if (strcmp(hook, "mount") == 0)
+		which = LXCHOOK_MOUNT;
+	else if (strcmp(hook, "start") == 0)
+		which = LXCHOOK_START;
+	else if (strcmp(hook, "post-stop") == 0)
+		which = LXCHOOK_POSTSTOP;
+	else
+		return -1;
+	lxc_list_for_each(it, &conf->hooks[which]) {
+		int ret;
+		char *hookname = it->elem;
+		ret = run_script(name, "lxc", hookname, hook, NULL);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index 09f55cb..c91872b 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -199,6 +199,9 @@ struct lxc_rootfs {
  * @console    : console data
  * @ttydir     : directory (under /dev) in which to create console and ttys
  */
+enum lxchooks {
+	LXCHOOK_PRESTART, LXCHOOK_MOUNT, LXCHOOK_START,
+	LXCHOOK_POSTSTOP, NUM_LXC_HOOKS};
 struct lxc_conf {
 	char *fstab;
 	int tty;
@@ -216,8 +219,17 @@ struct lxc_conf {
 	struct lxc_rootfs rootfs;
 	char *ttydir;
 	int close_all_fds;
+	struct lxc_list hooks[NUM_LXC_HOOKS];
 };
 
+int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf);
+/* we don't want to stick with the HOOK define, it's just to easily start */
+#define HOOK(name, which, conf) \
+	do { \
+		int hookret = run_lxc_hooks(name, which, conf); \
+		if (hookret) return -1; \
+	} while (0);
+
 /*
  * Initialize the lxc configuration structure
  */
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index b305aef..75cf4d7 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -55,6 +55,7 @@ static int config_rootfs(const char *, char *, struct lxc_conf *);
 static int config_rootfs_mount(const char *, char *, struct lxc_conf *);
 static int config_pivotdir(const char *, char *, struct lxc_conf *);
 static int config_utsname(const char *, char *, struct lxc_conf *);
+static int config_hook(const char *key, char *value, struct lxc_conf *lxc_conf);
 static int config_network_type(const char *, char *, struct lxc_conf *);
 static int config_network_flags(const char *, char *, struct lxc_conf *);
 static int config_network_link(const char *, char *, struct lxc_conf *);
@@ -91,6 +92,10 @@ static struct config config[] = {
 	{ "lxc.rootfs",               config_rootfs               },
 	{ "lxc.pivotdir",             config_pivotdir             },
 	{ "lxc.utsname",              config_utsname              },
+	{ "lxc.hook.pre-start",       config_hook                 },
+	{ "lxc.hook.mount",           config_hook                 },
+	{ "lxc.hook.start",           config_hook                 },
+	{ "lxc.hook.post-stop",       config_hook                 },
 	{ "lxc.network.type",         config_network_type         },
 	{ "lxc.network.flags",        config_network_flags        },
 	{ "lxc.network.link",         config_network_link         },
@@ -584,6 +589,41 @@ static int config_network_script(const char *key, char *value,
 	return -1;
 }
 
+static int add_hook(struct lxc_conf *lxc_conf, int which, char *hook)
+{
+	struct lxc_list *hooklist;
+
+	hooklist = malloc(sizeof(*hooklist));
+	if (!hooklist) {
+		free(hook);
+		return -1;
+	}
+	hooklist->elem = hook;
+	lxc_list_add_tail(&lxc_conf->hooks[which], hooklist);
+	return 0;
+}
+
+static int config_hook(const char *key, char *value,
+				 struct lxc_conf *lxc_conf)
+{
+	char *copy = strdup(value);
+	if (!copy) {
+		SYSERROR("failed to dup string '%s'", value);
+		return -1;
+	}
+	if (strcmp(key, "lxc.hook.pre-start") == 0)
+		return add_hook(lxc_conf, LXCHOOK_PRESTART, copy);
+	else if (strcmp(key, "lxc.hook.mount") == 0)
+		return add_hook(lxc_conf, LXCHOOK_MOUNT, copy);
+	else if (strcmp(key, "lxc.hook.start") == 0)
+		return add_hook(lxc_conf, LXCHOOK_START, copy);
+	else if (strcmp(key, "lxc.hook.post-stop") == 0)
+		return add_hook(lxc_conf, LXCHOOK_POSTSTOP, copy);
+	SYSERROR("Unknown key: %s", key);
+	free(copy);
+	return -1;
+}
+
 static int config_personality(const char *key, char *value,
 			      struct lxc_conf *lxc_conf)
 {
diff --git a/src/lxc/start.c b/src/lxc/start.c
index 920ff77..eba444d 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -357,6 +357,8 @@ struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf)
 		goto out_free_name;
 	}
 
+	HOOK(name, "pre-start", conf);
+
 	if (lxc_create_tty(name, conf)) {
 		ERROR("failed to create the ttys");
 		goto out_aborting;
@@ -401,6 +403,8 @@ void lxc_fini(const char *name, struct lxc_handler *handler)
 	lxc_set_state(name, handler, STOPPING);
 	lxc_set_state(name, handler, STOPPED);
 
+	HOOK(name, "post-stop", handler->conf);
+
 	/* reset mask set by setup_signal_fd */
 	if (sigprocmask(SIG_SETMASK, &handler->oldmask, NULL))
 		WARN("failed to restore sigprocmask");
@@ -519,6 +523,8 @@ static int do_start(void *data)
 
 	close(handler->sigfd);
 
+	HOOK(handler->name, "start", handler->conf);
+
 	/* after this call, we are in error because this
 	 * ops should not return as it execs */
 	if (handler->ops->start(handler, handler->data))
-- 
1.7.9.5





More information about the lxc-devel mailing list