mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
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:
parent
4a27ac1de1
commit
895913dd59
@ -36,6 +36,7 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "xml.h"
|
#include "xml.h"
|
||||||
|
#include "conf/network_conf.h"
|
||||||
|
|
||||||
virNetworkPtr
|
virNetworkPtr
|
||||||
vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd,
|
vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd,
|
||||||
@ -342,6 +343,225 @@ cmdNetworkInfo(vshControl *ctl, const vshCmd *cmd)
|
|||||||
return true;
|
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
|
* "net-list" command
|
||||||
*/
|
*/
|
||||||
@ -354,114 +574,70 @@ static const vshCmdInfo info_network_list[] = {
|
|||||||
static const vshCmdOptDef opts_network_list[] = {
|
static const vshCmdOptDef opts_network_list[] = {
|
||||||
{"inactive", VSH_OT_BOOL, 0, N_("list inactive networks")},
|
{"inactive", VSH_OT_BOOL, 0, N_("list inactive networks")},
|
||||||
{"all", VSH_OT_BOOL, 0, N_("list inactive & active 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}
|
{NULL, 0, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
cmdNetworkList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
|
cmdNetworkList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
|
vshNetworkListPtr list = NULL;
|
||||||
|
int i;
|
||||||
bool inactive = vshCommandOptBool(cmd, "inactive");
|
bool inactive = vshCommandOptBool(cmd, "inactive");
|
||||||
bool all = vshCommandOptBool(cmd, "all");
|
bool all = vshCommandOptBool(cmd, "all");
|
||||||
bool active = !inactive || all;
|
bool persistent = vshCommandOptBool(cmd, "persistent");
|
||||||
int maxactive = 0, maxinactive = 0, i;
|
bool transient = vshCommandOptBool(cmd, "transient");
|
||||||
char **activeNames = NULL, **inactiveNames = NULL;
|
bool autostart = vshCommandOptBool(cmd, "autostart");
|
||||||
inactive |= all;
|
bool no_autostart = vshCommandOptBool(cmd, "no-autostart");
|
||||||
|
unsigned int flags = VIR_CONNECT_LIST_NETWORKS_ACTIVE;
|
||||||
|
|
||||||
if (active) {
|
if (inactive)
|
||||||
maxactive = virConnectNumOfNetworks(ctl->conn);
|
flags = VIR_CONNECT_LIST_NETWORKS_INACTIVE;
|
||||||
if (maxactive < 0) {
|
|
||||||
vshError(ctl, "%s", _("Failed to list active networks"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (maxactive) {
|
|
||||||
activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);
|
|
||||||
|
|
||||||
if ((maxactive = virConnectListNetworks(ctl->conn, activeNames,
|
if (all)
|
||||||
maxactive)) < 0) {
|
flags = VIR_CONNECT_LIST_NETWORKS_ACTIVE |
|
||||||
vshError(ctl, "%s", _("Failed to list active networks"));
|
VIR_CONNECT_LIST_NETWORKS_INACTIVE;
|
||||||
VIR_FREE(activeNames);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
qsort(&activeNames[0], maxactive, sizeof(char *), vshNameSorter);
|
if (persistent)
|
||||||
}
|
flags |= VIR_CONNECT_LIST_NETWORKS_PERSISTENT;
|
||||||
}
|
|
||||||
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 ((maxinactive =
|
if (transient)
|
||||||
virConnectListDefinedNetworks(ctl->conn, inactiveNames,
|
flags |= VIR_CONNECT_LIST_NETWORKS_TRANSIENT;
|
||||||
maxinactive)) < 0) {
|
|
||||||
vshError(ctl, "%s", _("Failed to list inactive networks"));
|
|
||||||
VIR_FREE(activeNames);
|
|
||||||
VIR_FREE(inactiveNames);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
qsort(&inactiveNames[0], maxinactive, sizeof(char*), vshNameSorter);
|
if (autostart)
|
||||||
}
|
flags |= VIR_CONNECT_LIST_NETWORKS_AUTOSTART;
|
||||||
}
|
|
||||||
vshPrintExtra(ctl, "%-20s %-10s %s\n", _("Name"), _("State"),
|
|
||||||
_("Autostart"));
|
|
||||||
vshPrintExtra(ctl, "-----------------------------------------\n");
|
|
||||||
|
|
||||||
for (i = 0; i < maxactive; i++) {
|
if (no_autostart)
|
||||||
virNetworkPtr network =
|
flags |= VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART;
|
||||||
virNetworkLookupByName(ctl->conn, activeNames[i]);
|
|
||||||
|
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;
|
const char *autostartStr;
|
||||||
int autostart = 0;
|
int is_autostart = 0;
|
||||||
|
|
||||||
/* this kind of work with networks is not atomic operation */
|
if (virNetworkGetAutostart(network, &is_autostart) < 0)
|
||||||
if (!network) {
|
|
||||||
VIR_FREE(activeNames[i]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (virNetworkGetAutostart(network, &autostart) < 0)
|
|
||||||
autostartStr = _("no autostart");
|
autostartStr = _("no autostart");
|
||||||
else
|
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),
|
virNetworkGetName(network),
|
||||||
_("active"),
|
virNetworkIsActive(network) ? _("active") : _("inactive"),
|
||||||
autostartStr);
|
autostartStr,
|
||||||
virNetworkFree(network);
|
virNetworkIsPersistent(network) ? _("yes") : _("no"));
|
||||||
VIR_FREE(activeNames[i]);
|
|
||||||
}
|
}
|
||||||
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 */
|
vshNetworkListFree(list);
|
||||||
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);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1934,10 +1934,20 @@ variables, and defaults to C<vi>.
|
|||||||
Returns basic information about the I<network> object.
|
Returns basic information about the I<network> object.
|
||||||
|
|
||||||
=item B<net-list> [I<--inactive> | I<--all>]
|
=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
|
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
|
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>
|
=item B<net-name> I<network-UUID>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user