mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-27 08:05:24 +00:00
7d3b2eb58f
Introduce libxl hook and use it for start, prepare, started, stop, stopped, migrate events.
382 lines
20 KiB
XML
382 lines
20 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
<body>
|
|
<h1>Hooks for specific system management</h1>
|
|
|
|
<ul id="toc"></ul>
|
|
|
|
<h2><a name="intro">Custom event scripts</a></h2>
|
|
<p>Beginning with libvirt 0.8.0, specific events on a host system will
|
|
trigger custom scripts.</p>
|
|
<p>These custom <b>hook</b> scripts are executed when any of the following
|
|
actions occur:</p>
|
|
<ul>
|
|
<li>The libvirt daemon starts, stops, or reloads its
|
|
configuration
|
|
(<span class="since">since 0.8.0</span>)<br/><br/></li>
|
|
<li>A QEMU guest is started or stopped
|
|
(<span class="since">since 0.8.0</span>)<br/><br/></li>
|
|
<li>An LXC guest is started or stopped
|
|
(<span class="since">since 0.8.0</span>)<br/><br/></li>
|
|
<li>A libxl-handled Xen guest is started or stopped
|
|
(<span class="since">since 2.1.0</span>)<br/><br/></li>
|
|
<li>A network is started or stopped or an interface is
|
|
plugged/unplugged to/from the network
|
|
(<span class="since">since 1.2.2</span>)<br/><br/></li>
|
|
</ul>
|
|
|
|
<h2><a name="location">Script location</a></h2>
|
|
<p>The libvirt hook scripts are located in the directory
|
|
<code>$SYSCONFDIR/libvirt/hooks/</code>.</p>
|
|
<ul>
|
|
<li>In Linux distributions such as Fedora and RHEL, this is
|
|
<code>/etc/libvirt/hooks/</code>. Other Linux distributions may do
|
|
this differently.</li>
|
|
<li>If your installation of libvirt has instead been compiled from
|
|
source, it is likely to be
|
|
<code>/usr/local/etc/libvirt/hooks/</code>.</li>
|
|
</ul>
|
|
<p>To use hook scripts, you will need to create this <code>hooks</code>
|
|
directory manually, place the desired hook scripts inside, then make
|
|
them executable.</p>
|
|
<br/>
|
|
|
|
<h2><a name="names">Script names</a></h2>
|
|
<p>At present, there are five hook scripts that can be called:</p>
|
|
<ul>
|
|
<li><code>/etc/libvirt/hooks/daemon</code><br/><br/>
|
|
Executed when the libvirt daemon is started, stopped, or reloads
|
|
its configuration<br/><br/></li>
|
|
<li><code>/etc/libvirt/hooks/qemu</code><br/><br/>
|
|
Executed when a QEMU guest is started, stopped, or migrated<br/><br/></li>
|
|
<li><code>/etc/libvirt/hooks/lxc</code><br /><br/>
|
|
Executed when an LXC guest is started or stopped</li>
|
|
<li><code>/etc/libvirt/hooks/libxl</code><br/><br/>
|
|
Executed when a libxl-handled Xen guest is started, stopped, or
|
|
migrated<br/><br/></li>
|
|
<li><code>/etc/libvirt/hooks/network</code><br/><br/>
|
|
Executed when a network is started or stopped or an
|
|
interface is plugged/unplugged to/from the network</li>
|
|
</ul>
|
|
<br/>
|
|
|
|
<h2><a name="structure">Script structure</a></h2>
|
|
<p>The hook scripts are executed using standard Linux process creation
|
|
functions. Therefore, they must begin with the declaration of the
|
|
command interpreter to use.</p>
|
|
<p>For example:</p>
|
|
<pre>#!/bin/bash</pre>
|
|
<p>or:</p>
|
|
<pre>#!/usr/bin/python</pre>
|
|
<p>Other command interpreters are equally valid, as is any executable
|
|
binary, so you are welcome to use your favourite languages.</p>
|
|
<br/>
|
|
|
|
<h2><a name="arguments">Script arguments</a></h2>
|
|
<p>The hook scripts are called with specific command line arguments,
|
|
depending upon the script, and the operation being performed.</p>
|
|
<p>The guest hook scripts, qemu and lxc, are also given the <b>full</b>
|
|
XML description for the domain on their stdin. This includes items
|
|
such the UUID of the domain and its storage information, and is
|
|
intended to provide all the libvirt information the script needs.</p>
|
|
<p>For all cases, stdin of the network hook script is provided with the
|
|
full XML description of the network status in the following form:</p>
|
|
|
|
<pre><hookData>
|
|
<network>
|
|
<name>$network_name</name>
|
|
<uuid>afca425a-2c3a-420c-b2fb-dd7b4950d722</uuid>
|
|
...
|
|
</network>
|
|
</hookData></pre>
|
|
|
|
<p>In the case of an interface
|
|
being plugged/unplugged to/from the network, the network XML will be
|
|
followed with the full XML description of the domain containing the
|
|
interface that is being plugged/unplugged:</p>
|
|
|
|
<pre><hookData>
|
|
<network>
|
|
<name>$network_name</name>
|
|
<uuid>afca425a-2c3a-420c-b2fb-dd7b4950d722</uuid>
|
|
...
|
|
</network>
|
|
<domain type='$domain_type' id='$domain_id'>
|
|
<name>$domain_name</name>
|
|
<uuid>afca425a-2c3a-420c-b2fb-dd7b4950d722</uuid>
|
|
...
|
|
</domain>
|
|
</hookData></pre>
|
|
|
|
<p>Please note that this approach is different from other cases such as
|
|
<code>daemon</code>, <code>qemu</code> or <code>lxc</code> hook scripts,
|
|
because two XMLs may be passed here, while in the other cases only a single
|
|
XML is passed.</p>
|
|
|
|
<p>The command line arguments take this approach:</p>
|
|
<ol>
|
|
<li>The first argument is the name of the <b>object</b> involved in the
|
|
operation, or '-' if there is none.<br/><br/>
|
|
For example, the name of a guest being started.<br/><br/></li>
|
|
<li>The second argument is the name of the <b>operation</b> being
|
|
performed.<br/><br/>
|
|
For example, "start" if a guest is being started.<br/><br/></li>
|
|
<li>The third argument is a <b>sub-operation</b> indication, or '-' if there
|
|
is none.<br/><br/></li>
|
|
<li>The last argument is an <b>extra argument</b> string, or '-' if there is
|
|
none.</li>
|
|
</ol>
|
|
|
|
<h4><a name="arguments_specifics">Specifics</a></h4>
|
|
<p>This translates to the following specifics for each hook script:</p>
|
|
|
|
<h5><a name="daemon">/etc/libvirt/hooks/daemon</a></h5>
|
|
<ul>
|
|
<li>When the libvirt daemon is started, this script is called as:<br/>
|
|
<pre>/etc/libvirt/hooks/daemon - start - start</pre></li>
|
|
<li>When the libvirt daemon is shut down, this script is called as:<br/>
|
|
<pre>/etc/libvirt/hooks/daemon - shutdown - shutdown</pre></li>
|
|
<li>When the libvirt daemon receives the SIGHUP signal, it reloads its
|
|
configuration and triggers the hook script as:<br/>
|
|
<pre>/etc/libvirt/hooks/daemon - reload begin SIGHUP</pre></li>
|
|
</ul>
|
|
<p>Please note that when the libvirt daemon is restarted, the <i>daemon</i>
|
|
hook script is called once with the "shutdown" operation, and then once
|
|
with the "start" operation. There is no specific operation to indicate
|
|
a "restart" is occurring.</p>
|
|
|
|
<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 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
|
|
libvirt such as DRBD or missing bridges. This is called as:<br/>
|
|
<pre>/etc/libvirt/hooks/qemu 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/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
|
|
called before libvirt restores any labels:<br/>
|
|
<pre>/etc/libvirt/hooks/qemu 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/qemu guest_name release end -</pre></li>
|
|
<li><span class="since">Since 0.9.11</span>, the qemu hook script
|
|
is also called at the beginning of incoming migration. It is called
|
|
as: <pre>/etc/libvirt/hooks/qemu guest_name migrate begin -</pre>
|
|
with domain XML sent to standard input of the script. In this case,
|
|
the script acts as a filter and is supposed to modify the domain
|
|
XML and print it out on its standard output. Empty output is
|
|
identical to copying the input XML without changing it. In case the
|
|
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 1.2.9</span>, the qemu hook script is
|
|
also called when restoring a saved image either via the API or
|
|
automatically when restoring a managed save machine. It is called
|
|
as: <pre>/etc/libvirt/hooks/qemu guest_name restore begin -</pre>
|
|
with domain XML sent to standard input of the script. In this case,
|
|
the script acts as a filter and is supposed to modify the domain
|
|
XML and print it out on its standard output. Empty output is
|
|
identical to copying the input XML without changing it. In case the
|
|
script returns failure or the output XML is not valid, restore of the
|
|
image will be aborted. This hook may be used, e.g., to change
|
|
location of disk images for restored 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>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
|
|
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>
|
|
|
|
<h5><a name="libxl">/etc/libvirt/hooks/libxl</a></h5>
|
|
<ul>
|
|
<li>Before a Xen guest is started using libxl driver, the libxl hook
|
|
script is called in three locations; if any location fails, the guest
|
|
is not started. The first location, <span class="since">since
|
|
2.1.0</span>, is before libvirt performs any resource
|
|
labeling, and the hook can allocate resources not managed by
|
|
libvirt. This is called as:<br/>
|
|
<pre>/etc/libvirt/hooks/libxl guest_name prepare begin -</pre>
|
|
The second location, available <span class="since">Since
|
|
2.1.0</span>, occurs after libvirt has finished labeling
|
|
all resources, but has not yet started the guest, called as:<br/>
|
|
<pre>/etc/libvirt/hooks/libxl guest_name start begin -</pre>
|
|
The third location, <span class="since">2.1.0</span>,
|
|
occurs after the domain has successfully started up:<br/>
|
|
<pre>/etc/libvirt/hooks/libxl guest_name started begin -</pre>
|
|
</li>
|
|
<li>When a libxl-handled Xen guest is stopped, the libxl hook script
|
|
is called in two locations, to match the startup.
|
|
First, <span class="since">since 2.1.0</span>, the hook is
|
|
called before libvirt restores any labels:<br/>
|
|
<pre>/etc/libvirt/hooks/libxl guest_name stopped end -</pre>
|
|
Then, after libvirt has released all resources, the hook is
|
|
called again, <span class="since">since 2.1.0</span>, to allow
|
|
any additional resource cleanup:<br/>
|
|
<pre>/etc/libvirt/hooks/libxl guest_name release end -</pre></li>
|
|
<li><span class="since">Since 2.1.0</span>, the libxl hook script
|
|
is also called at the beginning of incoming migration. It is called
|
|
as: <pre>/etc/libvirt/hooks/libxl guest_name migrate begin -</pre>
|
|
with domain XML sent to standard input of the script. In this case,
|
|
the script acts as a filter and is supposed to modify the domain
|
|
XML and print it out on its standard output. Empty output is
|
|
identical to copying the input XML without changing it. In case the
|
|
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 2.1.0</span>, the libxl hook script
|
|
is also called when the libvirtd daemon restarts and reconnects
|
|
to previously running Xen domains. If the script fails, the
|
|
existing Xen domains will be killed off. It is called as:
|
|
<pre>/etc/libvirt/hooks/libxl guest_name reconnect begin -</pre>
|
|
</li>
|
|
</ul>
|
|
|
|
<h5><a name="network">/etc/libvirt/hooks/network</a></h5>
|
|
<ul>
|
|
<li><span class="since">Since 1.2.2</span>, before a network is started,
|
|
this script is called as:<br/>
|
|
<pre>/etc/libvirt/hooks/network network_name start begin -</pre></li>
|
|
<li>After the network is started, up ∧ running, the script is
|
|
called as:<br/>
|
|
<pre>/etc/libvirt/hooks/network network_name started begin -</pre></li>
|
|
<li>When a network is shut down, this script is called as:<br/>
|
|
<pre>/etc/libvirt/hooks/network network_name stopped end -</pre></li>
|
|
<li>Later, when network is started and there's an interface from a
|
|
domain to be plugged into the network, the hook script is called as:<br/>
|
|
<pre>/etc/libvirt/hooks/network network_name plugged begin -</pre>
|
|
Please note, that in this case, the script is passed both network and
|
|
domain XMLs on its stdin.</li>
|
|
<li>When network is updated, the hook script is called as:<br/>
|
|
<pre>/etc/libvirt/hooks/network network_name updated begin -</pre></li>
|
|
<li>When the domain from previous case is shutting down, the interface
|
|
is unplugged. This leads to another script invocation:<br/>
|
|
<pre>/etc/libvirt/hooks/network network_name unplugged begin -</pre>
|
|
And again, as in previous case, both network and domain XMLs are passed
|
|
onto script's stdin.</li>
|
|
</ul>
|
|
|
|
<br/>
|
|
|
|
<h2><a name="execution">Script execution</a></h2>
|
|
<ul>
|
|
<li>The "start" operation for the guest and network hook scripts,
|
|
executes <b>prior</b> to the object (guest or network) being created.
|
|
This allows the object start operation to be aborted if the script
|
|
returns indicating failure.<br/><br/></li>
|
|
<li>The "shutdown" operation for the guest and network hook scripts,
|
|
executes <b>after</b> the object (guest or network) has stopped. If
|
|
the hook script indicates failure in its return, the shut down of the
|
|
object cannot be aborted because it has already been performed.
|
|
<br/><br/></li>
|
|
<li>Hook scripts execute in a synchronous fashion. Libvirt waits
|
|
for them to return before continuing the given operation.<br/><br/>
|
|
This is most noticeable with the guest or network start operation,
|
|
as a lengthy operation in the hook script can mean an extended wait
|
|
for the guest or network to be available to end users.<br/><br/></li>
|
|
<li>For a hook script to be utilised, it must have its execute bit set
|
|
(e.g. chmod o+rx <i>qemu</i>), and must be present when the libvirt
|
|
daemon is started.<br/><br/></li>
|
|
<li>If a hook script is added to a host after the libvirt daemon is
|
|
already running, it won't be used until the libvirt daemon
|
|
next starts.</li>
|
|
</ul>
|
|
<br/>
|
|
|
|
<h2><a name="qemu_migration">QEMU guest migration</a></h2>
|
|
<p>Migration of a QEMU guest involves running hook scripts on both the
|
|
source and destination hosts:</p>
|
|
<ol>
|
|
<li>At the beginning of the migration, the <i>qemu</i> hook script on
|
|
the <b>destination</b> host is executed with the "migrate"
|
|
operation.</li>
|
|
<li>Before QEMU process is spawned, the two operations ("prepare" and
|
|
"start") called for domain start are executed on
|
|
<b>destination</b> host.</li>
|
|
<li>If both of these hook script executions exit successfully (exit
|
|
status 0), the migration continues. Any other exit code indicates
|
|
failure, and the migration is aborted.</li>
|
|
<li>The QEMU guest is then migrated to the destination host.</li>
|
|
<li>Unless an error occurs during the migration process, the <i>qemu</i>
|
|
hook script on the <b>source</b> host is then executed with the
|
|
"stopped" and "release" operations to indicate it is no longer
|
|
running on this host. Regardless of the return codes, the
|
|
migration is not aborted as it has already been performed.</li>
|
|
</ol>
|
|
<br/>
|
|
|
|
<h2><a name="recursive">Calling libvirt functions from within a hook script</a></h2>
|
|
<p><b>DO NOT DO THIS!</b></p>
|
|
<p>A hook script must not call back into libvirt, as the libvirt daemon
|
|
is already waiting for the script to exit.</p>
|
|
<p>A deadlock is likely to occur.</p>
|
|
<br/>
|
|
|
|
<h2><a name="return_codes">Return codes and logging</a></h2>
|
|
<p>If a hook script returns with an exit code of 0, the libvirt daemon
|
|
regards this as successful and performs no logging of it.</p>
|
|
<p>However, if a hook script returns with a non zero exit code, the libvirt
|
|
daemon regards this as a failure, logs its return code, and
|
|
additionally logs anything on stderr the hook script returns.</p>
|
|
<p>For example, a hook script might use this code to indicate failure,
|
|
and send a text string to stderr:</p>
|
|
<pre>echo "Could not find required XYZZY" >&2
|
|
exit 1</pre>
|
|
<p>The resulting entry in the libvirt log will appear as:</p>
|
|
<pre>20:02:40.297: error : virHookCall:285 : Hook script execution failed: internal error Child process (LC_ALL=C PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
|
HOME=/root USER=root LOGNAME=root /etc/libvirt/hooks/qemu qemu prepare begin -) unexpected exit status 1: Could not find required XYZZY</pre>
|
|
</body>
|
|
</html>
|