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 :|