[libvirt] [PATCH v2 4/6] remote: implement storage lifecycle event APIs

Jovanka Gulicoska jovanka.gulicoska at gmail.com
Mon Jun 13 16:38:41 UTC 2016


---
 daemon/libvirtd.h            |   2 +
 daemon/remote.c              | 201 ++++++++++++++++++++++++++++++++++++++++++-
 src/remote/remote_driver.c   | 128 +++++++++++++++++++++++++++
 src/remote/remote_protocol.x |  43 ++++++++-
 src/remote_protocol-structs  |  16 ++++
 5 files changed, 388 insertions(+), 2 deletions(-)

diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h
index 7271b0f..cc91266 100644
--- a/daemon/libvirtd.h
+++ b/daemon/libvirtd.h
@@ -60,6 +60,8 @@ struct daemonClientPrivate {
     size_t nnetworkEventCallbacks;
     daemonClientEventCallbackPtr *qemuEventCallbacks;
     size_t nqemuEventCallbacks;
+    daemonClientEventCallbackPtr *storageEventCallbacks;
+    size_t nstorageEventCallbacks;
     bool closeRegistered;
 
 # if WITH_SASL
diff --git a/daemon/remote.c b/daemon/remote.c
index b2a420b..d6f5f1e 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -181,6 +181,32 @@ remoteRelayNetworkEventCheckACL(virNetServerClientPtr client,
     return ret;
 }
 
+static bool
+remoteRelayStoragePoolEventCheckACL(virNetServerClientPtr client,
+                                    virConnectPtr conn,
+                                    virStoragePoolPtr pool)
+{
+    virStoragePoolDef def;
+    virIdentityPtr identity = NULL;
+    bool ret = false;
+
+    /* For now, we just create a virStoragePoolDef with enough contents to
+ *      * satisfy what viraccessdriverpolkit.c references.  This is a bit
+ *           * fragile, but I don't know of anything better.  */
+    def.name = pool->name;
+    memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN);
+
+    if (!(identity = virNetServerClientGetIdentity(client)))
+        goto cleanup;
+    if (virIdentitySetCurrent(identity) < 0)
+        goto cleanup;
+    ret = virConnectStoragePoolEventRegisterAnyCheckACL(conn, &def);
+
+ cleanup:
+    ignore_value(virIdentitySetCurrent(NULL));
+    virObjectUnref(identity);
+    return ret;
+}
 
 static bool
 remoteRelayDomainQemuMonitorEventCheckACL(virNetServerClientPtr client,
@@ -208,7 +234,6 @@ remoteRelayDomainQemuMonitorEventCheckACL(virNetServerClientPtr client,
     return ret;
 }
 
-
 static int
 remoteRelayDomainEventLifecycle(virConnectPtr conn,
                                 virDomainPtr dom,
@@ -1236,6 +1261,44 @@ static virConnectNetworkEventGenericCallback networkEventCallbacks[] = {
 
 verify(ARRAY_CARDINALITY(networkEventCallbacks) == VIR_NETWORK_EVENT_ID_LAST);
 
+static int
+remoteRelayStoragePoolEventLifecycle(virConnectPtr conn,
+                                     virStoragePoolPtr pool,
+                                     int event,
+                                     int detail,
+                                     void *opaque)
+{
+    daemonClientEventCallbackPtr callback = opaque;
+    remote_storage_pool_event_lifecycle_msg data;
+
+    if (callback->callbackID < 0 ||
+        !remoteRelayStoragePoolEventCheckACL(callback->client, conn, pool))
+        return -1;
+
+    VIR_DEBUG("Relaying storage pool lifecycle event %d, detail %d, callback %d",
+              event, detail, callback->callbackID);
+
+    /* build return data */
+    memset(&data, 0, sizeof(data));
+    make_nonnull_storage_pool(&data.pool, pool);
+    data.callbackID = callback->callbackID;
+    data.event = event;
+    data.detail = detail;
+
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
+                                  REMOTE_PROC_STORAGE_POOL_EVENT_LIFECYCLE,
+                                  (xdrproc_t)xdr_remote_storage_pool_event_lifecycle_msg,
+                                  &data);
+
+    return 0;
+}
+
+static virConnectStoragePoolEventGenericCallback storageEventCallbacks[] = {
+    VIR_STORAGE_POOL_EVENT_CALLBACK(remoteRelayStoragePoolEventLifecycle),
+};
+
+verify(ARRAY_CARDINALITY(storageEventCallbacks) == VIR_STORAGE_POOL_EVENT_ID_LAST);
+
 static void
 remoteRelayDomainQemuMonitorEvent(virConnectPtr conn,
                                   virDomainPtr dom,
@@ -1343,6 +1406,21 @@ void remoteClientFreeFunc(void *data)
         }
         VIR_FREE(priv->networkEventCallbacks);
 
+        for (i = 0; i < priv->nstorageEventCallbacks; i++) {
+            int callbackID = priv->storageEventCallbacks[i]->callbackID;
+            if (callbackID < 0) {
+                VIR_WARN("unexpected incomplete storage pool callback %zu", i);
+                continue;
+            }
+            VIR_DEBUG("Deregistering remote storage pool event relay %d",
+                      callbackID);
+            priv->storageEventCallbacks[i]->callbackID = -1;
+            if (virConnectStoragePoolEventDeregisterAny(priv->conn,
+                                                        callbackID) < 0)
+                VIR_WARN("unexpected storage pool event deregister failure");
+        }
+        VIR_FREE(priv->storageEventCallbacks);
+
         for (i = 0; i < priv->nqemuEventCallbacks; i++) {
             int callbackID = priv->qemuEventCallbacks[i]->callbackID;
             if (callbackID < 0) {
@@ -5434,6 +5512,127 @@ remoteDispatchConnectNetworkEventDeregisterAny(virNetServerPtr server ATTRIBUTE_
     return rv;
 }
 
+static int
+remoteDispatchConnectStoragePoolEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                                 virNetServerClientPtr client,
+                                                 virNetMessagePtr msg ATTRIBUTE_UNUSED,
+                                                 virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+                                                 remote_connect_storage_pool_event_register_any_args *args,
+                                                 remote_connect_storage_pool_event_register_any_ret *ret)
+{
+    int callbackID;
+    int rv = -1;
+    daemonClientEventCallbackPtr callback = NULL;
+    daemonClientEventCallbackPtr ref;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
+    virStoragePoolPtr  pool = NULL;
+
+    if (!priv->conn) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+        goto cleanup;
+    }
+
+    virMutexLock(&priv->lock);
+
+    if (args->pool &&
+        !(pool = get_nonnull_storage_pool(priv->conn, *args->pool)))
+        goto cleanup;
+
+    if (args->eventID >= VIR_STORAGE_POOL_EVENT_ID_LAST || args->eventID < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("unsupported storage pool event ID %d"), args->eventID);
+        goto cleanup;
+    }
+
+    /* If we call register first, we could append a complete callback
+     * to our array, but on OOM append failure, we'd have to then hope
+     * deregister works to undo our register.  So instead we append an
+     * incomplete callback to our array, then register, then fix up
+     * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
+     * success, we use 'ref' to save a copy of the pointer.  */
+    if (VIR_ALLOC(callback) < 0)
+        goto cleanup;
+    callback->client = client;
+    callback->eventID = args->eventID;
+    callback->callbackID = -1;
+    ref = callback;
+    if (VIR_APPEND_ELEMENT(priv->storageEventCallbacks,
+                           priv->nstorageEventCallbacks,
+                           callback) < 0)
+        goto cleanup;
+
+    if ((callbackID = virConnectStoragePoolEventRegisterAny(priv->conn,
+                                                            pool,
+                                                            args->eventID,
+                                                            storageEventCallbacks[args->eventID],
+                                                            ref,
+                                                            remoteEventCallbackFree)) < 0) {
+        VIR_SHRINK_N(priv->storageEventCallbacks,
+                     priv->nstorageEventCallbacks, 1);
+        callback = ref;
+        goto cleanup;
+    }
+
+    ref->callbackID = callbackID;
+    ret->callbackID = callbackID;
+
+    rv = 0;
+
+ cleanup:
+    VIR_FREE(callback);
+    if (rv < 0)
+        virNetMessageSaveError(rerr);
+    virObjectUnref(pool);
+    virMutexUnlock(&priv->lock);
+    return rv;
+}
+
+static int
+remoteDispatchConnectStoragePoolEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                               virNetServerClientPtr client,
+                                               virNetMessagePtr msg ATTRIBUTE_UNUSED,
+                                               virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+                                               remote_connect_storage_pool_event_deregister_any_args *args)
+{
+    int rv = -1;
+    size_t i;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
+
+    if (!priv->conn) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+        goto cleanup;
+    }
+
+    virMutexLock(&priv->lock);
+
+    for (i = 0; i < priv->nstorageEventCallbacks; i++) {
+        if (priv->storageEventCallbacks[i]->callbackID == args->callbackID)
+            break;
+    }
+    if (i == priv->nstorageEventCallbacks) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("storage pool event callback %d not registered"),
+                       args->callbackID);
+        goto cleanup;
+    }
+
+    if (virConnectStoragePoolEventDeregisterAny(priv->conn, args->callbackID) < 0)
+        goto cleanup;
+
+    VIR_DELETE_ELEMENT(priv->storageEventCallbacks, i,
+                       priv->nstorageEventCallbacks);
+
+    rv = 0;
+
+ cleanup:
+    if (rv < 0)
+        virNetMessageSaveError(rerr);
+    virMutexUnlock(&priv->lock);
+    return rv;
+}
+
 
 static int
 qemuDispatchConnectDomainMonitorEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index f494cbf..6fae72e 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -34,6 +34,7 @@
 #include "datatypes.h"
 #include "domain_event.h"
 #include "network_event.h"
