From de87691ff0c793e2e96e45f1d5c3f38738354768 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 14 Feb 2014 17:19:32 -0700 Subject: [PATCH] virsh: add net-event command Add 'virsh net-event --list' and 'virsh net-event [net] --event=name [--loop] [--timeout]'. Very similar to 'virsh event'. * tools/virsh.pod (net-event): Document new command. * tools/virsh-network.c (vshNetworkEventToString, vshNetEventData) (vshEventLifecyclePrint, cmdNetworkEvent): New struct and functions. Signed-off-by: Eric Blake --- tools/virsh-network.c | 171 +++++++++++++++++++++++++++++++++++++++++- tools/virsh.pod | 15 ++++ 2 files changed, 185 insertions(+), 1 deletion(-) diff --git a/tools/virsh-network.c b/tools/virsh-network.c index 44a676be5d..43773915e1 100644 --- a/tools/virsh-network.c +++ b/tools/virsh-network.c @@ -1,7 +1,7 @@ /* * virsh-network.c: Commands to manage network * - * Copyright (C) 2005, 2007-2013 Red Hat, Inc. + * Copyright (C) 2005, 2007-2014 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -1130,6 +1130,169 @@ cmdNetworkEdit(vshControl *ctl, const vshCmd *cmd) return ret; } + +/* + * "net-event" command + */ +static const char * +vshNetworkEventToString(int event) +{ + const char *ret = _("unknown"); + switch ((virNetworkEventLifecycleType) event) { + case VIR_NETWORK_EVENT_DEFINED: + ret = _("Defined"); + break; + case VIR_NETWORK_EVENT_UNDEFINED: + ret = _("Undefined"); + break; + case VIR_NETWORK_EVENT_STARTED: + ret = _("Started"); + break; + case VIR_NETWORK_EVENT_STOPPED: + ret = _("Stopped"); + break; + case VIR_NETWORK_EVENT_LAST: + break; + } + return ret; +} + +struct vshNetEventData { + vshControl *ctl; + bool loop; + int count; +}; +typedef struct vshNetEventData vshNetEventData; + +VIR_ENUM_DECL(vshNetworkEvent) +VIR_ENUM_IMPL(vshNetworkEvent, + VIR_NETWORK_EVENT_ID_LAST, + "lifecycle") + +static void +vshEventLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED, + virNetworkPtr net, + int event, + int detail ATTRIBUTE_UNUSED, + void *opaque) +{ + vshNetEventData *data = opaque; + + if (!data->loop && data->count) + return; + vshPrint(data->ctl, _("event 'lifecycle' for network %s: %s\n"), + virNetworkGetName(net), vshNetworkEventToString(event)); + data->count++; + if (!data->loop) + vshEventDone(data->ctl); +} + +static const vshCmdInfo info_network_event[] = { + {.name = "net-event", + .data = N_("Network Events") + }, + {.name = "desc", + .data = N_("List event types, or wait for network events to occur") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_network_event[] = { + {.name = "network", + .type = VSH_OT_DATA, + .help = N_("filter by network name or uuid") + }, + {.name = "event", + .type = VSH_OT_DATA, + .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 = NULL} +}; + +static bool +cmdNetworkEvent(vshControl *ctl, const vshCmd *cmd) +{ + virNetworkPtr net = NULL; + bool ret = false; + int eventId = -1; + int timeout = 0; + vshNetEventData data; + const char *eventName = NULL; + int event; + + if (vshCommandOptBool(cmd, "list")) { + size_t i; + + for (i = 0; i < VIR_NETWORK_EVENT_ID_LAST; i++) + vshPrint(ctl, "%s\n", vshNetworkEventTypeToString(i)); + return true; + } + + if (vshCommandOptString(cmd, "event", &eventName) < 0) + return false; + if (!eventName) { + vshError(ctl, "%s", _("either --list or event type is required")); + return false; + } + if ((event = vshNetworkEventTypeFromString(eventName) < 0)) { + vshError(ctl, _("unknown event type %s"), eventName); + return false; + } + + data.ctl = ctl; + data.loop = vshCommandOptBool(cmd, "loop"); + data.count = 0; + if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0) + return false; + + if (vshCommandOptBool(cmd, "network")) + net = vshCommandOptNetwork(ctl, cmd, NULL); + if (vshEventStart(ctl, timeout) < 0) + goto cleanup; + + if ((eventId = virConnectNetworkEventRegisterAny(ctl->conn, net, event, + VIR_NETWORK_EVENT_CALLBACK(vshEventLifecyclePrint), + &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 && + virConnectNetworkEventDeregisterAny(ctl->conn, eventId) < 0) + ret = false; + if (net) + virNetworkFree(net); + return ret; +} + + const vshCmdDef networkCmds[] = { {.name = "net-autostart", .handler = cmdNetworkAutostart, @@ -1167,6 +1330,12 @@ const vshCmdDef networkCmds[] = { .info = info_network_edit, .flags = 0 }, + {.name = "net-event", + .handler = cmdNetworkEvent, + .opts = opts_network_event, + .info = info_network_event, + .flags = 0 + }, {.name = "net-info", .handler = cmdNetworkInfo, .opts = opts_network_info, diff --git a/tools/virsh.pod b/tools/virsh.pod index bb5340f02d..568e06eecf 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -2327,6 +2327,21 @@ except that it does some error checking. The editor used can be supplied by the C<$VISUAL> or C<$EDITOR> environment variables, and defaults to C. +=item B {[I] I [I<--loop>] [I<--timeout> +I] | I<--list>} + +Wait for a class of network events to occur, and print appropriate details +of events as they happen. The events can optionally be filtered by +I. Using I<--list> as the only argument will provide a list +of possible I values known by this client, although the connection +might not allow registering for all these events. + +By default, this command is one-shot, and returns success once an event +occurs; you can send SIGINT (usually via C) to quit immediately. +If I<--timeout> is specified, the command gives up waiting for events +after I have elapsed. With I<--loop>, the command prints all +events until a timeout or interrupt key. + =item B I Returns basic information about the I object.