diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in index aceeb1e12..994932eaf 100644 --- a/doc/lxc.container.conf.sgml.in +++ b/doc/lxc.container.conf.sgml.in @@ -1359,6 +1359,18 @@ mknod errno 0 + + + + + + + + A hook to be run when the container is destroyed. + + + + diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 9255b3488..eabba6ca8 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -163,7 +163,7 @@ return -1; #endif char *lxchook_names[NUM_LXC_HOOKS] = { - "pre-start", "pre-mount", "mount", "autodev", "start", "post-stop", "clone" }; + "pre-start", "pre-mount", "mount", "autodev", "start", "post-stop", "clone", "destroy" }; typedef int (*instantiate_cb)(struct lxc_handler *, struct lxc_netdev *); @@ -3977,6 +3977,8 @@ int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf, which = LXCHOOK_POSTSTOP; else if (strcmp(hook, "clone") == 0) which = LXCHOOK_CLONE; + else if (strcmp(hook, "destroy") == 0) + which = LXCHOOK_DESTROY; else return -1; lxc_list_for_each(it, &conf->hooks[which]) { @@ -4605,4 +4607,4 @@ struct lxc_list *sort_cgroup_settings(struct lxc_list* cgroup_settings) } return result; -} \ No newline at end of file +} diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 48f7fa253..d8b418e21 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -279,7 +279,8 @@ enum { */ enum lxchooks { LXCHOOK_PRESTART, LXCHOOK_PREMOUNT, LXCHOOK_MOUNT, LXCHOOK_AUTODEV, - LXCHOOK_START, LXCHOOK_POSTSTOP, LXCHOOK_CLONE, NUM_LXC_HOOKS}; + LXCHOOK_START, LXCHOOK_POSTSTOP, LXCHOOK_CLONE, LXCHOOK_DESTROY, + NUM_LXC_HOOKS}; extern char *lxchook_names[NUM_LXC_HOOKS]; struct saved_nic { diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 7e8b6a2d7..663b79142 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -132,6 +132,7 @@ static struct lxc_config_t config[] = { { "lxc.hook.start", config_hook }, { "lxc.hook.post-stop", config_hook }, { "lxc.hook.clone", config_hook }, + { "lxc.hook.destroy", config_hook }, { "lxc.hook", config_hook }, { "lxc.network.type", config_network_type }, { "lxc.network.flags", config_network_flags }, @@ -1002,6 +1003,8 @@ static int config_hook(const char *key, const char *value, return add_hook(lxc_conf, LXCHOOK_POSTSTOP, copy); else if (strcmp(key, "lxc.hook.clone") == 0) return add_hook(lxc_conf, LXCHOOK_CLONE, copy); + else if (strcmp(key, "lxc.hook.destroy") == 0) + return add_hook(lxc_conf, LXCHOOK_DESTROY, copy); SYSERROR("Unknown key: %s", key); free(copy); return -1; diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 8999f4423..fd56327e6 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -2154,6 +2154,7 @@ static bool container_destroy(struct lxc_container *c) { bool bret = false; int ret; + struct lxc_conf *conf = c->lxc_conf; if (!c || !do_lxcapi_is_defined(c)) return false; @@ -2167,19 +2168,47 @@ static bool container_destroy(struct lxc_container *c) goto out; } - if (current_config && c->lxc_conf == current_config) { - current_config = NULL; - if (c->lxc_conf->logfd != -1) { - close(c->lxc_conf->logfd); - c->lxc_conf->logfd = -1; + if (!lxc_list_empty(&conf->hooks[LXCHOOK_DESTROY])) { + /* Start of environment variable setup for hooks */ + if (setenv("LXC_NAME", c->name, 1)) { + SYSERROR("failed to set environment variable for container name"); + } + if (setenv("LXC_CONFIG_FILE", conf->rcfile, 1)) { + SYSERROR("failed to set environment variable for config path"); + } + if (setenv("LXC_ROOTFS_MOUNT", conf->rootfs.mount, 1)) { + SYSERROR("failed to set environment variable for rootfs mount"); + } + if (setenv("LXC_ROOTFS_PATH", conf->rootfs.path, 1)) { + SYSERROR("failed to set environment variable for rootfs mount"); + } + if (conf->console.path && setenv("LXC_CONSOLE", conf->console.path, 1)) { + SYSERROR("failed to set environment variable for console path"); + } + if (conf->console.log_path && setenv("LXC_CONSOLE_LOGPATH", conf->console.log_path, 1)) { + 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)) { + ERROR("Error executing clone hook for %s", c->name); + goto out; } } - if (c->lxc_conf && c->lxc_conf->rootfs.path && c->lxc_conf->rootfs.mount) { + if (current_config && conf == current_config) { + current_config = NULL; + if (conf->logfd != -1) { + close(conf->logfd); + conf->logfd = -1; + } + } + + if (conf && conf->rootfs.path && conf->rootfs.mount) { if (am_unpriv()) - ret = userns_exec_1(c->lxc_conf, bdev_destroy_wrapper, c->lxc_conf); + ret = userns_exec_1(conf, bdev_destroy_wrapper, conf); else - ret = do_bdev_destroy(c->lxc_conf); + ret = do_bdev_destroy(conf); if (ret < 0) { ERROR("Error destroying rootfs for %s", c->name); goto out; @@ -2192,7 +2221,7 @@ static bool container_destroy(struct lxc_container *c) char *path = alloca(strlen(p1) + strlen(c->name) + 2); sprintf(path, "%s/%s", p1, c->name); if (am_unpriv()) - ret = userns_exec_1(c->lxc_conf, lxc_rmdir_onedev_wrapper, path); + ret = userns_exec_1(conf, lxc_rmdir_onedev_wrapper, path); else ret = lxc_rmdir_onedev(path, "snaps"); if (ret < 0) {