Introduce node device update event as top level event

This event is emitted when a nodedev XML definition is updated,
like when cdrom media is changed in a cdrom block device.

Also includes node device update event implementation for udev
backend, virsh nodedev-event support, and event-test support
This commit is contained in:
Jovanka Gulicoska 2016-08-11 17:15:23 +02:00 committed by Cole Robinson
parent 18701e9d62
commit 43a6b37b24
11 changed files with 204 additions and 9 deletions

View File

@ -1388,8 +1388,37 @@ remoteRelayNodeDeviceEventLifecycle(virConnectPtr conn,
return 0; return 0;
} }
static int
remoteRelayNodeDeviceEventUpdate(virConnectPtr conn,
virNodeDevicePtr dev,
void *opaque)
{
daemonClientEventCallbackPtr callback = opaque;
remote_node_device_event_update_msg data;
if (callback->callbackID < 0 ||
!remoteRelayNodeDeviceEventCheckACL(callback->client, conn, dev))
return -1;
VIR_DEBUG("Relaying node device update event callback %d",
callback->callbackID);
/* build return data */
memset(&data, 0, sizeof(data));
make_nonnull_node_device(&data.dev, dev);
data.callbackID = callback->callbackID;
remoteDispatchObjectEventSend(callback->client, remoteProgram,
REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE,
(xdrproc_t)xdr_remote_node_device_event_update_msg,
&data);
return 0;
}
static virConnectNodeDeviceEventGenericCallback nodeDeviceEventCallbacks[] = { static virConnectNodeDeviceEventGenericCallback nodeDeviceEventCallbacks[] = {
VIR_NODE_DEVICE_EVENT_CALLBACK(remoteRelayNodeDeviceEventLifecycle), VIR_NODE_DEVICE_EVENT_CALLBACK(remoteRelayNodeDeviceEventLifecycle),
VIR_NODE_DEVICE_EVENT_CALLBACK(remoteRelayNodeDeviceEventUpdate),
}; };
verify(ARRAY_CARDINALITY(nodeDeviceEventCallbacks) == VIR_NODE_DEVICE_EVENT_ID_LAST); verify(ARRAY_CARDINALITY(nodeDeviceEventCallbacks) == VIR_NODE_DEVICE_EVENT_ID_LAST);

View File

