[lxc-devel] [lxc/master] execute: add a way to wait in lxc-init before spawning

tych0 on Github lxc-bot at linuxcontainers.org
Mon Apr 15 18:37:55 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 1584 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190415/888681c0/attachment.bin>
-------------- next part --------------
From 14cbaf5d08e1ff0d349a9be27a803b04e52d2479 Mon Sep 17 00:00:00 2001
From: Michael McCracken <mikmccra at cisco.com>
Date: Mon, 15 Apr 2019 10:05:15 -0600
Subject: [PATCH] execute: add a way to wait in lxc-init before spawning

We're working on an implementation of crio-lxc. The crio spec thinks about
create and start slightly differently than liblxc does: create actually
creates the namespaces that the container will finally be run in to allow
them to be manipulated. It also allows passing the fds that the container
will use as stdin/stdout, etc. Alternatively, create() in lxc parlance is
just an on-disk operation, where start() creates the namespaces and spawns
the "real" init.

To support the crio semantics in liblxc, we introduce an option to have
lxc-init (blocking) write to a fifo, so that the crio implementation can
wait to read from the fifo until crio's start method is called. This means
that all the namespaces are around and can be manipulated, and the fds
passed at create() time are kept around and correct.

This abstraction is slightly leaky, since it requires the user to both set
up the fifo (e.g. bind mount it in, by setting a mount on liblxc) and then
say again where it is. A less leaky approach might be to just handle the
fifo setup inside liblxc entirely, but then we'd need a new
->execute_really_start() api call instead of just a new config option.

Signed-off-by: Michael McCracken <mikmccra at cisco.com>
Signed-off-by: Tycho Andersen <tycho at tycho.ws>
---
 src/lxc/cmd/lxc_init.c | 38 ++++++++++++++++++++++++++++++++++++--
 src/lxc/conf.h         |  3 +++
 src/lxc/confile.c      | 26 ++++++++++++++++++++++++++
 src/lxc/execute.c      |  8 ++++++++
 4 files changed, 73 insertions(+), 2 deletions(-)

diff --git a/src/lxc/cmd/lxc_init.c b/src/lxc/cmd/lxc_init.c
index aca14d64b8..0ef5cd4ba8 100644
--- a/src/lxc/cmd/lxc_init.c
+++ b/src/lxc/cmd/lxc_init.c
@@ -74,9 +74,10 @@ static struct option long_options[] = {
 	    { "version",     no_argument,       0, OPT_VERSION },
 	    { "quiet",       no_argument,       0, 'q'         },
 	    { "lxcpath",     required_argument, 0, 'P'         },
+	    { "exec-wait",   no_argument,       0, 'w'         },
 	    { 0,             0,                 0, 0           }
 	};
