mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-03 11:35:19 +00:00
snapshot: add virsh back-compat support for new filters
Snapshot filtering based on types is useful enough to add back-compat support into virsh. It is also rather easy - all versions of libvirt that don't understand the new filter flags already gave us sufficient information in a single XML field to reconstruct all the information we need (that is, it isn't until libvirt 1.0.1 that we have more interesting types of snapshots, such as offline external). * tools/virsh-snapshot.c (vshSnapshotFilter): New function. (vshSnapshotListCollect): Add fallback support.
This commit is contained in:
parent
e9028f4b73
commit
1d272e8f22
@ -39,6 +39,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "virsh-domain.h"
|
#include "virsh-domain.h"
|
||||||
#include "xml.h"
|
#include "xml.h"
|
||||||
|
#include "conf/snapshot_conf.h"
|
||||||
|
|
||||||
/* Helper for snapshot-create and snapshot-create-as */
|
/* Helper for snapshot-create and snapshot-create-as */
|
||||||
static bool
|
static bool
|
||||||
@ -712,6 +713,63 @@ cleanup:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Helper function to filter snapshots according to status and
|
||||||
|
* location portion of flags. Returns 0 if filter excluded snapshot,
|
||||||
|
* 1 if snapshot is okay (or if snapshot is already NULL), and -1 on
|
||||||
|
* failure, with error already reported. */
|
||||||
|
static int
|
||||||
|
vshSnapshotFilter(vshControl *ctl, virDomainSnapshotPtr snapshot,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
char *xml = NULL;
|
||||||
|
xmlDocPtr xmldoc = NULL;
|
||||||
|
xmlXPathContextPtr ctxt = NULL;
|
||||||
|
int ret = -1;
|
||||||
|
char *state = NULL;
|
||||||
|
|
||||||
|
if (!snapshot)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
xml = virDomainSnapshotGetXMLDesc(snapshot, 0);
|
||||||
|
if (!xml)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
xmldoc = virXMLParseStringCtxt(xml, _("(domain_snapshot)"), &ctxt);
|
||||||
|
if (!xmldoc)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* Libvirt 1.0.1 and newer never call this function, because the
|
||||||
|
* filtering is already supported by the listing functions. Older
|
||||||
|
* libvirt lacked /domainsnapshot/memory, but was also limited in
|
||||||
|
* the types of snapshots it could create: if state was disk-only,
|
||||||
|
* the snapshot is external; all other snapshots are internal. */
|
||||||
|
state = virXPathString("string(/domainsnapshot/state)", ctxt);
|
||||||
|
if (!state) {
|
||||||
|
vshError(ctl, "%s", _("unable to perform snapshot filtering"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (STREQ(state, "disk-snapshot")) {
|
||||||
|
ret = ((flags & (VIR_DOMAIN_SNAPSHOT_LIST_DISK_ONLY |
|
||||||
|
VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL)) ==
|
||||||
|
(VIR_DOMAIN_SNAPSHOT_LIST_DISK_ONLY |
|
||||||
|
VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL));
|
||||||
|
} else {
|
||||||
|
if (!(flags & VIR_DOMAIN_SNAPSHOT_LIST_INTERNAL))
|
||||||
|
ret = 0;
|
||||||
|
else if (STREQ(state, "shutoff"))
|
||||||
|
ret = !!(flags & VIR_DOMAIN_SNAPSHOT_LIST_INACTIVE);
|
||||||
|
else
|
||||||
|
ret = !!(flags & VIR_DOMAIN_SNAPSHOT_LIST_ACTIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(state);
|
||||||
|
xmlXPathFreeContext(ctxt);
|
||||||
|
xmlFreeDoc(xmldoc);
|
||||||
|
VIR_FREE(xml);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "snapshot-info" command
|
* "snapshot-info" command
|
||||||
*/
|
*/
|
||||||
@ -883,7 +941,7 @@ vshSnapSorter(const void *a, const void *b)
|
|||||||
static vshSnapshotListPtr
|
static vshSnapshotListPtr
|
||||||
vshSnapshotListCollect(vshControl *ctl, virDomainPtr dom,
|
vshSnapshotListCollect(vshControl *ctl, virDomainPtr dom,
|
||||||
virDomainSnapshotPtr from,
|
virDomainSnapshotPtr from,
|
||||||
unsigned int flags, bool tree)
|
unsigned int orig_flags, bool tree)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char **names = NULL;
|
char **names = NULL;
|
||||||
@ -896,6 +954,8 @@ vshSnapshotListCollect(vshControl *ctl, virDomainPtr dom,
|
|||||||
const char *fromname = NULL;
|
const char *fromname = NULL;
|
||||||
int start_index = -1;
|
int start_index = -1;
|
||||||
int deleted = 0;
|
int deleted = 0;
|
||||||
|
bool filter_fallback = false;
|
||||||
|
unsigned int flags = orig_flags;
|
||||||
|
|
||||||
/* Try the interface available in 0.9.13 and newer. */
|
/* Try the interface available in 0.9.13 and newer. */
|
||||||
if (!ctl->useSnapshotOld) {
|
if (!ctl->useSnapshotOld) {
|
||||||
@ -903,6 +963,20 @@ vshSnapshotListCollect(vshControl *ctl, virDomainPtr dom,
|
|||||||
count = virDomainSnapshotListAllChildren(from, &snaps, flags);
|
count = virDomainSnapshotListAllChildren(from, &snaps, flags);
|
||||||
else
|
else
|
||||||
count = virDomainListAllSnapshots(dom, &snaps, flags);
|
count = virDomainListAllSnapshots(dom, &snaps, flags);
|
||||||
|
/* If we failed because of flags added in 1.0.1, we can do
|
||||||
|
* fallback filtering. */
|
||||||
|
if (count < 0 && last_error->code == VIR_ERR_INVALID_ARG &&
|
||||||
|
flags & (VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS |
|
||||||
|
VIR_DOMAIN_SNAPSHOT_FILTERS_LOCATION)) {
|
||||||
|
flags &= ~(VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS |
|
||||||
|
VIR_DOMAIN_SNAPSHOT_FILTERS_LOCATION);
|
||||||
|
vshResetLibvirtError();
|
||||||
|
filter_fallback = true;
|
||||||
|
if (from)
|
||||||
|
count = virDomainSnapshotListAllChildren(from, &snaps, flags);
|
||||||
|
else
|
||||||
|
count = virDomainListAllSnapshots(dom, &snaps, flags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (count >= 0) {
|
if (count >= 0) {
|
||||||
/* When mixing --from and --tree, we also want a copy of from
|
/* When mixing --from and --tree, we also want a copy of from
|
||||||
@ -950,6 +1024,12 @@ vshSnapshotListCollect(vshControl *ctl, virDomainPtr dom,
|
|||||||
return snaplist;
|
return snaplist;
|
||||||
flags &= ~VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA;
|
flags &= ~VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA;
|
||||||
}
|
}
|
||||||
|
if (flags & (VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS |
|
||||||
|
VIR_DOMAIN_SNAPSHOT_FILTERS_LOCATION)) {
|
||||||
|
flags &= ~(VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS |
|
||||||
|
VIR_DOMAIN_SNAPSHOT_FILTERS_LOCATION);
|
||||||
|
filter_fallback = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* This uses the interfaces available in 0.8.0-0.9.6
|
/* This uses the interfaces available in 0.8.0-0.9.6
|
||||||
* (virDomainSnapshotListNames, global list only) and in
|
* (virDomainSnapshotListNames, global list only) and in
|
||||||
@ -1144,6 +1224,29 @@ vshSnapshotListCollect(vshControl *ctl, virDomainPtr dom,
|
|||||||
}
|
}
|
||||||
|
|
||||||
success:
|
success:
|
||||||
|
if (filter_fallback) {
|
||||||
|
/* Older API didn't filter on status or location, but the
|
||||||
|
* information is available in domain XML. */
|
||||||
|
if (!(orig_flags & VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS))
|
||||||
|
orig_flags |= VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS;
|
||||||
|
if (!(orig_flags & VIR_DOMAIN_SNAPSHOT_FILTERS_LOCATION))
|
||||||
|
orig_flags |= VIR_DOMAIN_SNAPSHOT_FILTERS_LOCATION;
|
||||||
|
for (i = 0; i < snaplist->nsnaps; i++) {
|
||||||
|
switch (vshSnapshotFilter(ctl, snaplist->snaps[i].snap,
|
||||||
|
orig_flags)) {
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
virDomainSnapshotFree(snaplist->snaps[i].snap);
|
||||||
|
snaplist->snaps[i].snap = NULL;
|
||||||
|
VIR_FREE(snaplist->snaps[i].parent);
|
||||||
|
deleted++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
qsort(snaplist->snaps, snaplist->nsnaps, sizeof(*snaplist->snaps),
|
qsort(snaplist->snaps, snaplist->nsnaps, sizeof(*snaplist->snaps),
|
||||||
vshSnapSorter);
|
vshSnapSorter);
|
||||||
snaplist->nsnaps -= deleted;
|
snaplist->nsnaps -= deleted;
|
||||||
|
Loading…
Reference in New Issue
Block a user