[libvirt] [PATCH] Add some missing hook functions

Daniel P. Berrange berrange at redhat.com
Mon May 28 14:20:12 UTC 2012


From: "Daniel P. Berrange" <berrange at redhat.com>

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 ab16db2..2d64d42 100644
--- a/docs/hooks.html.in
+++ b/docs/hooks.html.in
@@ -101,7 +101,7 @@
     <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 either 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
@@ -110,7 +110,11 @@
         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
@@ -130,15 +134,51 @@
         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 either 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/>
 
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 9aea556..0669c17 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 58ba5bf..b79944f 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;
 
@@ -3747,6 +3764,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);
 
@@ -4255,6 +4289,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 ce60b43..f89a40f 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 7fd29f6..1af7c04 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,
 };
-- 
1.7.10.1




More information about the libvir-list mailing list