@ -717,6 +717,17 @@ myNodeDeviceEventCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
} }
static int
myNodeDeviceEventUpdateCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
virNodeDevicePtr dev,
void *opaque ATTRIBUTE_UNUSED)
{
printf("%s EVENT: Node device %s update\n", __func__,
virNodeDeviceGetName(dev));
return 0;
}
static void static void
eventTypedParamsPrint(virTypedParameterPtr params, eventTypedParamsPrint(virTypedParameterPtr params,
int nparams) int nparams)
@ -989,6 +1000,7 @@ struct nodeDeviceEventData {
struct nodeDeviceEventData nodeDeviceEvents[] = { struct nodeDeviceEventData nodeDeviceEvents[] = {
NODE_DEVICE_EVENT(VIR_NODE_DEVICE_EVENT_ID_LIFECYCLE, myNodeDeviceEventCallback), NODE_DEVICE_EVENT(VIR_NODE_DEVICE_EVENT_ID_LIFECYCLE, myNodeDeviceEventCallback),
NODE_DEVICE_EVENT(VIR_NODE_DEVICE_EVENT_ID_UPDATE, myNodeDeviceEventUpdateCallback),
}; };
/* make sure that the events are kept in sync */ /* make sure that the events are kept in sync */

View File

@ -138,6 +138,7 @@ int virNodeDeviceDestroy (virNodeDevicePtr dev);
*/ */
typedef enum { typedef enum {
VIR_NODE_DEVICE_EVENT_ID_LIFECYCLE = 0, /* virConnectNodeDeviceEventLifecycleCallback */ VIR_NODE_DEVICE_EVENT_ID_LIFECYCLE = 0, /* virConnectNodeDeviceEventLifecycleCallback */
VIR_NODE_DEVICE_EVENT_ID_UPDATE = 1, /* virConnectNodeDeviceEventUpdateCallback */
# ifdef VIR_ENUM_SENTINELS # ifdef VIR_ENUM_SENTINELS
VIR_NODE_DEVICE_EVENT_ID_LAST VIR_NODE_DEVICE_EVENT_ID_LAST

View File

@ -48,10 +48,20 @@ struct _virNodeDeviceEventLifecycle {
typedef struct _virNodeDeviceEventLifecycle virNodeDeviceEventLifecycle; typedef struct _virNodeDeviceEventLifecycle virNodeDeviceEventLifecycle;
typedef virNodeDeviceEventLifecycle *virNodeDeviceEventLifecyclePtr; typedef virNodeDeviceEventLifecycle *virNodeDeviceEventLifecyclePtr;
struct _virNodeDeviceEventUpdate {
virNodeDeviceEvent parent;
bool dummy;
};
typedef struct _virNodeDeviceEventUpdate virNodeDeviceEventUpdate;
typedef virNodeDeviceEventUpdate *virNodeDeviceEventUpdatePtr;
static virClassPtr virNodeDeviceEventClass; static virClassPtr virNodeDeviceEventClass;
static virClassPtr virNodeDeviceEventLifecycleClass; static virClassPtr virNodeDeviceEventLifecycleClass;
static virClassPtr virNodeDeviceEventUpdateClass;
static void virNodeDeviceEventDispose(void *obj); static void virNodeDeviceEventDispose(void *obj);
static void virNodeDeviceEventLifecycleDispose(void *obj); static void virNodeDeviceEventLifecycleDispose(void *obj);
static void virNodeDeviceEventUpdateDispose(void *obj);
static int static int
virNodeDeviceEventsOnceInit(void) virNodeDeviceEventsOnceInit(void)
@ -68,6 +78,12 @@ virNodeDeviceEventsOnceInit(void)
sizeof(virNodeDeviceEventLifecycle), sizeof(virNodeDeviceEventLifecycle),
virNodeDeviceEventLifecycleDispose))) virNodeDeviceEventLifecycleDispose)))
return -1; return -1;
if (!(virNodeDeviceEventUpdateClass =
virClassNew(virNodeDeviceEventClass,
"virNodeDeviceEventUpdate",
sizeof(virNodeDeviceEventUpdate),
virNodeDeviceEventUpdateDispose)))
return -1;
return 0; return 0;
} }
@ -89,6 +105,14 @@ virNodeDeviceEventLifecycleDispose(void *obj)
} }
static void
virNodeDeviceEventUpdateDispose(void *obj)
{
virNodeDeviceEventUpdatePtr event = obj;
VIR_DEBUG("obj=%p", event);
}
static void static void
virNodeDeviceEventDispatchDefaultFunc(virConnectPtr conn, virNodeDeviceEventDispatchDefaultFunc(virConnectPtr conn,
virObjectEventPtr event, virObjectEventPtr event,
@ -114,6 +138,13 @@ virNodeDeviceEventDispatchDefaultFunc(virConnectPtr conn,
goto cleanup; goto cleanup;
} }
case VIR_NODE_DEVICE_EVENT_ID_UPDATE:
{
((virConnectNodeDeviceEventGenericCallback)cb)(conn, dev,
cbopaque);
goto cleanup;
}
case VIR_NODE_DEVICE_EVENT_ID_LAST: case VIR_NODE_DEVICE_EVENT_ID_LAST:
break; break;
} }
@ -232,3 +263,27 @@ virNodeDeviceEventLifecycleNew(const char *name,
return (virObjectEventPtr)event; return (virObjectEventPtr)event;
} }
/**
* virNodeDeviceEventUpdateNew:
* @name: name of the node device object the event describes
*
* Create a new node device update event.
*/
virObjectEventPtr
virNodeDeviceEventUpdateNew(const char *name)
{
virNodeDeviceEventUpdatePtr event;
if (virNodeDeviceEventsInitialize() < 0)
return NULL;
if (!(event = virObjectEventNew(virNodeDeviceEventUpdateClass,
virNodeDeviceEventDispatchDefaultFunc,
VIR_NODE_DEVICE_EVENT_ID_UPDATE,
0, name, NULL, name)))
return NULL;
return (virObjectEventPtr)event;
}

View File

@ -56,4 +56,7 @@ virNodeDeviceEventLifecycleNew(const char *name,
int type, int type,
int detail); int detail);
virObjectEventPtr
virNodeDeviceEventUpdateNew(const char *name);
#endif #endif

View File

@ -687,6 +687,7 @@ virNodeDeviceObjUnlock;
# conf/node_device_event.h # conf/node_device_event.h
virNodeDeviceEventLifecycleNew; virNodeDeviceEventLifecycleNew;
virNodeDeviceEventStateRegisterID; virNodeDeviceEventStateRegisterID;
virNodeDeviceEventUpdateNew;
# conf/numa_conf.h # conf/numa_conf.h

View File

@ -1147,6 +1147,8 @@ static int udevAddOneDevice(struct udev_device *device)
event = virNodeDeviceEventLifecycleNew(dev->def->name, event = virNodeDeviceEventLifecycleNew(dev->def->name,
VIR_NODE_DEVICE_EVENT_CREATED, VIR_NODE_DEVICE_EVENT_CREATED,
0); 0);
else
event = virNodeDeviceEventUpdateNew(dev->def->name);
virNodeDeviceObjUnlock(dev); virNodeDeviceObjUnlock(dev);

View File

