libvirt/examples/c/misc/event-test.c
zhenwei pi b866adf8d9 libvirt: support memory failure event
Introduce memory failure event. Libvirt should monitor domain's
event, then posts it to uplayer. According to the hardware memory
corrupted message, a cloud scheduler could migrate domain to another
health physical server.

Several changes in this patch:
public API:
    include/*
    src/conf/*
    src/remote/*
    src/remote_protocol-structs

client:
    examples/c/misc/event-test.c
    tools/virsh-domain.c

With this patch, each driver could implement its own method to run
this new event.

Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2020-10-23 09:41:52 +02:00

1347 lines
40 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <inttypes.h>
#define VIR_ENUM_SENTINELS
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
#define G_N_ELEMENTS(Array) (sizeof(Array) / sizeof(*(Array)))
#define STREQ(a, b) (strcmp(a, b) == 0)
#define NULLSTR(s) ((s) ? (s) : "<null>")
#if (4 < __GNUC__ + (6 <= __GNUC_MINOR__) \
&& (201112L <= __STDC_VERSION__ || !defined __STRICT_ANSI__) \
&& !defined __cplusplus)
# define G_STATIC_ASSERT(cond) _Static_assert(cond, "verify (" #cond ")")
#else
# define G_STATIC_ASSERT(cond)
#endif
#ifndef G_GNUC_UNUSED
# define G_GNUC_UNUSED __attribute__((__unused__))
#endif
int run = 1;
/* Callback functions */
static void
connectClose(virConnectPtr conn G_GNUC_UNUSED,
int reason,
void *opaque G_GNUC_UNUSED)
{
run = 0;
switch ((virConnectCloseReason) reason) {
case VIR_CONNECT_CLOSE_REASON_ERROR:
fprintf(stderr, "Connection closed due to I/O error\n");
return;
case VIR_CONNECT_CLOSE_REASON_EOF:
fprintf(stderr, "Connection closed due to end of file\n");
return;
case VIR_CONNECT_CLOSE_REASON_KEEPALIVE:
fprintf(stderr, "Connection closed due to keepalive timeout\n");
return;
case VIR_CONNECT_CLOSE_REASON_CLIENT:
fprintf(stderr, "Connection closed due to client request\n");
return;
case VIR_CONNECT_CLOSE_REASON_LAST:
break;
};
fprintf(stderr, "Connection closed due to unknown reason\n");
}
static const char *
eventToString(int event)
{
switch ((virDomainEventType) event) {
case VIR_DOMAIN_EVENT_DEFINED:
return "Defined";
case VIR_DOMAIN_EVENT_UNDEFINED:
return "Undefined";
case VIR_DOMAIN_EVENT_STARTED:
return "Started";
case VIR_DOMAIN_EVENT_SUSPENDED:
return "Suspended";
case VIR_DOMAIN_EVENT_RESUMED:
return "Resumed";
case VIR_DOMAIN_EVENT_STOPPED:
return "Stopped";
case VIR_DOMAIN_EVENT_SHUTDOWN:
return "Shutdown";
case VIR_DOMAIN_EVENT_PMSUSPENDED:
return "PMSuspended";
case VIR_DOMAIN_EVENT_CRASHED:
return "Crashed";
case VIR_DOMAIN_EVENT_LAST:
break;
}
return "unknown";
}
static const char *
eventDetailToString(int event,
int detail)
{
switch ((virDomainEventType) event) {
case VIR_DOMAIN_EVENT_DEFINED:
switch ((virDomainEventDefinedDetailType) detail) {
case VIR_DOMAIN_EVENT_DEFINED_ADDED:
return "Added";
case VIR_DOMAIN_EVENT_DEFINED_UPDATED:
return "Updated";
case VIR_DOMAIN_EVENT_DEFINED_RENAMED:
return "Renamed";
case VIR_DOMAIN_EVENT_DEFINED_FROM_SNAPSHOT:
return "Snapshot";
case VIR_DOMAIN_EVENT_DEFINED_LAST:
break;
}
break;
case VIR_DOMAIN_EVENT_UNDEFINED:
switch ((virDomainEventUndefinedDetailType) detail) {
case VIR_DOMAIN_EVENT_UNDEFINED_REMOVED:
return "Removed";
case VIR_DOMAIN_EVENT_UNDEFINED_RENAMED:
return "Renamed";
case VIR_DOMAIN_EVENT_UNDEFINED_LAST:
break;
}
break;
case VIR_DOMAIN_EVENT_STARTED:
switch ((virDomainEventStartedDetailType) detail) {
case VIR_DOMAIN_EVENT_STARTED_BOOTED:
return "Booted";
case VIR_DOMAIN_EVENT_STARTED_MIGRATED:
return "Migrated";
case VIR_DOMAIN_EVENT_STARTED_RESTORED:
return "Restored";
case VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT:
return "Snapshot";
case VIR_DOMAIN_EVENT_STARTED_WAKEUP:
return "Event wakeup";
case VIR_DOMAIN_EVENT_STARTED_LAST:
break;
}
break;
case VIR_DOMAIN_EVENT_SUSPENDED:
switch ((virDomainEventSuspendedDetailType) detail) {
case VIR_DOMAIN_EVENT_SUSPENDED_PAUSED:
return "Paused";
case VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED:
return "Migrated";
case VIR_DOMAIN_EVENT_SUSPENDED_IOERROR:
return "I/O Error";
case VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG:
return "Watchdog";
case VIR_DOMAIN_EVENT_SUSPENDED_RESTORED:
return "Restored";
case VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT:
return "Snapshot";
case VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR:
return "API error";
case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY:
return "Post-copy";
case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY_FAILED:
return "Post-copy Error";
case VIR_DOMAIN_EVENT_SUSPENDED_LAST:
break;
}
break;
case VIR_DOMAIN_EVENT_RESUMED:
switch ((virDomainEventResumedDetailType) detail) {
case VIR_DOMAIN_EVENT_RESUMED_UNPAUSED:
return "Unpaused";
case VIR_DOMAIN_EVENT_RESUMED_MIGRATED:
return "Migrated";
case VIR_DOMAIN_EVENT_RESUMED_FROM_SNAPSHOT:
return "Snapshot";
case VIR_DOMAIN_EVENT_RESUMED_POSTCOPY:
return "Post-copy";
case VIR_DOMAIN_EVENT_RESUMED_LAST:
break;
}
break;
case VIR_DOMAIN_EVENT_STOPPED:
switch ((virDomainEventStoppedDetailType) detail) {
case VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN:
return "Shutdown";
case VIR_DOMAIN_EVENT_STOPPED_DESTROYED:
return "Destroyed";
case VIR_DOMAIN_EVENT_STOPPED_CRASHED:
return "Crashed";
case VIR_DOMAIN_EVENT_STOPPED_MIGRATED:
return "Migrated";
case VIR_DOMAIN_EVENT_STOPPED_SAVED:
return "Saved";
case VIR_DOMAIN_EVENT_STOPPED_FAILED:
return "Failed";
case VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT:
return "Snapshot";
case VIR_DOMAIN_EVENT_STOPPED_LAST:
break;
}
break;
case VIR_DOMAIN_EVENT_SHUTDOWN:
switch ((virDomainEventShutdownDetailType) detail) {
case VIR_DOMAIN_EVENT_SHUTDOWN_FINISHED:
return "Finished";
case VIR_DOMAIN_EVENT_SHUTDOWN_GUEST:
return "Guest request";
case VIR_DOMAIN_EVENT_SHUTDOWN_HOST:
return "Host request";
case VIR_DOMAIN_EVENT_SHUTDOWN_LAST:
break;
}
break;
case VIR_DOMAIN_EVENT_PMSUSPENDED:
switch ((virDomainEventPMSuspendedDetailType) detail) {
case VIR_DOMAIN_EVENT_PMSUSPENDED_MEMORY:
return "Memory";
case VIR_DOMAIN_EVENT_PMSUSPENDED_DISK:
return "Disk";
case VIR_DOMAIN_EVENT_PMSUSPENDED_LAST:
break;
}
break;
case VIR_DOMAIN_EVENT_CRASHED:
switch ((virDomainEventCrashedDetailType) detail) {
case VIR_DOMAIN_EVENT_CRASHED_PANICKED:
return "Panicked";
case VIR_DOMAIN_EVENT_CRASHED_CRASHLOADED:
return "Crashloaded";
case VIR_DOMAIN_EVENT_CRASHED_LAST:
break;
}
break;
case VIR_DOMAIN_EVENT_LAST:
break;
}
return "unknown";
}
static const char *
networkEventToString(int event)
{
switch ((virNetworkEventLifecycleType) event) {
case VIR_NETWORK_EVENT_DEFINED:
return "Defined";
case VIR_NETWORK_EVENT_UNDEFINED:
return "Undefined";
case VIR_NETWORK_EVENT_STARTED:
return "Started";
case VIR_NETWORK_EVENT_STOPPED:
return "Stopped";
case VIR_NETWORK_EVENT_LAST:
break;
}
return "unknown";
}
static const char *
guestAgentLifecycleEventStateToString(int event)
{
switch ((virConnectDomainEventAgentLifecycleState) event) {
case VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_STATE_DISCONNECTED:
return "Disconnected";
case VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_STATE_CONNECTED:
return "Connected";
case VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_STATE_LAST:
break;
}
return "unknown";
}
static const char *
guestAgentLifecycleEventReasonToString(int event)
{
switch ((virConnectDomainEventAgentLifecycleReason) event) {
case VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_UNKNOWN:
return "Unknown";
case VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_DOMAIN_STARTED:
return "Domain started";
case VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_CHANNEL:
return "Channel event";
case VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_LAST:
break;
}
return "unknown";
}
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";
case VIR_STORAGE_POOL_EVENT_CREATED:
return "Created";
case VIR_STORAGE_POOL_EVENT_DELETED:
return "Deleted";
case VIR_STORAGE_POOL_EVENT_LAST:
break;
}
return "unknown";
}
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";
}
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";
}
static int
myDomainEventCallback1(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
int event,
int detail,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) %s %s\n", __func__, virDomainGetName(dom),
virDomainGetID(dom), eventToString(event),
eventDetailToString(event, detail));
return 0;
}
static int
myDomainEventCallback2(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
int event,
int detail,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) %s %s\n", __func__, virDomainGetName(dom),
virDomainGetID(dom), eventToString(event),
eventDetailToString(event, detail));
return 0;
}
static int
myDomainEventRebootCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) rebooted\n", __func__, virDomainGetName(dom),
virDomainGetID(dom));
return 0;
}
static int
myDomainEventRTCChangeCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
long long offset,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) rtc change %" PRIdMAX "\n",
__func__, virDomainGetName(dom), virDomainGetID(dom),
(intmax_t)offset);
return 0;
}
static int
myDomainEventBalloonChangeCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
unsigned long long actual,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) balloon change %" PRIuMAX "KB\n",
__func__, virDomainGetName(dom), virDomainGetID(dom), (uintmax_t)actual);
return 0;
}
static int
myDomainEventWatchdogCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
int action,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) watchdog action=%d\n", __func__,
virDomainGetName(dom), virDomainGetID(dom), action);
return 0;
}
static int
myDomainEventIOErrorCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) io error path=%s alias=%s action=%d\n",
__func__, virDomainGetName(dom), virDomainGetID(dom),
srcPath, devAlias, action);
return 0;
}
static int
myDomainEventIOErrorReasonCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
const char *srcPath,
const char *devAlias,
int action,
const char *reason,
void *opaque G_GNUC_UNUSED)
{
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;
}
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";
case VIR_DOMAIN_EVENT_GRAPHICS_LAST:
break;
}
return "unknown";
}
static int
myDomainEventGraphicsCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
int phase,
virDomainEventGraphicsAddressPtr local,
virDomainEventGraphicsAddressPtr remote,
const char *authScheme,
virDomainEventGraphicsSubjectPtr subject,
void *opaque G_GNUC_UNUSED)
{
size_t i;
printf("%s EVENT: Domain %s(%d) graphics ", __func__, virDomainGetName(dom),
virDomainGetID(dom));
printf("%s ", graphicsPhaseToStr(phase));
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);
for (i = 0; i < subject->nidentity; i++) {
printf(" identity: %s=%s",
subject->identities[i].type,
subject->identities[i].name);
}
printf("\n");
return 0;
}
static int
myDomainEventControlErrorCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) control error\n", __func__,
virDomainGetName(dom), virDomainGetID(dom));
return 0;
}
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";
case VIR_DOMAIN_EVENT_DISK_CHANGE_LAST:
break;
}
return "unknown";
}
static int
myDomainEventDiskChangeCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
const char *oldSrcPath,
const char *newSrcPath,
const char *devAlias,
int reason,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) disk change oldSrcPath: %s newSrcPath: %s "
"devAlias: %s reason: %s\n",
__func__, virDomainGetName(dom), virDomainGetID(dom),
oldSrcPath, newSrcPath, devAlias, diskChangeReasonToStr(reason));
return 0;
}
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";
case VIR_DOMAIN_EVENT_TRAY_CHANGE_LAST:
break;
}
return "unknown";
};
static int
myDomainEventTrayChangeCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
const char *devAlias,
int reason,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) removable disk's tray change devAlias: %s "
"reason: %s\n",
__func__, virDomainGetName(dom), virDomainGetID(dom),
devAlias, trayChangeReasonToStr(reason));
return 0;
}
static int
myDomainEventPMWakeupCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
int reason G_GNUC_UNUSED,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) system pmwakeup\n",
__func__, virDomainGetName(dom), virDomainGetID(dom));
return 0;
}
static int
myDomainEventPMSuspendCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
int reason G_GNUC_UNUSED,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) system pmsuspend\n",
__func__, virDomainGetName(dom), virDomainGetID(dom));
return 0;
}
static int
myDomainEventPMSuspendDiskCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
int reason G_GNUC_UNUSED,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) system pmsuspend-disk\n",
__func__, virDomainGetName(dom), virDomainGetID(dom));
return 0;
}
static int
myDomainEventDeviceRemovedCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
const char *devAlias,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) device removed: %s\n",
__func__, virDomainGetName(dom), virDomainGetID(dom), devAlias);
return 0;
}
static int
myNetworkEventCallback(virConnectPtr conn G_GNUC_UNUSED,
virNetworkPtr dom,
int event,
int detail,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Network %s %s %d\n", __func__, virNetworkGetName(dom),
networkEventToString(event), detail);
return 0;
}
static int
myStoragePoolEventCallback(virConnectPtr conn G_GNUC_UNUSED,
virStoragePoolPtr pool,
int event,
int detail,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Storage pool %s %s %d\n", __func__,
virStoragePoolGetName(pool),
storagePoolEventToString(event),
detail);
return 0;
}
static int
myStoragePoolEventRefreshCallback(virConnectPtr conn G_GNUC_UNUSED,
virStoragePoolPtr pool,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Storage pool %s refresh\n", __func__,
virStoragePoolGetName(pool));
return 0;
}
static int
myNodeDeviceEventCallback(virConnectPtr conn G_GNUC_UNUSED,
virNodeDevicePtr dev,
int event,
int detail,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Node device %s %s %d\n", __func__,
virNodeDeviceGetName(dev),
nodeDeviceEventToString(event),
detail);
return 0;
}
static int
myNodeDeviceEventUpdateCallback(virConnectPtr conn G_GNUC_UNUSED,
virNodeDevicePtr dev,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Node device %s update\n", __func__,
virNodeDeviceGetName(dev));
return 0;
}
static int
mySecretEventCallback(virConnectPtr conn G_GNUC_UNUSED,
virSecretPtr secret,
int event,
int detail,
void *opaque G_GNUC_UNUSED)
{
char uuid[VIR_UUID_STRING_BUFLEN];
virSecretGetUUIDString(secret, uuid);
printf("%s EVENT: Secret %s %s %d\n", __func__,
uuid,
secretEventToString(event),
detail);
return 0;
}
static int
mySecretEventValueChanged(virConnectPtr conn G_GNUC_UNUSED,
virSecretPtr secret,
void *opaque G_GNUC_UNUSED)
{
char uuid[VIR_UUID_STRING_BUFLEN];
virSecretGetUUIDString(secret, uuid);
printf("%s EVENT: Secret %s\n", __func__, uuid);
return 0;
}
static void
eventTypedParamsPrint(virTypedParameterPtr params,
int nparams)
{
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:
printf("\t%s: %" PRId64 "\n", params[i].field,
(int64_t) params[i].value.l);
break;
case VIR_TYPED_PARAM_ULLONG:
printf("\t%s: %" PRIu64 "\n", params[i].field,
(uint64_t) params[i].value.ul);
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);
}
}
}
static int
myDomainEventTunableCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
virTypedParameterPtr params,
int nparams,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) tunable updated:\n",
__func__, virDomainGetName(dom), virDomainGetID(dom));
eventTypedParamsPrint(params, nparams);
return 0;
}
static int
myDomainEventAgentLifecycleCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
int state,
int reason,
void *opaque G_GNUC_UNUSED)
{
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;
}
static int
myDomainEventDeviceAddedCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
const char *devAlias,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) device added: %s\n",
__func__, virDomainGetName(dom), virDomainGetID(dom), devAlias);
return 0;
}
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";
case VIR_DOMAIN_BLOCK_JOB_TYPE_BACKUP:
return "backup";
}
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
myDomainEventBlockJobCallback(virConnectPtr conn G_GNUC_UNUSED,
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', "
"type '%s' status '%s'",
__func__, virDomainGetName(dom), virDomainGetID(dom), eventName,
disk, blockJobTypeToStr(type), blockJobStatusToStr(status));
return 0;
}
static int
myDomainEventBlockThresholdCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
const char *dev,
const char *path,
unsigned long long threshold,
unsigned long long excess,
void *opaque G_GNUC_UNUSED)
{
/* Casts to uint64_t to work around mingw not knowing %lld */
printf("%s EVENT: Domain %s(%d) block threshold callback dev '%s'(%s), "
"threshold: '%" PRIu64 "', excess: '%" PRIu64 "'",
__func__, virDomainGetName(dom), virDomainGetID(dom),
dev, NULLSTR(path), (uint64_t)threshold, (uint64_t)excess);
return 0;
}
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', "
"aciont '%d', flags '%d'", __func__, virDomainGetName(dom),
virDomainGetID(dom), recipient, action, flags);
return 0;
}
static int
myDomainEventMigrationIterationCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
int iteration,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) migration iteration '%d'\n",
__func__, virDomainGetName(dom), virDomainGetID(dom), iteration);
return 0;
}
static int
myDomainEventJobCompletedCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
virTypedParameterPtr params,
int nparams,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) job completed:\n",
__func__, virDomainGetName(dom), virDomainGetID(dom));
eventTypedParamsPrint(params, nparams);
return 0;
}
static int
myDomainEventDeviceRemovalFailedCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
const char *devAlias,
void *opaque G_GNUC_UNUSED)
{
printf("%s EVENT: Domain %s(%d) device removal failed: %s\n",
__func__, virDomainGetName(dom), virDomainGetID(dom), devAlias);
return 0;
}
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
myDomainEventMetadataChangeCallback(virConnectPtr conn G_GNUC_UNUSED,
virDomainPtr dom,
int type,
const char *nsuri,
void *opaque G_GNUC_UNUSED)
{
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;
}
static void
myFreeFunc(void *opaque)
{
char *str = opaque;
printf("%s: Freeing [%s]\n", __func__, str);
free(str);
}
/* main test functions */
static void
stop(int sig)
{
printf("Exiting on signal %d\n", sig);
run = 0;
}
struct domainEventData {
int event;
int id;
virConnectDomainEventGenericCallback cb;
const char *name;
};
#define DOMAIN_EVENT(event, callback) \
{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),
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON, myDomainEventIOErrorReasonCallback),
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_CONTROL_ERROR, myDomainEventControlErrorCallback),
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_BLOCK_JOB, myDomainEventBlockJobCallback),
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),
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_BLOCK_JOB_2, myDomainEventBlockJobCallback),
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),
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_MIGRATION_ITERATION, myDomainEventMigrationIterationCallback),
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_JOB_COMPLETED, myDomainEventJobCompletedCallback),
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED, myDomainEventDeviceRemovalFailedCallback),
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_METADATA_CHANGE, myDomainEventMetadataChangeCallback),
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD, myDomainEventBlockThresholdCallback),
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_MEMORY_FAILURE, myDomainEventMemoryFailureCallback),
};
struct storagePoolEventData {
int event;
int id;
virConnectStoragePoolEventGenericCallback cb;
const char *name;
};
#define STORAGE_POOL_EVENT(event, callback) \
{event, -1, VIR_STORAGE_POOL_EVENT_CALLBACK(callback), #event}
struct storagePoolEventData storagePoolEvents[] = {
STORAGE_POOL_EVENT(VIR_STORAGE_POOL_EVENT_ID_LIFECYCLE, myStoragePoolEventCallback),
STORAGE_POOL_EVENT(VIR_STORAGE_POOL_EVENT_ID_REFRESH, myStoragePoolEventRefreshCallback),
};
struct nodeDeviceEventData {
int event;
int id;
virConnectNodeDeviceEventGenericCallback cb;
const char *name;
};
#define NODE_DEVICE_EVENT(event, callback) \
{event, -1, VIR_NODE_DEVICE_EVENT_CALLBACK(callback), #event}
struct nodeDeviceEventData nodeDeviceEvents[] = {
NODE_DEVICE_EVENT(VIR_NODE_DEVICE_EVENT_ID_LIFECYCLE, myNodeDeviceEventCallback),
NODE_DEVICE_EVENT(VIR_NODE_DEVICE_EVENT_ID_UPDATE, myNodeDeviceEventUpdateCallback),
};
struct secretEventData {
int event;
int id;
virConnectSecretEventGenericCallback cb;
const char *name;
};
#define SECRET_EVENT(event, callback) \
{event, -1, VIR_SECRET_EVENT_CALLBACK(callback), #event}
struct secretEventData secretEvents[] = {
SECRET_EVENT(VIR_SECRET_EVENT_ID_LIFECYCLE, mySecretEventCallback),
SECRET_EVENT(VIR_SECRET_EVENT_ID_VALUE_CHANGED, mySecretEventValueChanged),
};
/* make sure that the events are kept in sync */
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);
int
main(int argc, char **argv)
{
int ret = EXIT_FAILURE;
virConnectPtr dconn = NULL;
int callback1ret = -1;
int callback16ret = -1;
size_t i;
if (argc > 1 && STREQ(argv[1], "--help")) {
printf("%s uri\n", argv[0]);
goto cleanup;
}
if (virInitialize() < 0) {
fprintf(stderr, "Failed to initialize libvirt");
goto cleanup;
}
if (virEventRegisterDefaultImpl() < 0) {
fprintf(stderr, "Failed to register event implementation: %s\n",
virGetLastErrorMessage());
goto cleanup;
}
dconn = virConnectOpenAuth(argc > 1 ? argv[1] : NULL,
virConnectAuthPtrDefault,
VIR_CONNECT_RO);
if (!dconn) {
printf("error opening\n");
goto cleanup;
}
if (virConnectRegisterCloseCallback(dconn,
connectClose, NULL, NULL) < 0) {
fprintf(stderr, "Unable to register close callback\n");
goto cleanup;
}
/* The ideal program would use sigaction to set this handler, but
* this way is portable to mingw. */
signal(SIGTERM, stop);
signal(SIGINT, stop);
printf("Registering event callbacks\n");
callback1ret = virConnectDomainEventRegister(dconn, myDomainEventCallback1,
strdup("callback 1"), myFreeFunc);
/* register common domain callbacks */
for (i = 0; i < G_N_ELEMENTS(domainEvents); i++) {
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;
}
}
callback16ret = virConnectNetworkEventRegisterAny(dconn,
NULL,
VIR_NETWORK_EVENT_ID_LIFECYCLE,
VIR_NETWORK_EVENT_CALLBACK(myNetworkEventCallback),
strdup("net callback"), myFreeFunc);
/* register common storage pool callbacks */
for (i = 0; i < G_N_ELEMENTS(storagePoolEvents); i++) {
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;
}
}
/* register common node device callbacks */
for (i = 0; i < G_N_ELEMENTS(nodeDeviceEvents); i++) {
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;
}
}
/* register common secret callbacks */
for (i = 0; i < G_N_ELEMENTS(secretEvents); i++) {
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;
}
}
if ((callback1ret == -1) ||
(callback16ret == -1))
goto cleanup;
if (virConnectSetKeepAlive(dconn, 5, 3) < 0) {
fprintf(stderr, "Failed to start keepalive protocol: %s\n",
virGetLastErrorMessage());
run = 0;
}
while (run) {
if (virEventRunDefaultImpl() < 0) {
fprintf(stderr, "Failed to run event loop: %s\n",
virGetLastErrorMessage());
}
}
printf("Deregistering event callbacks\n");
virConnectDomainEventDeregister(dconn, myDomainEventCallback1);
virConnectNetworkEventDeregisterAny(dconn, callback16ret);
printf("Deregistering domain event callbacks\n");
for (i = 0; i < G_N_ELEMENTS(domainEvents); i++) {
if (domainEvents[i].id > 0)
virConnectDomainEventDeregisterAny(dconn, domainEvents[i].id);
}
printf("Deregistering storage pool event callbacks\n");
for (i = 0; i < G_N_ELEMENTS(storagePoolEvents); i++) {
if (storagePoolEvents[i].id > 0)
virConnectStoragePoolEventDeregisterAny(dconn, storagePoolEvents[i].id);
}
printf("Deregistering node device event callbacks\n");
for (i = 0; i < G_N_ELEMENTS(nodeDeviceEvents); i++) {
if (nodeDeviceEvents[i].id > 0)
virConnectNodeDeviceEventDeregisterAny(dconn, nodeDeviceEvents[i].id);
}
printf("Deregistering secret event callbacks\n");
for (i = 0; i < G_N_ELEMENTS(secretEvents); i++) {
if (secretEvents[i].id > 0)
virConnectSecretEventDeregisterAny(dconn, secretEvents[i].id);
}
virConnectUnregisterCloseCallback(dconn, connectClose);
ret = EXIT_SUCCESS;
cleanup:
if (dconn) {
printf("Closing connection: ");
if (virConnectClose(dconn) < 0)
printf("failed\n");
printf("done\n");
}
return ret;
}