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 <eblake@redhat.com>
This commit is contained in:
Eric Blake 2014-02-14 17:19:32 -07:00
parent 99fa96c390
commit de87691ff0
2 changed files with 185 additions and 1 deletions

View File

@ -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,

View File

@ -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<vi>.
=item B<net-event> {[I<network>] I<event> [I<--loop>] [I<--timeout>
I<seconds>] | 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<network>. Using I<--list> as the only argument will provide a list
of possible I<event> 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<Ctrl-C>) to quit immediately.
If I<--timeout> is specified, the command gives up waiting for events
after I<seconds> have elapsed. With I<--loop>, the command prints all
events until a timeout or interrupt key.
=item B<net-info> I<network>
Returns basic information about the I<network> object.