list: Use virConnectListAllNetworks in virsh

tools/virsh-network.c:
  * vshNetworkSorter to sort networks by name

  * vshNetworkListFree to free the network objects list.

  * vshNetworkListCollect to collect the network objects, trying
    to use new API first, fall back to older APIs if it's not supported.

  * New options --persistent, --transient, --autostart, --no-autostart,
    for net-list, and new field 'Persistent' for its output.

tools/virsh.pod:
  * Add documents for the new options.
This commit is contained in:
Osier Yang 2012-09-04 23:55:20 +08:00
parent 4a27ac1de1
commit 895913dd59
2 changed files with 273 additions and 87 deletions

View File

@ -36,6 +36,7 @@
#include "memory.h"
#include "util.h"
#include "xml.h"
#include "conf/network_conf.h"
virNetworkPtr
vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd,
@ -342,6 +343,225 @@ cmdNetworkInfo(vshControl *ctl, const vshCmd *cmd)
return true;
}
static int
vshNetworkSorter(const void *a, const void *b)
{
virNetworkPtr *na = (virNetworkPtr *) a;
virNetworkPtr *nb = (virNetworkPtr *) b;
if (*na && !*nb)
return -1;
if (!*na)
return *nb != NULL;
return vshStrcasecmp(virNetworkGetName(*na),
virNetworkGetName(*nb));
}
struct vshNetworkList {
virNetworkPtr *nets;
size_t nnets;
};
typedef struct vshNetworkList *vshNetworkListPtr;
static void
vshNetworkListFree(vshNetworkListPtr list)
{
int i;
if (list && list->nnets) {
for (i = 0; i < list->nnets; i++) {
if (list->nets[i])
virNetworkFree(list->nets[i]);
}
VIR_FREE(list->nets);
}
VIR_FREE(list);
}
static vshNetworkListPtr
vshNetworkListCollect(vshControl *ctl,
unsigned int flags)
{
vshNetworkListPtr list = vshMalloc(ctl, sizeof(*list));
int i;
int ret;
char **names = NULL;
virNetworkPtr net;
bool success = false;
size_t deleted = 0;
int persistent;
int autostart;
int nActiveNets = 0;
int nInactiveNets = 0;
int nAllNets = 0;
/* try the list with flags support (0.10.0 and later) */
if ((ret = virConnectListAllNetworks(ctl->conn,
&list->nets,
flags)) >= 0) {
list->nnets = ret;
goto finished;
}
/* check if the command is actually supported */
if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) {
vshResetLibvirtError();
goto fallback;
}
if (last_error && last_error->code == VIR_ERR_INVALID_ARG) {
/* try the new API again but mask non-guaranteed flags */
unsigned int newflags = flags & (VIR_CONNECT_LIST_NETWORKS_ACTIVE |
VIR_CONNECT_LIST_NETWORKS_INACTIVE);
vshResetLibvirtError();
if ((ret = virConnectListAllNetworks(ctl->conn, &list->nets,
newflags)) >= 0) {
list->nnets = ret;
goto filter;
}
}
/* there was an error during the first or second call */
vshError(ctl, "%s", _("Failed to list networks"));
goto cleanup;
fallback:
/* fall back to old method (0.9.13 and older) */
vshResetLibvirtError();
/* Get the number of active networks */
if (!MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE) ||
MATCH(VIR_CONNECT_LIST_NETWORKS_ACTIVE)) {
if ((nActiveNets = virConnectNumOfNetworks(ctl->conn)) < 0) {
vshError(ctl, "%s", _("Failed to get the number of active networks"));
goto cleanup;
}
}
/* Get the number of inactive networks */
if (!MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE) ||
MATCH(VIR_CONNECT_LIST_NETWORKS_INACTIVE)) {
if ((nInactiveNets = virConnectNumOfDefinedNetworks(ctl->conn)) < 0) {
vshError(ctl, "%s", _("Failed to get the number of inactive networks"));
goto cleanup;
}
}
nAllNets = nActiveNets + nInactiveNets;
if (nAllNets == 0)
return list;
names = vshMalloc(ctl, sizeof(char *) * nAllNets);
/* Retrieve a list of active network names */
if (!MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE) ||
MATCH(VIR_CONNECT_LIST_NETWORKS_ACTIVE)) {
if (virConnectListNetworks(ctl->conn,
names, nActiveNets) < 0) {
vshError(ctl, "%s", _("Failed to list active networks"));
goto cleanup;
}
}
/* Add the inactive networks to the end of the name list */
if (!MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE) ||
MATCH(VIR_CONNECT_LIST_NETWORKS_ACTIVE)) {
if (virConnectListDefinedNetworks(ctl->conn,
&names[nActiveNets],
nInactiveNets) < 0) {
vshError(ctl, "%s", _("Failed to list inactive networks"));
goto cleanup;
}
}
list->nets = vshMalloc(ctl, sizeof(virNetworkPtr) * (nAllNets));
list->nnets = 0;
/* get active networks */
for (i = 0; i < nActiveNets; i++) {
if (!(net = virNetworkLookupByName(ctl->conn, names[i])))
continue;
list->nets[list->nnets++] = net;
}
/* get inactive networks */
for (i = 0; i < nInactiveNets; i++) {
if (!(net = virNetworkLookupByName(ctl->conn, names[i])))
continue;
list->nets[list->nnets++] = net;
}
/* truncate networks that weren't found */
deleted = nAllNets - list->nnets;
filter:
/* filter list the list if the list was acquired by fallback means */
for (i = 0; i < list->nnets; i++) {
net = list->nets[i];
/* persistence filter */
if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_PERSISTENT)) {
if ((persistent = virNetworkIsPersistent(net)) < 0) {
vshError(ctl, "%s", _("Failed to get network persistence info"));
goto cleanup;
}
if (!((MATCH(VIR_CONNECT_LIST_NETWORKS_PERSISTENT) && persistent) ||
(MATCH(VIR_CONNECT_LIST_NETWORKS_TRANSIENT) && !persistent)))
goto remove_entry;
}
/* autostart filter */
if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_AUTOSTART)) {
if (virNetworkGetAutostart(net, &autostart) < 0) {
vshError(ctl, "%s", _("Failed to get network autostart state"));
goto cleanup;
}
if (!((MATCH(VIR_CONNECT_LIST_NETWORKS_AUTOSTART) && autostart) ||
(MATCH(VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART) && !autostart)))
goto remove_entry;
}
/* the pool matched all filters, it may stay */
continue;
remove_entry:
/* the pool has to be removed as it failed one of the filters */
virNetworkFree(list->nets[i]);
list->nets[i] = NULL;
deleted++;
}
finished:
/* sort the list */
if (list->nets && list->nnets)
qsort(list->nets, list->nnets,
sizeof(*list->nets), vshNetworkSorter);
/* truncate the list if filter simulation deleted entries */
if (deleted)
VIR_SHRINK_N(list->nets, list->nnets, deleted);
success = true;
cleanup:
for (i = 0; i < nAllNets; i++)
VIR_FREE(names[i]);
VIR_FREE(names);
if (!success) {
vshNetworkListFree(list);
list = NULL;
}
return list;
}
/*
* "net-list" command
*/
@ -354,114 +574,70 @@ static const vshCmdInfo info_network_list[] = {
static const vshCmdOptDef opts_network_list[] = {
{"inactive", VSH_OT_BOOL, 0, N_("list inactive networks")},
{"all", VSH_OT_BOOL, 0, N_("list inactive & active networks")},
{"persistent", VSH_OT_BOOL, 0, N_("list persistent networks")},
{"transient", VSH_OT_BOOL, 0, N_("list transient networks")},
{"autostart", VSH_OT_BOOL, 0, N_("list networks with autostart enabled")},
{"no-autostart", VSH_OT_BOOL, 0, N_("list networks with autostart disabled")},
{NULL, 0, 0, NULL}
};
static bool
cmdNetworkList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
{
vshNetworkListPtr list = NULL;
int i;
bool inactive = vshCommandOptBool(cmd, "inactive");
bool all = vshCommandOptBool(cmd, "all");
bool active = !inactive || all;
int maxactive = 0, maxinactive = 0, i;
char **activeNames = NULL, **inactiveNames = NULL;
inactive |= all;
bool persistent = vshCommandOptBool(cmd, "persistent");
bool transient = vshCommandOptBool(cmd, "transient");
bool autostart = vshCommandOptBool(cmd, "autostart");
bool no_autostart = vshCommandOptBool(cmd, "no-autostart");
unsigned int flags = VIR_CONNECT_LIST_NETWORKS_ACTIVE;
if (active) {
maxactive = virConnectNumOfNetworks(ctl->conn);
if (maxactive < 0) {
vshError(ctl, "%s", _("Failed to list active networks"));
return false;
}
if (maxactive) {
activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);
if (inactive)
flags = VIR_CONNECT_LIST_NETWORKS_INACTIVE;
if ((maxactive = virConnectListNetworks(ctl->conn, activeNames,
maxactive)) < 0) {
vshError(ctl, "%s", _("Failed to list active networks"));
VIR_FREE(activeNames);
return false;
}
if (all)
flags = VIR_CONNECT_LIST_NETWORKS_ACTIVE |
VIR_CONNECT_LIST_NETWORKS_INACTIVE;
qsort(&activeNames[0], maxactive, sizeof(char *), vshNameSorter);
}
}
if (inactive) {
maxinactive = virConnectNumOfDefinedNetworks(ctl->conn);
if (maxinactive < 0) {
vshError(ctl, "%s", _("Failed to list inactive networks"));
VIR_FREE(activeNames);
return false;
}
if (maxinactive) {
inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive);
if (persistent)
flags |= VIR_CONNECT_LIST_NETWORKS_PERSISTENT;
if ((maxinactive =
virConnectListDefinedNetworks(ctl->conn, inactiveNames,
maxinactive)) < 0) {
vshError(ctl, "%s", _("Failed to list inactive networks"));
VIR_FREE(activeNames);
VIR_FREE(inactiveNames);
return false;
}
if (transient)
flags |= VIR_CONNECT_LIST_NETWORKS_TRANSIENT;
qsort(&inactiveNames[0], maxinactive, sizeof(char*), vshNameSorter);
}
}
vshPrintExtra(ctl, "%-20s %-10s %s\n", _("Name"), _("State"),
_("Autostart"));
vshPrintExtra(ctl, "-----------------------------------------\n");
if (autostart)
flags |= VIR_CONNECT_LIST_NETWORKS_AUTOSTART;
for (i = 0; i < maxactive; i++) {
virNetworkPtr network =
virNetworkLookupByName(ctl->conn, activeNames[i]);
if (no_autostart)
flags |= VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART;
if (!(list = vshNetworkListCollect(ctl, flags)))
return false;
vshPrintExtra(ctl, "%-20s %-10s %-13s %s\n", _("Name"), _("State"),
_("Autostart"), _("Persistent"));
vshPrintExtra(ctl, "--------------------------------------------------\n");
for (i = 0; i < list->nnets; i++) {
virNetworkPtr network = list->nets[i];
const char *autostartStr;
int autostart = 0;
int is_autostart = 0;
/* this kind of work with networks is not atomic operation */
if (!network) {
VIR_FREE(activeNames[i]);
continue;
}
if (virNetworkGetAutostart(network, &autostart) < 0)
if (virNetworkGetAutostart(network, &is_autostart) < 0)
autostartStr = _("no autostart");
else
autostartStr = autostart ? _("yes") : _("no");
autostartStr = is_autostart ? _("yes") : _("no");
vshPrint(ctl, "%-20s %-10s %-10s\n",
vshPrint(ctl, "%-20s %-10s %-13s %s\n",
virNetworkGetName(network),
_("active"),
autostartStr);
virNetworkFree(network);
VIR_FREE(activeNames[i]);
virNetworkIsActive(network) ? _("active") : _("inactive"),
autostartStr,
virNetworkIsPersistent(network) ? _("yes") : _("no"));
}
for (i = 0; i < maxinactive; i++) {
virNetworkPtr network = virNetworkLookupByName(ctl->conn, inactiveNames[i]);
const char *autostartStr;
int autostart = 0;
/* this kind of work with networks is not atomic operation */
if (!network) {
VIR_FREE(inactiveNames[i]);
continue;
}
if (virNetworkGetAutostart(network, &autostart) < 0)
autostartStr = _("no autostart");
else
autostartStr = autostart ? _("yes") : _("no");
vshPrint(ctl, "%-20s %-10s %-10s\n",
inactiveNames[i],
_("inactive"),
autostartStr);
virNetworkFree(network);
VIR_FREE(inactiveNames[i]);
}
VIR_FREE(activeNames);
VIR_FREE(inactiveNames);
vshNetworkListFree(list);
return true;
}

View File

@ -1934,10 +1934,20 @@ variables, and defaults to C<vi>.
Returns basic information about the I<network> object.
=item B<net-list> [I<--inactive> | I<--all>]
[I<--persistent>] [<--transient>]
[I<--autostart>] [<--no-autostart>]
Returns the list of active networks, if I<--all> is specified this will also
include defined but inactive networks, if I<--inactive> is specified only the
inactive ones will be listed.
inactive ones will be listed. You may also want to filter the returned networks
by I<--persistent> to list the persitent ones, I<--transient> to list the
transient ones, I<--autostart> to list the ones with autostart enabled, and
I<--no-autostart> to list the ones with autostart disabled.
NOTE: When talking to older servers, this command is forced to use a series of
API calls with an inherent race, where a pool might not be listed or might appear
more than once if it changed state between calls while the list was being
collected. Newer servers do not have this problem.
=item B<net-name> I<network-UUID>