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

Serge Hallyn serge.hallyn at canonical.com
Thu Jun 21 15:32:01 UTC 2012


Hi,

any comments on this patch?  If there are no major objections to the
fundamental patch (the lxc.conf entries and the basic hooks), I will go
ahead and get it into our ubuntu package to get it some more testing.

thanks,
-serge

Quoting Serge Hallyn (serge.hallyn at canonical.com):
> 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
> 
> 
> ------------------------------------------------------------------------------
> Live Security Virtual Conference
> Exclusive live event will cover all the ways today's security and 
> threat landscape has changed and how IT managers can respond. Discussions 
> will include endpoint security, mobile security and the latest in malware 
> threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
> _______________________________________________
> Lxc-devel mailing list
> Lxc-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/lxc-devel




More information about the lxc-users mailing list