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