From 6510c97bf5920044355d22646a91fb0a8fb9bf68 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 28 May 2012 15:04:31 +0100 Subject: [PATCH] Add some missing hook functions A core use case of the hook scripts is to be able to do things to a guest's network configuration. It is possible to hook into the 'start' operation for a QEMU guest which runs just before the guest is started. The TAP devices will exist at this point, but the QEMU process will not. It can be desirable to have a 'started' hook too, which runs once QEMU has started. If libvirtd is restarted it will re-populate firewall rules, but there is no QEMU hook to trigger for existing domains. This is solved with a 'reconnect' hook. Finally, if attaching to an external QEMU process there needs to be an 'attach' hook script. This all also applies to the LXC driver * docs/hooks.html.in: Document new operations * src/util/hooks.c, src/util/hooks.c: Add 'started', 'reconnect' and 'attach' operations for QEMU. Add 'prepare', 'started', 'release' and 'reconnect' operations for LXC * src/lxc/lxc_driver.c: Add hooks for 'prepare', 'started', 'release' and 'reconnect' operations * src/qemu/qemu_process.c: Add hooks for 'started', 'reconnect' and 'reconnect' operations --- docs/hooks.html.in | 52 ++++++++++++++++++++--- src/lxc/lxc_driver.c | 94 +++++++++++++++++++++++++++++++++-------- src/qemu/qemu_process.c | 51 ++++++++++++++++++++++ src/util/hooks.c | 11 ++++- src/util/hooks.h | 7 +++ 5 files changed, 190 insertions(+), 25 deletions(-) diff --git a/docs/hooks.html.in b/docs/hooks.html.in index ab16db2177..5f9963dee3 100644 --- a/docs/hooks.html.in +++ b/docs/hooks.html.in @@ -101,7 +101,7 @@
/etc/libvirt/hooks/qemu
/etc/libvirt/hooks/lxc

diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 919f4abeeb..1b91a6d99d 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -1152,6 +1152,17 @@ static void lxcVmCleanup(lxc_driver_t *driver, virCgroupFree(&cgroup); } + /* now that we know it's stopped call the hook if present */ + if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { + char *xml = virDomainDefFormat(vm->def, 0); + + /* we can't stop the operation even if the script raised an error */ + virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, + VIR_HOOK_LXC_OP_RELEASE, VIR_HOOK_SUBOP_END, + NULL, xml, NULL); + VIR_FREE(xml); + } + if (vm->newDef) { virDomainDefFree(vm->def); vm->def = vm->newDef; @@ -1625,23 +1636,6 @@ lxcBuildControllerCmd(lxc_driver_t *driver, virCommandAddArgList(cmd, "--veth", veths[i], NULL); } - /* now that we know it is about to start call the hook if present */ - if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { - char *xml = virDomainDefFormat(vm->def, 0); - int hookret; - - hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, - VIR_HOOK_LXC_OP_START, VIR_HOOK_SUBOP_BEGIN, - NULL, xml, NULL); - VIR_FREE(xml); - - /* - * If the script raised an error abort the launch - */ - if (hookret < 0) - goto cleanup; - } - virCommandPreserveFD(cmd, handshakefd); return cmd; @@ -1803,6 +1797,23 @@ static int lxcVmStart(virConnectPtr conn, if (virDomainObjSetDefTransient(driver->caps, vm, true) < 0) goto cleanup; + /* Run an early hook to set-up missing devices */ + if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { + char *xml = virDomainDefFormat(vm->def, 0); + int hookret; + + hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, + VIR_HOOK_LXC_OP_PREPARE, VIR_HOOK_SUBOP_BEGIN, + NULL, xml, NULL); + VIR_FREE(xml); + + /* + * If the script raised an error abort the launch + */ + if (hookret < 0) + goto cleanup; + } + /* Here we open all the PTYs we need on the host OS side. * The LXC controller will open the guest OS side PTYs * and forward I/O between them. @@ -1887,6 +1898,23 @@ static int lxcVmStart(virConnectPtr conn, virCommandSetOutputFD(cmd, &logfd); virCommandSetErrorFD(cmd, &logfd); + /* now that we know it is about to start call the hook if present */ + if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { + char *xml = virDomainDefFormat(vm->def, 0); + int hookret; + + hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, + VIR_HOOK_LXC_OP_START, VIR_HOOK_SUBOP_BEGIN, + NULL, xml, NULL); + VIR_FREE(xml); + + /* + * If the script raised an error abort the launch + */ + if (hookret < 0) + goto cleanup; + } + /* Log timestamp */ if ((timestamp = virTimeStringNow()) == NULL) { virReportOOMError(); @@ -1965,6 +1993,23 @@ static int lxcVmStart(virConnectPtr conn, if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) goto error; + /* finally we can call the 'started' hook script if any */ + if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { + char *xml = virDomainDefFormat(vm->def, 0); + int hookret; + + hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, + VIR_HOOK_LXC_OP_STARTED, VIR_HOOK_SUBOP_BEGIN, + NULL, xml, NULL); + VIR_FREE(xml); + + /* + * If the script raised an error abort the launch + */ + if (hookret < 0) + goto error; + } + rc = 0; cleanup: @@ -2512,6 +2557,21 @@ lxcReconnectVM(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque) if (virSecurityManagerReserveLabel(driver->securityManager, vm->def, vm->pid) < 0) goto error; + + /* now that we know it's reconnected call the hook if present */ + if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { + char *xml = virDomainDefFormat(vm->def, 0); + int hookret; + + /* we can't stop the operation even if the script raised an error */ + hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, + VIR_HOOK_LXC_OP_RECONNECT, VIR_HOOK_SUBOP_BEGIN, + NULL, xml, NULL); + VIR_FREE(xml); + if (hookret < 0) + goto error; + } + } else { vm->def->id = -1; VIR_FORCE_CLOSE(priv->monitor); diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 5f3aa99db6..544eed5838 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3108,6 +3108,23 @@ qemuProcessReconnect(void *opaque) if (virDomainSaveStatus(driver->caps, driver->stateDir, obj) < 0) goto error; + /* Run an hook to allow admins to do some magic */ + if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) { + char *xml = qemuDomainDefFormatXML(driver, obj->def, 0, false); + int hookret; + + hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, obj->def->name, + VIR_HOOK_QEMU_OP_RECONNECT, VIR_HOOK_SUBOP_BEGIN, + NULL, xml, NULL); + VIR_FREE(xml); + + /* + * If the script raised an error abort the launch + */ + if (hookret < 0) + goto error; + } + if (obj->def->id >= driver->nextvmid) driver->nextvmid = obj->def->id + 1; @@ -3770,6 +3787,23 @@ int qemuProcessStart(virConnectPtr conn, if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) goto cleanup; + /* finally we can call the 'started' hook script if any */ + if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) { + char *xml = qemuDomainDefFormatXML(driver, vm->def, 0, false); + int hookret; + + hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, vm->def->name, + VIR_HOOK_QEMU_OP_STARTED, VIR_HOOK_SUBOP_BEGIN, + NULL, xml, NULL); + VIR_FREE(xml); + + /* + * If the script raised an error abort the launch + */ + if (hookret < 0) + goto cleanup; + } + virCommandFree(cmd); VIR_FORCE_CLOSE(logfile); @@ -4280,6 +4314,23 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED, if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) goto cleanup; + /* Run an hook to allow admins to do some magic */ + if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) { + char *xml = qemuDomainDefFormatXML(driver, vm->def, 0, false); + int hookret; + + hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, vm->def->name, + VIR_HOOK_QEMU_OP_ATTACH, VIR_HOOK_SUBOP_BEGIN, + NULL, xml, NULL); + VIR_FREE(xml); + + /* + * If the script raised an error abort the launch + */ + if (hookret < 0) + goto cleanup; + } + VIR_FORCE_CLOSE(logfile); VIR_FREE(seclabel); diff --git a/src/util/hooks.c b/src/util/hooks.c index ce60b43b90..f89a40ffbe 100644 --- a/src/util/hooks.c +++ b/src/util/hooks.c @@ -74,11 +74,18 @@ VIR_ENUM_IMPL(virHookQemuOp, VIR_HOOK_QEMU_OP_LAST, "stopped", "prepare", "release", - "migrate") + "migrate", + "started", + "reconnect", + "attach") VIR_ENUM_IMPL(virHookLxcOp, VIR_HOOK_LXC_OP_LAST, "start", - "stopped") + "stopped", + "prepare", + "release", + "started", + "reconnect") static int virHooksFound = -1; diff --git a/src/util/hooks.h b/src/util/hooks.h index 7fd29f6cb1..1af7c04f58 100644 --- a/src/util/hooks.h +++ b/src/util/hooks.h @@ -57,6 +57,9 @@ enum virHookQemuOpType { VIR_HOOK_QEMU_OP_PREPARE, /* domain startup initiated */ VIR_HOOK_QEMU_OP_RELEASE, /* domain destruction is over */ VIR_HOOK_QEMU_OP_MIGRATE, /* domain is being migrated */ + VIR_HOOK_QEMU_OP_STARTED, /* domain has started */ + VIR_HOOK_QEMU_OP_RECONNECT, /* domain is being reconnected by libvirt */ + VIR_HOOK_QEMU_OP_ATTACH, /* domain is being attached to be libvirt */ VIR_HOOK_QEMU_OP_LAST, }; @@ -64,6 +67,10 @@ enum virHookQemuOpType { enum virHookLxcOpType { VIR_HOOK_LXC_OP_START, /* domain is about to start */ VIR_HOOK_LXC_OP_STOPPED, /* domain has stopped */ + VIR_HOOK_LXC_OP_PREPARE, /* domain startup initiated */ + VIR_HOOK_LXC_OP_RELEASE, /* domain destruction is over */ + VIR_HOOK_LXC_OP_STARTED, /* domain has started */ + VIR_HOOK_LXC_OP_RECONNECT, /* domain is being reconnected by libvirt */ VIR_HOOK_LXC_OP_LAST, };