remote: implement storage lifecycle event APIs

This commit is contained in:
Jovanka Gulicoska 2016-06-15 20:35:45 +02:00 committed by Cole Robinson
parent edc1a27a5a
commit 22fb4374da
5 changed files with 395 additions and 3 deletions

View File

@ -60,6 +60,8 @@ struct daemonClientPrivate {
size_t nnetworkEventCallbacks;
daemonClientEventCallbackPtr *qemuEventCallbacks;
size_t nqemuEventCallbacks;
daemonClientEventCallbackPtr *storageEventCallbacks;
size_t nstorageEventCallbacks;
bool closeRegistered;
# if WITH_SASL

View File

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

View File

@ -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"
@ -355,6 +356,11 @@ remoteNetworkBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client 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,
@ -534,6 +540,10 @@ static virNetClientProgramEvent remoteEvents[] = {
remoteDomainBuildEventCallbackDeviceRemovalFailed,
sizeof(remote_domain_event_callback_device_removal_failed_msg),
(xdrproc_t)xdr_remote_domain_event_callback_device_removal_failed_msg },
{ REMOTE_PROC_STORAGE_POOL_EVENT_LIFECYCLE,
remoteStoragePoolBuildEventLifecycle,
sizeof(remote_storage_pool_event_lifecycle_msg),
(xdrproc_t)xdr_remote_storage_pool_event_lifecycle_msg },
};
static void
@ -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, /* 2.0.0 */
.connectStoragePoolEventRegisterAny = remoteConnectStoragePoolEventRegisterAny, /* 2.0.0 */
.storagePoolLookupByName = remoteStoragePoolLookupByName, /* 0.4.1 */
.storagePoolLookupByUUID = remoteStoragePoolLookupByUUID, /* 0.4.1 */
.storagePoolLookupByVolume = remoteStoragePoolLookupByVolume, /* 0.4.1 */

View File

@ -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
};

View File

@ -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 {
@ -3103,4 +3119,7 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_GET_PERF_EVENTS = 365,
REMOTE_PROC_DOMAIN_SET_PERF_EVENTS = 366,
REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVAL_FAILED = 367,
REMOTE_PROC_CONNECT_STORAGE_POOL_EVENT_REGISTER_ANY = 368,
REMOTE_PROC_CONNECT_STORAGE_POOL_EVENT_DEREGISTER_ANY = 369,
REMOTE_PROC_STORAGE_POOL_EVENT_LIFECYCLE = 370,
};