[libvirt] [PATCH] virsh: support remaining domain events

Eric Blake eblake at redhat.com
Mon Feb 24 21:49:44 UTC 2014


Earlier, I added 'virsh event' for lifecycle events, to get the
concept approved; this patch finishes the support for all other
events, although the user still has to register for one event
type at a time.  A future patch may add an --all parameter to
make it possible to register for all events through a single
call.

* tools/virsh-domain.c (vshDomainEventWatchdogToString)
(vshDomainEventIOErrorToString, vshGraphicsPhaseToString)
(vshGraphicsAddressToString, vshDomainBlockJobStatusToString)
(vshDomainEventDiskChangeToString)
(vshDomainEventTrayChangeToString, vshEventGenericPrint)
(vshEventRTCChangePrint, vshEventWatchdogPrint)
(vshEventIOErrorPrint, vshEventGraphicsPrint)
(vshEventIOErrorReasonPrint, vshEventBlockJobPrint)
(vshEventDiskChangePrint, vshEventTrayChangePrint)
(vshEventPMChangePrint, vshEventBalloonChangePrint)
(vshEventDeviceRemovedPrint): New helper routines.
(cmdEvent): Support full array of event callbacks.

Signed-off-by: Eric Blake <eblake at redhat.com>
---
 tools/virsh-domain.c | 392 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 381 insertions(+), 11 deletions(-)

diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 8e42300..3cffc9c 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -10434,18 +10434,135 @@ vshDomainEventDetailToString(int event, int detail)
     return str ? _(str) : _("unknown");
 }

+VIR_ENUM_DECL(vshDomainEventWatchdog)
+VIR_ENUM_IMPL(vshDomainEventWatchdog,
+              VIR_DOMAIN_EVENT_WATCHDOG_LAST,
+              N_("none"),
+              N_("pause"),
+              N_("reset"),
+              N_("poweroff"),
+              N_("shutdown"),
+              N_("debug"))
+
+static const char *
+vshDomainEventWatchdogToString(int action)
+{
+    const char *str = vshDomainEventWatchdogTypeToString(action);
+    return str ? _(str) : _("unknown");
+}
+
+VIR_ENUM_DECL(vshDomainEventIOError)
+VIR_ENUM_IMPL(vshDomainEventIOError,
+              VIR_DOMAIN_EVENT_IO_ERROR_LAST,
+              N_("none"),
+              N_("pause"),
+              N_("report"))
+
+static const char *
+vshDomainEventIOErrorToString(int action)
+{
+    const char *str = vshDomainEventIOErrorTypeToString(action);
+    return str ? _(str) : _("unknown");
+}
+
+VIR_ENUM_DECL(vshGraphicsPhase)
+VIR_ENUM_IMPL(vshGraphicsPhase,
+              VIR_DOMAIN_EVENT_GRAPHICS_LAST,
+              N_("connect"),
+              N_("initialize"),
+              N_("disconnect"))
+
+static const char *
+vshGraphicsPhaseToString(int phase)
+{
+    const char *str = vshGraphicsPhaseTypeToString(phase);
+    return str ? _(str) : _("unknown");
+}
+
+VIR_ENUM_DECL(vshGraphicsAddress)
+VIR_ENUM_IMPL(vshGraphicsAddress,
+              VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_LAST,
+              N_("IPv4"),
+              N_("IPv6"),
+              N_("unix"))
+
+static const char *
+vshGraphicsAddressToString(int family)
+{
+    const char *str = vshGraphicsAddressTypeToString(family);
+    return str ? _(str) : _("unknown");
+}
+
+VIR_ENUM_DECL(vshDomainBlockJobStatus)
+VIR_ENUM_IMPL(vshDomainBlockJobStatus,
+              VIR_DOMAIN_BLOCK_JOB_LAST,
+              N_("completed"),
+              N_("failed"),
+              N_("canceled"),
+              N_("ready"))
+
+static const char *
+vshDomainBlockJobStatusToString(int status)
+{
+    const char *str = vshDomainBlockJobStatusTypeToString(status);
+    return str ? _(str) : _("unknown");
+}
+
+VIR_ENUM_DECL(vshDomainEventDiskChange)
+VIR_ENUM_IMPL(vshDomainEventDiskChange,
+              VIR_DOMAIN_EVENT_DISK_CHANGE_LAST,
+              N_("changed"),
+              N_("dropped"))
+
+static const char *
+vshDomainEventDiskChangeToString(int reason)
+{
+    const char *str = vshDomainEventDiskChangeTypeToString(reason);
+    return str ? _(str) : _("unknown");
+}
+
+VIR_ENUM_DECL(vshDomainEventTrayChange)
+VIR_ENUM_IMPL(vshDomainEventTrayChange,
+              VIR_DOMAIN_EVENT_TRAY_CHANGE_LAST,
+              N_("opened"),
+              N_("closed"))
+
+static const char *
+vshDomainEventTrayChangeToString(int reason)
+{
+    const char *str = vshDomainEventTrayChangeTypeToString(reason);
+    return str ? _(str) : _("unknown");
+}
+
+struct vshEventCallback {
+    const char *name;
+    virConnectDomainEventGenericCallback cb;
+};
+typedef struct vshEventCallback vshEventCallback;
+
 struct vshDomEventData {
     vshControl *ctl;
     bool loop;
     int count;
+    vshEventCallback *cb;
 };
 typedef struct vshDomEventData vshDomEventData;

