
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@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@redhat.com> + * Karel Zak <kzak@redhat.com> + * Daniel P. Berrange <berrange@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@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list