Right now, copying the state of a transient domain with snapshots from one host to another requires multiple API calls on both machines - on the host: get the domain XML, get a list of the snapshots, and then for each snapshot get the snapshot's XML; then on the destination: create the domain, then multiple domain snapshot create calls with the REDEFINE flag. This patch aims to make the process use fewer APIs by making it possible to grab the XML for all snapshots at the same time as grabbing the domain XML. Note that we had to do the modification to virDomainGetXMLDesc(), rather than virDomainSnapshotGetXMLDesc(), since the latter requires a single non-NULL snapshot object, whereas we want the list of all snapshots for the domain (even if the list has 0 elements).
The new information is provided as: <domain ...> ... </devices> <snapshots current='name'> <domainsnapshot> ... </domainsnapshot> <domainsnapshot> ... </domainsnapshot> </snapshots> </domain> For now, I did not modify the schema to permit this information during virDomainDefineXML; it is still necessary to use virDomainSnapshotCreateXML with VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE multiple times to recreate the added state output here. Unfortunately, libvirt versions between 1.2.12 and 5.0.0 will silently ignore the new flag, rather than diagnosing that they don't support it; but at least silent lack of snapshots from an older server is not a security hole. Plumb the new flag into the test and qemu driver, and into virsh dumpxml. Signed-off-by: Eric Blake <ebl...@redhat.com> --- include/libvirt/libvirt-domain.h | 1 + src/conf/domain_conf.c | 13 ++++++++----- src/libvirt-domain.c | 5 +++++ src/qemu/qemu_domain.c | 23 +++++++++++++++++------ src/qemu/qemu_driver.c | 4 ++-- src/test/test_driver.c | 7 ++++--- tools/virsh-domain.c | 7 +++++++ 7 files changed, 44 insertions(+), 16 deletions(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 1d5bdb545d..a8ebb68388 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -1570,6 +1570,7 @@ typedef enum { VIR_DOMAIN_XML_INACTIVE = (1 << 1), /* dump inactive domain information */ VIR_DOMAIN_XML_UPDATE_CPU = (1 << 2), /* update guest CPU requirements according to host CPU */ VIR_DOMAIN_XML_MIGRATABLE = (1 << 3), /* dump XML suitable for migration */ + VIR_DOMAIN_XML_SNAPSHOTS = (1 << 4), /* include all snapshots in the dump */ } virDomainXMLFlags; typedef enum { diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index ae496834ee..88cb2d8ae5 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -29109,11 +29109,12 @@ virDomainDefFormatInternal(virDomainDefPtr def, return -1; } -/* Converts VIR_DOMAIN_XML_COMMON_FLAGS into VIR_DOMAIN_DEF_FORMAT_* - * flags, and silently ignores any other flags. Note that the caller - * should validate the set of flags it is willing to accept; see also - * the comment on VIR_DOMAIN_XML_COMMON_FLAGS about security - * considerations with adding new flags. */ +/* Converts VIR_DOMAIN_XML_COMMON_FLAGS and VIR_DOMAIN_XML_SNAPSHOTS + * into VIR_DOMAIN_DEF_FORMAT_* flags, and silently ignores any other + * flags. Note that the caller should validate the set of flags it is + * willing to accept; see also the comment on + * VIR_DOMAIN_XML_COMMON_FLAGS about security considerations with + * adding new flags. */ unsigned int virDomainDefFormatConvertXMLFlags(unsigned int flags) { unsigned int formatFlags = 0; @@ -29124,6 +29125,8 @@ unsigned int virDomainDefFormatConvertXMLFlags(unsigned int flags) formatFlags |= VIR_DOMAIN_DEF_FORMAT_INACTIVE; if (flags & VIR_DOMAIN_XML_MIGRATABLE) formatFlags |= VIR_DOMAIN_DEF_FORMAT_MIGRATABLE; + if (flags & VIR_DOMAIN_XML_SNAPSHOTS) + formatFlags |= VIR_DOMAIN_DEF_FORMAT_SNAPSHOTS; return formatFlags; } diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index 072b92b717..2691698bd5 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -2570,6 +2570,11 @@ virDomainGetControlInfo(virDomainPtr domain, * XML might not validate against the schema, so it is mainly for * internal use. * + * If @flags contains VIR_DOMAIN_XML_SNAPSHOTS, the XML will include + * an additional <snapshots> child element describing all snapshots + * belonging to the domain, including an attribute current='name' if + * one of those snapshots is current. + * * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error. * the caller must free() the returned value. */ diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 51d1b19c00..da0fde78a6 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -7715,6 +7715,7 @@ qemuDomainDefCopy(virQEMUDriverPtr driver, static int qemuDomainDefFormatBufInternal(virQEMUDriverPtr driver, + virDomainObjPtr vm, virDomainDefPtr def, virCPUDefPtr origCPU, unsigned int flags, @@ -7724,6 +7725,7 @@ qemuDomainDefFormatBufInternal(virQEMUDriverPtr driver, virDomainDefPtr copy = NULL; virCapsPtr caps = NULL; virQEMUCapsPtr qemuCaps = NULL; + bool snapshots = flags & VIR_DOMAIN_XML_SNAPSHOTS; virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS | VIR_DOMAIN_XML_UPDATE_CPU, -1); @@ -7892,7 +7894,14 @@ qemuDomainDefFormatBufInternal(virQEMUDriverPtr driver, } format: - ret = virDomainDefFormatInternal(def, caps, NULL, NULL, + if (snapshots && !vm) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("snapshots XML requested but not provided")); + goto cleanup; + } + ret = virDomainDefFormatInternal(def, caps, + snapshots ? vm->snapshots : NULL, + snapshots ? vm->current_snapshot : NULL, virDomainDefFormatConvertXMLFlags(flags), buf, driver->xmlopt); @@ -7910,19 +7919,21 @@ qemuDomainDefFormatBuf(virQEMUDriverPtr driver, unsigned int flags, virBufferPtr buf) { - return qemuDomainDefFormatBufInternal(driver, def, NULL, flags, buf); + return qemuDomainDefFormatBufInternal(driver, NULL, def, NULL, flags, buf); } static char * qemuDomainDefFormatXMLInternal(virQEMUDriverPtr driver, + virDomainObjPtr vm, virDomainDefPtr def, virCPUDefPtr origCPU, unsigned int flags) { virBuffer buf = VIR_BUFFER_INITIALIZER; - if (qemuDomainDefFormatBufInternal(driver, def, origCPU, flags, &buf) < 0) + if (qemuDomainDefFormatBufInternal(driver, vm, def, origCPU, flags, + &buf) < 0) return NULL; return virBufferContentAndReset(&buf); @@ -7934,7 +7945,7 @@ qemuDomainDefFormatXML(virQEMUDriverPtr driver, virDomainDefPtr def, unsigned int flags) { - return qemuDomainDefFormatXMLInternal(driver, def, NULL, flags); + return qemuDomainDefFormatXMLInternal(driver, NULL, def, NULL, flags); } @@ -7953,7 +7964,7 @@ char *qemuDomainFormatXML(virQEMUDriverPtr driver, origCPU = priv->origCPU; } - return qemuDomainDefFormatXMLInternal(driver, def, origCPU, flags); + return qemuDomainDefFormatXMLInternal(driver, vm, def, origCPU, flags); } char * @@ -7970,7 +7981,7 @@ qemuDomainDefFormatLive(virQEMUDriverPtr driver, if (compatible) flags |= VIR_DOMAIN_XML_MIGRATABLE; - return qemuDomainDefFormatXMLInternal(driver, def, origCPU, flags); + return qemuDomainDefFormatXMLInternal(driver, NULL, def, origCPU, flags); } diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 7cfeed4479..07323d2efc 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7337,8 +7337,8 @@ static char virDomainObjPtr vm; char *ret = NULL; - virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS | VIR_DOMAIN_XML_UPDATE_CPU, - NULL); + virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS | VIR_DOMAIN_XML_UPDATE_CPU | + VIR_DOMAIN_XML_SNAPSHOTS, NULL); if (!(vm = qemuDomObjFromDomain(dom))) goto cleanup; diff --git a/src/test/test_driver.c b/src/test/test_driver.c index a6a67d42e2..e810207af0 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -2628,7 +2628,7 @@ static char *testDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) virDomainObjPtr privdom; char *ret = NULL; - virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS, NULL); + virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS | VIR_DOMAIN_XML_SNAPSHOTS, NULL); if (!(privdom = testDomObjFromDomain(domain))) return NULL; @@ -2636,8 +2636,9 @@ static char *testDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) def = (flags & VIR_DOMAIN_XML_INACTIVE) && privdom->newDef ? privdom->newDef : privdom->def; - ret = virDomainDefFormat(def, privconn->caps, - virDomainDefFormatConvertXMLFlags(flags)); + ret = virDomainDefFormatFull(def, privconn->caps, + privdom->snapshots, privdom->current_snapshot, + virDomainDefFormatConvertXMLFlags(flags)); virDomainObjEndAPI(&privdom); return ret; diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 5699018dcc..78854b1e0a 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -10055,6 +10055,10 @@ static const vshCmdOptDef opts_dumpxml[] = { .type = VSH_OT_BOOL, .help = N_("provide XML suitable for migrations") }, + {.name = "snapshots", + .type = VSH_OT_BOOL, + .help = N_("include all domain snapshots in XML dump"), + }, {.name = NULL} }; @@ -10069,6 +10073,7 @@ cmdDumpXML(vshControl *ctl, const vshCmd *cmd) bool secure = vshCommandOptBool(cmd, "security-info"); bool update = vshCommandOptBool(cmd, "update-cpu"); bool migratable = vshCommandOptBool(cmd, "migratable"); + bool snapshots = vshCommandOptBool(cmd, "snapshots"); if (inactive) flags |= VIR_DOMAIN_XML_INACTIVE; @@ -10078,6 +10083,8 @@ cmdDumpXML(vshControl *ctl, const vshCmd *cmd) flags |= VIR_DOMAIN_XML_UPDATE_CPU; if (migratable) flags |= VIR_DOMAIN_XML_MIGRATABLE; + if (snapshots) + flags |= VIR_DOMAIN_XML_SNAPSHOTS; if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) return false; -- 2.20.1 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list