From nobody Mon Feb 9 11:05:53 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) client-ip=170.10.129.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1648469609; cv=none; d=zohomail.com; s=zohoarc; b=OXUt8oUjpOn2We/VqyHZzhtfduKEOZEp54LX83vWh1Po+WQKzstSLJuT7bzOqMf/C39KVNJcprgk+J0YKUYvs9Tiy1PEeloFYKjAb5IUzuFYsw32AogWWujGi5cUBmOtKHazEfVSHb7T7zHCk7bVEshMpLehNIZPaD0ffmyj8Ww= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1648469609; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=rDqedhhYlvjNJcPnvzE75CuvBQFlHKwE8gdYFaYNbks=; b=CRtdr/QeKzksIx7Ah1XSHoooiGe838WnkasYOvTqNZD8xDiPeDr3o1tlItxL0D2Zy23BBuYVYYicvS7hk1gvuQG7Hcxpa6AZq1qJXjWW1QuzXSdZ16UD4tbbqFFz6YChHqOP3efVVTSHFmW6R9ye4ozF7eGMqxn1XAKorXsThI8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by mx.zohomail.com with SMTPS id 1648469609774604.5584743680308; Mon, 28 Mar 2022 05:13:29 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-648-pfCdexMsOiC2dAp-7YyBXQ-1; Mon, 28 Mar 2022 08:11:15 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 4C816802819; Mon, 28 Mar 2022 12:11:13 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 304AD40149AC; Mon, 28 Mar 2022 12:11:13 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id BEAE91940353; Mon, 28 Mar 2022 12:11:12 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id C991B1947BBE for ; Mon, 28 Mar 2022 12:11:11 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id ABAC21410F3B; Mon, 28 Mar 2022 12:11:11 +0000 (UTC) Received: from speedmetal.lan (unknown [10.40.208.35]) by smtp.corp.redhat.com (Postfix) with ESMTP id E95CF1400B19 for ; Mon, 28 Mar 2022 12:11:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1648469608; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=rDqedhhYlvjNJcPnvzE75CuvBQFlHKwE8gdYFaYNbks=; b=e1jriLRvTTFCWHPkbbl5O2FLySwvkoXpkJE0UKH5et+N/YQ6CJoF9fBuHTa6RQqJjBDpS9 yuNls/C8/sORucHCozBqTFw4t7AwrD9XaKZ/8iQpfpV0L654JMkX0LigCsU+hJ4fwZEFCv oFl4c+lFldBGz4OdNUFNYlGuClnppls= X-MC-Unique: pfCdexMsOiC2dAp-7YyBXQ-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 25/29] docs: Convert 'hooks' page to rST Date: Mon, 28 Mar 2022 14:10:40 +0200 Message-Id: <4a7401d0bf2a9e72d5e47d402b632b7d131155ba.1648469356.git.pkrempa@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.7 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.84 on 10.11.54.2 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1648469611635100001 Content-Type: text/plain; charset="utf-8"; x-default="true" Signed-off-by: Peter Krempa Reviewed-by: Erik Skultety --- docs/hooks.html.in | 406 ----------------------------------- docs/hooks.rst | 518 +++++++++++++++++++++++++++++++++++++++++++++ docs/meson.build | 2 +- 3 files changed, 519 insertions(+), 407 deletions(-) delete mode 100644 docs/hooks.html.in create mode 100644 docs/hooks.rst diff --git a/docs/hooks.html.in b/docs/hooks.html.in deleted file mode 100644 index bbbc414dc4..0000000000 --- a/docs/hooks.html.in +++ /dev/null @@ -1,406 +0,0 @@ - - - - -

Hooks for specific system management

