snapshots, as described above. Readonly.
</dd>
<dt><code>domain</code></dt>
- <dd>The domain that this snapshot was taken against. This
- element contains exactly one child element, uuid. This
- specifies the uuid of the domain that this snapshot was taken
- against. Readonly.
+ <dd>The domain that this snapshot was taken against. Older
+ versions of libvirt stored only a single child element, uuid;
+ reverting to a snapshot like this is risky if the current
+ state of the domain differs from the state that the domain was
+ created in, and requires the use of the
+ <code>VIR_DOMAIN_SNAPSHOT_REVERT_FORCE</code> flag
+ in <code>virDomainRevertToSnapshot()</code>. Newer versions
+ of libvirt store the entire
+ inactive <a href="formatdomain.html">domain configuration</a>
+ at the time of the snapshot (<span class="since">since
+ 0.9.5</span>). Readonly.
</dd>
</dl>
- <h2><a name="example">Example</a></h2>
+ <h2><a name="example">Examples</a></h2>
+ <p>Using this XML on creation:</p>
<pre>
<domainsnapshot>
- <name>os-updates</name>
+ <description>Snapshot of OS install and updates</description>
+</domainsnapshot></pre>
+
+ <p>will result in XML similar to this from
+ virDomainSnapshotGetXMLDesc:</p>
+ <pre>
+<domainsnapshot>
+ <name>1270477159</name>
<description>Snapshot of OS install and updates</description>
<state>running</state>
<creationTime>1270477159</creationTime>
<name>bare-os-install</name>
</parent>
<domain>
+ <name>fedora</name>
<uuid>93a5c045-6457-2c09-e56c-927cdf34e178</uuid>
+ <memory>1048576</memory>
+ ...
+ </devices>
</domain>
</domainsnapshot></pre>
</body>
VIR_FREE(def->name);
VIR_FREE(def->description);
VIR_FREE(def->parent);
+ virDomainDefFree(def->dom);
VIR_FREE(def);
}
-/* flags are from virDomainSnapshotParseFlags */
+/* flags is bitwise-or of virDomainSnapshotParseFlags.
+ * If flags does not include VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE, then
+ * caps and expectedVirtTypes are ignored.
+ */
virDomainSnapshotDefPtr
-virDomainSnapshotDefParseString(const char *xmlStr, unsigned int flags)
+virDomainSnapshotDefParseString(const char *xmlStr,
+ virCapsPtr caps,
+ unsigned int expectedVirtTypes,
+ unsigned int flags)
{
xmlXPathContextPtr ctxt = NULL;
xmlDocPtr xml = NULL;
char *creation = NULL, *state = NULL;
struct timeval tv;
int active;
+ char *tmp;
xml = virXMLParseCtxt(NULL, xmlStr, "domainsnapshot.xml", &ctxt);
if (!xml) {
state);
goto cleanup;
}
+
+ /* Older snapshots were created with just <domain>/<uuid>, and
+ * lack domain/@type. In that case, leave dom NULL, and
+ * clients will have to decide between best effort
+ * initialization or outright failure. */
+ if ((tmp = virXPathString("string(./domain/@type)", ctxt))) {
+ xmlNodePtr domainNode = virXPathNode("./domain", ctxt);
+
+ VIR_FREE(tmp);
+ if (!domainNode) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing domain in snapshot"));
+ goto cleanup;
+ }
+ def->dom = virDomainDefParseNode(caps, xml, domainNode,
+ expectedVirtTypes,
+ (VIR_DOMAIN_XML_INACTIVE |
+ VIR_DOMAIN_XML_SECURE));
+ if (!def->dom)
+ goto cleanup;
+ } else {
+ VIR_WARN("parsing older snapshot that lacks domain");
+ }
} else {
def->creationTime = tv.tv_sec;
}
char *virDomainSnapshotDefFormat(char *domain_uuid,
virDomainSnapshotDefPtr def,
+ unsigned int flags,
int internal)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
+ virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
+
+ flags |= VIR_DOMAIN_XML_INACTIVE;
+
virBufferAddLit(&buf, "<domainsnapshot>\n");
virBufferAsprintf(&buf, " <name>%s</name>\n", def->name);
if (def->description)
}
virBufferAsprintf(&buf, " <creationTime>%lld</creationTime>\n",
def->creationTime);
- virBufferAddLit(&buf, " <domain>\n");
- virBufferAsprintf(&buf, " <uuid>%s</uuid>\n", domain_uuid);
- virBufferAddLit(&buf, " </domain>\n");
+ if (def->dom) {
+ virDomainDefFormatInternal(def->dom, flags, &buf);
+ } else {
+ virBufferAddLit(&buf, " <domain>\n");
+ virBufferAsprintf(&buf, " <uuid>%s</uuid>\n", domain_uuid);
+ virBufferAddLit(&buf, " </domain>\n");
+ }
if (internal)
virBufferAsprintf(&buf, " <active>%d</active>\n", def->current);
virBufferAddLit(&buf, "</domainsnapshot>\n");
char *parent;
long long creationTime; /* in seconds */
int state;
+ virDomainDefPtr dom;
/* Internal use. */
bool current; /* At most one snapshot in the list should have this set */
} virDomainSnapshotParseFlags;
virDomainSnapshotDefPtr virDomainSnapshotDefParseString(const char *xmlStr,
+ virCapsPtr caps,
+ unsigned int expectedVirtTypes,
unsigned int flags);
void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def);
char *virDomainSnapshotDefFormat(char *domain_uuid,
virDomainSnapshotDefPtr def,
+ unsigned int flags,
int internal);
virDomainSnapshotObjPtr virDomainSnapshotAssignDef(virDomainSnapshotObjListPtr snapshots,
const virDomainSnapshotDefPtr def);
return NULL;
}
- def = virDomainSnapshotDefParseString(xmlDesc, 0);
+ def = virDomainSnapshotDefParseString(xmlDesc, NULL, 0, 0);
if (def == NULL) {
return NULL;
virUUIDFormat(snapshot->domain->uuid, uuid_string);
- xml = virDomainSnapshotDefFormat(uuid_string, &def, 0);
+ xml = virDomainSnapshotDefFormat(uuid_string, &def, flags, 0);
cleanup:
esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
/**
* virDomainSnapshotGetXMLDesc:
* @snapshot: a domain snapshot object
- * @flags: unused flag parameters; callers should pass 0
+ * @flags: bitwise-OR of subset of virDomainXMLFlags
*
* Provide an XML description of the domain snapshot.
*
+ * 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.
*/
continue;
}
- def = virDomainSnapshotDefParseString(xmlStr, flags);
+ def = virDomainSnapshotDefParseString(xmlStr, qemu_driver->caps,
+ QEMU_EXPECTED_VIRT_TYPES,
+ flags);
if (def == NULL) {
/* Nothing we can do here, skip this one */
VIR_ERROR(_("Failed to parse snapshot XML from file '%s'"),
char *snapDir = NULL;
char *snapFile = NULL;
char uuidstr[VIR_UUID_STRING_BUFLEN];
+ char *tmp;
virUUIDFormat(vm->def->uuid, uuidstr);
- newxml = virDomainSnapshotDefFormat(uuidstr, snapshot->def, 1);
+ newxml = virDomainSnapshotDefFormat(uuidstr, snapshot->def,
+ VIR_DOMAIN_XML_SECURE, 1);
if (newxml == NULL) {
virReportOOMError();
return -1;
_("failed to create snapshot file '%s'"), snapFile);
goto cleanup;
}
+
+ if (virAsprintf(&tmp, "snapshot-edit %s", vm->def->name) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ virEmitXMLWarning(fd, snapshot->def->name, tmp);
+ VIR_FREE(tmp);
+
if (safewrite(fd, newxml, strlen(newxml)) != strlen(newxml)) {
virReportSystemError(errno, _("Failed to write snapshot data to %s"),
snapFile);
if (!qemuDomainSnapshotIsAllowed(vm))
goto cleanup;
- if (!(def = virDomainSnapshotDefParseString(xmlDesc, parse_flags)))
+ if (!(def = virDomainSnapshotDefParseString(xmlDesc, driver->caps,
+ QEMU_EXPECTED_VIRT_TYPES,
+ parse_flags)))
goto cleanup;
if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
virDomainSnapshotObjPtr snap = NULL;
char uuidstr[VIR_UUID_STRING_BUFLEN];
- /* XXX Actually wire this up once we return domain xml; for now,
- * it is trivially safe to ignore this flag. */
virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
qemuDriverLock(driver);
goto cleanup;
}
- xml = virDomainSnapshotDefFormat(uuidstr, snap->def, 0);
+ xml = virDomainSnapshotDefFormat(uuidstr, snap->def, flags, 0);
cleanup:
if (vm)
/* VBox has no snapshot metadata, so this flag is trivial. */
virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
- if (!(def = virDomainSnapshotDefParseString(xmlDesc, 0)))
+ if (!(def = virDomainSnapshotDefParseString(xmlDesc, NULL, 0, 0)))
goto cleanup;
vboxIIDFromUUID(&domiid, dom->uuid);
def->state = VIR_DOMAIN_SHUTOFF;
virUUIDFormat(dom->uuid, uuidstr);
- ret = virDomainSnapshotDefFormat(uuidstr, def, 0);
+ ret = virDomainSnapshotDefFormat(uuidstr, def, flags, 0);
cleanup:
virDomainSnapshotDefFree(def);