提交 965a957c 编写于 作者: C Cole Robinson

lxc: Improve guest startup error reporting

Add a simple handshake with the lxc_controller process so we can detect
process startup failures. We do this by adding a new --handshake cli arg
to lxc_controller for passing a file descriptor. If the process fails to
launch, we scrape all output from the logfile and report it to the user.
上级 af1e180f
...@@ -213,7 +213,7 @@ error_out: ...@@ -213,7 +213,7 @@ error_out:
* *
* Returns 0 on success or -1 in case of error * Returns 0 on success or -1 in case of error
*/ */
static int lxcContainerWaitForContinue(int control) int lxcContainerWaitForContinue(int control)
{ {
lxc_message_t msg; lxc_message_t msg;
int readLen; int readLen;
......
...@@ -46,6 +46,7 @@ enum { ...@@ -46,6 +46,7 @@ enum {
# define LXC_DEV_MAJ_PTY 136 # define LXC_DEV_MAJ_PTY 136
int lxcContainerSendContinue(int control); int lxcContainerSendContinue(int control);
int lxcContainerWaitForContinue(int control);
int lxcContainerStart(virDomainDefPtr def, int lxcContainerStart(virDomainDefPtr def,
unsigned int nveths, unsigned int nveths,
......
...@@ -612,7 +612,8 @@ lxcControllerRun(virDomainDefPtr def, ...@@ -612,7 +612,8 @@ lxcControllerRun(virDomainDefPtr def,
char **veths, char **veths,
int monitor, int monitor,
int client, int client,
int appPty) int appPty,
int handshakefd)
{ {
int rc = -1; int rc = -1;
int control[2] = { -1, -1}; int control[2] = { -1, -1};
...@@ -742,6 +743,13 @@ lxcControllerRun(virDomainDefPtr def, ...@@ -742,6 +743,13 @@ lxcControllerRun(virDomainDefPtr def,
if (lxcControllerClearCapabilities() < 0) if (lxcControllerClearCapabilities() < 0)
goto cleanup; goto cleanup;
if (lxcContainerSendContinue(handshakefd) < 0) {
virReportSystemError(errno, "%s",
_("error sending continue signal to parent"));
goto cleanup;
}
VIR_FORCE_CLOSE(handshakefd);
rc = lxcControllerMain(monitor, client, appPty, containerPty, container); rc = lxcControllerMain(monitor, client, appPty, containerPty, container);
cleanup: cleanup:
...@@ -751,6 +759,7 @@ cleanup: ...@@ -751,6 +759,7 @@ cleanup:
VIR_FORCE_CLOSE(control[1]); VIR_FORCE_CLOSE(control[1]);
VIR_FREE(containerPtyPath); VIR_FREE(containerPtyPath);
VIR_FORCE_CLOSE(containerPty); VIR_FORCE_CLOSE(containerPty);
VIR_FORCE_CLOSE(handshakefd);
if (container > 1) { if (container > 1) {
int status; int status;
...@@ -774,6 +783,7 @@ int main(int argc, char *argv[]) ...@@ -774,6 +783,7 @@ int main(int argc, char *argv[])
char **veths = NULL; char **veths = NULL;
int monitor = -1; int monitor = -1;
int appPty = -1; int appPty = -1;
int handshakefd = -1;
int bg = 0; int bg = 0;
virCapsPtr caps = NULL; virCapsPtr caps = NULL;
virDomainDefPtr def = NULL; virDomainDefPtr def = NULL;
...@@ -784,6 +794,7 @@ int main(int argc, char *argv[]) ...@@ -784,6 +794,7 @@ int main(int argc, char *argv[])
{ "name", 1, NULL, 'n' }, { "name", 1, NULL, 'n' },
{ "veth", 1, NULL, 'v' }, { "veth", 1, NULL, 'v' },
{ "console", 1, NULL, 'c' }, { "console", 1, NULL, 'c' },
{ "handshakefd", 1, NULL, 's' },
{ "help", 0, NULL, 'h' }, { "help", 0, NULL, 'h' },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 },
}; };
...@@ -798,7 +809,7 @@ int main(int argc, char *argv[]) ...@@ -798,7 +809,7 @@ int main(int argc, char *argv[])
while (1) { while (1) {
int c; int c;
c = getopt_long(argc, argv, "dn:v:m:c:h", c = getopt_long(argc, argv, "dn:v:m:c:s:h",
options, NULL); options, NULL);
if (c == -1) if (c == -1)
...@@ -834,6 +845,14 @@ int main(int argc, char *argv[]) ...@@ -834,6 +845,14 @@ int main(int argc, char *argv[])
} }
break; break;
case 's':
if (virStrToLong_i(optarg, NULL, 10, &handshakefd) < 0) {
fprintf(stderr, "malformed --handshakefd argument '%s'",
optarg);
goto cleanup;
}
break;
case 'h': case 'h':
case '?': case '?':
fprintf(stderr, "\n"); fprintf(stderr, "\n");
...@@ -845,6 +864,7 @@ int main(int argc, char *argv[]) ...@@ -845,6 +864,7 @@ int main(int argc, char *argv[])
fprintf(stderr, " -n NAME, --name NAME\n"); fprintf(stderr, " -n NAME, --name NAME\n");
fprintf(stderr, " -c FD, --console FD\n"); fprintf(stderr, " -c FD, --console FD\n");
fprintf(stderr, " -v VETH, --veth VETH\n"); fprintf(stderr, " -v VETH, --veth VETH\n");
fprintf(stderr, " -s FD, --handshakefd FD\n");
fprintf(stderr, " -h, --help\n"); fprintf(stderr, " -h, --help\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
goto cleanup; goto cleanup;
...@@ -862,6 +882,12 @@ int main(int argc, char *argv[]) ...@@ -862,6 +882,12 @@ int main(int argc, char *argv[])
goto cleanup; goto cleanup;
} }
if (handshakefd < 0) {
fprintf(stderr, "%s: missing --handshake argument for container PTY\n",
argv[0]);
goto cleanup;
}
if (getuid() != 0) { if (getuid() != 0) {
fprintf(stderr, "%s: must be run as the 'root' user\n", argv[0]); fprintf(stderr, "%s: must be run as the 'root' user\n", argv[0]);
goto cleanup; goto cleanup;
...@@ -932,7 +958,8 @@ int main(int argc, char *argv[]) ...@@ -932,7 +958,8 @@ int main(int argc, char *argv[])
goto cleanup; goto cleanup;
} }
rc = lxcControllerRun(def, nveths, veths, monitor, client, appPty); rc = lxcControllerRun(def, nveths, veths, monitor, client, appPty,
handshakefd);
cleanup: cleanup:
......
...@@ -1287,7 +1287,8 @@ lxcBuildControllerCmd(lxc_driver_t *driver, ...@@ -1287,7 +1287,8 @@ lxcBuildControllerCmd(lxc_driver_t *driver,
int nveths, int nveths,
char **veths, char **veths,
int appPty, int appPty,
int logfile) int logfile,
int handshakefd)
{ {
int i; int i;
char *filterstr; char *filterstr;
...@@ -1332,6 +1333,8 @@ lxcBuildControllerCmd(lxc_driver_t *driver, ...@@ -1332,6 +1333,8 @@ lxcBuildControllerCmd(lxc_driver_t *driver,
virCommandAddArgList(cmd, "--name", vm->def->name, "--console", NULL); virCommandAddArgList(cmd, "--name", vm->def->name, "--console", NULL);
virCommandAddArgFormat(cmd, "%d", appPty); virCommandAddArgFormat(cmd, "%d", appPty);
virCommandAddArg(cmd, "--handshake");
virCommandAddArgFormat(cmd, "%d", handshakefd);
virCommandAddArg(cmd, "--background"); virCommandAddArg(cmd, "--background");
for (i = 0 ; i < nveths ; i++) { for (i = 0 ; i < nveths ; i++) {
...@@ -1355,6 +1358,7 @@ lxcBuildControllerCmd(lxc_driver_t *driver, ...@@ -1355,6 +1358,7 @@ lxcBuildControllerCmd(lxc_driver_t *driver,
} }
virCommandPreserveFD(cmd, appPty); virCommandPreserveFD(cmd, appPty);
virCommandPreserveFD(cmd, handshakefd);
virCommandSetOutputFD(cmd, &logfile); virCommandSetOutputFD(cmd, &logfile);
virCommandSetErrorFD(cmd, &logfile); virCommandSetErrorFD(cmd, &logfile);
...@@ -1364,6 +1368,78 @@ cleanup: ...@@ -1364,6 +1368,78 @@ cleanup:
return NULL; return NULL;
} }
static int
lxcReadLogOutput(virDomainObjPtr vm,
char *logfile,
off_t pos,
char *buf,
size_t buflen)
{
int fd;
off_t off;
int whence;
int got = 0, ret = -1;
int retries = 10;
if ((fd = open(logfile, O_RDONLY)) < 0) {
virReportSystemError(errno, _("failed to open logfile %s"),
logfile);
goto cleanup;
}
if (pos < 0) {
off = 0;
whence = SEEK_END;
} else {
off = pos;
whence = SEEK_SET;
}
if (lseek(fd, off, whence) < 0) {
if (whence == SEEK_END)
virReportSystemError(errno,
_("unable to seek to end of log for %s"),
logfile);
else
virReportSystemError(errno,
_("unable to seek to %lld from start for %s"),
(long long)off, logfile);
goto cleanup;
}
while (retries) {
ssize_t bytes;
int isdead = 0;
if (kill(vm->pid, 0) == -1 && errno == ESRCH)
isdead = 1;
/* Any failures should be detected before we read the log, so we
* always have something useful to report on failure. */
bytes = saferead(fd, buf+got, buflen-got-1);
if (bytes < 0) {
virReportSystemError(errno, "%s",
_("Failure while reading guest log output"));
goto cleanup;
}
got += bytes;
buf[got] = '\0';
if ((got == buflen-1) || isdead) {
break;
}
usleep(100*1000);
retries--;
}
ret = got;
cleanup:
VIR_FORCE_CLOSE(fd);
return ret;
}
/** /**
* lxcVmStart: * lxcVmStart:
...@@ -1389,6 +1465,7 @@ static int lxcVmStart(virConnectPtr conn, ...@@ -1389,6 +1465,7 @@ static int lxcVmStart(virConnectPtr conn,
int logfd = -1; int logfd = -1;
unsigned int nveths = 0; unsigned int nveths = 0;
char **veths = NULL; char **veths = NULL;
int handshakefds[2] = { -1, -1 };
off_t pos = -1; off_t pos = -1;
char ebuf[1024]; char ebuf[1024];
char *timestamp; char *timestamp;
...@@ -1462,10 +1539,16 @@ static int lxcVmStart(virConnectPtr conn, ...@@ -1462,10 +1539,16 @@ static int lxcVmStart(virConnectPtr conn,
goto cleanup; goto cleanup;
} }
if (pipe(handshakefds) < 0) {
virReportSystemError(errno, "%s",
_("Unable to create pipe"));
goto cleanup;
}
if (!(cmd = lxcBuildControllerCmd(driver, if (!(cmd = lxcBuildControllerCmd(driver,
vm, vm,
nveths, veths, nveths, veths,
parentTty, logfd))) parentTty, logfd, handshakefds[1])))
goto cleanup; goto cleanup;
/* Log timestamp */ /* Log timestamp */
...@@ -1489,6 +1572,11 @@ static int lxcVmStart(virConnectPtr conn, ...@@ -1489,6 +1572,11 @@ static int lxcVmStart(virConnectPtr conn,
if (virCommandRun(cmd, NULL) < 0) if (virCommandRun(cmd, NULL) < 0)
goto cleanup; goto cleanup;
if (VIR_CLOSE(handshakefds[1]) < 0) {
virReportSystemError(errno, "%s", _("could not close handshake fd"));
goto cleanup;
}
/* 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
* pid file out to disk */ * pid file out to disk */
...@@ -1506,6 +1594,18 @@ static int lxcVmStart(virConnectPtr conn, ...@@ -1506,6 +1594,18 @@ static int lxcVmStart(virConnectPtr conn,
vm->def->id = vm->pid; vm->def->id = vm->pid;
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason); virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason);
if (lxcContainerWaitForContinue(handshakefds[0]) < 0) {
char out[1024];
if (!(lxcReadLogOutput(vm, logfile, pos, out, 1024) < 0)) {
lxcError(VIR_ERR_INTERNAL_ERROR,
_("guest failed to start: %s"), out);
}
lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED);
goto cleanup;
}
if ((priv->monitorWatch = virEventAddHandle( if ((priv->monitorWatch = virEventAddHandle(
priv->monitor, priv->monitor,
VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP, VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP,
...@@ -1545,6 +1645,8 @@ cleanup: ...@@ -1545,6 +1645,8 @@ cleanup:
if (rc != 0) if (rc != 0)
VIR_FORCE_CLOSE(priv->monitor); VIR_FORCE_CLOSE(priv->monitor);
VIR_FORCE_CLOSE(parentTty); VIR_FORCE_CLOSE(parentTty);
VIR_FORCE_CLOSE(handshakefds[0]);
VIR_FORCE_CLOSE(handshakefds[1]);
VIR_FREE(logfile); VIR_FREE(logfile);
return rc; return rc;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册