代码拉取完成,页面将自动刷新
同步操作将从 src-openEuler/lxc 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
From 52aa8985248200041b2a093634a8c36cb4bb8414 Mon Sep 17 00:00:00 2001
From: haozi007 <[email protected]>
Date: Tue, 14 Apr 2020 18:33:53 +0800
Subject: [PATCH 25/49] support oci hooks
Signed-off-by: haozi007 <[email protected]>
---
src/lxc/conf.c | 542 +++++++++++++++++++++++++++++++++++++++++++++++++
src/lxc/conf.h | 17 ++
src/lxc/lxccontainer.c | 110 ++++++++++
src/lxc/lxccontainer.h | 28 +++
src/lxc/start.c | 277 +++++++++++++++++++++++++
src/lxc/start.h | 8 +
src/lxc/sync.h | 4 +
src/lxc/utils.c | 38 ++++
src/lxc/utils.h | 2 +
9 files changed, 1026 insertions(+)
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index e0a6f98..71fd6f9 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -33,6 +33,11 @@
#include <time.h>
#include <unistd.h>
+#ifdef HAVE_ISULAD
+#include <pthread.h>
+#include "sync.h"
+#endif
+
#include "af_unix.h"
#include "caps.h"
#include "cgroup.h"
@@ -121,7 +126,14 @@ char *lxchook_names[NUM_LXC_HOOKS] = {
"post-stop",
"clone",
"destroy",
+#ifdef HAVE_ISULAD
+ "start-host",
+ "oci-prestart",
+ "oci-poststart",
+ "oci-poststop"
+#else
"start-host"
+#endif
};
struct mount_opt {
@@ -3947,6 +3959,530 @@ static int setup_rootfs_mountopts(const struct lxc_rootfs *rootfs)
}
return 0;
}
+
+struct oci_hook_conf {
+ defs_hook *ocihook;
+
+ int errfd;
+ int which;
+};
+
+struct wait_conf {
+ pid_t pid;
+ unsigned long long startat;
+ int timeout;
+ int errfd;
+ int which;
+};
+
+static char* generate_json_str(const char *name, const char *lxcpath, const char *rootfs)
+{
+ char *cpid = NULL;
+ char *inmsg = NULL;
+ int rc = 0, ret = 0;
+ size_t size;
+
+ if (!name || !lxcpath || !rootfs) {
+ ERROR("Invalid arguments");
+ return NULL;
+ }
+ cpid = getenv("LXC_PID");
+ if (!cpid) {
+ ERROR("Get container %s pid failed: %s", name, strerror(errno));
+ cpid = "-1";
+ }
+
+ if ((strlen(name) + strlen(cpid) + strlen(rootfs) + strlen(lxcpath) + strlen(name)) >
+ SIZE_MAX - (strlen("{\"ociVersion\":\"\",\"id\":\"\",\"pid\":,\"root\":\"\",\"bundle\":\"\"}") - 1 - 1)) {
+ ERROR("Out of memory");
+ ret = -1;
+ goto out_free;
+ }
+
+ // {"ociVersion":"","id":"xxx","pid":777,"root":"xxx","bundle":"xxx"}
+ size = strlen("{\"ociVersion\":\"\",\"id\":\"\",\"pid\":,\"root\":\"\",\"bundle\":\"\"}") +
+ strlen(name) + strlen(cpid) + strlen(rootfs) + strlen(lxcpath) + 1 + strlen(name) + 1;
+ inmsg = malloc(size);
+ if (inmsg == NULL) {
+ ERROR("Out of memory");
+ ret = -1;
+ goto out_free;
+ }
+ rc = snprintf(inmsg, size,
+ "{\"ociVersion\":\"\",\"id\":\"%s\",\"pid\":%s,\"root\":\"%s\",\"bundle\":\"%s/%s\"}",
+ name, cpid, rootfs, lxcpath, name);
+ if (rc < 0 || rc >= size) {
+ ERROR("Create json string failed");
+ ret = -1;
+ }
+
+out_free:
+ if (ret) {
+ free(inmsg);
+ inmsg = NULL;
+ }
+ return inmsg;
+}
+
+static char **merge_ocihook_env(char **oldenvs, size_t env_len, size_t *merge_env_len)
+{
+ char **result = NULL;
+ size_t result_len = env_len;
+ size_t i, j;
+ char *tmpenv = NULL;
+ char *lxc_envs[] = {"LD_LIBRARY_PATH", "PATH", "LXC_CGNS_AWARE", "LXC_PID", "LXC_ROOTFS_MOUNT",
+ "LXC_CONFIG_FILE", "LXC_CGROUP_PATH", "LXC_ROOTFS_PATH", "LXC_NAME"
+ };
+ char *lxcenv_buf = NULL;
+
+ if (result_len > SIZE_MAX - (sizeof(lxc_envs) / sizeof(char *)) - 1)
+ return NULL;
+ result_len += (sizeof(lxc_envs) / sizeof(char *)) + 1;
+ result = malloc(sizeof(char *) * result_len);
+ if (result == NULL)
+ return NULL;
+ memset(result, 0, sizeof(char *) * result_len);
+
+ for(i = 0; i < env_len; i++) {
+ if (oldenvs[i])
+ result[i] = safe_strdup(oldenvs[i]);
+ }
+
+ for(j = 0; j < (sizeof(lxc_envs) / sizeof(char *)); j++) {
+ size_t env_buf_len = 0;
+ tmpenv = getenv(lxc_envs[j]);
+ if (tmpenv && i < (result_len - 1)) {
+ if (strlen(tmpenv) > (SIZE_MAX - 1 - 1 - strlen(lxc_envs[j]))) {
+ lxc_free_array((void **)result, free);
+ return NULL;
+ }
+ env_buf_len = ((strlen(tmpenv) + 1) + strlen(lxc_envs[j])) + 1;
+ lxcenv_buf = malloc(env_buf_len);
+ if (lxcenv_buf == NULL) {
+ lxc_free_array((void **)result, free);
+ return NULL;
+ }
+ if (snprintf(lxcenv_buf, env_buf_len, "%s=%s", lxc_envs[j], tmpenv) < 0) {
+ free(lxcenv_buf);
+ continue;
+ }
+ result[i++] = lxcenv_buf;
+ lxcenv_buf = NULL;
+ }
+ }
+
+ *merge_env_len = i;
+ return result;
+}
+
+static struct lxc_popen_FILE *lxc_popen_ocihook(const char *commandpath, char **args, int args_len,
+ char **envs, int env_len, const char *instr)
+{
+ int ret;
+ struct lxc_popen_FILE *fp = NULL;
+ int pipe_fds[2] = {-1, -1};
+ int pipe_msg[2] = {-1, -1};
+ pid_t child_pid;
+
+ ret = pipe2(pipe_fds, O_CLOEXEC | O_NONBLOCK);
+ if (ret < 0)
+ return NULL;
+
+ ret = pipe2(pipe_msg, O_CLOEXEC | O_NONBLOCK);
+ if (ret < 0) {
+ ERROR("Pipe msg failure");
+ close(pipe_fds[0]);
+ close(pipe_fds[1]);
+ return NULL;
+ }
+
+ child_pid = fork();
+ if (child_pid < 0)
+ goto on_error;
+
+ if (child_pid == 0) {
+ close(pipe_msg[1]);
+ if (pipe_msg[0] != STDIN_FILENO)
+ dup2(pipe_msg[0], STDIN_FILENO);
+ else {
+ if (fcntl(pipe_msg[0], F_SETFD, 0) != 0) {
+ fprintf(stderr, "Failed to remove FD_CLOEXEC from fd.");
+ exit(127);
+ }
+ }
+ close(pipe_msg[0]);
+
+ close(pipe_fds[0]);
+
+ /* duplicate stdout */
+ if (pipe_fds[1] != STDOUT_FILENO)
+ ret = dup2(pipe_fds[1], STDOUT_FILENO);
+ else
+ ret = fcntl(pipe_fds[1], F_SETFD, 0);
+ if (ret < 0) {
+ close(pipe_fds[1]);
+ _exit(EXIT_FAILURE);
+ }
+
+ /* duplicate stderr */
+ if (pipe_fds[1] != STDERR_FILENO)
+ ret = dup2(pipe_fds[1], STDERR_FILENO);
+ else
+ ret = fcntl(pipe_fds[1], F_SETFD, 0);
+ close(pipe_fds[1]);
+ if (ret < 0)
+ _exit(EXIT_FAILURE);
+
+ if (lxc_check_inherited(NULL, true, NULL, 0) != 0) {
+ fprintf(stderr, "check inherited fd failed");
+ exit(127);
+ }
+
+ /*
+ * Unblock signals.
+ * This is the main/only reason
+ * why we do our lousy popen() emulation.
+ */
+ {
+ sigset_t mask;
+ sigfillset(&mask);
+ sigprocmask(SIG_UNBLOCK, &mask, NULL);
+ }
+
+ if (env_len > 0)
+ execvpe(commandpath, args, envs);
+ else
+ execvp(commandpath, args);
+ fprintf(stderr, "fork/exec %s: %s", commandpath, strerror(errno));
+ exit(127);
+ }
+
+ /* parent */
+
+ close(pipe_fds[1]);
+ pipe_fds[1] = -1;
+
+ close(pipe_msg[0]);
+ pipe_msg[0]= -1;
+ if (instr) {
+ size_t len = strlen(instr);
+ if (lxc_write_nointr(pipe_msg[1], instr, len) != len) {
+ WARN("Write instr: %s failed", instr);
+ }
+ }
+ close(pipe_msg[1]);
+ pipe_msg[1]= -1;
+
+ fp = calloc(1, sizeof(*fp));
+ if (!fp) {
+ ERROR("Failed to allocate memory");
+ goto on_error;
+ }
+
+ fp->child_pid = child_pid;
+ fp->pipe = pipe_fds[0];
+
+ return fp;
+
+on_error:
+
+ if (pipe_fds[0] >= 0)
+ close(pipe_fds[0]);
+
+ if (pipe_fds[1] >= 0)
+ close(pipe_fds[1]);
+
+ if (pipe_msg[0] >= 0)
+ close(pipe_msg[0]);
+
+ if (pipe_msg[1] >= 0)
+ close(pipe_msg[1]);
+
+ if (fp)
+ free(fp);
+
+ return NULL;
+}
+
+void* wait_ocihook_timeout(void *arg)
+{
+ bool alive = false;
+ struct wait_conf *conf = (struct wait_conf *)arg;
+
+ if (!conf || conf->timeout < 1)
+ goto out;
+
+ sleep(conf->timeout);
+
+ alive = lxc_process_alive(conf->pid, conf->startat);
+
+ if (alive) {
+ ERROR("%s:%d: running %s hook caused \"hook ran past specified timeout of %.1fs\"",
+ __FILE__, __LINE__, lxchook_names[conf->which],
+ (double)conf->timeout);
+
+ lxc_write_error_message(conf->errfd, "%s:%d: running %s hook caused \"hook ran past specified timeout of %.1fs\".",
+ __FILE__, __LINE__, lxchook_names[conf->which],
+ (double)conf->timeout);
+
+ if (kill(conf->pid, SIGKILL) && errno != ESRCH) {
+ ERROR("Send kill signal failed");
+ goto out;
+ }
+ }
+
+out:
+ free(conf);
+ return ((void *)0);
+}
+
+static int run_ocihook_buffer(struct oci_hook_conf *oconf, const char *inmsg)
+{
+ struct lxc_popen_FILE *f;
+ char output[LXC_LOG_BUFFER_SIZE] = {0};
+ int ret;
+ pthread_t ptid;
+ int err;
+ struct wait_conf *conf = NULL;
+ pthread_attr_t attr;
+ char *buffer = oconf->ocihook->path;
+ char *err_args_msg = NULL;
+ char *err_envs_msg = NULL;
+ char **hookenvs = NULL;
+ size_t hookenvs_len = 0;
+
+ hookenvs = merge_ocihook_env(oconf->ocihook->env, oconf->ocihook->env_len, &hookenvs_len);
+ if (!hookenvs) {
+ ERROR("Out of memory.");
+ return -1;
+ }
+
+ f = lxc_popen_ocihook(buffer, oconf->ocihook->args, oconf->ocihook->args_len, hookenvs, hookenvs_len, inmsg);
+ lxc_free_array((void **)hookenvs, free);
+ if (!f) {
+ SYSERROR("Failed to popen() %s.", buffer);
+ return -1;
+ }
+
+ conf = malloc(sizeof(struct wait_conf));
+ if (conf == NULL) {
+ SYSERROR("Failed to malloc.");
+ goto on_error;
+ }
+
+ memset(conf, 0x00, sizeof(struct wait_conf));
+
+ conf->pid = f->child_pid;
+ conf->startat = lxc_get_process_startat(conf->pid);
+
+ INFO("hook_conf timeout %d", oconf->ocihook->timeout);
+ if(oconf->ocihook->timeout > 0)
+ conf->timeout = oconf->ocihook->timeout;
+ else {
+ conf->timeout = 30;
+ INFO("Set hook timeout 30s");
+ }
+ conf->errfd = oconf->errfd;
+ conf->which = oconf->which;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ err = pthread_create(&ptid, &attr, wait_ocihook_timeout, conf);
+ if (err != 0) {
+ ERROR("Create wait timeout thread failed");
+ free(conf);
+ goto on_error;
+ }
+
+ ret = lxc_wait_for_pid_status(f->child_pid);
+
+ lxc_read_nointr(f->pipe, output, sizeof(output) - 1);
+ close(f->pipe);
+ free(f);
+
+ if (ret == -1) {
+ SYSERROR("Script exited with error.");
+ goto print_hook;
+ } else if (WIFEXITED(ret) && WEXITSTATUS(ret) != 0) {
+ ERROR("Script exited with status %d. output: %s", WEXITSTATUS(ret), output);
+ lxc_write_error_message(oconf->errfd, "%s:%d: running %s hook caused \"error running hook: exit status %d, output: %s\".",
+ __FILE__, __LINE__,
+ (oconf->which >= NUM_LXC_HOOKS) ? "invalid type" : lxchook_names[oconf->which],
+ WEXITSTATUS(ret), output);
+
+ goto print_hook;
+ } else if (WIFSIGNALED(ret)) {
+ ERROR("Script terminated by signal %d.", WTERMSIG(ret));
+ lxc_write_error_message(oconf->errfd, "%s:%d: running %s hook caused \"error running hook: Script terminated by signal %d\".",
+ __FILE__, __LINE__,
+ (oconf->which >= NUM_LXC_HOOKS) ? "invalid type" : lxchook_names[oconf->which],
+ WTERMSIG(ret));
+
+ goto print_hook;
+ }
+
+ return 0;
+
+on_error:
+ if (f) {
+ if (f->pipe >= 0)
+ close(f->pipe);
+ free(f);
+ }
+
+print_hook:
+ if (oconf->ocihook->args)
+ err_args_msg = lxc_string_join(" ", (const char **)oconf->ocihook->args, false);
+ if (oconf->ocihook->env)
+ err_envs_msg = lxc_string_join(" ", (const char **)oconf->ocihook->env, false);
+ ERROR("Hook script command: \"%s\", args: \"%s\", envs: \"%s\", timeout: %d.",
+ buffer, err_args_msg ? err_args_msg : "",
+ err_envs_msg ? err_envs_msg : "", oconf->ocihook->timeout);
+
+ free(err_args_msg);
+ free(err_envs_msg);
+ return -1;
+}
+
+static int run_ocihook_script_argv(const char *name, const char *section,
+ struct oci_hook_conf *oconf,
+ const char *lxcpath, const char *rootfs)
+{
+ int ret;
+ const char *script = oconf->ocihook->path;
+ char *inmsg = NULL;
+
+ INFO("Executing script \"%s\" for container \"%s\", config section \"%s\".",
+ script, name, section);
+
+ inmsg = generate_json_str(name, lxcpath, rootfs);
+ if (!inmsg) {
+ return -1;
+ }
+
+ ret = run_ocihook_buffer(oconf, inmsg);
+ free(inmsg);
+ inmsg = NULL;
+ return ret;
+}
+
+static char *get_root_path(const char *path, const char *backend)
+{
+ char *ret = NULL;
+ char *tmp = NULL;
+
+ if (!path) {
+ ret = safe_strdup("/");
+ return ret;
+ }
+ if (!backend) {
+ goto default_out;
+ }
+
+ if (strcmp(backend, "aufs") == 0 ||
+ strcmp(backend, "overlayfs") == 0 ||
+ strcmp(backend, "loop") == 0) {
+ tmp = strrchr(path, ':');
+ if (tmp == NULL) {
+ ERROR("Invalid root path format");
+ return NULL;
+ }
+ tmp++;
+ ret = safe_strdup(tmp);
+ return ret;
+ }
+
+default_out:
+ ret = safe_strdup(path);
+ return ret;
+}
+
+static int do_run_oci_hooks(const char *name, const char *lxcpath, struct lxc_conf *lc, int which, int errfd)
+{
+ struct oci_hook_conf work_conf = {0};
+ size_t i;
+ int ret = 0;
+ int nret = 0;
+ char *rootpath = NULL;
+
+ if (!lc) {
+ return -1;
+ }
+ if (!lc->ocihooks) {
+ return 0;
+ }
+
+ rootpath = get_root_path(lc->rootfs.path, lc->rootfs.bdev_type);
+ if (!rootpath) {
+ ERROR("Get container %s rootpath failed.", name);
+ return -1;
+ }
+
+ work_conf.errfd = errfd;
+ work_conf.which = which;
+ switch (which) {
+ case OCI_HOOK_PRESTART:
+ for (i = 0; i < lc->ocihooks->prestart_len; i++) {
+ work_conf.ocihook = lc->ocihooks->prestart[i];
+ ret = run_ocihook_script_argv(name, "lxc", &work_conf, lxcpath, rootpath);
+ if (ret != 0)
+ break;
+ }
+ break;
+ case OCI_HOOK_POSTSTART:
+ for (i = 0; i < lc->ocihooks->poststart_len; i++) {
+ work_conf.ocihook = lc->ocihooks->poststart[i];
+ nret = run_ocihook_script_argv(name, "lxc", &work_conf, lxcpath, rootpath);
+ if (nret != 0)
+ WARN("running poststart hook %zu failed, ContainerId: %s", i, name);
+ }
+ break;
+ case OCI_HOOK_POSTSTOP:
+ for (i = 0; i < lc->ocihooks->poststop_len; i++) {
+ work_conf.ocihook = lc->ocihooks->poststop[i];
+ nret = run_ocihook_script_argv(name, "lxc", &work_conf, lxcpath, rootpath);
+ if (nret != 0)
+ WARN("running poststart hook %zu failed, ContainerId: %s", i, name);
+ }
+ break;
+ default:
+ ret = -1;
+ }
+ if (rootpath)
+ free(rootpath);
+ return ret;
+}
+
+int run_oci_hooks(const char *name, const char *hookname, struct lxc_conf *conf, const char *lxcpath)
+{
+ int which = -1;
+
+ if (strcmp(hookname, "oci-prestart") == 0) {
+ which = OCI_HOOK_PRESTART;
+ if (!lxcpath) {
+ ERROR("oci hook require lxcpath");
+ return -1;
+ }
+ return do_run_oci_hooks(name, lxcpath, conf, which, conf->errpipe[1]);
+ } else if (strcmp(hookname, "oci-poststart") == 0) {
+ which = OCI_HOOK_POSTSTART;
+ if (!lxcpath) {
+ ERROR("oci hook require lxcpath");
+ return -1;
+ }
+ return do_run_oci_hooks(name, lxcpath, conf, which, conf->errpipe[1]);
+ } else if (strcmp(hookname, "oci-poststop") == 0) {
+ which = OCI_HOOK_POSTSTOP;
+ if (!lxcpath) {
+ ERROR("oci hook require lxcpath");
+ return -1;
+ }
+ return do_run_oci_hooks(name, lxcpath, conf, which, conf->errpipe[1]);
+ } else
+ return -1;
+
+ return 0;
+}
#endif
int lxc_setup(struct lxc_handler *handler)
@@ -4083,6 +4619,12 @@ int lxc_setup(struct lxc_handler *handler)
if (ret < 0)
return log_error(-1, "Failed to \"/proc\" LSMs");
+#ifdef HAVE_ISULAD
+ /* Ask father to run oci prestart hooks and wait for him to finish. */
+ if (lxc_sync_barrier_parent(handler, LXC_SYNC_OCI_PRESTART_HOOK)) {
+ return log_error(-1, "Failed to sync parent to start host hook");
+ }
+#endif
ret = lxc_setup_rootfs_switch_root(&lxc_conf->rootfs);
if (ret < 0)
return log_error(-1, "Failed to pivot root into rootfs");
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index 22c554d..61c3383 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -23,6 +23,10 @@
#include "start.h"
#include "terminal.h"
+#ifdef HAVE_ISULAD
+#include "oci_runtime_hooks.h"
+#endif
+
#if HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
@@ -212,6 +216,11 @@ enum lxchooks {
LXCHOOK_CLONE,
LXCHOOK_DESTROY,
LXCHOOK_START_HOST,
+#ifdef HAVE_ISULAD
+ OCI_HOOK_PRESTART,
+ OCI_HOOK_POSTSTART,
+ OCI_HOOK_POSTSTOP,
+#endif
NUM_LXC_HOOKS
};
@@ -433,6 +442,11 @@ struct lxc_conf {
} shmount;
#ifdef HAVE_ISULAD
+ /*
+ * isulad: support oci hook
+ * */
+ oci_runtime_spec_hooks *ocihooks;
+
/* isulad add: init args used to repalce init_cmd*/
char **init_argv;
size_t init_argc;
@@ -447,6 +461,8 @@ struct lxc_conf {
char *errmsg; /* record error messages */
+ int errpipe[2];//pipdfd for get error message of child or grandchild process.
+
char *systemd; //systemd value
#endif
@@ -535,5 +551,6 @@ int lxc_clear_init_args(struct lxc_conf *lxc_conf);
int lxc_clear_populate_devices(struct lxc_conf *c);
int lxc_clear_rootfs_masked_paths(struct lxc_conf *c);
int lxc_clear_rootfs_ro_paths(struct lxc_conf *c);
+int run_oci_hooks(const char *name, const char *hookname, struct lxc_conf *conf, const char *lxcpath);
#endif
#endif /* __LXC_CONF_H */
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 821cfa1..9b3ab75 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -288,6 +288,8 @@ static void lxc_container_free(struct lxc_container *c)
#ifdef HAVE_ISULAD
free(c->exit_fifo);
c->exit_fifo = NULL;
+ free(c->ocihookfile);
+ c->ocihookfile = NULL;
#endif
free(c);
@@ -632,6 +634,66 @@ static bool load_config_locked(struct lxc_container *c, const char *fname)
return true;
}
+#ifdef HAVE_ISULAD
+static bool load_ocihooks_locked(struct lxc_container *c)
+{
+ parser_error err = NULL;
+ oci_runtime_spec_hooks *hooks = NULL;
+
+ if (!c->lxc_conf)
+ c->lxc_conf = lxc_conf_init();
+
+ if (!c->lxc_conf)
+ return false;
+
+ hooks = oci_runtime_spec_hooks_parse_file(c->ocihookfile, NULL, &err);
+ if (!hooks) {
+ fprintf(stderr, "parse oci hooks config failed: %s\n", err);
+ free(err);
+ return true;
+ }
+ c->lxc_conf->ocihooks = hooks;
+
+ if (err)
+ free(err);
+ return true;
+}
+
+/*
+ * isulad: set oci hook file path
+ * */
+static bool set_oci_hook_config_filename(struct lxc_container *c)
+{
+#define OCI_HOOK_JSON_FILE_NAME "ocihooks.json"
+ char *newpath = NULL;
+ int len, ret;
+
+ if (!c->config_path)
+ return false;
+
+ /* $lxc_path + "/" + c->name + "/" + "config" + '\0' */
+ if (strlen(c->config_path) + strlen(c->name) > SIZE_MAX - strlen(OCI_HOOK_JSON_FILE_NAME) - 3)
+ return false;
+ len = strlen(c->config_path) + strlen(c->name) + strlen(OCI_HOOK_JSON_FILE_NAME) + 3;
+
+ newpath = malloc(len);
+ if (newpath == NULL)
+ return false;
+
+ ret = snprintf(newpath, len, "%s/%s/%s", c->config_path, c->name, OCI_HOOK_JSON_FILE_NAME);
+ if (ret < 0 || ret >= len) {
+ fprintf(stderr, "Error printing out config file name\n");
+ free(newpath);
+ return false;
+ }
+
+ free(c->ocihookfile);
+ c->ocihookfile = newpath;
+
+ return true;
+}
+#endif
+
static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file)
{
int lret;
@@ -665,6 +727,11 @@ static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file)
ret = load_config_locked(c, fname);
+#ifdef HAVE_ISULAD
+ if (ret && file_exists(c->ocihookfile))
+ ret = load_ocihooks_locked(c);
+#endif
+
if (need_disklock)
container_disk_unlock(c);
else
@@ -5492,6 +5559,40 @@ static bool do_lxcapi_set_exec_terminal_winch(struct lxc_container *c, const cha
}
WRAP_API_3(bool, lxcapi_set_exec_terminal_winch, const char *, unsigned int, unsigned int)
+
+/* isulad add clean resources */
+static bool do_lxcapi_clean_container_resource(struct lxc_container *c, pid_t pid)
+{
+ int ret;
+
+ if (!c)
+ return false;
+
+ ret = do_lxcapi_clean_resource(c->name, c->config_path, c->lxc_conf, pid);
+ if (ret)
+ ERROR("Failed to clean container %s resource", c->name);
+ return ret == 0;
+
+}
+
+WRAP_API_1(bool, lxcapi_clean_container_resource, pid_t)
+
+/* isulad get coantainer pids */
+static bool do_lxcapi_get_container_pids(struct lxc_container *c, pid_t **pids,size_t *pids_len)
+{
+ int ret;
+
+ if (!c)
+ return false;
+
+ ret = do_lxcapi_get_pids(c->name, c->config_path, c->lxc_conf, pids,pids_len);
+ if (ret)
+ ERROR("Failed to get container %s pids", c->name);
+ return ret == 0;
+
+}
+
+WRAP_API_2(bool, lxcapi_get_container_pids, pid_t **,size_t *)
#endif
struct lxc_container *lxc_container_new(const char *name, const char *configpath)
@@ -5547,6 +5648,13 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
goto err;
}
+#ifdef HAVE_ISULAD
+ if (!set_oci_hook_config_filename(c)) {
+ fprintf(stderr, "Error allocating oci hooks file pathname\n");
+ goto err;
+ }
+#endif
+
if (file_exists(c->configfile) && !lxcapi_load_config(c, NULL)) {
fprintf(stderr, "Failed to load config for %s\n", name);
goto err;
@@ -5643,6 +5751,8 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
c->set_exec_terminal_winch = lxcapi_set_exec_terminal_winch;
c->want_disable_pty = lxcapi_want_disable_pty;
c->want_open_stdin = lxcapi_want_open_stdin;
+ c->clean_container_resource = lxcapi_clean_container_resource;
+ c->get_container_pids = lxcapi_get_container_pids;
#endif
return c;
diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
index de2ee46..f1621f9 100644
--- a/src/lxc/lxccontainer.h
+++ b/src/lxc/lxccontainer.h
@@ -118,6 +118,13 @@ struct lxc_container {
/*! Whether container wishes to keep stdin active */
bool open_stdin;
+
+ /*!
+ * \private
+ * isulad: support oci hook from json file
+ * full path of json file
+ * */
+ char *ocihookfile;
#endif
/*!
@@ -935,6 +942,27 @@ struct lxc_container {
* \return \c true on success, else \c false.
*/
bool (*want_open_stdin)(struct lxc_container *c, bool state);
+
+ /*! isulad add
+ * \brief An API call to clean resources of container
+ *
+ * \param c Container.
+ * \param pid Value of container process.
+ *
+ * \return \c true on success, else \c false.
+ */
+ bool (*clean_container_resource) (struct lxc_container *c, pid_t pid);
+
+ /*! isulad add
+ * \brief An API call to get container pids
+ *
+ * \param c Container.
+ * \param pids Value of container pids.
+ * \param pids_len Value of container pids len.
+ * \param pid Value of container pid.
+ * \return \c true on success, else \c false.
+ */
+ bool (*get_container_pids)(struct lxc_container *c,pid_t **pids,size_t *pids_len);
#endif
};
diff --git a/src/lxc/start.c b/src/lxc/start.c
index f6a96b4..4f45776 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -2239,6 +2239,20 @@ static int lxc_spawn(struct lxc_handler *handler)
ERROR("Failed to run lxc.hook.start-host");
goto out_delete_net;
}
+#ifdef HAVE_ISULAD
+ /* isulad: Run oci prestart hook at here */
+ ret = run_oci_hooks(name, "oci-prestart", conf, lxcpath);
+ if (ret < 0) {
+ ERROR("Failed to run oci prestart hooks");
+ goto out_delete_net;
+ }
+
+ /* Tell the child to continue its initialization. We'll get
+ * LXC_SYNC_POST_OCI_PRESTART_HOOK when it is ready for us to run oci prestart hooks.
+ */
+ if (lxc_sync_barrier_child(handler, LXC_SYNC_POST_OCI_PRESTART_HOOK))
+ goto out_delete_net;
+#endif
/* Tell the child to complete its initialization and wait for it to exec
* or return an error. (The child will never return
@@ -2282,6 +2296,15 @@ static int lxc_spawn(struct lxc_handler *handler)
if (ret < 0)
goto out_abort;
+#ifdef HAVE_ISULAD
+ /* isulad: Run oci prestart hook at here */
+ ret = run_oci_hooks(name, "oci-poststart", conf, lxcpath);
+ if (ret < 0) {
+ ERROR("Failed to run oci poststart hooks");
+ goto out_abort;
+ }
+#endif
+
ret = lxc_set_state(name, handler, RUNNING);
if (ret < 0) {
ERROR("Failed to set state to \"%s\"", lxc_state2str(RUNNING));
@@ -2592,3 +2615,257 @@ static bool do_destroy_container(struct lxc_handler *handler)
return storage_destroy(handler->conf);
}
+
+#ifdef HAVE_ISULAD
+/*isulad: set env for clean resources */
+static int clean_resource_set_env(struct lxc_handler *handler)
+{
+ const char *name = handler->name;
+ struct lxc_conf *conf = handler->conf;
+ char bufstr[PATH_MAX + 1];
+ int i = 0;
+ int j = 0;
+ int len = 2; //set "LXC_PID" and "LXC_CGNS_AWARE"
+
+ if (conf == NULL || conf->ocihooks == NULL || conf->ocihooks->poststop_len == 0) {
+ return 0;
+ }
+
+ if (name) {
+ len++;
+ }
+ if (conf->rcfile) {
+ len++;
+ }
+ if (conf->rootfs.mount) {
+ len++;
+ }
+ if (conf->rootfs.path) {
+ len++;
+ }
+ if (conf->console.path) {
+ len++;
+ }
+ if (conf->console.log_path) {
+ len++;
+ }
+ if (handler->cgroup_ops->container_cgroup) {
+ len++;
+ }
+
+ for (; i < conf->ocihooks->poststop_len; i++) {
+ size_t cap = conf->ocihooks->poststop[i]->env_len;
+ size_t newcap = cap + len + 1;
+ if (lxc_grow_array((void ***)&(conf->ocihooks->poststop[i]->env), &cap, newcap, 1) != 0) {
+ return -1;
+ }
+ j = conf->ocihooks->poststop[i]->env_len;
+ /* Start of environment variable setup for hooks. */
+ if (name) {
+ snprintf(bufstr, PATH_MAX + 1, "LXC_NAME=%s", name);
+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr);
+ }
+ if (conf->rcfile) {
+ snprintf(bufstr, PATH_MAX + 1, "LXC_CONFIG_FILE=%s", conf->rcfile);
+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr);
+ }
+ if (conf->rootfs.mount) {
+ snprintf(bufstr, PATH_MAX + 1, "LXC_ROOTFS_MOUNT=%s", conf->rootfs.mount);
+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr);
+ }
+ if (conf->rootfs.path) {
+ snprintf(bufstr, PATH_MAX + 1, "LXC_ROOTFS_PATH=%s", conf->rootfs.path);
+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr);
+ }
+ if (conf->console.path) {
+ snprintf(bufstr, PATH_MAX + 1, "LXC_CONSOLE=%s", conf->console.path);
+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr);
+ }
+ if (conf->console.log_path) {
+ snprintf(bufstr, PATH_MAX + 1, "LXC_CONSOLE_LOGPATH=%s", conf->console.log_path);
+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr);
+ }
+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup("LXC_CGNS_AWARE=1");
+
+ snprintf(bufstr, PATH_MAX + 1, "LXC_PID=%d", handler->pid);
+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr);
+ if (handler->cgroup_ops->container_cgroup) {
+ snprintf(bufstr, PATH_MAX + 1, "LXC_CGROUP_PATH=%s", handler->cgroup_ops->container_cgroup);
+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr);
+ }
+ conf->ocihooks->poststop[i]->env_len = j;
+ /* End of environment variable setup for hooks. */
+ }
+ return 0;
+}
+
+/*isulad: init handler for clean */
+static struct lxc_handler *lxc_init_clean_handler(char *name, char *lxcpath, struct lxc_conf *conf, pid_t pid)
+{
+ int i;
+ struct lxc_handler *handler;
+
+ handler = malloc(sizeof(*handler));
+ if (handler == NULL)
+ return NULL;
+
+ memset(handler, 0, sizeof(*handler));
+
+ /* Note that am_guest_unpriv() checks the effective uid. We
+ * probably don't care if we are real root only if we are running
+ * as root so this should be fine.
+ */
+ handler->am_root = !am_guest_unpriv();
+ handler->data_sock[0] = handler->data_sock[1] = -1;
+ handler->conf = conf;
+ handler->lxcpath = lxcpath;
+ handler->pinfd = -1;
+ handler->sigfd = -EBADF;
+ handler->init_died = false;
+ handler->pid = pid;
+ handler->state_socket_pair[0] = handler->state_socket_pair[1] = -1;
+ if (handler->conf->reboot == REBOOT_NONE)
+ lxc_list_init(&handler->conf->state_clients);
+
+ for (i = 0; i < LXC_NS_MAX; i++)
+ handler->nsfd[i] = -1;
+
+ handler->name = name;
+ handler->exit_code = -1; /* isulad: record exit code of container */
+
+ handler->cgroup_ops = cgroup_init(conf);
+ if (!handler->cgroup_ops) {
+ ERROR("Failed to initialize cgroup driver");
+ goto on_error;
+ }
+
+ INFO("Container \"%s\" 's clean handler is initialized.", name);
+
+ return handler;
+
+on_error:
+ lxc_free_handler(handler);
+
+ return NULL;
+}
+
+/*isulad: init handler for clean */
+static struct lxc_handler *lxc_init_pids_handler(char *name, char *lxcpath, struct lxc_conf *conf)
+{
+ int i;
+ struct lxc_handler *handler;
+
+ handler = malloc(sizeof(*handler));
+ if (handler == NULL)
+ return NULL;
+
+ memset(handler, 0, sizeof(*handler));
+
+ /* Note that am_guest_unpriv() checks the effective uid. We
+ * probably don't care if we are real root only if we are running
+ * as root so this should be fine.
+ */
+ handler->am_root = !am_guest_unpriv();
+ handler->data_sock[0] = handler->data_sock[1] = -1;
+ handler->conf = conf;
+ handler->lxcpath = lxcpath;
+ handler->pinfd = -1;
+ handler->sigfd = -EBADF;
+ handler->init_died = false;
+ handler->state_socket_pair[0] = handler->state_socket_pair[1] = -1;
+ if (handler->conf->reboot == REBOOT_NONE)
+ lxc_list_init(&handler->conf->state_clients);
+
+ for (i = 0; i < LXC_NS_MAX; i++)
+ handler->nsfd[i] = -1;
+
+ handler->name = name;
+ handler->exit_code = -1; /* isulad: record exit code of container */
+
+ handler->cgroup_ops = cgroup_init(conf);
+ if (!handler->cgroup_ops) {
+ ERROR("Failed to initialize cgroup driver");
+ goto on_error;
+ }
+
+ INFO("Container \"%s\" 's clean handler is initialized.", name);
+
+ return handler;
+
+on_error:
+ lxc_free_handler(handler);
+
+ return NULL;
+}
+
+/*isulad: do_lxcapi_clean_resource */
+int do_lxcapi_clean_resource(char *name, char *lxcpath, struct lxc_conf *conf, pid_t pid)
+{
+ int ret = 0;
+ struct lxc_handler *handler = NULL;
+ int retry_count = 0;
+ int max_retry = 10;
+
+ handler = lxc_init_clean_handler(name, lxcpath, conf, pid);
+ if (!handler) {
+ ERROR("Failed to init container %s clean handler", name);
+ ret = -1;
+ goto out;
+ }
+
+ if (clean_resource_set_env(handler) != 0) {
+ ERROR("Failed to set env for poststop hooks");
+ ret = -1;
+ goto out;
+ }
+
+ if (run_oci_hooks(handler->name, "oci-poststop", handler->conf, handler->lxcpath)) {
+ ERROR("Failed to run lxc.hook.post-stop for container \"%s\".", handler->name);
+ ret = -1;
+ }
+
+retry:
+ if (!handler->cgroup_ops->payload_destroy(handler->cgroup_ops, handler)) {
+ TRACE("Trying to kill all subprocess");
+ signal_all_processes(handler);
+ TRACE("Finished kill all subprocess");
+ if (retry_count < max_retry) {
+ usleep(100 * 1000); /* 100 millisecond */
+ retry_count++;
+ goto retry;
+ }
+ SYSERROR("Failed to destroy cgroup path for container: \"%s\"", handler->name);
+ ret = -1;
+ }
+
+out:
+ lxc_free_handler(handler);
+ return ret;
+}
+
+/*isulad: do_lxcapi_get_pids */
+int do_lxcapi_get_pids(char *name, char *lxcpath, struct lxc_conf *conf, pid_t **pids,size_t *pids_len)
+{
+ int ret = 0;
+ struct lxc_handler *handler = NULL;
+ struct cgroup_ops *cg_ops = NULL;
+
+ handler = lxc_init_pids_handler(name, lxcpath, conf);
+ if (!handler) {
+ ERROR("Failed to init container %s clean handler", name);
+ ret = -1;
+ goto out;
+ }
+
+ cg_ops = handler->cgroup_ops;
+ ret = get_all_pids(cg_ops, pids, pids_len);
+ if (ret < 0) {
+ WARN("failed to get all pids");
+ }
+
+out:
+ lxc_free_handler(handler);
+ return ret;
+}
+
+#endif
diff --git a/src/lxc/start.h b/src/lxc/start.h
index 5ea5fe2..4fc3ff7 100644
--- a/src/lxc/start.h
+++ b/src/lxc/start.h
@@ -175,4 +175,12 @@ extern int __lxc_start(struct lxc_handler *, struct lxc_operations *, void *,
extern int resolve_clone_flags(struct lxc_handler *handler);
+#ifdef HAVE_ISULAD
+/*isulad: do_lxcapi_clean_resource */
+extern int do_lxcapi_clean_resource(char *name, char *lxcpath, struct lxc_conf *conf, pid_t pid);
+
+/*isulad: do_lxcapi_get_pids */
+extern int do_lxcapi_get_pids(char *name, char *lxcpath, struct lxc_conf *conf, pid_t **pids,size_t *pids_len);
+#endif
+
#endif
diff --git a/src/lxc/sync.h b/src/lxc/sync.h
index ff7a1eb..56c1dfc 100644
--- a/src/lxc/sync.h
+++ b/src/lxc/sync.h
@@ -11,6 +11,10 @@ enum {
LXC_SYNC_POST_CONFIGURE,
LXC_SYNC_CGROUP,
LXC_SYNC_CGROUP_UNSHARE,
+#ifdef HAVE_ISULAD
+ LXC_SYNC_OCI_PRESTART_HOOK,
+ LXC_SYNC_POST_OCI_PRESTART_HOOK,
+#endif
LXC_SYNC_CGROUP_LIMITS,
LXC_SYNC_READY_START,
LXC_SYNC_RESTART,
diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index 27078e2..39413ee 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -2122,4 +2122,42 @@ set_env:
return 0;
}
+bool lxc_process_alive(pid_t pid, unsigned long long start_time)
+{
+ int sret = 0;
+ bool alive = true;
+ proc_t *pid_info = NULL;
+ char filename[PATH_MAX] = {0};
+ char sbuf[1024] = {0}; /* bufs for stat */
+
+ sret = kill(pid, 0);
+ if (sret < 0 && errno == ESRCH)
+ return false;
+
+ sret = snprintf(filename, sizeof(filename), "/proc/%d/stat", pid);
+ if (sret < 0 || sret >= sizeof(filename)) {
+ ERROR("Failed to sprintf filename");
+ goto out;
+ }
+
+ if ((lxc_file2str(filename, sbuf, sizeof(sbuf))) == -1) {
+ ERROR("Failed to read pidfile %s", filename);
+ alive = false;
+ goto out;
+ }
+
+ pid_info = lxc_stat2proc(sbuf);
+ if (!pid_info) {
+ ERROR("Failed to get proc stat info");
+ alive = false;
+ goto out;
+ }
+
+ if (start_time != pid_info->start_time)
+ alive = false;
+out:
+ free(pid_info);
+ return alive;
+}
+
#endif
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index 36c458e..a213ba7 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -322,6 +322,8 @@ extern int lxc_file2str(const char *filename, char ret[], int cap);
extern int unsigned long long lxc_get_process_startat(pid_t pid);
// set env home in container
extern int lxc_setup_env_home(uid_t uid);
+
+extern bool lxc_process_alive(pid_t pid, unsigned long long start_time);
#endif
#endif /* __LXC_UTILS_H */
--
1.8.3.1
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。