-/* FIXME: Support all callbacks, not just lifecycle */
-VIR_ENUM_DECL(vshDomainEventId)
-VIR_ENUM_IMPL(vshDomainEventId,
-              /* VIR_DOMAIN_EVENT_ID_LAST, */ 1,
-              "lifecycle")
+static void
+vshEventGenericPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+                     virDomainPtr dom,
+                     void *opaque)
+{
+    vshDomEventData *data = opaque;
+
+    if (!data->loop && data->count)
+        return;
+    vshPrint(data->ctl, _("event '%s' for domain %s\n"),
+             data->cb->name, virDomainGetName(dom));
+    data->count++;
+    if (!data->loop)
+        vshEventDone(data->ctl);
+}

 static void
 vshEventLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
@@ -10466,6 +10583,257 @@ vshEventLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
         vshEventDone(data->ctl);
 }

+static void
+vshEventRTCChangePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+                       virDomainPtr dom,
+                       long long utcoffset,
+                       void *opaque)
+{
+    vshDomEventData *data = opaque;
+
+    if (!data->loop && data->count)
+        return;
+    vshPrint(data->ctl, _("event 'rtc-change' for domain %s: %lld\n"),
+             virDomainGetName(dom), utcoffset);
+    data->count++;
+    if (!data->loop)
+        vshEventDone(data->ctl);
+}
+
+static void
+vshEventWatchdogPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+                      virDomainPtr dom,
+                      int action,
+                      void *opaque)
+{
+    vshDomEventData *data = opaque;
+
+    if (!data->loop && data->count)
+        return;
+    vshPrint(data->ctl, _("event 'watchdog' for domain %s: %s\n"),
+             virDomainGetName(dom), vshDomainEventWatchdogToString(action));
+    data->count++;
+    if (!data->loop)
+        vshEventDone(data->ctl);
+}
+
+static void
+vshEventIOErrorPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+                     virDomainPtr dom,
+                     const char *srcPath,
+                     const char *devAlias,
+                     int action,
+                     void *opaque)
+{
+    vshDomEventData *data = opaque;
+
+    if (!data->loop && data->count)
+        return;
+    vshPrint(data->ctl, _("event 'io-error' for domain %s: %s (%s) %s\n"),
+             virDomainGetName(dom), srcPath, devAlias,
+             vshDomainEventIOErrorToString(action));
+    data->count++;
+    if (!data->loop)
+        vshEventDone(data->ctl);
+}
+
+static void
+vshEventGraphicsPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+                      virDomainPtr dom,
+                      int phase,
+                      const virDomainEventGraphicsAddress *local,
+                      const virDomainEventGraphicsAddress *remote,
+                      const char *authScheme,
+                      const virDomainEventGraphicsSubject *subject,
+                      void *opaque)
+{
+    vshDomEventData *data = opaque;
+    size_t i;
+
+    if (!data->loop && data->count)
+        return;
+    vshPrint(data->ctl, _("event 'graphics' for domain %s: "
+                          "%s local[%s %s %s] remote[%s %s %s] %s"),
+             virDomainGetName(dom), vshGraphicsPhaseToString(phase),
+             vshGraphicsAddressToString(local->family),
+             local->node, local->service,
+             vshGraphicsAddressToString(remote->family),
+             remote->node, remote->service,
+             authScheme);
+    for (i = 0; i < subject->nidentity; i++)
+        vshPrint(data->ctl, " %s=%s", subject->identities[i].type,
+                 subject->identities[i].name);
+    vshPrint(data->ctl, "\n");
+    data->count++;
+    if (!data->loop)
+        vshEventDone(data->ctl);
+}
+
+static void
+vshEventIOErrorReasonPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+                           virDomainPtr dom,
+                           const char *srcPath,
+                           const char *devAlias,
+                           int action,
+                           const char *reason,
+                           void *opaque)
+{
+    vshDomEventData *data = opaque;
+
+    if (!data->loop && data->count)
+        return;
+    vshPrint(data->ctl, _("event 'io-error-reason' for domain %s: "
+                          "%s (%s) %s due to %s\n"),
+             virDomainGetName(dom), srcPath, devAlias,
+             vshDomainEventIOErrorToString(action), reason);
+    data->count++;
+    if (!data->loop)
+        vshEventDone(data->ctl);
+}
+
+static void
+vshEventBlockJobPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+                      virDomainPtr dom,
+                      const char *disk,
+                      int type,
+                      int status,
+                      void *opaque)
+{
+    vshDomEventData *data = opaque;
+
+    if (!data->loop && data->count)
+        return;
+    vshPrint(data->ctl, _("event 'block-job' for domain %s: %s for %s %s\n"),
+             virDomainGetName(dom), vshDomainBlockJobToString(type),
+             disk, vshDomainBlockJobStatusToString(status));
+    data->count++;
+    if (!data->loop)
+        vshEventDone(data->ctl);
+}
+
+static void
+vshEventDiskChangePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+                        virDomainPtr dom,
+                        const char *oldSrc,
+                        const char *newSrc,
+                        const char *alias,
+                        int reason,
+                        void *opaque)
+{
+    vshDomEventData *data = opaque;
+
+    if (!data->loop && data->count)
+        return;
+    vshPrint(data->ctl,
+             _("event 'disk-change' for domain %s disk %s: %s -> %s: %s\n"),
+             virDomainGetName(dom), alias, NULLSTR(oldSrc), NULLSTR(newSrc),
+             vshDomainEventDiskChangeToString(reason));
+    data->count++;
+    if (!data->loop)
+        vshEventDone(data->ctl);
+}
+
+static void
+vshEventTrayChangePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+                        virDomainPtr dom,
+                        const char *alias,
+                        int reason,
+                        void *opaque)
+{
+    vshDomEventData *data = opaque;
+
+    if (!data->loop && data->count)
+        return;
+    vshPrint(data->ctl,
+             _("event 'disk-change' for domain %s disk %s: %s\n"),
+             virDomainGetName(dom), alias,
+             vshDomainEventTrayChangeToString(reason));
+    data->count++;
+    if (!data->loop)
+        vshEventDone(data->ctl);
+}
+
+static void
+vshEventPMChangePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+                      virDomainPtr dom,
+                      int reason ATTRIBUTE_UNUSED,
+                      void *opaque)
+{
+    /* As long as libvirt.h doesn't define any reasons, we might as
+     * well treat all PM state changes as generic events.  */
+    vshEventGenericPrint(conn, dom, opaque);
+}
+
+static void
+vshEventBalloonChangePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+                           virDomainPtr dom,
+                           unsigned long long actual,
+                           void *opaque)
+{
+    vshDomEventData *data = opaque;
+
+    if (!data->loop && data->count)
+        return;
+    vshPrint(data->ctl,
+             _("event 'balloon-change' for domain %s: %lluKiB\n"),
+             virDomainGetName(dom), actual);
+    data->count++;
+    if (!data->loop)
+        vshEventDone(data->ctl);
+}
+
+static void
+vshEventDeviceRemovedPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+                           virDomainPtr dom,
+                           const char *alias,
+                           void *opaque)
+{
+    vshDomEventData *data = opaque;
+
+    if (!data->loop && data->count)
+        return;
+    vshPrint(data->ctl,
+             _("event 'device-removed' for domain %s: %s\n"),
+             virDomainGetName(dom), alias);
+    data->count++;
+    if (!data->loop)
+        vshEventDone(data->ctl);
+}
+
+static vshEventCallback vshEventCallbacks[] = {
+    { "lifecycle",
+      VIR_DOMAIN_EVENT_CALLBACK(vshEventLifecyclePrint), },
+    { "reboot", vshEventGenericPrint, },
+    { "rtc-change",
+      VIR_DOMAIN_EVENT_CALLBACK(vshEventRTCChangePrint), },
+    { "watchdog",
+      VIR_DOMAIN_EVENT_CALLBACK(vshEventWatchdogPrint), },
+    { "io-error",
+      VIR_DOMAIN_EVENT_CALLBACK(vshEventIOErrorPrint), },
+    { "graphics",
+      VIR_DOMAIN_EVENT_CALLBACK(vshEventGraphicsPrint), },
+    { "io-error-reason",
+      VIR_DOMAIN_EVENT_CALLBACK(vshEventIOErrorReasonPrint), },
+    { "control-error", vshEventGenericPrint, },
+    { "block-job",
+      VIR_DOMAIN_EVENT_CALLBACK(vshEventBlockJobPrint), },
+    { "disk-change",
+      VIR_DOMAIN_EVENT_CALLBACK(vshEventDiskChangePrint), },
+    { "tray-change",
+      VIR_DOMAIN_EVENT_CALLBACK(vshEventTrayChangePrint), },
+    { "pm-wakeup",
+      VIR_DOMAIN_EVENT_CALLBACK(vshEventPMChangePrint), },
+    { "pm-suspend",
+      VIR_DOMAIN_EVENT_CALLBACK(vshEventPMChangePrint), },
+    { "balloon-change",
+      VIR_DOMAIN_EVENT_CALLBACK(vshEventBalloonChangePrint), },
+    { "pm-suspend-disk",
+      VIR_DOMAIN_EVENT_CALLBACK(vshEventPMChangePrint), },
+    { "device-removed",
+      VIR_DOMAIN_EVENT_CALLBACK(vshEventDeviceRemovedPrint), },
+};
+verify(VIR_DOMAIN_EVENT_ID_LAST == ARRAY_CARDINALITY(vshEventCallbacks));
+
 static const vshCmdInfo info_event[] = {
     {.name = "event",
      .data = N_("Domain Events")
@@ -10512,10 +10880,8 @@ cmdEvent(vshControl *ctl, const vshCmd *cmd)
     int event;

     if (vshCommandOptBool(cmd, "list")) {
-        size_t i;
-
-        for (i = 0; i < 1 /* VIR_DOMAIN_EVENT_ID_LAST */; i++)
-            vshPrint(ctl, "%s\n", vshDomainEventIdTypeToString(i));
+        for (event = 0; event < VIR_DOMAIN_EVENT_ID_LAST; event++)
+            vshPrint(ctl, "%s\n", vshEventCallbacks[event].name);
         return true;
     }

@@ -10525,7 +10891,10 @@ cmdEvent(vshControl *ctl, const vshCmd *cmd)
         vshError(ctl, "%s", _("either --list or event type is required"));
         return false;
     }
-    if ((event = vshDomainEventIdTypeFromString(eventName) < 0)) {
+    for (event = 0; event < VIR_DOMAIN_EVENT_ID_LAST; event++)
+        if (STREQ(eventName, vshEventCallbacks[event].name))
+            break;
+    if (event == VIR_DOMAIN_EVENT_ID_LAST) {
         vshError(ctl, _("unknown event type %s"), eventName);
         return false;
     }
@@ -10533,6 +10902,7 @@ cmdEvent(vshControl *ctl, const vshCmd *cmd)
     data.ctl = ctl;
     data.loop = vshCommandOptBool(cmd, "loop");
     data.count = 0;
+    data.cb = &vshEventCallbacks[event];
     if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0)
         return false;

@@ -10542,7 +10912,7 @@ cmdEvent(vshControl *ctl, const vshCmd *cmd)
         goto cleanup;

     if ((eventId = virConnectDomainEventRegisterAny(ctl->conn, dom, event,
-                                                    VIR_DOMAIN_EVENT_CALLBACK(vshEventLifecyclePrint),
+                                                    data.cb->cb,
                                                     &data, NULL)) < 0)
         goto cleanup;
     switch (vshEventWait(ctl)) {
-- 
1.8.5.3




More information about the libvir-list mailing list