mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-12 15:52:55 +00:00
qemu: Check domain status details when reconnecting monitor
Current qemu is able to give us detailed domain status (not just if it is running or not) which we can translate into a status reason.
This commit is contained in:
parent
1cb031a2bb
commit
c20b7c9826
@ -81,6 +81,12 @@ VIR_ENUM_IMPL(qemuMonitorMigrationStatus,
|
|||||||
QEMU_MONITOR_MIGRATION_STATUS_LAST,
|
QEMU_MONITOR_MIGRATION_STATUS_LAST,
|
||||||
"inactive", "active", "completed", "failed", "cancelled")
|
"inactive", "active", "completed", "failed", "cancelled")
|
||||||
|
|
||||||
|
VIR_ENUM_IMPL(qemuMonitorVMStatus,
|
||||||
|
QEMU_MONITOR_VM_STATUS_LAST,
|
||||||
|
"debug", "inmigrate", "internal-error", "io-error", "paused",
|
||||||
|
"postmigrate", "prelaunch", "finish-migrate", "restore-vm",
|
||||||
|
"running", "save-vm", "shutdown", "watchdog")
|
||||||
|
|
||||||
char *qemuMonitorEscapeArg(const char *in)
|
char *qemuMonitorEscapeArg(const char *in)
|
||||||
{
|
{
|
||||||
int len = 0;
|
int len = 0;
|
||||||
@ -1059,10 +1065,12 @@ qemuMonitorStopCPUs(qemuMonitorPtr mon)
|
|||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
qemuMonitorGetStatus(qemuMonitorPtr mon, bool *running)
|
qemuMonitorGetStatus(qemuMonitorPtr mon,
|
||||||
|
bool *running,
|
||||||
|
virDomainPausedReason *reason)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
VIR_DEBUG("mon=%p, running=%p", mon, running);
|
VIR_DEBUG("mon=%p, running=%p, reason=%p", mon, running, reason);
|
||||||
|
|
||||||
if (!mon || !running) {
|
if (!mon || !running) {
|
||||||
qemuReportError(VIR_ERR_INVALID_ARG, "%s",
|
qemuReportError(VIR_ERR_INVALID_ARG, "%s",
|
||||||
@ -1071,9 +1079,9 @@ qemuMonitorGetStatus(qemuMonitorPtr mon, bool *running)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mon->json)
|
if (mon->json)
|
||||||
ret = qemuMonitorJSONGetStatus(mon, running);
|
ret = qemuMonitorJSONGetStatus(mon, running, reason);
|
||||||
else
|
else
|
||||||
ret = qemuMonitorTextGetStatus(mon, running);
|
ret = qemuMonitorTextGetStatus(mon, running, reason);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2553,3 +2561,53 @@ int qemuMonitorBlockJob(qemuMonitorPtr mon,
|
|||||||
ret = qemuMonitorTextBlockJob(mon, device, bandwidth, info, mode);
|
ret = qemuMonitorTextBlockJob(mon, device, bandwidth, info, mode);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int qemuMonitorVMStatusToPausedReason(const char *status)
|
||||||
|
{
|
||||||
|
int st;
|
||||||
|
|
||||||
|
if (!status)
|
||||||
|
return VIR_DOMAIN_PAUSED_UNKNOWN;
|
||||||
|
|
||||||
|
if ((st = qemuMonitorVMStatusTypeFromString(status)) < 0) {
|
||||||
|
VIR_WARN("Qemu reported unknown VM status: '%s'", status);
|
||||||
|
return VIR_DOMAIN_PAUSED_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ((qemuMonitorVMStatus) st) {
|
||||||
|
case QEMU_MONITOR_VM_STATUS_DEBUG:
|
||||||
|
case QEMU_MONITOR_VM_STATUS_INTERNAL_ERROR:
|
||||||
|
case QEMU_MONITOR_VM_STATUS_RESTORE_VM:
|
||||||
|
return VIR_DOMAIN_PAUSED_UNKNOWN;
|
||||||
|
|
||||||
|
case QEMU_MONITOR_VM_STATUS_INMIGRATE:
|
||||||
|
case QEMU_MONITOR_VM_STATUS_POSTMIGRATE:
|
||||||
|
case QEMU_MONITOR_VM_STATUS_FINISH_MIGRATE:
|
||||||
|
return VIR_DOMAIN_PAUSED_MIGRATION;
|
||||||
|
|
||||||
|
case QEMU_MONITOR_VM_STATUS_IO_ERROR:
|
||||||
|
return VIR_DOMAIN_PAUSED_IOERROR;
|
||||||
|
|
||||||
|
case QEMU_MONITOR_VM_STATUS_PAUSED:
|
||||||
|
case QEMU_MONITOR_VM_STATUS_PRELAUNCH:
|
||||||
|
return VIR_DOMAIN_PAUSED_USER;
|
||||||
|
|
||||||
|
case QEMU_MONITOR_VM_STATUS_RUNNING:
|
||||||
|
VIR_WARN("Qemu reports the guest is paused but status is 'running'");
|
||||||
|
return VIR_DOMAIN_PAUSED_UNKNOWN;
|
||||||
|
|
||||||
|
case QEMU_MONITOR_VM_STATUS_SAVE_VM:
|
||||||
|
return VIR_DOMAIN_PAUSED_SAVE;
|
||||||
|
|
||||||
|
case QEMU_MONITOR_VM_STATUS_SHUTDOWN:
|
||||||
|
return VIR_DOMAIN_PAUSED_SHUTTING_DOWN;
|
||||||
|
|
||||||
|
case QEMU_MONITOR_VM_STATUS_WATCHDOG:
|
||||||
|
return VIR_DOMAIN_PAUSED_WATCHDOG;
|
||||||
|
|
||||||
|
/* unreachable from this point on */
|
||||||
|
case QEMU_MONITOR_VM_STATUS_LAST:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
return VIR_DOMAIN_PAUSED_UNKNOWN;
|
||||||
|
}
|
||||||
|
@ -198,7 +198,30 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
|
|||||||
int qemuMonitorStartCPUs(qemuMonitorPtr mon,
|
int qemuMonitorStartCPUs(qemuMonitorPtr mon,
|
||||||
virConnectPtr conn);
|
virConnectPtr conn);
|
||||||
int qemuMonitorStopCPUs(qemuMonitorPtr mon);
|
int qemuMonitorStopCPUs(qemuMonitorPtr mon);
|
||||||
int qemuMonitorGetStatus(qemuMonitorPtr mon, bool *running);
|
|
||||||
|
typedef enum {
|
||||||
|
QEMU_MONITOR_VM_STATUS_DEBUG,
|
||||||
|
QEMU_MONITOR_VM_STATUS_INMIGRATE,
|
||||||
|
QEMU_MONITOR_VM_STATUS_INTERNAL_ERROR,
|
||||||
|
QEMU_MONITOR_VM_STATUS_IO_ERROR,
|
||||||
|
QEMU_MONITOR_VM_STATUS_PAUSED,
|
||||||
|
QEMU_MONITOR_VM_STATUS_POSTMIGRATE,
|
||||||
|
QEMU_MONITOR_VM_STATUS_PRELAUNCH,
|
||||||
|
QEMU_MONITOR_VM_STATUS_FINISH_MIGRATE,
|
||||||
|
QEMU_MONITOR_VM_STATUS_RESTORE_VM,
|
||||||
|
QEMU_MONITOR_VM_STATUS_RUNNING,
|
||||||
|
QEMU_MONITOR_VM_STATUS_SAVE_VM,
|
||||||
|
QEMU_MONITOR_VM_STATUS_SHUTDOWN,
|
||||||
|
QEMU_MONITOR_VM_STATUS_WATCHDOG,
|
||||||
|
|
||||||
|
QEMU_MONITOR_VM_STATUS_LAST
|
||||||
|
} qemuMonitorVMStatus;
|
||||||
|
VIR_ENUM_DECL(qemuMonitorVMStatus)
|
||||||
|
int qemuMonitorVMStatusToPausedReason(const char *status);
|
||||||
|
|
||||||
|
int qemuMonitorGetStatus(qemuMonitorPtr mon,
|
||||||
|
bool *running,
|
||||||
|
virDomainPausedReason *reason);
|
||||||
|
|
||||||
int qemuMonitorSystemReset(qemuMonitorPtr mon);
|
int qemuMonitorSystemReset(qemuMonitorPtr mon);
|
||||||
int qemuMonitorSystemPowerdown(qemuMonitorPtr mon);
|
int qemuMonitorSystemPowerdown(qemuMonitorPtr mon);
|
||||||
|
@ -896,13 +896,19 @@ qemuMonitorJSONStopCPUs(qemuMonitorPtr mon)
|
|||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
qemuMonitorJSONGetStatus(qemuMonitorPtr mon, bool *running)
|
qemuMonitorJSONGetStatus(qemuMonitorPtr mon,
|
||||||
|
bool *running,
|
||||||
|
virDomainPausedReason *reason)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
const char *status;
|
||||||
virJSONValuePtr cmd;
|
virJSONValuePtr cmd;
|
||||||
virJSONValuePtr reply = NULL;
|
virJSONValuePtr reply = NULL;
|
||||||
virJSONValuePtr data;
|
virJSONValuePtr data;
|
||||||
|
|
||||||
|
if (reason)
|
||||||
|
*reason = VIR_DOMAIN_PAUSED_UNKNOWN;
|
||||||
|
|
||||||
if (!(cmd = qemuMonitorJSONMakeCommand("query-status", NULL)))
|
if (!(cmd = qemuMonitorJSONMakeCommand("query-status", NULL)))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -928,6 +934,13 @@ qemuMonitorJSONGetStatus(qemuMonitorPtr mon, bool *running)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((status = virJSONValueObjectGetString(data, "status"))) {
|
||||||
|
if (!*running && reason)
|
||||||
|
*reason = qemuMonitorVMStatusToPausedReason(status);
|
||||||
|
} else if (!*running) {
|
||||||
|
VIR_DEBUG("query-status reply was missing status details");
|
||||||
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
@ -46,7 +46,9 @@ int qemuMonitorJSONCheckHMP(qemuMonitorPtr mon);
|
|||||||
int qemuMonitorJSONStartCPUs(qemuMonitorPtr mon,
|
int qemuMonitorJSONStartCPUs(qemuMonitorPtr mon,
|
||||||
virConnectPtr conn);
|
virConnectPtr conn);
|
||||||
int qemuMonitorJSONStopCPUs(qemuMonitorPtr mon);
|
int qemuMonitorJSONStopCPUs(qemuMonitorPtr mon);
|
||||||
int qemuMonitorJSONGetStatus(qemuMonitorPtr mon, bool *running);
|
int qemuMonitorJSONGetStatus(qemuMonitorPtr mon,
|
||||||
|
bool *running,
|
||||||
|
virDomainPausedReason *reason);
|
||||||
|
|
||||||
int qemuMonitorJSONSystemPowerdown(qemuMonitorPtr mon);
|
int qemuMonitorJSONSystemPowerdown(qemuMonitorPtr mon);
|
||||||
int qemuMonitorJSONSystemReset(qemuMonitorPtr mon);
|
int qemuMonitorJSONSystemReset(qemuMonitorPtr mon);
|
||||||
|
@ -392,11 +392,16 @@ qemuMonitorTextStopCPUs(qemuMonitorPtr mon) {
|
|||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
qemuMonitorTextGetStatus(qemuMonitorPtr mon, bool *running)
|
qemuMonitorTextGetStatus(qemuMonitorPtr mon,
|
||||||
|
bool *running,
|
||||||
|
virDomainPausedReason *reason)
|
||||||
{
|
{
|
||||||
char *reply;
|
char *reply;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
|
if (reason)
|
||||||
|
*reason = VIR_DOMAIN_PAUSED_UNKNOWN;
|
||||||
|
|
||||||
if (qemuMonitorHMPCommand(mon, "info status", &reply) < 0) {
|
if (qemuMonitorHMPCommand(mon, "info status", &reply) < 0) {
|
||||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
"%s", _("cannot get status info"));
|
"%s", _("cannot get status info"));
|
||||||
@ -406,6 +411,19 @@ qemuMonitorTextGetStatus(qemuMonitorPtr mon, bool *running)
|
|||||||
if (strstr(reply, "running")) {
|
if (strstr(reply, "running")) {
|
||||||
*running = true;
|
*running = true;
|
||||||
} else if (strstr(reply, "paused")) {
|
} else if (strstr(reply, "paused")) {
|
||||||
|
char *status;
|
||||||
|
|
||||||
|
if ((status = strchr(reply, '('))) {
|
||||||
|
char *end = strchr(status, ')');
|
||||||
|
if (end)
|
||||||
|
*end = '\0';
|
||||||
|
else
|
||||||
|
status = NULL;
|
||||||
|
}
|
||||||
|
if (!status)
|
||||||
|
VIR_DEBUG("info status was missing status details");
|
||||||
|
else if (reason)
|
||||||
|
*reason = qemuMonitorVMStatusToPausedReason(status);
|
||||||
*running = false;
|
*running = false;
|
||||||
} else {
|
} else {
|
||||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
|
@ -43,7 +43,9 @@ int qemuMonitorTextCommandWithFd(qemuMonitorPtr mon,
|
|||||||
int qemuMonitorTextStartCPUs(qemuMonitorPtr mon,
|
int qemuMonitorTextStartCPUs(qemuMonitorPtr mon,
|
||||||
virConnectPtr conn);
|
virConnectPtr conn);
|
||||||
int qemuMonitorTextStopCPUs(qemuMonitorPtr mon);
|
int qemuMonitorTextStopCPUs(qemuMonitorPtr mon);
|
||||||
int qemuMonitorTextGetStatus(qemuMonitorPtr mon, bool *running);
|
int qemuMonitorTextGetStatus(qemuMonitorPtr mon,
|
||||||
|
bool *running,
|
||||||
|
virDomainPausedReason *reason);
|
||||||
|
|
||||||
int qemuMonitorTextSystemPowerdown(qemuMonitorPtr mon);
|
int qemuMonitorTextSystemPowerdown(qemuMonitorPtr mon);
|
||||||
int qemuMonitorTextSystemReset(qemuMonitorPtr mon);
|
int qemuMonitorTextSystemReset(qemuMonitorPtr mon);
|
||||||
|
@ -2321,11 +2321,12 @@ qemuProcessUpdateState(struct qemud_driver *driver, virDomainObjPtr vm)
|
|||||||
{
|
{
|
||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
virDomainState state;
|
virDomainState state;
|
||||||
|
virDomainPausedReason reason;
|
||||||
bool running;
|
bool running;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
||||||
ret = qemuMonitorGetStatus(priv->mon, &running);
|
ret = qemuMonitorGetStatus(priv->mon, &running, &reason);
|
||||||
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
||||||
|
|
||||||
if (ret < 0 || !virDomainObjIsActive(vm))
|
if (ret < 0 || !virDomainObjIsActive(vm))
|
||||||
@ -2339,9 +2340,10 @@ qemuProcessUpdateState(struct qemud_driver *driver, virDomainObjPtr vm)
|
|||||||
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
|
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
|
||||||
VIR_DOMAIN_RUNNING_UNPAUSED);
|
VIR_DOMAIN_RUNNING_UNPAUSED);
|
||||||
} else if (state == VIR_DOMAIN_RUNNING && !running) {
|
} else if (state == VIR_DOMAIN_RUNNING && !running) {
|
||||||
VIR_DEBUG("Domain %s was paused while its monitor was disconnected;"
|
VIR_DEBUG("Domain %s was paused (%s) while its monitor was"
|
||||||
" changing state to paused", vm->def->name);
|
" disconnected; changing state to paused",
|
||||||
virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_UNKNOWN);
|
vm->def->name, virDomainPausedReasonTypeToString(reason));
|
||||||
|
virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, reason);
|
||||||
} else if (state == VIR_DOMAIN_SHUTOFF && running) {
|
} else if (state == VIR_DOMAIN_SHUTOFF && running) {
|
||||||
VIR_DEBUG("Domain %s finished booting; changing state to running",
|
VIR_DEBUG("Domain %s finished booting; changing state to running",
|
||||||
vm->def->name);
|
vm->def->name);
|
||||||
@ -3470,6 +3472,7 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
char *timestamp;
|
char *timestamp;
|
||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
bool running = true;
|
bool running = true;
|
||||||
|
virDomainPausedReason reason;
|
||||||
virSecurityLabelPtr seclabel = NULL;
|
virSecurityLabelPtr seclabel = NULL;
|
||||||
|
|
||||||
VIR_DEBUG("Beginning VM attach process");
|
VIR_DEBUG("Beginning VM attach process");
|
||||||
@ -3599,7 +3602,7 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (qemuMonitorGetStatus(priv->mon, &running) < 0) {
|
if (qemuMonitorGetStatus(priv->mon, &running, &reason) < 0) {
|
||||||
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -3616,7 +3619,7 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
|
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
|
||||||
VIR_DOMAIN_RUNNING_UNPAUSED);
|
VIR_DOMAIN_RUNNING_UNPAUSED);
|
||||||
else
|
else
|
||||||
virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_UNKNOWN);
|
virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, reason);
|
||||||
|
|
||||||
VIR_DEBUG("Writing domain status to disk");
|
VIR_DEBUG("Writing domain status to disk");
|
||||||
if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
|
if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user