Backup xml description is like this:
<domainbackup>
<name>backup name</name>
<disks>
<disk type="file" name="sda">
<target file="/path/to/backup/file.qcow2"/>
<driver type="qcow2"/>
</disk>
</disks>
</domainbackup>
1. <name> element is optional.
2. disk @type attribute is optional, default to 'file'. Valid
values are 'file', 'block', 'dir', 'network',
'volume' just
as usual for specifing domain disk sources. It specifies
backup <target> type.
3. <target> element has same attributes and its values as
<source> element in domain disk description.
4. <driver> element is optional. It specifies backup
target format. If it is omitted that target format is
same as domain disks format.
Elements that are not explicitly mentioned as optional are
mandatory. Current description does not support implicitly
specified disks to be backed up like snapshot xml description
for example.
---
A few more notes.
1. introducing virDomainBackupDefParseNode is future proof. We
definitely want to support backups in test driver and its
infrastructure requires such a function.
2. domain, snapshot xmls use <source> element to specify
disk images etc. However this naming is rather unexpected
in case of backups. Let's use <target>. <source> choice
is biased towards domain disk representation.
po/POTFILES.in | 1 +
src/Makefile.am | 1 +
src/conf/backup_conf.c | 259 +++++++++++++++++++++++++++++++++++++++++++++++
src/conf/backup_conf.h | 65 ++++++++++++
src/libvirt_private.syms | 6 ++
src/qemu/qemu_conf.h | 1 +
6 files changed, 333 insertions(+)
create mode 100644 src/conf/backup_conf.c
create mode 100644 src/conf/backup_conf.h
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1469240..2124eb0 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -18,6 +18,7 @@ src/bhyve/bhyve_driver.c
src/bhyve/bhyve_monitor.c
src/bhyve/bhyve_parse_command.c
src/bhyve/bhyve_process.c
+src/conf/backup_conf.c
src/conf/capabilities.c
src/conf/cpu_conf.c
src/conf/device_conf.c
diff --git a/src/Makefile.am b/src/Makefile.am
index eb68728..c04e72c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -335,6 +335,7 @@ DOMAIN_CONF_SOURCES = \
conf/domain_audit.c conf/domain_audit.h \
conf/domain_nwfilter.c conf/domain_nwfilter.h \
conf/snapshot_conf.c conf/snapshot_conf.h \
+ conf/backup_conf.c conf/backup_conf.h \
conf/numa_conf.c conf/numa_conf.h \
conf/virdomainobjlist.c conf/virdomainobjlist.h
diff --git a/src/conf/backup_conf.c b/src/conf/backup_conf.c
new file mode 100644
index 0000000..f8111e9
--- /dev/null
+++ b/src/conf/backup_conf.c
@@ -0,0 +1,259 @@
+/*
+ * backup_conf.c: domain backup XML processing
+ *
+ * Copyright (C) 2016 Virtuozzo
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "internal.h"
+#include "virbitmap.h"
+#include "virbuffer.h"
+#include "count-one-bits.h"
+#include "datatypes.h"
+#include "domain_conf.h"
+#include "virlog.h"
+#include "viralloc.h"
+#include "netdev_bandwidth_conf.h"
+#include "netdev_vport_profile_conf.h"
+#include "nwfilter_conf.h"
+#include "secret_conf.h"
+#include "backup_conf.h"
+#include "virstoragefile.h"
+#include "viruuid.h"
+#include "virfile.h"
+#include "virerror.h"
+#include "virxml.h"
+#include "virstring.h"
+
+#define VIR_FROM_THIS VIR_FROM_DOMAIN_BACKUP
+
+VIR_LOG_INIT("conf.backup_conf");
+
+/* Backup Def functions */
+static void
+virDomainBackupDiskDefClear(virDomainBackupDiskDefPtr disk)
+{
+ VIR_FREE(disk->name);
+ virStorageSourceFree(disk->target);
+ disk->target = NULL;
+}
+
+static int
+virDomainBackupDiskDefParseXML(xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
+ virDomainBackupDiskDefPtr def)
+{
+ int ret = -1;
+ char *type = NULL;
+ char *format = NULL;
+ xmlNodePtr cur;
+ xmlNodePtr saved = ctxt->node;
+ virStorageSourcePtr target;
+
+ ctxt->node = node;
+
+ if (!(def->name = virXMLPropString(node, "name"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing name from disk backup element"));
+ goto cleanup;
+ }
+
+ if (!(cur = virXPathNode("./target", ctxt))) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("missing target for disk '%s'"), def->name);
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC(def->target) < 0)
+ goto cleanup;
+ target = def->target;
+
+ if ((type = virXMLPropString(node, "type"))) {
+ if ((target->type = virStorageTypeFromString(type)) <= 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("unknown disk '%s' backup type
'%s'"),
+ def->name, type);
+ goto cleanup;
+ }
+ } else {
+ target->type = VIR_STORAGE_TYPE_FILE;
+ }
+
+ if (virDomainDiskSourceParse(cur, ctxt, target) < 0)
+ goto cleanup;
+
+ if ((format = virXPathString("string(./driver/@type)", ctxt)) &&
+ (target->format = virStorageFileFormatTypeFromString(format)) <= 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("unknown disk '%s' backup format
'%s'"),
+ def->name, format);
+ goto cleanup;
+ }
+
+ if (virStorageSourceIsLocalStorage(def->target)) {
+ if (!target->path) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("disk '%s' backup path is not
specified"),
+ def->name);
+ goto cleanup;
+ }
+ if (target->path[0] != '/') {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("disk '%s' backup path '%s' must be
absolute"),
+ def->name, target->path);
+ goto cleanup;
+ }
+ }
+
+ ret = 0;
+ cleanup:
+ ctxt->node = saved;
+
+ VIR_FREE(format);
+ VIR_FREE(type);
+ if (ret < 0)
+ virDomainBackupDiskDefClear(def);
+ return ret;
+}
+
+static virDomainBackupDefPtr
+virDomainBackupDefParse(xmlXPathContextPtr ctxt,
+ virCapsPtr caps ATTRIBUTE_UNUSED,
+ virDomainXMLOptionPtr xmlopt ATTRIBUTE_UNUSED,
+ unsigned int fflags ATTRIBUTE_UNUSED)
+{
+ virDomainBackupDefPtr def;
+ virDomainBackupDefPtr ret = NULL;
+ xmlNodePtr *nodes = NULL;
+ size_t i;
+ int n;
+ struct timeval tv;
+
+ if (VIR_ALLOC(def) < 0)
+ return NULL;
+
+ gettimeofday(&tv, NULL);
+
+ if (!(def->name = virXPathString("string(./name)", ctxt)) &&
+ virAsprintf(&def->name, "%lld", (long long)tv.tv_sec) < 0)
+ goto cleanup;
+
+ def->description = virXPathString("string(./description)", ctxt);
+ def->creationTime = tv.tv_sec;
+
+ if ((n = virXPathNodeSet("./disks/*", ctxt, &nodes)) < 0)
+ goto cleanup;
+
+ if (n == 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("no disk is specified to be backed up"));
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC_N(def->disks, n) < 0)
+ goto cleanup;
+ def->ndisks = n;
+
+ for (i = 0; i < def->ndisks; i++) {
+ if (virDomainBackupDiskDefParseXML(nodes[i], ctxt, &def->disks[i]) <
0)
+ goto cleanup;
+ }
+
+ ret = def;
+ def = NULL;
+
+ cleanup:
+ VIR_FREE(nodes);
+ virDomainBackupDefFree(def);
+
+ return ret;
+}
+
+virDomainBackupDefPtr
+virDomainBackupDefParseNode(xmlDocPtr xml,
+ xmlNodePtr root,
+ virCapsPtr caps,
+ virDomainXMLOptionPtr xmlopt,
+ unsigned int flags)
+{
+ xmlXPathContextPtr ctxt = NULL;
+ virDomainBackupDefPtr def = NULL;
+
+ if (!xmlStrEqual(root->name, BAD_CAST "domainbackup")) {
+ virReportError(VIR_ERR_XML_ERROR, "%s", _("domainbackup"));
+ goto cleanup;
+ }
+
+ ctxt = xmlXPathNewContext(xml);
+ if (ctxt == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ctxt->node = root;
+ def = virDomainBackupDefParse(ctxt, caps, xmlopt, flags);
+
+ cleanup:
+ xmlXPathFreeContext(ctxt);
+ return def;
+}
+
+virDomainBackupDefPtr
+virDomainBackupDefParseString(const char *xmlStr,
+ virCapsPtr caps,
+ virDomainXMLOptionPtr xmlopt,
+ unsigned int flags)
+{
+ virDomainBackupDefPtr ret = NULL;
+ xmlDocPtr xml;
+ int keepBlanksDefault = xmlKeepBlanksDefault(0);
+
+ if ((xml = virXMLParse(NULL, xmlStr, _("(domain_backup)")))) {
+ xmlKeepBlanksDefault(keepBlanksDefault);
+ ret = virDomainBackupDefParseNode(xml, xmlDocGetRootElement(xml),
+ caps, xmlopt, flags);
+ xmlFreeDoc(xml);
+ }
+ xmlKeepBlanksDefault(keepBlanksDefault);
+
+ return ret;
+}
+
+void
+virDomainBackupDefFree(virDomainBackupDefPtr def)
+{
+ size_t i;
+
+ if (!def)
+ return;
+
+ VIR_FREE(def->name);
+ VIR_FREE(def->description);
+
+ for (i = 0; i < def->ndisks; i++)
+ virDomainBackupDiskDefClear(&def->disks[i]);
+ VIR_FREE(def->disks);
+
+ VIR_FREE(def);
+}
diff --git a/src/conf/backup_conf.h b/src/conf/backup_conf.h
new file mode 100644
index 0000000..223fc19
--- /dev/null
+++ b/src/conf/backup_conf.h
@@ -0,0 +1,65 @@
+/*
+ * backup_conf.h: domain backup XML processing
+ *
+ * Copyright (C) 2016 Virtuozzo
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __BACKUP_CONF_H
+# define __BACKUP_CONF_H
+
+# include "internal.h"
+# include "domain_conf.h"
+
+/* Items related to backup state */
+
+/* Stores disk-backup information */
+typedef struct _virDomainBackupDiskDef virDomainBackupDiskDef;
+typedef virDomainBackupDiskDef *virDomainBackupDiskDefPtr;
+struct _virDomainBackupDiskDef {
+ char *name; /* name matching the <target dev='...' of the domain */
+ virStorageSourcePtr target;
+};
+
+/* Stores the complete backup metadata */
+typedef struct _virDomainBackupDef virDomainBackupDef;
+typedef virDomainBackupDef *virDomainBackupDefPtr;
+struct _virDomainBackupDef {
+ /* Public XML. */
+ char *name;
+ char *description;
+ long long creationTime; /* in seconds */
+
+ size_t ndisks; /* should not exceed dom->ndisks */
+ virDomainBackupDiskDef *disks;
+};
+
+virDomainBackupDefPtr
+virDomainBackupDefParseString(const char *xmlStr,
+ virCapsPtr caps,
+ virDomainXMLOptionPtr xmlopt,
+ unsigned int flags);
+virDomainBackupDefPtr
+virDomainBackupDefParseNode(xmlDocPtr xml,
+ xmlNodePtr root,
+ virCapsPtr caps,
+ virDomainXMLOptionPtr xmlopt,
+ unsigned int flags);
+void
+virDomainBackupDefFree(virDomainBackupDefPtr def);
+
+#endif /* __BACKUP_CONF_H */
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index c85602c..beeee9b 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -42,6 +42,12 @@ virAccessPermStorageVolTypeFromString;
virAccessPermStorageVolTypeToString;
+# conf/backup_conf.h
+virDomainBackupDefFree;
+virDomainBackupDefParseNode;
+virDomainBackupDefParseString;
+
+
# conf/capabilities.h
virCapabilitiesAddGuest;
virCapabilitiesAddGuestDomain;
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 12b2661..b322ee6 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -32,6 +32,7 @@
# include "network_conf.h"
# include "domain_conf.h"
# include "snapshot_conf.h"
+# include "backup_conf.h"
# include "domain_event.h"
# include "virthread.h"
# include "security/security_manager.h"
--
1.8.3.1