diff options
author | Jovanka Gulicoska <jovanka.gulicoska@gmail.com> | 2016-06-15 20:35:45 +0200 |
---|---|---|
committer | Cole Robinson <crobinso@redhat.com> | 2016-06-16 12:22:11 -0400 |
commit | 22fb4374dad02232d212b16d9977fc8af6313532 (patch) | |
tree | fd3cc2b2e734d9b7b591a87bf84f5afc5b3938db /daemon/remote.c | |
parent | edc1a27a5af66314dd04f15749aac687c072bed1 (diff) | |
download | libvirt-22fb4374dad02232d212b16d9977fc8af6313532.tar.gz |
remote: implement storage lifecycle event APIs
Diffstat (limited to 'daemon/remote.c')
-rw-r--r-- | daemon/remote.c | 206 |
1 files changed, 204 insertions, 2 deletions
diff --git a/daemon/remote.c b/daemon/remote.c index b2a420bc00..4e2aff87b4 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, @@ -1236,6 +1262,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 +1407,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) { @@ -3528,8 +3607,10 @@ remoteDispatchConnectDomainEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED * 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. */ + * our callback; or you can use VIR_APPEND_ELEMENT_COPY to avoid + * clearing 'callback' and having to juggle the pointer + * between 'ref' and 'callback'. + */ if (VIR_ALLOC(callback) < 0) goto cleanup; callback->client = client; @@ -5434,6 +5515,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, |