- -
    - -

    Custom event scripts

    -

    Beginning with libvirt 0.8.0, specific events on a host system will - trigger custom scripts.

    -

    These custom hook scripts are executed when any of the follo= wing - actions occur:

    -
      -
    • The libvirt daemon starts, stops, or reloads its - configuration - (since 0.8.0)

    • -
    • A QEMU guest is started or stopped - (since 0.8.0)

    • -
    • An LXC guest is started or stopped - (since 0.8.0)

    • -
    • A libxl-handled Xen guest is started or stopped - (since 2.1.0)

    • -
    • A network is started or stopped or an interface is - plugged/unplugged to/from the network - (since 1.2.2)

    • -
    - -

    Script location

    -

    The libvirt hook scripts are located in the directory - $SYSCONFDIR/libvirt/hooks/.

    -
      -
    • In Linux distributions such as Fedora and RHEL, this is - /etc/libvirt/hooks/. Other Linux distributions may= do - this differently.
    • -
    • If your installation of libvirt has instead been compiled from - source, it is likely to be - /usr/local/etc/libvirt/hooks/.
    • -
    • Since 6.5.0, you can also place sev= eral - hook scripts in the directories - /etc/libvirt/hooks/<driver>.d/.
    • -
    -

    To use hook scripts, you will need to create this hooks - directory manually, place the desired hook scripts inside, then make - them executable.

    -
    - -

    Script names

    -

    At present, there are five hook scripts that can be called:

    -
      -
    • /etc/libvirt/hooks/daemon

      - Executed when the libvirt daemon is started, stopped, or reloads - its configuration

    • -
    • /etc/libvirt/hooks/qemu

      - Executed when a QEMU guest is started, stopped, or migrated
      =
    • -
    • /etc/libvirt/hooks/lxc

      - Executed when an LXC guest is started or stopped
    • -
    • /etc/libvirt/hooks/libxl

      - Executed when a libxl-handled Xen guest is started, stopped, or - migrated

    • -
    • /etc/libvirt/hooks/network

      - Executed when a network is started or stopped or an - interface is plugged/unplugged to/from the network
    • -
    -

    Since 6.5.0, you can also have - several scripts with any name in the directories - /etc/libvirt/hooks/<driver>.d/. They are - executed in alphabetical order after main script.

    -
    - -

    Script structure

    -

    The hook scripts are executed using standard Linux process creation - functions. Therefore, they must begin with the declaration of the - command interpreter to use.

    -

    For example:

    -
    #!/bin/bash
    -

    or:

    -
    #!/usr/bin/python
    -

    Other command interpreters are equally valid, as is any executable - binary, so you are welcome to use your favourite languages.

    -
    - -

    Script arguments

    -

    The hook scripts are called with specific command line arguments, - depending upon the script, and the operation being performed.

    -

    The guest hook scripts, qemu and lxc, are also given the full - 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. -

    For all cases, stdin of the network hook script is provided with the - full XML description of the network status in the following form: - -

    <hookData>
    -  <network>
    -     <name>$network_name</name>
    -     <uuid>afca425a-2c3a-420c-b2fb-dd7b4950d722</uuid>
    -     ...
    -  </network>
    -</hookData>
    - -

    In the case of an network port being created / deleted, the network - XML will be followed with the full XML description of the port:

    - -
    <hookData>
    -  <network>
    -     <name>$network_name</name>
    -     <uuid>afca425a-2c3a-420c-b2fb-dd7b4950d722</uuid>
    -     ...
    -  </network>
    -  <networkport>
    -    <uuid>5d744f21-ba4a-4d6e-bdb2-30a35ff3207d</uuid>
    -    ...
    -    <plug type=3D'direct' dev=3D'ens3' mode=3D'vepa'/>
    -  </networkport>
    -</hookData>
    - -

    Please note that this approach is different from other cases such as - daemon, qemu or lxc hook scr= ipts, - because two XMLs may be passed here, while in the other cases only = a single - XML is passed.

    - -

    The command line arguments take this approach:

    -
      -
    1. The first argument is the name of the object involved in = the - operation, or '-' if there is none.

      - For example, the name of a guest being started.

    2. -
    3. The second argument is the name of the operation being - performed.

      - For example, "start" if a guest is being started.

    4. -
    5. The third argument is a sub-operation indication, or '-' = if there - is none.

    6. -
    7. The last argument is an extra argument string, or '-' if = there is - none.
    8. -
    - -

    Specifics

    -

    This translates to the following specifics for each hook script:

    - -
    /etc/libvirt/hooks/daemon
    -
      -
    • When the libvirt daemon is started, this script is called as: -
      /etc/libvirt/hooks/daemon - start - start
    • -
    • When the libvirt daemon is shut down, this script is called as:<= br/> -
      /etc/libvirt/hooks/daemon - shutdown - shutdown
    • -
    • When the libvirt daemon receives the SIGHUP signal, it reloads i= ts - configuration and triggers the hook script as:
      -
      /etc/libvirt/hooks/daemon - reload begin SIGHUP
    • -
    -

    Please note that when the libvirt daemon is restarted, the daemo= n - hook script is called once with the "shutdown" operation, and then = once - with the "start" operation. There is no specific operation to indi= cate - a "restart" is occurring.

    - -
    /etc/libvirt/hooks/qemu
    -
      -
    • 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, since - 0.9.0, 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:
      -
      /etc/libvirt/hooks/qemu guest_name prepare begin -
      - The second location, available Since - 0.8.0, occurs after libvirt has finished labeling - all resources, but has not yet started the guest, called as:
      -
      /etc/libvirt/hooks/qemu guest_name start begin -
      - The third location, 0.9.13, - occurs after the QEMU process has successfully started up:
      -
      /etc/libvirt/hooks/qemu guest_name started begin -
      -
    • -
    • When a QEMU guest is stopped, the qemu hook script is called - in two locations, to match the startup. - First, since 0.8.0, the hook is - called before libvirt restores any labels:
      -
      /etc/libvirt/hooks/qemu guest_name stopped end -
      - Then, after libvirt has released all resources, the hook is - called again, since 0.9.0, to allow - any additional resource cleanup:
      -
      /etc/libvirt/hooks/qemu guest_name release end -
    • -
    • Since 0.9.11, the qemu hook script - is also called at the beginning of incoming migration. It is called - as:
      /etc/libvirt/hooks/qemu guest_name migrate begin -
      - 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.
    • -
    • Since 1.2.9, 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:
      /etc/libvirt/hooks/qemu guest_name restore begin -
      - 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.
    • -
    • Since 6.5.0, you can also place sev= eral - hook scripts in the directory - /etc/libvirt/hooks/qemu.d/. They are executed in - alphabetical order after main script. In this case each script also - acts as filter and can modify the domain XML and print it out on - its standard output. This script output is passed to standard input - next script in order. Empty output from any script is also identic= al - to copying the input XML without changing it. - In case any script returns failure common process will be aborted, - but all scripts from the directory will are executed.
    • -
    • Since 0.9.13, 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: -
      /etc/libvirt/hooks/qemu guest_name reconnect begin -
      -
    • -
    • Since 0.9.13, 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: -
      /etc/libvirt/hooks/qemu guest_name attach begin -
      -
    • -
    - -
    /etc/libvirt/hooks/lxc
    -
      -
    • 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, since - 0.9.13, 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:
      -
      /etc/libvirt/hooks/lxc guest_name prepare begin -
      - The second location, available Since - 0.8.0, occurs after libvirt has finished labeling - all resources, but has not yet started the guest, called as:
      -
      /etc/libvirt/hooks/lxc guest_name start begin -
      - The third location, 0.9.13, - occurs after the LXC process has successfully started up:
      -
      /etc/libvirt/hooks/lxc guest_name started begin -
      -
    • -
    • When a LXC guest is stopped, the lxc hook script is called - in two locations, to match the startup. - First, since 0.8.0, the hook is - called before libvirt restores any labels:
      -
      /etc/libvirt/hooks/lxc guest_name stopped end -
      - Then, after libvirt has released all resources, the hook is - called again, since 0.9.0, to allow - any additional resource cleanup:
      -
      /etc/libvirt/hooks/lxc guest_name release end -
    • -
    • Since 0.9.13, 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: -
      /etc/libvirt/hooks/lxc guest_name reconnect begin -
      -
    • -
    - -
    /etc/libvirt/hooks/libxl
    -
      -
    • Before a Xen guest is started using libxl driver, the libxl hook - script is called in three locations; if any location fails, the gu= est - is not started. The first location, since - 2.1.0, is before libvirt performs any resource - labeling, and the hook can allocate resources not managed by - libvirt. This is called as:
      -
      /etc/libvirt/hooks/libxl guest_name prepare begin -
      - The second location, available Since - 2.1.0, occurs after libvirt has finished labeling - all resources, but has not yet started the guest, called as:
      -
      /etc/libvirt/hooks/libxl guest_name start begin -
      - The third location, 2.1.0, - occurs after the domain has successfully started up:
      -
      /etc/libvirt/hooks/libxl guest_name started begin -
      -
    • -
    • When a libxl-handled Xen guest is stopped, the libxl hook script - is called in two locations, to match the startup. - First, since 2.1.0, the hook is - called before libvirt restores any labels:
      -
      /etc/libvirt/hooks/libxl guest_name stopped end -
      - Then, after libvirt has released all resources, the hook is - called again, since 2.1.0, to allow - any additional resource cleanup:
      -
      /etc/libvirt/hooks/libxl guest_name release end -
    • -
    • Since 2.1.0, the libxl hook script - is also called at the beginning of incoming migration. It is called - as:
      /etc/libvirt/hooks/libxl guest_name migrate begin -
      - 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.
    • -
    • Since 6.5.0, you can also place sev= eral - hook scripts in the directory - /etc/libvirt/hooks/libxl.d/. They are executed in - alphabetical order after main script. In this case each script also - acts as filter and can modify the domain XML and print it out on - its standard output. This script output is passed to standard input - next script in order. Empty output from any script is also identic= al - to copying the input XML without changing it. - In case any script returns failure common process will be aborted, - but all scripts from the directory will are executed.
    • -
    • Since 2.1.0, 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: -
      /etc/libvirt/hooks/libxl guest_name reconnect begin -
      -
    • -
    - -
    /etc/libvirt/hooks/network
    -
      -
    • Since 1.2.2, before a network is st= arted, - this script is called as:
      -
      /etc/libvirt/hooks/network network_name start begin -
      =
    • -
    • After the network is started, up & running, the script is - called as:
      -
      /etc/libvirt/hooks/network network_name started begin -
    • -
    • When a network is shut down, this script is called as:
      -
      /etc/libvirt/hooks/network network_name stopped end -
      =
    • -
    • Later, when network is started and there's an interface from a - domain to be plugged into the network, the hook script is called a= s:
      -
      /etc/libvirt/hooks/network network_name port-created begin =
      -
      - Please note, that in this case, the script is passed both network = and - port XMLs on its stdin.
    • -
    • When network is updated, the hook script is called as:
      -
      /etc/libvirt/hooks/network network_name updated begin -
    • -
    • When the domain from previous case is shutting down, the interfa= ce - is unplugged. This leads to another script invocation:
      -
      /etc/libvirt/hooks/network network_name port-deleted begin =
      -
      - And again, as in previous case, both network and port XMLs are pas= sed - onto script's stdin.
    • -
    - -
    - -

    Script execution

    -
      -
    • The "start" operation for the guest and network hook scripts, - executes prior to the object (guest or network) being cre= ated. - This allows the object start operation to be aborted if the scri= pt - returns indicating failure.

    • -
    • The "stopped" operation for the guest and network hook scripts, - executes after the object (guest or network) has stopped.= If - the hook script indicates failure in its return, the shut down o= f the - object cannot be aborted because it has already been performed. -

    • -
    • Hook scripts execute in a synchronous fashion. Libvirt waits - for them to return before continuing the given operation.
      - This is most noticeable with the guest or network start operatio= n, - as a lengthy operation in the hook script can mean an extended w= ait - for the guest or network to be available to end users.

      =
    • -
    • For a hook script to be utilised, it must have its execute bit s= et - (e.g. chmod o+rx qemu), and must be present when the libv= irt - daemon is started.

    • -
    • 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.
    • -
    -
    - -

    QEMU guest migration

    -

    Migration of a QEMU guest involves running hook scripts on both the - source and destination hosts:

    -
      -
    1. At the beginning of the migration, the qemu hook script on - the destination host is executed with the "migrate" - operation.
    2. -
    3. Before QEMU process is spawned, the two operations ("prepare" and - "start") called for domain start are executed on - destination host.
    4. -
    5. If both of these hook script executions exit successfully (exit - status 0), the migration continues. Any other exit code indicat= es - failure, and the migration is aborted.
    6. -
    7. The QEMU guest is then migrated to the destination host.
    8. -
    9. Unless an error occurs during the migration process, the qemu= - hook script on the source 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.
    10. -
    -
    - -

    Calling libvirt functions from within a hook s= cript

    -

    DO NOT DO THIS!

    -

    A hook script must not call back into libvirt, as the libvirt daemon - is already waiting for the script to exit.

    -

    A deadlock is likely to occur.

    -
    - -

    Return codes and logging

    -

    If a hook script returns with an exit code of 0, the libvirt daemon - regards this as successful and performs no logging of it.

    -

    However, if a hook script returns with a non zero exit code, the li= bvirt - daemon regards this as a failure, logs its return code, and - additionally logs anything on stderr the hook script returns.

    -

    For example, a hook script might use this code to indicate failure, - and send a text string to stderr:

    -
    echo "Could not find required XYZZY" >&2
    -exit 1
    -

    The resulting entry in the libvirt log will appear as:

    -
    20:02:40.297: error : virHookCall:285 : Hook script execution fai=
    led: internal error Child process (LC_ALL=3DC PATH=3D/usr/local/sbin:/usr/l=
    ocal/bin:/usr/sbin:/usr/bin:/sbin:/bin
    -                       HOME=3D/root USER=3Droot LOGNAME=3Droot /etc/libvir=
    t/hooks/qemu qemu prepare begin -) unexpected exit status 1: Could not find=
     required XYZZY
    - - diff --git a/docs/hooks.rst b/docs/hooks.rst new file mode 100644 index 0000000000..9c5f3ff456 --- /dev/null +++ b/docs/hooks.rst @@ -0,0 +1,518 @@ +.. role:: since + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Hooks for specific system management +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +.. contents:: + +Custom event scripts +-------------------- + +Beginning with libvirt 0.8.0, specific events on a host system will trigger +custom scripts. + +These custom **hook** scripts are executed when any of the following actio= ns +occur: + +- The libvirt daemon starts, stops, or reloads its configuration ( + :since:`since 0.8.0` ) +- A QEMU guest is started or stopped ( :since:`since 0.8.0` ) +- An LXC guest is started or stopped ( :since:`since 0.8.0` ) +- A libxl-handled Xen guest is started or stopped ( :since:`since 2.1.0` ) +- A network is started or stopped or an interface is plugged/unplugged to= /from + the network ( :since:`since 1.2.2` ) + +Script location +--------------- + +The libvirt hook scripts are located in the directory +``$SYSCONFDIR/libvirt/hooks/``. + +- In Linux distributions such as Fedora and RHEL, this is + ``/etc/libvirt/hooks/``. Other Linux distributions may do this differen= tly. +- If your installation of libvirt has instead been compiled from source, = it is + likely to be ``/usr/local/etc/libvirt/hooks/``. +- :since:`Since 6.5.0` , you can also place several hook scripts in the + directories ``/etc/libvirt/hooks/.d/``. + +To use hook scripts, you will need to create this ``hooks`` directory manu= ally, +place the desired hook scripts inside, then make them executable. + +Script names +------------ + +At present, there are five hook scripts that can be called: + +- ``/etc/libvirt/hooks/daemon`` + Executed when the libvirt daemon is started, stopped, or reloads its + configuration +- ``/etc/libvirt/hooks/qemu`` + Executed when a QEMU guest is started, stopped, or migrated +- ``/etc/libvirt/hooks/lxc`` + Executed when an LXC guest is started or stopped +- ``/etc/libvirt/hooks/libxl`` + Executed when a libxl-handled Xen guest is started, stopped, or migrated +- ``/etc/libvirt/hooks/network`` + Executed when a network is started or stopped or an interface is + plugged/unplugged to/from the network + +:since:`Since 6.5.0` , you can also have several scripts with any name in = the +directories ``/etc/libvirt/hooks/.d/``. They are executed in +alphabetical order after main script. + +Script structure +---------------- + +The hook scripts are executed using standard Linux process creation functi= ons. +Therefore, they must begin with the declaration of the command interpreter= to +use. + +For example: + +:: + + #!/bin/bash + +or: + +:: + + #!/usr/bin/python + +Other command interpreters are equally valid, as is any executable binary,= so +you are welcome to use your favourite languages. + +Script arguments +---------------- + +The hook scripts are called with specific command line arguments, dependin= g upon +the script, and the operation being performed. + +The guest hook scripts, qemu and lxc, are also given the **full** XML +description for the domain on their stdin. This includes items such the UU= ID of +the domain and its storage information, and is intended to provide all the +libvirt information the script needs. + +For all cases, stdin of the network hook script is provided with the full = XML +description of the network status in the following form: + +:: + + + + $network_name + afca425a-2c3a-420c-b2fb-dd7b4950d722 + ... + + + +In the case of an network port being created / deleted, the network XML wi= ll be +followed with the full XML description of the port: + +:: + + + + $network_name + afca425a-2c3a-420c-b2fb-dd7b4950d722 + ... + + + 5d744f21-ba4a-4d6e-bdb2-30a35ff3207d + ... + + + + +Please note that this approach is different from other cases such as ``dae= mon``, +``qemu`` or ``lxc`` hook scripts, because two XMLs may be passed here, whi= le in +the other cases only a single XML is passed. + +The command line arguments take this approach: + +#. The first argument is the name of the **object** involved in the operat= ion, + or '-' if there is none. + For example, the name of a guest being started. +#. The second argument is the name of the **operation** being performed. + For example, "start" if a guest is being started. +#. The third argument is a **sub-operation** indication, or '-' if there is + none. +#. The last argument is an **extra argument** string, or '-' if there is n= one. + +Specifics +~~~~~~~~~ + +This translates to the following specifics for each hook script: + +/etc/libvirt/hooks/daemon +^^^^^^^^^^^^^^^^^^^^^^^^^ + +- | When the libvirt daemon is started, this script is called as: + + :: + + /etc/libvirt/hooks/daemon - start - start + +- | When the libvirt daemon is shut down, this script is called as: + + :: + + /etc/libvirt/hooks/daemon - shutdown - shutdown + +- | When the libvirt daemon receives the SIGHUP signal, it reloads its + configuration and triggers the hook script as: + + :: + + /etc/libvirt/hooks/daemon - reload begin SIGHUP + +Please note that when the libvirt daemon is restarted, the *daemon* hook s= cript +is called once with the "shutdown" operation, and then once with the "star= t" +operation. There is no specific operation to indicate a "restart" is occur= ring. + +/etc/libvirt/hooks/qemu +^^^^^^^^^^^^^^^^^^^^^^^ + +- | Before a QEMU guest is started, the qemu hook script is called in thr= ee + locations; if any location fails, the guest is not started. The first + location, :since:`since 0.9.0` , is before libvirt performs any resou= rce + labeling, and the hook can allocate resources not managed by libvirt = such + as DRBD or missing bridges. This is called as: + + :: + + /etc/libvirt/hooks/qemu guest_name prepare begin - + + | The second location, available :since:`Since 0.8.0` , occurs after li= bvirt + has finished labeling all resources, but has not yet started the gues= t, + called as: + + :: + + /etc/libvirt/hooks/qemu guest_name start begin - + + | The third location, :since:`0.9.13` , occurs after the QEMU process h= as + successfully started up: + + :: + + /etc/libvirt/hooks/qemu guest_name started begin - + +- | When a QEMU guest is stopped, the qemu hook script is called in two + locations, to match the startup. First, :since:`since 0.8.0` , the ho= ok is + called before libvirt restores any labels: + + :: + + /etc/libvirt/hooks/qemu guest_name stopped end - + + | Then, after libvirt has released all resources, the hook is called ag= ain, + :since:`since 0.9.0` , to allow any additional resource cleanup: + + :: + + /etc/libvirt/hooks/qemu guest_name release end - + +- :since:`Since 0.9.11` , the qemu hook script is also called at the begi= nning + of incoming migration. It is called as: + + :: + + /etc/libvirt/hooks/qemu guest_name migrate begin - + + 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 pr= int it + out on its standard output. Empty output is identical to copying the in= put + XML without changing it. In case the script returns failure or the outp= ut XML + is not valid, incoming migration will be canceled. This hook may be use= d, + e.g., to change location of disk images for incoming domains. + +- :since:`Since 1.2.9` , the qemu hook script is also called when restori= ng a + saved image either via the API or automatically when restoring a manage= d save + machine. It is called as: + + :: + + /etc/libvirt/hooks/qemu guest_name restore begin - + + 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 pr= int it + out on its standard output. Empty output is identical to copying the in= put + XML without changing it. In case the script returns failure or the outp= ut XML + is not valid, restore of the image will be aborted. This hook may be us= ed, + e.g., to change location of disk images for restored domains. + +- :since:`Since 6.5.0` , you can also place several hook scripts in the + directory ``/etc/libvirt/hooks/qemu.d/``. They are executed in alphabet= ical + order after main script. In this case each script also acts as filter a= nd can + modify the domain XML and print it out on its standard output. This scr= ipt + output is passed to standard input next script in order. Empty output f= rom + any script is also identical to copying the input XML without changing = it. In + case any script returns failure common process will be aborted, but all + scripts from the directory will are executed. + +- :since:`Since 0.9.13` , the qemu hook script is also called when the li= bvirtd + daemon restarts and reconnects to previously running QEMU processes. If= the + script fails, the existing QEMU process will be killed off. It is calle= d as: + + :: + + /etc/libvirt/hooks/qemu guest_name reconnect begin - + +- :since:`Since 0.9.13` , the qemu hook script is also called when the QE= MU + driver is told to attach to an externally launched QEMU process. It is = called + as: + + :: + + /etc/libvirt/hooks/qemu guest_name attach begin - + +/etc/libvirt/hooks/lxc +^^^^^^^^^^^^^^^^^^^^^^ + +- | 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, :since:`since 0.9.13` , is before libvirt performs any reso= urce + labeling, and the hook can allocate resources not managed by libvirt = such + as DRBD or missing bridges. This is called as: + + :: + + /etc/libvirt/hooks/lxc guest_name prepare begin - + + | The second location, available :since:`Since 0.8.0` , occurs after li= bvirt + has finished labeling all resources, but has not yet started the gues= t, + called as: + + :: + + /etc/libvirt/hooks/lxc guest_name start begin - + + | The third location, :since:`0.9.13` , occurs after the LXC process has + successfully started up: + + :: + + /etc/libvirt/hooks/lxc guest_name started begin - + +- | When a LXC guest is stopped, the lxc hook script is called in two + locations, to match the startup. First, :since:`since 0.8.0` , the ho= ok is + called before libvirt restores any labels: + + :: + + /etc/libvirt/hooks/lxc guest_name stopped end - + + | Then, after libvirt has released all resources, the hook is called ag= ain, + :since:`since 0.9.0` , to allow any additional resource cleanup: + + :: + + /etc/libvirt/hooks/lxc guest_name release end - + +- :since:`Since 0.9.13` , the lxc hook script is also called when the lib= virtd + 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: + + :: + + /etc/libvirt/hooks/lxc guest_name reconnect begin - + +/etc/libvirt/hooks/libxl +^^^^^^^^^^^^^^^^^^^^^^^^ + +- | Before a Xen guest is started using libxl driver, the libxl hook scri= pt is + called in three locations; if any location fails, the guest is not st= arted. + The first location, :since:`since 2.1.0` , is before libvirt performs= any + resource labeling, and the hook can allocate resources not managed by + libvirt. This is called as: + + :: + + /etc/libvirt/hooks/libxl guest_name prepare begin - + + | The second location, available :since:`Since 2.1.0` , occurs after li= bvirt + has finished labeling all resources, but has not yet started the gues= t, + called as: + + :: + + /etc/libvirt/hooks/libxl guest_name start begin - + + | The third location, :since:`2.1.0` , occurs after the domain has + successfully started up: + + :: + + /etc/libvirt/hooks/libxl guest_name started begin - + +- | When a libxl-handled Xen guest is stopped, the libxl hook script is c= alled + in two locations, to match the startup. First, :since:`since 2.1.0` ,= the + hook is called before libvirt restores any labels: + + :: + + /etc/libvirt/hooks/libxl guest_name stopped end - + + | Then, after libvirt has released all resources, the hook is called ag= ain, + :since:`since 2.1.0` , to allow any additional resource cleanup: + + :: + + /etc/libvirt/hooks/libxl guest_name release end - + +- :since:`Since 2.1.0` , the libxl hook script is also called at the begi= nning + of incoming migration. It is called as: + + :: + + /etc/libvirt/hooks/libxl guest_name migrate begin - + + 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 pr= int it + out on its standard output. Empty output is identical to copying the in= put + XML without changing it. In case the script returns failure or the outp= ut XML + is not valid, incoming migration will be canceled. This hook may be use= d, + e.g., to change location of disk images for incoming domains. + +- :since:`Since 6.5.0` , you can also place several hook scripts in the + directory ``/etc/libvirt/hooks/libxl.d/``. They are executed in alphabe= tical + order after main script. In this case each script also acts as filter a= nd can + modify the domain XML and print it out on its standard output. This scr= ipt + output is passed to standard input next script in order. Empty output f= rom + any script is also identical to copying the input XML without changing = it. In + case any script returns failure common process will be aborted, but all + scripts from the directory will are executed. + +- :since:`Since 2.1.0` , the libxl hook script is also called when the li= bvirtd + 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: + + :: + + /etc/libvirt/hooks/libxl guest_name reconnect begin - + +/etc/libvirt/hooks/network +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- | :since:`Since 1.2.2` , before a network is started, this script is ca= lled + as: + + :: + + /etc/libvirt/hooks/network network_name start begin - + +- | After the network is started, up & running, the script is called as: + + :: + + /etc/libvirt/hooks/network network_name started begin - + +- | When a network is shut down, this script is called as: + + :: + + /etc/libvirt/hooks/network network_name stopped end - + +- | 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: + + :: + + /etc/libvirt/hooks/network network_name port-created begin - + + Please note, that in this case, the script is passed both network and p= ort + XMLs on its stdin. + +- | When network is updated, the hook script is called as: + + :: + + /etc/libvirt/hooks/network network_name updated begin - + +- | When the domain from previous case is shutting down, the interface is + unplugged. This leads to another script invocation: + + :: + + /etc/libvirt/hooks/network network_name port-deleted begin - + + And again, as in previous case, both network and port XMLs are passed o= nto + script's stdin. + +Script execution +---------------- + +- The "start" operation for the guest and network hook scripts, executes + **prior** to the object (guest or network) being created. This allows t= he + object start operation to be aborted if the script returns indicating + failure. +- The "stopped" operation for the guest and network hook scripts, executes + **after** 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. +- Hook scripts execute in a synchronous fashion. Libvirt waits for them to + return before continuing the given operation. + 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. +- For a hook script to be utilised, it must have its execute bit set (e.g. + chmod o+rx *qemu*), and must be present when the libvirt daemon is star= ted. +- 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. + +QEMU guest migration +-------------------- + +Migration of a QEMU guest involves running hook scripts on both the source= and +destination hosts: + +#. At the beginning of the migration, the *qemu* hook script on the + **destination** host is executed with the "migrate" operation. +#. Before QEMU process is spawned, the two operations ("prepare" and "star= t") + called for domain start are executed on **destination** host. +#. 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. +#. The QEMU guest is then migrated to the destination host. +#. Unless an error occurs during the migration process, the *qemu* hook sc= ript + on the **source** 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. + +Calling libvirt functions from within a hook script +--------------------------------------------------- + +**DO NOT DO THIS!** + +A hook script must not call back into libvirt, as the libvirt daemon is al= ready +waiting for the script to exit. + +A deadlock is likely to occur. + +Return codes and logging +------------------------ + +If a hook script returns with an exit code of 0, the libvirt daemon regard= s this +as successful and performs no logging of it. + +However, if a hook script returns with a non zero exit code, the libvirt d= aemon +regards this as a failure, logs its return code, and additionally logs any= thing +on stderr the hook script returns. + +For example, a hook script might use this code to indicate failure, and se= nd a +text string to stderr: + +:: + + echo "Could not find required XYZZY" >&2 + exit 1 + +The resulting entry in the libvirt log will appear as: + +:: + + 20:02:40.297: error : virHookCall:285 : Hook script execution failed: i= nternal error Child process (LC_ALL=3DC PATH=3D/usr/local/sbin:/usr/local/b= in:/usr/sbin:/usr/bin:/sbin:/bin + HOME=3D/root USER=3Droot LOGNAME=3Droot /etc/lib= virt/hooks/qemu qemu prepare begin -) unexpected exit status 1: Could not f= ind required XYZZY diff --git a/docs/meson.build b/docs/meson.build index 22eca7d8bd..a0e96e2453 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -25,7 +25,6 @@ docs_html_in_files =3D [ 'formatnetwork', 'formatnode', 'formatnwfilter', - 'hooks', 'index', 'internals', 'java', @@ -92,6 +91,7 @@ docs_rst_files =3D [ 'goals', 'governance', 'hacking', + 'hooks', 'libvirt-go', 'libvirt-go-xml', 'macos', --=20 2.35.1