On Wed, Apr 17, 2019 at 09:09:12 -0500, Eric Blake wrote:
Introduce a bunch of new virsh commands for managing checkpoints
in isolation. More commands are needed for performing incremental
backups, but these commands were easy to implement by modeling
heavily after virsh-snapshot.c (no need for checkpoint-revert,
and checkpoint-list was a lot easier since we don't have to cater
to older libvirt API).
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
tools/virsh-checkpoint.h | 29 +
tools/virsh-completer.h | 4 +
tools/virsh-util.h | 3 +
tools/virsh.h | 1 +
po/POTFILES | 1 +
tools/Makefile.am | 1 +
tools/virsh-checkpoint.c | 1370 ++++++++++++++++++++++++++++++++++
tools/virsh-completer.c | 51 ++
tools/virsh-domain-monitor.c | 23 +
tools/virsh-domain.c | 15 +
tools/virsh-util.c | 11 +
tools/virsh.c | 2 +
tools/virsh.pod | 238 +++++-
13 files changed, 1742 insertions(+), 7 deletions(-)
create mode 100644 tools/virsh-checkpoint.h
create mode 100644 tools/virsh-checkpoint.c
[...]
diff --git a/tools/virsh-checkpoint.c b/tools/virsh-checkpoint.c
new file mode 100644
index 0000000000..3089383dc5
--- /dev/null
+++ b/tools/virsh-checkpoint.c
@@ -0,0 +1,1370 @@
+/*
+ * virsh-checkpoint.c: Commands to manage domain checkpoints
+ *
+ * Copyright (C) 2005-2019 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ * Daniel Veillard <veillard(a)redhat.com>
+ * Karel Zak <kzak(a)redhat.com>
+ * Daniel P. Berrange <berrange(a)redhat.com>
+ *
+ */
+
+#include <config.h>
+#include "virsh-checkpoint.h"
+
+#include <assert.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/xmlsave.h>
+
+#include "internal.h"
+#include "virbuffer.h"
+#include "viralloc.h"
+#include "virfile.h"
+#include "virsh-util.h"
+#include "virstring.h"
+#include "virxml.h"
+#include "conf/checkpoint_conf.h"
+
+/* Helper for checkpoint-create and checkpoint-create-as */
+static bool
+virshCheckpointCreate(vshControl *ctl,
+ virDomainPtr dom,
+ const char *buffer,
+ unsigned int flags,
+ const char *from)
+{
+ bool ret = false;
+ virDomainCheckpointPtr checkpoint;
+ const char *name = NULL;
+
+ checkpoint = virDomainCheckpointCreateXML(dom, buffer, flags);
+
+ if (checkpoint == NULL)
+ goto cleanup;
+
+ name = virDomainCheckpointGetName(checkpoint);
+ if (!name) {
+ vshError(ctl, "%s", _("Could not get snapshot name"));
Some copypaste leftovers.
+ goto cleanup;
+ }
+
+ if (from)
+ vshPrintExtra(ctl, _("Domain checkpoint %s created from
'%s'"),
+ name, from);
+ else
+ vshPrintExtra(ctl, _("Domain checkpoint %s created"), name);
+
+ ret = true;
+
+ cleanup:
+ virshDomainCheckpointFree(checkpoint);
+ return ret;
+}
+
+
+/*
[...]
+
+static bool
+cmdCheckpointCreate(vshControl *ctl,
+ const vshCmd *cmd)
+{
+ virDomainPtr dom = NULL;
+ bool ret = false;
+ const char *from = NULL;
+ char *buffer = NULL;
+ unsigned int flags = 0;
+
+ if (vshCommandOptBool(cmd, "redefine"))
+ flags |= VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE;
+ if (vshCommandOptBool(cmd, "current"))
+ flags |= VIR_DOMAIN_CHECKPOINT_CREATE_CURRENT;
+ if (vshCommandOptBool(cmd, "no-metadata"))
+ flags |= VIR_DOMAIN_CHECKPOINT_CREATE_NO_METADATA;
+ if (vshCommandOptBool(cmd, "quiesce"))
+ flags |= VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE;
leftovers
+
+ if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+ goto cleanup;
+
+ if (vshCommandOptStringReq(ctl, cmd, "xmlfile", &from) < 0)
+ goto cleanup;
+ if (!from) {
+ buffer = vshStrdup(ctl, "<domaincheckpoint/>");
+ } else {
+ if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) {
+ vshSaveLibvirtError();
+ goto cleanup;
+ }
+ }
+
+ ret = virshCheckpointCreate(ctl, dom, buffer, flags, from);
+
+ cleanup:
+ VIR_FREE(buffer);
+ virshDomainFree(dom);
+
+ return ret;
+}
+
+
[...]
+/* Helper for resolving {--current | --ARG name} into a checkpoint
+ * belonging to DOM. If EXCLUSIVE, fail if both --current and arg are
+ * present. On success, populate *CHK and *NAME, before returning 0.
+ * On failure, return -1 after issuing an error message. */
+static int
+virshLookupCheckpoint(vshControl *ctl,
+ const vshCmd *cmd,
+ const char *arg,
+ bool exclusive,
+ virDomainPtr dom,
+ virDomainCheckpointPtr *chk,
+ const char **name)
+{
+ bool current = vshCommandOptBool(cmd, "current");
+ const char *chkname = NULL;
+
+ if (vshCommandOptStringReq(ctl, cmd, arg, &chkname) < 0)
+ return -1;
+
+ if (exclusive && current && chkname) {
+ vshError(ctl, _("--%s and --current are mutually exclusive"), arg);
+ return -1;
+ }
+
+ if (chkname) {
+ *chk = virDomainCheckpointLookupByName(dom, chkname, 0);
+ } else if (current) {
+ *chk = virDomainCheckpointCurrent(dom, 0);
+ } else {
+ vshError(ctl, _("--%s or --current is required"), arg);
+ return -1;
+ }
+ if (!*chk) {
+ vshReportError(ctl);
+ return -1;
+ }
+
+ *name = virDomainCheckpointGetName(*chk);
+ return 0;
+}
+
+
+/*
+ * "checkpoint-edit" command
+ */
+static const vshCmdInfo info_checkpoint_edit[] = {
+ {.name = "help",
+ .data = N_("edit XML for a checkpoint")
+ },
+ {.name = "desc",
+ .data = N_("Edit the domain checkpoint XML for a named checkpoint")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_checkpoint_edit[] = {
+ VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+ {.name = "checkpointname",
+ .type = VSH_OT_STRING,
+ .help = N_("checkpoint name"),
+ .completer = virshCheckpointNameCompleter,
+ },
+ VIRSH_COMMON_OPT_CURRENT(N_("also set edited checkpoint as current")),
+ {.name = "rename",
+ .type = VSH_OT_BOOL,
+ .help = N_("allow renaming an existing checkpoint")
+ },
+ {.name = "clone",
+ .type = VSH_OT_BOOL,
+ .help = N_("allow cloning to new name")
+ },
+ {.name = NULL}
+};
[...]
+
+
+/*
+ * "checkpoint-current" command
+ */
+static const vshCmdInfo info_checkpoint_current[] = {
+ {.name = "help",
+ .data = N_("Get or set the current checkpoint")
Set?!? I see we do that with snapshots, but that's pure insanity.
It uses redefine to set the snapshot as current? But that defeats the
purpose of the 'current' snapshot/checkpoint since it does not change
the underlying state.
I don't think we should copy this.
+ },
+ {.name = "desc",
+ .data = N_("Get or set the current checkpoint")
+ },
+ {.name = NULL}
+};
[...]
+/* Helper function to get the name of a checkpoint's parent.
Caller
+ * must free the result. Returns 0 on success (including when it was
+ * proven no parent exists), and -1 on failure with error reported
+ * (such as no checkpoint support or domain deleted in meantime). */
+static int
+virshGetCheckpointParent(vshControl *ctl,
+ virDomainCheckpointPtr checkpoint,
+ char **parent_name)
+{
+ virDomainCheckpointPtr parent = NULL;
+ int ret = -1;
+
+ *parent_name = NULL;
+
+ parent = virDomainCheckpointGetParent(checkpoint, 0);
+ if (parent) {
+ /* API works, and virDomainCheckpointGetName will succeed */
There's no option when the API would not work. Only when it isn't
supported, but then you have other problems.
+ *parent_name = vshStrdup(ctl,
virDomainCheckpointGetName(parent));
+ ret = 0;
+ } else if (last_error->code == VIR_ERR_NO_DOMAIN_CHECKPOINT) {
+ /* API works, and we found a root with no parent */
+ ret = 0;
+ }
+
+ if (ret < 0) {
+ vshReportError(ctl);
+ vshError(ctl, "%s", _("unable to determine if checkpoint has
parent"));
+ } else {
+ vshResetLibvirtError();
+ }
+ virshDomainCheckpointFree(parent);
+ return ret;
+}
+
+
+/*
+ * "checkpoint-info" command
+ */
+static const vshCmdInfo info_checkpoint_info[] = {
+ {.name = "help",
+ .data = N_("checkpoint information")
+ },
+ {.name = "desc",
+ .data = N_("Returns basic information about a checkpoint.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_checkpoint_info[] = {
+ VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+ {.name = "checkpointname",
+ .type = VSH_OT_STRING,
+ .help = N_("checkpoint name"),
+ .completer = virshCheckpointNameCompleter,
+ },
+ VIRSH_COMMON_OPT_CURRENT(N_("info on current checkpoint")),
+ {.name = NULL}
+};
+
+
+static bool
+cmdCheckpointInfo(vshControl *ctl,
+ const vshCmd *cmd)
+{
+ virDomainPtr dom;
+ virDomainCheckpointPtr checkpoint = NULL;
+ const char *name;
+ char *parent = NULL;
+ bool ret = false;
+ int count;
+ unsigned int flags;
+ int current;
+ int metadata;
+
+ dom = virshCommandOptDomain(ctl, cmd, NULL);
+ if (dom == NULL)
+ return false;
+
+ if (virshLookupCheckpoint(ctl, cmd, "checkpointname", true, dom,
+ &checkpoint, &name) < 0)
+ goto cleanup;
+
+ vshPrint(ctl, "%-15s %s\n", _("Name:"), name);
+ vshPrint(ctl, "%-15s %s\n", _("Domain:"),
virDomainGetName(dom));
+
+ /* Determine if checkpoint is current. */
+ current = virDomainCheckpointIsCurrent(checkpoint, 0);
+ if (current < 0) {
+ vshError(ctl, "%s",
+ _("unexpected problem querying checkpoint state"));
+ goto cleanup;
+ }
+ vshPrint(ctl, "%-15s %s\n", _("Current:"),
+ current > 0 ? _("yes") : _("no"));
+
+ if (virshGetCheckpointParent(ctl, checkpoint, &parent) < 0) {
+ vshError(ctl, "%s",
+ _("unexpected problem querying checkpoint state"));
virshGetCheckpointParent already reports errors
+ goto cleanup;
+ }
+ vshPrint(ctl, "%-15s %s\n", _("Parent:"), parent ? parent :
"-");
+
+ /* Children, Descendants. */
+ flags = 0;
+ count = virDomainCheckpointListAllChildren(checkpoint, NULL, flags);
+ if (count < 0) {
+ if (last_error->code == VIR_ERR_NO_SUPPORT) {
+ vshResetLibvirtError();
Other calls are fatal.
+ ret = true;
+ }
+ goto cleanup;
+ }
+ vshPrint(ctl, "%-15s %d\n", _("Children:"), count);
+ flags = VIR_DOMAIN_CHECKPOINT_LIST_DESCENDANTS;
+ count = virDomainCheckpointListAllChildren(checkpoint, NULL, flags);
+ if (count < 0)
+ goto cleanup;
+ vshPrint(ctl, "%-15s %d\n", _("Descendants:"), count);
+
+ /* Metadata. */
+ metadata = virDomainCheckpointHasMetadata(checkpoint, 0);
+ if (metadata >= 0)
+ vshPrint(ctl, "%-15s %s\n", _("Metadata:"),
+ metadata ? _("yes") : _("no"));
This should be probably dropped altogether. I don't see a reason to have
metadata-less checkpoints.
+
+ ret = true;
+
+ cleanup:
+ VIR_FREE(parent);
+ virshDomainCheckpointFree(checkpoint);
+ virshDomainFree(dom);
+ return ret;
+}
[...]
+ if (vshCommandOptBool(cmd, "topological"))
+ flags |= VIR_DOMAIN_CHECKPOINT_LIST_TOPOLOGICAL;
+
+ if (roots)
+ flags |= VIR_DOMAIN_CHECKPOINT_LIST_ROOTS;
+
+ if (vshCommandOptBool(cmd, "metadata"))
+ flags |= VIR_DOMAIN_CHECKPOINT_LIST_METADATA;
+
+ if (vshCommandOptBool(cmd, "no-metadata"))
+ flags |= VIR_DOMAIN_CHECKPOINT_LIST_NO_METADATA;
+
+ if (vshCommandOptBool(cmd, "descendants")) {
+ if (!from && !current) {
+ vshError(ctl, "%s",
+ _("--descendants requires either --from or --current"));
+ return false;
+ }
+ flags |= VIR_DOMAIN_CHECKPOINT_LIST_DESCENDANTS;
+ }
+
+ if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+ return false;
+
+ if ((from || current) &&
+ virshLookupCheckpoint(ctl, cmd, "from", true, dom, &start,
&from_chk) < 0)
+ goto cleanup;
+
+ if (!(chklist = virshCheckpointListCollect(ctl, dom, start, flags, tree)))
+ goto cleanup;
+
+ if (!tree && !name) {
+ if (parent)
+ vshPrintExtra(ctl, " %-20s %-25s %s",
+ _("Name"), _("Creation Time"),
_("Parent"));
+ else
+ vshPrintExtra(ctl, " %-20s %-25s",
+ _("Name"), _("Creation Time"));
+ vshPrintExtra(ctl, "\n"
+ "------------------------------"
+ "--------------\n");
We don't do manual tables for some time now.
+ }
+
+ if (tree) {
+ for (i = 0; i < chklist->nchks; i++) {
+ if (!chklist->chks[i].parent &&
+ vshTreePrint(ctl, virshCheckpointListLookup, chklist,
+ chklist->nchks, i) < 0)
+ goto cleanup;
+ }
+ ret = true;
+ goto cleanup;
+ }
+
+ for (i = 0; i < chklist->nchks; i++) {
+ const char *chk_name;
+
+ /* free up memory from previous iterations of the loop */
+ VIR_FREE(parent_chk);
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(xml);
+ VIR_FREE(doc);
+
+ checkpoint = chklist->chks[i].chk;
+ chk_name = virDomainCheckpointGetName(checkpoint);
+ assert(chk_name);
+
+ if (name) {
+ /* just print the checkpoint name */
+ vshPrint(ctl, "%s\n", chk_name);
+ continue;
+ }
+
+ if (!(doc = virDomainCheckpointGetXMLDesc(checkpoint, 0)))
+ continue;
+
+ if (!(xml = virXMLParseStringCtxt(doc, _("(domain_checkpoint)"),
&ctxt)))
+ continue;
+
+ if (parent)
+ parent_chk =
virXPathString("string(/domaincheckpoint/parent/name)",
+ ctxt);
+
+ if (virXPathLongLong("string(/domaincheckpoint/creationTime)", ctxt,
+ &creation_longlong) < 0)
+ continue;
+ creation_time_t = creation_longlong;
+ if (creation_time_t != creation_longlong) {
+ vshError(ctl, "%s", _("time_t overflow"));
+ continue;
+ }
+ localtime_r(&creation_time_t, &time_info);
+ strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S %z",
+ &time_info);
+
+ if (parent)
+ vshPrint(ctl, " %-20s %-25s %s\n",
+ chk_name, timestr, parent_chk ?: "-");
+ else
+ vshPrint(ctl, " %-20s %-25s\n", chk_name, timestr);
+ }
+
+ ret = true;
+
+ cleanup:
+ /* this frees up memory from the last iteration of the loop */
+ virshCheckpointListFree(chklist);
+ VIR_FREE(parent_chk);
+ virshDomainCheckpointFree(start);
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(xml);
+ VIR_FREE(doc);
+ virshDomainFree(dom);
+
+ return ret;
+}
+
[...]
diff --git a/tools/virsh-domain-monitor.c
b/tools/virsh-domain-monitor.c
index d87475f6f6..59f3d7e6d9 100644
--- a/tools/virsh-domain-monitor.c
+++ b/tools/virsh-domain-monitor.c
[...]
@@ -1782,6 +1783,17 @@ virshDomainListCollect(vshControl *ctl,
unsigned int flags)
goto remove_entry;
}
We could make the checkpoint flags mandatory if the driver supports
checkpoints.
+ /* checkpoint filter */
+ if (VSH_MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_CHECKPOINT)) {
+ if ((nchk = virDomainListAllCheckpoints(dom, NULL, 0)) < 0) {
+ vshError(ctl, "%s", _("Failed to get checkpoint
count"));
+ goto cleanup;
+ }
+ if (!((VSH_MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_CHECKPOINT) && nchk
> 0) ||
+ (VSH_MATCH(VIR_CONNECT_LIST_DOMAINS_NO_CHECKPOINT) && nchk ==
0)))
+ goto remove_entry;
+ }
+
/* the domain matched all filters, it may stay */
continue;
[...]
diff --git a/tools/virsh.pod b/tools/virsh.pod
index afc1684db0..064a0a2fa3 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -409,6 +409,7 @@ Inject NMI to the guest.
[I<--with-managed-save>] [I<--without-managed-save>]
[I<--autostart>] [I<--no-autostart>]
[I<--with-snapshot>] [I<--without-snapshot>]
+ [I<--with-checkpoint>] [I<--without-checkpoint>]
[I<--state-running>] [I<--state-paused>]
[I<--state-shutoff>] [I<--state-other>]
@@ -514,6 +515,11 @@ this feature disabled use I<--no-autostart>.
Domains that have snapshot images can be listed using flag I<--with-snapshot>,
domains without a snapshot I<--without-snapshot>.
+=item B<Checkpoint existence>
+
+Domains that have checkpoints can be listed using flag I<--with-checkpoint>,
+domains without a checkpoint I<--without-checkpoint>.
+
=back
When talking to older servers, this command is forced to use a series of API
@@ -809,7 +815,8 @@ can be restarted later.
If I<domain> is transient, then the metadata of any snapshots will
be lost once the guest stops running, but the snapshot contents still
exist, and a new domain with the same name and UUID can restore the
-snapshot metadata with B<snapshot-create>.
+snapshot metadata with B<snapshot-create>. Similarly, the metadata of
+any checkpoints will be lost, but can be restored with B<checkpoint-create>.
If I<--graceful> is specified, don't resort to extreme measures
(e.g. SIGKILL) when the guest doesn't stop after a reasonable timeout;
@@ -1570,7 +1577,7 @@ Convert a domain Id (or UUID) to domain name
Rename a domain. This command changes current domain name to the new name
specified in the second argument.
-B<Note>: Domain must be inactive and without snapshots.
+B<Note>: Domain must be inactive and without snapshots or checkpoints.
=item B<domstate> I<domain> [I<--reason>]
@@ -2811,10 +2818,11 @@ services must be shutdown in the domain.
The exact behavior of a domain when it shuts down is set by the
I<on_poweroff> parameter in the domain's XML definition.
-If I<domain> is transient, then the metadata of any snapshots will
-be lost once the guest stops running, but the snapshot contents still
-exist, and a new domain with the same name and UUID can restore the
-snapshot metadata with B<snapshot-create>.
+If I<domain> is transient, then the metadata of any snapshots and
+checkpoints will be lost once the guest stops running, but the underlying
+contents still exist, and a new domain with the same name and UUID can
+restore the snapshot metadata with B<snapshot-create>, and the checkpoint
+metadata with B<checkpoint-create>.
By default the hypervisor will try to pick a suitable shutdown
method. To specify an alternative method, the I<--mode> parameter
@@ -2891,7 +2899,7 @@ Output the device used for the TTY console of the domain. If the
information
is not available the processes will provide an exit code of 1.
=item B<undefine> I<domain> [I<--managed-save>]
[I<--snapshots-metadata>]
-[I<--nvram>] [I<--keep-nvram>]
+[I<--checkpoints-metadata>] [I<--nvram>] [I<--keep-nvram>]
[ {I<--storage> B<volumes> | I<--remove-all-storage>
[I<--delete-snapshots>]}
I<--wipe-storage>]
@@ -2909,6 +2917,12 @@ domain. Without the flag, attempts to undefine an inactive domain
with
snapshot metadata will fail. If the domain is active, this flag is
ignored.
+The I<--checkpoints-metadata> flag guarantees that any checkpoints (see the
+B<checkpoint-list> command) are also cleaned up when undefining an inactive
+domain. Without the flag, attempts to undefine an inactive domain with
+checkpoint metadata will fail. If the domain is active, this flag is
+ignored.
+
I<--nvram> and I<--keep-nvram> specify accordingly to delete or keep nvram
(/domain/os/nvram/) file. If the domain has an nvram file and the flags are
omitted, the undefine will fail.
@@ -4876,6 +4890,216 @@ the data contents from that point in time.
=back
+=head1 CHECKPOINT COMMANDS
+
+The following commands manipulate domain checkpoints. Checkpoints serve as
+a point in time to identify which portions of a guest's disks have changed
+after that time, making it possible to perform incremental and differential
+backups. Checkpoints are identified with a unique name. See
+L<https://libvirt.org/formatcheckpoint.html> for documentation of the XML
+format used to represent properties of checkpoints.
+
+=over 4
+
+=item B<checkpoint-create> I<domain> [I<xmlfile>]
{[I<--redefine>
+{[I<--current>] | [I<--redefine-list>]}] | [I<--no-metadata>]
[I<--quiesce>]}
+
+Create a checkpoint for domain I<domain> with the properties specified
+in I<xmlfile> describing a <domaincheckpoint> top-level element. If
+I<xmlfile> is completely omitted, then libvirt will create a
+checkpoint with a name based on the current time. The new checkpoint
+will become current, as listed by B<checkpoint-current>.
+
+If I<--redefine> is specified, then all XML elements produced by
+B<checkpoint-dumpxml> are valid; this can be used to migrate
+checkpoint hierarchy from one machine to another, to recreate
+hierarchy for the case of a transient domain that goes away and is
+later recreated with the same name and UUID, or to make slight
+alterations in the checkpoint metadata (such as host-specific aspects
+of the domain XML embedded in the checkpoint). When this flag is
+supplied, the I<xmlfile> argument is mandatory, and the domain's
+current snapshot will not be altered unless the I<--current> flag is
+also given. If I<--redefine-list> is specified, I<--redefine> is
+implied, I<--current> is rejected, and the XML changes from being a
+single <domaincheckpoint> to instead being a <checkpoints> element
+describing a list of checkpoints. List form only works if the domain
+has no currently-defined checkpoint metadata, and can be obtained as a
+subset of I<dumpxml --checkpoints> output.
+
+If I<--no-metadata> is specified, then the checkpoint data is created,
+but any metadata is immediately discarded (that is, libvirt does not
+treat the checkpoint as current, and cannot use the checkpoint for an
+incremental backup unless I<--redefine> is later used to teach libvirt
+about the metadata again).
+
+If I<--quiesce> is specified, libvirt will try to use guest agent
+to freeze and unfreeze domain's mounted file systems. However,
+if domain has no guest agent, checkpoint creation will fail.
+
+Existence of checkpoint metadata will prevent attempts to B<undefine>
+a persistent domain. However, for transient domains, checkpoint
+metadata is silently lost when the domain quits running (whether
+by command such as B<destroy> or by internal guest action).
+
+=item B<checkpoint-create-as> I<domain> {[I<--print-xml>]
+| [I<--no-metadata>]} [I<name>] [I<description>] [I<--quiesce>]
+[I<--diskspec>] B<diskspec>]...
+
+Create a checkpoint for domain I<domain> with the given <name> and
+<description>; if either value is omitted, libvirt will choose a
+value. If I<--print-xml> is specified, then XML appropriate for
+I<checkpoint-create> is output, rather than actually creating a
+checkpoint.
+
+The I<--diskspec> option can be used to control which guest disks participate in
the checkpoint. This option can occur
+multiple times, according to the number of <disk> elements in the domain
+xml. Each <diskspec> is in the
+form B<disk[,checkpoint=type][,bitmap=name]>. A literal I<--diskspec> must
precede each B<diskspec> unless
+all three of I<domain>, I<name>, and I<description> are also present.
+For example, a diskspec of "vda,checkpoint=bitmap,bitmap=map1"
+results in the following XML:
+ <disk name='vda' checkpoint='bitmap' bitmap='map1'/>
+
+If I<--quiesce> is specified, libvirt will try to use guest agent
+to freeze and unfreeze domain's mounted file systems. However,
+if domain has no guest agent, checkpoint creation will fail.
+
+If I<--no-metadata> is specified, then the checkpoint data is created,
+but any metadata is immediately discarded (that is, libvirt does not
+treat the checkpoint as current, and cannot use the checkpoint for an
+incremental backup unless I<--redefine> is later used to teach libvirt
+about the metadata again).
+
+=item B<checkpoint-current> I<domain> {[I<--name>] |
[I<--security-info>]
+[I<--no-domain>] [I<--size>] | [I<checkpointname>]}
+
+Without I<checkpointname>, this will output the checkpoint XML for the
+domain's current checkpoint (if any). If I<--name> is specified,
+output just the current checkpoint name instead of the full xml.
+Otherwise, using I<--security-info> will also include security
+sensitive information in the XML, using I<--size> will add XML
+indicating roughly how much guest data has changed since the
+checkpoint was created, and using I<--no-domain> will omit the
+<domain> element from the output for a more compact view.
+
+With I<checkpointname>, this is a request to make the existing named
+checkpoint become the current checkpoint.
+
+=item B<checkpoint-edit> I<domain> [I<checkpointname>]
[I<--current>]
+{[I<--rename>] | [I<--clone>]}
+
+Edit the XML configuration file for I<checkpointname> of a domain. If
+both I<checkpointname> and I<--current> are specified, also force the
+edited checkpoint to become the current snapshot. If
+I<checkpointname> is omitted, then I<--current> must be supplied, to
+edit the current checkpoint.
+
+This is equivalent to:
+
+ virsh checkpoint-dumpxml dom name > checkpoint.xml
+ vi checkpoint.xml (or make changes with your other text editor)
+ virsh checkpoint-create dom checkpoint.xml --redefine [--current]
+
+except that it does some error checking.
+
+The editor used can be supplied by the C<$VISUAL> or C<$EDITOR> environment
+variables, and defaults to C<vi>.
+
+If I<--rename> is specified, then the edits can change the checkpoint
+name. If I<--clone> is specified, then changing the snapshot name
+will create a clone of the checkpoint metadata. If neither is
+specified, then the edits must not change the checkpoint name. Note
+that changing a checkpoint name must be done with care, since some
+drivers may require the original checkpoint name for actually
+accessing changes since a point in time.
+
+=item B<checkpoint-info> I<domain> {I<checkpoint> |
I<--current>}
+
+Output basic information about a named <checkpoint>, or the current
+checkpoint with I<--current>.
+
+=item B<checkpoint-list> I<domain> [I<--metadata>]
[I<--no-metadata>]
+[{I<--parent> | I<--roots> | [{I<--tree> | I<--name>}]}]
[I<--topological>]
+[{[I<--from>] B<checkpoint> | I<--current>} [I<--descendants>]]
+[I<--leaves>] [I<--no-leaves>]
+
+List all of the available checkpoints for the given domain, defaulting
+to show columns for the checkpoint name and creation time.
+
+Normally, table form output is sorted by checkpoint name; using
+I<--topological> instead sorts so that no child is listed before its
+ancestors (although there may be more than one possible ordering with
+this property).
+
+If I<--parent> is specified, add a column to the output table giving
+the name of the parent of each checkpoint. If I<--roots> is
+specified, the list will be filtered to just checkpoints that have no
+parents. If I<--tree> is specified, the output will be in a tree
+format, listing just checkpoint names. These three options are
+mutually exclusive. If I<--name> is specified only the checkpoint name
+is printed. This option is mutually exclusive with I<--tree>.
+
+If I<--from> is provided, filter the list to checkpoints which are
+children of the given B<checkpoint>; or if I<--current> is provided,
+start at the current checkpoint. When used in isolation or with
+I<--parent>, the list is limited to direct children unless
+I<--descendants> is also present. When used with I<--tree>, the use
+of I<--descendants> is implied. This option is not compatible with
+I<--roots>. Note that the starting point of I<--from> or
I<--current>
+is not included in the list unless the I<--tree> option is also
+present.
+
+If I<--leaves> is specified, the list will be filtered to just
+checkpoints that have no children. Likewise, if I<--no-leaves> is
+specified, the list will be filtered to just checkpoints with
+children. (Note that omitting both options does no filtering, while
+providing both options will either produce the same list or error out
+depending on whether the server recognizes the flags). Filtering
+options are not compatible with I<--tree>.
+
+If I<--metadata> is specified, the list will be filtered to just
+checkpoints that involve libvirt metadata, and thus would prevent
+B<undefine> of a persistent domain, or be lost on B<destroy> of a
+transient domain. Likewise, if I<--no-metadata> is specified, the
+list will be filtered to just checkpoints that exist without the need
+for libvirt metadata.
Hmmm. This actually reminds me that we should forbid checkpoints without
metadata. It's a dead-end also with snapshots.
+
+=item B<checkpoint-dumpxml> I<domain> I<snapshot>
[I<--security-info>]
+[I<--no-domain>] [I<--size>]
+
+Output the snapshot XML for the domain's checkpoint named
+I<checkpoint>. Using I<--security-info> will also include security
+sensitive information, using I<--size> will add XML indicating roughly
+how much guest data has changed since the checkpoint was created, and
+using I<--no-domain> will omit the <domain> element from the output
+for a more compact view. Use B<checkpoint-current> to easily access
+the XML of the current snapshot. To grab the XML for all checkpoints
+at once, use B<dumpxml --checkpoints>.
+
+=item B<checkpoint-parent> I<domain> {I<checkpoint> |
I<--current>}
+
+Output the name of the parent checkpoint, if any, for the given
+I<checkpoint>, or for the current checkpoint with I<--current>.
+
+=item B<checkpoint-delete> I<domain> {I<checkpoint> |
I<--current>}
+[I<--metadata>] [{I<--children> | I<--children-only>}]
+
+Delete the checkpoint for the domain named I<checkpoint>, or the
+current checkpoint with I<--current>. The record of which portions of
+the disk changed since the checkpoint are merged into the parent
+checkpoint (if any). If I<--children> is passed, then delete this
+checkpoint and any children of this checkpoint. If I<--children-only>
+is passed, then delete any children of this checkpoint, but leave this
+checkpoint intact. These two flags are mutually exclusive.
+
+If I<--metadata> is specified, then only delete the checkpoint
+metadata maintained by libvirt, while leaving the checkpoint contents
+intact for access by external tools; otherwise deleting a checkpoint
+also removes the ability to perform an incremental backup from that
+point in time.
+
+=back
+
=head1 NWFILTER COMMANDS
The following commands manipulate network filters. Network filters allow
--
2.20.1
--
libvir-list mailing list
libvir-list(a)redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list