-static const char short_options[] = "n:hqo:l:P:";
+static const char short_options[] = "n:hqo:l:P:wk";
 
 struct arguments {
 	const struct option *options;
@@ -86,6 +87,8 @@ struct arguments {
 	bool quiet;
 	const char *lxcpath;
 
+	bool exec_wait;
+
 	/* remaining arguments */
 	char *const *argv;
 	int argc;
@@ -331,6 +334,33 @@ int main(int argc, char *argv[])
 
 		(void)ioctl(STDIN_FILENO, TIOCSCTTY, 0);
 
+		if (my_args.exec_wait) {
+			// wait by doing a blocking write to /syncfifo
+			struct stat fifo_stat;
+			if (stat("/syncfifo", &fifo_stat) == -1){
+				perror("stat");
+				exit(EXIT_FAILURE);
+			}
+			if (!S_ISFIFO(fifo_stat.st_mode)){
+				if (!my_args.quiet) fprintf(stderr, "/syncfifo exists but is not a fifo");
+				exit(EXIT_FAILURE);
+
+			}
+
+			int syncfifo_fd = open("/syncfifo", O_WRONLY | O_NOFOLLOW);
+			if (syncfifo_fd == -1){
+				exit(EXIT_FAILURE);
+			}
+			char ready[6] = "Ready\n";
+			ssize_t wrote = write(syncfifo_fd, ready, strlen(ready));
+			if (wrote == -1){
+				perror("write");
+				close(syncfifo_fd);
+				exit(EXIT_FAILURE);
+			}
+			close(syncfifo_fd);
+		}
+
 		ret = execvp(my_args.argv[0], my_args.argv);
 		if (my_args.quiet)
 			fprintf(stderr, "Failed to exec \"%s\"\n", my_args.argv[0]);
@@ -452,7 +482,7 @@ __noreturn static void print_usage_exit(const struct option longopts[])
 
 {
 	fprintf(stderr, "Usage: lxc-init [-n|--name=NAME] [-h|--help] [--usage] [--version]\n\
-		[-q|--quiet] [-P|--lxcpath=LXCPATH]\n");
+		[-q|--quiet] [-P|--lxcpath=LXCPATH] [-w|--exec-wait]\n");
 	exit(EXIT_SUCCESS);
 }
 
@@ -473,6 +503,7 @@ Options :\n\
   -n, --name=NAME                  NAME of the container\n\
   -q, --quiet                      Don't produce any output\n\
   -P, --lxcpath=PATH               Use specified container path\n\
+  -w, --exec-wait                  Wait for external signal to run COMMAND\n\
   -?, --help                       Give this help list\n\
       --usage                      Give a short usage message\n\
       --version                    Print the version number\n\
@@ -508,6 +539,9 @@ static int arguments_parse(struct arguments *args, int argc,
 			remove_trailing_slashes(optarg);
 			args->lxcpath = optarg;
 			break;
+		case 'w':
+			args->exec_wait = true;
+			break;
 		case OPT_USAGE:
 			print_usage_exit(args->options);
 		case OPT_VERSION:
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index 85daf1b6a5..ae7c7d0bf6 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -343,6 +343,9 @@ struct lxc_conf {
 	/* default command for lxc-execute */
 	char *execute_cmd;
 
+	/* the path to a fifo to do wait on during execute */
+	char *execute_wait_fifo_path;
+
 	/* init command */
 	char *init_cmd;
 
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 8f94635d1b..45f979c90b 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -157,6 +157,7 @@ lxc_config_define(tty_dir);
 lxc_config_define(uts_name);
 lxc_config_define(sysctl);
 lxc_config_define(proc);
+lxc_config_define(execute_wait_fifo_path);
 
 static struct lxc_config_t config_jump_table[] = {
 	{ "lxc.arch",                      set_config_personality,                 get_config_personality,                 clr_config_personality,               },
@@ -179,6 +180,7 @@ static struct lxc_config_t config_jump_table[] = {
 	{ "lxc.environment",               set_config_environment,                 get_config_environment,                 clr_config_environment,               },
 	{ "lxc.ephemeral",                 set_config_ephemeral,                   get_config_ephemeral,                   clr_config_ephemeral,                 },
 	{ "lxc.execute.cmd",               set_config_execute_cmd,                 get_config_execute_cmd,                 clr_config_execute_cmd,               },
+	{ "lxc.execute.wait_fifo_path",    set_config_execute_wait_fifo_path,      get_config_execute_wait_fifo_path,      clr_config_execute_wait_fifo_path,    },
 	{ "lxc.group",                     set_config_group,                       get_config_group,                       clr_config_group,                     },
 	{ "lxc.hook.autodev",              set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
 	{ "lxc.hook.clone",                set_config_hooks,                       get_config_hooks,                       clr_config_hooks,                     },
@@ -801,6 +803,14 @@ static int set_config_execute_cmd(const char *key, const char *value,
 	return set_config_path_item(&lxc_conf->execute_cmd, value);
 }
 
+static int set_config_execute_wait_fifo_path(const char *key,
+					     const char *value,
+					     struct lxc_conf *lxc_conf,
+					     void *data)
+{
+	return set_config_path_item(&lxc_conf->execute_wait_fifo_path, value);
+}
+
 static int set_config_init_cmd(const char *key, const char *value,
 			       struct lxc_conf *lxc_conf, void *data)
 {
@@ -3808,6 +3818,13 @@ static int get_config_execute_cmd(const char *key, char *retv, int inlen,
 	return lxc_get_conf_str(retv, inlen, c->execute_cmd);
 }
 
+static int get_config_execute_wait_fifo_path(const char *key, char *retv,
+					     int inlen, struct lxc_conf *c,
+					     void *data)
+{
+	return lxc_get_conf_str(retv, inlen, c->execute_wait_fifo_path);
+}
+
 static int get_config_init_cmd(const char *key, char *retv, int inlen,
 			       struct lxc_conf *c, void *data)
 {
@@ -4385,6 +4402,15 @@ static inline int clr_config_execute_cmd(const char *key, struct lxc_conf *c,
 	return 0;
 }
 
+static inline int clr_config_execute_wait_fifo_path(const char *key,
+						    struct lxc_conf *c,
+						    void *data)
+{
+	free(c->execute_wait_fifo_path);
+	c->execute_wait_fifo_path = NULL;
+	return 0;
+}
+
 static inline int clr_config_init_cmd(const char *key, struct lxc_conf *c,
 				      void *data)
 {
diff --git a/src/lxc/execute.c b/src/lxc/execute.c
index 45ca67e3a8..85bdce7bda 100644
--- a/src/lxc/execute.c
+++ b/src/lxc/execute.c
@@ -57,6 +57,9 @@ static int execute_start(struct lxc_handler *handler, void* data)
 	if (!handler->conf->rootfs.path)
 		argc_add += 2;
 
+	if (handler->conf->execute_wait_fifo_path)
+		argc_add += 2;
+
 	argv = malloc((argc + argc_add) * sizeof(*argv));
 	if (!argv) {
 		SYSERROR("Allocating init args failed");
@@ -79,6 +82,11 @@ static int execute_start(struct lxc_handler *handler, void* data)
 		argv[i++] = (char *)handler->lxcpath;
 	}
 
+	if (handler->conf->execute_wait_fifo_path) {
+		argv[i++] = "--exec-wait";
+		argv[i++] = handler->conf->execute_wait_fifo_path;
+	}
+
 	argv[i++] = "--";
 	for (j = 0; j < argc; j++)
 		argv[i++] = my_args->argv[j];


More information about the lxc-devel mailing list