[libvirt] [PATCH v2 RFC 02/12] api: backup: add driver based implementation

Nikolay Shirokovskiy nshirokovskiy at virtuozzo.com
Fri May 12 13:37:18 UTC 2017


---
 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




More information about the libvir-list mailing list