Modifying the xml on either save or restore only gets you so far - you have to remember to 'virsh dumpxml dom' just prior to the 'virsh save' in order to have an xml file worth modifying that won't be rejected due to abi breaks. To make this more powerful, we need a way to grab the xml embedded within a state file, and from there, it's not much harder to also support modifying a state file in-place. Also, virDomainGetXMLDesc didn't document its flags. * include/libvirt/libvirt.h.in (virDomainSaveImageGetXMLDesc) (virDomainSaveImageDefineXML): New prototypes. * src/libvirt.c (virDomainSaveImageGetXMLDesc) (virDomainSaveImageDefineXML): New API. * src/libvirt_public.syms: Export them. * src/driver.h (virDrvDomainSaveImageGetXMLDesc) (virDrvDomainSaveImgeDefineXML): New driver callbacks. --- I've waffled over various choices for naming this API, such as virConnectDomainSaveGetXMLDesc, but I think what I've chosen works out well - it creates the new virDomainSaveImage* prefix for use with any other commands that might also later operate on a domain saved state file. Saved state is always inactive (the guest shuts down during virDomainSave), so the VIR_DOMAIN_XML_INACTIVE flag would be a no-op if it were accepted; I suppose I could silently ignore it, but as written the patches reject it instead. I'm not sure whether VIR_DOMAIN_XML_UPDATE_CPU makes sense, so I rejected it. include/libvirt/libvirt.h.in | 9 ++- src/driver.h | 11 +++ src/libvirt.c | 158 +++++++++++++++++++++++++++++++++++++++++- src/libvirt_public.syms | 2 + 4 files changed, 178 insertions(+), 2 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 20c5109..fa0eeb4 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -966,6 +966,14 @@ int virDomainRestoreFlags (virConnectPtr conn, const char *dxml, unsigned int flags); +char * virDomainSaveImageGetXMLDesc (virConnectPtr conn, + const char *file, + unsigned int flags); +int virDomainSaveImageDefineXML (virConnectPtr conn, + const char *file, + const char *dxml, + unsigned int flags); + /* * Managed domain save */ diff --git a/src/driver.h b/src/driver.h index d931c9b..8d583ba 100644 --- a/src/driver.h +++ b/src/driver.h @@ -190,6 +190,15 @@ typedef int const char *from, const char *dxml, unsigned int flags); +typedef char * + (*virDrvDomainSaveImageGetXMLDesc) (virConnectPtr conn, + const char *file, + unsigned int flags); +typedef int + (*virDrvDomainSaveImageDefineXML) (virConnectPtr conn, + const char *file, + const char *dxml, + unsigned int flags); typedef int (*virDrvDomainCoreDump) (virDomainPtr domain, const char *to, @@ -727,6 +736,8 @@ struct _virDriver { virDrvDomainSaveFlags domainSaveFlags; virDrvDomainRestore domainRestore; virDrvDomainRestoreFlags domainRestoreFlags; + virDrvDomainSaveImageGetXMLDesc domainSaveImageGetXMLDesc; + virDrvDomainSaveImageDefineXML domainSaveImageDefineXML; virDrvDomainCoreDump domainCoreDump; virDrvDomainScreenshot domainScreenshot; virDrvDomainSetVcpus domainSetVcpus; diff --git a/src/libvirt.c b/src/libvirt.c index c769589..ee550be 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -2242,7 +2242,9 @@ error: * listed as running anymore (this may be a problem). * Use virDomainRestore() to restore a domain after saving. * - * See virDomainSaveFlags() for more control. + * See virDomainSaveFlags() for more control. Also, a save file can + * be inspected or modified slightly with virDomainSaveImageGetXMLDesc() + * and virDomainSaveImageDefineXML(). * * Returns 0 in case of success and -1 in case of failure. */ @@ -2321,6 +2323,9 @@ error: * fail if it cannot do so for the given system; this can allow less * pressure on file system cache, but also risks slowing saves to NFS. * + * A save file can be inspected or modified slightly with + * virDomainSaveImageGetXMLDesc() and virDomainSaveImageDefineXML(). + * * Returns 0 in case of success and -1 in case of failure. */ int @@ -2510,6 +2515,147 @@ error: } /** + * virDomainSaveImageGetXMLDesc: + * @conn: pointer to the hypervisor connection + * @file: path to saved state file + * @flags: bitwise-OR of subset of virDomainXMLFlags + * + * This method will extract the XML describing the domain at the time + * a saved state file was created. @file must be a file created + * previously by virDomainSave() or virDomainSaveFlags(). + * + * No security-sensitive data will be included unless @flags contains + * VIR_DOMAIN_XML_SECURE; this flag is rejected on read-only + * connections. For this API, @flags should not contain either + * VIR_DOMAIN_XML_INACTIVE or VIR_DOMAIN_XML_UPDATE_CPU. + * + * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of + * error. The caller must free() the returned value. + */ +char * +virDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *file, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, file=%s, flags=%x", + conn, file, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return NULL; + } + if (file == NULL) { + virLibConnError(VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + if ((conn->flags & VIR_CONNECT_RO) && (flags & VIR_DOMAIN_XML_SECURE)) { + virLibConnError(VIR_ERR_OPERATION_DENIED, + _("virDomainSaveImageGetXMLDesc with secure flag")); + goto error; + } + + if (conn->driver->domainSaveImageGetXMLDesc) { + char *ret; + char *absolute_file; + + /* We must absolutize the file path as the read is done out of process */ + if (virFileAbsPath(file, &absolute_file) < 0) { + virLibConnError(VIR_ERR_INTERNAL_ERROR, + _("could not build absolute input file path")); + goto error; + } + + ret = conn->driver->domainSaveImageGetXMLDesc(conn, absolute_file, + flags); + + VIR_FREE(absolute_file); + + if (!ret) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return NULL; +} + +/** + * virDomainSaveImageDefineXML: + * @conn: pointer to the hypervisor connection + * @file: path to saved state file + * @dxml: XML config for adjusting guest xml used on restore + * @flags: 0 for now + * + * This updates the definition of a domain stored in a saved state + * file. @file must be a file created previously by virDomainSave() + * or virDomainSaveFlags(). + * + * @dxml can be used to alter host-specific portions of the domain XML + * that will be used when restoring an image. For example, it is + * possible to alter the backing filename that is associated with a + * disk device, to match renaming done as part of backing up the disk + * device while the domain is stopped. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virDomainSaveImageDefineXML(virConnectPtr conn, const char *file, + const char *dxml, unsigned int flags) +{ + VIR_DEBUG("conn=%p, file=%s, dxml=%s, flags=%x", + conn, file, dxml, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + if (conn->flags & VIR_CONNECT_RO) { + virLibConnError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + if (!file || !dxml) { + virLibConnError(VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + if (conn->driver->domainSaveImageDefineXML) { + int ret; + char *absolute_file; + + /* We must absolutize the file path as the read is done out of process */ + if (virFileAbsPath(file, &absolute_file) < 0) { + virLibConnError(VIR_ERR_INTERNAL_ERROR, + _("could not build absolute input file path")); + goto error; + } + + ret = conn->driver->domainSaveImageDefineXML(conn, absolute_file, + dxml, flags); + + VIR_FREE(absolute_file); + + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} + +/** * virDomainCoreDump: * @domain: a domain object * @to: path for the core file @@ -3523,6 +3669,16 @@ error: * Provide an XML description of the domain. The description may be reused * later to relaunch the domain with virDomainCreateXML(). * + * No security-sensitive data will be included unless @flags contains + * VIR_DOMAIN_XML_SECURE; this flag is rejected on read-only + * connections. If @flags includes VIR_DOMAIN_XML_INACTIVE, then the + * XML represents the configuration that will be used on the next boot + * of a persistent domain; otherwise, the configuration represents the + * currently running domain. If @flags contains + * VIR_DOMAIN_XML_UPDATE_CPU, then the portion of the domain XML + * describing CPU capabilities is modified to match actual + * capabilities of the host. + * * 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/libvirt_public.syms b/src/libvirt_public.syms index 6935140..773291a 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -470,6 +470,8 @@ LIBVIRT_0.9.4 { global: virDomainRestoreFlags; virDomainSaveFlags; + virDomainSaveImageDefineXML; + virDomainSaveImageGetXMLDesc; virDomainUndefineFlags; } LIBVIRT_0.9.3; -- 1.7.4.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list