mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-22 04:25:18 +00:00
tools: console: pass stream/fd errors to user
If the console was disconnected due to a connection problem or a problem on the server side it is convinient to provide the cause to the user. If the error come from the API then the error is saved in a virsh global variable. However, since success is returned from virshRunConsole after we reach the waiting stage, then the error is never reported. Let's track the error in the event loop. Next after failure we do a cleanup and this cleanup can overwrite root cause. Thus let's save root cause immediately and then set it to virsh error after all cleanup is done. Since we'll be sending the error to the consumer, each failure path from the event handlers needs to be augmented to provide what error generated the failure. Reviewed-by: Cole Robinson <crobinso@redhat.com> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com>
This commit is contained in:
parent
4525de7356
commit
29f2b5248c
@ -73,6 +73,7 @@ struct virConsole {
|
||||
struct virConsoleBuffer terminalToStream;
|
||||
|
||||
char escapeChar;
|
||||
virError error;
|
||||
};
|
||||
|
||||
static virClassPtr virConsoleClass;
|
||||
@ -98,6 +99,11 @@ virConsoleHandleSignal(int sig ATTRIBUTE_UNUSED)
|
||||
static void
|
||||
virConsoleShutdown(virConsolePtr con)
|
||||
{
|
||||
virErrorPtr err = virGetLastError();
|
||||
|
||||
if (con->error.code == VIR_ERR_OK && err)
|
||||
virCopyLastError(&con->error);
|
||||
|
||||
if (con->st) {
|
||||
virStreamEventRemoveCallback(con->st);
|
||||
virStreamAbort(con->st);
|
||||
@ -128,6 +134,7 @@ virConsoleDispose(void *obj)
|
||||
virStreamFree(con->st);
|
||||
|
||||
virCondDestroy(&con->cond);
|
||||
virResetError(&con->error);
|
||||
}
|
||||
|
||||
|
||||
@ -165,6 +172,10 @@ virConsoleEventOnStream(virStreamPtr st,
|
||||
if (got == -2)
|
||||
goto cleanup; /* blocking */
|
||||
if (got <= 0) {
|
||||
if (got == 0)
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("console stream EOF"));
|
||||
|
||||
virConsoleShutdown(con);
|
||||
goto cleanup;
|
||||
}
|
||||
@ -247,11 +258,14 @@ virConsoleEventOnStdin(int watch ATTRIBUTE_UNUSED,
|
||||
con->terminalToStream.offset,
|
||||
avail);
|
||||
if (got < 0) {
|
||||
if (errno != EAGAIN)
|
||||
if (errno != EAGAIN) {
|
||||
virReportSystemError(errno, "%s", _("cannot read from stdin"));
|
||||
virConsoleShutdown(con);
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
if (got == 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("EOF on stdin"));
|
||||
virConsoleShutdown(con);
|
||||
goto cleanup;
|
||||
}
|
||||
@ -267,9 +281,16 @@ virConsoleEventOnStdin(int watch ATTRIBUTE_UNUSED,
|
||||
VIR_STREAM_EVENT_WRITABLE);
|
||||
}
|
||||
|
||||
if (events & VIR_EVENT_HANDLE_ERROR ||
|
||||
events & VIR_EVENT_HANDLE_HANGUP) {
|
||||
if (events & VIR_EVENT_HANDLE_ERROR) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("IO error on stdin"));
|
||||
virConsoleShutdown(con);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (events & VIR_EVENT_HANDLE_HANGUP) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("EOF on stdin"));
|
||||
virConsoleShutdown(con);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
@ -299,8 +320,10 @@ virConsoleEventOnStdout(int watch ATTRIBUTE_UNUSED,
|
||||
con->streamToTerminal.data,
|
||||
con->streamToTerminal.offset);
|
||||
if (done < 0) {
|
||||
if (errno != EAGAIN)
|
||||
if (errno != EAGAIN) {
|
||||
virReportSystemError(errno, "%s", _("cannot write to stdout"));
|
||||
virConsoleShutdown(con);
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
memmove(con->streamToTerminal.data,
|
||||
@ -319,9 +342,16 @@ virConsoleEventOnStdout(int watch ATTRIBUTE_UNUSED,
|
||||
if (!con->streamToTerminal.offset)
|
||||
virEventUpdateHandle(con->stdoutWatch, 0);
|
||||
|
||||
if (events & VIR_EVENT_HANDLE_ERROR ||
|
||||
events & VIR_EVENT_HANDLE_HANGUP) {
|
||||
if (events & VIR_EVENT_HANDLE_ERROR) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("IO error stdout"));
|
||||
virConsoleShutdown(con);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (events & VIR_EVENT_HANDLE_HANGUP) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("EOF on stdout"));
|
||||
virConsoleShutdown(con);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
@ -449,15 +479,24 @@ virshRunConsole(vshControl *ctl,
|
||||
|
||||
while (!con->quit) {
|
||||
if (virCondWait(&con->cond, &con->parent.lock) < 0) {
|
||||
VIR_ERROR(_("unable to wait on console condition"));
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("unable to wait on console condition"));
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
if (con->error.code == VIR_ERR_OK)
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
virConsoleShutdown(con);
|
||||
|
||||
if (ret < 0) {
|
||||
vshResetLibvirtError();
|
||||
virSetError(&con->error);
|
||||
vshSaveLibvirtHelperError();
|
||||
}
|
||||
|
||||
virObjectUnlock(con);
|
||||
virObjectUnref(con);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user