mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
Create lxc_controller standalone binary
This commit is contained in:
parent
bb16f4a25d
commit
177c74b1fa
@ -1,3 +1,12 @@
|
|||||||
|
Wed Aug 20 21:50:09 BST 2008 Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
|
||||||
|
* src/domain_conf.c: Include PTY name if available
|
||||||
|
* src/Makefile.am: Add lxc_controller binary
|
||||||
|
* src/lxc_conf.c, src/lxc_conf.h, src/lxc_controller.c,
|
||||||
|
src/lxc_controller.h, src/lxc_driver.c: Move LXC controller
|
||||||
|
into a properly exec'd binary, instead of fork'd child of
|
||||||
|
libvirtd daemon
|
||||||
|
|
||||||
Wed Aug 20 21:05:09 BST 2008 Daniel P. Berrange <berrange@redhat.com>
|
Wed Aug 20 21:05:09 BST 2008 Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
|
||||||
* configure.in, qemud/Makefile.am, src/Makefile.am: Use automake
|
* configure.in, qemud/Makefile.am, src/Makefile.am: Use automake
|
||||||
|
@ -88,10 +88,15 @@ XEN_DRIVER_SOURCES = \
|
|||||||
LXC_DRIVER_SOURCES = \
|
LXC_DRIVER_SOURCES = \
|
||||||
lxc_conf.c lxc_conf.h \
|
lxc_conf.c lxc_conf.h \
|
||||||
lxc_container.c lxc_container.h \
|
lxc_container.c lxc_container.h \
|
||||||
lxc_controller.c lxc_controller.h \
|
|
||||||
lxc_driver.c lxc_driver.h \
|
lxc_driver.c lxc_driver.h \
|
||||||
veth.c veth.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 = \
|
OPENVZ_DRIVER_SOURCES = \
|
||||||
openvz_conf.c openvz_conf.h \
|
openvz_conf.c openvz_conf.h \
|
||||||
openvz_driver.c openvz_driver.h
|
openvz_driver.c openvz_driver.h
|
||||||
@ -272,9 +277,11 @@ virsh-pool-edit.c: virsh.c Makefile.am
|
|||||||
rm -f $@
|
rm -f $@
|
||||||
mv $@-tmp $@
|
mv $@-tmp $@
|
||||||
|
|
||||||
|
libexec_PROGRAMS =
|
||||||
|
|
||||||
if WITH_STORAGE_DISK
|
if WITH_STORAGE_DISK
|
||||||
if WITH_LIBVIRTD
|
if WITH_LIBVIRTD
|
||||||
libexec_PROGRAMS = libvirt_parthelper
|
libexec_PROGRAMS += libvirt_parthelper
|
||||||
|
|
||||||
libvirt_parthelper_SOURCES = $(STORAGE_HELPER_DISK_SOURCES)
|
libvirt_parthelper_SOURCES = $(STORAGE_HELPER_DISK_SOURCES)
|
||||||
libvirt_parthelper_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS)
|
libvirt_parthelper_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS)
|
||||||
@ -285,6 +292,21 @@ endif
|
|||||||
EXTRA_DIST += $(STORAGE_HELPER_DISK_SOURCES)
|
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.
|
# Create the /var/cache/libvirt directory when installing.
|
||||||
install-exec-local:
|
install-exec-local:
|
||||||
$(MKDIR_P) $(DESTDIR)$(localstatedir)/cache/libvirt
|
$(MKDIR_P) $(DESTDIR)$(localstatedir)/cache/libvirt
|
||||||
|
@ -1109,13 +1109,11 @@ virDomainChrDefParseXML(virConnectPtr conn,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case VIR_DOMAIN_CHR_TYPE_PTY:
|
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_DEV:
|
||||||
case VIR_DOMAIN_CHR_TYPE_FILE:
|
case VIR_DOMAIN_CHR_TYPE_FILE:
|
||||||
case VIR_DOMAIN_CHR_TYPE_PIPE:
|
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,
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
"%s", _("Missing source path attribute for char device"));
|
"%s", _("Missing source path attribute for char device"));
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -71,7 +71,7 @@ virCapsPtr lxcCapsInit(void)
|
|||||||
"exe",
|
"exe",
|
||||||
utsname.machine,
|
utsname.machine,
|
||||||
sizeof(int) == 4 ? 32 : 8,
|
sizeof(int) == 4 ? 32 : 8,
|
||||||
NULL,
|
BINDIR "/libvirt_lxc",
|
||||||
NULL,
|
NULL,
|
||||||
0,
|
0,
|
||||||
NULL)) == NULL)
|
NULL)) == NULL)
|
||||||
@ -94,11 +94,11 @@ no_memory:
|
|||||||
int lxcLoadDriverConfig(lxc_driver_t *driver)
|
int lxcLoadDriverConfig(lxc_driver_t *driver)
|
||||||
{
|
{
|
||||||
/* Set the container configuration directory */
|
/* 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;
|
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;
|
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;
|
goto no_memory;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -30,6 +30,10 @@
|
|||||||
#include "domain_conf.h"
|
#include "domain_conf.h"
|
||||||
#include "capabilities.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;
|
typedef struct __lxc_driver lxc_driver_t;
|
||||||
struct __lxc_driver {
|
struct __lxc_driver {
|
||||||
virCapsPtr caps;
|
virCapsPtr caps;
|
||||||
|
@ -23,22 +23,22 @@
|
|||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#ifdef WITH_LXC
|
|
||||||
|
|
||||||
#include <sys/epoll.h>
|
#include <sys/epoll.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/un.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#include "lxc_conf.h"
|
#include "lxc_conf.h"
|
||||||
#include "lxc_container.h"
|
#include "lxc_container.h"
|
||||||
#include "lxc_controller.h"
|
|
||||||
#include "veth.h"
|
#include "veth.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -47,6 +47,56 @@
|
|||||||
#define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__)
|
#define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__)
|
||||||
#define DEBUG0(msg) VIR_DEBUG(__FILE__, "%s", msg)
|
#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:
|
* lxcFdForward:
|
||||||
@ -305,8 +355,7 @@ static int lxcControllerCleanupInterfaces(unsigned int nveths,
|
|||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lxcControllerRun(const char *stateDir,
|
lxcControllerRun(virDomainDefPtr def,
|
||||||
virDomainDefPtr def,
|
|
||||||
unsigned int nveths,
|
unsigned int nveths,
|
||||||
char **veths,
|
char **veths,
|
||||||
int monitor,
|
int monitor,
|
||||||
@ -359,148 +408,187 @@ cleanup:
|
|||||||
if (containerPty != -1)
|
if (containerPty != -1)
|
||||||
close(containerPty);
|
close(containerPty);
|
||||||
|
|
||||||
kill(container, SIGTERM);
|
if (container > 1) {
|
||||||
waitpid(container, NULL, 0);
|
kill(container, SIGTERM);
|
||||||
lxcControllerCleanupInterfaces(nveths, veths);
|
waitpid(container, NULL, 0);
|
||||||
virFileDeletePid(stateDir, def->name);
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int lxcControllerStart(const char *stateDir,
|
int main(int argc, char *argv[])
|
||||||
virDomainDefPtr def,
|
|
||||||
unsigned int nveths,
|
|
||||||
char **veths,
|
|
||||||
int monitor,
|
|
||||||
int appPty,
|
|
||||||
int logfd)
|
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int rc;
|
int rc = 1;
|
||||||
int status, null;
|
|
||||||
int open_max, i;
|
|
||||||
int client;
|
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)
|
while (1) {
|
||||||
return -1;
|
int c;
|
||||||
|
|
||||||
if (pid > 0) {
|
c = getopt_long(argc, argv, "dn:v:m:c:h",
|
||||||
/* Original caller waits for first child to exit */
|
options, NULL);
|
||||||
while (1) {
|
|
||||||
rc = waitpid(pid, &status, 0);
|
if (c == -1)
|
||||||
if (rc < 0) {
|
break;
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
switch (c) {
|
||||||
return -1;
|
case 'b':
|
||||||
|
bg = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
if ((name = strdup(optarg)) == NULL) {
|
||||||
|
fprintf(stderr, "%s", strerror(errno));
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (rc != pid) {
|
break;
|
||||||
fprintf(stderr,
|
|
||||||
_("Unexpected pid %d != %d from waitpid\n"),
|
case 'v':
|
||||||
rc, pid);
|
if (VIR_REALLOC_N(veths, nveths+1) < 0) {
|
||||||
return -1;
|
fprintf(stderr, "cannot allocate veths %s", strerror(errno));
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (WIFEXITED(status) &&
|
if ((veths[nveths++] = strdup(optarg)) == NULL) {
|
||||||
WEXITSTATUS(status) == 0)
|
fprintf(stderr, "cannot allocate veth name %s", strerror(errno));
|
||||||
return 0;
|
goto cleanup;
|
||||||
else {
|
|
||||||
fprintf(stderr,
|
|
||||||
_("Unexpected status %d from pid %d\n"),
|
|
||||||
status, pid);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
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
|
if (name == NULL) {
|
||||||
* don't affect us
|
fprintf(stderr, "%s: missing --name argument for configuration\n", argv[0]);
|
||||||
*/
|
goto cleanup;
|
||||||
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 (setsid() < 0) {
|
if (appPty < 0) {
|
||||||
fprintf(stderr, _("Unable to become session leader: %s\n"),
|
fprintf(stderr, "%s: missing --console argument for container PTY\n", argv[0]);
|
||||||
strerror(errno));
|
goto cleanup;
|
||||||
_exit(-1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((null = open(_PATH_DEVNULL, O_RDONLY)) < 0) {
|
if (getuid() && 0) {
|
||||||
fprintf(stderr, _("Unable to open %s: %s\n"),
|
fprintf(stderr, "%s: must be run as the 'root' user\n", argv[0]);
|
||||||
_PATH_DEVNULL, strerror(errno));
|
goto cleanup;
|
||||||
_exit(-1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open_max = sysconf (_SC_OPEN_MAX);
|
if ((caps = lxcCapsInit()) == NULL)
|
||||||
for (i = 0; i < open_max; i++)
|
goto cleanup;
|
||||||
if (i != appPty &&
|
|
||||||
i != monitor &&
|
|
||||||
i != logfd &&
|
|
||||||
i != null)
|
|
||||||
close(i);
|
|
||||||
|
|
||||||
if (dup2(null, STDIN_FILENO) < 0 ||
|
if ((configFile = virDomainConfigFile(NULL,
|
||||||
dup2(logfd, STDOUT_FILENO) < 0 ||
|
LXC_STATE_DIR,
|
||||||
dup2(logfd, STDERR_FILENO) < 0) {
|
name)) == NULL)
|
||||||
fprintf(stderr, _("Unable to redirect stdio: %s\n"),
|
goto cleanup;
|
||||||
strerror(errno));
|
|
||||||
_exit(-1);
|
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);
|
if ((sockpath = lxcMonitorPath(def)) == NULL)
|
||||||
close(logfd);
|
goto cleanup;
|
||||||
|
|
||||||
/* Now fork the real controller process */
|
if ((monitor = lxcMonitorServer(sockpath)) < 0)
|
||||||
if ((pid = fork()) < 0) {
|
goto cleanup;
|
||||||
fprintf(stderr, _("Unable to fork controller: %s\n"),
|
|
||||||
strerror(errno));
|
|
||||||
_exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pid > 0) {
|
if (bg) {
|
||||||
if ((rc = virFileWritePid(stateDir, def->name, pid)) != 0) {
|
if ((pid = fork()) < 0)
|
||||||
fprintf(stderr, _("Unable to write pid file: %s\n"),
|
goto cleanup;
|
||||||
strerror(rc));
|
|
||||||
_exit(-1);
|
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);
|
||||||
}
|
}
|
||||||
/* First child now exits, allowing originall caller to
|
|
||||||
* complete their waitpid & continue */
|
|
||||||
_exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is real controller running finally... */
|
/* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Accept initial client which is the libvirtd daemon */
|
/* Accept initial client which is the libvirtd daemon */
|
||||||
if ((client = accept(monitor, NULL, 0))) {
|
if ((client = accept(monitor, NULL, 0)) < 0) {
|
||||||
fprintf(stderr, _("Failed connection from LXC driver: %s\n"),
|
fprintf(stderr, _("Failed connection from LXC driver: %s\n"),
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
_exit(-1);
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Controlling libvirtd LXC driver now knows
|
rc = lxcControllerRun(def, nveths, veths, monitor, client, appPty);
|
||||||
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
|
|
||||||
|
191
src/lxc_driver.c
191
src/lxc_driver.c
@ -38,7 +38,6 @@
|
|||||||
#include "lxc_conf.h"
|
#include "lxc_conf.h"
|
||||||
#include "lxc_container.h"
|
#include "lxc_container.h"
|
||||||
#include "lxc_driver.h"
|
#include "lxc_driver.h"
|
||||||
#include "lxc_controller.h"
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "bridge.h"
|
#include "bridge.h"
|
||||||
@ -398,6 +397,7 @@ static int lxcVMCleanup(virConnectPtr conn,
|
|||||||
close(vm->monitor);
|
close(vm->monitor);
|
||||||
|
|
||||||
virFileDeletePid(driver->stateDir, vm->def->name);
|
virFileDeletePid(driver->stateDir, vm->def->name);
|
||||||
|
virDomainDeleteConfig(conn, driver->stateDir, NULL, vm);
|
||||||
|
|
||||||
vm->state = VIR_DOMAIN_SHUTOFF;
|
vm->state = VIR_DOMAIN_SHUTOFF;
|
||||||
vm->pid = -1;
|
vm->pid = -1;
|
||||||
@ -507,55 +507,6 @@ error_exit:
|
|||||||
return rc;
|
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,
|
static int lxcMonitorClient(virConnectPtr conn,
|
||||||
lxc_driver_t * driver,
|
lxc_driver_t * driver,
|
||||||
@ -608,6 +559,12 @@ static int lxcVmTerminate(virConnectPtr conn,
|
|||||||
if (signum == 0)
|
if (signum == 0)
|
||||||
signum = SIGINT;
|
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 (kill(vm->pid, signum) < 0) {
|
||||||
if (errno != ESRCH) {
|
if (errno != ESRCH) {
|
||||||
lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
|
lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
@ -644,6 +601,102 @@ static void lxcMonitorEvent(int fd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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:
|
* lxcVmStart:
|
||||||
* @conn: pointer to connection
|
* @conn: pointer to connection
|
||||||
@ -660,7 +713,6 @@ static int lxcVmStart(virConnectPtr conn,
|
|||||||
{
|
{
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int monitor;
|
|
||||||
int parentTty;
|
int parentTty;
|
||||||
char *parentTtyPath = NULL;
|
char *parentTtyPath = NULL;
|
||||||
char *logfile = NULL;
|
char *logfile = NULL;
|
||||||
@ -681,9 +733,6 @@ static int lxcVmStart(virConnectPtr conn,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((monitor = lxcMonitorServer(conn, driver, vm)) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
/* open parent tty */
|
/* open parent tty */
|
||||||
if (virFileOpenTty(&parentTty, &parentTtyPath, 1) < 0) {
|
if (virFileOpenTty(&parentTty, &parentTtyPath, 1) < 0) {
|
||||||
lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
|
lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
@ -702,6 +751,12 @@ static int lxcVmStart(virConnectPtr conn,
|
|||||||
if (lxcSetupInterfaces(conn, vm->def, &nveths, &veths) != 0)
|
if (lxcSetupInterfaces(conn, vm->def, &nveths, &veths) != 0)
|
||||||
goto cleanup;
|
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,
|
if ((logfd = open(logfile, O_WRONLY | O_TRUNC | O_CREAT,
|
||||||
S_IRUSR|S_IWUSR)) < 0) {
|
S_IRUSR|S_IWUSR)) < 0) {
|
||||||
lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
|
lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
@ -710,14 +765,11 @@ static int lxcVmStart(virConnectPtr conn,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lxcControllerStart(driver->stateDir,
|
if (lxcControllerStart(conn,
|
||||||
vm->def, nveths, veths,
|
vm,
|
||||||
monitor, parentTty, logfd) < 0)
|
nveths, veths,
|
||||||
|
parentTty, logfd) < 0)
|
||||||
goto cleanup;
|
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
|
/* Connect to the controller as a client *first* because
|
||||||
* this will block until the child has written their
|
* this will block until the child has written their
|
||||||
@ -753,8 +805,6 @@ cleanup:
|
|||||||
vethDelete(veths[i]);
|
vethDelete(veths[i]);
|
||||||
VIR_FREE(veths[i]);
|
VIR_FREE(veths[i]);
|
||||||
}
|
}
|
||||||
if (monitor != -1)
|
|
||||||
close(monitor);
|
|
||||||
if (rc != 0 && vm->monitor != -1) {
|
if (rc != 0 && vm->monitor != -1) {
|
||||||
close(vm->monitor);
|
close(vm->monitor);
|
||||||
vm->monitor = -1;
|
vm->monitor = -1;
|
||||||
@ -951,6 +1001,8 @@ static int lxcStartup(void)
|
|||||||
|
|
||||||
vm = lxc_driver->domains;
|
vm = lxc_driver->domains;
|
||||||
while (vm) {
|
while (vm) {
|
||||||
|
char *config = NULL;
|
||||||
|
virDomainDefPtr tmp;
|
||||||
int rc;
|
int rc;
|
||||||
if ((vm->monitor = lxcMonitorClient(NULL, lxc_driver, vm)) < 0) {
|
if ((vm->monitor = lxcMonitorClient(NULL, lxc_driver, vm)) < 0) {
|
||||||
vm = vm->next;
|
vm = vm->next;
|
||||||
@ -965,6 +1017,19 @@ static int lxcStartup(void)
|
|||||||
continue;
|
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) {
|
if (vm->pid != 0) {
|
||||||
vm->def->id = vm->pid;
|
vm->def->id = vm->pid;
|
||||||
vm->state = VIR_DOMAIN_RUNNING;
|
vm->state = VIR_DOMAIN_RUNNING;
|
||||||
|
Loading…
Reference in New Issue
Block a user