]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Add some missing hook functions
authorDaniel P. Berrange <berrange@redhat.com>
Mon, 28 May 2012 14:04:31 +0000 (15:04 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Wed, 13 Jun 2012 17:23:00 +0000 (18:23 +0100)
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
src/lxc/lxc_driver.c
src/qemu/qemu_process.c
src/util/hooks.c
src/util/hooks.h

index ab16db217758ee248efa03f3422a47379aa63974..5f9963dee32a04bc2a5fbc5d5e9d67665166a273 100644 (file)
     <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/>
 
index 919f4abeeb1b6ced63a92e6d3a57a14316709a41..1b91a6d99d9ca00a576337d8b66e3168238a9811 100644 (file)
@@ -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);
index 5f3aa99db6af58cd480b38a2e23468a3c6b00e52..544eed5838bcc89fa91b4b4e83e056075413ac0c 100644 (file)
@@ -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);
 
index ce60b43b9011a515952ce6bb8f31bf185cb7d84f..f89a40ffbe08cf92e406e0f6030203c031284ab3 100644 (file)
@@ -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;
 
index 7fd29f6cb1465ff4572a680a3250c8244b3c2adc..1af7c04f5825452ddd1950b6eefb18f2a18fc910 100644 (file)
@@ -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,
 };