This patch is the important one, switching from an I/O controller which is simply fork'd off libvirtd, to a properly execable libvirt_lxc binary. The libvirtd LXC driver writes the config it wants to launch with to /var/run/libvirt/lxc/NAME.log and invokves libvirt_lxc --name NAME This then loads the config and spawns the container. It also expects a '--console FD' arg to provide a file descriptor for the master PTY to use for the container's stdin/out/err. Currently this is compulsory but we can make it optional in future and have the container stdin/out/err plumbe straight to the libvirt_lxc process' existing stdin/out/err. This would allow launching containers standalone. If networking is configured, then we also pass '--veth NAME' for each configured interface specifying the name of the veth that will be moved into the container's namespace. The libvirt_lxc process writes a PID file to /var/run/libvirt/lxc/NAME.pid and opens a UNIX socket in the same dir - this is how libvirtd discovers when the container dies. a/src/lxc_controller.h | 41 ------ src/Makefile.am | 26 +++ src/domain_conf.c | 6 src/lxc_conf.c | 8 - src/lxc_conf.h | 4 src/lxc_controller.c | 320 +++++++++++++++++++++++++++++++------------------ src/lxc_driver.c | 191 +++++++++++++++++++---------- 7 files changed, 366 insertions(+), 230 deletions(-) Daniel diff -r 1cf789924625 src/Makefile.am --- a/src/Makefile.am Tue Aug 12 22:21:48 2008 +0100 +++ b/src/Makefile.am Tue Aug 12 22:22:37 2008 +0100 @@ -88,8 +88,13 @@ LXC_DRIVER_SOURCES = \ lxc_conf.c lxc_conf.h \ lxc_container.c lxc_container.h \ - lxc_controller.c lxc_controller.h \ lxc_driver.c lxc_driver.h \ + veth.c veth.h + +LXC_CONTROLLER_SOURCES = \ + lxc_conf.c lxc_conf.h \ + lxc_container.c lxc_container.h \ + lxc_controller.c \ veth.c veth.h OPENVZ_DRIVER_SOURCES = \ @@ -272,9 +277,11 @@ rm -f $@ mv $@-tmp $@ +libexec_PROGRAMS = + if WITH_STORAGE_DISK if WITH_LIBVIRTD -libexec_PROGRAMS = libvirt_parthelper +libexec_PROGRAMS += libvirt_parthelper libvirt_parthelper_SOURCES = $(STORAGE_HELPER_DISK_SOURCES) libvirt_parthelper_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS) @@ -284,6 +291,21 @@ endif EXTRA_DIST += $(STORAGE_HELPER_DISK_SOURCES) + +if WITH_LXC +if WITH_LIBVIRTD +libexec_PROGRAMS += libvirt_lxc + +libvirt_lxc_SOURCES = \ + $(LXC_CONTROLLER_SOURCES) \ + $(GENERIC_LIB_SOURCES) \ + $(DOMAIN_CONF_SOURCES) +libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS) +libvirt_lxc_LDADD = $(LIBXML_LIBS) ../gnulib/lib/libgnu.la +libvirt_lxc_CFLAGS = $(LIBPARTED_CFLAGS) +endif +endif +EXTRA_DIST += $(LXC_CONTROLLER_SOURCES) # Create the /var/cache/libvirt directory when installing. install-exec-local: diff -r 1cf789924625 src/domain_conf.c --- a/src/domain_conf.c Tue Aug 12 22:21:48 2008 +0100 +++ b/src/domain_conf.c Tue Aug 12 22:22:37 2008 +0100 @@ -1109,13 +1109,11 @@ break; case VIR_DOMAIN_CHR_TYPE_PTY: - /* @path attribute is an output only property - pty is auto-allocted */ - break; - case VIR_DOMAIN_CHR_TYPE_DEV: case VIR_DOMAIN_CHR_TYPE_FILE: case VIR_DOMAIN_CHR_TYPE_PIPE: - if (path == NULL) { + if (path == NULL && + def->type != VIR_DOMAIN_CHR_TYPE_PTY) { virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("Missing source path attribute for char device")); goto error; diff -r 1cf789924625 src/lxc_conf.c --- a/src/lxc_conf.c Tue Aug 12 22:21:48 2008 +0100 +++ b/src/lxc_conf.c Tue Aug 12 22:22:37 2008 +0100 @@ -71,7 +71,7 @@ "exe", utsname.machine, sizeof(int) == 4 ? 32 : 8, - NULL, + BINDIR "/libvirt_lxc", NULL, 0, NULL)) == NULL) @@ -94,11 +94,11 @@ int lxcLoadDriverConfig(lxc_driver_t *driver) { /* Set the container configuration directory */ - if ((driver->configDir = strdup(SYSCONF_DIR "/libvirt/lxc")) == NULL) + if ((driver->configDir = strdup(LXC_CONFIG_DIR)) == NULL) goto no_memory; - if ((driver->stateDir = strdup(LOCAL_STATE_DIR "/run/libvirt/lxc")) == NULL) + if ((driver->stateDir = strdup(LXC_STATE_DIR)) == NULL) goto no_memory; - if ((driver->logDir = strdup(LOCAL_STATE_DIR "/log/libvirt/lxc")) == NULL) + if ((driver->logDir = strdup(LXC_LOG_DIR)) == NULL) goto no_memory; return 0; diff -r 1cf789924625 src/lxc_conf.h --- a/src/lxc_conf.h Tue Aug 12 22:21:48 2008 +0100 +++ b/src/lxc_conf.h Tue Aug 12 22:22:37 2008 +0100 @@ -30,6 +30,10 @@ #include "domain_conf.h" #include "capabilities.h" +#define LXC_CONFIG_DIR SYSCONF_DIR "/libvirt/lxc" +#define LXC_STATE_DIR LOCAL_STATE_DIR "/run/libvirt/lxc" +#define LXC_LOG_DIR LOCAL_STATE_DIR "/log/libvirt/lxc" + typedef struct __lxc_driver lxc_driver_t; struct __lxc_driver { virCapsPtr caps; diff -r 1cf789924625 src/lxc_controller.c --- a/src/lxc_controller.c Tue Aug 12 22:21:48 2008 +0100 +++ b/src/lxc_controller.c Tue Aug 12 22:22:37 2008 +0100 @@ -23,22 +23,22 @@ #include <config.h> -#ifdef WITH_LXC - #include <sys/epoll.h> #include <sys/wait.h> #include <sys/socket.h> +#include <sys/types.h> +#include <sys/un.h> #include <unistd.h> #include <paths.h> #include <fcntl.h> #include <signal.h> +#include <getopt.h> #include "internal.h" #include "util.h" #include "lxc_conf.h" #include "lxc_container.h" -#include "lxc_controller.h" #include "veth.h" #include "memory.h" #include "util.h" @@ -47,6 +47,56 @@ #define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__) #define DEBUG0(msg) VIR_DEBUG(__FILE__, "%s", msg) +int debugFlag = 0; + +static char*lxcMonitorPath(virDomainDefPtr def) +{ + char *sockpath; + if (asprintf(&sockpath, "%s/%s.sock", + LXC_STATE_DIR, def->name) < 0) { + lxcError(NULL, NULL, VIR_ERR_NO_MEMORY, NULL); + return NULL; + } + return sockpath; +} + +static int lxcMonitorServer(const char *sockpath) +{ + int fd; + struct sockaddr_un addr; + + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to create server socket %s: %s"), + sockpath, strerror(errno)); + goto error; + } + + unlink(sockpath); + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, sockpath, sizeof(addr.sun_path)); + + if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to bind server socket %s: %s"), + sockpath, strerror(errno)); + goto error; + } + if (listen(fd, 30 /* backlog */ ) < 0) { + lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("failed to listen server socket %s: %s"), + sockpath, strerror(errno)); + goto error; + } + + return fd; + +error: + if (fd != -1) + close(fd); + return -1; +} /** * lxcFdForward: @@ -305,8 +355,7 @@ static int -lxcControllerRun(const char *stateDir, - virDomainDefPtr def, +lxcControllerRun(virDomainDefPtr def, unsigned int nveths, char **veths, int monitor, @@ -359,148 +408,187 @@ if (containerPty != -1) close(containerPty); - kill(container, SIGTERM); - waitpid(container, NULL, 0); - lxcControllerCleanupInterfaces(nveths, veths); - virFileDeletePid(stateDir, def->name); + if (container > 1) { + kill(container, SIGTERM); + waitpid(container, NULL, 0); + } return rc; } -int lxcControllerStart(const char *stateDir, - virDomainDefPtr def, - unsigned int nveths, - char **veths, - int monitor, - int appPty, - int logfd) +int main(int argc, char *argv[]) { pid_t pid; - int rc; - int status, null; - int open_max, i; + int rc = 1; int client; - struct sigaction sig_action; + char *name = NULL; + int nveths = 0; + char **veths = NULL; + int monitor = -1; + int appPty = -1; + int bg = 0; + virCapsPtr caps = NULL; + virDomainDefPtr def = NULL; + int nnets = 0; + virDomainNetDefPtr nets = NULL; + char *configFile = NULL; + char *sockpath = NULL; + const struct option const options[] = { + { "background", 0, NULL, 'b' }, + { "name", 1, NULL, 'n' }, + { "veth", 1, NULL, 'v' }, + { "console", 1, NULL, 'c' }, + { "help", 0, NULL, 'h' }, + { 0, 0, 0, 0 }, + }; - if ((pid = fork()) < 0) - return -1; + while (1) { + int c; - if (pid > 0) { - /* Original caller waits for first child to exit */ - while (1) { - rc = waitpid(pid, &status, 0); - if (rc < 0) { - if (errno == EINTR) - continue; - return -1; + c = getopt_long(argc, argv, "dn:v:m:c:h", + options, NULL); + + if (c == -1) + break; + + switch (c) { + case 'b': + bg = 1; + break; + + case 'n': + if ((name = strdup(optarg)) == NULL) { + fprintf(stderr, "%s", strerror(errno)); + goto cleanup; } - if (rc != pid) { - fprintf(stderr, - _("Unexpected pid %d != %d from waitpid\n"), - rc, pid); - return -1; + break; + + case 'v': + if (VIR_REALLOC_N(veths, nveths+1) < 0) { + fprintf(stderr, "cannot allocate veths %s", strerror(errno)); + goto cleanup; } - if (WIFEXITED(status) && - WEXITSTATUS(status) == 0) - return 0; - else { - fprintf(stderr, - _("Unexpected status %d from pid %d\n"), - status, pid); - return -1; + if ((veths[nveths++] = strdup(optarg)) == NULL) { + fprintf(stderr, "cannot allocate veth name %s", strerror(errno)); + goto cleanup; } + break; + + case 'c': + if (virStrToLong_i(optarg, NULL, 10, &appPty) < 0) { + fprintf(stderr, "malformed --console argument '%s'", optarg); + goto cleanup; + } + break; + + case 'h': + case '?': + fprintf(stderr, "\n"); + fprintf(stderr, "syntax: %s [OPTIONS]\n", argv[0]); + fprintf(stderr, "\n"); + fprintf(stderr, "Options\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " -b, --background\n"); + fprintf(stderr, " -n NAME, --name NAME\n"); + fprintf(stderr, " -c FD, --console FD\n"); + fprintf(stderr, " -v VETH, --veth VETH\n"); + fprintf(stderr, " -h, --help\n"); + fprintf(stderr, "\n"); + goto cleanup; } } - /* First child is running here */ - /* Clobber all libvirtd's signal handlers so they - * don't affect us - */ - sig_action.sa_handler = SIG_DFL; - sig_action.sa_flags = 0; - sigemptyset(&sig_action.sa_mask); - - sigaction(SIGHUP, &sig_action, NULL); - sigaction(SIGINT, &sig_action, NULL); - sigaction(SIGQUIT, &sig_action, NULL); - sigaction(SIGTERM, &sig_action, NULL); - sigaction(SIGCHLD, &sig_action, NULL); - - sig_action.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &sig_action, NULL); - - - /* Don't hold onto any cwd we inherit from libvirtd either */ - if (chdir("/") < 0) { - fprintf(stderr, _("Unable to change to root dir: %s\n"), - strerror(errno)); - _exit(-1); + if (name == NULL) { + fprintf(stderr, "%s: missing --name argument for configuration\n", argv[0]); + goto cleanup; } - if (setsid() < 0) { - fprintf(stderr, _("Unable to become session leader: %s\n"), - strerror(errno)); - _exit(-1); + if (appPty < 0) { + fprintf(stderr, "%s: missing --console argument for container PTY\n", argv[0]); + goto cleanup; } - if ((null = open(_PATH_DEVNULL, O_RDONLY)) < 0) { - fprintf(stderr, _("Unable to open %s: %s\n"), - _PATH_DEVNULL, strerror(errno)); - _exit(-1); + if (getuid() && 0) { + fprintf(stderr, "%s: must be run as the 'root' user\n", argv[0]); + goto cleanup; } - open_max = sysconf (_SC_OPEN_MAX); - for (i = 0; i < open_max; i++) - if (i != appPty && - i != monitor && - i != logfd && - i != null) - close(i); + if ((caps = lxcCapsInit()) == NULL) + goto cleanup; - if (dup2(null, STDIN_FILENO) < 0 || - dup2(logfd, STDOUT_FILENO) < 0 || - dup2(logfd, STDERR_FILENO) < 0) { - fprintf(stderr, _("Unable to redirect stdio: %s\n"), - strerror(errno)); - _exit(-1); + if ((configFile = virDomainConfigFile(NULL, + LXC_STATE_DIR, + name)) == NULL) + goto cleanup; + + if ((def = virDomainDefParseFile(NULL, caps, configFile)) == NULL) + goto cleanup; + + nets = def->nets; + while (nets) { + nnets++; + nets = nets->next; + } + if (nnets != nveths) { + fprintf(stderr, "%s: expecting %d veths, but got %d\n", + argv[0], nnets, nveths); + goto cleanup; } - close(null); - close(logfd); + if ((sockpath = lxcMonitorPath(def)) == NULL) + goto cleanup; - /* Now fork the real controller process */ - if ((pid = fork()) < 0) { - fprintf(stderr, _("Unable to fork controller: %s\n"), - strerror(errno)); - _exit(-1); + if ((monitor = lxcMonitorServer(sockpath)) < 0) + goto cleanup; + + if (bg) { + if ((pid = fork()) < 0) + goto cleanup; + + if (pid > 0) { + if ((rc = virFileWritePid(LXC_STATE_DIR, name, pid)) != 0) { + fprintf(stderr, _("Unable to write pid file: %s\n"), + strerror(rc)); + _exit(1); + } + + /* First child now exits, allowing original caller + * (ie libvirtd's LXC driver to complete their + * waitpid & continue */ + _exit(0); + } + + /* Don't hold onto any cwd we inherit from libvirtd either */ + if (chdir("/") < 0) { + fprintf(stderr, _("Unable to change to root dir: %s\n"), + strerror(errno)); + goto cleanup; + } + + if (setsid() < 0) { + fprintf(stderr, _("Unable to become session leader: %s\n"), + strerror(errno)); + goto cleanup; + } } - if (pid > 0) { - if ((rc = virFileWritePid(stateDir, def->name, pid)) != 0) { - fprintf(stderr, _("Unable to write pid file: %s\n"), - strerror(rc)); - _exit(-1); - } - /* First child now exits, allowing originall caller to - * complete their waitpid & continue */ - _exit(0); + /* Accept initial client which is the libvirtd daemon */ + if ((client = accept(monitor, NULL, 0)) < 0) { + fprintf(stderr, _("Failed connection from LXC driver: %s\n"), + strerror(errno)); + goto cleanup; } - /* This is real controller running finally... */ + rc = lxcControllerRun(def, nveths, veths, monitor, client, appPty); - /* Accept initial client which is the libvirtd daemon */ - if ((client = accept(monitor, NULL, 0))) { - fprintf(stderr, _("Failed connection from LXC driver: %s\n"), - strerror(errno)); - _exit(-1); - } - /* Controlling libvirtd LXC driver now knows - what our PID is, and is able to cleanup after - us from now on */ - _exit(lxcControllerRun(stateDir, def, nveths, veths, monitor, client, appPty)); +cleanup: + virFileDeletePid(LXC_STATE_DIR, def->name); + lxcControllerCleanupInterfaces(nveths, veths); + unlink(sockpath); + VIR_FREE(sockpath); + + return rc; } - -#endif diff -r 1cf789924625 src/lxc_controller.h --- a/src/lxc_controller.h Tue Aug 12 22:21:48 2008 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright IBM Corp. 2008 - * - * lxc_controller.h: linux container process controller - * - * Authors: - * David L. Leskovec <dlesko at linux.vnet.ibm.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef LXC_CONTROLLER_H -#define LXC_CONTROLLER_H - -#ifdef WITH_LXC - -#include "lxc_conf.h" - -int lxcControllerStart(const char *stateDir, - virDomainDefPtr def, - unsigned int nveths, - char **veths, - int monitor, - int appPty, - int logfd); - -#endif /* WITH_LXC */ - -#endif /* LXC_CONTROLLER_H */ diff -r 1cf789924625 src/lxc_driver.c --- a/src/lxc_driver.c Tue Aug 12 22:21:48 2008 +0100 +++ b/src/lxc_driver.c Tue Aug 12 22:22:37 2008 +0100 @@ -38,7 +38,6 @@ #include "lxc_conf.h" #include "lxc_container.h" #include "lxc_driver.h" -#include "lxc_controller.h" #include "memory.h" #include "util.h" #include "bridge.h" @@ -398,6 +397,7 @@ close(vm->monitor); virFileDeletePid(driver->stateDir, vm->def->name); + virDomainDeleteConfig(conn, driver->stateDir, NULL, vm); vm->state = VIR_DOMAIN_SHUTOFF; vm->pid = -1; @@ -507,55 +507,6 @@ return rc; } -static int lxcMonitorServer(virConnectPtr conn, - lxc_driver_t * driver, - virDomainObjPtr vm) -{ - char *sockpath = NULL; - int fd; - struct sockaddr_un addr; - - if (asprintf(&sockpath, "%s/%s.sock", - driver->stateDir, vm->def->name) < 0) { - lxcError(conn, NULL, VIR_ERR_NO_MEMORY, NULL); - return -1; - } - - if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to create server socket: %s"), - strerror(errno)); - goto error; - } - - unlink(sockpath); - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, sockpath, sizeof(addr.sun_path)); - - if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to bind server socket: %s"), - strerror(errno)); - goto error; - } - if (listen(fd, 30 /* backlog */ ) < 0) { - lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, - _("failed to listen server socket: %s"), - strerror(errno)); - goto error; - return (-1); - } - - VIR_FREE(sockpath); - return fd; - -error: - VIR_FREE(sockpath); - if (fd != -1) - close(fd); - return -1; -} static int lxcMonitorClient(virConnectPtr conn, lxc_driver_t * driver, @@ -608,6 +559,12 @@ if (signum == 0) signum = SIGINT; + if (vm->pid <= 0) { + lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, + _("invalid PID %d for container"), vm->pid); + return -1; + } + if (kill(vm->pid, signum) < 0) { if (errno != ESRCH) { lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, @@ -644,6 +601,102 @@ } +static int lxcControllerStart(virConnectPtr conn, + virDomainObjPtr vm, + int nveths, + char **veths, + int appPty, + int logfd) +{ + int i; + int rc; + int ret = -1; + int largc = 0, larga = 0; + const char **largv = NULL; + pid_t child; + int status; + +#define ADD_ARG_SPACE \ + do { \ + if (largc == larga) { \ + larga += 10; \ + if (VIR_REALLOC_N(largv, larga) < 0) \ + goto no_memory; \ + } \ + } while (0) + +#define ADD_ARG(thisarg) \ + do { \ + ADD_ARG_SPACE; \ + largv[largc++] = thisarg; \ + } while (0) + +#define ADD_ARG_LIT(thisarg) \ + do { \ + ADD_ARG_SPACE; \ + if ((largv[largc++] = strdup(thisarg)) == NULL) \ + goto no_memory; \ + } while (0) + + ADD_ARG_LIT(vm->def->emulator); + ADD_ARG_LIT("--name"); + ADD_ARG_LIT(vm->def->name); + ADD_ARG_LIT("--console"); + ADD_ARG_LIT("0"); /* Passing console master PTY as FD 0 */ + ADD_ARG_LIT("--background"); + + for (i = 0 ; i < nveths ; i++) { + ADD_ARG_LIT("--veth"); + ADD_ARG_LIT(veths[i]); + } + + ADD_ARG(NULL); + + vm->stdin_fd = appPty; /* Passing console master PTY as FD 0 */ + vm->stdout_fd = vm->stderr_fd = logfd; + + if (virExec(conn, largv, NULL, &child, + vm->stdin_fd, &vm->stdout_fd, &vm->stderr_fd, + VIR_EXEC_NONE) < 0) + goto cleanup; + + /* We now wait for the process to exit - the controller + * will fork() itself into the background - waiting for + * it to exit thus guarentees it has written its pidfile + */ + while ((rc = waitpid(child, &status, 0) == -1) && errno == EINTR); + if (rc == -1) { + lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot wait for '%s': %s"), + largv[0], strerror(errno)); + goto cleanup; + } + + if (!(WIFEXITED(status) && WEXITSTATUS(status) == 0)) { + lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, + _("container '%s' unexpectedly shutdown during startup"), + largv[0]); + goto cleanup; + } + +#undef ADD_ARG +#undef ADD_ARG_LIT +#undef ADD_ARG_SPACE + + ret = 0; + +cleanup: + for (i = 0 ; i < largc ; i++) + VIR_FREE(largv[i]); + + return ret; + +no_memory: + lxcError(conn, NULL, VIR_ERR_NO_MEMORY, NULL); + goto cleanup; +} + + /** * lxcVmStart: * @conn: pointer to connection @@ -660,7 +713,6 @@ { int rc = -1; unsigned int i; - int monitor; int parentTty; char *parentTtyPath = NULL; char *logfile = NULL; @@ -681,9 +733,6 @@ return -1; } - if ((monitor = lxcMonitorServer(conn, driver, vm)) < 0) - goto cleanup; - /* open parent tty */ if (virFileOpenTty(&parentTty, &parentTtyPath, 1) < 0) { lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, @@ -702,6 +751,12 @@ if (lxcSetupInterfaces(conn, vm->def, &nveths, &veths) != 0) goto cleanup; + /* Persist the live configuration now we have veth & tty info */ + if (virDomainSaveConfig(conn, driver->stateDir, vm->def) < 0) { + rc = -1; + goto cleanup; + } + if ((logfd = open(logfile, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR|S_IWUSR)) < 0) { lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR, @@ -710,14 +765,11 @@ goto cleanup; } - if (lxcControllerStart(driver->stateDir, - vm->def, nveths, veths, - monitor, parentTty, logfd) < 0) + if (lxcControllerStart(conn, + vm, + nveths, veths, + parentTty, logfd) < 0) goto cleanup; - /* Close the server side of the monitor, now owned - * by the controller process */ - close(monitor); - monitor = -1; /* Connect to the controller as a client *first* because * this will block until the child has written their @@ -753,8 +805,6 @@ vethDelete(veths[i]); VIR_FREE(veths[i]); } - if (monitor != -1) - close(monitor); if (rc != 0 && vm->monitor != -1) { close(vm->monitor); vm->monitor = -1; @@ -951,6 +1001,8 @@ vm = lxc_driver->domains; while (vm) { + char *config = NULL; + virDomainDefPtr tmp; int rc; if ((vm->monitor = lxcMonitorClient(NULL, lxc_driver, vm)) < 0) { vm = vm->next; @@ -963,6 +1015,19 @@ vm->monitor = -1; vm = vm->next; continue; + } + + if ((config = virDomainConfigFile(NULL, + lxc_driver->stateDir, + vm->def->name)) == NULL) + continue; + + /* Try and load the live config */ + tmp = virDomainDefParseFile(NULL, lxc_driver->caps, config); + VIR_FREE(config); + if (tmp) { + vm->newDef = vm->def; + vm->def = tmp; } if (vm->pid != 0) { -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list