As we have some basics events for volumes, virsh can have the 'vol-event' command to check some events related to volumes. Signed-off-by: Julio Faracco <jcfaracco@xxxxxxxxx> --- tools/virsh-completer.c | 27 ++++++ tools/virsh-completer.h | 4 + tools/virsh-volume.c | 192 ++++++++++++++++++++++++++++++++++++++++ tools/virsh-volume.h | 8 ++ 4 files changed, 231 insertions(+) diff --git a/tools/virsh-completer.c b/tools/virsh-completer.c index d3effe59ea..30cc595376 100644 --- a/tools/virsh-completer.c +++ b/tools/virsh-completer.c @@ -26,6 +26,7 @@ #include "virsh-domain.h" #include "virsh.h" #include "virsh-pool.h" +#include "virsh-volume.h" #include "virsh-nodedev.h" #include "virsh-util.h" #include "virsh-secret.h" @@ -732,6 +733,32 @@ virshPoolEventNameCompleter(vshControl *ctl ATTRIBUTE_UNUSED, } +char ** +virshVolEventNameCompleter(vshControl *ctl ATTRIBUTE_UNUSED, + const vshCmd *cmd ATTRIBUTE_UNUSED, + unsigned int flags) +{ + size_t i = 0; + char **ret = NULL; + + virCheckFlags(0, NULL); + + if (VIR_ALLOC_N(ret, VIR_STORAGE_VOL_EVENT_ID_LAST) < 0) + goto error; + + for (i = 0; i < VIR_STORAGE_VOL_EVENT_ID_LAST; i++) { + if (VIR_STRDUP(ret[i], virshVolEventCallbacks[i].name) < 0) + goto error; + } + + return ret; + + error: + virStringListFree(ret); + return NULL; +} + + char ** virshNodedevEventNameCompleter(vshControl *ctl ATTRIBUTE_UNUSED, const vshCmd *cmd ATTRIBUTE_UNUSED, diff --git a/tools/virsh-completer.h b/tools/virsh-completer.h index ee7eec68c5..831be73d7e 100644 --- a/tools/virsh-completer.h +++ b/tools/virsh-completer.h @@ -90,6 +90,10 @@ char ** virshPoolEventNameCompleter(vshControl *ctl, const vshCmd *cmd, unsigned int flags); +char ** virshVolEventNameCompleter(vshControl *ctl, + const vshCmd *cmd, + unsigned int flags); + char ** virshNodedevEventNameCompleter(vshControl *ctl, const vshCmd *cmd, unsigned int flags); diff --git a/tools/virsh-volume.c b/tools/virsh-volume.c index 9d6ebd2325..63497b7d8c 100644 --- a/tools/virsh-volume.c +++ b/tools/virsh-volume.c @@ -42,6 +42,7 @@ #include "virsh-pool.h" #include "virxml.h" #include "virstring.h" +#include "virtime.h" #define VIRSH_COMMON_OPT_POOL_FULL \ VIRSH_COMMON_OPT_POOL(N_("pool name or uuid"), \ @@ -1772,6 +1773,191 @@ cmdVolPath(vshControl *ctl, const vshCmd *cmd) return true; } +/* + * "vol-event" command + */ +VIR_ENUM_DECL(virshVolEvent) +VIR_ENUM_IMPL(virshVolEvent, + VIR_STORAGE_VOL_EVENT_LAST, + N_("Created"), + N_("Deleted")) + +static const char * +virshVolEventToString(int event) +{ + const char *str = virshVolEventTypeToString(event); + return str ? _(str) : _("unknown"); +} + +struct virshVolEventData { + vshControl *ctl; + bool loop; + bool timestamp; + int count; + virshVolEventCallback *cb; +}; +typedef struct virshVolEventData virshVolEventData; + + +static void +vshEventLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED, + virStorageVolPtr vol, + int event, + int detail ATTRIBUTE_UNUSED, + void *opaque) +{ + virshVolEventData *data = opaque; + + if (!data->loop && data->count) + return; + + if (data->timestamp) { + char timestamp[VIR_TIME_STRING_BUFLEN]; + + if (virTimeStringNowRaw(timestamp) < 0) + timestamp[0] = '\0'; + + vshPrint(data->ctl, _("%s: event 'lifecycle' for storage vol %s: %s\n"), + timestamp, + virStorageVolGetName(vol), + virshVolEventToString(event)); + } else { + vshPrint(data->ctl, _("event 'lifecycle' for storage vol %s: %s\n"), + virStorageVolGetName(vol), + virshVolEventToString(event)); + } + + data->count++; + if (!data->loop) + vshEventDone(data->ctl); +} + +virshVolEventCallback virshVolEventCallbacks[] = { + { "lifecycle", + VIR_STORAGE_VOL_EVENT_CALLBACK(vshEventLifecyclePrint), } +}; +verify(VIR_STORAGE_VOL_EVENT_ID_LAST == ARRAY_CARDINALITY(virshVolEventCallbacks)); + + +static const vshCmdInfo info_vol_event[] = { + {.name = "help", + .data = N_("Storage Vol Events") + }, + {.name = "desc", + .data = N_("List event types, or wait for storage vol events to occur") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_vol_event[] = { + {.name = "vol", + .type = VSH_OT_STRING, + .help = N_("filter by storage vol name or uuid") + }, + {.name = "event", + .type = VSH_OT_STRING, + .completer = virshVolEventNameCompleter, + .help = N_("which event type to wait for") + }, + {.name = "loop", + .type = VSH_OT_BOOL, + .help = N_("loop until timeout or interrupt, rather than one-shot") + }, + {.name = "timeout", + .type = VSH_OT_INT, + .help = N_("timeout seconds") + }, + {.name = "list", + .type = VSH_OT_BOOL, + .help = N_("list valid event types") + }, + {.name = "timestamp", + .type = VSH_OT_BOOL, + .help = N_("show timestamp for each printed event") + }, + {.name = NULL} +}; + +static bool +cmdVolEvent(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol = NULL; + bool ret = false; + int eventId = -1; + int timeout = 0; + virshVolEventData data; + const char *eventName = NULL; + int event; + virshControlPtr priv = ctl->privData; + + if (vshCommandOptBool(cmd, "list")) { + size_t i; + + for (i = 0; i < VIR_STORAGE_VOL_EVENT_ID_LAST; i++) + vshPrint(ctl, "%s\n", virshVolEventCallbacks[i].name); + return true; + } + + if (vshCommandOptStringReq(ctl, cmd, "event", &eventName) < 0) + return false; + if (!eventName) { + vshError(ctl, "%s", _("either --list or --event <type> is required")); + return false; + } + + for (event = 0; event < VIR_STORAGE_VOL_EVENT_ID_LAST; event++) + if (STREQ(eventName, virshVolEventCallbacks[event].name)) + break; + if (event == VIR_STORAGE_VOL_EVENT_ID_LAST) { + vshError(ctl, _("unknown event type %s"), eventName); + return false; + } + + data.ctl = ctl; + data.loop = vshCommandOptBool(cmd, "loop"); + data.timestamp = vshCommandOptBool(cmd, "timestamp"); + data.count = 0; + data.cb = &virshVolEventCallbacks[event]; + if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0) + return false; + + if (vshCommandOptBool(cmd, "vol")) + vol = virshCommandOptVolBy(ctl, cmd, "vol", NULL, NULL, + VIRSH_BYUUID); + + if (vshEventStart(ctl, timeout) < 0) + goto cleanup; + + if ((eventId = virConnectStorageVolEventRegisterAny(priv->conn, vol, event, + data.cb->cb, + &data, NULL)) < 0) + goto cleanup; + switch (vshEventWait(ctl)) { + case VSH_EVENT_INTERRUPT: + vshPrint(ctl, "%s", _("event loop interrupted\n")); + break; + case VSH_EVENT_TIMEOUT: + vshPrint(ctl, "%s", _("event loop timed out\n")); + break; + case VSH_EVENT_DONE: + break; + default: + goto cleanup; + } + vshPrint(ctl, _("events received: %d\n"), data.count); + if (data.count) + ret = true; + + cleanup: + vshEventCleanup(ctl); + if (eventId >= 0 && + virConnectStorageVolEventDeregisterAny(priv->conn, eventId) < 0) + ret = false; + if (vol) + virStorageVolFree(vol); + return ret; +} + const vshCmdDef storageVolCmds[] = { {.name = "vol-clone", .handler = cmdVolClone, @@ -1869,5 +2055,11 @@ const vshCmdDef storageVolCmds[] = { .info = info_vol_wipe, .flags = 0 }, + {.name = "vol-event", + .handler = cmdVolEvent, + .opts = opts_vol_event, + .info = info_vol_event, + .flags = 0 + }, {.name = NULL} }; diff --git a/tools/virsh-volume.h b/tools/virsh-volume.h index 60f647776e..7869d3bfaf 100644 --- a/tools/virsh-volume.h +++ b/tools/virsh-volume.h @@ -38,6 +38,14 @@ virStorageVolPtr virshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd, virshCommandOptVolBy(_ctl, _cmd, _optname, _pooloptname, _name, \ VIRSH_BYUUID | VIRSH_BYNAME) +struct virshVolEventCallback { + const char *name; + virConnectStorageVolEventGenericCallback cb; +}; +typedef struct virshVolEventCallback virshVolEventCallback; + +extern virshVolEventCallback virshVolEventCallbacks[]; + extern const vshCmdDef storageVolCmds[]; #endif /* VIRSH_VOLUME_H */ -- 2.17.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list