+#include "storage_event.h"
 #include "driver.h"
 #include "virbuffer.h"
 #include "remote_driver.h"
@@ -356,6 +357,11 @@ remoteNetworkBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
                                  void *evdata, void *opaque);
 
 static void
+remoteStoragePoolBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+                                     virNetClientPtr client ATTRIBUTE_UNUSED,
+                                     void *evdata, void *opaque);
+
+static void
 remoteConnectNotifyEventConnectionClosed(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
                                          virNetClientPtr client ATTRIBUTE_UNUSED,
                                          void *evdata, void *opaque);
@@ -438,6 +444,10 @@ static virNetClientProgramEvent remoteEvents[] = {
       remoteNetworkBuildEventLifecycle,
       sizeof(remote_network_event_lifecycle_msg),
       (xdrproc_t)xdr_remote_network_event_lifecycle_msg },
+    { REMOTE_PROC_STORAGE_POOL_EVENT_LIFECYCLE,
+      remoteStoragePoolBuildEventLifecycle,
+      sizeof(remote_storage_pool_event_lifecycle_msg),
+      (xdrproc_t)xdr_remote_storage_pool_event_lifecycle_msg },
     { REMOTE_PROC_DOMAIN_EVENT_CALLBACK_LIFECYCLE,
       remoteDomainBuildEventCallbackLifecycle,
       sizeof(remote_domain_event_callback_lifecycle_msg),
@@ -3040,6 +3050,101 @@ remoteConnectNetworkEventDeregisterAny(virConnectPtr conn,
     return rv;
 }
 
+static int
+remoteConnectStoragePoolEventRegisterAny(virConnectPtr conn,
+                                         virStoragePoolPtr pool,
+                                         int eventID,
+                                         virConnectStoragePoolEventGenericCallback callback,
+                                         void *opaque,
+                                         virFreeCallback freecb)
+{
+    int rv = -1;
+    struct private_data *priv = conn->privateData;
+    remote_connect_storage_pool_event_register_any_args args;
+    remote_connect_storage_pool_event_register_any_ret ret;
+    int callbackID;
+    int count;
+    remote_nonnull_storage_pool storage_pool;
+
+    remoteDriverLock(priv);
+
+    if ((count = virStoragePoolEventStateRegisterClient(conn, priv->eventState,
+                                                        pool, eventID, callback,
+                                                        opaque, freecb,
+                                                        &callbackID)) < 0)
+        goto done;
+
+    /* If this is the first callback for this eventID, we need to enable
+     * events on the server */
+    if (count == 1) {
+        args.eventID = eventID;
+        if (pool) {
+            make_nonnull_storage_pool(&storage_pool, pool);
+            args.pool = &storage_pool;
+        } else {
+            args.pool = NULL;
+        }
+
+        memset(&ret, 0, sizeof(ret));
+        if (call(conn, priv, 0, REMOTE_PROC_CONNECT_STORAGE_POOL_EVENT_REGISTER_ANY,
+                 (xdrproc_t) xdr_remote_connect_storage_pool_event_register_any_args, (char *) &args,
+                 (xdrproc_t) xdr_remote_connect_storage_pool_event_register_any_ret, (char *) &ret) == -1) {
+            virObjectEventStateDeregisterID(conn, priv->eventState,
+                                            callbackID);
+            goto done;
+        }
+
+        virObjectEventStateSetRemote(conn, priv->eventState, callbackID,
+                                     ret.callbackID);
+    }
+
+    rv = callbackID;
+
+ done:
+    remoteDriverUnlock(priv);
+    return rv;
+}
+
+static int
+remoteConnectStoragePoolEventDeregisterAny(virConnectPtr conn,
+                                           int callbackID)
+{
+    struct private_data *priv = conn->privateData;
+    int rv = -1;
+    remote_connect_storage_pool_event_deregister_any_args args;
+    int eventID;
+    int remoteID;
+    int count;
+
+    remoteDriverLock(priv);
+
+    if ((eventID = virObjectEventStateEventID(conn, priv->eventState,
+                                              callbackID, &remoteID)) < 0)
+        goto done;
+
+    if ((count = virObjectEventStateDeregisterID(conn, priv->eventState,
+                                                 callbackID)) < 0)
+        goto done;
+
+    /* If that was the last callback for this eventID, we need to disable
+     * events on the server */
+    if (count == 0) {
+        args.callbackID = remoteID;
+
+        if (call(conn, priv, 0, REMOTE_PROC_CONNECT_STORAGE_POOL_EVENT_DEREGISTER_ANY,
+                 (xdrproc_t) xdr_remote_connect_storage_pool_event_deregister_any_args, (char *) &args,
+                 (xdrproc_t) xdr_void, (char *) NULL) == -1)
+            goto done;
+
+    }
+
+    rv = 0;
+
+ done:
+    remoteDriverUnlock(priv);
+    return rv;
+}
+
 
 static int
 remoteConnectDomainQemuMonitorEventRegister(virConnectPtr conn,
@@ -5013,6 +5118,27 @@ remoteNetworkBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
     remoteEventQueue(priv, event, msg->callbackID);
 }
 
+static void
+remoteStoragePoolBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+                                     virNetClientPtr client ATTRIBUTE_UNUSED,
+                                     void *evdata, void *opaque)
+{
+    virConnectPtr conn = opaque;
+    struct private_data *priv = conn->privateData;
+    remote_storage_pool_event_lifecycle_msg *msg = evdata;
+    virStoragePoolPtr pool;
+    virObjectEventPtr event = NULL;
+
+    pool = get_nonnull_storage_pool(conn, msg->pool);
+    if (!pool)
+        return;
+
+    event = virStoragePoolEventLifecycleNew(pool->name, pool->uuid, msg->event,
+                                            msg->detail);
+    virObjectUnref(pool);
+
+    remoteEventQueue(priv, event, msg->callbackID);
+}
 
 static void
 remoteDomainBuildQemuMonitorEvent(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
@@ -7908,6 +8034,8 @@ static virStorageDriver storage_driver = {
     .connectListDefinedStoragePools = remoteConnectListDefinedStoragePools, /* 0.4.1 */
     .connectListAllStoragePools = remoteConnectListAllStoragePools, /* 0.10.2 */
     .connectFindStoragePoolSources = remoteConnectFindStoragePoolSources, /* 0.4.5 */
+    .connectStoragePoolEventDeregisterAny = remoteConnectStoragePoolEventDeregisterAny, /* 1.3.6 */
+    .connectStoragePoolEventRegisterAny = remoteConnectStoragePoolEventRegisterAny, /* 1.3.6 */
     .storagePoolLookupByName = remoteStoragePoolLookupByName, /* 0.4.1 */
     .storagePoolLookupByUUID = remoteStoragePoolLookupByUUID, /* 0.4.1 */
     .storagePoolLookupByVolume = remoteStoragePoolLookupByVolume, /* 0.4.1 */
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index bab8ef2..0170c0c 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -3098,6 +3098,26 @@ struct remote_network_event_lifecycle_msg {
     int detail;
 };
 
+struct remote_connect_storage_pool_event_register_any_args {
+    int eventID;
+    remote_storage_pool pool;
+};
+
+struct remote_connect_storage_pool_event_register_any_ret {
+    int callbackID;
+};
+
+struct remote_connect_storage_pool_event_deregister_any_args {
+    int callbackID;
+};
+
+struct remote_storage_pool_event_lifecycle_msg {
+    int callbackID;
+    remote_nonnull_storage_pool pool;
+    int event;
+    int detail;
+};
+
 struct remote_domain_fsfreeze_args {
     remote_nonnull_domain dom;
     remote_nonnull_string mountpoints<REMOTE_DOMAIN_FSFREEZE_MOUNTPOINTS_MAX>; /* (const char **) */
@@ -5793,5 +5813,26 @@ enum remote_procedure {
      * @generate: both
      * @acl: none
      */
-    REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVAL_FAILED = 367
+    REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVAL_FAILED = 367,
+
+    /**
+     * @generate: none
+     * @priority: high
+     * @acl: connect:search_storage_pools
+     * @aclfilter: storage_pool:getattr
+     */
+    REMOTE_PROC_CONNECT_STORAGE_POOL_EVENT_REGISTER_ANY = 368,
+
+    /**
+     * @generate: none
+     * @priority: high
+     * @acl: connect:read
+     */
+    REMOTE_PROC_CONNECT_STORAGE_POOL_EVENT_DEREGISTER_ANY = 369,
+
+    /**
+     * @generate: both
+     * @acl: none
+     */
+    REMOTE_PROC_STORAGE_POOL_EVENT_LIFECYCLE = 370
 };
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index fe1b8a8..85bc62d 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -2551,6 +2551,22 @@ struct remote_network_event_lifecycle_msg {
         int                        event;
         int                        detail;
 };
+struct remote_connect_storage_pool_event_register_any_args {
+        int                             eventID;
+        remote_storage_pool             pool;
+};
+struct remote_connect_storage_pool_event_register_any_ret {
+        int                        callbackID;
+};
+struct remote_connect_storage_pool_event_deregister_any_args {
+        int                        callbackID;
+};
+struct remote_storage_pool_event_lifecycle_msg {
+        int                             callbackID;
+        remote_nonnull_storage_pool     pool;
+        int                             event;
+        int                             detail;
+};
 struct remote_domain_fsfreeze_args {
         remote_nonnull_domain      dom;
         struct {
-- 
2.5.5




More information about the libvir-list mailing list