This event will be emitted whenever a lease is attached or detached. The even consists of four values: lockspace, key, path and offset. These are verbatim copy of the lease XML. Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> --- examples/c/misc/event-test.c | 37 ++++++++++ include/libvirt/libvirt-domain.h | 37 ++++++++++ src/conf/domain_event.c | 100 ++++++++++++++++++++++++++++ src/conf/domain_event.h | 16 +++++ src/libvirt_private.syms | 2 + src/remote/remote_daemon_dispatch.c | 37 ++++++++++ src/remote/remote_driver.c | 34 ++++++++++ src/remote/remote_protocol.x | 18 ++++- src/remote_protocol-structs | 8 +++ tools/virsh-domain.c | 34 ++++++++++ 10 files changed, 322 insertions(+), 1 deletion(-) diff --git a/examples/c/misc/event-test.c b/examples/c/misc/event-test.c index 52caa8ffa8..8b2d1c1e5b 100644 --- a/examples/c/misc/event-test.c +++ b/examples/c/misc/event-test.c @@ -963,6 +963,42 @@ myDomainEventBlockThresholdCallback(virConnectPtr conn G_GNUC_UNUSED, } +static const char * +leaseActionTypeToStr(int action) +{ + switch ((virConnectDomainEventLeaseAction) action) { + case VIR_CONNECT_DOMAIN_EVENT_LEASE_ACTION_ATTACH: + return "attach"; + + case VIR_CONNECT_DOMAIN_EVENT_LEASE_ACTION_DETACH: + return "detach"; + + case VIR_CONNECT_DOMAIN_EVENT_LEASE_ACTION_LAST: + break; + } + + return "unknown"; +} + + +static int +myDomainEventLeaseChangeCallback(virConnectPtr conn G_GNUC_UNUSED, + virDomainPtr dom, + int action, + const char *lockspace, + const char *key, + const char *path, + unsigned long long offset, + void *opaque G_GNUC_UNUSED) +{ + printf("%s EVENT domain %s(%d) lease change: action %s lockspace %s key %s " + "path %s offset %llu", + __func__, virDomainGetName(dom), virDomainGetID(dom), + leaseActionTypeToStr(action), lockspace, key, path, offset); + return 0; +} + + static int myDomainEventMigrationIterationCallback(virConnectPtr conn G_GNUC_UNUSED, virDomainPtr dom, @@ -1093,6 +1129,7 @@ struct domainEventData domainEvents[] = { DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED, myDomainEventDeviceRemovalFailedCallback), DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_METADATA_CHANGE, myDomainEventMetadataChangeCallback), DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD, myDomainEventBlockThresholdCallback), + DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_LEASE_CHANGE, myDomainEventLeaseChangeCallback), }; struct storagePoolEventData { diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index f129e6a1af..e002d5cb18 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -4551,6 +4551,42 @@ typedef void (*virConnectDomainEventBlockThresholdCallback)(virConnectPtr conn, unsigned long long excess, void *opaque); + +typedef enum { + VIR_CONNECT_DOMAIN_EVENT_LEASE_ACTION_ATTACH = 1, /* lease attached */ + VIR_CONNECT_DOMAIN_EVENT_LEASE_ACTION_DETACH = 2, /* lease detached */ + +# ifdef VIR_ENUM_SENTINELS + VIR_CONNECT_DOMAIN_EVENT_LEASE_ACTION_LAST +# endif +} virConnectDomainEventLeaseAction; + +/** + * virConnectDomainEventLeaseChangeCallback: + * @conn: connection object + * @dom: domain on which the event occurred + * @action: action which occurred, one of virConnectDomainEventLeaseAction + * @lockspace: string identifying within which lockspace @key is held + * @key: unique key + * @path: fully qualified path of the file associated with the lockspace + * @offset: offset within @path, may be 0 if the lock manager doesn't support offsets + * @opaque: application specified data + * + * The callback occurs on lease attach or detach. + * + * The callback signature to use when registering for an event of type + * VIR_DOMAIN_EVENT_ID_LEASE_CHANGE with virConnectDomainEventRegisterAny() + */ +typedef void (*virConnectDomainEventLeaseChangeCallback)(virConnectPtr conn, + virDomainPtr dom, + int action, + const char *lockspace, + const char *key, + const char *path, + unsigned long long offset, + void *opaque); + + /** * VIR_DOMAIN_EVENT_CALLBACK: * @@ -4593,6 +4629,7 @@ typedef enum { VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED = 22, /* virConnectDomainEventDeviceRemovalFailedCallback */ VIR_DOMAIN_EVENT_ID_METADATA_CHANGE = 23, /* virConnectDomainEventMetadataChangeCallback */ VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD = 24, /* virConnectDomainEventBlockThresholdCallback */ + VIR_DOMAIN_EVENT_ID_LEASE_CHANGE = 25, /* virConnectDomainEventLeaseChangeCallback */ # ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_EVENT_ID_LAST diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index 33fbf10406..b1eff402ac 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -57,6 +57,7 @@ static virClassPtr virDomainEventJobCompletedClass; static virClassPtr virDomainEventDeviceRemovalFailedClass; static virClassPtr virDomainEventMetadataChangeClass; static virClassPtr virDomainEventBlockThresholdClass; +static virClassPtr virDomainEventLeaseChangeClass; static void virDomainEventDispose(void *obj); static void virDomainEventLifecycleDispose(void *obj); @@ -79,6 +80,7 @@ static void virDomainEventJobCompletedDispose(void *obj); static void virDomainEventDeviceRemovalFailedDispose(void *obj); static void virDomainEventMetadataChangeDispose(void *obj); static void virDomainEventBlockThresholdDispose(void *obj); +static void virDomainEventLeaseChangeDispose(void *obj); static void virDomainEventDispatchDefaultFunc(virConnectPtr conn, @@ -287,6 +289,19 @@ struct _virDomainEventBlockThreshold { typedef struct _virDomainEventBlockThreshold virDomainEventBlockThreshold; typedef virDomainEventBlockThreshold *virDomainEventBlockThresholdPtr; +struct _virDomainEventLeaseChange { + virDomainEvent parent; + + int action; + + char *lockspace; + char *key; + char *path; + unsigned long long offset; +}; +typedef struct _virDomainEventLeaseChange virDomainEventLeaseChange; +typedef virDomainEventLeaseChange *virDomainEventLeaseChangePtr; + static int virDomainEventsOnceInit(void) @@ -333,6 +348,8 @@ virDomainEventsOnceInit(void) return -1; if (!VIR_CLASS_NEW(virDomainEventBlockThreshold, virDomainEventClass)) return -1; + if (!VIR_CLASS_NEW(virDomainEventLeaseChange, virDomainEventClass)) + return -1; return 0; } @@ -542,6 +559,17 @@ virDomainEventBlockThresholdDispose(void *obj) } +static void +virDomainEventLeaseChangeDispose(void *obj) +{ + virDomainEventLeaseChangePtr event = obj; + VIR_DEBUG("obj=%p", event); + + VIR_FREE(event->lockspace); + VIR_FREE(event->key); +} + + static void * virDomainEventNew(virClassPtr klass, int eventID, @@ -1619,6 +1647,62 @@ virDomainEventBlockThresholdNewFromDom(virDomainPtr dom, } +static virObjectEventPtr +virDomainEventLeaseChangeNew(int id, + const char *name, + unsigned char *uuid, + int action, + const char *lockspace, + const char *key, + const char *path, + unsigned long long offset) +{ + virDomainEventLeaseChangePtr ev; + + if (virDomainEventsInitialize() < 0) + return NULL; + + if (!(ev = virDomainEventNew(virDomainEventLeaseChangeClass, + VIR_DOMAIN_EVENT_ID_LEASE_CHANGE, + id, name, uuid))) + return NULL; + + ev->action = action; + ev->lockspace = g_strdup(lockspace); + ev->key = g_strdup(key); + ev->path = g_strdup(path); + ev->offset = offset; + + return (virObjectEventPtr)ev; +} + +virObjectEventPtr +virDomainEventLeaseChangeNewFromObj(virDomainObjPtr obj, + int action, + const char *lockspace, + const char *key, + const char *path, + unsigned long long offset) +{ + return virDomainEventLeaseChangeNew(obj->def->id, obj->def->name, + obj->def->uuid, action, lockspace, + key, path, offset); +} + +virObjectEventPtr +virDomainEventLeaseChangeNewFromDom(virDomainPtr dom, + int action, + const char *lockspace, + const char *key, + const char *path, + unsigned long long offset) +{ + return virDomainEventLeaseChangeNew(dom->id, dom->name, dom->uuid, + action, lockspace, key, + path, offset); +} + + static void virDomainEventDispatchDefaultFunc(virConnectPtr conn, virObjectEventPtr event, @@ -1902,6 +1986,22 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn, cbopaque); goto cleanup; } + + case VIR_DOMAIN_EVENT_ID_LEASE_CHANGE: + { + virDomainEventLeaseChangePtr leaseChangeEvent; + + leaseChangeEvent = (virDomainEventLeaseChangePtr)event; + ((virConnectDomainEventLeaseChangeCallback)cb)(conn, dom, + leaseChangeEvent->action, + leaseChangeEvent->lockspace, + leaseChangeEvent->key, + leaseChangeEvent->path, + leaseChangeEvent->offset, + cbopaque); + goto cleanup; + } + case VIR_DOMAIN_EVENT_ID_LAST: break; } diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h index d1cfb81d62..3e5641f9c2 100644 --- a/src/conf/domain_event.h +++ b/src/conf/domain_event.h @@ -255,6 +255,22 @@ virDomainEventBlockThresholdNewFromDom(virDomainPtr dom, unsigned long long threshold, unsigned long long excess); +virObjectEventPtr +virDomainEventLeaseChangeNewFromObj(virDomainObjPtr obj, + int action, + const char *lockspace, + const char *key, + const char *path, + unsigned long long offset); + +virObjectEventPtr +virDomainEventLeaseChangeNewFromDom(virDomainPtr dom, + int action, + const char *lockspace, + const char *key, + const char *path, + unsigned long long offset); + int virDomainEventStateRegister(virConnectPtr conn, virObjectEventStatePtr state, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 935ef7303b..8ccca53b83 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -692,6 +692,8 @@ virDomainEventIOErrorReasonNewFromDom; virDomainEventIOErrorReasonNewFromObj; virDomainEventJobCompletedNewFromDom; virDomainEventJobCompletedNewFromObj; +virDomainEventLeaseChangeNewFromDom; +virDomainEventLeaseChangeNewFromObj; virDomainEventLifecycleNew; virDomainEventLifecycleNewFromDef; virDomainEventLifecycleNewFromDom; diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c index 6f67d2fb30..97b167ef42 100644 --- a/src/remote/remote_daemon_dispatch.c +++ b/src/remote/remote_daemon_dispatch.c @@ -1304,6 +1304,42 @@ remoteRelayDomainEventBlockThreshold(virConnectPtr conn, } +static int +remoteRelayDomainEventLeaseChange(virConnectPtr conn, + virDomainPtr dom, + int action, + const char *lockspace, + const char *key, + const char *path, + unsigned long long offset, + void *opaque) +{ + daemonClientEventCallbackPtr callback = opaque; + remote_domain_event_lease_change_msg data; + + if (callback->callbackID < 0 || + !remoteRelayDomainEventCheckACL(callback->client, conn, dom)) + return -1; + + VIR_DEBUG("Relaying domain lease change event %s %d %d %s %s, callback %d", + dom->name, dom->id, action, lockspace, key, callback->callbackID); + + memset(&data, 0, sizeof(data)); + data.callbackID = callback->callbackID; + data.action = action; + data.locspace = g_strdup(lockspace); + data.key = g_strdup(key); + data.path = g_strdup(path); + data.offset = offset; + make_nonnull_domain(&data.dom, dom); + + remoteDispatchObjectEventSend(callback->client, remoteProgram, + REMOTE_PROC_DOMAIN_EVENT_LEASE_CHANGE, + (xdrproc_t)xdr_remote_domain_event_lease_change_msg, &data); + return 0; +} + + static virConnectDomainEventGenericCallback domainEventCallbacks[] = { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot), @@ -1330,6 +1366,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = { VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemovalFailed), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMetadataChange), VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockThreshold), + VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLeaseChange), }; G_STATIC_ASSERT(G_N_ELEMENTS(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST); diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 0aeab9db27..78e8541c95 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -468,6 +468,11 @@ remoteDomainBuildEventBlockThreshold(virNetClientProgramPtr prog, virNetClientPtr client, void *evdata, void *opaque); +static void +remoteDomainBuildEventLeaseChange(virNetClientProgramPtr prog, + virNetClientPtr client, + void *evdata, void *opaque); + static void remoteConnectNotifyEventConnectionClosed(virNetClientProgramPtr prog G_GNUC_UNUSED, virNetClientPtr client G_GNUC_UNUSED, @@ -679,6 +684,10 @@ static virNetClientProgramEvent remoteEvents[] = { remoteDomainBuildEventBlockThreshold, sizeof(remote_domain_event_block_threshold_msg), (xdrproc_t)xdr_remote_domain_event_block_threshold_msg }, + { REMOTE_PROC_DOMAIN_EVENT_LEASE_CHANGE, + remoteDomainBuildEventLeaseChange, + sizeof(remote_domain_event_lease_change_msg), + (xdrproc_t)xdr_remote_domain_event_lease_change_msg }, }; static void @@ -5687,6 +5696,31 @@ remoteDomainBuildEventBlockThreshold(virNetClientProgramPtr prog G_GNUC_UNUSED, } +static void +remoteDomainBuildEventLeaseChange(virNetClientProgramPtr prog G_GNUC_UNUSED, + virNetClientPtr client G_GNUC_UNUSED, + void *evdata, void *opaque) +{ + virConnectPtr conn = opaque; + remote_domain_event_lease_change_msg *msg = evdata; + struct private_data *priv = conn->privateData; + virDomainPtr dom; + virObjectEventPtr event = NULL; + + if (!(dom = get_nonnull_domain(conn, msg->dom))) + return; + + event = virDomainEventLeaseChangeNewFromDom(dom, + msg->action, + msg->locspace, + msg->key, + msg->path, + msg->offset); + virObjectUnref(dom); + virObjectEventStateQueueRemote(priv->eventState, event, msg->callbackID); +} + + static int remoteStreamSend(virStreamPtr st, const char *data, diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index d4393680e9..909b0db9c7 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -3771,6 +3771,16 @@ struct remote_domain_backup_get_xml_desc_ret { remote_nonnull_string xml; }; +struct remote_domain_event_lease_change_msg { + int callbackID; + remote_nonnull_domain dom; + int action; + remote_nonnull_string locspace; + remote_nonnull_string key; + remote_nonnull_string path; + unsigned hyper offset; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -6664,5 +6674,11 @@ enum remote_procedure { * @priority: high * @acl: domain:read */ - REMOTE_PROC_DOMAIN_BACKUP_GET_XML_DESC = 422 + REMOTE_PROC_DOMAIN_BACKUP_GET_XML_DESC = 422, + + /** + * @generate: both + * @acl: none + */ + REMOTE_PROC_DOMAIN_EVENT_LEASE_CHANGE = 423 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index bae0f0b545..70e9c2ae6b 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -3135,6 +3135,13 @@ struct remote_domain_backup_get_xml_desc_args { struct remote_domain_backup_get_xml_desc_ret { remote_nonnull_string xml; }; +struct remote_domain_event_lease_change_msg { + int callbackID; + remote_nonnull_domain dom; + int action; + remote_nonnull_string locspace; + remote_nonnull_string key; +}; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN = 1, REMOTE_PROC_CONNECT_CLOSE = 2, @@ -3558,4 +3565,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_AGENT_SET_RESPONSE_TIMEOUT = 420, REMOTE_PROC_DOMAIN_BACKUP_BEGIN = 421, REMOTE_PROC_DOMAIN_BACKUP_GET_XML_DESC = 422, + REMOTE_PROC_DOMAIN_EVENT_LEASE_CHANGE = 423, }; diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 61cd72f714..3a062dd184 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -13591,6 +13591,38 @@ virshEventBlockThresholdPrint(virConnectPtr conn G_GNUC_UNUSED, } +VIR_ENUM_DECL(virshEventLeaseChangeAction); +VIR_ENUM_IMPL(virshEventLeaseChangeAction, + VIR_CONNECT_DOMAIN_EVENT_LEASE_ACTION_LAST, + N_("unknown"), + N_("attach"), + N_("detach")); + + +static void +virshEventLeaseChangePrint(virConnectPtr conn G_GNUC_UNUSED, + virDomainPtr dom, + int action, + const char *lockspace, + const char *key, + const char *path, + unsigned long long offset, + void *opaque) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + + virBufferAsprintf(&buf, + _("event 'lease-change' for domain %s: " + "action: %s lockspace: %s key: %s " + "path %s offset: %llu\n"), + virDomainGetName(dom), + UNKNOWNSTR(virshEventLeaseChangeActionTypeToString(action)), + lockspace, key, path, offset); + + virshEventPrint(opaque, &buf); +} + + virshDomainEventCallback virshDomainEventCallbacks[] = { { "lifecycle", VIR_DOMAIN_EVENT_CALLBACK(virshEventLifecyclePrint), }, @@ -13640,6 +13672,8 @@ virshDomainEventCallback virshDomainEventCallbacks[] = { VIR_DOMAIN_EVENT_CALLBACK(virshEventMetadataChangePrint), }, { "block-threshold", VIR_DOMAIN_EVENT_CALLBACK(virshEventBlockThresholdPrint), }, + { "lease-change", + VIR_DOMAIN_EVENT_CALLBACK(virshEventLeaseChangePrint), }, }; G_STATIC_ASSERT(VIR_DOMAIN_EVENT_ID_LAST == G_N_ELEMENTS(virshDomainEventCallbacks)); -- 2.26.2