mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-26 02:50:32 +03:00
Add handling for reboots of LXC containers
The reboot() syscall is allowed by new kernels for LXC containers. The LXC controller can detect whether a reboot was requested (instead of a normal shutdown) by looking at the "init" process exit status. If a reboot was triggered, the exit status will record SIGHUP as the kill reason. The LXC controller has cleared all its capabilities, and the veth network devices will no longer exist at this time. Thus it cannot restart the container init process itself. Instead it emits an event which is picked up by the LXC driver in libvirtd. This will then re-create the container, using the same configuration as it was previously running with (ie it will not activate 'newDef'). Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
parent
b46b1c762a
commit
cb612ee489
@ -661,6 +661,7 @@ static int lxcControllerClearCapabilities(void)
|
||||
}
|
||||
|
||||
static bool quit = false;
|
||||
static bool wantReboot = false;
|
||||
static virMutex lock;
|
||||
|
||||
|
||||
@ -670,11 +671,15 @@ static void virLXCControllerSignalChildIO(virNetServerPtr server ATTRIBUTE_UNUSE
|
||||
{
|
||||
virLXCControllerPtr ctrl = opaque;
|
||||
int ret;
|
||||
int status;
|
||||
|
||||
ret = waitpid(-1, NULL, WNOHANG);
|
||||
ret = waitpid(-1, &status, WNOHANG);
|
||||
if (ret == ctrl->initpid) {
|
||||
virMutexLock(&lock);
|
||||
quit = true;
|
||||
if (WIFSIGNALED(status) &&
|
||||
WTERMSIG(status) == SIGHUP)
|
||||
wantReboot = true;
|
||||
virMutexUnlock(&lock);
|
||||
}
|
||||
}
|
||||
@ -998,7 +1003,7 @@ static int virLXCControllerMain(virLXCControllerPtr ctrl)
|
||||
|
||||
err = virGetLastError();
|
||||
if (!err || err->code == VIR_ERR_OK)
|
||||
rc = 0;
|
||||
rc = wantReboot ? 1 : 0;
|
||||
|
||||
cleanup:
|
||||
virMutexDestroy(&lock);
|
||||
@ -1319,6 +1324,9 @@ virLXCControllerEventSendExit(virLXCControllerPtr ctrl,
|
||||
case 0:
|
||||
msg.status = VIR_LXC_PROTOCOL_EXIT_STATUS_SHUTDOWN;
|
||||
break;
|
||||
case 1:
|
||||
msg.status = VIR_LXC_PROTOCOL_EXIT_STATUS_REBOOT;
|
||||
break;
|
||||
default:
|
||||
msg.status = VIR_LXC_PROTOCOL_EXIT_STATUS_ERROR;
|
||||
break;
|
||||
|
@ -33,6 +33,7 @@ struct _virLXCDomainObjPrivate {
|
||||
virLXCMonitorPtr monitor;
|
||||
bool doneStopEvent;
|
||||
int stopReason;
|
||||
bool wantReboot;
|
||||
};
|
||||
|
||||
void virLXCDomainSetPrivateDataHooks(virCapsPtr caps);
|
||||
|
@ -148,6 +148,58 @@ int virLXCProcessAutoDestroyRemove(virLXCDriverPtr driver,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static virConnectPtr
|
||||
virLXCProcessAutoDestroyGetConn(virLXCDriverPtr driver,
|
||||
virDomainObjPtr vm)
|
||||
{
|
||||
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
||||
virUUIDFormat(vm->def->uuid, uuidstr);
|
||||
VIR_DEBUG("vm=%s uuid=%s", vm->def->name, uuidstr);
|
||||
return virHashLookup(driver->autodestroy, uuidstr);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virLXCProcessReboot(virLXCDriverPtr driver,
|
||||
virDomainObjPtr vm)
|
||||
{
|
||||
virConnectPtr conn = virLXCProcessAutoDestroyGetConn(driver, vm);
|
||||
int reason = vm->state.reason;
|
||||
bool autodestroy = false;
|
||||
int ret = -1;
|
||||
virDomainDefPtr savedDef;
|
||||
|
||||
if (conn) {
|
||||
virConnectRef(conn);
|
||||
autodestroy = true;
|
||||
} else {
|
||||
conn = virConnectOpen("lxc:///");
|
||||
/* Ignoring NULL conn which is mostly harmless here */
|
||||
}
|
||||
|
||||
/* In a reboot scenario, we need to make sure we continue
|
||||
* to use the current 'def', and not switch to 'newDef'.
|
||||
* So temporarily hide the newDef and then reinstate it
|
||||
*/
|
||||
savedDef = vm->newDef;
|
||||
vm->newDef = NULL;
|
||||
virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
|
||||
vm->newDef = savedDef;
|
||||
if (virLXCProcessStart(conn, driver, vm, autodestroy, reason) < 0) {
|
||||
VIR_WARN("Unable to handle reboot of vm %s",
|
||||
vm->def->name);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (conn)
|
||||
virConnectClose(conn);
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* virLXCProcessCleanup:
|
||||
@ -509,17 +561,35 @@ static void virLXCProcessMonitorEOFNotify(virLXCMonitorPtr mon ATTRIBUTE_UNUSED,
|
||||
|
||||
priv = vm->privateData;
|
||||
virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
|
||||
if (!priv->doneStopEvent) {
|
||||
event = virDomainEventNewFromObj(vm,
|
||||
VIR_DOMAIN_EVENT_STOPPED,
|
||||
priv->stopReason);
|
||||
virDomainAuditStop(vm, "shutdown");
|
||||
if (!priv->wantReboot) {
|
||||
virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
|
||||
if (!priv->doneStopEvent) {
|
||||
event = virDomainEventNewFromObj(vm,
|
||||
VIR_DOMAIN_EVENT_STOPPED,
|
||||
priv->stopReason);
|
||||
virDomainAuditStop(vm, "shutdown");
|
||||
} else {
|
||||
VIR_DEBUG("Stop event has already been sent");
|
||||
}
|
||||
if (!vm->persistent) {
|
||||
virDomainRemoveInactive(&driver->domains, vm);
|
||||
vm = NULL;
|
||||
}
|
||||
} else {
|
||||
VIR_DEBUG("Stop event has already been sent");
|
||||
}
|
||||
if (!vm->persistent) {
|
||||
virDomainRemoveInactive(&driver->domains, vm);
|
||||
vm = NULL;
|
||||
int ret = virLXCProcessReboot(driver, vm);
|
||||
virDomainAuditStop(vm, "reboot");
|
||||
virDomainAuditStart(vm, "reboot", ret == 0);
|
||||
if (ret == 0) {
|
||||
event = virDomainEventRebootNewFromObj(vm);
|
||||
} else {
|
||||
event = virDomainEventNewFromObj(vm,
|
||||
VIR_DOMAIN_EVENT_STOPPED,
|
||||
priv->stopReason);
|
||||
if (!vm->persistent) {
|
||||
virDomainRemoveInactive(&driver->domains, vm);
|
||||
vm = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vm)
|
||||
@ -544,6 +614,10 @@ static void virLXCProcessMonitorExitNotify(virLXCMonitorPtr mon ATTRIBUTE_UNUSED
|
||||
case VIR_LXC_PROTOCOL_EXIT_STATUS_ERROR:
|
||||
priv->stopReason = VIR_DOMAIN_EVENT_STOPPED_FAILED;
|
||||
break;
|
||||
case VIR_LXC_PROTOCOL_EXIT_STATUS_REBOOT:
|
||||
priv->stopReason = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN;
|
||||
priv->wantReboot = true;
|
||||
break;
|
||||
default:
|
||||
priv->stopReason = VIR_DOMAIN_EVENT_STOPPED_FAILED;
|
||||
break;
|
||||
@ -1033,6 +1107,7 @@ int virLXCProcessStart(virConnectPtr conn,
|
||||
}
|
||||
|
||||
priv->stopReason = VIR_DOMAIN_EVENT_STOPPED_FAILED;
|
||||
priv->wantReboot = false;
|
||||
vm->def->id = vm->pid;
|
||||
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason);
|
||||
priv->doneStopEvent = false;
|
||||
|
@ -6,7 +6,8 @@
|
||||
|
||||
enum virLXCProtocolExitStatus {
|
||||
VIR_LXC_PROTOCOL_EXIT_STATUS_ERROR,
|
||||
VIR_LXC_PROTOCOL_EXIT_STATUS_SHUTDOWN
|
||||
VIR_LXC_PROTOCOL_EXIT_STATUS_SHUTDOWN,
|
||||
VIR_LXC_PROTOCOL_EXIT_STATUS_REBOOT
|
||||
};
|
||||
|
||||
struct virLXCProtocolExitEventMsg {
|
||||
|
Loading…
x
Reference in New Issue
Block a user