<h5><a name="qemu">/etc/libvirt/hooks/qemu</a></h5>
<ul>
<li>Before a QEMU guest is started, the qemu hook script is
- called in two locations; if either location fails, the guest
+ called in three locations; if any location fails, the guest
is not started. The first location, <span class="since">since
0.9.0</span>, is before libvirt performs any resource
labeling, and the hook can allocate resources not managed by
The second location, available <span class="since">Since
0.8.0</span>, occurs after libvirt has finished labeling
all resources, but has not yet started the guest, called as:<br/>
- <pre>/etc/libvirt/hooks/qemu guest_name start begin -</pre></li>
+ <pre>/etc/libvirt/hooks/qemu guest_name start begin -</pre>
+ The third location, <span class="since">0.9.13</span>,
+ occurs after the QEMU process has successfully started up:<br/>
+ <pre>/etc/libvirt/hooks/qemu guest_name started begin -</pre>
+ </li>
<li>When a QEMU guest is stopped, the qemu hook script is called
in two locations, to match the startup.
First, <span class="since">since 0.8.0</span>, the hook is
script returns failure or the output XML is not valid, incoming
migration will be canceled. This hook may be used, e.g., to change
location of disk images for incoming domains.</li>
+ <li><span class="since">Since 0.9.13</span>, the qemu hook script
+ is also called when the libvirtd daemon restarts and reconnects
+ to previously running QEMU processes. If the script fails, the
+ existing QEMU process will be killed off. It is called as:
+ <pre>/etc/libvirt/hooks/qemu guest_name reconnect begin -</pre>
+ </li>
+ <li><span class="since">Since 0.9.13</span>, the qemu hook script
+ is also called when the QEMU driver is told to attach to an
+ externally launched QEMU process. It is called as:
+ <pre>/etc/libvirt/hooks/qemu guest_name attach begin -</pre>
+ </li>
</ul>
<h5><a name="lxc">/etc/libvirt/hooks/lxc</a></h5>
<ul>
- <li>When an LXC guest is started, the lxc hook script is called as:<br/>
- <pre>/etc/libvirt/hooks/lxc guest_name start begin -</pre></li>
+ <li>Before a LXC guest is started, the lxc hook script is
+ called in three locations; if any location fails, the guest
+ is not started. The first location, <span class="since">since
+ 0.9.13</span>, is before libvirt performs any resource
+ labeling, and the hook can allocate resources not managed by
+ libvirt such as DRBD or missing bridges. This is called as:<br/>
+ <pre>/etc/libvirt/hooks/lxc guest_name prepare begin -</pre>
+ The second location, available <span class="since">Since
+ 0.8.0</span>, occurs after libvirt has finished labeling
+ all resources, but has not yet started the guest, called as:<br/>
+ <pre>/etc/libvirt/hooks/lxc guest_name start begin -</pre>
+ The third location, <span class="since">0.9.13</span>,
+ occurs after the LXC process has successfully started up:<br/>
+ <pre>/etc/libvirt/hooks/lxc guest_name started begin -</pre>
+ </li>
<li>When a LXC guest is stopped, the lxc hook script is called
- as:<br/>
- <pre>/etc/libvirt/hooks/lxc guest_name stopped end -</pre></li>
+ in two locations, to match the startup.
+ First, <span class="since">since 0.8.0</span>, the hook is
+ called before libvirt restores any labels:<br/>
+ <pre>/etc/libvirt/hooks/lxc guest_name stopped end -</pre>
+ Then, after libvirt has released all resources, the hook is
+ called again, <span class="since">since 0.9.0</span>, to allow
+ any additional resource cleanup:<br/>
+ <pre>/etc/libvirt/hooks/lxc guest_name release end -</pre></li>
+ <li><span class="since">Since 0.9.13</span>, the lxc hook script
+ is also called when the libvirtd daemon restarts and reconnects
+ to previously running LXC processes. If the script fails, the
+ existing LXC process will be killed off. It is called as:
+ <pre>/etc/libvirt/hooks/lxc guest_name reconnect begin -</pre>
+ </li>
</ul>
<br/>
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;
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;
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.
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();
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:
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);
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;
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);
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);
"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;
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,
};
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,
};