---
include/libvirt/virterror.h | 2 +
src/Makefile.am | 2 +
src/datatypes.c | 60 +++++++++++++
src/datatypes.h | 29 ++++++
src/driver-hypervisor.h | 5 ++
src/libvirt-domain-backup.c | 209 ++++++++++++++++++++++++++++++++++++++++++++
src/libvirt_private.syms | 2 +
src/libvirt_public.syms | 10 +++
src/util/virerror.c | 6 ++
9 files changed, 325 insertions(+)
create mode 100644 src/libvirt-domain-backup.c
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index 2efee8f..c9ae10e 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -132,6 +132,7 @@ typedef enum {
VIR_FROM_PERF = 65, /* Error from perf */
VIR_FROM_LIBSSH = 66, /* Error from libssh connection transport */
+ VIR_FROM_DOMAIN_BACKUP = 67,/* Error from domain backup */
# ifdef VIR_ENUM_SENTINELS
VIR_ERR_DOMAIN_LAST
@@ -319,6 +320,7 @@ typedef enum {
VIR_ERR_AGENT_UNSYNCED = 97, /* guest agent replies with wrong id
to guest-sync command */
VIR_ERR_LIBSSH = 98, /* error in libssh transport driver */
+ VIR_ERR_INVALID_DOMAIN_BACKUP = 99, /* invalid domain backup */
} virErrorNumber;
/**
diff --git a/src/Makefile.am b/src/Makefile.am
index f95f30e..c4ffc2f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -287,6 +287,7 @@ DRIVER_SOURCES = \
libvirt.c libvirt_internal.h \
libvirt-domain.c \
libvirt-domain-snapshot.c \
+ libvirt-domain-backup.c \
libvirt-host.c \
libvirt-interface.c \
libvirt-network.c \
@@ -2682,6 +2683,7 @@ libvirt_setuid_rpc_client_la_SOURCES = \
libvirt.c \
libvirt-domain.c \
libvirt-domain-snapshot.c \
+ libvirt-domain-backup.c \
libvirt-host.c \
libvirt-interface.c \
libvirt-network.c \
diff --git a/src/datatypes.c b/src/datatypes.c
index 59ba956..365687c 100644
--- a/src/datatypes.c
+++ b/src/datatypes.c
@@ -37,6 +37,7 @@ virClassPtr virConnectClass;
virClassPtr virConnectCloseCallbackDataClass;
virClassPtr virDomainClass;
virClassPtr virDomainSnapshotClass;
+virClassPtr virDomainBackupClass;
virClassPtr virInterfaceClass;
virClassPtr virNetworkClass;
virClassPtr virNodeDeviceClass;
@@ -50,6 +51,7 @@ static void virConnectDispose(void *obj);
static void virConnectCloseCallbackDataDispose(void *obj);
static void virDomainDispose(void *obj);
static void virDomainSnapshotDispose(void *obj);
+static void virDomainBackupDispose(void *obj);
static void virInterfaceDispose(void *obj);
static void virNetworkDispose(void *obj);
static void virNodeDeviceDispose(void *obj);
@@ -88,6 +90,7 @@ virDataTypesOnceInit(void)
DECLARE_CLASS_LOCKABLE(virConnectCloseCallbackData);
DECLARE_CLASS(virDomain);
DECLARE_CLASS(virDomainSnapshot);
+ DECLARE_CLASS(virDomainBackup);
DECLARE_CLASS(virInterface);
DECLARE_CLASS(virNetwork);
DECLARE_CLASS(virNodeDevice);
@@ -891,6 +894,63 @@ virDomainSnapshotDispose(void *obj)
}
+/**
+ * virGetDomainBackup:
+ * @domain: the domain to backup
+ * @name: pointer to the domain backup name
+ *
+ * Allocates a new domain backup object. When the object is no longer needed,
+ * virObjectUnref() must be called in order to not leak data.
+ *
+ * Returns a pointer to the domain backup object, or NULL on error.
+ */
+virDomainBackupPtr
+virGetDomainBackup(virDomainPtr domain, const char *name)
+{
+ virDomainBackupPtr ret = NULL;
+
+ if (virDataTypesInitialize() < 0)
+ return NULL;
+
+ virCheckDomainGoto(domain, error);
+ virCheckNonNullArgGoto(name, error);
+
+ if (!(ret = virObjectNew(virDomainBackupClass)))
+ goto error;
+ if (VIR_STRDUP(ret->name, name) < 0)
+ goto error;
+
+ ret->domain = virObjectRef(domain);
+
+ return ret;
+
+ error:
+ virObjectUnref(ret);
+ return NULL;
+}
+
+
+/**
+ * virDomainBackupDispose:
+ * @obj: the domain backup to release
+ *
+ * Unconditionally release all memory associated with a backup.
+ * The backup object must not be used once this method returns.
+ *
+ * It will also unreference the associated connection object,
+ * which may also be released if its ref count hits zero.
+ */
+static void
+virDomainBackupDispose(void *obj)
+{
+ virDomainBackupPtr backup = obj;
+ VIR_DEBUG("release backup %p %s", backup, backup->name);
+
+ VIR_FREE(backup->name);
+ virObjectUnref(backup->domain);
+}
+
+
virAdmConnectPtr
virAdmConnectNew(void)
{
diff --git a/src/datatypes.h b/src/datatypes.h
index 288e057..54006ef 100644
--- a/src/datatypes.h
+++ b/src/datatypes.h
@@ -32,6 +32,7 @@
extern virClassPtr virConnectClass;
extern virClassPtr virDomainClass;
extern virClassPtr virDomainSnapshotClass;
+extern virClassPtr virDomainBackupClass;
extern virClassPtr virInterfaceClass;
extern virClassPtr virNetworkClass;
extern virClassPtr virNodeDeviceClass;
@@ -292,6 +293,21 @@ extern virClassPtr virAdmClientClass;
} \
} while (0)
+# define virCheckDomainBackupReturn(obj, retval) \
+ do { \
+ virDomainBackupPtr _back = (obj); \
+ if (!virObjectIsClass(_back, virDomainBackupClass) || \
+ !virObjectIsClass(_back->domain, virDomainClass) || \
+ !virObjectIsClass(_back->domain->conn, virConnectClass)) { \
+ virReportErrorHelper(VIR_FROM_DOMAIN_BACKUP, \
+ VIR_ERR_INVALID_DOMAIN_BACKUP, \
+ __FILE__, __FUNCTION__, __LINE__, \
+ __FUNCTION__); \
+ virDispatchError(NULL); \
+ return retval; \
+ } \
+ } while (0)
+
/* Helper macros to implement VIR_DOMAIN_DEBUG using just C99. This
* assumes you pass fewer than 15 arguments to VIR_DOMAIN_DEBUG, but
@@ -675,6 +691,17 @@ struct _virNWFilter {
unsigned char uuid[VIR_UUID_BUFLEN]; /* the network filter unique identifier */
};
+/**
+ * _virDomainBackup
+ *
+ * Internal structure associated with a domain backup
+ */
+struct _virDomainBackup {
+ virObject object;
+ char *name;
+ virDomainPtr domain;
+};
+
/*
* Helper APIs for allocating new object instances
@@ -714,6 +741,8 @@ virNWFilterPtr virGetNWFilter(virConnectPtr conn,
const unsigned char *uuid);
virDomainSnapshotPtr virGetDomainSnapshot(virDomainPtr domain,
const char *name);
+virDomainBackupPtr virGetDomainBackup(virDomainPtr domain,
+ const char *name);
virAdmConnectPtr virAdmConnectNew(void);
diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h
index 3053d7a..9c1756f 100644
--- a/src/driver-hypervisor.h
+++ b/src/driver-hypervisor.h
@@ -1263,6 +1263,10 @@ typedef int
unsigned long long threshold,
unsigned int flags);
+typedef virDomainBackupPtr
+(*virDrvDomainBackupCreateXML)(virDomainPtr domain,
+ const char *xmlDesc,
+ unsigned int flags);
typedef struct _virHypervisorDriver virHypervisorDriver;
typedef virHypervisorDriver *virHypervisorDriverPtr;
@@ -1504,6 +1508,7 @@ struct _virHypervisorDriver {
virDrvDomainSetGuestVcpus domainSetGuestVcpus;
virDrvDomainSetVcpu domainSetVcpu;
virDrvDomainSetBlockThreshold domainSetBlockThreshold;
+ virDrvDomainBackupCreateXML domainBackupCreateXML;
};
diff --git a/src/libvirt-domain-backup.c b/src/libvirt-domain-backup.c
new file mode 100644
index 0000000..f019d2c
--- /dev/null
+++ b/src/libvirt-domain-backup.c
@@ -0,0 +1,209 @@
+/*
+ * libvirt-domain-backup.c: entry points for virDomainBackupPtr APIs
+
+ * Copyright (C) 2017 Parallels International GmbH
+ *
+ * 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 "datatypes.h"
+#include "virlog.h"
+
+VIR_LOG_INIT("libvirt.domain-backup");
+
+#define VIR_FROM_THIS VIR_FROM_DOMAIN_BACKUP
+
+/**
+ * virDomainBackupGetName:
+ * @backup: a backup object
+ *
+ * Get the public name for that backup
+ *
+ * Returns a pointer to the name or NULL, the string need not be deallocated
+ * as its lifetime will be the same as the backup object.
+ */
+const char *
+virDomainBackupGetName(virDomainBackupPtr backup)
+{
+ VIR_DEBUG("backup=%p", backup);
+
+ virResetLastError();
+
+ virCheckDomainBackupReturn(backup, NULL);
+
+ return backup->name;
+}
+
+
+/**
+ * virDomainBackupGetDomain:
+ * @backup: a backup object
+ *
+ * Provides the domain pointer associated with a backup. The
+ * reference counter on the domain is not increased by this
+ * call.
+ *
+ * WARNING: When writing libvirt bindings in other languages, do not use this
+ * function. Instead, store the domain and the backup object together.
+ *
+ * Returns the domain or NULL.
+ */
+virDomainPtr
+virDomainBackupGetDomain(virDomainBackupPtr backup)
+{
+ VIR_DEBUG("backup=%p", backup);
+
+ virResetLastError();
+
+ virCheckDomainBackupReturn(backup, NULL);
+
+ return backup->domain;
+}
+
+
+/**
+ * virDomainBackupGetConnect:
+ * @backup: a backup object
+ *
+ * Provides the connection pointer associated with a backup. The
+ * reference counter on the connection is not increased by this
+ * call.
+ *
+ * WARNING: When writing libvirt bindings in other languages, do not use this
+ * function. Instead, store the connection and the backup object together.
+ *
+ * Returns the connection or NULL.
+ */
+virConnectPtr
+virDomainBackupGetConnect(virDomainBackupPtr backup)
+{
+ VIR_DEBUG("backup=%p", backup);
+
+ virResetLastError();
+
+ virCheckDomainBackupReturn(backup, NULL);
+
+ return backup->domain->conn;
+}
+
+
+/**
+ * virDomainBackupCreateXML:
+ * @domain: a domain object
+ * @xmlDesc: domain backup XML description
+ * @flags: reserved, must be 0
+ *
+ * Starts creating of the domain disks backup based on the xml description in
+ * @xmlDesc. Backup is a copy of the specified domain disks at the moment of
+ * operation start.
+ *
+ * Backup creates a blockjob for every specified disk hence the backup
+ * status can be tracked thru blockjob event API and the backup progress
+ * is given by per blockjob virDomainBlockJobInfo. Backup can be cancelled by
+ * cancelling any of its still active blockjobs via virDomainBlockJobAbort.
+ *
+ * Known issues. In case libvirt connection is lost and restored back and all
+ * backup blockjobs are already gone then currenly it is not possible to know
+ * whether backup is completed or failed.
+ *
+ * Returns an (opaque) virDomainBackupPtr on success, NULL on failure.
+ */
+virDomainBackupPtr
+virDomainBackupCreateXML(virDomainPtr domain,
+ const char *xmlDesc,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DOMAIN_DEBUG(domain, "xmlDesc=%s, flags=%x", xmlDesc, flags);
+
+ virResetLastError();
+
+ virCheckDomainReturn(domain, NULL);
+ conn = domain->conn;
+
+ virCheckNonNullArgGoto(xmlDesc, error);
+ virCheckReadOnlyGoto(conn->flags, error);
+
+ if (conn->driver->domainBackupCreateXML) {
+ virDomainBackupPtr ret;
+ ret = conn->driver->domainBackupCreateXML(domain, xmlDesc, flags);
+ if (!ret)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+ error:
+ virDispatchError(conn);
+ return NULL;
+}
+
+
+/**
+ * virDomainBackupRef:
+ * @backup: the backup to hold a reference on
+ *
+ * Increment the reference count on the backup. For each
+ * additional call to this method, there shall be a corresponding
+ * call to virDomainBackupFree to release the reference count, once
+ * the caller no longer needs the reference to this object.
+ *
+ * This method is typically useful for applications where multiple
+ * threads are using a connection, and it is required that the
+ * connection and domain remain open until all threads have finished
+ * using the backup. ie, each new thread using a backup would
+ * increment the reference count.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainBackupRef(virDomainBackupPtr backup)
+{
+ VIR_DEBUG("backup=%p, refs=%d", backup,
+ backup ? backup->object.u.s.refs : 0);
+
+ virResetLastError();
+
+ virCheckDomainBackupReturn(backup, -1);
+
+ virObjectRef(backup);
+ return 0;
+}
+
+
+/**
+ * virDomainBackupFree:
+ * @backup: a domain backup object
+ *
+ * Free the domain backup object. The backup itself is not modified.
+ * The data structure is freed and should not be used thereafter.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainBackupFree(virDomainBackupPtr backup)
+{
+ VIR_DEBUG("backup=%p", backup);
+
+ virResetLastError();
+
+ virCheckDomainBackupReturn(backup, -1);
+
+ virObjectUnref(backup);
+ return 0;
+}
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index afb9100..2b40d34 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1068,10 +1068,12 @@ virConnectCloseCallbackDataClass;
virConnectCloseCallbackDataGetCallback;
virConnectCloseCallbackDataRegister;
virConnectCloseCallbackDataUnregister;
+virDomainBackupClass;
virDomainClass;
virDomainSnapshotClass;
virGetConnect;
virGetDomain;
+virGetDomainBackup;
virGetDomainSnapshot;
virGetInterface;
virGetNetwork;
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 428cf2e..e3ee083 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -759,4 +759,14 @@ LIBVIRT_3.1.0 {
virDomainSetVcpu;
} LIBVIRT_3.0.0;
+LIBVIRT_3.4.0 {
+ global:
+ virDomainBackupRef;
+ virDomainBackupFree;
+ virDomainBackupGetName;
+ virDomainBackupGetDomain;
+ virDomainBackupGetConnect;
+ virDomainBackupCreateXML;
+} LIBVIRT_3.1.0;
+
# .... define new API here using predicted next version number ....
diff --git a/src/util/virerror.c b/src/util/virerror.c
index ef17fb5..f666e6e 100644
--- a/src/util/virerror.c
+++ b/src/util/virerror.c
@@ -139,6 +139,7 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST,
"Perf", /* 65 */
"Libssh transport layer",
+ "Domain Backup",
)
@@ -1400,6 +1401,11 @@ virErrorMsg(virErrorNumber error, const char *info)
errmsg = _("guest agent replied with wrong id to guest-sync
command");
else
errmsg = _("guest agent replied with wrong id to guest-sync command:
%s");
+ case VIR_ERR_INVALID_DOMAIN_BACKUP:
+ if (info == NULL)
+ errmsg = _("Invalid backup");
+ else
+ errmsg = _("Invalid backup: %s");
break;
case VIR_ERR_LIBSSH:
if (info == NULL)
--
1.8.3.1