Prepare for new checkpoint APIs by describing the XML that will
represent a checkpoint. The checkpoint XML is modeled heavily after
virDomainSnapshotPtr. (See the docs for more details).
Add testsuite coverage for some minimal uses of the XML.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
docs/docs.html.in | 3 +-
docs/format.html.in | 1 +
docs/formatcheckpoint.html.in | 202 ++++++++++++++++++++
docs/index.html.in | 3 +-
docs/schemas/domaincheckpoint.rng | 94 +++++++++
libvirt.spec.in | 1 +
mingw-libvirt.spec.in | 2 +
tests/Makefile.am | 2 +
tests/domaincheckpointxml2xmlin/empty.xml | 1 +
tests/domaincheckpointxml2xmlin/sample.xml | 7 +
tests/domaincheckpointxml2xmlout/empty.xml | 10 +
tests/domaincheckpointxml2xmlout/sample.xml | 16 ++
tests/virschematest.c | 2 +
13 files changed, 342 insertions(+), 2 deletions(-)
create mode 100644 docs/formatcheckpoint.html.in
create mode 100644 docs/schemas/domaincheckpoint.rng
create mode 100644 tests/domaincheckpointxml2xmlin/empty.xml
create mode 100644 tests/domaincheckpointxml2xmlin/sample.xml
create mode 100644 tests/domaincheckpointxml2xmlout/empty.xml
create mode 100644 tests/domaincheckpointxml2xmlout/sample.xml
diff --git a/docs/docs.html.in b/docs/docs.html.in
index d0ff844d0c..f6e599b77b 100644
--- a/docs/docs.html.in
+++ b/docs/docs.html.in
@@ -80,7 +80,8 @@
<a href="formatstoragecaps.html">storage pool
capabilities</a>,
<a href="formatnode.html">node devices</a>,
<a href="formatsecret.html">secrets</a>,
- <a href="formatsnapshot.html">snapshots</a></dd>
+ <a href="formatsnapshot.html">snapshots</a>,
+ <a
href="formatcheckpoint.html">checkpoints</a></dd>
<dt><a href="uri.html">URI format</a></dt>
<dd>The URI formats used for connecting to libvirt</dd>
diff --git a/docs/format.html.in b/docs/format.html.in
index 640a9957ee..20f9ef3348 100644
--- a/docs/format.html.in
+++ b/docs/format.html.in
@@ -25,6 +25,7 @@
<li><a href="formatnode.html">Node
devices</a></li>
<li><a href="formatsecret.html">Secrets</a></li>
<li><a
href="formatsnapshot.html">Snapshots</a></li>
+ <li><a
href="formatcheckpoint.html">Checkpoints</a></li>
</ul>
<h2>Command line validation</h2>
diff --git a/docs/formatcheckpoint.html.in b/docs/formatcheckpoint.html.in
new file mode 100644
index 0000000000..5c844f1f27
--- /dev/null
+++ b/docs/formatcheckpoint.html.in
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html
xmlns="http://www.w3.org/1999/xhtml">
+ <body>
+ <h1>Checkpoint XML format</h1>
+
+ <ul id="toc"></ul>
+
+ <h2><a id="CheckpointAttributes">Checkpoint
XML</a></h2>
+
+ <p>
+ One method of capturing domain disk backups is via the use of
+ incremental backups. Right now, incremental backups are only
+ supported for the QEMU hypervisor when using qcow2 disks at the
+ active layer; if other disk formats are in use, capturing disk
+ backups requires different libvirt APIs.
+ </p>
+ <p>
+ Libvirt is able to facilitate incremental backups by tracking
+ disk checkpoints, which are points in time against which it is
+ easy to compute which portion of the disk has changed. Given a
+ full backup (a backup created from the creation of the disk to a
+ given point in time), coupled with the creation of a disk
+ checkpoint at that time, and an incremental backup (a backup
+ created from just the dirty portion of the disk between the
+ first checkpoint and the second backup operation), it is
+ possible to do an offline reconstruction of the state of the
+ disk at the time of the second backup without having to copy as
+ much data as a second full backup would require. Most disk
+ checkpoints are created in conjunction with a backup
+ via <code>virDomainBackupBegin()</code> or with a snapshot
+ via <code>virDomainSnapshotCreateXML2</code>; however, libvirt
+ also exposes enough support to create disk checkpoints
+ independently from a backup operation
+ via <code>virDomainCheckpointCreateXML()</code>.
+ </p>
+ <p>
+ Attributes of libvirt checkpoints are stored as child elements
+ of the <code>domaincheckpoint</code> element. At checkpoint
+ creation time, normally only
+ the <code>name</code>, <code>description</code>,
+ and <code>disks</code> elements are settable. The rest of the
+ fields are ignored on creation and will be filled in by libvirt
+ in for informational purposes
+ by <code>virDomainCheckpointGetXMLDesc()</code>. However, when
+ redefining a checkpoint, with
+ the <code>VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE</code> flag
+ of <code>virDomainCheckpointCreateXML()</code>, all of the XML
+ fields described here are relevant on input, even the fields
+ that are normally described as readonly for output.
+ </p>
+ <p>
+ Checkpoints are maintained in a hierarchy. A domain can have a
+ current checkpoint, which is the most recent checkpoint compared
+ to the current state of the domain (although a domain might have
+ checkpoints without a current checkpoint, if checkpoints have
+ been deleted in the meantime). Creating a checkpoint sets that
+ checkpoint as current and the prior current checkpoint is the
+ parent of the new checkpoint. In the future, reverting to a
+ domain snapshot may also affect the current checkpoint.
+ </p>
+ <p>
+ The top-level <code>domaincheckpoint</code> element may contain
+ the following elements:
+ </p>
+ <dl>
+ <dt><code>name</code></dt>
+ <dd>The optional name for this checkpoint. If the name is
+ omitted, libvirt will create a name based on the time of the
+ creation.
+ </dd>
+ <dt><code>description</code></dt>
+ <dd>An optional human-readable description of the checkpoint.
+ If the description is omitted when initially creating the
+ checkpoint, then this field will be empty.
+ </dd>
+ <dt><code>disks</code></dt>
+ <dd>On input, this is an optional listing of specific
+ instructions for disk checkpoints; it is needed when making a
+ checkpoint on only a subset of the disks associated with a
+ domain. In particular, since QEMU checkpoints require qcow2
+ disks, this element may be needed on input for excluding guest
+ disks that are not in qcow2 format. If the entire element was
+ omitted on input, then all disks participate in the
+ checkpoint, otherwise, only the disks explicitly listed which
+ do not also use <code>checkpoint='no'</code> will
+ participate. On output, this is the checkpoint state of each
+ of the domain's disks.
+ <dl>
+ <dt><code>disk</code></dt>
+ <dd>This sub-element describes the checkpoint properties of
+ a specific disk with the following attributes:
+ <dl>
+ <dt><code>name</code></dt>
+ <dd>A mandatory attribute which must match either
+ the <code><target dev='name'/></code>
or an
+ unambiguous <code><source
file='name'/></code>
+ of one of
+ the <a href="formatdomain.html#elementsDisks">disk
+ devices</a> specified for the domain at the time of
+ the checkpoint.</dd>
+ <dt><code>checkpoint</code></dt>
+ <dd>An optional attribute; possible values
+ are <code>no</code> when the disk does not participate
+ in this checkpoint; or <code>bitmap</code> if the disk
+ will track all changes since the creation of this
+ checkpoint via a bitmap.</dd>
+ <dt><code>bitmap</code></dt>
+ <dd>The attribute <code>bitmap</code> is only valid
+ if <code>checkpoint='bitmap'</code>; it describes
the
+ name of the tracking bitmap (defaulting to the
+ checkpoint name).</dd>
+ <dt><code>size</code></dt>
+ <dd>The attribute <code>size</code> is ignored on input;
+ on output, it is only present if
+ the <code>VIR_DOMAIN_CHECKPOINT_XML_SIZE</code> flag
+ was used to perform a dynamic query of the estimated
+ size in bytes of the changes made since the checkpoint
+ was created.</dd>
+ </dl>
+ </dd>
+ </dl>
+ </dd>
+ <dt><code>creationTime</code></dt>
+ <dd>A readonly representation of the time this checkpoint was
+ created. The time is specified in seconds since the Epoch,
+ UTC (i.e. Unix time).
+ </dd>
+ <dt><code>parent</code></dt>
+ <dd>An optional readonly representation of the parent of this
+ checkpoint. If present, this element contains exactly one
+ child element, <code>name</code>.
+ </dd>
+ <dt><code>domain</code></dt>
+ <dd>A readonly representation of the
+ inactive <a href="formatdomain.html">domain
configuration</a>
+ at the time the checkpoint was created. This element may be
+ omitted for output brevity by supplying
+ the <code>VIR_DOMAIN_CHECKPOINT_XML_NO_DOMAIN</code> flag, but
+ the resulting XML is no longer viable for use with
+ the <code>VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE</code> flag
+ of <code>virDomainCheckpointCreateXML()</code>. The domain
+ will have security-sensitive information omitted unless the
+ flag <code>VIR_DOMAIN_SNAPSHOT_XML_SECURE</code> is provided
+ on a read-write connection.
+ </dd>
+ </dl>
+
+ <h2><a id="example">Examples</a></h2>
+
+ <p>Using this XML to create a checkpoint of just vda on a qemu
+ domain with two disks and a prior checkpoint:</p>
+ <pre>
+<domaincheckpoint>
+ <description>Completion of updates after OS
install</description>
+ <disks>
+ <disk name='vda' checkpoint='bitmap'/>
+ <disk name='vdb' checkpoint='no'/>
+ </disks>
+</domaincheckpoint></pre>
+
+ <p>will result in XML similar to this from
+ <code>virDomainCheckpointGetXMLDesc()</code>:</p>
+ <pre>
+<domaincheckpoint>
+ <name>1525889631</name>
+ <description>Completion of updates after OS
install</description>
+ <creationTime>1525889631</creationTime>
+ <parent>
+ <name>1525111885</name>
+ </parent>
+ <disks>
+ <disk name='vda' checkpoint='bitmap'
bitmap='1525889631'/>
+ <disk name='vdb' checkpoint='no'/>
+ </disks>
+ <domain type='qemu'>
+ <name>fedora</name>
+ <uuid>93a5c045-6457-2c09-e56c-927cdf34e178</uuid>
+ <memory>1048576</memory>
+ ...
+ <devices>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='qcow2'/>
+ <source file='/path/to/file1'/>
+ <target dev='vda' bus='virtio'/>
+ </disk>
+ <disk type='file' device='disk'
snapshot='external'>
+ <driver name='qemu' type='raw'/>
+ <source file='/path/to/file2'/>
+ <target dev='vdb' bus='virtio'/>
+ </disk>
+ ...
+ </devices>
+ </domain>
+</domaincheckpoint></pre>
+
+ <p>With that checkpoint created, the qcow2 image is now tracking
+ all changes that occur in the image since the checkpoint via
+ the persistent bitmap named <code>1525889631</code>.
+ </p>
+ </body>
+</html>
diff --git a/docs/index.html.in b/docs/index.html.in
index f593445d06..0315915402 100644
--- a/docs/index.html.in
+++ b/docs/index.html.in
@@ -69,7 +69,8 @@
<a href="formatstoragecaps.html">storage pool
capabilities</a>,
<a href="formatnode.html">node devices</a>,
<a href="formatsecret.html">secrets</a>,
- <a href="formatsnapshot.html">snapshots</a></dd>
+ <a href="formatsnapshot.html">snapshots</a>,
+ <a
href="formatcheckpoint.html">checkpoints</a></dd>
<dt><a
href="http://wiki.libvirt.org">Wiki</a></dt>
<dd>Read further community contributed content</dd>
</dl>
diff --git a/docs/schemas/domaincheckpoint.rng b/docs/schemas/domaincheckpoint.rng
new file mode 100644
index 0000000000..d8dfda9f1c
--- /dev/null
+++ b/docs/schemas/domaincheckpoint.rng
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+<!-- A Relax NG schema for the libvirt domain checkpoint properties XML format -->
+<grammar
xmlns="http://relaxng.org/ns/structure/1.0">
+ <start>
+ <ref name='domaincheckpoint'/>
+ </start>
+
+ <include href='domaincommon.rng'/>
+
+ <define name='domaincheckpoint'>
+ <element name='domaincheckpoint'>
+ <interleave>
+ <optional>
+ <element name='name'>
+ <text/>
+ </element>
+ </optional>
+ <optional>
+ <element name='description'>
+ <text/>
+ </element>
+ </optional>
+ <optional>
+ <element name='creationTime'>
+ <text/>
+ </element>
+ </optional>
+ <optional>
+ <element name='disks'>
+ <oneOrMore>
+ <ref name='diskcheckpoint'/>
+ </oneOrMore>
+ </element>
+ </optional>
+ <optional>
+ <choice>
+ <element name='domain'>
+ <element name='uuid'>
+ <ref name="UUID"/>
+ </element>
+ </element>
+ <!-- Nested grammar ensures that any of our overrides of
+ storagecommon/domaincommon defines do not conflict
+ with any domain.rng overrides. -->
+ <grammar>
+ <include href='domain.rng'/>
+ </grammar>
+ </choice>
+ </optional>
+ <optional>
+ <element name='parent'>
+ <element name='name'>
+ <text/>
+ </element>
+ </element>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name='diskcheckpoint'>
+ <element name='disk'>
+ <attribute name='name'>
+ <choice>
+ <ref name='diskTarget'/>
+ <ref name='absFilePath'/>
+ </choice>
+ </attribute>
+ <choice>
+ <attribute name='checkpoint'>
+ <value>no</value>
+ </attribute>
+ <group>
+ <optional>
+ <attribute name='checkpoint'>
+ <value>bitmap</value>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name='bitmap'>
+ <text/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name='size'>
+ <ref name="unsignedLong"/>
+ </attribute>
+ </optional>
+ </group>
+ </choice>
+ </element>
+ </define>
+
+</grammar>
diff --git a/libvirt.spec.in b/libvirt.spec.in
index b7a35a0fb1..6a730befdd 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -1800,6 +1800,7 @@ exit 0
%{_datadir}/libvirt/schemas/cputypes.rng
%{_datadir}/libvirt/schemas/domain.rng
%{_datadir}/libvirt/schemas/domaincaps.rng
+%{_datadir}/libvirt/schemas/domaincheckpoint.rng
%{_datadir}/libvirt/schemas/domaincommon.rng
%{_datadir}/libvirt/schemas/domainsnapshot.rng
%{_datadir}/libvirt/schemas/interface.rng
diff --git a/mingw-libvirt.spec.in b/mingw-libvirt.spec.in
index bea822fd73..553533c88f 100644
--- a/mingw-libvirt.spec.in
+++ b/mingw-libvirt.spec.in
@@ -240,6 +240,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt-guests.sh
%{mingw32_datadir}/libvirt/schemas/cputypes.rng
%{mingw32_datadir}/libvirt/schemas/domain.rng
%{mingw32_datadir}/libvirt/schemas/domaincaps.rng
+%{mingw32_datadir}/libvirt/schemas/domaincheckpoint.rng
%{mingw32_datadir}/libvirt/schemas/domaincommon.rng
%{mingw32_datadir}/libvirt/schemas/domainsnapshot.rng
%{mingw32_datadir}/libvirt/schemas/interface.rng
@@ -328,6 +329,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt-guests.sh
%{mingw64_datadir}/libvirt/schemas/cputypes.rng
%{mingw64_datadir}/libvirt/schemas/domain.rng
%{mingw64_datadir}/libvirt/schemas/domaincaps.rng
+%{mingw64_datadir}/libvirt/schemas/domaincheckpoint.rng
%{mingw64_datadir}/libvirt/schemas/domaincommon.rng
%{mingw64_datadir}/libvirt/schemas/domainsnapshot.rng
%{mingw64_datadir}/libvirt/schemas/interface.rng
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d3cdbff8bb..c552d08e12 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -83,6 +83,8 @@ EXTRA_DIST = \
commanddata \
cputestdata \
domaincapsschemadata \
+ domaincheckpointxml2xmlin \
+ domaincheckpointxml2xmlout \
domainconfdata \
domainschemadata \
domainsnapshotxml2xmlin \
diff --git a/tests/domaincheckpointxml2xmlin/empty.xml
b/tests/domaincheckpointxml2xmlin/empty.xml
new file mode 100644
index 0000000000..dc36449142
--- /dev/null
+++ b/tests/domaincheckpointxml2xmlin/empty.xml
@@ -0,0 +1 @@
+<domaincheckpoint/>
diff --git a/tests/domaincheckpointxml2xmlin/sample.xml
b/tests/domaincheckpointxml2xmlin/sample.xml
new file mode 100644
index 0000000000..70ed964e1e
--- /dev/null
+++ b/tests/domaincheckpointxml2xmlin/sample.xml
@@ -0,0 +1,7 @@
+<domaincheckpoint>
+ <description>Completion of updates after OS install</description>
+ <disks>
+ <disk name='vda' checkpoint='bitmap'/>
+ <disk name='vdb' checkpoint='no'/>
+ </disks>
+</domaincheckpoint>
diff --git a/tests/domaincheckpointxml2xmlout/empty.xml
b/tests/domaincheckpointxml2xmlout/empty.xml
new file mode 100644
index 0000000000..a26c7caab0
--- /dev/null
+++ b/tests/domaincheckpointxml2xmlout/empty.xml
@@ -0,0 +1,10 @@
+<domaincheckpoint>
+ <name>1525889631</name>
+ <creationTime>1525889631</creationTime>
+ <disks>
+ <disk name='vda' checkpoint='bitmap'
bitmap='1525889631'/>
+ </disks>
+ <domain>
+ <uuid>9d37b878-a7cc-9f9a-b78f-49b3abad25a8</uuid>
+ </domain>
+</domaincheckpoint>
diff --git a/tests/domaincheckpointxml2xmlout/sample.xml
b/tests/domaincheckpointxml2xmlout/sample.xml
new file mode 100644
index 0000000000..559b29c8c1
--- /dev/null
+++ b/tests/domaincheckpointxml2xmlout/sample.xml
@@ -0,0 +1,16 @@
+<domaincheckpoint>
+ <name>1525889631</name>
+ <description>Completion of updates after OS install</description>
+ <creationTime>1525889631</creationTime>
+ <parent>
+ <name>1525111885</name>
+ </parent>
+ <disks>
+ <disk name='vda' checkpoint='bitmap'
bitmap='1525889631'/>
+ <disk name='vdb' checkpoint='no'/>
+ </disks>
+ <domain type='qemu'>
+ <name>fedora</name>
+ <uuid>93a5c045-6457-2c09-e56c-927cdf34e178</uuid>
+ </domain>
+</domaincheckpoint>
diff --git a/tests/virschematest.c b/tests/virschematest.c
index 56bdcb2f88..fa99e67a57 100644
--- a/tests/virschematest.c
+++ b/tests/virschematest.c
@@ -222,6 +222,8 @@ mymain(void)
"genericxml2xmloutdata", "xlconfigdata",
"libxlxml2domconfigdata",
"qemuhotplugtestdomains");
DO_TEST_DIR("domaincaps.rng", "domaincapsschemadata");
+ DO_TEST_DIR("domaincheckpoint.rng", "domaincheckpointxml2xmlin",
+ "domaincheckpointxml2xmlout");
DO_TEST_DIR("domainsnapshot.rng", "domainsnapshotxml2xmlin",
"domainsnapshotxml2xmlout");
DO_TEST_DIR("interface.rng", "interfaceschemadata");
--
2.20.1