3311 lines
91 KiB
Diff
3311 lines
91 KiB
Diff
From 3e7fb35a35cff34be2bb7ace0b239d540fe0657f Mon Sep 17 00:00:00 2001
|
|
From: zhangxiaoyu <zhangxiaoyu58@huawei.com>
|
|
Date: Wed, 26 Jul 2023 14:57:33 +0800
|
|
Subject: [PATCH] [iSulad] adapt confile lxccontainer and start
|
|
|
|
Signed-off-by: zhangxiaoyu <zhangxiaoyu58@huawei.com>
|
|
---
|
|
src/lxc/conf.c | 11 -
|
|
src/lxc/conf.h | 4 -
|
|
src/lxc/confile.c | 558 +++++++++++++++++++++++++
|
|
src/lxc/lxccontainer.c | 899 +++++++++++++++++++++++++++++++++++++++-
|
|
src/lxc/lxccontainer.h | 197 +++++++++
|
|
src/lxc/start.c | 902 +++++++++++++++++++++++++++++++++++++++++
|
|
src/lxc/start.h | 18 +
|
|
7 files changed, 2573 insertions(+), 16 deletions(-)
|
|
|
|
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
|
|
index a0e0375..187e60e 100644
|
|
--- a/src/lxc/conf.c
|
|
+++ b/src/lxc/conf.c
|
|
@@ -5242,7 +5242,6 @@ void lxc_conf_free(struct lxc_conf *conf)
|
|
}
|
|
free(conf->systemd);
|
|
lxc_clear_init_args(conf);
|
|
- lxc_clear_init_groups(conf);
|
|
lxc_clear_populate_devices(conf);
|
|
lxc_clear_rootfs_masked_paths(conf);
|
|
lxc_clear_rootfs_ro_paths(conf);
|
|
@@ -7427,16 +7426,6 @@ int lxc_clear_init_args(struct lxc_conf *lxc_conf)
|
|
return 0;
|
|
}
|
|
|
|
-/*isulad clear init groups*/
|
|
-int lxc_clear_init_groups(struct lxc_conf *lxc_conf)
|
|
-{
|
|
- free(lxc_conf->init_groups);
|
|
- lxc_conf->init_groups = NULL;
|
|
- lxc_conf->init_groups_len = 0;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
/*isulad: clear populate devices*/
|
|
int lxc_clear_populate_devices(struct lxc_conf *c)
|
|
{
|
|
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
|
|
index 683b8ba..108e05b 100644
|
|
--- a/src/lxc/conf.h
|
|
+++ b/src/lxc/conf.h
|
|
@@ -622,9 +622,6 @@ struct lxc_conf {
|
|
char **init_argv;
|
|
size_t init_argc;
|
|
|
|
- gid_t *init_groups;
|
|
- size_t init_groups_len;
|
|
-
|
|
/* populate devices */
|
|
struct lxc_list populate_devs;
|
|
mode_t umask; // umask value
|
|
@@ -794,7 +791,6 @@ __hidden extern int parse_cap(const char *cap_name, __u32 *cap);
|
|
#ifdef HAVE_ISULAD
|
|
// isulad add
|
|
__hidden int lxc_clear_init_args(struct lxc_conf *lxc_conf);
|
|
-__hidden int lxc_clear_init_groups(struct lxc_conf *lxc_conf);
|
|
__hidden int lxc_clear_populate_devices(struct lxc_conf *c);
|
|
__hidden int lxc_clear_rootfs_masked_paths(struct lxc_conf *c);
|
|
__hidden int lxc_clear_rootfs_ro_paths(struct lxc_conf *c);
|
|
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
|
|
index 7966d32..1492776 100644
|
|
--- a/src/lxc/confile.c
|
|
+++ b/src/lxc/confile.c
|
|
@@ -157,6 +157,18 @@ lxc_config_define(uts_name);
|
|
lxc_config_define(sysctl);
|
|
lxc_config_define(proc);
|
|
lxc_config_define(sched_core);
|
|
+#ifdef HAVE_ISULAD
|
|
+lxc_config_define(init_args);
|
|
+lxc_config_define(populate_device);
|
|
+lxc_config_define(umask);
|
|
+lxc_config_define(rootfs_masked_paths);
|
|
+lxc_config_define(rootfs_ro_paths);
|
|
+lxc_config_define(systemd);
|
|
+lxc_config_define(console_log_driver);
|
|
+lxc_config_define(console_syslog_tag);
|
|
+lxc_config_define(console_syslog_facility);
|
|
+lxc_config_define(selinux_mount_context);
|
|
+#endif
|
|
|
|
static int set_config_unsupported_key(const char *key, const char *value,
|
|
struct lxc_conf *lxc_conf, void *data)
|
|
@@ -274,6 +286,18 @@ static struct lxc_config_t config_jump_table[] = {
|
|
{ "lxc.uts.name", true, set_config_uts_name, get_config_uts_name, clr_config_uts_name, },
|
|
{ "lxc.sysctl", false, set_config_sysctl, get_config_sysctl, clr_config_sysctl, },
|
|
{ "lxc.proc", false, set_config_proc, get_config_proc, clr_config_proc, },
|
|
+#ifdef HAVE_ISULAD
|
|
+ { "lxc.isulad.init.args", set_config_init_args, get_config_init_args, clr_config_init_args, },
|
|
+ { "lxc.isulad.populate.device", set_config_populate_device, get_config_populate_device, clr_config_populate_device, },
|
|
+ { "lxc.isulad.umask", set_config_umask, get_config_umask, clr_config_umask, },
|
|
+ { "lxc.isulad.rootfs.maskedpaths", set_config_rootfs_masked_paths, get_config_rootfs_masked_paths, clr_config_rootfs_masked_paths, },
|
|
+ { "lxc.isulad.rootfs.ropaths", set_config_rootfs_ro_paths, get_config_rootfs_ro_paths, clr_config_rootfs_ro_paths, },
|
|
+ { "lxc.isulad.systemd", set_config_systemd, get_config_systemd, clr_config_systemd, },
|
|
+ { "lxc.console.logdriver", set_config_console_log_driver, get_config_console_log_driver, clr_config_console_log_driver, },
|
|
+ { "lxc.console.syslog_tag", set_config_console_syslog_tag, get_config_console_syslog_tag, clr_config_console_syslog_tag, },
|
|
+ { "lxc.console.syslog_facility", set_config_console_syslog_facility, get_config_console_syslog_facility, clr_config_console_syslog_facility, },
|
|
+ { "lxc.selinux.mount_context", set_config_selinux_mount_context, get_config_selinux_mount_context, clr_config_selinux_mount_context, },
|
|
+#endif
|
|
};
|
|
|
|
static struct lxc_config_t unsupported_config_key = {
|
|
@@ -1588,7 +1612,12 @@ static int set_config_environment(const char *key, const char *value,
|
|
if (!new_env)
|
|
return ret_errno(ENOMEM);
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ /* isulad: recover space replaced by SPACE_MAGIC_STR */
|
|
+ dup = lxc_string_replace(SPACE_MAGIC_STR, " ", value);
|
|
+#else
|
|
dup = strdup(value);
|
|
+#endif
|
|
if (!dup)
|
|
return ret_errno(ENOMEM);
|
|
|
|
@@ -2558,8 +2587,11 @@ static int set_config_console_rotate(const char *key, const char *value,
|
|
if (ret)
|
|
return ret_errno(EINVAL);
|
|
|
|
+#ifndef HAVE_ISULAD
|
|
+ /* isulad: support rotate muti-files */
|
|
if (lxc_conf->console.log_rotate > 1)
|
|
return log_error_errno(-EINVAL, EINVAL, "The \"lxc.console.rotate\" config key can only be set to 0 or 1");
|
|
+#endif
|
|
|
|
return 0;
|
|
}
|
|
@@ -3049,6 +3081,54 @@ struct parse_line_conf {
|
|
bool from_include;
|
|
};
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+// escape_string_decode compress some escape characters
|
|
+static char *escape_string_decode(const char *src)
|
|
+{
|
|
+ size_t src_end = 0;
|
|
+ size_t dst_end = 0;
|
|
+ size_t len = 0;
|
|
+ char *dst = NULL;
|
|
+
|
|
+ if (src == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ len = strlen(src);
|
|
+ if (len == 0) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ dst = calloc(1, len + 1);
|
|
+ if (dst == NULL) {
|
|
+ ERROR("Out of memory");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ while(src_end < len) {
|
|
+ if (src[src_end] == '\\') {
|
|
+ switch (src[++src_end])
|
|
+ {
|
|
+ case 'r': dst[dst_end] = '\r'; break;
|
|
+ case 'n': dst[dst_end] = '\n'; break;
|
|
+ case 'f': dst[dst_end] = '\f'; break;
|
|
+ case 'b': dst[dst_end] = '\b'; break;
|
|
+ case 't': dst[dst_end] = '\t'; break;
|
|
+ case '\\': dst[dst_end] = '\\'; break;
|
|
+ // default do not decode
|
|
+ default: dst[dst_end++] = '\\'; dst[dst_end] = src[src_end]; break;
|
|
+ }
|
|
+ } else {
|
|
+ dst[dst_end] = src[src_end];
|
|
+ }
|
|
+ dst_end++;
|
|
+ src_end++;
|
|
+ }
|
|
+
|
|
+ return dst;
|
|
+}
|
|
+#endif
|
|
+
|
|
static int parse_line(char *buffer, void *data)
|
|
{
|
|
__do_free char *linep = NULL;
|
|
@@ -3058,6 +3138,9 @@ static int parse_line(char *buffer, void *data)
|
|
int ret;
|
|
char *dup = buffer;
|
|
struct parse_line_conf *plc = data;
|
|
+#ifdef HAVE_ISULAD
|
|
+ __do_free char *value_decode = NULL;
|
|
+#endif
|
|
|
|
if (!plc->conf)
|
|
return syserror_set(-EINVAL, "Missing config");
|
|
@@ -3118,7 +3201,15 @@ static int parse_line(char *buffer, void *data)
|
|
}
|
|
|
|
config = lxc_get_config(key);
|
|
+#ifdef HAVE_ISULAD
|
|
+ value_decode = escape_string_decode(value);
|
|
+ if (value_decode == NULL) {
|
|
+ ERROR("Value %s decode failed", value);
|
|
+ }
|
|
+ ret = config->set(key, value_decode ? value_decode: value, plc->conf, NULL);
|
|
+#else
|
|
return config->set(key, value, plc->conf, NULL);
|
|
+#endif
|
|
}
|
|
|
|
static struct new_config_item *parse_new_conf_line(char *buffer)
|
|
@@ -3222,6 +3313,12 @@ bool lxc_config_define_load(struct lxc_list *defines, struct lxc_container *c)
|
|
|
|
lxc_list_for_each(it, defines) {
|
|
struct new_config_item *new_item = it->elem;
|
|
+#ifdef HAVE_ISULAD
|
|
+ if (strcmp(new_item->key, LXC_IMAGE_OCI_KEY) == 0) {
|
|
+ c->set_oci_type(c, true);
|
|
+ continue;
|
|
+ }
|
|
+#endif
|
|
bret = c->set_config_item(c, new_item->key, new_item->val);
|
|
if (!bret)
|
|
break;
|
|
@@ -6764,3 +6861,464 @@ static int clr_config_sched_core(const char *key, struct lxc_conf *c, void *data
|
|
c->sched_core = false;
|
|
return 0;
|
|
}
|
|
+
|
|
+
|
|
+#ifdef HAVE_ISULAD
|
|
+/* isulad: set config for init args */
|
|
+static int set_config_init_args(const char *key, const char *value,
|
|
+ struct lxc_conf *lxc_conf, void *data)
|
|
+{
|
|
+ int ret = 0;
|
|
+ char **tmp = NULL;
|
|
+ char *new_value = NULL;
|
|
+
|
|
+ ret = set_config_string_item(&new_value, value);
|
|
+ if (ret || !new_value)
|
|
+ return ret;
|
|
+
|
|
+ tmp = (char **)realloc(lxc_conf->init_argv, (lxc_conf->init_argc + 1) * sizeof(char *));
|
|
+ if (!tmp) {
|
|
+ ERROR("Out of memory");
|
|
+ free(new_value);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ lxc_conf->init_argv = tmp;
|
|
+
|
|
+ lxc_conf->init_argv[lxc_conf->init_argc] = new_value;
|
|
+ lxc_conf->init_argc++;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* isulad: get config init args */
|
|
+static int get_config_init_args(const char *key, char *retv, int inlen,
|
|
+ struct lxc_conf *c, void *data)
|
|
+{
|
|
+ int i, len, fulllen = 0;
|
|
+
|
|
+ if (!retv)
|
|
+ inlen = 0;
|
|
+ else
|
|
+ memset(retv, 0, inlen);
|
|
+
|
|
+ for (i = 0; i < c->init_argc; i++) {
|
|
+ strprint(retv, inlen, "%s", c->init_argv[i]);
|
|
+ }
|
|
+
|
|
+ return fulllen;
|
|
+}
|
|
+
|
|
+/* isulad: clr config init args*/
|
|
+static inline int clr_config_init_args(const char *key, struct lxc_conf *c,
|
|
+ void *data)
|
|
+{
|
|
+ return lxc_clear_init_args(c);
|
|
+}
|
|
+
|
|
+/* isulad: set config for populate device */
|
|
+static int set_config_populate_device(const char *key, const char *value,
|
|
+ struct lxc_conf *lxc_conf, void *data)
|
|
+{
|
|
+ int ret = 0, major = 0, minor = 0;
|
|
+ uid_t uid = (uid_t)-1;
|
|
+ gid_t gid = (gid_t)-1;
|
|
+ char name[4096] = {0}; /* MAX dev path name */
|
|
+ char type[3] = {0};
|
|
+ char *replace_value = NULL;
|
|
+ mode_t filemode = 0;
|
|
+ struct lxc_list *iter = NULL;
|
|
+ struct lxc_list *dev_list = NULL;
|
|
+ struct lxc_populate_devs *dev_elem = NULL;
|
|
+
|
|
+ if (lxc_config_value_empty(value))
|
|
+ return lxc_clear_populate_devices(lxc_conf);
|
|
+
|
|
+ /* lxc.populate.device = PATH_IN_CONTAINER:DEVICETYPE:MAJOR:MINOR:MODE:UID:GID
|
|
+ * For e.g. lxc.populate.device = /dev/sda:b:8:0:0666:0:0
|
|
+ */
|
|
+ ret = sscanf(value, "%4095[^:]:%2[^:]:%i:%i:%i:%u:%u", name, type, &major, &minor, &filemode, &uid, &gid);
|
|
+ if (ret != 7)
|
|
+ return -1;
|
|
+
|
|
+ /* find existing list element */
|
|
+ lxc_list_for_each(iter, &lxc_conf->populate_devs) {
|
|
+ dev_elem = iter->elem;
|
|
+
|
|
+ if (strcmp(name, dev_elem->name) != 0)
|
|
+ continue;
|
|
+
|
|
+ replace_value = safe_strdup(type);
|
|
+
|
|
+ free(dev_elem->type);
|
|
+ dev_elem->type = replace_value;
|
|
+ dev_elem->file_mode = filemode;
|
|
+ dev_elem->maj = major;
|
|
+ dev_elem->min = minor;
|
|
+ dev_elem->uid = (uid_t)uid;
|
|
+ dev_elem->gid = (gid_t)gid;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* allocate list element */
|
|
+ dev_list = malloc(sizeof(*dev_list));
|
|
+ if (dev_list == NULL)
|
|
+ goto on_error;
|
|
+
|
|
+ lxc_list_init(dev_list);
|
|
+
|
|
+ dev_elem = malloc(sizeof(*dev_elem));
|
|
+ if (dev_elem == NULL)
|
|
+ goto on_error;
|
|
+ memset(dev_elem, 0, sizeof(*dev_elem));
|
|
+
|
|
+ dev_elem->name = safe_strdup(name);
|
|
+
|
|
+ dev_elem->type = safe_strdup(type);
|
|
+
|
|
+ dev_elem->file_mode = filemode;
|
|
+ dev_elem->maj = major;
|
|
+ dev_elem->min = minor;
|
|
+ dev_elem->uid = (uid_t)uid;
|
|
+ dev_elem->gid = (gid_t)gid;
|
|
+
|
|
+ lxc_list_add_elem(dev_list, dev_elem);
|
|
+
|
|
+ lxc_list_add_tail(&lxc_conf->populate_devs, dev_list);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+on_error:
|
|
+ free(dev_list);
|
|
+ if (dev_elem) {
|
|
+ free(dev_elem->name);
|
|
+ free(dev_elem->type);
|
|
+ free(dev_elem);
|
|
+ }
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+/* isulad: get config populate device
|
|
+ * If you ask for 'lxc.populate.device', then all populate device
|
|
+ * entries will be printed, in 'lxc.populate.device = path_in_container:type:major:minor:mode:uid:gid' format.
|
|
+ * For e.g. lxc.populate.device = /dev/sda:b:8:0:0666:0:0
|
|
+ */
|
|
+static int get_config_populate_device(const char *key, char *retv, int inlen,
|
|
+ struct lxc_conf *c, void *data)
|
|
+{
|
|
+ int len;
|
|
+ struct lxc_list *it = NULL;
|
|
+ int fulllen = 0;
|
|
+
|
|
+ if (!retv)
|
|
+ inlen = 0;
|
|
+ else
|
|
+ memset(retv, 0, inlen);
|
|
+
|
|
+ lxc_list_for_each(it, &c->populate_devs) {
|
|
+ struct lxc_populate_devs *elem = it->elem;
|
|
+ strprint(retv, inlen, "lxc.populate.device = %s:%s:%d:%d:%o:%u:%u\n",
|
|
+ elem->name, elem->type, elem->maj,
|
|
+ elem->min, elem->file_mode, elem->uid, elem->gid);
|
|
+ }
|
|
+
|
|
+ return fulllen;
|
|
+}
|
|
+
|
|
+/* isulad: clr config populate devices*/
|
|
+static inline int clr_config_populate_device(const char *key, struct lxc_conf *c,
|
|
+ void *data)
|
|
+{
|
|
+ return lxc_clear_populate_devices(c);
|
|
+}
|
|
+
|
|
+/* isulad: set config for umask */
|
|
+static int set_config_umask(const char *key, const char *value,
|
|
+ struct lxc_conf *lxc_conf, void *data)
|
|
+{
|
|
+ if (lxc_config_value_empty(value)) {
|
|
+ ERROR("Empty umask");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (strcmp(value, "normal") == 0) {
|
|
+ lxc_conf->umask = 0022;
|
|
+ return 0;
|
|
+ } else if (strcmp(value, "secure") == 0) {
|
|
+ lxc_conf->umask = 0027;
|
|
+ return 0;
|
|
+ } else {
|
|
+ ERROR("Invalid native umask: %s", value);
|
|
+ return -1;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* isulad add: get umask value*/
|
|
+static int get_config_umask(const char *key, char *retv, int inlen,
|
|
+ struct lxc_conf *c, void *data)
|
|
+{
|
|
+ return lxc_get_conf_size_t(c, retv, inlen, c->umask);
|
|
+}
|
|
+
|
|
+/* isulad add: clear umask value */
|
|
+static inline int clr_config_umask(const char *key, struct lxc_conf *c,
|
|
+ void *data)
|
|
+{
|
|
+ c->umask = 0027;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* isulad: set config for rootfs masked paths */
|
|
+static int set_config_rootfs_masked_paths(const char *key, const char *value,
|
|
+ struct lxc_conf *lxc_conf, void *data)
|
|
+{
|
|
+ struct lxc_list *list_item = NULL;
|
|
+
|
|
+ if (lxc_config_value_empty(value))
|
|
+ return lxc_clear_rootfs_masked_paths(lxc_conf);
|
|
+
|
|
+ list_item = malloc(sizeof(*list_item));
|
|
+ if (list_item == NULL)
|
|
+ goto on_error;
|
|
+
|
|
+ list_item->elem = safe_strdup(value);
|
|
+
|
|
+ lxc_list_add_tail(&lxc_conf->rootfs.maskedpaths, list_item);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+on_error:
|
|
+ free(list_item);
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+// isulad: get config rootfs masked paths
|
|
+static int get_config_rootfs_masked_paths(const char *key, char *retv, int inlen,
|
|
+ struct lxc_conf *c, void *data)
|
|
+{
|
|
+ int len, fulllen = 0;
|
|
+ struct lxc_list *it = NULL;
|
|
+
|
|
+ if (!retv)
|
|
+ inlen = 0;
|
|
+ else
|
|
+ memset(retv, 0, inlen);
|
|
+
|
|
+ lxc_list_for_each(it, &c->rootfs.maskedpaths) {
|
|
+ strprint(retv, inlen, "%s\n", (char *)it->elem);
|
|
+ }
|
|
+
|
|
+ return fulllen;
|
|
+}
|
|
+
|
|
+/* isulad: set config for rootfs ro paths */
|
|
+static int set_config_rootfs_ro_paths(const char *key, const char *value,
|
|
+ struct lxc_conf *lxc_conf, void *data)
|
|
+{
|
|
+ struct lxc_list *list_item = NULL;
|
|
+
|
|
+ if (lxc_config_value_empty(value))
|
|
+ return lxc_clear_rootfs_ro_paths(lxc_conf);
|
|
+
|
|
+ list_item = malloc(sizeof(*list_item));
|
|
+ if (list_item == NULL)
|
|
+ goto on_error;
|
|
+
|
|
+ list_item->elem = safe_strdup(value);
|
|
+
|
|
+ lxc_list_add_tail(&lxc_conf->rootfs.ropaths, list_item);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+on_error:
|
|
+ free(list_item);
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+// isulad: get config rootfs ro paths
|
|
+static int get_config_rootfs_ro_paths(const char *key, char *retv, int inlen,
|
|
+ struct lxc_conf *c, void *data)
|
|
+{
|
|
+ int len, fulllen = 0;
|
|
+ struct lxc_list *it = NULL;
|
|
+
|
|
+ if (!retv)
|
|
+ inlen = 0;
|
|
+ else
|
|
+ memset(retv, 0, inlen);
|
|
+
|
|
+ lxc_list_for_each(it, &c->rootfs.ropaths) {
|
|
+ strprint(retv, inlen, "%s\n", (char *)it->elem);
|
|
+ }
|
|
+
|
|
+ return fulllen;
|
|
+}
|
|
+
|
|
+/* isulad: clr config rootfs masked paths */
|
|
+static inline int clr_config_rootfs_masked_paths(const char *key, struct lxc_conf *c,
|
|
+ void *data)
|
|
+{
|
|
+ return lxc_clear_rootfs_masked_paths(c);
|
|
+}
|
|
+
|
|
+/* isulad: clr config rootfs ro paths */
|
|
+static inline int clr_config_rootfs_ro_paths(const char *key, struct lxc_conf *c,
|
|
+ void *data)
|
|
+{
|
|
+ return lxc_clear_rootfs_ro_paths(c);
|
|
+}
|
|
+
|
|
+/* isulad: set config for systemd */
|
|
+static int set_config_systemd(const char *key, const char *value,
|
|
+ struct lxc_conf *lxc_conf, void *data)
|
|
+{
|
|
+ if (lxc_config_value_empty(value)) {
|
|
+ ERROR("Empty umask");
|
|
+ return -1;
|
|
+ }
|
|
+ lxc_conf->systemd = strdup(value);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* isulad add: get systemd value*/
|
|
+static int get_config_systemd(const char *key, char *retv, int inlen,
|
|
+ struct lxc_conf *c, void *data)
|
|
+{
|
|
+ return lxc_get_conf_str(retv, inlen, c->systemd);
|
|
+}
|
|
+
|
|
+/* isulad add: clear systemd value */
|
|
+static inline int clr_config_systemd(const char *key, struct lxc_conf *c,
|
|
+ void *data)
|
|
+{
|
|
+ free(c->systemd);
|
|
+ c->systemd = NULL;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int set_config_console_log_driver(const char *key, const char *value,
|
|
+ struct lxc_conf *lxc_conf, void *data)
|
|
+{
|
|
+ return set_config_string_item(&lxc_conf->console.log_driver, value);
|
|
+}
|
|
+
|
|
+static int set_config_console_syslog_tag(const char *key, const char *value,
|
|
+ struct lxc_conf *lxc_conf, void *data)
|
|
+{
|
|
+ if (value == NULL) {
|
|
+ return -1;
|
|
+ }
|
|
+ return set_config_string_item(&lxc_conf->console.log_syslog_tag, value);
|
|
+}
|
|
+
|
|
+static int parse_facility(const char *facility)
|
|
+{
|
|
+#define FACILITIES_LEN 20
|
|
+ const char *facility_keys[FACILITIES_LEN] = {
|
|
+ "kern", "user", "mail", "daemon", "auth",
|
|
+ "syslog", "lpr", "news", "uucp", "cron", "authpriv", "ftp",
|
|
+ "local0", "local1", "local2", "local3", "local4", "local5", "local6", "local7"
|
|
+ };
|
|
+ const int facilities[FACILITIES_LEN] = {
|
|
+ LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON, LOG_AUTH, LOG_SYSLOG,
|
|
+ LOG_LPR, LOG_NEWS, LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_FTP,
|
|
+ LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4,
|
|
+ LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7
|
|
+ };
|
|
+ int i = 0;
|
|
+
|
|
+ if (facility == NULL) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ for (; i < FACILITIES_LEN; i++) {
|
|
+ if (strcmp(facility, facility_keys[i]) == 0) {
|
|
+ return facilities[i];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static int set_config_console_syslog_facility(const char *key, const char *value,
|
|
+ struct lxc_conf *lxc_conf, void *data)
|
|
+{
|
|
+ int facility;
|
|
+
|
|
+ facility = parse_facility(value);
|
|
+ if (facility < 0) {
|
|
+ NOTICE("Invalid facility: %s", value);
|
|
+ facility = LOG_DAEMON;
|
|
+ }
|
|
+
|
|
+ lxc_conf->console.log_syslog_facility = facility;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int set_config_selinux_mount_context(const char *key, const char *value,
|
|
+ struct lxc_conf *lxc_conf, void *data)
|
|
+{
|
|
+ if (value != NULL && strcmp(value, "unconfined_t") == 0) {
|
|
+ return set_config_string_item(&lxc_conf->lsm_se_mount_context, NULL);
|
|
+ }
|
|
+
|
|
+ return set_config_string_item(&lxc_conf->lsm_se_mount_context, value);
|
|
+}
|
|
+
|
|
+static int get_config_console_log_driver(const char *key, char *retv, int inlen,
|
|
+ struct lxc_conf *c, void *data)
|
|
+{
|
|
+ return lxc_get_conf_str(retv, inlen, c->console.log_driver);
|
|
+}
|
|
+
|
|
+static int get_config_console_syslog_tag(const char *key, char *retv, int inlen,
|
|
+ struct lxc_conf *c, void *data)
|
|
+{
|
|
+ return lxc_get_conf_str(retv, inlen, c->console.log_syslog_tag);
|
|
+}
|
|
+
|
|
+static int get_config_console_syslog_facility(const char *key, char *retv, int inlen,
|
|
+ struct lxc_conf *c, void *data)
|
|
+{
|
|
+ return lxc_get_conf_int(c, retv, inlen, c->console.log_syslog_facility);
|
|
+}
|
|
+
|
|
+static int get_config_selinux_mount_context(const char *key, char *retv, int inlen,
|
|
+ struct lxc_conf *c, void *data)
|
|
+{
|
|
+ return lxc_get_conf_str(retv, inlen, c->lsm_se_mount_context);
|
|
+}
|
|
+
|
|
+static inline int clr_config_console_log_driver(const char *key,
|
|
+ struct lxc_conf *c, void *data)
|
|
+{
|
|
+ free(c->console.log_driver);
|
|
+ c->console.log_driver = NULL;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline int clr_config_console_syslog_tag(const char *key,
|
|
+ struct lxc_conf *c, void *data)
|
|
+{
|
|
+ free(c->console.log_syslog_tag);
|
|
+ c->console.log_syslog_tag= NULL;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline int clr_config_console_syslog_facility(const char *key,
|
|
+ struct lxc_conf *c, void *data)
|
|
+{
|
|
+ c->console.log_syslog_facility = LOG_DAEMON;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline int clr_config_selinux_mount_context(const char *key,
|
|
+ struct lxc_conf *c, void *data)
|
|
+{
|
|
+ free(c->lsm_se_mount_context);
|
|
+ c->lsm_se_mount_context = NULL;
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
|
|
index 8df6059..d4495f7 100644
|
|
--- a/src/lxc/lxccontainer.c
|
|
+++ b/src/lxc/lxccontainer.c
|
|
@@ -62,6 +62,10 @@
|
|
#include "utils.h"
|
|
#include "version.h"
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+#include "exec_commands.h"
|
|
+#endif
|
|
+
|
|
#if HAVE_OPENSSL
|
|
#include <openssl/evp.h>
|
|
#endif
|
|
@@ -83,6 +87,11 @@
|
|
|
|
lxc_log_define(lxccontainer, lxc);
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+typedef bool (*func_is_io_stat_read)(const char *value);
|
|
+typedef bool (*func_is_io_stat_write)(const char *value);
|
|
+#endif
|
|
+
|
|
static bool do_lxcapi_destroy(struct lxc_container *c);
|
|
static const char *lxcapi_get_config_path(struct lxc_container *c);
|
|
#define do_lxcapi_get_config_path(c) lxcapi_get_config_path(c)
|
|
@@ -272,6 +281,13 @@ static void lxc_container_free(struct lxc_container *c)
|
|
free(c->config_path);
|
|
c->config_path = NULL;
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ free(c->exit_fifo);
|
|
+ c->exit_fifo = NULL;
|
|
+ free(c->ocihookfile);
|
|
+ c->ocihookfile = NULL;
|
|
+#endif
|
|
+
|
|
free(c);
|
|
}
|
|
|
|
@@ -652,6 +668,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;
|
|
@@ -685,6 +761,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
|
|
@@ -884,6 +965,33 @@ static bool wait_on_daemonized_start(struct lxc_handler *handler, int pid)
|
|
return true;
|
|
}
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+/* isulad: use init argv as init cmd */
|
|
+static char **use_init_args(char **init_argv, size_t init_args)
|
|
+{
|
|
+ size_t i;
|
|
+ int nargs = 0;
|
|
+ char **argv;
|
|
+
|
|
+ if (!init_argv)
|
|
+ return NULL;
|
|
+
|
|
+ do {
|
|
+ argv = malloc(sizeof(char *));
|
|
+ } while (!argv);
|
|
+
|
|
+ argv[0] = NULL;
|
|
+ for (i = 0; i < init_args; i++)
|
|
+ push_arg(&argv, init_argv[i], &nargs);
|
|
+
|
|
+ if (nargs == 0) {
|
|
+ free(argv);
|
|
+ return NULL;
|
|
+ }
|
|
+ return argv;
|
|
+}
|
|
+#endif
|
|
+
|
|
static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const argv[])
|
|
{
|
|
int ret;
|
|
@@ -894,6 +1002,11 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
|
|
NULL,
|
|
};
|
|
char **init_cmd = NULL;
|
|
+#ifdef HAVE_ISULAD
|
|
+ int keepfds[] = {-1, -1, -1, -1, -1};
|
|
+ ssize_t size_read;
|
|
+ char errbuf[BUFSIZ + 1] = {0};
|
|
+#endif
|
|
|
|
/* container does exist */
|
|
if (!c)
|
|
@@ -940,6 +1053,30 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
|
|
argv = init_cmd = split_init_cmd(conf->init_cmd);
|
|
}
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ if (!argv) {
|
|
+ argv = init_cmd = use_init_args(conf->init_argv, conf->init_argc);
|
|
+ }
|
|
+
|
|
+ // do not allow using default rootfs path when isulad
|
|
+ if (conf->rootfs.mount == NULL) {
|
|
+ ERROR("Empty rootfs path detected");
|
|
+ lxc_put_handler(handler);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ // do not allow using default args when isulad
|
|
+ if (!argv) {
|
|
+ ERROR("Empty args detected");
|
|
+ lxc_put_handler(handler);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (c->image_type_oci) {
|
|
+ handler->image_type_oci = true;
|
|
+ }
|
|
+#endif
|
|
+
|
|
/* ... otherwise use default_args. */
|
|
if (!argv) {
|
|
if (useinit) {
|
|
@@ -959,10 +1096,23 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
|
|
char title[2048];
|
|
pid_t pid_first, pid_second;
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ //isulad: pipdfd for get error message of child or grandchild process.
|
|
+ if (pipe2(conf->errpipe, O_CLOEXEC) != 0) {
|
|
+ SYSERROR("Failed to init errpipe");
|
|
+ free_init_cmd(init_cmd);
|
|
+ lxc_put_handler(handler);
|
|
+ return false;
|
|
+ }
|
|
+#endif
|
|
+
|
|
pid_first = fork();
|
|
if (pid_first < 0) {
|
|
free_init_cmd(init_cmd);
|
|
lxc_put_handler(handler);
|
|
+#ifdef HAVE_ISULAD
|
|
+ lxc_close_error_pipe(conf->errpipe);
|
|
+#endif
|
|
return false;
|
|
}
|
|
|
|
@@ -972,11 +1122,25 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
|
|
* the PID file, child will do the free and unlink.
|
|
*/
|
|
c->pidfile = NULL;
|
|
+#ifdef HAVE_ISULAD
|
|
+ close(conf->errpipe[1]);
|
|
+ conf->errpipe[1] = -1;
|
|
+#endif
|
|
|
|
/* Wait for container to tell us whether it started
|
|
* successfully.
|
|
*/
|
|
started = wait_on_daemonized_start(handler, pid_first);
|
|
+#ifdef HAVE_ISULAD
|
|
+ if (!started) {
|
|
+ size_read = read(conf->errpipe[0], errbuf, BUFSIZ);
|
|
+ if (size_read > 0) {
|
|
+ conf->errmsg = safe_strdup(errbuf);
|
|
+ }
|
|
+ }
|
|
+ close(conf->errpipe[0]);
|
|
+ conf->errpipe[0] = -1;
|
|
+#endif
|
|
|
|
free_init_cmd(init_cmd);
|
|
lxc_put_handler(handler);
|
|
@@ -1012,6 +1176,9 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
|
|
if (pid_second != 0) {
|
|
free_init_cmd(init_cmd);
|
|
lxc_put_handler(handler);
|
|
+#ifdef HAVE_ISULAD
|
|
+ lxc_close_error_pipe(conf->errpipe);
|
|
+#endif
|
|
_exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
@@ -1024,7 +1191,18 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
|
|
_exit(EXIT_FAILURE);
|
|
}
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ keepfds[0] = handler->conf->maincmd_fd;
|
|
+ keepfds[1] = handler->state_socket_pair[0];
|
|
+ keepfds[2] = handler->state_socket_pair[1];
|
|
+ keepfds[4] = conf->errpipe[1];
|
|
+ close(conf->errpipe[0]);
|
|
+ conf->errpipe[0] = -1;
|
|
+ ret = lxc_check_inherited(conf, true, keepfds,
|
|
+ sizeof(keepfds) / sizeof(keepfds[0]));
|
|
+#else
|
|
ret = inherit_fds(handler, true);
|
|
+#endif
|
|
if (ret < 0)
|
|
_exit(EXIT_FAILURE);
|
|
|
|
@@ -1057,6 +1235,9 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
|
|
if (w < 0) {
|
|
free_init_cmd(init_cmd);
|
|
lxc_put_handler(handler);
|
|
+#ifdef HAVE_ISULAD
|
|
+ lxc_close_error_pipe(conf->errpipe);
|
|
+#endif
|
|
|
|
SYSERROR("Failed to write monitor pid to \"%s\"", c->pidfile);
|
|
|
|
@@ -1070,6 +1251,9 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
|
|
if (ret < 0) {
|
|
free_init_cmd(init_cmd);
|
|
lxc_put_handler(handler);
|
|
+#ifdef HAVE_ISULAD
|
|
+ lxc_close_error_pipe(conf->errpipe);
|
|
+#endif
|
|
|
|
SYSERROR("Failed to write monitor pid to \"%s\"", c->pidfile);
|
|
|
|
@@ -1080,6 +1264,19 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
|
|
}
|
|
}
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ /* isulad: open exit fifo */
|
|
+ if (c->exit_fifo) {
|
|
+ conf->exit_fd = lxc_open(c->exit_fifo, O_WRONLY | O_NONBLOCK | O_CLOEXEC, 0);
|
|
+ if (conf->exit_fd < 0) {
|
|
+ ERROR("Failed to open exit fifo %s: %s.", c->exit_fifo, strerror(errno));
|
|
+ lxc_put_handler(handler);
|
|
+ ret = 1;
|
|
+ goto on_error;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
conf->reboot = REBOOT_NONE;
|
|
|
|
/* Unshare the mount namespace if requested */
|
|
@@ -1111,19 +1308,53 @@ reboot:
|
|
}
|
|
}
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ keepfds[0] = handler->conf->maincmd_fd;
|
|
+ keepfds[1] = handler->state_socket_pair[0];
|
|
+ keepfds[2] = handler->state_socket_pair[1];
|
|
+
|
|
+ /* keep exit fifo fd */
|
|
+ if (conf->exit_fd >= 0) {
|
|
+ keepfds[3] = conf->exit_fd;
|
|
+ }
|
|
+ /* isulad: keep errpipe fd */
|
|
+ if (c->daemonize)
|
|
+ keepfds[4] = conf->errpipe[1];
|
|
+
|
|
+ ret = lxc_check_inherited(conf, c->daemonize, keepfds,
|
|
+ sizeof(keepfds) / sizeof(keepfds[0]));
|
|
+ if (ret < 0) {
|
|
+ lxc_put_handler(handler);
|
|
+ ret = 1;
|
|
+ goto on_error;
|
|
+ }
|
|
+#else
|
|
ret = inherit_fds(handler, c->daemonize);
|
|
if (ret < 0) {
|
|
lxc_put_handler(handler);
|
|
ret = 1;
|
|
goto on_error;
|
|
}
|
|
+#endif
|
|
|
|
+#ifndef HAVE_ISULAD
|
|
if (useinit)
|
|
ret = lxc_execute(c->name, argv, 1, handler, c->config_path,
|
|
c->daemonize, &c->error_num);
|
|
else
|
|
ret = lxc_start(argv, handler, c->config_path, c->daemonize,
|
|
&c->error_num);
|
|
+#else
|
|
+ if (useinit) {
|
|
+ ret = lxc_execute(c->name, argv, 1, handler, c->config_path,
|
|
+ c->daemonize, &c->error_num, c->start_timeout);
|
|
+ } else {
|
|
+ handler->disable_pty = c->disable_pty;
|
|
+ handler->open_stdin = c->open_stdin;
|
|
+ ret = lxc_start(argv, handler, c->config_path, c->daemonize,
|
|
+ &c->error_num, c->start_timeout);
|
|
+ }
|
|
+#endif
|
|
|
|
if (conf->reboot == REBOOT_REQ) {
|
|
INFO("Container requested reboot");
|
|
@@ -2065,7 +2296,12 @@ WRAP_API_1(bool, lxcapi_reboot2, int)
|
|
static bool do_lxcapi_shutdown(struct lxc_container *c, int timeout)
|
|
{
|
|
__do_close int pidfd = -EBADF, state_client_fd = -EBADF;
|
|
+#ifdef HAVE_ISULAD
|
|
+ // isulad: keep default signal the same as docker
|
|
+ int haltsignal = SIGTERM;
|
|
+#else
|
|
int haltsignal = SIGPWR;
|
|
+#endif
|
|
pid_t pid = -1;
|
|
lxc_state_t states[MAX_STATE] = {0};
|
|
int killret, ret;
|
|
@@ -2084,9 +2320,10 @@ static bool do_lxcapi_shutdown(struct lxc_container *c, int timeout)
|
|
/* Detect whether we should send SIGRTMIN + 3 (e.g. systemd). */
|
|
if (c->lxc_conf && c->lxc_conf->haltsignal)
|
|
haltsignal = c->lxc_conf->haltsignal;
|
|
+#ifndef HAVE_ISULAD
|
|
else if (task_blocks_signal(pid, (SIGRTMIN + 3)))
|
|
haltsignal = (SIGRTMIN + 3);
|
|
-
|
|
+#endif
|
|
|
|
/*
|
|
* Add a new state client before sending the shutdown signal so
|
|
@@ -2939,6 +3176,21 @@ static int lxc_unlink_exec_wrapper(void *data)
|
|
return unlink(arg);
|
|
}
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+static void container_sock_dir_delete(const char *name)
|
|
+{
|
|
+ __do_free char *sock_dir = NULL;
|
|
+
|
|
+ sock_dir = generate_named_unix_sock_dir(name);
|
|
+ if (sock_dir == NULL) {
|
|
+ ERROR("Failed to generate exec unix sock dir");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ (void)lxc_rmdir_onedev(sock_dir, NULL);
|
|
+}
|
|
+#endif
|
|
+
|
|
static bool container_destroy(struct lxc_container *c,
|
|
struct lxc_storage *storage)
|
|
{
|
|
@@ -2949,8 +3201,19 @@ static bool container_destroy(struct lxc_container *c,
|
|
bool bret = false;
|
|
int ret = 0;
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ if (!c)
|
|
+ return false;
|
|
+ // isulad: if container is not defined, we need to remove disk lock file
|
|
+ // which is created in lxc_container_new.
|
|
+ if (!do_lxcapi_is_defined(c)) {
|
|
+ container_disk_removelock(c);
|
|
+ return false;
|
|
+ }
|
|
+#else
|
|
if (!c || !do_lxcapi_is_defined(c))
|
|
return false;
|
|
+#endif
|
|
|
|
conf = c->lxc_conf;
|
|
if (container_disk_lock(c))
|
|
@@ -3070,8 +3333,20 @@ static bool container_destroy(struct lxc_container *c,
|
|
if (ret < 0) {
|
|
ERROR("Failed to destroy directory \"%s\" for \"%s\"", path,
|
|
c->name);
|
|
+#ifdef HAVE_ISULAD
|
|
+ char msg[BUFSIZ] = { 0 };
|
|
+ ret = snprintf(msg, BUFSIZ, "Failed to destroy directory \"%s\": %s", path, errno ? strerror(errno) : "error");
|
|
+ if (ret < 0 || ret >= BUFSIZ) {
|
|
+ ERROR("Sprintf failed");
|
|
+ goto out;
|
|
+ }
|
|
+ c->error_string = safe_strdup(msg);
|
|
+#endif
|
|
goto out;
|
|
}
|
|
+#ifdef HAVE_ISULAD
|
|
+ container_sock_dir_delete(c->name);
|
|
+#endif
|
|
INFO("Destroyed directory \"%s\" for \"%s\"", path, c->name);
|
|
|
|
on_success:
|
|
@@ -3082,6 +3357,11 @@ out:
|
|
free(path);
|
|
|
|
container_disk_unlock(c);
|
|
+#ifdef HAVE_ISULAD
|
|
+ if (bret && container_disk_removelock(c)) {
|
|
+ bret = false;
|
|
+ }
|
|
+#endif
|
|
return bret;
|
|
}
|
|
|
|
@@ -4042,8 +4322,13 @@ static int lxcapi_attach(struct lxc_container *c,
|
|
|
|
current_config = c->lxc_conf;
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ ret = lxc_attach(c, exec_function, exec_payload, options,
|
|
+ attached_process, &c->lxc_conf->errmsg);
|
|
+#else
|
|
ret = lxc_attach(c, exec_function, exec_payload, options,
|
|
attached_process);
|
|
+#endif
|
|
current_config = NULL;
|
|
return ret;
|
|
}
|
|
@@ -4063,7 +4348,11 @@ static int do_lxcapi_attach_run_wait(struct lxc_container *c,
|
|
command.program = (char *)program;
|
|
command.argv = (char **)argv;
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ ret = lxc_attach(c, lxc_attach_run_command, &command, options, &pid, NULL);
|
|
+#else
|
|
ret = lxc_attach(c, lxc_attach_run_command, &command, options, &pid);
|
|
+#endif
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
@@ -5257,6 +5546,560 @@ static int do_lxcapi_seccomp_notify_fd_active(struct lxc_container *c)
|
|
|
|
WRAP_API(int, lxcapi_seccomp_notify_fd_active)
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+/* isulad add set console fifos*/
|
|
+static bool do_lxcapi_set_terminal_default_fifos(struct lxc_container *c, const char *in, const char *out, const char *err)
|
|
+{
|
|
+ struct lxc_conf *conf = NULL;
|
|
+
|
|
+ if (!c || !c->lxc_conf)
|
|
+ return false;
|
|
+ if (container_mem_lock(c)) {
|
|
+ ERROR("Error getting mem lock");
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ conf = c->lxc_conf;
|
|
+ if (in) {
|
|
+ if (conf->console.init_fifo[0])
|
|
+ free(conf->console.init_fifo[0]);
|
|
+ conf->console.init_fifo[0] = safe_strdup(in);
|
|
+ }
|
|
+ if (out) {
|
|
+ if (conf->console.init_fifo[1])
|
|
+ free(conf->console.init_fifo[1]);
|
|
+ conf->console.init_fifo[1] = safe_strdup(out);
|
|
+ }
|
|
+ if (err) {
|
|
+ if (conf->console.init_fifo[2])
|
|
+ free(conf->console.init_fifo[2]);
|
|
+ conf->console.init_fifo[2] = safe_strdup(err);
|
|
+ }
|
|
+
|
|
+ container_mem_unlock(c);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+WRAP_API_3(bool, lxcapi_set_terminal_default_fifos, const char *, const char *, const char *)
|
|
+
|
|
+/* isulad add set info file path */
|
|
+static bool do_lxcapi_set_container_info_file(struct lxc_container *c, const char *info_file)
|
|
+{
|
|
+ struct lxc_conf *conf = NULL;
|
|
+
|
|
+ if (!c || !c->lxc_conf || !info_file)
|
|
+ return false;
|
|
+ if (container_mem_lock(c)) {
|
|
+ ERROR("Error getting mem lock");
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ conf = c->lxc_conf;
|
|
+ if (conf->container_info_file)
|
|
+ free(conf->container_info_file);
|
|
+ conf->container_info_file = safe_strdup(info_file);
|
|
+
|
|
+ container_mem_unlock(c);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+WRAP_API_1(bool, lxcapi_set_container_info_file, const char *)
|
|
+
|
|
+static bool do_lxcapi_want_disable_pty(struct lxc_container *c, bool state)
|
|
+{
|
|
+ if (!c || !c->lxc_conf)
|
|
+ return false;
|
|
+
|
|
+ if (container_mem_lock(c))
|
|
+ return false;
|
|
+
|
|
+ c->disable_pty = state;
|
|
+
|
|
+ container_mem_unlock(c);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+WRAP_API_1(bool, lxcapi_want_disable_pty, bool)
|
|
+
|
|
+static bool do_lxcapi_want_open_stdin(struct lxc_container *c, bool state)
|
|
+{
|
|
+ if (!c || !c->lxc_conf)
|
|
+ return false;
|
|
+
|
|
+ if (container_mem_lock(c))
|
|
+ return false;
|
|
+
|
|
+ c->open_stdin = state;
|
|
+
|
|
+ container_mem_unlock(c);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+WRAP_API_1(bool, lxcapi_want_open_stdin, bool)
|
|
+
|
|
+/* isulad add clean resources */
|
|
+static bool do_lxcapi_add_terminal_fifo(struct lxc_container *c, const char *in_fifo, const char *out_fifo, const char *err_fifo)
|
|
+{
|
|
+ bool ret = true;
|
|
+
|
|
+ if (!c || !c->lxc_conf)
|
|
+ return false;
|
|
+ if (container_mem_lock(c)) {
|
|
+ ERROR("Error getting mem lock");
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (lxc_cmd_set_terminal_fifos(c->name, c->config_path, in_fifo, out_fifo, err_fifo)) {
|
|
+ ERROR("Error set console fifos");
|
|
+ ret = false;
|
|
+ }
|
|
+
|
|
+ container_mem_unlock(c);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+WRAP_API_3(bool, lxcapi_add_terminal_fifo, const char *, const char *, const char *)
|
|
+
|
|
+static bool do_lxcapi_set_terminal_winch(struct lxc_container *c, unsigned int height, unsigned int width)
|
|
+{
|
|
+ bool ret = true;
|
|
+
|
|
+ if (!c || !c->lxc_conf)
|
|
+ return false;
|
|
+ if (container_mem_lock(c)) {
|
|
+ ERROR("Error getting mem lock");
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (lxc_cmd_set_terminal_winch(c->name, c->config_path, height, width)) {
|
|
+ ERROR("Error set terminal winch");
|
|
+ ret = false;
|
|
+ }
|
|
+
|
|
+ container_mem_unlock(c);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+WRAP_API_2(bool, lxcapi_set_terminal_winch, unsigned int, unsigned int)
|
|
+
|
|
+static bool do_lxcapi_set_exec_terminal_winch(struct lxc_container *c, const char *suffix, unsigned int height, unsigned int width)
|
|
+{
|
|
+ bool ret = true;
|
|
+
|
|
+ if (!c || !c->lxc_conf)
|
|
+ return false;
|
|
+ if (container_mem_lock(c)) {
|
|
+ ERROR("Error getting mem lock");
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (lxc_exec_cmd_set_terminal_winch(c->name, c->config_path, suffix, height, width)) {
|
|
+ ERROR("Error set terminal winch");
|
|
+ ret = false;
|
|
+ }
|
|
+
|
|
+ container_mem_unlock(c);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+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 *)
|
|
+
|
|
+/* isulad add start timeout */
|
|
+static bool do_lxcapi_set_start_timeout(struct lxc_container *c, unsigned int start_timeout)
|
|
+{
|
|
+ if (!c || !c->lxc_conf)
|
|
+ return false;
|
|
+ if (container_mem_lock(c)) {
|
|
+ ERROR("Error getting mem lock");
|
|
+ return false;
|
|
+ }
|
|
+ c->start_timeout = start_timeout;
|
|
+ container_mem_unlock(c);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+WRAP_API_1(bool, lxcapi_set_start_timeout, unsigned int)
|
|
+
|
|
+/* isulad add set image type */
|
|
+static bool do_lxcapi_set_oci_type(struct lxc_container *c, bool image_type_oci)
|
|
+{
|
|
+ if (!c || !c->lxc_conf)
|
|
+ return false;
|
|
+ if (container_mem_lock(c)) {
|
|
+ ERROR("Error getting mem lock");
|
|
+ return false;
|
|
+ }
|
|
+ c->image_type_oci = image_type_oci;
|
|
+ container_mem_unlock(c);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+WRAP_API_1(bool, lxcapi_set_oci_type, bool)
|
|
+
|
|
+static uint64_t metrics_get_ull(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item)
|
|
+{
|
|
+ char buf[81] = {0};
|
|
+ int len = 0;
|
|
+ uint64_t val = 0;
|
|
+
|
|
+ len = cgroup_ops->get(cgroup_ops, item, buf, sizeof(buf) - 1, c->name, c->config_path);
|
|
+ if (len <= 0) {
|
|
+ DEBUG("unable to read cgroup item %s", item);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ val = strtoull(buf, NULL, 0);
|
|
+ return val;
|
|
+}
|
|
+
|
|
+static uint64_t metrics_get_ull_with_max(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item)
|
|
+{
|
|
+ char buf[81] = {0};
|
|
+ int len = 0;
|
|
+ uint64_t val = 0;
|
|
+
|
|
+ len = cgroup_ops->get(cgroup_ops, item, buf, sizeof(buf) - 1, c->name, c->config_path);
|
|
+ if (len <= 0) {
|
|
+ DEBUG("unable to read cgroup item %s", item);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (strcmp(buf, "max") == 0) {
|
|
+ return ULONG_MAX;
|
|
+ }
|
|
+
|
|
+ val = strtoull(buf, NULL, 0);
|
|
+ return val;
|
|
+}
|
|
+
|
|
+static inline bool is_blk_metrics_read(const char *value)
|
|
+{
|
|
+ return strcmp(value, "Read") == 0;
|
|
+}
|
|
+
|
|
+static inline bool is_blk_metrics_write(const char *value)
|
|
+{
|
|
+ return strcmp(value, "Write") == 0;
|
|
+}
|
|
+
|
|
+static inline bool is_blk_metrics_total(const char *value)
|
|
+{
|
|
+ return strcmp(value, "Total") == 0;
|
|
+}
|
|
+
|
|
+static void metrics_get_blk_stats(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item, struct lxc_blkio_metrics *stats)
|
|
+{
|
|
+ char *buf = NULL;
|
|
+ int i = 0;
|
|
+ int len = 0;
|
|
+ int ret = 0;
|
|
+ char **lines = NULL;
|
|
+ char **cols = NULL;
|
|
+
|
|
+ len = cgroup_ops->get(cgroup_ops, item, NULL, 0, c->name, c->config_path);
|
|
+ if (len <= 0) {
|
|
+ DEBUG("unable to read cgroup item %s", item);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ buf = malloc(len + 1);
|
|
+ (void)memset(buf, 0, len + 1);
|
|
+ ret = cgroup_ops->get(cgroup_ops, item, buf, len, c->name, c->config_path);
|
|
+ if (ret <= 0) {
|
|
+ DEBUG("unable to read cgroup item %s", item);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ lines = lxc_string_split_and_trim(buf, '\n');
|
|
+ if (lines == NULL) {
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ (void)memset(stats, 0, sizeof(struct lxc_blkio_metrics));
|
|
+
|
|
+ for (i = 0; lines[i]; i++) {
|
|
+ cols = lxc_string_split_and_trim(lines[i], ' ');
|
|
+ if (cols == NULL) {
|
|
+ goto err_out;
|
|
+ }
|
|
+ if (lxc_array_len((void **)cols) == 3) {
|
|
+ if (is_blk_metrics_read(cols[1])) {
|
|
+ stats->read += strtoull(cols[2], NULL, 0);
|
|
+ } else if (is_blk_metrics_write(cols[1])) {
|
|
+ stats->write += strtoull(cols[2], NULL, 0);
|
|
+ }
|
|
+ }
|
|
+ if (lxc_array_len((void **)cols) == 2 && is_blk_metrics_total(cols[0])) {
|
|
+ stats->total = strtoull(cols[1], NULL, 0);
|
|
+ }
|
|
+
|
|
+ lxc_free_array((void **)cols, free);
|
|
+ }
|
|
+err_out:
|
|
+ lxc_free_array((void **)lines, free);
|
|
+out:
|
|
+ free(buf);
|
|
+ return;
|
|
+}
|
|
+
|
|
+static void metrics_get_io_stats_v2(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item, struct lxc_blkio_metrics *stats, func_is_io_stat_read is_io_stat_read, func_is_io_stat_write is_io_stat_write)
|
|
+{
|
|
+ char *buf = NULL;
|
|
+ int i = 0;
|
|
+ int j = 0;
|
|
+ int len = 0;
|
|
+ int ret = 0;
|
|
+ char **lines = NULL;
|
|
+ char **cols = NULL;
|
|
+ char **kv = NULL;
|
|
+
|
|
+ len = cgroup_ops->get(cgroup_ops, item, NULL, 0, c->name, c->config_path);
|
|
+ if (len <= 0) {
|
|
+ DEBUG("unable to read cgroup item %s", item);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ buf = malloc(len + 1);
|
|
+ (void)memset(buf, 0, len + 1);
|
|
+ ret = cgroup_ops->get(cgroup_ops, item, buf, len, c->name, c->config_path);
|
|
+ if (ret <= 0) {
|
|
+ DEBUG("unable to read cgroup item %s", item);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ lines = lxc_string_split_and_trim(buf, '\n');
|
|
+ if (lines == NULL) {
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ (void)memset(stats, 0, sizeof(struct lxc_blkio_metrics));
|
|
+ // line example:
|
|
+ // 259:0 rbytes=0 wbytes=12288 rios=0 wios=4 dbytes=0 dios=0
|
|
+ for (i = 0; lines[i]; i++) {
|
|
+ cols = lxc_string_split_and_trim(lines[i], ' ');
|
|
+ if (cols == NULL || lxc_array_len((void **)cols) < 2) {
|
|
+ goto err_out;
|
|
+ }
|
|
+ len = lxc_array_len((void **)cols);
|
|
+ for (j = 1; j < len; j++) {
|
|
+ kv = lxc_string_split(cols[j], '=');
|
|
+ if (kv == NULL || lxc_array_len((void **)kv) != 2) {
|
|
+ lxc_free_array((void **)kv, free);
|
|
+ continue;
|
|
+ }
|
|
+ if (is_io_stat_read(kv[0])) {
|
|
+ stats->read += strtoull(kv[1], NULL, 0);
|
|
+ } else if (is_io_stat_write(kv[0])) {
|
|
+ stats->write += strtoull(kv[1], NULL, 0);
|
|
+ }
|
|
+ lxc_free_array((void **)kv, free);
|
|
+ }
|
|
+ lxc_free_array((void **)cols, free);
|
|
+ }
|
|
+
|
|
+ stats->total = stats->read + stats->write;
|
|
+
|
|
+err_out:
|
|
+ lxc_free_array((void **)lines, free);
|
|
+out:
|
|
+ free(buf);
|
|
+ return;
|
|
+}
|
|
+
|
|
+static uint64_t metrics_match_get_ull(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item, const char *match, int column)
|
|
+{
|
|
+#define BUFSIZE 4096
|
|
+ char buf[BUFSIZE] = {0};
|
|
+ int i = 0;
|
|
+ int j = 0;
|
|
+ int len = 0;
|
|
+ uint64_t val = 0;
|
|
+ char **lines = NULL;
|
|
+ char **cols = NULL;
|
|
+ size_t matchlen = 0;
|
|
+
|
|
+ len = cgroup_ops->get(cgroup_ops, item, buf, sizeof(buf) - 1, c->name, c->config_path);
|
|
+ if (len <= 0) {
|
|
+ DEBUG("unable to read cgroup item %s", item);
|
|
+ goto err_out;
|
|
+ }
|
|
+
|
|
+ lines = lxc_string_split_and_trim(buf, '\n');
|
|
+ if (lines == NULL) {
|
|
+ goto err_out;
|
|
+ }
|
|
+
|
|
+ matchlen = strlen(match);
|
|
+ for (i = 0; lines[i]; i++) {
|
|
+ if (strncmp(lines[i], match, matchlen) != 0) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ cols = lxc_string_split_and_trim(lines[i], ' ');
|
|
+ if (cols == NULL) {
|
|
+ goto err1;
|
|
+ }
|
|
+ for (j = 0; cols[j]; j++) {
|
|
+ if (j == column) {
|
|
+ val = strtoull(cols[j], NULL, 0);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ lxc_free_array((void **)cols, free);
|
|
+ break;
|
|
+ }
|
|
+err1:
|
|
+ lxc_free_array((void **)lines, free);
|
|
+err_out:
|
|
+ return val;
|
|
+}
|
|
+
|
|
+static bool is_io_stat_rbytes(const char *value)
|
|
+{
|
|
+ return strcmp(value, "rbytes") == 0;
|
|
+}
|
|
+
|
|
+static bool is_io_stat_wbytes(const char *value)
|
|
+{
|
|
+ return strcmp(value, "wbytes") == 0;
|
|
+}
|
|
+
|
|
+static bool is_io_stat_rios(const char *value)
|
|
+{
|
|
+ return strcmp(value, "rios") == 0;
|
|
+}
|
|
+
|
|
+static bool is_io_stat_wios(const char *value)
|
|
+{
|
|
+ return strcmp(value, "wios") == 0;
|
|
+}
|
|
+
|
|
+static bool unified_metrics_get(struct lxc_container *c, struct cgroup_ops *cgroup_ops, struct lxc_container_metrics *metrics)
|
|
+{
|
|
+ // cpu
|
|
+ metrics->cpu_use_nanos = metrics_match_get_ull(c, cgroup_ops, "cpu.stat", "usage_usec", 1) * 1000;
|
|
+ metrics->cpu_use_user = metrics_match_get_ull(c, cgroup_ops, "cpu.stat", "user_usec", 1) * 1000;
|
|
+ metrics->cpu_use_sys = metrics_match_get_ull(c, cgroup_ops, "cpu.stat", "system_usec", 1) * 1000;
|
|
+
|
|
+ // io
|
|
+ metrics_get_io_stats_v2(c, cgroup_ops, "io.stat", &metrics->io_service_bytes, is_io_stat_rbytes, is_io_stat_wbytes);
|
|
+ metrics_get_io_stats_v2(c, cgroup_ops, "io.stat", &metrics->io_serviced, is_io_stat_rios, is_io_stat_wios);
|
|
+
|
|
+ // memory
|
|
+ metrics->mem_used = metrics_get_ull(c, cgroup_ops, "memory.current");
|
|
+ metrics->mem_limit = metrics_get_ull_with_max(c, cgroup_ops, "memory.max");
|
|
+ metrics->inactive_file_total = metrics_match_get_ull(c, cgroup_ops, "memory.stat", "inactive_file", 1);
|
|
+ metrics->cache = metrics_match_get_ull(c, cgroup_ops, "memory.stat", "file", 1);
|
|
+ metrics->cache_total = metrics->cache;
|
|
+
|
|
+ // cgroup v2 does not support kernel memory
|
|
+ metrics->kmem_used = 0;
|
|
+ metrics->kmem_limit = 0;
|
|
+
|
|
+ // pids
|
|
+ metrics->pids_current = metrics_get_ull(c, cgroup_ops, "pids.current");
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/* isulad add get container metrics */
|
|
+static bool do_lxcapi_get_container_metrics(struct lxc_container *c, struct lxc_container_metrics *metrics)
|
|
+{
|
|
+ call_cleaner(cgroup_exit) struct cgroup_ops *cgroup_ops = NULL;
|
|
+ const char *state = NULL;
|
|
+ if (c == NULL || c->lxc_conf == NULL || metrics == NULL) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ state = c->state(c);
|
|
+ metrics->state = state;
|
|
+
|
|
+ if (!is_stopped(c)) {
|
|
+ metrics->init = c->init_pid(c);
|
|
+ } else {
|
|
+ metrics->init = -1;
|
|
+ }
|
|
+
|
|
+ cgroup_ops = cgroup_init(c->lxc_conf);
|
|
+ if (cgroup_ops == NULL) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (cgroup_ops->cgroup_layout == CGROUP_LAYOUT_UNIFIED) {
|
|
+ return unified_metrics_get(c, cgroup_ops, metrics);
|
|
+ }
|
|
+
|
|
+ metrics->cpu_use_nanos = metrics_get_ull(c, cgroup_ops, "cpuacct.usage");
|
|
+ metrics->pids_current = metrics_get_ull(c, cgroup_ops, "pids.current");
|
|
+
|
|
+ metrics->rss_bytes = metrics_match_get_ull(c,cgroup_ops, "memory.stat", "rss", 1);
|
|
+ metrics->page_faults = metrics_match_get_ull(c,cgroup_ops, "memory.stat", "pgfault", 1);
|
|
+ metrics->major_page_faults = metrics_match_get_ull(c,cgroup_ops, "memory.stat", "pgmajfault", 1);
|
|
+
|
|
+ metrics->cpu_use_user = metrics_match_get_ull(c, cgroup_ops, "cpuacct.stat", "user", 1);
|
|
+ metrics->cpu_use_sys = metrics_match_get_ull(c, cgroup_ops, "cpuacct.stat", "system", 1);
|
|
+
|
|
+ // Try to read CFQ stats available on all CFQ enabled kernels first
|
|
+ metrics_get_blk_stats(c, cgroup_ops, "blkio.io_serviced_recursive", &metrics->io_serviced);
|
|
+ if (metrics->io_serviced.read == 0 && metrics->io_serviced.write == 0 && metrics->io_serviced.total == 0) {
|
|
+ metrics_get_blk_stats(c, cgroup_ops, "blkio.throttle.io_service_bytes", &metrics->io_service_bytes);
|
|
+ metrics_get_blk_stats(c, cgroup_ops, "blkio.throttle.io_serviced", &metrics->io_serviced);
|
|
+ } else {
|
|
+ metrics_get_blk_stats(c, cgroup_ops, "blkio.io_service_bytes_recursive", &metrics->io_service_bytes);
|
|
+ }
|
|
+
|
|
+ metrics->mem_used = metrics_get_ull(c, cgroup_ops, "memory.usage_in_bytes");
|
|
+ metrics->mem_limit = metrics_get_ull(c, cgroup_ops, "memory.limit_in_bytes");
|
|
+ metrics->kmem_used = metrics_get_ull(c, cgroup_ops, "memory.kmem.usage_in_bytes");
|
|
+ metrics->kmem_limit = metrics_get_ull(c, cgroup_ops, "memory.kmem.limit_in_bytes");
|
|
+
|
|
+ metrics->cache = metrics_match_get_ull(c, cgroup_ops, "memory.stat", "cache", 1);
|
|
+ metrics->cache_total = metrics_match_get_ull(c, cgroup_ops, "memory.stat", "total_cache", 1);
|
|
+ metrics->inactive_file_total = metrics_match_get_ull(c, cgroup_ops, "memory.stat", "total_inactive_file", 1);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+WRAP_API_1(bool, lxcapi_get_container_metrics, struct lxc_container_metrics *)
|
|
+
|
|
+#endif
|
|
+
|
|
struct lxc_container *lxc_container_new(const char *name, const char *configpath)
|
|
{
|
|
struct lxc_container *c;
|
|
@@ -5310,10 +6153,24 @@ 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;
|
|
+ }
|
|
+
|
|
+ if (load_config && file_exists(c->configfile)) {
|
|
+ if (!lxcapi_load_config(c, NULL)) {
|
|
+ fprintf(stderr, "Failed to load config for %s\n", name);
|
|
+ goto err;
|
|
+ }
|
|
+ }
|
|
+#else
|
|
if (file_exists(c->configfile) && !lxcapi_load_config(c, NULL)) {
|
|
fprintf(stderr, "Failed to load config for %s\n", name);
|
|
goto err;
|
|
}
|
|
+#endif
|
|
|
|
rc = ongoing_create(c);
|
|
switch (rc) {
|
|
@@ -5337,6 +6194,9 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
|
|
|
|
c->daemonize = true;
|
|
c->pidfile = NULL;
|
|
+#ifdef HAVE_ISULAD
|
|
+ c->image_type_oci = false;
|
|
+#endif
|
|
|
|
/* Assign the member functions. */
|
|
c->is_defined = lxcapi_is_defined;
|
|
@@ -5400,6 +6260,20 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
|
|
c->umount = lxcapi_umount;
|
|
c->seccomp_notify_fd = lxcapi_seccomp_notify_fd;
|
|
c->seccomp_notify_fd_active = lxcapi_seccomp_notify_fd_active;
|
|
+#ifdef HAVE_ISULAD
|
|
+ c->set_container_info_file = lxcapi_set_container_info_file;
|
|
+ c->set_terminal_init_fifos = lxcapi_set_terminal_default_fifos;
|
|
+ c->add_terminal_fifos = lxcapi_add_terminal_fifo;
|
|
+ c->set_terminal_winch = lxcapi_set_terminal_winch;
|
|
+ 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;
|
|
+ c->set_start_timeout = lxcapi_set_start_timeout;
|
|
+ c->set_oci_type = lxcapi_set_oci_type;
|
|
+ c->get_container_metrics = lxcapi_get_container_metrics;
|
|
+#endif
|
|
|
|
return c;
|
|
|
|
@@ -5408,6 +6282,19 @@ err:
|
|
return NULL;
|
|
}
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+// isulad: new container without load config to save time
|
|
+struct lxc_container *lxc_container_without_config_new(const char *name, const char *configpath)
|
|
+{
|
|
+ return do_lxc_container_new(name, configpath, false);
|
|
+}
|
|
+
|
|
+struct lxc_container *lxc_container_new(const char *name, const char *configpath)
|
|
+{
|
|
+ return do_lxc_container_new(name, configpath, true);
|
|
+}
|
|
+#endif
|
|
+
|
|
int lxc_get_wait_states(const char **states)
|
|
{
|
|
int i;
|
|
@@ -5578,11 +6465,21 @@ int list_active_containers(const char *lxcpath, char ***nret,
|
|
continue;
|
|
}
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ if (ct_name && ct_name_cnt) {
|
|
+ if (array_contains(&ct_name, p, ct_name_cnt)) {
|
|
+ if (is_hashed)
|
|
+ free(p);
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+#else
|
|
if (array_contains(&ct_name, p, ct_name_cnt)) {
|
|
if (is_hashed)
|
|
free(p);
|
|
continue;
|
|
}
|
|
+#endif
|
|
|
|
if (!add_to_array(&ct_name, p, ct_name_cnt)) {
|
|
if (is_hashed)
|
|
diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
|
|
index 3386bff..06e8f0b 100644
|
|
--- a/src/lxc/lxccontainer.h
|
|
+++ b/src/lxc/lxccontainer.h
|
|
@@ -26,6 +26,10 @@ extern "C" {
|
|
#define LXC_CREATE_MAXFLAGS (1 << 1) /*!< Number of \c LXC_CREATE* flags */
|
|
#define LXC_MOUNT_API_V1 1
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+#define LXC_IMAGE_OCI_KEY "lxc.imagetype.oci"
|
|
+#endif
|
|
+
|
|
struct bdev_specs;
|
|
|
|
struct lxc_snapshot;
|
|
@@ -40,6 +44,44 @@ struct lxc_mount {
|
|
int version;
|
|
};
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+struct lxc_blkio_metrics {
|
|
+ uint64_t read;
|
|
+ uint64_t write;
|
|
+ uint64_t total;
|
|
+};
|
|
+
|
|
+struct lxc_container_metrics {
|
|
+ /* State of container */
|
|
+ const char *state;
|
|
+ /* The process ID of the init container */
|
|
+ pid_t init;
|
|
+ /* Current pids */
|
|
+ uint64_t pids_current;
|
|
+ /* CPU usage */
|
|
+ uint64_t cpu_use_nanos;
|
|
+ uint64_t cpu_use_user;
|
|
+ uint64_t cpu_use_sys;
|
|
+ /* BlkIO usage */
|
|
+ struct lxc_blkio_metrics io_service_bytes;
|
|
+ struct lxc_blkio_metrics io_serviced;
|
|
+ /* Memory usage */
|
|
+ uint64_t mem_used;
|
|
+ uint64_t mem_limit;
|
|
+ uint64_t rss_bytes;
|
|
+ uint64_t page_faults;
|
|
+ uint64_t major_page_faults;
|
|
+ /* Kernel Memory usage */
|
|
+ uint64_t kmem_used;
|
|
+ uint64_t kmem_limit;
|
|
+ /* Cache usage */
|
|
+ uint64_t cache;
|
|
+ uint64_t cache_total;
|
|
+ /* total inactive file */
|
|
+ uint64_t inactive_file_total;
|
|
+};
|
|
+#endif
|
|
+
|
|
/*!
|
|
* An LXC container.
|
|
*
|
|
@@ -107,6 +149,38 @@ struct lxc_container {
|
|
/*! Full path to configuration file */
|
|
char *config_path;
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ /*! isulad:
|
|
+ * \private
|
|
+ * exit FIFO File to open used monitor the state of lxc monitor process.
|
|
+ */
|
|
+ char *exit_fifo;
|
|
+ /*! Whether container wishes to create pty or pipes for console log */
|
|
+ bool disable_pty;
|
|
+
|
|
+ /*! 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;
|
|
+
|
|
+ /*! isulad:
|
|
+ * \private
|
|
+ * start_timeout.
|
|
+ */
|
|
+ unsigned int start_timeout;
|
|
+
|
|
+ /*! isulad:
|
|
+ * \private
|
|
+ * image_type_oci
|
|
+ */
|
|
+ bool image_type_oci;
|
|
+#endif
|
|
+
|
|
/*!
|
|
* \brief Determine if \c /var/lib/lxc/$name/config exists.
|
|
*
|
|
@@ -884,6 +958,115 @@ struct lxc_container {
|
|
* \return Mount fd of the container's devpts instance.
|
|
*/
|
|
int (*devpts_fd)(struct lxc_container *c);
|
|
+
|
|
+#ifdef HAVE_ISULAD
|
|
+ /*! isulad add
|
|
+ * \brief An API call to set the path of info file
|
|
+ *
|
|
+ * \param c Container.
|
|
+ * \param info_file Value of the path of info file.
|
|
+ *
|
|
+ * \return \c true on success, else \c false.
|
|
+ */
|
|
+ bool (*set_container_info_file) (struct lxc_container *c, const char *info_file);
|
|
+
|
|
+ /*! isulad add
|
|
+ * \brief An API call to change the path of the console default fifos
|
|
+ *
|
|
+ * \param c Container.
|
|
+ * \param path Value of the console path.
|
|
+ *
|
|
+ * \return \c true on success, else \c false.
|
|
+ */
|
|
+ bool (*set_terminal_init_fifos)(struct lxc_container *c, const char *in, const char *out, const char *err);
|
|
+
|
|
+ /*! isulad add
|
|
+ * \brief An API call to add the path of terminal fifos
|
|
+ *
|
|
+ * \param c Container.
|
|
+ * \param path Value of the console path..
|
|
+ *
|
|
+ * \return \c true on success, else \c false.
|
|
+ */
|
|
+ bool (*add_terminal_fifos)(struct lxc_container *c, const char *in, const char *out, const char *err);
|
|
+
|
|
+ bool (*set_terminal_winch)(struct lxc_container *c, unsigned int height, unsigned int width);
|
|
+
|
|
+ bool (*set_exec_terminal_winch)(struct lxc_container *c, const char *suffix, unsigned int height, unsigned int width);
|
|
+
|
|
+ /*!
|
|
+ * \brief Change whether the container wants to create pty or pipes
|
|
+ * from the console log.
|
|
+ *
|
|
+ * \param c Container.
|
|
+ * \param state Value for the disable pty bit (0 or 1).
|
|
+ *
|
|
+ * \return \c true on success, else \c false.
|
|
+ */
|
|
+ bool (*want_disable_pty)(struct lxc_container *c, bool state);
|
|
+
|
|
+ /*!
|
|
+ * \brief Change whether the container wants to keep stdin active
|
|
+ * for parent process of container
|
|
+ *
|
|
+ * \param c Container.
|
|
+ * \param state Value for the open_stdin bit (0 or 1).
|
|
+ *
|
|
+ * \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);
|
|
+
|
|
+ /*! isulad add
|
|
+ * \brief An API call to set start timeout
|
|
+ *
|
|
+ * \param c Container.
|
|
+ * \param start_timeout Value of start timeout.
|
|
+ *
|
|
+ * \return \c true on success, else \c false.
|
|
+ */
|
|
+ bool (*set_start_timeout)(struct lxc_container *c, unsigned int start_timeout);
|
|
+
|
|
+ /*! isulad add
|
|
+ * \brief An API call to set oci type
|
|
+ *
|
|
+ * \param c Container.
|
|
+ * \param image_type_oci image oci type.
|
|
+ *
|
|
+ * \return \c true on success, else \c false.
|
|
+ */
|
|
+ bool (*set_oci_type)(struct lxc_container *c, bool image_type_oci);
|
|
+
|
|
+ /*! isulad add
|
|
+ * \brief An API call to set start timeout
|
|
+ *
|
|
+ * \param c Container.
|
|
+ * \param start_timeout Value of start timeout.
|
|
+ *
|
|
+ * \return \c true on success, else \c false.
|
|
+ */
|
|
+ bool (*get_container_metrics)(struct lxc_container *c, struct lxc_container_metrics *metrics);
|
|
+#endif
|
|
};
|
|
|
|
/*!
|
|
@@ -1017,6 +1200,20 @@ struct lxc_console_log {
|
|
*/
|
|
struct lxc_container *lxc_container_new(const char *name, const char *configpath);
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+/*!
|
|
+ * \brief Create a new container without loading config.
|
|
+ *
|
|
+ * \param name Name to use for container.
|
|
+ * \param configpath Full path to configuration file to use.
|
|
+ *
|
|
+ * \return Newly-allocated container, or \c NULL on error.
|
|
+ *
|
|
+ * \note This function can only used for listing container.
|
|
+ */
|
|
+struct lxc_container *lxc_container_without_config_new(const char *name, const char *configpath);
|
|
+#endif
|
|
+
|
|
/*!
|
|
* \brief Add a reference to the specified container.
|
|
*
|
|
diff --git a/src/lxc/start.c b/src/lxc/start.c
|
|
index 9f68304..70af128 100644
|
|
--- a/src/lxc/start.c
|
|
+++ b/src/lxc/start.c
|
|
@@ -344,7 +344,11 @@ static int setup_signal_fd(sigset_t *oldmask)
|
|
{
|
|
int ret;
|
|
sigset_t mask;
|
|
+#ifdef HAVE_ISULAD
|
|
+ const int signals[] = {SIGBUS, SIGILL, SIGSEGV, SIGWINCH, SIGTERM};
|
|
+#else
|
|
const int signals[] = {SIGBUS, SIGILL, SIGSEGV, SIGWINCH};
|
|
+#endif
|
|
|
|
/* Block everything except serious error signals. */
|
|
ret = sigfillset(&mask);
|
|
@@ -625,6 +629,16 @@ int lxc_poll(const char *name, struct lxc_handler *handler)
|
|
|
|
TRACE("Mainloop is ready");
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ // iSulad: close stdin pipe if we do not want open_stdin with container stdin
|
|
+ if (!handler->conf->console.open_stdin) {
|
|
+ if (handler->conf->console.pipes[0][1] > 0) {
|
|
+ close(handler->conf->console.pipes[0][1]);
|
|
+ handler->conf->console.pipes[0][1] = -1;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
ret = lxc_mainloop(&descr, -1);
|
|
if (descr.type == LXC_MAINLOOP_EPOLL)
|
|
close_prot_errno_disarm(descr.epfd);
|
|
@@ -634,7 +648,11 @@ int lxc_poll(const char *name, struct lxc_handler *handler)
|
|
if (console) {
|
|
ret = lxc_terminal_mainloop_add(&descr_console, console);
|
|
if (ret == 0)
|
|
+#ifdef HAVE_ISULAD
|
|
+ ret = isulad_safe_mainloop(&descr_console, 100);
|
|
+#else
|
|
ret = lxc_mainloop(&descr_console, 0);
|
|
+#endif
|
|
}
|
|
|
|
out_mainloop_console:
|
|
@@ -718,6 +736,12 @@ struct lxc_handler *lxc_init_handler(struct lxc_handler *old,
|
|
}
|
|
|
|
handler->name = name;
|
|
+
|
|
+#ifdef HAVE_ISULAD
|
|
+ handler->exit_code = -1; /* isulad: record exit code of container */
|
|
+ handler->image_type_oci = false;
|
|
+#endif
|
|
+
|
|
if (daemonize)
|
|
handler->transient_pid = lxc_raw_getpid();
|
|
else
|
|
@@ -768,6 +792,10 @@ int lxc_init(const char *name, struct lxc_handler *handler)
|
|
int ret;
|
|
const char *loglevel;
|
|
struct lxc_conf *conf = handler->conf;
|
|
+#ifdef HAVE_ISULAD
|
|
+ conf->console.disable_pty = handler->disable_pty;
|
|
+ conf->console.open_stdin = handler->open_stdin;
|
|
+#endif
|
|
|
|
handler->monitor_pid = lxc_raw_getpid();
|
|
status_fd = open("/proc/self/status", O_RDONLY | O_CLOEXEC);
|
|
@@ -908,6 +936,186 @@ void lxc_expose_namespace_environment(const struct lxc_handler *handler)
|
|
}
|
|
}
|
|
|
|
+
|
|
+#ifdef HAVE_ISULAD
|
|
+/* isulad: start timeout thread */
|
|
+typedef enum {
|
|
+ START_INIT,
|
|
+ START_TIMEOUT,
|
|
+ START_MAX,
|
|
+} start_timeout_t;
|
|
+
|
|
+static start_timeout_t global_timeout_state = START_INIT;
|
|
+static sem_t global_timeout_sem;
|
|
+
|
|
+struct start_timeout_conf {
|
|
+ unsigned int timeout;
|
|
+ int errfd;
|
|
+};
|
|
+
|
|
+void trim_line(char *s)
|
|
+{
|
|
+ size_t len;
|
|
+
|
|
+ len = strlen(s);
|
|
+ while ((len > 1) && (s[len - 1] == '\n'))
|
|
+ s[--len] = '\0';
|
|
+}
|
|
+
|
|
+static int _read_procs_file(const char *path, pid_t **pids, size_t *len)
|
|
+{
|
|
+ FILE *f;
|
|
+ char *line = NULL;
|
|
+ size_t sz = 0;
|
|
+ pid_t *tmp_pids = NULL;
|
|
+
|
|
+ f = fopen_cloexec(path, "r");
|
|
+ if (!f)
|
|
+ return -1;
|
|
+
|
|
+ while (getline(&line, &sz, f) != -1) {
|
|
+ pid_t pid;
|
|
+ trim_line(line);
|
|
+ pid = (pid_t)atoll(line);
|
|
+ if (lxc_mem_realloc((void **)&tmp_pids, sizeof(pid_t) * (*len + 1), *pids, sizeof(pid_t) * (*len)) != 0) {
|
|
+ free(*pids);
|
|
+ *pids = NULL;
|
|
+ ERROR("out of memory");
|
|
+ free(line);
|
|
+ fclose(f);
|
|
+ return -1;
|
|
+ }
|
|
+ *pids = tmp_pids;
|
|
+
|
|
+ (*pids)[*len] = pid;
|
|
+ (*len)++;
|
|
+ }
|
|
+
|
|
+ free(line);
|
|
+ fclose(f);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int _recursive_read_cgroup_procs(const char *dirpath, pid_t **pids, size_t *len)
|
|
+{
|
|
+ struct dirent *direntp = NULL;
|
|
+ DIR *dir = NULL;
|
|
+ int ret, failed = 0;
|
|
+ char pathname[PATH_MAX];
|
|
+
|
|
+ dir = opendir(dirpath);
|
|
+ if (dir == NULL) {
|
|
+ WARN("Failed to open \"%s\"", dirpath);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ while ((direntp = readdir(dir))) {
|
|
+ struct stat mystat;
|
|
+ int rc;
|
|
+
|
|
+ if (!strcmp(direntp->d_name, ".") ||
|
|
+ !strcmp(direntp->d_name, ".."))
|
|
+ continue;
|
|
+
|
|
+ rc = snprintf(pathname, PATH_MAX, "%s/%s", dirpath, direntp->d_name);
|
|
+ if (rc < 0 || rc >= PATH_MAX) {
|
|
+ failed = 1;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (strcmp(direntp->d_name, "cgroup.procs") == 0) {
|
|
+ if (_read_procs_file(pathname, pids, len)) {
|
|
+ failed = 1;
|
|
+
|
|
+ }
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ ret = lstat(pathname, &mystat);
|
|
+ if (ret) {
|
|
+ failed = 1;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (S_ISDIR(mystat.st_mode)) {
|
|
+ if (_recursive_read_cgroup_procs(pathname, pids, len) < 0)
|
|
+ failed = 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = closedir(dir);
|
|
+ if (ret) {
|
|
+ WARN("Failed to close directory \"%s\"", dirpath);
|
|
+ failed = 1;
|
|
+ }
|
|
+
|
|
+ return failed ? -1 : 0;
|
|
+}
|
|
+
|
|
+int get_all_pids(struct cgroup_ops *cg_ops, pid_t **pids, size_t *len)
|
|
+{
|
|
+ const char *devices_path = NULL;
|
|
+
|
|
+ devices_path = cg_ops->get_cgroup_full_path(cg_ops, "devices");
|
|
+ if (!file_exists(devices_path)) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return _recursive_read_cgroup_procs(devices_path, pids, len);
|
|
+}
|
|
+
|
|
+static int set_cgroup_freezer(struct cgroup_ops *cg_ops, const char *value)
|
|
+{
|
|
+ char *fullpath;
|
|
+ int ret;
|
|
+
|
|
+ fullpath = must_make_path(cg_ops->get_cgroup_full_path(cg_ops, "freezer"), "freezer.state", NULL);
|
|
+ ret = lxc_write_to_file(fullpath, value, strlen(value), false, 0666);
|
|
+ free(fullpath);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/* isulad: kill all process in container cgroup path */
|
|
+static void signal_all_processes(struct lxc_handler *handler)
|
|
+{
|
|
+ int ret;
|
|
+ struct cgroup_ops *cg_ops = handler->cgroup_ops;
|
|
+ pid_t *pids = NULL;
|
|
+ size_t len = 0, i;
|
|
+
|
|
+ ret = set_cgroup_freezer(cg_ops, "FROZEN");
|
|
+ if (ret < 0 && errno != ENOENT) {
|
|
+ WARN("cgroup_set frozen failed");
|
|
+ }
|
|
+
|
|
+ ret = get_all_pids(cg_ops, &pids, &len);
|
|
+ if (ret < 0) {
|
|
+ WARN("failed to get all pids");
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < len; i++) {
|
|
+ ret = kill(pids[i], SIGKILL);
|
|
+ if (ret < 0 && errno != ESRCH) {
|
|
+ WARN("Can not kill process (pid=%d) with SIGKILL for container %s", pids[i], handler->name);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = set_cgroup_freezer(cg_ops, "THAWED");
|
|
+ if (ret < 0 && errno != ENOENT) {
|
|
+ WARN("cgroup_set thawed failed");
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < len; i++) {
|
|
+ ret = lxc_wait_for_pid_status(pids[i]);
|
|
+ if (ret < 0 && errno != ECHILD) {
|
|
+ WARN("Failed to wait pid %d for container %s: %s", pids[i], handler->name, strerror(errno));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ free(pids);
|
|
+}
|
|
+#endif
|
|
+
|
|
void lxc_end(struct lxc_handler *handler)
|
|
{
|
|
int ret;
|
|
@@ -945,14 +1153,44 @@ void lxc_end(struct lxc_handler *handler)
|
|
|
|
handler->lsm_ops->cleanup(handler->lsm_ops, handler->conf, handler->lxcpath);
|
|
|
|
+
|
|
+#ifdef HAVE_ISULAD
|
|
+ // close maincmd fd before destroy cgroup for isulad
|
|
+ if (handler->conf->reboot == REBOOT_NONE) {
|
|
+ /* For all new state clients simply close the command socket.
|
|
+ * This will inform all state clients that the container is
|
|
+ * STOPPED and also prevents a race between a open()/close() on
|
|
+ * the command socket causing a new process to get ECONNREFUSED
|
|
+ * because we haven't yet closed the command socket.
|
|
+ */
|
|
+ close_prot_errno_disarm(handler->conf->maincmd_fd);
|
|
+ TRACE("Closed command socket");
|
|
+ }
|
|
+ int retry_count = 0;
|
|
+ int max_retry = 10;
|
|
+retry:
|
|
+ if (cgroup_ops != NULL && !cgroup_ops->payload_destroy(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);
|
|
+ }
|
|
+#else
|
|
if (cgroup_ops) {
|
|
cgroup_ops->payload_destroy(cgroup_ops, handler);
|
|
cgroup_ops->monitor_destroy(cgroup_ops, handler);
|
|
}
|
|
+#endif
|
|
|
|
put_lxc_rootfs(&handler->conf->rootfs, true);
|
|
|
|
if (handler->conf->reboot == REBOOT_NONE) {
|
|
+#ifndef HAVE_ISULAD
|
|
/* For all new state clients simply close the command socket.
|
|
* This will inform all state clients that the container is
|
|
* STOPPED and also prevents a race between a open()/close() on
|
|
@@ -961,12 +1199,23 @@ void lxc_end(struct lxc_handler *handler)
|
|
*/
|
|
close_prot_errno_disarm(handler->conf->maincmd_fd);
|
|
TRACE("Closed command socket");
|
|
+#endif
|
|
|
|
/* This function will try to connect to the legacy lxc-monitord
|
|
* state server and only exists for backwards compatibility.
|
|
*/
|
|
lxc_monitor_send_state(name, STOPPED, handler->lxcpath);
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ /* isuald: write exit code to exit fifo */
|
|
+ if (handler->conf->exit_fd >= 0) {
|
|
+ ret = write(handler->conf->exit_fd, &handler->exit_code, sizeof(int));
|
|
+ if (ret != sizeof(int)) {
|
|
+ SYSERROR("Failed to write to exit code to exit fifo.");
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
/* The command socket is closed so no one can acces the command
|
|
* socket anymore so there's no need to lock it.
|
|
*/
|
|
@@ -1060,6 +1309,25 @@ static int do_start(void *data)
|
|
|
|
lxc_sync_fini_parent(handler);
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ sigset_t mask;
|
|
+
|
|
+ /*isulad: restore default signal handlers and unblock all signals*/
|
|
+ for (int i = 1; i < NSIG; i++)
|
|
+ signal(i, SIG_DFL);
|
|
+
|
|
+ ret = sigfillset(&mask);
|
|
+ if (ret < 0) {
|
|
+ SYSERROR("Failed to fill signal mask");
|
|
+ goto out_warn_father;
|
|
+ }
|
|
+ ret = sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
|
+ if (ret < 0) {
|
|
+ SYSERROR("Failed to set signal mask");
|
|
+ goto out_warn_father;
|
|
+ }
|
|
+#endif
|
|
+
|
|
if (lxc_abstract_unix_recv_one_fd(data_sock1, &status_fd, NULL, 0) < 0) {
|
|
ERROR("Failed to receive status file descriptor from parent process");
|
|
goto out_warn_father;
|
|
@@ -1153,7 +1421,11 @@ static int do_start(void *data)
|
|
* means that migration won't work, but at least we won't spew output
|
|
* where it isn't wanted.
|
|
*/
|
|
+#ifdef HAVE_ISULAD
|
|
+ if (!handler->disable_pty && handler->daemonize && !handler->conf->autodev) {
|
|
+#else
|
|
if (handler->daemonize && !handler->conf->autodev) {
|
|
+#endif
|
|
char path[PATH_MAX];
|
|
|
|
ret = strnprintf(path, sizeof(path), "%s/dev/null",
|
|
@@ -1269,6 +1541,9 @@ static int do_start(void *data)
|
|
/* Setup the container, ip, names, utsname, ... */
|
|
ret = lxc_setup(handler);
|
|
if (ret < 0) {
|
|
+#ifdef HAVE_ISULAD
|
|
+ lxc_write_error_message(handler->conf->errpipe[1], "Failed to setup lxc, please check the config file.");
|
|
+#endif
|
|
ERROR("Failed to setup container \"%s\"", handler->name);
|
|
goto out_warn_father;
|
|
}
|
|
@@ -1291,6 +1566,43 @@ static int do_start(void *data)
|
|
DEBUG("Set PR_SET_NO_NEW_PRIVS to block execve() gainable privileges");
|
|
}
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ /* isulad: dup2 pipe[0][0] to container stdin, pipe[1][1] to container stdout, pipe[2][1] to container stderr */
|
|
+ if (handler->disable_pty) {
|
|
+ if (handler->conf->console.pipes[0][1] >= 0) {
|
|
+ close(handler->conf->console.pipes[0][1]);
|
|
+ handler->conf->console.pipes[0][1] = -1;
|
|
+ }
|
|
+
|
|
+ if (handler->conf->console.pipes[0][0] >= 0) {
|
|
+ ret = dup2(handler->conf->console.pipes[0][0], STDIN_FILENO);
|
|
+ if (ret < 0)
|
|
+ goto out_warn_father;
|
|
+ }
|
|
+
|
|
+ if (handler->conf->console.pipes[1][0] >= 0) {
|
|
+ close(handler->conf->console.pipes[1][0]);
|
|
+ handler->conf->console.pipes[1][0] = -1;
|
|
+ }
|
|
+
|
|
+ if (handler->conf->console.pipes[1][1] >= 0) {
|
|
+ ret = dup2(handler->conf->console.pipes[1][1], STDOUT_FILENO);
|
|
+ if (ret < 0)
|
|
+ goto out_warn_father;
|
|
+ }
|
|
+ if (handler->conf->console.pipes[2][0] >= 0) {
|
|
+ close(handler->conf->console.pipes[2][0]);
|
|
+ handler->conf->console.pipes[2][0] = -1;
|
|
+ }
|
|
+
|
|
+ if (handler->conf->console.pipes[2][1] >= 0) {
|
|
+ ret = dup2(handler->conf->console.pipes[2][1], STDERR_FILENO);
|
|
+ if (ret < 0)
|
|
+ goto out_warn_father;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
/* If we mounted a temporary proc, then unmount it now. */
|
|
tmp_proc_unmount(handler->conf);
|
|
|
|
@@ -1307,7 +1619,11 @@ static int do_start(void *data)
|
|
|
|
close_prot_errno_disarm(handler->sigfd);
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ if (!handler->disable_pty && handler->conf->console.pty < 0 && handler->daemonize) {
|
|
+#else
|
|
if (handler->conf->console.pty < 0 && handler->daemonize) {
|
|
+#endif
|
|
if (devnull_fd < 0) {
|
|
devnull_fd = open_devnull();
|
|
if (devnull_fd < 0)
|
|
@@ -1326,6 +1642,16 @@ static int do_start(void *data)
|
|
setsid();
|
|
|
|
if (handler->conf->init_cwd) {
|
|
+#ifdef HAVE_ISULAD
|
|
+ /* try to craete workdir if not exist */
|
|
+ struct stat st;
|
|
+ if (stat(handler->conf->init_cwd, &st) < 0 && mkdir_p(handler->conf->init_cwd, 0755) < 0) {
|
|
+ SYSERROR("Try to create directory \"%s\" as workdir failed", handler->conf->init_cwd);
|
|
+ lxc_write_error_message(handler->conf->errpipe[1], "%s:%d: Failed to create workdir: %s.",
|
|
+ __FILE__, __LINE__, strerror(errno));
|
|
+ goto out_warn_father;
|
|
+ }
|
|
+#endif
|
|
ret = chdir(handler->conf->init_cwd);
|
|
if (ret < 0) {
|
|
SYSERROR("Could not change directory to \"%s\"",
|
|
@@ -1372,12 +1698,26 @@ static int do_start(void *data)
|
|
}
|
|
}
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
|
|
+ SYSERROR("Failed to keep permitted capabilities");
|
|
+ goto out_warn_father;
|
|
+ }
|
|
+#endif
|
|
+
|
|
/* The container has been setup. We can now switch to an unprivileged
|
|
* uid/gid.
|
|
*/
|
|
new_uid = handler->conf->init_uid;
|
|
new_gid = handler->conf->init_gid;
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ // isulad: set env home in container, must before "Avoid unnecessary syscalls."
|
|
+ if (lxc_setup_env_home(new_uid) < 0) {
|
|
+ goto out_warn_father;
|
|
+ }
|
|
+#endif
|
|
+
|
|
/* Avoid unnecessary syscalls. */
|
|
if (new_uid == nsuid)
|
|
new_uid = LXC_INVALID_UID;
|
|
@@ -1419,6 +1759,19 @@ static int do_start(void *data)
|
|
goto out_warn_father;
|
|
}
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ /* isulad: drop the cap of current process */
|
|
+ if (prctl(PR_SET_KEEPCAPS, 0) < 0) {
|
|
+ SYSERROR("Failed to clear permitted capabilities");
|
|
+ goto out_warn_father;
|
|
+ }
|
|
+
|
|
+ if (lxc_drop_caps(handler->conf)) {
|
|
+ SYSERROR("Failed to drop caps");
|
|
+ goto out_warn_father;
|
|
+ }
|
|
+#endif
|
|
+
|
|
if (handler->conf->monitor_signal_pdeath != SIGKILL) {
|
|
ret = lxc_set_death_signal(handler->conf->monitor_signal_pdeath,
|
|
handler->monitor_pid, status_fd);
|
|
@@ -1433,7 +1786,12 @@ static int do_start(void *data)
|
|
* After this call, we are in error because this ops should not return
|
|
* as it execs.
|
|
*/
|
|
+#ifdef HAVE_ISULAD
|
|
+ close_prot_errno_disarm(status_fd);
|
|
+ handler->ops->start(handler, handler->data, handler->daemonize ? handler->conf->errpipe[1] : -1);
|
|
+#else
|
|
handler->ops->start(handler, handler->data);
|
|
+#endif
|
|
|
|
out_warn_father:
|
|
/*
|
|
@@ -1604,6 +1962,94 @@ static inline void resolve_cgroup_clone_flags(struct lxc_handler *handler)
|
|
handler->ns_unshare_flags |= CLONE_NEWCGROUP;
|
|
}
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+static int lxc_write_container_info(char *filename, pid_t pid, pid_t p_pid,
|
|
+ unsigned long long start_at, unsigned long long p_start_at)
|
|
+{
|
|
+ FILE *pid_fp = NULL;
|
|
+ int ret = 0;
|
|
+
|
|
+ pid_fp = lxc_fopen(filename, "w");
|
|
+ if (pid_fp == NULL) {
|
|
+ SYSERROR("Failed to create pidfile '%s'",filename);
|
|
+ ret = -1;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (fprintf(pid_fp, "%d %llu %d %llu\n", pid, start_at, p_pid, p_start_at) < 0) {
|
|
+ SYSERROR("Failed to write '%s'", filename);
|
|
+ ret = -1;
|
|
+ goto out;
|
|
+ }
|
|
+out:
|
|
+ if (pid_fp)
|
|
+ fclose(pid_fp);
|
|
+ pid_fp = NULL;
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int lxc_check_container_info(char *filename, pid_t pid, pid_t p_pid,
|
|
+ unsigned long long start_at, unsigned long long p_start_at)
|
|
+{
|
|
+ int ret = 0;
|
|
+ int num;
|
|
+ char sbuf[1024] = {0}; /* bufs for stat */
|
|
+ int saved_pid; /* process id */
|
|
+ int saved_ppid; /* pid of parent process */
|
|
+ unsigned long long saved_start_time; /* start time of process -- seconds since 1-1-70 */
|
|
+ unsigned long long saved_pstart_time; /* start time of parent process -- seconds since 1-1-70 */
|
|
+
|
|
+ if ((lxc_file2str(filename, sbuf, sizeof(sbuf))) == -1) {
|
|
+ SYSERROR("Failed to read pidfile %s", filename);
|
|
+ ret = -1;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ num = sscanf(sbuf, "%d %Lu %d %Lu", &saved_pid, &saved_start_time, &saved_ppid, &saved_pstart_time);
|
|
+ if (num != 4) {
|
|
+ SYSERROR("Call sscanf error");
|
|
+ ret = -1;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (pid != saved_pid || p_pid != saved_ppid
|
|
+ || start_at != saved_start_time || p_start_at != saved_pstart_time) {
|
|
+ ERROR("Check container info failed");
|
|
+ ret = -1;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+out:
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/* isuald: save pid/ppid info */
|
|
+static int lxc_save_container_info(char *filename, pid_t pid)
|
|
+{
|
|
+ int ret = 0;
|
|
+ pid_t p_pid = 0;
|
|
+ unsigned long long start_at = 0;
|
|
+ unsigned long long p_start_at = 0;
|
|
+
|
|
+ start_at = lxc_get_process_startat(pid);
|
|
+ p_pid = getpid();
|
|
+ p_start_at = lxc_get_process_startat(p_pid);
|
|
+
|
|
+ ret = lxc_write_container_info(filename, pid, p_pid, start_at, p_start_at);
|
|
+ if (ret != 0) {
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ ret = lxc_check_container_info(filename, pid, p_pid, start_at, p_start_at);
|
|
+ if (ret != 0) {
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+out:
|
|
+ return ret;
|
|
+}
|
|
+#endif
|
|
+
|
|
/* lxc_spawn() performs crucial setup tasks and clone()s the new process which
|
|
* exec()s the requested container binary.
|
|
* Note that lxc_spawn() runs in the parent namespaces. Any operations performed
|
|
@@ -1741,6 +2187,32 @@ static int lxc_spawn(struct lxc_handler *handler)
|
|
handler->clone_flags &= ~CLONE_PIDFD;
|
|
TRACE("Cloned child process %d", handler->pid);
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ /* isulad: close pipe after clone */
|
|
+ if (handler->conf->console.pipes[0][0] >= 0) {
|
|
+ close(handler->conf->console.pipes[0][0]);
|
|
+ handler->conf->console.pipes[0][0] = -1;
|
|
+ }
|
|
+
|
|
+ if (handler->conf->console.pipes[1][1] >= 0) {
|
|
+ close(handler->conf->console.pipes[1][1]);
|
|
+ handler->conf->console.pipes[1][1] = -1;
|
|
+ }
|
|
+
|
|
+ if (handler->conf->console.pipes[2][1] >= 0) {
|
|
+ close(handler->conf->console.pipes[2][1]);
|
|
+ handler->conf->console.pipes[2][1] = -1;
|
|
+ }
|
|
+
|
|
+ /* isulad: save pid/ppid info into file*/
|
|
+ if (handler->conf->container_info_file) {
|
|
+ if (lxc_save_container_info(handler->conf->container_info_file, handler->pid)) {
|
|
+ ERROR("Failed to save cloned container pid");
|
|
+ goto out_delete_net;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
ret = core_scheduling(handler);
|
|
if (ret < 0)
|
|
goto out_delete_net;
|
|
@@ -1757,6 +2229,13 @@ static int lxc_spawn(struct lxc_handler *handler)
|
|
if (ret < 0)
|
|
SYSERROR("Failed to set environment variable: LXC_PID=%s", pidstr);
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ if (handler->cgroup_ops->container_cgroup) {
|
|
+ if (setenv("LXC_CGROUP_PATH", handler->cgroup_ops->container_cgroup, 1))
|
|
+ SYSERROR("Failed to set environment variable: LXC_CGROUP_PATH=%s.", handler->cgroup_ops->container_cgroup);
|
|
+ }
|
|
+#endif
|
|
+
|
|
for (i = 0; i < LXC_NS_MAX; i++)
|
|
if (handler->ns_on_clone_flags & ns_info[i].clone_flag)
|
|
INFO("Cloned %s", ns_info[i].flag_name);
|
|
@@ -1848,7 +2327,11 @@ static int lxc_spawn(struct lxc_handler *handler)
|
|
goto out_delete_net;
|
|
}
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ ret = setup_resource_limits(conf, handler->pid, conf->errpipe[1]);
|
|
+#else
|
|
ret = setup_resource_limits(conf, handler->pid);
|
|
+#endif
|
|
if (ret < 0) {
|
|
ERROR("Failed to setup resource limits");
|
|
goto out_delete_net;
|
|
@@ -1911,6 +2394,27 @@ static int lxc_spawn(struct lxc_handler *handler)
|
|
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;
|
|
+ }
|
|
+
|
|
+ if (START_TIMEOUT == global_timeout_state) {
|
|
+ lxc_write_error_message(conf->errpipe[1], "Starting the container \"%s\" timeout.", name);
|
|
+ ERROR("Starting the container \"%s\" timeout.", name);
|
|
+ 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
|
|
+
|
|
if (!lxc_sync_wake_child(handler, START_SYNC_FDS))
|
|
goto out_delete_net;
|
|
|
|
@@ -1969,6 +2473,22 @@ 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;
|
|
+ }
|
|
+
|
|
+ if (START_TIMEOUT == global_timeout_state) {
|
|
+ lxc_write_error_message(conf->errpipe[1], "Starting the container \"%s\" timeout.", name);
|
|
+ ERROR("Starting the container \"%s\" timeout.", name);
|
|
+ goto out_abort;
|
|
+ }
|
|
+
|
|
+#endif
|
|
+
|
|
ret = lxc_set_state(name, handler, RUNNING);
|
|
if (ret < 0) {
|
|
ERROR("Failed to set state to \"%s\"", lxc_state2str(RUNNING));
|
|
@@ -2014,9 +2534,82 @@ static int lxc_inherit_namespaces(struct lxc_handler *handler)
|
|
return 0;
|
|
}
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+/* isulad: start timeout thread function */
|
|
+static void* wait_start_timeout(void *arg)
|
|
+{
|
|
+ struct start_timeout_conf *conf = (struct start_timeout_conf *)arg;
|
|
+
|
|
+ sem_post(&global_timeout_sem);
|
|
+
|
|
+ if (!conf || conf->timeout < 1)
|
|
+ goto out;
|
|
+
|
|
+ sleep(conf->timeout);
|
|
+
|
|
+ global_timeout_state = START_TIMEOUT;
|
|
+
|
|
+out:
|
|
+ free(conf);
|
|
+ return ((void *)0);
|
|
+}
|
|
+
|
|
+/* isulad: create start timeout thread */
|
|
+static int create_start_timeout_thread(struct lxc_conf *conf, unsigned int start_timeout)
|
|
+{
|
|
+ int ret = 0;
|
|
+ pthread_t ptid;
|
|
+ pthread_attr_t attr;
|
|
+ struct start_timeout_conf *timeout_conf = NULL;
|
|
+
|
|
+ if (sem_init(&global_timeout_sem, 0, 0)) {
|
|
+ ERROR("Failed to init start timeout semaphore");/*lint !e613*/
|
|
+ ret = -1;
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ timeout_conf = malloc(sizeof(struct start_timeout_conf));
|
|
+ if (timeout_conf == NULL) {
|
|
+ ERROR("Failed to malloc start timeout conf");
|
|
+ ret = -1;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ memset(timeout_conf, 0, sizeof(struct start_timeout_conf));
|
|
+ timeout_conf->errfd = conf->errpipe[1];
|
|
+ timeout_conf->timeout = start_timeout;
|
|
+
|
|
+ pthread_attr_init(&attr);
|
|
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
|
+ ret = pthread_create(&ptid, &attr, wait_start_timeout, timeout_conf);
|
|
+ pthread_attr_destroy(&attr);
|
|
+ if (ret != 0) {
|
|
+ ERROR("Create start wait timeout thread failed");
|
|
+ free(timeout_conf);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ sem_wait(&global_timeout_sem);
|
|
+out:
|
|
+ sem_destroy(&global_timeout_sem);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+// isulad: send '128 + signal' if container is killed by signal.
|
|
+#define EXIT_SIGNAL_OFFSET 128
|
|
+#endif
|
|
+
|
|
+#ifdef HAVE_ISULAD
|
|
+int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops,
|
|
+ void *data, const char *lxcpath, bool daemonize, int *error_num,
|
|
+ unsigned int start_timeout)
|
|
+{
|
|
+ int exit_code;
|
|
+#else
|
|
int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops,
|
|
void *data, const char *lxcpath, bool daemonize, int *error_num)
|
|
{
|
|
+#endif
|
|
int ret, status;
|
|
const char *name = handler->name;
|
|
struct lxc_conf *conf = handler->conf;
|
|
@@ -2032,6 +2625,17 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops,
|
|
handler->daemonize = daemonize;
|
|
cgroup_ops = handler->cgroup_ops;
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ /* isulad: add start timeout limit */
|
|
+ if (start_timeout > 0) {
|
|
+ ret = create_start_timeout_thread(conf, start_timeout);
|
|
+ if (ret) {
|
|
+ ERROR("Failed to create start timeout thread for container \"%s\".", name);
|
|
+ goto out_abort;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
if (!attach_block_device(handler->conf)) {
|
|
ERROR("Failed to attach block device");
|
|
ret = -1;
|
|
@@ -2116,11 +2720,13 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops,
|
|
goto out_delete_network;
|
|
}
|
|
|
|
+#ifndef HAVE_ISULAD
|
|
if (!handler->init_died && handler->pid > 0) {
|
|
ERROR("Child process is not killed");
|
|
ret = -1;
|
|
goto out_delete_network;
|
|
}
|
|
+#endif
|
|
|
|
status = lxc_wait_for_pid_status(handler->pid);
|
|
if (status < 0)
|
|
@@ -2130,6 +2736,20 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops,
|
|
* reboot. This should mean it was an lxc-execute which simply exited.
|
|
* In any case, treat it as a 'halt'.
|
|
*/
|
|
+#ifdef HAVE_ISULAD
|
|
+ // isulad: recored log for container init exit
|
|
+ if (WIFSIGNALED(status)) {
|
|
+ int signal_nr = WTERMSIG(status);
|
|
+ exit_code = EXIT_SIGNAL_OFFSET + signal_nr;
|
|
+ ERROR("Container \"%s\" init exited with signal %d", name, signal_nr);
|
|
+ } else if (WIFEXITED(status)) {
|
|
+ exit_code = WEXITSTATUS(status);
|
|
+ ERROR("Container \"%s\" init exited with status %d", name, exit_code);
|
|
+ } else {
|
|
+ exit_code = -1;
|
|
+ ERROR("Container \"%s\" init exited with unknown status", name);
|
|
+ }
|
|
+#else
|
|
if (WIFSIGNALED(status)) {
|
|
int signal_nr = WTERMSIG(status);
|
|
switch(signal_nr) {
|
|
@@ -2148,16 +2768,25 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops,
|
|
break;
|
|
}
|
|
}
|
|
+#endif
|
|
|
|
ret = lxc_restore_phys_nics_to_netns(handler);
|
|
if (ret < 0)
|
|
ERROR("Failed to move physical network devices back to parent network namespace");
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ lxc_monitor_send_exit_code(name, exit_code, handler->lxcpath);
|
|
+#else
|
|
lxc_monitor_send_exit_code(name, status, handler->lxcpath);
|
|
+#endif
|
|
lxc_error_set_and_log(handler->pid, status);
|
|
if (error_num)
|
|
*error_num = handler->exit_status;
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ handler->exit_code = exit_code; /* record exit code */
|
|
+#endif
|
|
+
|
|
lxc_delete_network(handler);
|
|
detach_block_device(handler->conf);
|
|
lxc_end(handler);
|
|
@@ -2187,7 +2816,11 @@ struct start_args {
|
|
char *const *argv;
|
|
};
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+static int start(struct lxc_handler *handler, void* data, int fd)
|
|
+#else
|
|
static int start(struct lxc_handler *handler, void* data)
|
|
+#endif
|
|
{
|
|
struct start_args *arg = data;
|
|
|
|
@@ -2195,6 +2828,9 @@ static int start(struct lxc_handler *handler, void* data)
|
|
|
|
execvp(arg->argv[0], arg->argv);
|
|
SYSERROR("Failed to exec \"%s\"", arg->argv[0]);
|
|
+#ifdef HAVE_ISULAD
|
|
+ lxc_write_error_message(fd, "exec: \"%s\": %s.", arg->argv[0], strerror(errno));
|
|
+#endif
|
|
return 0;
|
|
}
|
|
|
|
@@ -2212,14 +2848,22 @@ static struct lxc_operations start_ops = {
|
|
};
|
|
|
|
int lxc_start(char *const argv[], struct lxc_handler *handler,
|
|
+#ifdef HAVE_ISULAD
|
|
+ const char *lxcpath, bool daemonize, int *error_num, unsigned int start_timeout)
|
|
+#else
|
|
const char *lxcpath, bool daemonize, int *error_num)
|
|
+#endif
|
|
{
|
|
struct start_args start_arg = {
|
|
.argv = argv,
|
|
};
|
|
|
|
TRACE("Doing lxc_start");
|
|
+#ifdef HAVE_ISULAD
|
|
+ return __lxc_start(handler, &start_ops, &start_arg, lxcpath, daemonize, error_num, start_timeout);
|
|
+#else
|
|
return __lxc_start(handler, &start_ops, &start_arg, lxcpath, daemonize, error_num);
|
|
+#endif
|
|
}
|
|
|
|
static void lxc_destroy_container_on_signal(struct lxc_handler *handler,
|
|
@@ -2291,3 +2935,261 @@ 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->pidfd = -EBADF;
|
|
+ handler->init_died = false;
|
|
+ handler->monitor_status_fd = -EBADF;
|
|
+ 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_put_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;
|
|
+ handler->monitor_status_fd = -EBADF;
|
|
+ handler->pidfd = -EBADF;
|
|
+ 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_put_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_put_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_put_handler(handler);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/src/lxc/start.h b/src/lxc/start.h
|
|
index bbd1a83..d03e5d5 100644
|
|
--- a/src/lxc/start.h
|
|
+++ b/src/lxc/start.h
|
|
@@ -153,7 +153,11 @@ struct execute_args {
|
|
};
|
|
|
|
struct lxc_operations {
|
|
+#ifdef HAVE_ISULAD
|
|
+ int (*start)(struct lxc_handler *, void *, int);
|
|
+#else
|
|
int (*start)(struct lxc_handler *, void *);
|
|
+#endif
|
|
int (*post_start)(struct lxc_handler *, void *);
|
|
};
|
|
|
|
@@ -184,12 +188,26 @@ static inline int inherit_fds(struct lxc_handler *handler, bool closeall)
|
|
ARRAY_SIZE(handler->keep_fds));
|
|
}
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+__hidden extern int __lxc_start(struct lxc_handler *handler,
|
|
+ struct lxc_operations* ops, void *data, const char *lxcpath,
|
|
+ bool daemonize, int *error_num, unsigned int start_timeout);
|
|
+#else
|
|
__hidden extern int __lxc_start(struct lxc_handler *, struct lxc_operations *, void *, const char *,
|
|
bool, int *);
|
|
+#endif
|
|
|
|
__hidden extern int resolve_clone_flags(struct lxc_handler *handler);
|
|
__hidden extern void lxc_expose_namespace_environment(const 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
|
|
+
|
|
static inline bool container_uses_namespace(const struct lxc_handler *handler,
|
|
unsigned int ns_flag)
|
|
{
|
|
--
|
|
2.25.1
|
|
|