2008-10-23 13:18:18 +00:00
|
|
|
#include <stdio.h>
|
2008-11-19 15:25:24 +00:00
|
|
|
#include <stdlib.h>
|
2008-10-23 13:18:18 +00:00
|
|
|
#include <string.h>
|
2008-11-19 15:25:24 +00:00
|
|
|
#include <signal.h>
|
2012-07-13 09:05:17 +00:00
|
|
|
#include <inttypes.h>
|
2008-10-24 13:10:30 +00:00
|
|
|
|
2016-04-14 13:11:49 +00:00
|
|
|
#define VIR_ENUM_SENTINELS
|
|
|
|
|
2011-03-23 14:30:30 +00:00
|
|
|
#include <libvirt/libvirt.h>
|
|
|
|
#include <libvirt/virterror.h>
|
2008-10-23 13:18:18 +00:00
|
|
|
|
2019-10-15 11:51:20 +00:00
|
|
|
#define G_N_ELEMENTS(Array) (sizeof(Array) / sizeof(*(Array)))
|
2014-08-22 12:59:28 +00:00
|
|
|
#define STREQ(a, b) (strcmp(a, b) == 0)
|
2017-02-21 14:03:07 +00:00
|
|
|
#define NULLSTR(s) ((s) ? (s) : "<null>")
|
2008-10-23 13:18:18 +00:00
|
|
|
|
2019-01-08 05:23:52 +00:00
|
|
|
#if (4 < __GNUC__ + (6 <= __GNUC_MINOR__) \
|
|
|
|
&& (201112L <= __STDC_VERSION__ || !defined __STRICT_ANSI__) \
|
|
|
|
&& !defined __cplusplus)
|
2020-01-09 10:39:55 +00:00
|
|
|
# define G_STATIC_ASSERT(cond) _Static_assert(cond, "verify (" #cond ")")
|
2019-01-08 05:23:52 +00:00
|
|
|
#else
|
2020-01-09 10:39:55 +00:00
|
|
|
# define G_STATIC_ASSERT(cond)
|
2019-01-08 05:23:52 +00:00
|
|
|
#endif
|
|
|
|
|
2019-10-14 12:45:33 +00:00
|
|
|
#ifndef G_GNUC_UNUSED
|
|
|
|
# define G_GNUC_UNUSED __attribute__((__unused__))
|
2011-03-23 14:30:30 +00:00
|
|
|
#endif
|
2008-10-23 13:18:18 +00:00
|
|
|
|
2012-07-19 14:59:59 +00:00
|
|
|
int run = 1;
|
|
|
|
|
2008-10-23 13:18:18 +00:00
|
|
|
/* Callback functions */
|
2016-04-13 13:45:52 +00:00
|
|
|
static void
|
2019-10-14 12:45:33 +00:00
|
|
|
connectClose(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-13 13:45:52 +00:00
|
|
|
int reason,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2012-07-19 14:59:59 +00:00
|
|
|
{
|
2016-04-14 07:04:52 +00:00
|
|
|
run = 0;
|
|
|
|
|
|
|
|
switch ((virConnectCloseReason) reason) {
|
2012-07-19 14:59:59 +00:00
|
|
|
case VIR_CONNECT_CLOSE_REASON_ERROR:
|
|
|
|
fprintf(stderr, "Connection closed due to I/O error\n");
|
2016-04-14 07:04:52 +00:00
|
|
|
return;
|
|
|
|
|
2012-07-19 14:59:59 +00:00
|
|
|
case VIR_CONNECT_CLOSE_REASON_EOF:
|
|
|
|
fprintf(stderr, "Connection closed due to end of file\n");
|
2016-04-14 07:04:52 +00:00
|
|
|
return;
|
|
|
|
|
2012-07-19 14:59:59 +00:00
|
|
|
case VIR_CONNECT_CLOSE_REASON_KEEPALIVE:
|
|
|
|
fprintf(stderr, "Connection closed due to keepalive timeout\n");
|
2016-04-14 07:04:52 +00:00
|
|
|
return;
|
|
|
|
|
2012-07-19 14:59:59 +00:00
|
|
|
case VIR_CONNECT_CLOSE_REASON_CLIENT:
|
|
|
|
fprintf(stderr, "Connection closed due to client request\n");
|
2016-04-14 07:04:52 +00:00
|
|
|
return;
|
2016-04-14 13:11:49 +00:00
|
|
|
|
|
|
|
case VIR_CONNECT_CLOSE_REASON_LAST:
|
|
|
|
break;
|
2012-07-19 14:59:59 +00:00
|
|
|
};
|
2016-04-14 07:04:52 +00:00
|
|
|
|
|
|
|
fprintf(stderr, "Connection closed due to unknown reason\n");
|
2012-07-19 14:59:59 +00:00
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
|
|
|
static const char *
|
|
|
|
eventToString(int event)
|
|
|
|
{
|
2011-12-05 12:59:13 +00:00
|
|
|
switch ((virDomainEventType) event) {
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_DEFINED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Defined";
|
|
|
|
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_UNDEFINED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Undefined";
|
|
|
|
|
2008-10-23 13:18:18 +00:00
|
|
|
case VIR_DOMAIN_EVENT_STARTED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Started";
|
|
|
|
|
2008-10-23 13:18:18 +00:00
|
|
|
case VIR_DOMAIN_EVENT_SUSPENDED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Suspended";
|
|
|
|
|
2008-10-23 13:18:18 +00:00
|
|
|
case VIR_DOMAIN_EVENT_RESUMED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Resumed";
|
|
|
|
|
2008-10-23 13:18:18 +00:00
|
|
|
case VIR_DOMAIN_EVENT_STOPPED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Stopped";
|
|
|
|
|
2011-12-05 12:59:13 +00:00
|
|
|
case VIR_DOMAIN_EVENT_SHUTDOWN:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Shutdown";
|
|
|
|
|
2012-09-06 15:00:43 +00:00
|
|
|
case VIR_DOMAIN_EVENT_PMSUSPENDED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "PMSuspended";
|
|
|
|
|
2013-06-07 10:23:31 +00:00
|
|
|
case VIR_DOMAIN_EVENT_CRASHED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Crashed";
|
2016-04-14 13:11:49 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_EVENT_LAST:
|
|
|
|
break;
|
2008-11-17 16:43:00 +00:00
|
|
|
}
|
2016-04-14 12:51:40 +00:00
|
|
|
|
|
|
|
return "unknown";
|
2008-11-17 16:43:00 +00:00
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
|
|
|
static const char *
|
|
|
|
eventDetailToString(int event,
|
|
|
|
int detail)
|
|
|
|
{
|
2011-12-05 12:59:13 +00:00
|
|
|
switch ((virDomainEventType) event) {
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_DEFINED:
|
2016-04-14 12:44:07 +00:00
|
|
|
switch ((virDomainEventDefinedDetailType) detail) {
|
|
|
|
case VIR_DOMAIN_EVENT_DEFINED_ADDED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Added";
|
|
|
|
|
2016-04-14 12:44:07 +00:00
|
|
|
case VIR_DOMAIN_EVENT_DEFINED_UPDATED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Updated";
|
|
|
|
|
2016-04-14 12:44:07 +00:00
|
|
|
case VIR_DOMAIN_EVENT_DEFINED_RENAMED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Renamed";
|
|
|
|
|
2016-04-14 12:44:07 +00:00
|
|
|
case VIR_DOMAIN_EVENT_DEFINED_FROM_SNAPSHOT:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Snapshot";
|
2016-04-14 13:11:49 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_EVENT_DEFINED_LAST:
|
|
|
|
break;
|
2016-04-14 12:44:07 +00:00
|
|
|
}
|
2008-11-17 16:43:00 +00:00
|
|
|
break;
|
2016-04-14 12:51:40 +00:00
|
|
|
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_UNDEFINED:
|
2016-04-14 12:44:07 +00:00
|
|
|
switch ((virDomainEventUndefinedDetailType) detail) {
|
|
|
|
case VIR_DOMAIN_EVENT_UNDEFINED_REMOVED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Removed";
|
|
|
|
|
2016-04-14 12:44:07 +00:00
|
|
|
case VIR_DOMAIN_EVENT_UNDEFINED_RENAMED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Renamed";
|
2016-04-14 13:11:49 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_EVENT_UNDEFINED_LAST:
|
|
|
|
break;
|
2016-04-14 12:44:07 +00:00
|
|
|
}
|
2008-10-23 13:18:18 +00:00
|
|
|
break;
|
2016-04-14 12:51:40 +00:00
|
|
|
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_STARTED:
|
2011-12-05 12:59:13 +00:00
|
|
|
switch ((virDomainEventStartedDetailType) detail) {
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_STARTED_BOOTED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Booted";
|
|
|
|
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_STARTED_MIGRATED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Migrated";
|
|
|
|
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_STARTED_RESTORED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Restored";
|
|
|
|
|
2011-08-05 22:05:50 +00:00
|
|
|
case VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Snapshot";
|
|
|
|
|
2012-03-14 15:26:55 +00:00
|
|
|
case VIR_DOMAIN_EVENT_STARTED_WAKEUP:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Event wakeup";
|
2016-04-14 13:11:49 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_EVENT_STARTED_LAST:
|
|
|
|
break;
|
2008-11-17 16:43:00 +00:00
|
|
|
}
|
|
|
|
break;
|
2016-04-14 12:51:40 +00:00
|
|
|
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_SUSPENDED:
|
2011-12-05 12:59:13 +00:00
|
|
|
switch ((virDomainEventSuspendedDetailType) detail) {
|
2011-08-05 22:05:50 +00:00
|
|
|
case VIR_DOMAIN_EVENT_SUSPENDED_PAUSED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Paused";
|
|
|
|
|
2011-08-05 22:05:50 +00:00
|
|
|
case VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Migrated";
|
|
|
|
|
2011-08-05 22:05:50 +00:00
|
|
|
case VIR_DOMAIN_EVENT_SUSPENDED_IOERROR:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "I/O Error";
|
|
|
|
|
2011-08-05 22:05:50 +00:00
|
|
|
case VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Watchdog";
|
|
|
|
|
2011-08-05 22:05:50 +00:00
|
|
|
case VIR_DOMAIN_EVENT_SUSPENDED_RESTORED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Restored";
|
|
|
|
|
2011-08-05 22:05:50 +00:00
|
|
|
case VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Snapshot";
|
|
|
|
|
2012-11-06 17:39:18 +00:00
|
|
|
case VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "API error";
|
|
|
|
|
2016-01-05 11:08:37 +00:00
|
|
|
case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Post-copy";
|
|
|
|
|
2016-01-05 11:08:37 +00:00
|
|
|
case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY_FAILED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Post-copy Error";
|
2016-04-14 13:11:49 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_EVENT_SUSPENDED_LAST:
|
|
|
|
break;
|
2011-08-05 22:05:50 +00:00
|
|
|
}
|
2008-11-17 16:43:00 +00:00
|
|
|
break;
|
2016-04-14 12:51:40 +00:00
|
|
|
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_RESUMED:
|
2011-12-05 12:59:13 +00:00
|
|
|
switch ((virDomainEventResumedDetailType) detail) {
|
2011-08-05 22:05:50 +00:00
|
|
|
case VIR_DOMAIN_EVENT_RESUMED_UNPAUSED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Unpaused";
|
|
|
|
|
2011-08-05 22:05:50 +00:00
|
|
|
case VIR_DOMAIN_EVENT_RESUMED_MIGRATED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Migrated";
|
|
|
|
|
2011-08-05 22:05:50 +00:00
|
|
|
case VIR_DOMAIN_EVENT_RESUMED_FROM_SNAPSHOT:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Snapshot";
|
|
|
|
|
2016-01-05 11:08:37 +00:00
|
|
|
case VIR_DOMAIN_EVENT_RESUMED_POSTCOPY:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Post-copy";
|
2016-04-14 13:11:49 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_EVENT_RESUMED_LAST:
|
|
|
|
break;
|
2011-08-05 22:05:50 +00:00
|
|
|
}
|
2008-11-17 16:43:00 +00:00
|
|
|
break;
|
2016-04-14 12:51:40 +00:00
|
|
|
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_STOPPED:
|
2011-12-05 12:59:13 +00:00
|
|
|
switch ((virDomainEventStoppedDetailType) detail) {
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Shutdown";
|
|
|
|
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_STOPPED_DESTROYED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Destroyed";
|
|
|
|
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_STOPPED_CRASHED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Crashed";
|
|
|
|
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_STOPPED_MIGRATED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Migrated";
|
|
|
|
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_STOPPED_SAVED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Saved";
|
|
|
|
|
2008-11-17 16:43:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_STOPPED_FAILED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Failed";
|
|
|
|
|
2011-08-05 22:05:50 +00:00
|
|
|
case VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Snapshot";
|
2016-04-14 13:11:49 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_EVENT_STOPPED_LAST:
|
|
|
|
break;
|
2008-11-17 16:43:00 +00:00
|
|
|
}
|
2008-10-23 13:18:18 +00:00
|
|
|
break;
|
2016-04-14 12:51:40 +00:00
|
|
|
|
2011-12-05 12:59:13 +00:00
|
|
|
case VIR_DOMAIN_EVENT_SHUTDOWN:
|
|
|
|
switch ((virDomainEventShutdownDetailType) detail) {
|
|
|
|
case VIR_DOMAIN_EVENT_SHUTDOWN_FINISHED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Finished";
|
|
|
|
|
2017-04-12 10:00:37 +00:00
|
|
|
case VIR_DOMAIN_EVENT_SHUTDOWN_GUEST:
|
|
|
|
return "Guest request";
|
|
|
|
|
|
|
|
case VIR_DOMAIN_EVENT_SHUTDOWN_HOST:
|
|
|
|
return "Host request";
|
|
|
|
|
2016-04-14 13:11:49 +00:00
|
|
|
case VIR_DOMAIN_EVENT_SHUTDOWN_LAST:
|
|
|
|
break;
|
2011-12-05 12:59:13 +00:00
|
|
|
}
|
|
|
|
break;
|
2016-04-14 12:51:40 +00:00
|
|
|
|
2012-09-06 15:00:43 +00:00
|
|
|
case VIR_DOMAIN_EVENT_PMSUSPENDED:
|
|
|
|
switch ((virDomainEventPMSuspendedDetailType) detail) {
|
|
|
|
case VIR_DOMAIN_EVENT_PMSUSPENDED_MEMORY:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Memory";
|
|
|
|
|
2012-10-12 19:13:39 +00:00
|
|
|
case VIR_DOMAIN_EVENT_PMSUSPENDED_DISK:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Disk";
|
2016-04-14 13:11:49 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_EVENT_PMSUSPENDED_LAST:
|
|
|
|
break;
|
2012-09-06 15:00:43 +00:00
|
|
|
}
|
|
|
|
break;
|
2016-04-14 12:51:40 +00:00
|
|
|
|
2013-06-07 10:23:31 +00:00
|
|
|
case VIR_DOMAIN_EVENT_CRASHED:
|
|
|
|
switch ((virDomainEventCrashedDetailType) detail) {
|
|
|
|
case VIR_DOMAIN_EVENT_CRASHED_PANICKED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Panicked";
|
2016-04-14 13:11:49 +00:00
|
|
|
|
qemu: support Panic Crashloaded event handling
Pvpanic device supports bit 1 as crashloaded event, it means that
guest actually panicked and run kexec to handle error by guest side.
Handle crashloaded as a lifecyle event in libvirt.
Test case:
Guest side:
before testing, we need make sure kdump is enabled,
1, build new pvpanic driver (with commit from upstream
e0b9a42735f2672ca2764cfbea6e55a81098d5ba
191941692a3d1b6a9614502b279be062926b70f5)
2, insmod new kmod
3, enable crash_kexec_post_notifiers,
# echo 1 > /sys/module/kernel/parameters/crash_kexec_post_notifiers
4, trigger kernel panic
# echo 1 > /proc/sys/kernel/sysrq
# echo c > /proc/sysrq-trigger
Host side:
1, build new qemu with pvpanic patches (with commit from upstream
600d7b47e8f5085919fd1d1157f25950ea8dbc11
7dc58deea79a343ac3adc5cadb97215086054c86)
2, build libvirt with this patch
3, handle lifecycle event and trigger guest side panic
# virsh event stretch --event lifecycle
event 'lifecycle' for domain stretch: Crashed Crashloaded
events received: 1
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
2020-02-04 07:41:00 +00:00
|
|
|
case VIR_DOMAIN_EVENT_CRASHED_CRASHLOADED:
|
|
|
|
return "Crashloaded";
|
|
|
|
|
2016-04-14 13:11:49 +00:00
|
|
|
case VIR_DOMAIN_EVENT_CRASHED_LAST:
|
|
|
|
break;
|
2013-06-07 10:23:31 +00:00
|
|
|
}
|
|
|
|
break;
|
2016-04-14 13:11:49 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_EVENT_LAST:
|
|
|
|
break;
|
2008-10-23 13:18:18 +00:00
|
|
|
}
|
2016-04-14 12:51:40 +00:00
|
|
|
|
|
|
|
return "unknown";
|
2008-10-23 13:18:18 +00:00
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
2013-12-11 14:23:24 +00:00
|
|
|
static const char *
|
|
|
|
networkEventToString(int event)
|
|
|
|
{
|
|
|
|
switch ((virNetworkEventLifecycleType) event) {
|
|
|
|
case VIR_NETWORK_EVENT_DEFINED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Defined";
|
|
|
|
|
2013-12-11 14:23:24 +00:00
|
|
|
case VIR_NETWORK_EVENT_UNDEFINED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Undefined";
|
|
|
|
|
2013-12-11 14:23:24 +00:00
|
|
|
case VIR_NETWORK_EVENT_STARTED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Started";
|
|
|
|
|
2013-12-11 14:23:24 +00:00
|
|
|
case VIR_NETWORK_EVENT_STOPPED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Stopped";
|
|
|
|
|
2016-04-14 13:11:49 +00:00
|
|
|
case VIR_NETWORK_EVENT_LAST:
|
|
|
|
break;
|
2013-12-11 14:23:24 +00:00
|
|
|
}
|
2016-04-14 12:51:40 +00:00
|
|
|
|
|
|
|
return "unknown";
|
2013-12-11 14:23:24 +00:00
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
2014-11-19 09:27:55 +00:00
|
|
|
static const char *
|
|
|
|
guestAgentLifecycleEventStateToString(int event)
|
|
|
|
{
|
|
|
|
switch ((virConnectDomainEventAgentLifecycleState) event) {
|
|
|
|
case VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_STATE_DISCONNECTED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Disconnected";
|
2014-11-19 09:27:55 +00:00
|
|
|
|
|
|
|
case VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_STATE_CONNECTED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Connected";
|
2016-04-14 13:11:49 +00:00
|
|
|
|
|
|
|
case VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_STATE_LAST:
|
|
|
|
break;
|
2014-11-19 09:27:55 +00:00
|
|
|
}
|
|
|
|
|
2016-04-14 12:51:40 +00:00
|
|
|
return "unknown";
|
2014-11-19 09:27:55 +00:00
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
2014-11-19 09:27:55 +00:00
|
|
|
static const char *
|
|
|
|
guestAgentLifecycleEventReasonToString(int event)
|
|
|
|
{
|
|
|
|
switch ((virConnectDomainEventAgentLifecycleReason) event) {
|
|
|
|
case VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_UNKNOWN:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Unknown";
|
2014-11-19 09:27:55 +00:00
|
|
|
|
|
|
|
case VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_DOMAIN_STARTED:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Domain started";
|
2014-11-19 09:27:55 +00:00
|
|
|
|
|
|
|
case VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_CHANNEL:
|
2016-04-14 12:51:40 +00:00
|
|
|
return "Channel event";
|
2016-04-14 13:11:49 +00:00
|
|
|
|
|
|
|
case VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_LAST:
|
|
|
|
break;
|
2014-11-19 09:27:55 +00:00
|
|
|
}
|
|
|
|
|
2016-04-14 12:51:40 +00:00
|
|
|
return "unknown";
|
2014-11-19 09:27:55 +00:00
|
|
|
}
|
|
|
|
|
2016-06-15 18:50:18 +00:00
|
|
|
static const char *
|
|
|
|
storagePoolEventToString(int event)
|
|
|
|
{
|
|
|
|
switch ((virStoragePoolEventLifecycleType) event) {
|
|
|
|
case VIR_STORAGE_POOL_EVENT_DEFINED:
|
|
|
|
return "Defined";
|
|
|
|
case VIR_STORAGE_POOL_EVENT_UNDEFINED:
|
|
|
|
return "Undefined";
|
|
|
|
case VIR_STORAGE_POOL_EVENT_STARTED:
|
|
|
|
return "Started";
|
|
|
|
case VIR_STORAGE_POOL_EVENT_STOPPED:
|
|
|
|
return "Stopped";
|
2017-09-09 15:09:49 +00:00
|
|
|
case VIR_STORAGE_POOL_EVENT_CREATED:
|
|
|
|
return "Created";
|
|
|
|
case VIR_STORAGE_POOL_EVENT_DELETED:
|
|
|
|
return "Deleted";
|
2016-06-15 18:50:18 +00:00
|
|
|
case VIR_STORAGE_POOL_EVENT_LAST:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
|
2016-07-28 12:02:56 +00:00
|
|
|
static const char *
|
|
|
|
nodeDeviceEventToString(int event)
|
|
|
|
{
|
|
|
|
switch ((virNodeDeviceEventLifecycleType) event) {
|
|
|
|
case VIR_NODE_DEVICE_EVENT_CREATED:
|
|
|
|
return "Created";
|
|
|
|
case VIR_NODE_DEVICE_EVENT_DELETED:
|
|
|
|
return "Deleted";
|
|
|
|
case VIR_NODE_DEVICE_EVENT_LAST:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
|
2014-11-19 09:27:55 +00:00
|
|
|
|
2016-12-22 16:36:40 +00:00
|
|
|
static const char *
|
|
|
|
secretEventToString(int event)
|
|
|
|
{
|
|
|
|
switch ((virSecretEventLifecycleType) event) {
|
|
|
|
case VIR_SECRET_EVENT_DEFINED:
|
|
|
|
return "Defined";
|
|
|
|
|
|
|
|
case VIR_SECRET_EVENT_UNDEFINED:
|
|
|
|
return "Undefined";
|
|
|
|
|
|
|
|
case VIR_SECRET_EVENT_LAST:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventCallback1(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-13 13:45:52 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
int event,
|
|
|
|
int detail,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2008-10-23 13:18:18 +00:00
|
|
|
{
|
2008-12-18 12:25:11 +00:00
|
|
|
printf("%s EVENT: Domain %s(%d) %s %s\n", __func__, virDomainGetName(dom),
|
2008-11-17 16:43:00 +00:00
|
|
|
virDomainGetID(dom), eventToString(event),
|
|
|
|
eventDetailToString(event, detail));
|
2008-10-23 13:18:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventCallback2(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-13 13:45:52 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
int event,
|
|
|
|
int detail,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2008-10-23 13:18:18 +00:00
|
|
|
{
|
2008-12-18 12:25:11 +00:00
|
|
|
printf("%s EVENT: Domain %s(%d) %s %s\n", __func__, virDomainGetName(dom),
|
2008-11-17 16:43:00 +00:00
|
|
|
virDomainGetID(dom), eventToString(event),
|
|
|
|
eventDetailToString(event, detail));
|
2008-10-23 13:18:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventRebootCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-13 13:45:52 +00:00
|
|
|
virDomainPtr dom,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2010-03-18 15:25:38 +00:00
|
|
|
{
|
|
|
|
printf("%s EVENT: Domain %s(%d) rebooted\n", __func__, virDomainGetName(dom),
|
|
|
|
virDomainGetID(dom));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventRTCChangeCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-13 13:45:52 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
long long offset,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2010-03-18 18:28:15 +00:00
|
|
|
{
|
2013-07-29 18:53:36 +00:00
|
|
|
printf("%s EVENT: Domain %s(%d) rtc change %" PRIdMAX "\n",
|
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom),
|
|
|
|
(intmax_t)offset);
|
2010-03-18 18:28:15 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventBalloonChangeCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-13 13:45:52 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
unsigned long long actual,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2012-07-13 09:05:17 +00:00
|
|
|
{
|
|
|
|
printf("%s EVENT: Domain %s(%d) balloon change %" PRIuMAX "KB\n",
|
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom), (uintmax_t)actual);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventWatchdogCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-13 13:45:52 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
int action,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
Add support for an explicit watchdog event
This introduces a new event type
VIR_DOMAIN_EVENT_ID_WATCHDOG
This event includes the action that is about to be taken
as a result of the watchdog triggering
typedef enum {
VIR_DOMAIN_EVENT_WATCHDOG_NONE = 0,
VIR_DOMAIN_EVENT_WATCHDOG_PAUSE,
VIR_DOMAIN_EVENT_WATCHDOG_RESET,
VIR_DOMAIN_EVENT_WATCHDOG_POWEROFF,
VIR_DOMAIN_EVENT_WATCHDOG_SHUTDOWN,
VIR_DOMAIN_EVENT_WATCHDOG_DEBUG,
} virDomainEventWatchdogAction;
Thus there is a new callback definition for this event type
typedef void (*virConnectDomainEventWatchdogCallback)(virConnectPtr conn,
virDomainPtr dom,
int action,
void *opaque);
* daemon/remote.c: Dispatch watchdog events to client
* examples/domain-events/events-c/event-test.c: Watch for
watchdog events
* include/libvirt/libvirt.h.in: Define new watchdg event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle watchdog events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for watchdogs and emit a libvirt watchdog event
* src/remote/remote_driver.c: Receive and dispatch watchdog
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
watchdog events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for WATCHDOG event
from QEMU monitor
2010-03-18 19:07:48 +00:00
|
|
|
{
|
2016-04-13 13:45:52 +00:00
|
|
|
printf("%s EVENT: Domain %s(%d) watchdog action=%d\n", __func__,
|
|
|
|
virDomainGetName(dom), virDomainGetID(dom), action);
|
Add support for an explicit watchdog event
This introduces a new event type
VIR_DOMAIN_EVENT_ID_WATCHDOG
This event includes the action that is about to be taken
as a result of the watchdog triggering
typedef enum {
VIR_DOMAIN_EVENT_WATCHDOG_NONE = 0,
VIR_DOMAIN_EVENT_WATCHDOG_PAUSE,
VIR_DOMAIN_EVENT_WATCHDOG_RESET,
VIR_DOMAIN_EVENT_WATCHDOG_POWEROFF,
VIR_DOMAIN_EVENT_WATCHDOG_SHUTDOWN,
VIR_DOMAIN_EVENT_WATCHDOG_DEBUG,
} virDomainEventWatchdogAction;
Thus there is a new callback definition for this event type
typedef void (*virConnectDomainEventWatchdogCallback)(virConnectPtr conn,
virDomainPtr dom,
int action,
void *opaque);
* daemon/remote.c: Dispatch watchdog events to client
* examples/domain-events/events-c/event-test.c: Watch for
watchdog events
* include/libvirt/libvirt.h.in: Define new watchdg event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle watchdog events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for watchdogs and emit a libvirt watchdog event
* src/remote/remote_driver.c: Receive and dispatch watchdog
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
watchdog events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for WATCHDOG event
from QEMU monitor
2010-03-18 19:07:48 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventIOErrorCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-13 13:45:52 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
const char *srcPath,
|
|
|
|
const char *devAlias,
|
|
|
|
int action,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
Add support for an explicit IO error event
This introduces a new event type
VIR_DOMAIN_EVENT_ID_IO_ERROR
This event includes the action that is about to be taken
as a result of the watchdog triggering
typedef enum {
VIR_DOMAIN_EVENT_IO_ERROR_NONE = 0,
VIR_DOMAIN_EVENT_IO_ERROR_PAUSE,
VIR_DOMAIN_EVENT_IO_ERROR_REPORT,
} virDomainEventIOErrorAction;
In addition it has the source path of the disk that had the
error and its unique device alias. It does not include the
target device name (/dev/sda), since this would preclude
triggering IO errors from other file backed devices (eg
serial ports connected to a file)
Thus there is a new callback definition for this event type
typedef void (*virConnectDomainEventIOErrorCallback)(virConnectPtr conn,
virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action,
void *opaque);
This is currently wired up to the QEMU block IO error events
* daemon/remote.c: Dispatch IO error events to client
* examples/domain-events/events-c/event-test.c: Watch for
IO error events
* include/libvirt/libvirt.h.in: Define new IO error event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle IO error events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for block IO errors and emit a libvirt IO error event
* src/remote/remote_driver.c: Receive and dispatch IO error
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
IO error events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for BLOCK_IO_ERROR event
from QEMU monitor
2010-03-18 19:37:44 +00:00
|
|
|
{
|
2016-04-13 13:45:52 +00:00
|
|
|
printf("%s EVENT: Domain %s(%d) io error path=%s alias=%s action=%d\n",
|
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom),
|
|
|
|
srcPath, devAlias, action);
|
Add support for an explicit IO error event
This introduces a new event type
VIR_DOMAIN_EVENT_ID_IO_ERROR
This event includes the action that is about to be taken
as a result of the watchdog triggering
typedef enum {
VIR_DOMAIN_EVENT_IO_ERROR_NONE = 0,
VIR_DOMAIN_EVENT_IO_ERROR_PAUSE,
VIR_DOMAIN_EVENT_IO_ERROR_REPORT,
} virDomainEventIOErrorAction;
In addition it has the source path of the disk that had the
error and its unique device alias. It does not include the
target device name (/dev/sda), since this would preclude
triggering IO errors from other file backed devices (eg
serial ports connected to a file)
Thus there is a new callback definition for this event type
typedef void (*virConnectDomainEventIOErrorCallback)(virConnectPtr conn,
virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action,
void *opaque);
This is currently wired up to the QEMU block IO error events
* daemon/remote.c: Dispatch IO error events to client
* examples/domain-events/events-c/event-test.c: Watch for
IO error events
* include/libvirt/libvirt.h.in: Define new IO error event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle IO error events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for block IO errors and emit a libvirt IO error event
* src/remote/remote_driver.c: Receive and dispatch IO error
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
IO error events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for BLOCK_IO_ERROR event
from QEMU monitor
2010-03-18 19:37:44 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
2016-04-14 15:48:13 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventIOErrorReasonCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-14 15:48:13 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
const char *srcPath,
|
|
|
|
const char *devAlias,
|
|
|
|
int action,
|
|
|
|
const char *reason,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2016-04-14 15:48:13 +00:00
|
|
|
{
|
|
|
|
printf("%s EVENT: Domain %s(%d) io error (reason) path=%s alias=%s "
|
|
|
|
"action=%d reason=%s\n",
|
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom),
|
|
|
|
srcPath, devAlias, action, reason);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-14 08:49:59 +00:00
|
|
|
static const char *
|
|
|
|
graphicsPhaseToStr(int phase)
|
|
|
|
{
|
|
|
|
switch ((virDomainEventGraphicsPhase) phase) {
|
|
|
|
case VIR_DOMAIN_EVENT_GRAPHICS_CONNECT:
|
|
|
|
return "connected";
|
|
|
|
|
|
|
|
case VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE:
|
|
|
|
return "initialized";
|
|
|
|
|
|
|
|
case VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT:
|
|
|
|
return "disconnected";
|
2016-04-14 13:11:49 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_EVENT_GRAPHICS_LAST:
|
|
|
|
break;
|
2016-04-14 08:49:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventGraphicsCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-13 13:45:52 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
int phase,
|
|
|
|
virDomainEventGraphicsAddressPtr local,
|
|
|
|
virDomainEventGraphicsAddressPtr remote,
|
|
|
|
const char *authScheme,
|
|
|
|
virDomainEventGraphicsSubjectPtr subject,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
Add domain events for graphics network clients
This introduces a new event type
VIR_DOMAIN_EVENT_ID_GRAPHICS
The same event can be emitted in 3 scenarios
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_CONNECT = 0,
VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE,
VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT,
} virDomainEventGraphicsPhase;
Connect/disconnect are triggered at socket accept/close.
The initialize phase is immediately after the protocol
setup and authentication has completed. ie when the
client is authorized and about to start interacting with
the graphical desktop
This event comes with *a lot* of potential information
- IP address, port & address family of client
- IP address, port & address family of server
- Authentication scheme (arbitrary string)
- Authenticated subject identity. A subject may have
multiple identities with some authentication schemes.
For example, vencrypt+sasl results in a x509dname
and saslUsername identities.
This results in a very complicated callback :-(
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4,
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV6,
} virDomainEventGraphicsAddressType;
struct _virDomainEventGraphicsAddress {
int family;
const char *node;
const char *service;
};
typedef struct _virDomainEventGraphicsAddress virDomainEventGraphicsAddress;
typedef virDomainEventGraphicsAddress *virDomainEventGraphicsAddressPtr;
struct _virDomainEventGraphicsSubject {
int nidentity;
struct {
const char *type;
const char *name;
} *identities;
};
typedef struct _virDomainEventGraphicsSubject virDomainEventGraphicsSubject;
typedef virDomainEventGraphicsSubject *virDomainEventGraphicsSubjectPtr;
typedef void (*virConnectDomainEventGraphicsCallback)(virConnectPtr conn,
virDomainPtr dom,
int phase,
virDomainEventGraphicsAddressPtr local,
virDomainEventGraphicsAddressPtr remote,
const char *authScheme,
virDomainEventGraphicsSubjectPtr subject,
void *opaque);
The wire protocol is similarly complex
struct remote_domain_event_graphics_address {
int family;
remote_nonnull_string node;
remote_nonnull_string service;
};
const REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX = 20;
struct remote_domain_event_graphics_identity {
remote_nonnull_string type;
remote_nonnull_string name;
};
struct remote_domain_event_graphics_msg {
remote_nonnull_domain dom;
int phase;
remote_domain_event_graphics_address local;
remote_domain_event_graphics_address remote;
remote_nonnull_string authScheme;
remote_domain_event_graphics_identity subject<REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX>;
};
This is currently implemented in QEMU for the VNC graphics
protocol, but designed to be usable with SPICE graphics in
the future too.
* daemon/remote.c: Dispatch graphics events to client
* examples/domain-events/events-c/event-test.c: Watch for
graphics events
* include/libvirt/libvirt.h.in: Define new graphics event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle graphics events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for VNC events and emit a libvirt graphics event
* src/remote/remote_driver.c: Receive and dispatch graphics
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
graphics events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for VNC_CONNECTED,
VNC_INITIALIZED & VNC_DISCONNETED events from QEMU monitor
2010-03-19 13:27:45 +00:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in examples/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
Add domain events for graphics network clients
This introduces a new event type
VIR_DOMAIN_EVENT_ID_GRAPHICS
The same event can be emitted in 3 scenarios
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_CONNECT = 0,
VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE,
VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT,
} virDomainEventGraphicsPhase;
Connect/disconnect are triggered at socket accept/close.
The initialize phase is immediately after the protocol
setup and authentication has completed. ie when the
client is authorized and about to start interacting with
the graphical desktop
This event comes with *a lot* of potential information
- IP address, port & address family of client
- IP address, port & address family of server
- Authentication scheme (arbitrary string)
- Authenticated subject identity. A subject may have
multiple identities with some authentication schemes.
For example, vencrypt+sasl results in a x509dname
and saslUsername identities.
This results in a very complicated callback :-(
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4,
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV6,
} virDomainEventGraphicsAddressType;
struct _virDomainEventGraphicsAddress {
int family;
const char *node;
const char *service;
};
typedef struct _virDomainEventGraphicsAddress virDomainEventGraphicsAddress;
typedef virDomainEventGraphicsAddress *virDomainEventGraphicsAddressPtr;
struct _virDomainEventGraphicsSubject {
int nidentity;
struct {
const char *type;
const char *name;
} *identities;
};
typedef struct _virDomainEventGraphicsSubject virDomainEventGraphicsSubject;
typedef virDomainEventGraphicsSubject *virDomainEventGraphicsSubjectPtr;
typedef void (*virConnectDomainEventGraphicsCallback)(virConnectPtr conn,
virDomainPtr dom,
int phase,
virDomainEventGraphicsAddressPtr local,
virDomainEventGraphicsAddressPtr remote,
const char *authScheme,
virDomainEventGraphicsSubjectPtr subject,
void *opaque);
The wire protocol is similarly complex
struct remote_domain_event_graphics_address {
int family;
remote_nonnull_string node;
remote_nonnull_string service;
};
const REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX = 20;
struct remote_domain_event_graphics_identity {
remote_nonnull_string type;
remote_nonnull_string name;
};
struct remote_domain_event_graphics_msg {
remote_nonnull_domain dom;
int phase;
remote_domain_event_graphics_address local;
remote_domain_event_graphics_address remote;
remote_nonnull_string authScheme;
remote_domain_event_graphics_identity subject<REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX>;
};
This is currently implemented in QEMU for the VNC graphics
protocol, but designed to be usable with SPICE graphics in
the future too.
* daemon/remote.c: Dispatch graphics events to client
* examples/domain-events/events-c/event-test.c: Watch for
graphics events
* include/libvirt/libvirt.h.in: Define new graphics event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle graphics events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for VNC events and emit a libvirt graphics event
* src/remote/remote_driver.c: Receive and dispatch graphics
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
graphics events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for VNC_CONNECTED,
VNC_INITIALIZED & VNC_DISCONNETED events from QEMU monitor
2010-03-19 13:27:45 +00:00
|
|
|
printf("%s EVENT: Domain %s(%d) graphics ", __func__, virDomainGetName(dom),
|
|
|
|
virDomainGetID(dom));
|
|
|
|
|
2016-04-14 08:49:59 +00:00
|
|
|
printf("%s ", graphicsPhaseToStr(phase));
|
Add domain events for graphics network clients
This introduces a new event type
VIR_DOMAIN_EVENT_ID_GRAPHICS
The same event can be emitted in 3 scenarios
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_CONNECT = 0,
VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE,
VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT,
} virDomainEventGraphicsPhase;
Connect/disconnect are triggered at socket accept/close.
The initialize phase is immediately after the protocol
setup and authentication has completed. ie when the
client is authorized and about to start interacting with
the graphical desktop
This event comes with *a lot* of potential information
- IP address, port & address family of client
- IP address, port & address family of server
- Authentication scheme (arbitrary string)
- Authenticated subject identity. A subject may have
multiple identities with some authentication schemes.
For example, vencrypt+sasl results in a x509dname
and saslUsername identities.
This results in a very complicated callback :-(
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4,
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV6,
} virDomainEventGraphicsAddressType;
struct _virDomainEventGraphicsAddress {
int family;
const char *node;
const char *service;
};
typedef struct _virDomainEventGraphicsAddress virDomainEventGraphicsAddress;
typedef virDomainEventGraphicsAddress *virDomainEventGraphicsAddressPtr;
struct _virDomainEventGraphicsSubject {
int nidentity;
struct {
const char *type;
const char *name;
} *identities;
};
typedef struct _virDomainEventGraphicsSubject virDomainEventGraphicsSubject;
typedef virDomainEventGraphicsSubject *virDomainEventGraphicsSubjectPtr;
typedef void (*virConnectDomainEventGraphicsCallback)(virConnectPtr conn,
virDomainPtr dom,
int phase,
virDomainEventGraphicsAddressPtr local,
virDomainEventGraphicsAddressPtr remote,
const char *authScheme,
virDomainEventGraphicsSubjectPtr subject,
void *opaque);
The wire protocol is similarly complex
struct remote_domain_event_graphics_address {
int family;
remote_nonnull_string node;
remote_nonnull_string service;
};
const REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX = 20;
struct remote_domain_event_graphics_identity {
remote_nonnull_string type;
remote_nonnull_string name;
};
struct remote_domain_event_graphics_msg {
remote_nonnull_domain dom;
int phase;
remote_domain_event_graphics_address local;
remote_domain_event_graphics_address remote;
remote_nonnull_string authScheme;
remote_domain_event_graphics_identity subject<REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX>;
};
This is currently implemented in QEMU for the VNC graphics
protocol, but designed to be usable with SPICE graphics in
the future too.
* daemon/remote.c: Dispatch graphics events to client
* examples/domain-events/events-c/event-test.c: Watch for
graphics events
* include/libvirt/libvirt.h.in: Define new graphics event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle graphics events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for VNC events and emit a libvirt graphics event
* src/remote/remote_driver.c: Receive and dispatch graphics
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
graphics events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for VNC_CONNECTED,
VNC_INITIALIZED & VNC_DISCONNETED events from QEMU monitor
2010-03-19 13:27:45 +00:00
|
|
|
|
|
|
|
printf("local: family=%d node=%s service=%s ",
|
|
|
|
local->family, local->node, local->service);
|
|
|
|
printf("remote: family=%d node=%s service=%s ",
|
|
|
|
remote->family, remote->node, remote->service);
|
|
|
|
|
|
|
|
printf("auth: %s ", authScheme);
|
2013-05-21 08:04:26 +00:00
|
|
|
for (i = 0; i < subject->nidentity; i++) {
|
Add domain events for graphics network clients
This introduces a new event type
VIR_DOMAIN_EVENT_ID_GRAPHICS
The same event can be emitted in 3 scenarios
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_CONNECT = 0,
VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE,
VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT,
} virDomainEventGraphicsPhase;
Connect/disconnect are triggered at socket accept/close.
The initialize phase is immediately after the protocol
setup and authentication has completed. ie when the
client is authorized and about to start interacting with
the graphical desktop
This event comes with *a lot* of potential information
- IP address, port & address family of client
- IP address, port & address family of server
- Authentication scheme (arbitrary string)
- Authenticated subject identity. A subject may have
multiple identities with some authentication schemes.
For example, vencrypt+sasl results in a x509dname
and saslUsername identities.
This results in a very complicated callback :-(
typedef enum {
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4,
VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV6,
} virDomainEventGraphicsAddressType;
struct _virDomainEventGraphicsAddress {
int family;
const char *node;
const char *service;
};
typedef struct _virDomainEventGraphicsAddress virDomainEventGraphicsAddress;
typedef virDomainEventGraphicsAddress *virDomainEventGraphicsAddressPtr;
struct _virDomainEventGraphicsSubject {
int nidentity;
struct {
const char *type;
const char *name;
} *identities;
};
typedef struct _virDomainEventGraphicsSubject virDomainEventGraphicsSubject;
typedef virDomainEventGraphicsSubject *virDomainEventGraphicsSubjectPtr;
typedef void (*virConnectDomainEventGraphicsCallback)(virConnectPtr conn,
virDomainPtr dom,
int phase,
virDomainEventGraphicsAddressPtr local,
virDomainEventGraphicsAddressPtr remote,
const char *authScheme,
virDomainEventGraphicsSubjectPtr subject,
void *opaque);
The wire protocol is similarly complex
struct remote_domain_event_graphics_address {
int family;
remote_nonnull_string node;
remote_nonnull_string service;
};
const REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX = 20;
struct remote_domain_event_graphics_identity {
remote_nonnull_string type;
remote_nonnull_string name;
};
struct remote_domain_event_graphics_msg {
remote_nonnull_domain dom;
int phase;
remote_domain_event_graphics_address local;
remote_domain_event_graphics_address remote;
remote_nonnull_string authScheme;
remote_domain_event_graphics_identity subject<REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX>;
};
This is currently implemented in QEMU for the VNC graphics
protocol, but designed to be usable with SPICE graphics in
the future too.
* daemon/remote.c: Dispatch graphics events to client
* examples/domain-events/events-c/event-test.c: Watch for
graphics events
* include/libvirt/libvirt.h.in: Define new graphics event ID
and callback signature
* src/conf/domain_event.c, src/conf/domain_event.h,
src/libvirt_private.syms: Extend API to handle graphics events
* src/qemu/qemu_driver.c: Connect to the QEMU monitor event
for VNC events and emit a libvirt graphics event
* src/remote/remote_driver.c: Receive and dispatch graphics
events to application
* src/remote/remote_protocol.x: Wire protocol definition for
graphics events
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c: Watch for VNC_CONNECTED,
VNC_INITIALIZED & VNC_DISCONNETED events from QEMU monitor
2010-03-19 13:27:45 +00:00
|
|
|
printf(" identity: %s=%s",
|
|
|
|
subject->identities[i].type,
|
|
|
|
subject->identities[i].name);
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventControlErrorCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-13 13:45:52 +00:00
|
|
|
virDomainPtr dom,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2011-05-29 12:21:53 +00:00
|
|
|
{
|
2016-04-13 13:45:52 +00:00
|
|
|
printf("%s EVENT: Domain %s(%d) control error\n", __func__,
|
|
|
|
virDomainGetName(dom), virDomainGetID(dom));
|
2011-05-29 12:21:53 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-13 15:38:16 +00:00
|
|
|
static const char *
|
|
|
|
diskChangeReasonToStr(int reason)
|
|
|
|
{
|
|
|
|
switch ((virConnectDomainEventDiskChangeReason) reason) {
|
|
|
|
case VIR_DOMAIN_EVENT_DISK_CHANGE_MISSING_ON_START:
|
|
|
|
return "disk empty due to startupPolicy";
|
|
|
|
|
|
|
|
case VIR_DOMAIN_EVENT_DISK_DROP_MISSING_ON_START:
|
|
|
|
return "disk dropped due to startupPolicy";
|
2016-04-14 13:11:49 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_EVENT_DISK_CHANGE_LAST:
|
|
|
|
break;
|
2016-04-13 15:38:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
|
2011-05-29 12:21:53 +00:00
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventDiskChangeCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-13 13:45:52 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
const char *oldSrcPath,
|
|
|
|
const char *newSrcPath,
|
|
|
|
const char *devAlias,
|
|
|
|
int reason,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2011-10-18 14:15:42 +00:00
|
|
|
{
|
2016-04-13 13:45:52 +00:00
|
|
|
printf("%s EVENT: Domain %s(%d) disk change oldSrcPath: %s newSrcPath: %s "
|
|
|
|
"devAlias: %s reason: %s\n",
|
2011-10-18 14:15:42 +00:00
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom),
|
2016-04-13 15:38:16 +00:00
|
|
|
oldSrcPath, newSrcPath, devAlias, diskChangeReasonToStr(reason));
|
2011-10-18 14:15:42 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-13 15:38:16 +00:00
|
|
|
static const char *
|
|
|
|
trayChangeReasonToStr(int reason)
|
|
|
|
{
|
|
|
|
switch ((virDomainEventTrayChangeReason) reason) {
|
|
|
|
case VIR_DOMAIN_EVENT_TRAY_CHANGE_OPEN:
|
|
|
|
return "open";
|
|
|
|
|
|
|
|
case VIR_DOMAIN_EVENT_TRAY_CHANGE_CLOSE:
|
|
|
|
return "close";
|
2016-04-14 13:11:49 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_EVENT_TRAY_CHANGE_LAST:
|
|
|
|
break;
|
2016-04-13 15:38:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return "unknown";
|
2012-03-23 13:44:50 +00:00
|
|
|
};
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventTrayChangeCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-13 13:45:52 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
const char *devAlias,
|
|
|
|
int reason,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2012-03-23 13:44:50 +00:00
|
|
|
{
|
2016-04-13 13:45:52 +00:00
|
|
|
printf("%s EVENT: Domain %s(%d) removable disk's tray change devAlias: %s "
|
|
|
|
"reason: %s\n",
|
2012-03-23 13:44:50 +00:00
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom),
|
2016-04-13 15:38:16 +00:00
|
|
|
devAlias, trayChangeReasonToStr(reason));
|
2012-03-23 13:44:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2011-10-18 14:15:42 +00:00
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventPMWakeupCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-13 13:45:52 +00:00
|
|
|
virDomainPtr dom,
|
2019-10-14 12:45:33 +00:00
|
|
|
int reason G_GNUC_UNUSED,
|
|
|
|
void *opaque G_GNUC_UNUSED)
|
2012-03-23 14:43:14 +00:00
|
|
|
{
|
2012-09-06 14:56:08 +00:00
|
|
|
printf("%s EVENT: Domain %s(%d) system pmwakeup\n",
|
2012-03-23 14:43:14 +00:00
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventPMSuspendCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-13 13:45:52 +00:00
|
|
|
virDomainPtr dom,
|
2019-10-14 12:45:33 +00:00
|
|
|
int reason G_GNUC_UNUSED,
|
|
|
|
void *opaque G_GNUC_UNUSED)
|
2012-03-23 14:50:36 +00:00
|
|
|
{
|
2012-09-06 14:56:08 +00:00
|
|
|
printf("%s EVENT: Domain %s(%d) system pmsuspend\n",
|
2012-03-23 14:50:36 +00:00
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventPMSuspendDiskCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-13 13:45:52 +00:00
|
|
|
virDomainPtr dom,
|
2019-10-14 12:45:33 +00:00
|
|
|
int reason G_GNUC_UNUSED,
|
|
|
|
void *opaque G_GNUC_UNUSED)
|
2012-10-12 19:13:39 +00:00
|
|
|
{
|
|
|
|
printf("%s EVENT: Domain %s(%d) system pmsuspend-disk\n",
|
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
2013-06-19 13:28:00 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventDeviceRemovedCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2013-06-19 13:28:00 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
const char *devAlias,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2013-06-19 13:28:00 +00:00
|
|
|
{
|
|
|
|
printf("%s EVENT: Domain %s(%d) device removed: %s\n",
|
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom), devAlias);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myNetworkEventCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-13 13:45:52 +00:00
|
|
|
virNetworkPtr dom,
|
|
|
|
int event,
|
|
|
|
int detail,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2013-12-11 14:23:24 +00:00
|
|
|
{
|
|
|
|
printf("%s EVENT: Network %s %s %d\n", __func__, virNetworkGetName(dom),
|
|
|
|
networkEventToString(event), detail);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-15 18:50:18 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myStoragePoolEventCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-06-15 18:50:18 +00:00
|
|
|
virStoragePoolPtr pool,
|
|
|
|
int event,
|
|
|
|
int detail,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2016-06-15 18:50:18 +00:00
|
|
|
{
|
|
|
|
printf("%s EVENT: Storage pool %s %s %d\n", __func__,
|
|
|
|
virStoragePoolGetName(pool),
|
|
|
|
storagePoolEventToString(event),
|
|
|
|
detail);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-24 16:35:51 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myStoragePoolEventRefreshCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-06-24 16:35:51 +00:00
|
|
|
virStoragePoolPtr pool,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2016-06-24 16:35:51 +00:00
|
|
|
{
|
|
|
|
printf("%s EVENT: Storage pool %s refresh\n", __func__,
|
|
|
|
virStoragePoolGetName(pool));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-28 12:02:56 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myNodeDeviceEventCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-07-28 12:02:56 +00:00
|
|
|
virNodeDevicePtr dev,
|
|
|
|
int event,
|
|
|
|
int detail,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2016-07-28 12:02:56 +00:00
|
|
|
{
|
|
|
|
printf("%s EVENT: Node device %s %s %d\n", __func__,
|
|
|
|
virNodeDeviceGetName(dev),
|
|
|
|
nodeDeviceEventToString(event),
|
|
|
|
detail);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-11 15:15:23 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myNodeDeviceEventUpdateCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-08-11 15:15:23 +00:00
|
|
|
virNodeDevicePtr dev,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2016-08-11 15:15:23 +00:00
|
|
|
{
|
|
|
|
printf("%s EVENT: Node device %s update\n", __func__,
|
|
|
|
virNodeDeviceGetName(dev));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-22 16:36:40 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
mySecretEventCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-12-22 16:36:40 +00:00
|
|
|
virSecretPtr secret,
|
|
|
|
int event,
|
|
|
|
int detail,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2016-12-22 16:36:40 +00:00
|
|
|
{
|
|
|
|
char uuid[VIR_UUID_STRING_BUFLEN];
|
|
|
|
virSecretGetUUIDString(secret, uuid);
|
|
|
|
printf("%s EVENT: Secret %s %s %d\n", __func__,
|
|
|
|
uuid,
|
|
|
|
secretEventToString(event),
|
|
|
|
detail);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-05 13:51:07 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
mySecretEventValueChanged(virConnectPtr conn G_GNUC_UNUSED,
|
2017-01-05 13:51:07 +00:00
|
|
|
virSecretPtr secret,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2017-01-05 13:51:07 +00:00
|
|
|
{
|
|
|
|
char uuid[VIR_UUID_STRING_BUFLEN];
|
|
|
|
virSecretGetUUIDString(secret, uuid);
|
|
|
|
printf("%s EVENT: Secret %s\n", __func__, uuid);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-14 15:31:52 +00:00
|
|
|
static void
|
|
|
|
eventTypedParamsPrint(virTypedParameterPtr params,
|
|
|
|
int nparams)
|
2014-08-26 21:47:44 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < nparams; i++) {
|
|
|
|
switch (params[i].type) {
|
|
|
|
case VIR_TYPED_PARAM_INT:
|
|
|
|
printf("\t%s: %d\n", params[i].field, params[i].value.i);
|
|
|
|
break;
|
|
|
|
case VIR_TYPED_PARAM_UINT:
|
|
|
|
printf("\t%s: %u\n", params[i].field, params[i].value.ui);
|
|
|
|
break;
|
|
|
|
case VIR_TYPED_PARAM_LLONG:
|
2014-09-25 13:03:46 +00:00
|
|
|
printf("\t%s: %" PRId64 "\n", params[i].field,
|
|
|
|
(int64_t) params[i].value.l);
|
2014-08-26 21:47:44 +00:00
|
|
|
break;
|
|
|
|
case VIR_TYPED_PARAM_ULLONG:
|
2014-09-25 13:03:46 +00:00
|
|
|
printf("\t%s: %" PRIu64 "\n", params[i].field,
|
|
|
|
(uint64_t) params[i].value.ul);
|
2014-08-26 21:47:44 +00:00
|
|
|
break;
|
|
|
|
case VIR_TYPED_PARAM_DOUBLE:
|
|
|
|
printf("\t%s: %g\n", params[i].field, params[i].value.d);
|
|
|
|
break;
|
|
|
|
case VIR_TYPED_PARAM_BOOLEAN:
|
|
|
|
printf("\t%s: %d\n", params[i].field, params[i].value.b);
|
|
|
|
break;
|
|
|
|
case VIR_TYPED_PARAM_STRING:
|
|
|
|
printf("\t%s: %s\n", params[i].field, params[i].value.s);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("\t%s: unknown type\n", params[i].field);
|
|
|
|
}
|
|
|
|
}
|
2016-04-14 15:31:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventTunableCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-14 15:31:52 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
virTypedParameterPtr params,
|
|
|
|
int nparams,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2016-04-14 15:31:52 +00:00
|
|
|
{
|
|
|
|
printf("%s EVENT: Domain %s(%d) tunable updated:\n",
|
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom));
|
|
|
|
|
|
|
|
eventTypedParamsPrint(params, nparams);
|
2014-08-26 21:47:44 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2013-12-11 14:23:24 +00:00
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
2014-11-19 09:27:55 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventAgentLifecycleCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2014-11-19 09:27:55 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
int state,
|
|
|
|
int reason,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2014-11-19 09:27:55 +00:00
|
|
|
{
|
|
|
|
printf("%s EVENT: Domain %s(%d) guest agent state changed: %s reason: %s\n",
|
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom),
|
|
|
|
guestAgentLifecycleEventStateToString(state),
|
|
|
|
guestAgentLifecycleEventReasonToString(reason));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
2015-04-14 12:56:09 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventDeviceAddedCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2015-04-14 12:56:09 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
const char *devAlias,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2015-04-14 12:56:09 +00:00
|
|
|
{
|
|
|
|
printf("%s EVENT: Domain %s(%d) device added: %s\n",
|
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom), devAlias);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
|
2016-04-14 15:16:35 +00:00
|
|
|
static const char *
|
|
|
|
blockJobTypeToStr(int type)
|
|
|
|
{
|
|
|
|
switch ((virDomainBlockJobType) type) {
|
|
|
|
case VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN:
|
|
|
|
case VIR_DOMAIN_BLOCK_JOB_TYPE_LAST:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_BLOCK_JOB_TYPE_PULL:
|
|
|
|
return "block pull";
|
|
|
|
|
|
|
|
case VIR_DOMAIN_BLOCK_JOB_TYPE_COPY:
|
|
|
|
return "block copy";
|
|
|
|
|
|
|
|
case VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT:
|
|
|
|
return "block commit";
|
|
|
|
|
|
|
|
case VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT:
|
|
|
|
return "active layer block commit";
|
2019-10-18 13:10:33 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_BLOCK_JOB_TYPE_BACKUP:
|
|
|
|
return "backup";
|
2016-04-14 15:16:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
blockJobStatusToStr(int status)
|
|
|
|
{
|
|
|
|
switch ((virConnectDomainEventBlockJobStatus) status) {
|
|
|
|
case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
|
|
|
|
return "completed";
|
|
|
|
|
|
|
|
case VIR_DOMAIN_BLOCK_JOB_FAILED:
|
|
|
|
return "failed";
|
|
|
|
|
|
|
|
case VIR_DOMAIN_BLOCK_JOB_CANCELED:
|
|
|
|
return "cancelled";
|
|
|
|
|
|
|
|
case VIR_DOMAIN_BLOCK_JOB_READY:
|
|
|
|
return "ready";
|
|
|
|
|
|
|
|
case VIR_DOMAIN_BLOCK_JOB_LAST:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventBlockJobCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-14 15:16:35 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
const char *disk,
|
|
|
|
int type,
|
|
|
|
int status,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
const char *eventName = opaque;
|
|
|
|
|
|
|
|
printf("%s EVENT: Domain %s(%d) block job callback '%s' disk '%s', "
|
2021-02-19 13:07:53 +00:00
|
|
|
"type '%s' status '%s'\n",
|
2016-04-14 15:16:35 +00:00
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom), eventName,
|
|
|
|
disk, blockJobTypeToStr(type), blockJobStatusToStr(status));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-21 14:03:07 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventBlockThresholdCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2017-02-21 14:03:07 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
const char *dev,
|
|
|
|
const char *path,
|
|
|
|
unsigned long long threshold,
|
|
|
|
unsigned long long excess,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2017-02-21 14:03:07 +00:00
|
|
|
{
|
2019-01-08 19:46:48 +00:00
|
|
|
/* Casts to uint64_t to work around mingw not knowing %lld */
|
2017-02-21 14:03:07 +00:00
|
|
|
printf("%s EVENT: Domain %s(%d) block threshold callback dev '%s'(%s), "
|
2021-02-19 13:07:53 +00:00
|
|
|
"threshold: '%" PRIu64 "', excess: '%" PRIu64 "'\n",
|
2017-02-21 14:03:07 +00:00
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom),
|
2019-01-08 19:46:48 +00:00
|
|
|
dev, NULLSTR(path), (uint64_t)threshold, (uint64_t)excess);
|
2017-02-21 14:03:07 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-14 10:37:50 +00:00
|
|
|
static int
|
|
|
|
myDomainEventMemoryFailureCallback(virConnectPtr conn G_GNUC_UNUSED,
|
|
|
|
virDomainPtr dom,
|
|
|
|
int recipient,
|
|
|
|
int action,
|
|
|
|
unsigned int flags,
|
|
|
|
void *opaque G_GNUC_UNUSED)
|
|
|
|
{
|
|
|
|
printf("%s EVENT: Domain %s(%d) memory failure: recipient '%d', "
|
2021-02-19 13:07:53 +00:00
|
|
|
"aciont '%d', flags '%d'\n", __func__, virDomainGetName(dom),
|
2020-10-14 10:37:50 +00:00
|
|
|
virDomainGetID(dom), recipient, action, flags);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-14 15:26:53 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventMigrationIterationCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-14 15:26:53 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
int iteration,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2016-04-14 15:26:53 +00:00
|
|
|
{
|
|
|
|
printf("%s EVENT: Domain %s(%d) migration iteration '%d'\n",
|
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom), iteration);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-14 15:31:52 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventJobCompletedCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-14 15:31:52 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
virTypedParameterPtr params,
|
|
|
|
int nparams,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2016-04-14 15:31:52 +00:00
|
|
|
{
|
|
|
|
printf("%s EVENT: Domain %s(%d) job completed:\n",
|
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom));
|
|
|
|
|
|
|
|
eventTypedParamsPrint(params, nparams);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-14 15:34:50 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventDeviceRemovalFailedCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-04-14 15:34:50 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
const char *devAlias,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2016-04-14 15:34:50 +00:00
|
|
|
{
|
|
|
|
printf("%s EVENT: Domain %s(%d) device removal failed: %s\n",
|
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom), devAlias);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-22 14:41:30 +00:00
|
|
|
static const char *
|
|
|
|
metadataTypeToStr(int status)
|
|
|
|
{
|
|
|
|
switch ((virDomainMetadataType) status) {
|
|
|
|
case VIR_DOMAIN_METADATA_DESCRIPTION:
|
|
|
|
return "description";
|
|
|
|
|
|
|
|
case VIR_DOMAIN_METADATA_TITLE:
|
|
|
|
return "title";
|
|
|
|
|
|
|
|
case VIR_DOMAIN_METADATA_ELEMENT:
|
|
|
|
return "element";
|
|
|
|
|
|
|
|
case VIR_DOMAIN_METADATA_LAST:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
myDomainEventMetadataChangeCallback(virConnectPtr conn G_GNUC_UNUSED,
|
2016-12-22 14:41:30 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
int type,
|
|
|
|
const char *nsuri,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2016-12-22 14:41:30 +00:00
|
|
|
{
|
|
|
|
const char *typestr = metadataTypeToStr(type);
|
|
|
|
printf("%s EVENT: Domain %s(%d) metadata type: %s (%s)\n",
|
|
|
|
__func__, virDomainGetName(dom), virDomainGetID(dom), typestr, nsuri ? nsuri : "n/a");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-14 15:34:50 +00:00
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
static void
|
|
|
|
myFreeFunc(void *opaque)
|
2008-11-19 15:25:24 +00:00
|
|
|
{
|
|
|
|
char *str = opaque;
|
2008-12-18 12:25:11 +00:00
|
|
|
printf("%s: Freeing [%s]\n", __func__, str);
|
2008-11-19 15:25:24 +00:00
|
|
|
free(str);
|
|
|
|
}
|
|
|
|
|
2008-10-23 13:18:18 +00:00
|
|
|
|
|
|
|
/* main test functions */
|
2016-04-13 13:45:52 +00:00
|
|
|
static void
|
|
|
|
stop(int sig)
|
2008-11-19 15:25:24 +00:00
|
|
|
{
|
|
|
|
printf("Exiting on signal %d\n", sig);
|
|
|
|
run = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-14 14:57:02 +00:00
|
|
|
struct domainEventData {
|
|
|
|
int event;
|
|
|
|
int id;
|
|
|
|
virConnectDomainEventGenericCallback cb;
|
|
|
|
const char *name;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
#define DOMAIN_EVENT(event, callback) \
|
2016-04-14 14:57:02 +00:00
|
|
|
{event, -1, VIR_DOMAIN_EVENT_CALLBACK(callback), #event}
|
|
|
|
|
|
|
|
struct domainEventData domainEvents[] = {
|
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_LIFECYCLE, myDomainEventCallback2),
|
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_REBOOT, myDomainEventRebootCallback),
|
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_RTC_CHANGE, myDomainEventRTCChangeCallback),
|
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_WATCHDOG, myDomainEventWatchdogCallback),
|
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_IO_ERROR, myDomainEventIOErrorCallback),
|
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_GRAPHICS, myDomainEventGraphicsCallback),
|
2016-04-14 15:48:13 +00:00
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON, myDomainEventIOErrorReasonCallback),
|
2016-04-14 14:57:02 +00:00
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_CONTROL_ERROR, myDomainEventControlErrorCallback),
|
2016-04-14 15:16:35 +00:00
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_BLOCK_JOB, myDomainEventBlockJobCallback),
|
2016-04-14 14:57:02 +00:00
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_DISK_CHANGE, myDomainEventDiskChangeCallback),
|
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_TRAY_CHANGE, myDomainEventTrayChangeCallback),
|
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_PMWAKEUP, myDomainEventPMWakeupCallback),
|
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_PMSUSPEND, myDomainEventPMSuspendCallback),
|
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE, myDomainEventBalloonChangeCallback),
|
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK, myDomainEventPMSuspendDiskCallback),
|
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED, myDomainEventDeviceRemovedCallback),
|
2016-04-14 15:16:35 +00:00
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_BLOCK_JOB_2, myDomainEventBlockJobCallback),
|
2016-04-14 14:57:02 +00:00
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_TUNABLE, myDomainEventTunableCallback),
|
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE, myDomainEventAgentLifecycleCallback),
|
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_DEVICE_ADDED, myDomainEventDeviceAddedCallback),
|
2016-04-14 15:26:53 +00:00
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_MIGRATION_ITERATION, myDomainEventMigrationIterationCallback),
|
2016-04-14 15:31:52 +00:00
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_JOB_COMPLETED, myDomainEventJobCompletedCallback),
|
2016-04-14 15:34:50 +00:00
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED, myDomainEventDeviceRemovalFailedCallback),
|
2016-12-22 14:41:30 +00:00
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_METADATA_CHANGE, myDomainEventMetadataChangeCallback),
|
2017-02-21 14:03:07 +00:00
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD, myDomainEventBlockThresholdCallback),
|
2020-10-14 10:37:50 +00:00
|
|
|
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_MEMORY_FAILURE, myDomainEventMemoryFailureCallback),
|
2016-04-14 14:57:02 +00:00
|
|
|
};
|
|
|
|
|
2016-06-15 18:50:18 +00:00
|
|
|
struct storagePoolEventData {
|
|
|
|
int event;
|
|
|
|
int id;
|
|
|
|
virConnectStoragePoolEventGenericCallback cb;
|
|
|
|
const char *name;
|
|
|
|
};
|
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
#define STORAGE_POOL_EVENT(event, callback) \
|
2016-06-15 18:50:18 +00:00
|
|
|
{event, -1, VIR_STORAGE_POOL_EVENT_CALLBACK(callback), #event}
|
|
|
|
|
|
|
|
struct storagePoolEventData storagePoolEvents[] = {
|
|
|
|
STORAGE_POOL_EVENT(VIR_STORAGE_POOL_EVENT_ID_LIFECYCLE, myStoragePoolEventCallback),
|
2016-06-24 16:35:51 +00:00
|
|
|
STORAGE_POOL_EVENT(VIR_STORAGE_POOL_EVENT_ID_REFRESH, myStoragePoolEventRefreshCallback),
|
2016-06-15 18:50:18 +00:00
|
|
|
};
|
|
|
|
|
2016-07-28 12:02:56 +00:00
|
|
|
struct nodeDeviceEventData {
|
|
|
|
int event;
|
|
|
|
int id;
|
|
|
|
virConnectNodeDeviceEventGenericCallback cb;
|
|
|
|
const char *name;
|
|
|
|
};
|
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
#define NODE_DEVICE_EVENT(event, callback) \
|
2016-07-28 12:02:56 +00:00
|
|
|
{event, -1, VIR_NODE_DEVICE_EVENT_CALLBACK(callback), #event}
|
|
|
|
|
|
|
|
struct nodeDeviceEventData nodeDeviceEvents[] = {
|
|
|
|
NODE_DEVICE_EVENT(VIR_NODE_DEVICE_EVENT_ID_LIFECYCLE, myNodeDeviceEventCallback),
|
2016-08-11 15:15:23 +00:00
|
|
|
NODE_DEVICE_EVENT(VIR_NODE_DEVICE_EVENT_ID_UPDATE, myNodeDeviceEventUpdateCallback),
|
2016-07-28 12:02:56 +00:00
|
|
|
};
|
|
|
|
|
2016-12-22 16:36:40 +00:00
|
|
|
struct secretEventData {
|
|
|
|
int event;
|
|
|
|
int id;
|
|
|
|
virConnectSecretEventGenericCallback cb;
|
|
|
|
const char *name;
|
|
|
|
};
|
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
#define SECRET_EVENT(event, callback) \
|
2016-12-22 16:36:40 +00:00
|
|
|
{event, -1, VIR_SECRET_EVENT_CALLBACK(callback), #event}
|
|
|
|
|
|
|
|
struct secretEventData secretEvents[] = {
|
|
|
|
SECRET_EVENT(VIR_SECRET_EVENT_ID_LIFECYCLE, mySecretEventCallback),
|
2017-01-05 13:51:07 +00:00
|
|
|
SECRET_EVENT(VIR_SECRET_EVENT_ID_VALUE_CHANGED, mySecretEventValueChanged),
|
2016-12-22 16:36:40 +00:00
|
|
|
};
|
|
|
|
|
2016-04-14 15:41:19 +00:00
|
|
|
/* make sure that the events are kept in sync */
|
2020-01-09 10:39:55 +00:00
|
|
|
G_STATIC_ASSERT(G_N_ELEMENTS(domainEvents) == VIR_DOMAIN_EVENT_ID_LAST);
|
|
|
|
G_STATIC_ASSERT(G_N_ELEMENTS(storagePoolEvents) == VIR_STORAGE_POOL_EVENT_ID_LAST);
|
|
|
|
G_STATIC_ASSERT(G_N_ELEMENTS(nodeDeviceEvents) == VIR_NODE_DEVICE_EVENT_ID_LAST);
|
|
|
|
G_STATIC_ASSERT(G_N_ELEMENTS(secretEvents) == VIR_SECRET_EVENT_ID_LAST);
|
2016-04-14 15:41:19 +00:00
|
|
|
|
2016-04-13 13:45:52 +00:00
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
2008-10-23 13:18:18 +00:00
|
|
|
{
|
2016-03-16 08:55:47 +00:00
|
|
|
int ret = EXIT_FAILURE;
|
|
|
|
virConnectPtr dconn = NULL;
|
2009-05-25 09:44:10 +00:00
|
|
|
int callback1ret = -1;
|
2013-12-11 14:23:24 +00:00
|
|
|
int callback16ret = -1;
|
2016-04-14 14:57:02 +00:00
|
|
|
size_t i;
|
2010-03-18 17:47:02 +00:00
|
|
|
|
2011-03-23 14:30:30 +00:00
|
|
|
if (argc > 1 && STREQ(argv[1], "--help")) {
|
2016-04-13 13:21:17 +00:00
|
|
|
printf("%s uri\n", argv[0]);
|
2016-03-16 08:55:47 +00:00
|
|
|
goto cleanup;
|
2013-05-09 21:17:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virInitialize() < 0) {
|
|
|
|
fprintf(stderr, "Failed to initialize libvirt");
|
2016-03-16 08:55:47 +00:00
|
|
|
goto cleanup;
|
2008-10-23 13:18:18 +00:00
|
|
|
}
|
2008-11-19 15:25:24 +00:00
|
|
|
|
2013-05-09 21:17:44 +00:00
|
|
|
if (virEventRegisterDefaultImpl() < 0) {
|
|
|
|
fprintf(stderr, "Failed to register event implementation: %s\n",
|
2016-05-19 19:10:19 +00:00
|
|
|
virGetLastErrorMessage());
|
2016-03-16 08:55:47 +00:00
|
|
|
goto cleanup;
|
2013-05-09 21:17:44 +00:00
|
|
|
}
|
2008-10-23 13:18:18 +00:00
|
|
|
|
2011-11-22 11:09:13 +00:00
|
|
|
dconn = virConnectOpenAuth(argc > 1 ? argv[1] : NULL,
|
|
|
|
virConnectAuthPtrDefault,
|
|
|
|
VIR_CONNECT_RO);
|
2008-10-23 13:18:18 +00:00
|
|
|
if (!dconn) {
|
|
|
|
printf("error opening\n");
|
2016-03-16 08:55:47 +00:00
|
|
|
goto cleanup;
|
2008-10-23 13:18:18 +00:00
|
|
|
}
|
|
|
|
|
2016-03-16 08:32:44 +00:00
|
|
|
if (virConnectRegisterCloseCallback(dconn,
|
|
|
|
connectClose, NULL, NULL) < 0) {
|
|
|
|
fprintf(stderr, "Unable to register close callback\n");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-07-19 14:59:59 +00:00
|
|
|
|
2019-01-08 19:46:48 +00:00
|
|
|
/* The ideal program would use sigaction to set this handler, but
|
|
|
|
* this way is portable to mingw. */
|
|
|
|
signal(SIGTERM, stop);
|
|
|
|
signal(SIGINT, stop);
|
2008-11-19 15:25:24 +00:00
|
|
|
|
2016-04-13 11:55:12 +00:00
|
|
|
printf("Registering event callbacks\n");
|
2008-10-23 13:18:18 +00:00
|
|
|
|
2009-05-25 09:44:10 +00:00
|
|
|
callback1ret = virConnectDomainEventRegister(dconn, myDomainEventCallback1,
|
|
|
|
strdup("callback 1"), myFreeFunc);
|
2016-04-14 14:57:02 +00:00
|
|
|
|
|
|
|
/* register common domain callbacks */
|
2019-10-15 11:51:20 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(domainEvents); i++) {
|
2016-04-14 14:57:02 +00:00
|
|
|
struct domainEventData *event = domainEvents + i;
|
|
|
|
|
|
|
|
event->id = virConnectDomainEventRegisterAny(dconn, NULL,
|
|
|
|
event->event,
|
|
|
|
event->cb,
|
|
|
|
strdup(event->name),
|
|
|
|
myFreeFunc);
|
|
|
|
|
|
|
|
if (event->id < 0) {
|
|
|
|
fprintf(stderr, "Failed to register event '%s'\n", event->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-11 14:23:24 +00:00
|
|
|
callback16ret = virConnectNetworkEventRegisterAny(dconn,
|
|
|
|
NULL,
|
|
|
|
VIR_NETWORK_EVENT_ID_LIFECYCLE,
|
|
|
|
VIR_NETWORK_EVENT_CALLBACK(myNetworkEventCallback),
|
|
|
|
strdup("net callback"), myFreeFunc);
|
2013-06-19 13:28:00 +00:00
|
|
|
|
2016-06-15 18:50:18 +00:00
|
|
|
/* register common storage pool callbacks */
|
2019-10-15 11:51:20 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(storagePoolEvents); i++) {
|
2016-06-15 18:50:18 +00:00
|
|
|
struct storagePoolEventData *event = storagePoolEvents + i;
|
|
|
|
|
|
|
|
event->id = virConnectStoragePoolEventRegisterAny(dconn, NULL,
|
|
|
|
event->event,
|
|
|
|
event->cb,
|
|
|
|
strdup(event->name),
|
|
|
|
myFreeFunc);
|
|
|
|
|
|
|
|
if (event->id < 0) {
|
|
|
|
fprintf(stderr, "Failed to register event '%s'\n", event->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-28 12:02:56 +00:00
|
|
|
/* register common node device callbacks */
|
2019-10-15 11:51:20 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(nodeDeviceEvents); i++) {
|
2016-07-28 12:02:56 +00:00
|
|
|
struct nodeDeviceEventData *event = nodeDeviceEvents + i;
|
|
|
|
|
|
|
|
event->id = virConnectNodeDeviceEventRegisterAny(dconn, NULL,
|
|
|
|
event->event,
|
|
|
|
event->cb,
|
|
|
|
strdup(event->name),
|
|
|
|
myFreeFunc);
|
|
|
|
|
|
|
|
if (event->id < 0) {
|
|
|
|
fprintf(stderr, "Failed to register event '%s'\n", event->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-22 16:36:40 +00:00
|
|
|
/* register common secret callbacks */
|
2019-10-15 11:51:20 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(secretEvents); i++) {
|
2016-12-22 16:36:40 +00:00
|
|
|
struct secretEventData *event = secretEvents + i;
|
|
|
|
|
|
|
|
event->id = virConnectSecretEventRegisterAny(dconn, NULL,
|
|
|
|
event->event,
|
|
|
|
event->cb,
|
|
|
|
strdup(event->name),
|
|
|
|
myFreeFunc);
|
|
|
|
|
|
|
|
if (event->id < 0) {
|
|
|
|
fprintf(stderr, "Failed to register event '%s'\n", event->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-16 08:55:47 +00:00
|
|
|
if ((callback1ret == -1) ||
|
2016-04-14 14:57:02 +00:00
|
|
|
(callback16ret == -1))
|
2016-03-16 08:55:47 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virConnectSetKeepAlive(dconn, 5, 3) < 0) {
|
|
|
|
fprintf(stderr, "Failed to start keepalive protocol: %s\n",
|
2016-05-19 19:10:19 +00:00
|
|
|
virGetLastErrorMessage());
|
2016-03-16 08:55:47 +00:00
|
|
|
run = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (run) {
|
|
|
|
if (virEventRunDefaultImpl() < 0) {
|
|
|
|
fprintf(stderr, "Failed to run event loop: %s\n",
|
2016-05-19 19:10:19 +00:00
|
|
|
virGetLastErrorMessage());
|
2008-10-23 13:18:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-13 11:55:12 +00:00
|
|
|
printf("Deregistering event callbacks\n");
|
2016-03-16 08:55:47 +00:00
|
|
|
virConnectDomainEventDeregister(dconn, myDomainEventCallback1);
|
|
|
|
virConnectNetworkEventDeregisterAny(dconn, callback16ret);
|
|
|
|
|
2016-04-14 14:57:02 +00:00
|
|
|
|
|
|
|
printf("Deregistering domain event callbacks\n");
|
2019-10-15 11:51:20 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(domainEvents); i++) {
|
2016-04-14 14:57:02 +00:00
|
|
|
if (domainEvents[i].id > 0)
|
|
|
|
virConnectDomainEventDeregisterAny(dconn, domainEvents[i].id);
|
|
|
|
}
|
2016-03-16 08:55:47 +00:00
|
|
|
|
2016-06-15 18:50:18 +00:00
|
|
|
|
|
|
|
printf("Deregistering storage pool event callbacks\n");
|
2019-10-15 11:51:20 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(storagePoolEvents); i++) {
|
2016-06-15 18:50:18 +00:00
|
|
|
if (storagePoolEvents[i].id > 0)
|
|
|
|
virConnectStoragePoolEventDeregisterAny(dconn, storagePoolEvents[i].id);
|
|
|
|
}
|
|
|
|
|
2016-07-28 12:02:56 +00:00
|
|
|
|
|
|
|
printf("Deregistering node device event callbacks\n");
|
2019-10-15 11:51:20 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(nodeDeviceEvents); i++) {
|
2016-07-28 12:02:56 +00:00
|
|
|
if (nodeDeviceEvents[i].id > 0)
|
|
|
|
virConnectNodeDeviceEventDeregisterAny(dconn, nodeDeviceEvents[i].id);
|
|
|
|
}
|
|
|
|
|
2016-12-22 16:36:40 +00:00
|
|
|
printf("Deregistering secret event callbacks\n");
|
2019-10-15 11:51:20 +00:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(secretEvents); i++) {
|
2016-12-22 16:36:40 +00:00
|
|
|
if (secretEvents[i].id > 0)
|
|
|
|
virConnectSecretEventDeregisterAny(dconn, secretEvents[i].id);
|
|
|
|
}
|
|
|
|
|
2016-07-28 12:02:56 +00:00
|
|
|
|
2013-12-13 16:07:52 +00:00
|
|
|
virConnectUnregisterCloseCallback(dconn, connectClose);
|
2016-03-16 08:55:47 +00:00
|
|
|
ret = EXIT_SUCCESS;
|
2013-12-13 16:07:52 +00:00
|
|
|
|
2008-11-19 15:25:24 +00:00
|
|
|
|
2016-03-16 08:55:47 +00:00
|
|
|
cleanup:
|
|
|
|
if (dconn) {
|
2016-04-13 11:55:12 +00:00
|
|
|
printf("Closing connection: ");
|
2016-03-16 08:55:47 +00:00
|
|
|
if (virConnectClose(dconn) < 0)
|
2016-04-13 11:55:12 +00:00
|
|
|
printf("failed\n");
|
2016-03-16 08:55:47 +00:00
|
|
|
printf("done\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2008-10-23 13:18:18 +00:00
|
|
|
}
|