[libvirt] [PATCH v4 13/20] backup: Implement virsh support for checkpoints

Eric Blake eblake at redhat.com
Mon Feb 25 21:37:08 UTC 2019


On 2/12/19 1:15 PM, John Ferlan wrote:
> 
> 
> On 2/6/19 2:18 PM, 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 at 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        |    3 +-
>>  tools/virsh-checkpoint.c | 1329 ++++++++++++++++++++++++++++++++++++++
>>  tools/virsh-completer.c  |   52 +-
>>  tools/virsh-util.c       |   11 +
>>  tools/virsh.c            |    2 +
>>  10 files changed, 1433 insertions(+), 2 deletions(-)
>>  create mode 100644 tools/virsh-checkpoint.h
>>  create mode 100644 tools/virsh-checkpoint.c
> 
> virsh.pod would be useful in order to figure out what everything means.
> 

Gah. I completely forgot to copy-and-paste that portion of the snapshot
code.  Will rectify.

> This is just too much being added here to really give this a proper
> review. This really is a case where too much has been built up. Start
> with the basics and build up from there.
> 
> I have similar things as previously w/r/t 2 blank lines between
> functions and one argument per line per method - all newer norms than
> when -snapshot was created.
> 
> Also may as well use the VIR_AUTOFREE type functions for (char *)
> VIR_FREE's.  And VIR_AUTOPTR(virString) as approriate

Yep, on my list of things to clean up where I spot them, to avoid
regressing to the older state-of-the-art when I first copied this code
from snapshots.


>> +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"));
> 
> Could not find domain checkpoint '%s'
> 
> would be better

Particularly since it's not a snapshot.  (Too much copy-and-paste...)


>> +    /* TODO - worth adding this flag?
>> +    {.name = "quiesce",
>> +     .type = VSH_OT_BOOL,
>> +     .help = N_("quiesce guest's file systems")
>> +    },
>> +    */
> 
> More to do

At least adding it here is easy. Adding it in qemu is harder.


>> +/*
>> + * "checkpoint-edit" command
>> + */
> 
> Oh and this is *really* a scary thing to allow! Especially since IIRC
> the Assign function would just create a new one if a name didn't
> exist... There seems to be a few things that could happen without locks
> that could really mess things up.

Modeled after "snapshot-edit" - but yes, it is a scary-enough command
that splitting it to a separate commit doesn't hurt my feelings (nor
hold up the initial API).


>> +static bool
>> +cmdCheckpointCurrent(vshControl *ctl, const vshCmd *cmd)
>> +{
>> +    virDomainPtr dom = NULL;
>> +    bool ret = false;
>> +    int current;
>> +    virDomainCheckpointPtr checkpoint = NULL;
>> +    char *xml = NULL;
>> +    const char *checkpointname = NULL;
>> +    unsigned int flags = 0;
>> +    const char *domname;
>> +
>> +    if (vshCommandOptBool(cmd, "security-info"))
>> +        flags |= VIR_DOMAIN_CHECKPOINT_XML_SECURE;
>> +    if (vshCommandOptBool(cmd, "no-domain"))
>> +        flags |= VIR_DOMAIN_CHECKPOINT_XML_NO_DOMAIN;
>> +    if (vshCommandOptBool(cmd, "size"))
>> +        flags |= VIR_DOMAIN_CHECKPOINT_XML_SIZE;
>> +
>> +    VSH_EXCLUSIVE_OPTIONS("name", "checkpointname");
>> +
>> +    if (!(dom = virshCommandOptDomain(ctl, cmd, &domname)))
>> +        return false;
>> +
>> +    if (vshCommandOptStringReq(ctl, cmd, "checkpointname", &checkpointname) < 0)
>> +        goto cleanup;
>> +
>> +    if (checkpointname) {
>> +        virDomainCheckpointPtr checkpoint2 = NULL;
>> +        flags = (VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE |
>> +                 VIR_DOMAIN_CHECKPOINT_CREATE_CURRENT);
>> +
>> +        if (!(checkpoint = virDomainCheckpointLookupByName(dom,
>> +                                                           checkpointname, 0)))
>> +            goto cleanup;
>> +
>> +        xml = virDomainCheckpointGetXMLDesc(checkpoint,
>> +                                            VIR_DOMAIN_CHECKPOINT_XML_SECURE);
>> +        if (!xml)
>> +            goto cleanup;
>> +
>> +        if (!(checkpoint2 = virDomainCheckpointCreateXML(dom, xml, flags)))
>> +            goto cleanup;
> 
> I need a better map.  When creating a checkpoint a couple patches ago,
> the AssignDef would fail if the name already existed. This code seems to
> take existing XML with a name that would already exist.

Modeled after the existing 'snapshot-current', which can be used to
redefine WHICH snapshot is marked current (but oddly enough lacks a way
to mark NO snapshot as current).  It uses the _REDEFINE flag to do an
in-place edit to the virDomainCheckpointObjList on which checkpoint is
marked current (and based on the use of the _CURRENT flag to state which
checkpoint is the new current one).


>> +
>> +    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));
> 
> Meaning we could have partial printing if the subequent fails

Yeah. And isn't the new norm to use the new table-printer that formats
columns nicely according to content width?  I'll have to see if snapshot
code has improved here in the meantime.


>> +    /* Children, Descendants.  */
>> +    flags = 0;
>> +    count = virDomainCheckpointListChildren(checkpoint, NULL, flags);
>> +    if (count < 0) {
>> +        if (last_error->code == VIR_ERR_NO_SUPPORT) {
>> +            vshResetLibvirtError();
>> +            ret = true;
>> +        }
>> +        goto cleanup;
>> +    }
>> +    vshPrint(ctl, "%-15s %d\n", _("Children:"), count);
>> +    flags = VIR_DOMAIN_CHECKPOINT_LIST_DESCENDANTS;
>> +    count = virDomainCheckpointListChildren(checkpoint, NULL, flags);
>> +    if (count < 0)
>> +        goto cleanup;
>> +    vshPrint(ctl, "%-15s %d\n", _("Descendants:"), count);
> 
> Is delineating children and desendants necessary?

Knowing that you have 1 child but 3 descendents (and therefore, 2 of the
3 descendents are grandchildren or below) is interesting, if only to
prove that the filtering API flags work :)


>> +    /* When mixing --from and --tree, we also want a copy of from
>> +     * in the list, but with no parent for that one entry.  */
> 
> Still mumbling about too many options.

And that snapshot-list has just as many options.

> 
> That's a lot of different options... I'm confused over multiple
> checkpoints without a parent. I would figure a checkpoint without a
> parent is the root or first checkpoint and children are essentially
> linear. But this tree concept just complicates things so much.

Snapshots can definitely be more than linear. I'm not sure if
checkpoints can easily become more than linear, but I don't want to rule
it out (after all, reverting to prior states can do weird things).

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org




More information about the libvir-list mailing list