@ -374,6 +374,11 @@ remoteNodeDeviceBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED
virNetClientPtr client ATTRIBUTE_UNUSED, virNetClientPtr client ATTRIBUTE_UNUSED,
void *evdata, void *opaque); void *evdata, void *opaque);
static void
remoteNodeDeviceBuildEventUpdate(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED,
void *evdata, void *opaque);
static void static void
remoteConnectNotifyEventConnectionClosed(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, remoteConnectNotifyEventConnectionClosed(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED, virNetClientPtr client ATTRIBUTE_UNUSED,
@ -565,6 +570,10 @@ static virNetClientProgramEvent remoteEvents[] = {
remoteNodeDeviceBuildEventLifecycle, remoteNodeDeviceBuildEventLifecycle,
sizeof(remote_node_device_event_lifecycle_msg), sizeof(remote_node_device_event_lifecycle_msg),
(xdrproc_t)xdr_remote_node_device_event_lifecycle_msg }, (xdrproc_t)xdr_remote_node_device_event_lifecycle_msg },
{ REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE,
remoteNodeDeviceBuildEventUpdate,
sizeof(remote_node_device_event_update_msg),
(xdrproc_t)xdr_remote_node_device_event_update_msg },
}; };
static void static void
@ -5285,6 +5294,27 @@ remoteNodeDeviceBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED
remoteEventQueue(priv, event, msg->callbackID); remoteEventQueue(priv, event, msg->callbackID);
} }
static void
remoteNodeDeviceBuildEventUpdate(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED,
void *evdata, void *opaque)
{
virConnectPtr conn = opaque;
struct private_data *priv = conn->privateData;
remote_node_device_event_update_msg *msg = evdata;
virNodeDevicePtr dev;
virObjectEventPtr event = NULL;
dev = get_nonnull_node_device(conn, msg->dev);
if (!dev)
return;
event = virNodeDeviceEventUpdateNew(dev->name);
virObjectUnref(dev);
remoteEventQueue(priv, event, msg->callbackID);
}
static void static void
remoteDomainBuildQemuMonitorEvent(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, remoteDomainBuildQemuMonitorEvent(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED, virNetClientPtr client ATTRIBUTE_UNUSED,

View File

@ -3151,6 +3151,11 @@ struct remote_node_device_event_lifecycle_msg {
int detail; int detail;
}; };
struct remote_node_device_event_update_msg {
int callbackID;
remote_nonnull_node_device dev;
};
struct remote_domain_fsfreeze_args { struct remote_domain_fsfreeze_args {
remote_nonnull_domain dom; remote_nonnull_domain dom;
remote_nonnull_string mountpoints<REMOTE_DOMAIN_FSFREEZE_MOUNTPOINTS_MAX>; /* (const char **) */ remote_nonnull_string mountpoints<REMOTE_DOMAIN_FSFREEZE_MOUNTPOINTS_MAX>; /* (const char **) */
@ -5923,5 +5928,11 @@ enum remote_procedure {
* @generate: both * @generate: both
* @acl: none * @acl: none
*/ */
REMOTE_PROC_NODE_DEVICE_EVENT_LIFECYCLE = 376 REMOTE_PROC_NODE_DEVICE_EVENT_LIFECYCLE = 376,
/**
* @generate: both
* @acl: none
*/
REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE = 377
}; };

View File

@ -2587,6 +2587,10 @@ struct remote_node_device_event_lifecycle_msg {
int event; int event;
int detail; int detail;
}; };
struct remote_node_device_event_update_msg {
int callbackID;
remote_nonnull_node_device dev;
};
struct remote_domain_fsfreeze_args { struct remote_domain_fsfreeze_args {
remote_nonnull_domain dom; remote_nonnull_domain dom;
struct { struct {
@ -3164,4 +3168,5 @@ enum remote_procedure {
REMOTE_PROC_CONNECT_NODE_DEVICE_EVENT_REGISTER_ANY = 374, REMOTE_PROC_CONNECT_NODE_DEVICE_EVENT_REGISTER_ANY = 374,
REMOTE_PROC_CONNECT_NODE_DEVICE_EVENT_DEREGISTER_ANY = 375, REMOTE_PROC_CONNECT_NODE_DEVICE_EVENT_DEREGISTER_ANY = 375,
REMOTE_PROC_NODE_DEVICE_EVENT_LIFECYCLE = 376, REMOTE_PROC_NODE_DEVICE_EVENT_LIFECYCLE = 376,
REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE = 377,
}; };

View File

@ -756,19 +756,21 @@ virshNodeDeviceEventToString(int event)
return str ? _(str) : _("unknown"); return str ? _(str) : _("unknown");
} }
struct vshEventCallback {
const char *name;
virConnectNodeDeviceEventGenericCallback cb;
};
typedef struct vshEventCallback vshEventCallback;
struct virshNodeDeviceEventData { struct virshNodeDeviceEventData {
vshControl *ctl; vshControl *ctl;
bool loop; bool loop;
bool timestamp; bool timestamp;
int count; int count;
vshEventCallback *cb;
}; };
typedef struct virshNodeDeviceEventData virshNodeDeviceEventData; typedef struct virshNodeDeviceEventData virshNodeDeviceEventData;
VIR_ENUM_DECL(virshNodeDeviceEventId)
VIR_ENUM_IMPL(virshNodeDeviceEventId,
VIR_NODE_DEVICE_EVENT_ID_LAST,
"lifecycle")
static void static void
vshEventLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED, vshEventLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
virNodeDevicePtr dev, virNodeDevicePtr dev,
@ -800,6 +802,45 @@ vshEventLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
vshEventDone(data->ctl); vshEventDone(data->ctl);
} }
static void
vshEventGenericPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
virNodeDevicePtr dev,
void *opaque)
{
virshNodeDeviceEventData *data = opaque;
if (!data->loop && data->count)
return;
if (data->timestamp) {
char timestamp[VIR_TIME_STRING_BUFLEN];
if (virTimeStringNowRaw(timestamp) < 0)
timestamp[0] = '\0';
vshPrint(data->ctl, _("%s: event '%s'' for node device %s\n"),
timestamp,
data->cb->name,
virNodeDeviceGetName(dev));
} else {
vshPrint(data->ctl, _("event '%s' for node device %s\n"),
data->cb->name,
virNodeDeviceGetName(dev));
}
data->count++;
if (!data->loop)
vshEventDone(data->ctl);
}
static vshEventCallback vshEventCallbacks[] = {
{ "lifecycle",
VIR_NODE_DEVICE_EVENT_CALLBACK(vshEventLifecyclePrint), },
{ "update", vshEventGenericPrint, }
};
verify(VIR_NODE_DEVICE_EVENT_ID_LAST == ARRAY_CARDINALITY(vshEventCallbacks));
static const vshCmdInfo info_node_device_event[] = { static const vshCmdInfo info_node_device_event[] = {
{.name = "help", {.name = "help",
.data = N_("Node Device Events") .data = N_("Node Device Events")
@ -855,7 +896,7 @@ cmdNodeDeviceEvent(vshControl *ctl, const vshCmd *cmd)
size_t i; size_t i;
for (i = 0; i < VIR_NODE_DEVICE_EVENT_ID_LAST; i++) for (i = 0; i < VIR_NODE_DEVICE_EVENT_ID_LAST; i++)
vshPrint(ctl, "%s\n", virshNodeDeviceEventIdTypeToString(i)); vshPrint(ctl, "%s\n", vshEventCallbacks[i].name);
return true; return true;
} }
@ -865,7 +906,11 @@ cmdNodeDeviceEvent(vshControl *ctl, const vshCmd *cmd)
vshError(ctl, "%s", _("either --list or event type is required")); vshError(ctl, "%s", _("either --list or event type is required"));
return false; return false;
} }
if ((event = virshNodeDeviceEventIdTypeFromString(eventName)) < 0) {
for (event = 0; event < VIR_NODE_DEVICE_EVENT_ID_LAST; event++)
if (STREQ(eventName, vshEventCallbacks[event].name))
break;
if (event == VIR_NODE_DEVICE_EVENT_ID_LAST) {
vshError(ctl, _("unknown event type %s"), eventName); vshError(ctl, _("unknown event type %s"), eventName);
return false; return false;
} }
@ -874,6 +919,7 @@ cmdNodeDeviceEvent(vshControl *ctl, const vshCmd *cmd)
data.loop = vshCommandOptBool(cmd, "loop"); data.loop = vshCommandOptBool(cmd, "loop");
data.timestamp = vshCommandOptBool(cmd, "timestamp"); data.timestamp = vshCommandOptBool(cmd, "timestamp");
data.count = 0; data.count = 0;
data.cb = &vshEventCallbacks[event];
if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0) if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0)
return false; return false;
if (vshCommandOptStringReq(ctl, cmd, "device", &device_value) < 0) if (vshCommandOptStringReq(ctl, cmd, "device", &device_value) < 0)
@ -890,7 +936,7 @@ cmdNodeDeviceEvent(vshControl *ctl, const vshCmd *cmd)
goto cleanup; goto cleanup;
if ((eventId = virConnectNodeDeviceEventRegisterAny(priv->conn, dev, event, if ((eventId = virConnectNodeDeviceEventRegisterAny(priv->conn, dev, event,
VIR_NODE_DEVICE_EVENT_CALLBACK(vshEventLifecyclePrint), data.cb->cb,
&data, NULL)) < 0) &data, NULL)) < 0)
goto cleanup; goto cleanup;
switch (vshEventWait(ctl)) { switch (vshEventWait(ctl)) {