[libvirt] [PATCH 00/49 v2] Atomic APIs to list objects

v1 - v2: * Fix the stupid mistake - changing the public struct, error out if the new option '--type' for pool-list is specified, and the libvirt is old enough without listAllStoragePools supported. Except the already supported APIs for domain and domain snapshot, this series add the APIs for the left objects, including storage pool, storage vol, network, interface, node device, nwfilter, and secret. * Storage pool: - Support filtering the returned pool objects by active|inactive, persistent|transient, autostart|no-autostart, and pool types. - New options for virsh, --type to accept multiple pool types. * Storage vol: - Simply returns all the vol objects of a pool. * Network: - Support filtering the results using flags active|inactive, persistent|transient, autostart|no-autostart - New options for virsh. * Interface: - Support filtering the results using flags active|inactive. It's still O(n) underlying, as interface driver doesn't manage the objects itself, but using netcf lib instead. And netcf APIs don't support returning the struct yet. * Node Device: - Support filtering the results using capabilities type of the devices. - Extend --cap to accept multiple capability type. * Network Filter: - Simply returns all the objects. * Secret: - Simply returns all the objects. All the affected commands are tested with both new libvirt with the APIs support, or old libvirt without the support. But I still may lose some scenarios. Please review carefully. Osier Yang (49): Fix indentions list: Rename virdomainlist.[ch] for common use list: Define new API virStorageListALlStoragePools list: Add helpers for listing storage pool objects list: Implement the RPC calls for virConnectListAllStoragePools list: Implement listAllStoragePools for storage driver list: Implement listAllStoragePools for test driver list: Add helper to convert strings separated by ',' to array virsh: Fix the wrong doc for pool-list list: Change MATCH for common use in virsh list: Use virConnectListAllStoragePools in virsh virsh: Use vshPrint instead of printf python: Expose virStorageListAllStoragePools to python binding list: Define new API virStoragePoolListAllVolumes list: Implemente RPC calls for virStoragePoolListAllVolumes list: Implement virStoragePoolListAllVolumes for storage driver list: Implement virStoragePoolListAllVolumes for test driver list: Use virStoragePoolListAllVolumes in virsh list: Expose virStoragePoolListAllVolumes to Python binding list: Define new API virConnectListAllNetworks list: Implement RPC calls for virConnectListAllNetworks list: Add helpers to list network objects list: Implement listAllNetworks for network driver list: Implement listAllNetworks for test driver list: Use virConnectListAllNetworks in virsh list: Expose virConnectListAllNetworks to Python binding daemon: Fix the wrong macro name list: Define new API virConnectListAllInterfaces list: Implemente RPC calls for virConnectListAllInterfaces list: Implement listAllInterfaces list: Use virConnectListAllInterfaces in virsh list: Expose virConnectListAllInterfaces to Python binding list: Define new API virConnectListAllNodeDevices list: Implemente RPC calls for virConnectListAllNodeDevices list: Add helpers for listing node devices list: Implement listAllNodeDevices list: Expose virConnectListAllNodeDevices to Python binding virsh: Fix a bug of nodedev-list list: Use virConnectListAllNodeDevices in virsh list: Define new API virConnectListAllNWFilters list: Implement RPC calls for virConnectListAllNWFilters list: Implement listAllNWFilters list: Use virConnectListAllNWFilters in virsh list: Expose virConnectListAllNWFilters to Python binding list: Define new API virConnectListAllSecrets list: Implement RPC calls for virConnectListAllSecrets list: Implement listAllSecrets list: Use virConnectListAllSecrets in virsh list: Expose virConnectListAllSecrets to Python binding daemon/libvirtd.c | 2 +- daemon/remote.c | 382 +++++ include/libvirt/libvirt.h.in | 100 ++- python/generator.py | 11 +- python/libvirt-override-api.xml | 44 +- python/libvirt-override-virConnect.py | 72 + python/libvirt-override-virStoragePool.py | 11 + python/libvirt-override.c | 337 +++++ src/Makefile.am | 8 +- src/conf/domain_conf.c | 2 +- src/conf/virdomainlist.c | 222 --- src/conf/virdomainlist.h | 84 -- src/conf/virobjectlist.c | 535 +++++++ src/conf/virobjectlist.h | 162 +++ src/datatypes.h | 86 +- src/driver.h | 35 +- src/interface/netcf_driver.c | 135 ++ src/libvirt.c | 429 ++++++- src/libvirt_private.syms | 6 +- src/libvirt_public.syms | 11 + src/libxl/libxl_driver.c | 4 +- src/lxc/lxc_driver.c | 4 +- src/network/bridge_driver.c | 18 + src/node_device/node_device_driver.c | 16 + src/node_device/node_device_driver.h | 3 + src/node_device/node_device_hal.c | 1 + src/node_device/node_device_udev.c | 1 + src/nwfilter/nwfilter_driver.c | 57 + src/openvz/openvz_driver.c | 4 +- src/qemu/qemu_driver.c | 4 +- src/remote/remote_driver.c | 449 ++++++ src/remote/remote_protocol.x | 78 +- src/remote_protocol-structs | 85 ++ src/secret/secret_driver.c | 58 +- src/storage/storage_driver.c | 86 ++ src/test/test_driver.c | 105 ++- src/uml/uml_driver.c | 4 +- src/vbox/vbox_tmpl.c | 10 +- src/vmware/vmware_driver.c | 4 +- tests/virdrivermoduletest.c | 2 +- tools/virsh.c | 2171 ++++++++++++++++++++++------- tools/virsh.pod | 51 +- 42 files changed, 4952 insertions(+), 937 deletions(-) create mode 100644 python/libvirt-override-virStoragePool.py delete mode 100644 src/conf/virdomainlist.c delete mode 100644 src/conf/virdomainlist.h create mode 100644 src/conf/virobjectlist.c create mode 100644 src/conf/virobjectlist.h Regards, Osier

Some of the macros use tab, while the left use spaces, this patch change it to always use the spaces. And a few aligning fixes. --- src/datatypes.h | 86 +++++++++++++++++++++++++++--------------------------- 1 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/datatypes.h b/src/datatypes.h index fc284d2..01a8544 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -33,8 +33,8 @@ * magic value used to protect the API when pointers to connection structures * are passed down by the users. */ -# define VIR_CONNECT_MAGIC 0x4F23DEAD -# define VIR_IS_CONNECT(obj) ((obj) && (obj)->magic==VIR_CONNECT_MAGIC) +# define VIR_CONNECT_MAGIC 0x4F23DEAD +# define VIR_IS_CONNECT(obj) ((obj) && (obj)->magic==VIR_CONNECT_MAGIC) /** @@ -43,9 +43,9 @@ * magic value used to protect the API when pointers to domain structures * are passed down by the users. */ -# define VIR_DOMAIN_MAGIC 0xDEAD4321 -# define VIR_IS_DOMAIN(obj) ((obj) && (obj)->magic==VIR_DOMAIN_MAGIC) -# define VIR_IS_CONNECTED_DOMAIN(obj) (VIR_IS_DOMAIN(obj) && VIR_IS_CONNECT((obj)->conn)) +# define VIR_DOMAIN_MAGIC 0xDEAD4321 +# define VIR_IS_DOMAIN(obj) ((obj) && (obj)->magic==VIR_DOMAIN_MAGIC) +# define VIR_IS_CONNECTED_DOMAIN(obj) (VIR_IS_DOMAIN(obj) && VIR_IS_CONNECT((obj)->conn)) /** * VIR_NETWORK_MAGIC: @@ -53,9 +53,9 @@ * magic value used to protect the API when pointers to network structures * are passed down by the users. */ -# define VIR_NETWORK_MAGIC 0xDEAD1234 -# define VIR_IS_NETWORK(obj) ((obj) && (obj)->magic==VIR_NETWORK_MAGIC) -# define VIR_IS_CONNECTED_NETWORK(obj) (VIR_IS_NETWORK(obj) && VIR_IS_CONNECT((obj)->conn)) +# define VIR_NETWORK_MAGIC 0xDEAD1234 +# define VIR_IS_NETWORK(obj) ((obj) && (obj)->magic==VIR_NETWORK_MAGIC) +# define VIR_IS_CONNECTED_NETWORK(obj) (VIR_IS_NETWORK(obj) && VIR_IS_CONNECT((obj)->conn)) /** * VIR_INTERFACE_MAGIC: @@ -63,9 +63,9 @@ * magic value used to protect the API when pointers to interface structures * are passed down by the users. */ -# define VIR_INTERFACE_MAGIC 0xDEAD5309 -# define VIR_IS_INTERFACE(obj) ((obj) && (obj)->magic==VIR_INTERFACE_MAGIC) -# define VIR_IS_CONNECTED_INTERFACE(obj) (VIR_IS_INTERFACE(obj) && VIR_IS_CONNECT((obj)->conn)) +# define VIR_INTERFACE_MAGIC 0xDEAD5309 +# define VIR_IS_INTERFACE(obj) ((obj) && (obj)->magic==VIR_INTERFACE_MAGIC) +# define VIR_IS_CONNECTED_INTERFACE(obj) (VIR_IS_INTERFACE(obj) && VIR_IS_CONNECT((obj)->conn)) /** * VIR_STORAGE_POOL_MAGIC: @@ -73,9 +73,9 @@ * magic value used to protect the API when pointers to storage pool structures * are passed down by the users. */ -# define VIR_STORAGE_POOL_MAGIC 0xDEAD5678 -# define VIR_IS_STORAGE_POOL(obj) ((obj) && (obj)->magic==VIR_STORAGE_POOL_MAGIC) -# define VIR_IS_CONNECTED_STORAGE_POOL(obj) (VIR_IS_STORAGE_POOL(obj) && VIR_IS_CONNECT((obj)->conn)) +# define VIR_STORAGE_POOL_MAGIC 0xDEAD5678 +# define VIR_IS_STORAGE_POOL(obj) ((obj) && (obj)->magic==VIR_STORAGE_POOL_MAGIC) +# define VIR_IS_CONNECTED_STORAGE_POOL(obj) (VIR_IS_STORAGE_POOL(obj) && VIR_IS_CONNECT((obj)->conn)) /** * VIR_STORAGE_VOL_MAGIC: @@ -83,9 +83,9 @@ * magic value used to protect the API when pointers to storage vol structures * are passed down by the users. */ -# define VIR_STORAGE_VOL_MAGIC 0xDEAD8765 -# define VIR_IS_STORAGE_VOL(obj) ((obj) && (obj)->magic==VIR_STORAGE_VOL_MAGIC) -# define VIR_IS_CONNECTED_STORAGE_VOL(obj) (VIR_IS_STORAGE_VOL(obj) && VIR_IS_CONNECT((obj)->conn)) +# define VIR_STORAGE_VOL_MAGIC 0xDEAD8765 +# define VIR_IS_STORAGE_VOL(obj) ((obj) && (obj)->magic==VIR_STORAGE_VOL_MAGIC) +# define VIR_IS_CONNECTED_STORAGE_VOL(obj) (VIR_IS_STORAGE_VOL(obj) && VIR_IS_CONNECT((obj)->conn)) /** * VIR_NODE_DEVICE_MAGIC: @@ -93,9 +93,9 @@ * magic value used to protect the API when pointers to storage vol structures * are passed down by the users. */ -# define VIR_NODE_DEVICE_MAGIC 0xDEAD5679 -# define VIR_IS_NODE_DEVICE(obj) ((obj) && (obj)->magic==VIR_NODE_DEVICE_MAGIC) -# define VIR_IS_CONNECTED_NODE_DEVICE(obj) (VIR_IS_NODE_DEVICE(obj) && VIR_IS_CONNECT((obj)->conn)) +# define VIR_NODE_DEVICE_MAGIC 0xDEAD5679 +# define VIR_IS_NODE_DEVICE(obj) ((obj) && (obj)->magic==VIR_NODE_DEVICE_MAGIC) +# define VIR_IS_CONNECTED_NODE_DEVICE(obj) (VIR_IS_NODE_DEVICE(obj) && VIR_IS_CONNECT((obj)->conn)) /** * VIR_SECRET_MAGIC: @@ -103,9 +103,9 @@ * magic value used to protect the API when pointers to secret structures are * passed down by the users. */ -# define VIR_SECRET_MAGIC 0x5678DEAD -# define VIR_IS_SECRET(obj) ((obj) && (obj)->magic==VIR_SECRET_MAGIC) -# define VIR_IS_CONNECTED_SECRET(obj) (VIR_IS_SECRET(obj) && VIR_IS_CONNECT((obj)->conn)) +# define VIR_SECRET_MAGIC 0x5678DEAD +# define VIR_IS_SECRET(obj) ((obj) && (obj)->magic==VIR_SECRET_MAGIC) +# define VIR_IS_CONNECTED_SECRET(obj) (VIR_IS_SECRET(obj) && VIR_IS_CONNECT((obj)->conn)) /** @@ -114,9 +114,9 @@ * magic value used to protect the API when pointers to stream structures * are passed down by the users. */ -# define VIR_STREAM_MAGIC 0x1DEAD666 -# define VIR_IS_STREAM(obj) ((obj) && (obj)->magic==VIR_STREAM_MAGIC) -# define VIR_IS_CONNECTED_STREAM(obj) (VIR_IS_STREAM(obj) && VIR_IS_CONNECT((obj)->conn)) +# define VIR_STREAM_MAGIC 0x1DEAD666 +# define VIR_IS_STREAM(obj) ((obj) && (obj)->magic==VIR_STREAM_MAGIC) +# define VIR_IS_CONNECTED_STREAM(obj) (VIR_IS_STREAM(obj) && VIR_IS_CONNECT((obj)->conn)) /** @@ -125,9 +125,9 @@ * magic value used to protect the API when pointers to network filter * pool structures are passed down by the users. */ -# define VIR_NWFILTER_MAGIC 0xDEAD7777 -# define VIR_IS_NWFILTER(obj) ((obj) && (obj)->magic==VIR_NWFILTER_MAGIC) -# define VIR_IS_CONNECTED_NWFILTER(obj) (VIR_IS_NWFILTER(obj) && VIR_IS_CONNECT((obj)->conn)) +# define VIR_NWFILTER_MAGIC 0xDEAD7777 +# define VIR_IS_NWFILTER(obj) ((obj) && (obj)->magic==VIR_NWFILTER_MAGIC) +# define VIR_IS_CONNECTED_NWFILTER(obj) (VIR_IS_NWFILTER(obj) && VIR_IS_CONNECT((obj)->conn)) /** * VIR_SNAPSHOT_MAGIC: @@ -135,9 +135,9 @@ * magic value used to protect the API when pointers to snapshot structures * are passed down by the users. */ -# define VIR_SNAPSHOT_MAGIC 0x6666DEAD -# define VIR_IS_SNAPSHOT(obj) ((obj) && (obj)->magic==VIR_SNAPSHOT_MAGIC) -# define VIR_IS_DOMAIN_SNAPSHOT(obj) (VIR_IS_SNAPSHOT(obj) && VIR_IS_DOMAIN((obj)->domain)) +# define VIR_SNAPSHOT_MAGIC 0x6666DEAD +# define VIR_IS_SNAPSHOT(obj) ((obj) && (obj)->magic==VIR_SNAPSHOT_MAGIC) +# define VIR_IS_DOMAIN_SNAPSHOT(obj) (VIR_IS_SNAPSHOT(obj) && VIR_IS_DOMAIN((obj)->domain)) /** * _virConnect: @@ -324,12 +324,12 @@ struct _virDomainSnapshot { virConnectPtr virGetConnect(void); int virUnrefConnect(virConnectPtr conn); virDomainPtr virGetDomain(virConnectPtr conn, - const char *name, - const unsigned char *uuid); + const char *name, + const unsigned char *uuid); int virUnrefDomain(virDomainPtr domain); virNetworkPtr virGetNetwork(virConnectPtr conn, - const char *name, - const unsigned char *uuid); + const char *name, + const unsigned char *uuid); int virUnrefNetwork(virNetworkPtr network); virInterfacePtr virGetInterface(virConnectPtr conn, @@ -338,13 +338,13 @@ virInterfacePtr virGetInterface(virConnectPtr conn, int virUnrefInterface(virInterfacePtr iface); virStoragePoolPtr virGetStoragePool(virConnectPtr conn, - const char *name, - const unsigned char *uuid); + const char *name, + const unsigned char *uuid); int virUnrefStoragePool(virStoragePoolPtr pool); virStorageVolPtr virGetStorageVol(virConnectPtr conn, - const char *pool, - const char *name, - const char *key); + const char *pool, + const char *name, + const char *key); int virUnrefStorageVol(virStorageVolPtr vol); virNodeDevicePtr virGetNodeDevice(virConnectPtr conn, @@ -374,8 +374,8 @@ struct _virNWFilter { }; virNWFilterPtr virGetNWFilter(virConnectPtr conn, - const char *name, - const unsigned char *uuid); + const char *name, + const unsigned char *uuid); int virUnrefNWFilter(virNWFilterPtr nwfilter); virDomainSnapshotPtr virGetDomainSnapshot(virDomainPtr domain, -- 1.7.7.3

On 07/20/2012 08:24 AM, Osier Yang wrote:
Some of the macros use tab, while the left use spaces, this patch change it to always use the spaces. And a few aligning fixes. --- src/datatypes.h | 86 +++++++++++++++++++++++++++--------------------------- 1 files changed, 43 insertions(+), 43 deletions(-)
ACK.
diff --git a/src/datatypes.h b/src/datatypes.h index fc284d2..01a8544 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -33,8 +33,8 @@ * magic value used to protect the API when pointers to connection structures * are passed down by the users. */ -# define VIR_CONNECT_MAGIC 0x4F23DEAD -# define VIR_IS_CONNECT(obj) ((obj) && (obj)->magic==VIR_CONNECT_MAGIC) +# define VIR_CONNECT_MAGIC 0x4F23DEAD +# define VIR_IS_CONNECT(obj) ((obj) && (obj)->magic==VIR_CONNECT_MAGIC)
Conflicts with Dan's series to use virObject. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Fri, Jul 20, 2012 at 10:15:29AM -0600, Eric Blake wrote:
On 07/20/2012 08:24 AM, Osier Yang wrote:
Some of the macros use tab, while the left use spaces, this patch change it to always use the spaces. And a few aligning fixes. --- src/datatypes.h | 86 +++++++++++++++++++++++++++--------------------------- 1 files changed, 43 insertions(+), 43 deletions(-)
ACK.
diff --git a/src/datatypes.h b/src/datatypes.h index fc284d2..01a8544 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -33,8 +33,8 @@ * magic value used to protect the API when pointers to connection structures * are passed down by the users. */ -# define VIR_CONNECT_MAGIC 0x4F23DEAD -# define VIR_IS_CONNECT(obj) ((obj) && (obj)->magic==VIR_CONNECT_MAGIC) +# define VIR_CONNECT_MAGIC 0x4F23DEAD +# define VIR_IS_CONNECT(obj) ((obj) && (obj)->magic==VIR_CONNECT_MAGIC)
Conflicts with Dan's series to use virObject.
Push this patch now independantly of the rest of this huge series. I'll sort out conflicts when I rebase my virObject code next week. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 2012年07月21日 00:17, Daniel P. Berrange wrote:
On Fri, Jul 20, 2012 at 10:15:29AM -0600, Eric Blake wrote:
On 07/20/2012 08:24 AM, Osier Yang wrote:
Some of the macros use tab, while the left use spaces, this patch change it to always use the spaces. And a few aligning fixes. --- src/datatypes.h | 86 +++++++++++++++++++++++++++--------------------------- 1 files changed, 43 insertions(+), 43 deletions(-)
ACK.
diff --git a/src/datatypes.h b/src/datatypes.h index fc284d2..01a8544 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -33,8 +33,8 @@ * magic value used to protect the API when pointers to connection structures * are passed down by the users. */ -# define VIR_CONNECT_MAGIC 0x4F23DEAD -# define VIR_IS_CONNECT(obj) ((obj)&& (obj)->magic==VIR_CONNECT_MAGIC) +# define VIR_CONNECT_MAGIC 0x4F23DEAD +# define VIR_IS_CONNECT(obj) ((obj)&& (obj)->magic==VIR_CONNECT_MAGIC)
Conflicts with Dan's series to use virObject.
Push this patch now independantly of the rest of this huge series. I'll sort out conflicts when I rebase my virObject code next week.
Oh, I misunderstood you had push it, now pushed, sorry if it causes conflicts. Regards, Osier

On Thu, Aug 02, 2012 at 03:19:29PM +0800, Osier Yang wrote:
On 2012年07月21日 00:17, Daniel P. Berrange wrote:
On Fri, Jul 20, 2012 at 10:15:29AM -0600, Eric Blake wrote:
On 07/20/2012 08:24 AM, Osier Yang wrote:
Some of the macros use tab, while the left use spaces, this patch change it to always use the spaces. And a few aligning fixes. --- src/datatypes.h | 86 +++++++++++++++++++++++++++--------------------------- 1 files changed, 43 insertions(+), 43 deletions(-)
ACK.
diff --git a/src/datatypes.h b/src/datatypes.h index fc284d2..01a8544 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -33,8 +33,8 @@ * magic value used to protect the API when pointers to connection structures * are passed down by the users. */ -# define VIR_CONNECT_MAGIC 0x4F23DEAD -# define VIR_IS_CONNECT(obj) ((obj)&& (obj)->magic==VIR_CONNECT_MAGIC) +# define VIR_CONNECT_MAGIC 0x4F23DEAD +# define VIR_IS_CONNECT(obj) ((obj)&& (obj)->magic==VIR_CONNECT_MAGIC)
Conflicts with Dan's series to use virObject.
Push this patch now independantly of the rest of this huge series. I'll sort out conflicts when I rebase my virObject code next week.
Oh, I misunderstood you had push it, now pushed, sorry if it causes conflicts.
Don't worry, its not a problem. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Except objects of domains, domain snapshots, we will also add APIs to list objects like storage pools, storage vols, network, interface, etc. And it's deserved to have the small helper functions in a common file instead of in separate files. This patch renames virdomainlist.[ch] to virobjectlist.[ch], and also renames the macros to filter domain objects more specificly. src/conf/virdomainlist.c: Renamed to src/conf/virobjectlist.c src/conf/virdomainlist.h: Renamed to src/conf/virobjectlist.h src/Makefile.am: s/virdomainlist/virobjectlist/g, s/DOMAIN_LIST/OBJECT_LIST/g src/conf/domain_conf.c: Likewise src/libvirt_private.syms: Likewise tools/virsh.c: Likewise src/libxl/libxl_driver.c: s/LIST_FILTERS/LIST_DOMAINS_FILTERS/g src/lxc/lxc_driver.c: Likewise src/openvz/openvz_driver.c: Likewise src/qemu/qemu_driver.c: Likewise src/test/test_driver.c: Likewise src/uml/uml_driver.c: Likewise src/vbox/vbox_tmpl.c: Likewise src/vmware/vmware_driver.c: Likewise --- src/Makefile.am | 8 +++--- src/conf/domain_conf.c | 2 +- src/conf/{virdomainlist.c => virobjectlist.c} | 20 +++++++------ src/conf/{virdomainlist.h => virobjectlist.h} | 36 +++++++++++++----------- src/libvirt_private.syms | 2 +- src/libxl/libxl_driver.c | 4 +- src/lxc/lxc_driver.c | 4 +- src/openvz/openvz_driver.c | 4 +- src/qemu/qemu_driver.c | 4 +- src/test/test_driver.c | 4 +- src/uml/uml_driver.c | 4 +- src/vbox/vbox_tmpl.c | 10 +++--- src/vmware/vmware_driver.c | 4 +- tools/virsh.c | 16 +++++----- 14 files changed, 63 insertions(+), 59 deletions(-) rename src/conf/{virdomainlist.c => virobjectlist.c} (90%) rename src/conf/{virdomainlist.h => virobjectlist.h} (71%) diff --git a/src/Makefile.am b/src/Makefile.am index a9f8d94..4931381 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -195,9 +195,9 @@ CPU_CONF_SOURCES = \ CONSOLE_CONF_SOURCES = \ conf/virconsole.c conf/virconsole.h -# Domain listing helpers -DOMAIN_LIST_SOURCES = \ - conf/virdomainlist.c conf/virdomainlist.h +# Object listing helpers +OBJECT_LIST_SOURCES = \ + conf/virobjectlist.c conf/virobjectlist.h CONF_SOURCES = \ $(NETDEV_CONF_SOURCES) \ @@ -212,7 +212,7 @@ CONF_SOURCES = \ $(SECRET_CONF_SOURCES) \ $(CPU_CONF_SOURCES) \ $(CONSOLE_CONF_SOURCES) \ - $(DOMAIN_LIST_SOURCES) + $(OBJECT_LIST_SOURCES) # The remote RPC driver, covering domains, storage, networks, etc REMOTE_DRIVER_GENERATED = \ diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 1b5dad9..f3a7f14 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -51,7 +51,7 @@ #include "secret_conf.h" #include "netdev_vport_profile_conf.h" #include "netdev_bandwidth_conf.h" -#include "virdomainlist.h" +#include "virobjectlist.h" #define VIR_FROM_THIS VIR_FROM_DOMAIN diff --git a/src/conf/virdomainlist.c b/src/conf/virobjectlist.c similarity index 90% rename from src/conf/virdomainlist.c rename to src/conf/virobjectlist.c index 2b0b878..91eb660 100644 --- a/src/conf/virdomainlist.c +++ b/src/conf/virobjectlist.c @@ -1,5 +1,7 @@ /** - * virdomainlist.c: Helpers for listing and filtering domains. + *virobjectlist.h: Helpers for listing and filtering objects + * like domains, domain snapshots, storage pools, + * storage vols, networks, etc. * * Copyright (C) 2012 Red Hat, Inc. * @@ -22,7 +24,7 @@ #include <config.h> -#include "virdomainlist.h" +#include "virobjectlist.h" #include "internal.h" #include "virhash.h" @@ -31,7 +33,7 @@ #include "datatypes.h" #include "virterror_internal.h" -#define VIR_FROM_THIS VIR_FROM_DOMAIN +#define VIR_FROM_THIS VIR_FROM_NONE struct virDomainListData { virConnectPtr conn; @@ -58,7 +60,7 @@ virDomainListPopulate(void *payload, /* check if the domain matches the filter */ /* filter by active state */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_ACTIVE) && + if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) && !((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) && virDomainObjIsActive(vm)) || (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) && @@ -66,7 +68,7 @@ virDomainListPopulate(void *payload, goto cleanup; /* filter by persistence */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_PERSISTENT) && + if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT) && !((MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT) && vm->persistent) || (MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) && @@ -74,7 +76,7 @@ virDomainListPopulate(void *payload, goto cleanup; /* filter by domain state */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_STATE)) { + if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE)) { int st = virDomainObjGetState(vm, NULL); if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING) && st == VIR_DOMAIN_RUNNING) || @@ -90,7 +92,7 @@ virDomainListPopulate(void *payload, } /* filter by existence of managed save state */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_MANAGEDSAVE) && + if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_MANAGEDSAVE) && !((MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) && vm->hasManagedSave) || (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE) && @@ -98,13 +100,13 @@ virDomainListPopulate(void *payload, goto cleanup; /* filter by autostart option */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_AUTOSTART) && + if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_AUTOSTART) && !((MATCH(VIR_CONNECT_LIST_DOMAINS_AUTOSTART) && vm->autostart) || (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART) && !vm->autostart))) goto cleanup; /* filter by snapshot existence */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_SNAPSHOT)) { + if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) { int nsnap = virDomainSnapshotObjListNum(&vm->snapshots, NULL, 0); if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) && nsnap > 0) || (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) && nsnap <= 0))) diff --git a/src/conf/virdomainlist.h b/src/conf/virobjectlist.h similarity index 71% rename from src/conf/virdomainlist.h rename to src/conf/virobjectlist.h index e623129..510a900 100644 --- a/src/conf/virdomainlist.h +++ b/src/conf/virobjectlist.h @@ -1,5 +1,7 @@ /** - * virdomainlist.h: Helpers for listing and filtering domains. + * virobjectlist.h: Helpers for listing and filtering objects + * like domains, storage pools, storage vols + * networks, etc. * * Copyright (C) 2012 Red Hat, Inc. * @@ -19,46 +21,46 @@ * * Author: Peter Krempa <pkrempa@redhat.com> */ -#ifndef __VIR_DOMAIN_LIST_H__ -# define __VIR_DOMAIN_LIST_H__ +#ifndef __VIR_OBJECT_LIST_H__ +# define __VIR_OBJECT_LIST_H__ # include "internal.h" # include "virhash.h" # include "domain_conf.h" -# define VIR_CONNECT_LIST_FILTERS_ACTIVE \ +# define VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE \ (VIR_CONNECT_LIST_DOMAINS_ACTIVE | \ VIR_CONNECT_LIST_DOMAINS_INACTIVE) -# define VIR_CONNECT_LIST_FILTERS_PERSISTENT \ +# define VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT \ (VIR_CONNECT_LIST_DOMAINS_PERSISTENT | \ VIR_CONNECT_LIST_DOMAINS_TRANSIENT) -# define VIR_CONNECT_LIST_FILTERS_STATE \ +# define VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE \ (VIR_CONNECT_LIST_DOMAINS_RUNNING | \ VIR_CONNECT_LIST_DOMAINS_PAUSED | \ VIR_CONNECT_LIST_DOMAINS_SHUTOFF | \ VIR_CONNECT_LIST_DOMAINS_OTHER) -# define VIR_CONNECT_LIST_FILTERS_MANAGEDSAVE \ +# define VIR_CONNECT_LIST_DOMAINS_FILTERS_MANAGEDSAVE \ (VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE | \ VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE) -# define VIR_CONNECT_LIST_FILTERS_AUTOSTART \ +# define VIR_CONNECT_LIST_DOMAINS_FILTERS_AUTOSTART \ (VIR_CONNECT_LIST_DOMAINS_AUTOSTART | \ VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART) -# define VIR_CONNECT_LIST_FILTERS_SNAPSHOT \ +# define VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT \ (VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT | \ VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) -# define VIR_CONNECT_LIST_FILTERS_ALL \ - (VIR_CONNECT_LIST_FILTERS_ACTIVE | \ - VIR_CONNECT_LIST_FILTERS_PERSISTENT | \ - VIR_CONNECT_LIST_FILTERS_STATE | \ - VIR_CONNECT_LIST_FILTERS_MANAGEDSAVE | \ - VIR_CONNECT_LIST_FILTERS_AUTOSTART | \ - VIR_CONNECT_LIST_FILTERS_SNAPSHOT) +# define VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL \ + (VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE | \ + VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT | \ + VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE | \ + VIR_CONNECT_LIST_DOMAINS_FILTERS_MANAGEDSAVE | \ + VIR_CONNECT_LIST_DOMAINS_FILTERS_AUTOSTART | \ + VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT) # define VIR_DOMAIN_SNAPSHOT_FILTERS_METADATA \ (VIR_DOMAIN_SNAPSHOT_LIST_METADATA | \ @@ -81,4 +83,4 @@ int virDomainListSnapshots(virDomainSnapshotObjListPtr snapshots, virDomainSnapshotPtr **snaps, unsigned int flags); -#endif /* __VIR_DOMAIN_LIST_H__ */ +#endif /* __VIR_OBJECT_LIST_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 734c881..e66d358 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1243,7 +1243,7 @@ virConsoleOpen; virDBusGetSystemBus; -# virdomainlist.h +# virobjectlist.h virDomainList; virDomainListSnapshots; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index edf5c33..3cd55c4 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -45,7 +45,7 @@ #include "xen_xm.h" #include "virtypedparam.h" #include "viruri.h" -#include "virdomainlist.h" +#include "virobjectlist.h" #define VIR_FROM_THIS VIR_FROM_LIBXL @@ -3869,7 +3869,7 @@ libxlListAllDomains(virConnectPtr conn, libxlDriverPrivatePtr driver = conn->privateData; int ret = -1; - virCheckFlags(VIR_CONNECT_LIST_FILTERS_ALL, -1); + virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1); libxlDriverLock(driver); ret = virDomainList(conn, driver->domains.objs, domains, flags); diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 09c64b2..52208d1 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -63,7 +63,7 @@ #include "virtime.h" #include "virtypedparam.h" #include "viruri.h" -#include "virdomainlist.h" +#include "virobjectlist.h" #define VIR_FROM_THIS VIR_FROM_LXC @@ -2641,7 +2641,7 @@ lxcListAllDomains(virConnectPtr conn, lxc_driver_t *driver = conn->privateData; int ret = -1; - virCheckFlags(VIR_CONNECT_LIST_FILTERS_ALL, -1); + virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1); lxcDriverLock(driver); ret = virDomainList(conn, driver->domains.objs, domains, flags); diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 2251b89..30c4032 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -60,7 +60,7 @@ #include "command.h" #include "viruri.h" #include "stats_linux.h" -#include "virdomainlist.h" +#include "virobjectlist.h" #define VIR_FROM_THIS VIR_FROM_OPENVZ @@ -2063,7 +2063,7 @@ openvzListAllDomains(virConnectPtr conn, struct openvz_driver *driver = conn->privateData; int ret = -1; - virCheckFlags(VIR_CONNECT_LIST_FILTERS_ALL, -1); + virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1); openvzDriverLock(driver); ret = virDomainList(conn, driver->domains.objs, domains, flags); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 46831a6..b4cfd7a 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -92,7 +92,7 @@ #include "virnodesuspend.h" #include "virtime.h" #include "virtypedparam.h" -#include "virdomainlist.h" +#include "virobjectlist.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -13158,7 +13158,7 @@ qemuListAllDomains(virConnectPtr conn, struct qemud_driver *driver = conn->privateData; int ret = -1; - virCheckFlags(VIR_CONNECT_LIST_FILTERS_ALL, -1); + virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1); qemuDriverLock(driver); ret = virDomainList(conn, driver->domains.objs, domains, flags); diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 990b20d..bf2c1c2 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -52,7 +52,7 @@ #include "virfile.h" #include "virtypedparam.h" #include "virrandom.h" -#include "virdomainlist.h" +#include "virobjectlist.h" #define VIR_FROM_THIS VIR_FROM_TEST @@ -5526,7 +5526,7 @@ static int testListAllDomains(virConnectPtr conn, testConnPtr privconn = conn->privateData; int ret; - virCheckFlags(VIR_CONNECT_LIST_FILTERS_ALL, -1); + virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1); testDriverLock(privconn); ret = virDomainList(conn, privconn->domains.objs, domains, flags); diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 128b112..fd6b49b 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -64,7 +64,7 @@ #include "virnetdevtap.h" #include "virnodesuspend.h" #include "viruri.h" -#include "virdomainlist.h" +#include "virobjectlist.h" #define VIR_FROM_THIS VIR_FROM_UML @@ -2525,7 +2525,7 @@ static int umlListAllDomains(virConnectPtr conn, struct uml_driver *driver = conn->privateData; int ret = -1; - virCheckFlags(VIR_CONNECT_LIST_FILTERS_ALL, -1); + virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1); umlDriverLock(driver); ret = virDomainList(conn, driver->domains.objs, domains, flags); diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 17e7e9a..12b834a 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -57,7 +57,7 @@ #include "virfile.h" #include "fdstream.h" #include "viruri.h" -#include "virdomainlist.h" +#include "virobjectlist.h" /* This one changes from version to version. */ #if VBOX_API_VERSION == 2002 @@ -9254,7 +9254,7 @@ vboxListAllDomains(virConnectPtr conn, bool active; PRUint32 snapshotCount; - virCheckFlags(VIR_CONNECT_LIST_FILTERS_ALL, -1); + virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1); /* filter out flag options that will produce 0 results in vbox driver: * - managed save: vbox guests don't have managed save images @@ -9302,13 +9302,13 @@ vboxListAllDomains(virConnectPtr conn, active = false; /* filter by active state */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_ACTIVE) && + if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) && !((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) && active) || (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) && !active))) continue; /* filter by snapshot existence */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_SNAPSHOT)) { + if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) { rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -9323,7 +9323,7 @@ vboxListAllDomains(virConnectPtr conn, } /* filter by machine state */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_STATE) && + if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE) && !((MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING) && state == MachineState_Running) || (MATCH(VIR_CONNECT_LIST_DOMAINS_PAUSED) && diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index 9af5078..3dc02ed 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -34,7 +34,7 @@ #include "vmx.h" #include "vmware_conf.h" #include "vmware_driver.h" -#include "virdomainlist.h" +#include "virobjectlist.h" static const char *vmw_types[] = { "player", "ws" }; @@ -1098,7 +1098,7 @@ vmwareListAllDomains(virConnectPtr conn, struct vmware_driver *driver = conn->privateData; int ret = -1; - virCheckFlags(VIR_CONNECT_LIST_FILTERS_ALL, -1); + virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1); vmwareDriverLock(driver); vmwareDomainObjListUpdateAll(&driver->domains, driver); diff --git a/tools/virsh.c b/tools/virsh.c index b9e159b..40f3be3 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -65,7 +65,7 @@ #include "conf/domain_conf.h" #include "virtypedparam.h" #include "intprops.h" -#include "conf/virdomainlist.h" +#include "conf/virobjectlist.h" static char *progname; @@ -1100,7 +1100,7 @@ fallback: virResetLastError(); /* list active domains, if necessary */ - if (!MATCH(VIR_CONNECT_LIST_FILTERS_ACTIVE) || + if (!MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) || MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE)) { if ((nids = virConnectNumOfDomains(ctl->conn)) < 0) { vshError(ctl, "%s", _("Failed to list active domains")); @@ -1117,7 +1117,7 @@ fallback: } } - if (!MATCH(VIR_CONNECT_LIST_FILTERS_ACTIVE) || + if (!MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) || MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE)) { if ((nnames = virConnectNumOfDefinedDomains(ctl->conn)) < 0) { vshError(ctl, "%s", _("Failed to list inactive domains")); @@ -1161,7 +1161,7 @@ filter: dom = list->domains[i]; /* persistence filter */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_PERSISTENT)) { + if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT)) { if ((persistent = virDomainIsPersistent(dom)) < 0) { vshError(ctl, "%s", _("Failed to get domain persistence info")); goto cleanup; @@ -1173,7 +1173,7 @@ filter: } /* domain state filter */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_STATE)) { + if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE)) { if (virDomainGetState(dom, &state, NULL, 0) < 0) { vshError(ctl, "%s", _("Failed to get domain state")); goto cleanup; @@ -1193,7 +1193,7 @@ filter: } /* autostart filter */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_AUTOSTART)) { + if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_AUTOSTART)) { if (virDomainGetAutostart(dom, &autostart) < 0) { vshError(ctl, "%s", _("Failed to get domain autostart state")); goto cleanup; @@ -1205,7 +1205,7 @@ filter: } /* managed save filter */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_MANAGEDSAVE)) { + if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_MANAGEDSAVE)) { if ((mansave = virDomainHasManagedSaveImage(dom, 0)) < 0) { vshError(ctl, "%s", _("Failed to check for managed save image")); @@ -1218,7 +1218,7 @@ filter: } /* snapshot filter */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_SNAPSHOT)) { + if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) { if ((nsnap = virDomainSnapshotNum(dom, 0)) < 0) { vshError(ctl, "%s", _("Failed to get snapshot count")); goto cleanup; -- 1.7.7.3

On 07/20/2012 08:24 AM, Osier Yang wrote:
Except objects of domains, domain snapshots, we will also add APIs to list objects like storage pools, storage vols, network, interface, etc. And it's deserved to have the small helper functions in a common file instead of in separate files.
This patch renames virdomainlist.[ch] to virobjectlist.[ch], and also renames the macros to filter domain objects more specificly.
s/specificly/specifically/
src/conf/virdomainlist.c: Renamed to src/conf/virobjectlist.c src/conf/virdomainlist.h: Renamed to src/conf/virobjectlist.h
Looks reasonable.
@@ -31,7 +33,7 @@ #include "datatypes.h" #include "virterror_internal.h"
-#define VIR_FROM_THIS VIR_FROM_DOMAIN +#define VIR_FROM_THIS VIR_FROM_NONE
I'm debating whether: s/VIR_FROM_NONE/VIR_FROM_CONF/ makes sense. Or maybe you keep the file organized in sections, and between each section, you: #undef VIR_FROM_THIS #define VIR_FROM_THIS VIR_FROM_SECRET // secret listing #undef VIR_FROM_THIS #define VIR_FROM_THIS VIR_FROM_DOMAIN_SNAPSHOT // snapshot listing and so forth. That way, the error messages will be a bit better. ACK. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 07/20/2012 10:24 AM, Osier Yang wrote:
Except objects of domains, domain snapshots, we will also add APIs to list objects like storage pools, storage vols, network, interface, etc. And it's deserved to have the small helper functions in a common file instead of in separate files.
This patch renames virdomainlist.[ch] to virobjectlist.[ch], and also renames the macros to filter domain objects more specificly.
I actually started looking at this series down in virConnectListAllNetworks, and was curious why functions specific to virNetwork were put into this new common file. After looking up at a few of the other additions to virobjectlist.c (all the patches with "add helpers (to|for) list" in the subject), it looks like what's ended up in this file are driver-specific functions that just look similar to each other. I don't think that is right. If there are any functions or data structures that are truly reusable *unchanged* by all of the drivers for their listall functions, it makes sense to put those in a common file, but to group together all of these functions just because they superficially look similar is wrong - it's going against all the work that's been done to separate things out on functional boundaries. In short, if a function is specific enough that its name starts with, e.g. virNetwork or virStoragePool, then it should be in that driver's file (or at least the *_conf.c associated with that driver), not in a common location.

This introduces a new API to list the storage pool objects, 4 groups of flags are provided to filter the returned pools: * Active or not * Autostarting or not * Persistent or not * And the pool type. include/libvirt/libvirt.h.in: New enum virConnectListAllStoragePoolFlags; Declare the API. python/generator.py: Skip the generating src/driver.h: (virDrvConnectListAllStoragePools) src/libvirt.c: Implementation for the API. src/libvirt_public.syms: Export the symbol. --- include/libvirt/libvirt.h.in | 32 ++++++++++++++ python/generator.py | 5 +- src/driver.h | 5 ++ src/libvirt.c | 93 +++++++++++++++++++++++++++++++++++++++--- src/libvirt_public.syms | 5 ++ 5 files changed, 132 insertions(+), 8 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index e34438c..c7e810e 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2471,6 +2471,38 @@ int virConnectListDefinedStoragePools(virConnectPtr conn, int maxnames); /* + * virConnectListAllStoragePoolsFlags: + * + * Flags used to filter the returned pools. Flags in each group + * are exclusive attribute for a pool. + */ +typedef enum { + VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE = 1 << 0, + VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE = 1 << 1, + + VIR_CONNECT_LIST_STORAGE_POOLS_PERSISTENT = 1 << 2, + VIR_CONNECT_LIST_STORAGE_POOLS_TRANSIENT = 1 << 3, + + VIR_CONNECT_LIST_STORAGE_POOLS_AUTOSTART = 1 << 4, + VIR_CONNECT_LIST_STORAGE_POOLS_NO_AUTOSTART = 1 << 5, + + /* List pools by type */ + VIR_CONNECT_LIST_STORAGE_POOLS_DIR = 1 << 6, + VIR_CONNECT_LIST_STORAGE_POOLS_FS = 1 << 7, + VIR_CONNECT_LIST_STORAGE_POOLS_NETFS = 1 << 8, + VIR_CONNECT_LIST_STORAGE_POOLS_LOGICAL = 1 << 9, + VIR_CONNECT_LIST_STORAGE_POOLS_DISK = 1 << 10, + VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI = 1 << 11, + VIR_CONNECT_LIST_STORAGE_POOLS_SCSI = 1 << 12, + VIR_CONNECT_LIST_STORAGE_POOLS_MPATH = 1 << 13, + VIR_CONNECT_LIST_STORAGE_POOLS_RBD = 1 << 14, + VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG = 1 << 15, +} virConnectListAllStoragePoolsFlags; + +int virConnectListAllStoragePools(virConnectPtr conn, + virStoragePoolPtr **pools, + unsigned int flags); +/* * Query a host for storage pools of a particular type */ char * virConnectFindStoragePoolSources(virConnectPtr conn, diff --git a/python/generator.py b/python/generator.py index 2dada6e..5934040 100755 --- a/python/generator.py +++ b/python/generator.py @@ -337,7 +337,7 @@ foreign_encoding_args = ( # ####################################################################### -# Class methods which are written by hand in libvir.c but the Python-level +# Class methods which are written by hand in libvirt.c but the Python-level # code is still automatically generated (so they are not in skip_function()). skip_impl = ( 'virConnectGetVersion', @@ -453,9 +453,10 @@ skip_function = ( 'virConnectDomainEventDeregisterAny', # overridden in virConnect.py 'virSaveLastError', # We have our own python error wrapper 'virFreeError', # Only needed if we use virSaveLastError - 'virConnectListAllDomains', #overridden in virConnect.py + 'virConnectListAllDomains', # overridden in virConnect.py 'virDomainListAllSnapshots', # overridden in virDomain.py 'virDomainSnapshotListAllChildren', # overridden in virDomainSnapshot.py + 'virConnectListAllStoragePools', # overridden in virConnect.py 'virStreamRecvAll', # Pure python libvirt-override-virStream.py 'virStreamSendAll', # Pure python libvirt-override-virStream.py diff --git a/src/driver.h b/src/driver.h index b3c1740..7e3e8a1 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1225,6 +1225,10 @@ typedef int (*virDrvConnectListDefinedStoragePools) (virConnectPtr conn, char **const names, int maxnames); +typedef int + (*virDrvConnectListAllStoragePools) (virConnectPtr conn, + virStoragePoolPtr **pools, + unsigned int flags); typedef char * (*virDrvConnectFindStoragePoolSources) (virConnectPtr conn, const char *type, @@ -1369,6 +1373,7 @@ struct _virStorageDriver { virDrvConnectListStoragePools listPools; virDrvConnectNumOfDefinedStoragePools numOfDefinedPools; virDrvConnectListDefinedStoragePools listDefinedPools; + virDrvConnectListAllStoragePools listAllPools; virDrvConnectFindStoragePoolSources findPoolSources; virDrvStoragePoolLookupByName poolLookupByName; virDrvStoragePoolLookupByUUID poolLookupByUUID; diff --git a/src/libvirt.c b/src/libvirt.c index df78e8a..541b1c3 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -11215,6 +11215,83 @@ virStoragePoolGetConnect (virStoragePoolPtr pool) } /** + * virConnectListAllStoragePools: + * @conn: Pointer to the hypervisor connection. + * @pools: Pointer to a variable to store the array containing storage pool + * objects or NULL if the list is not required (just returns number + * of pools). + * @flags: bitwise-OR of virConnectListAllStoragePoolsFlags. + * + * Collect the list of storage pools, and allocate an array to store those + * objects. This API solves the race inherent between virConnectListStoragePools + * and virConnectListDefinedStoragePools. + * + * By default, this API covers all storage pools; it is also possible + * to return the filtered objects with flags. Filters are provided in groups, + * where each group contains bits that describe mutually exclusive attributes + * of a storage pool. + * + * The first group of @flags is VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE and + * VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE to fitler the pools by state. + * + * The second group of @flags is VIR_CONNECT_LIST_STORAGE_POOLS_PERSITENT + * and VIR_CONNECT_LIST_STORAGE_POOLS_TRANSICIENT, to filter the pools by + * whether they have persistent config or not. + * + * The third group of @flags is VIR_CONNECT_LIST_STORAGE_POOLS_AUTOSTART + * and VIR_CONNECT_LIST_STORAGE_POOLS_NO_AUTOSTART, to filter the pools by + * whether they are marked as autostart or not. + * + * The last group of @flags is provided to filter the pools by the types, + * the flags include: + * VIR_CONNECT_LIST_STORAGE_POOLS_DIR, VIR_CONNECT_LIST_STORAGE_POOLS_FS, + * VIR_CONNECT_LIST_STORAGE_POOLS_NETFS, VIR_CONNECT_LIST_STORAGE_POOLS_LOGICAL, + * VIR_CONNECT_LIST_STORAGE_POOLS_DISK, VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI, + * VIR_CONNECT_LIST_STORAGE_POOLS_SCSI, VIR_CONNECT_LIST_STORAGE_POOLS_MPATH, + * VIR_CONNECT_LIST_STORAGE_POOLS_RBD, and VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG. + * + * Returns the number of storage pools found or -1 and sets @pools to + * NULL in case of error. On success, the array stored into @pools is + * guaranteed to have an extra allocated element set to NULL but not included + * in the return count, to make iteration easier. The caller is responsible + * for calling virStoragePoolFree() on each array element, then calling + * free() on @pools. + */ +int +virConnectListAllStoragePools(virConnectPtr conn, + virStoragePoolPtr **pools, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, pools=%p, flags=%x", conn, pools, flags); + + virResetLastError(); + + if (pools) + *pools = NULL; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (conn->storageDriver && + conn->storageDriver->listAllPools) { + int ret; + ret = conn->storageDriver->listAllPools(conn, pools, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} + +/** * virConnectNumOfStoragePools: * @conn: pointer to hypervisor connection * @@ -11256,9 +11333,11 @@ error: * @names: array of char * to fill with pool names (allocated by caller) * @maxnames: size of the names array * - * Provides the list of names of active storage pools - * upto maxnames. If there are more than maxnames, the - * remaining names will be silently ignored. + * Provides the list of names of active storage pools upto maxnames. + * If there are more than maxnames, the remaining names will be silently + * ignored. + * + * For more control over the results, see virConnectListAllStoragePools(). * * Returns 0 on success, -1 on error */ @@ -11339,9 +11418,11 @@ error: * @names: array of char * to fill with pool names (allocated by caller) * @maxnames: size of the names array * - * Provides the list of names of inactive storage pools - * upto maxnames. If there are more than maxnames, the - * remaining names will be silently ignored. + * Provides the list of names of inactive storage pools upto maxnames. + * If there are more than maxnames, the remaining names will be silently + * ignored. + * + * For more control over the results, see virConnectListAllStoragePools(). * * Returns 0 on success, -1 on error */ diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 2913a81..693a390 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -544,4 +544,9 @@ LIBVIRT_0.9.13 { virDomainSnapshotRef; } LIBVIRT_0.9.11; +LIBVIRT_0.9.14 { + global: + virConnectListAllStoragePools; +} LIBVIRT_0.9.13; + # .... define new API here using predicted next version number .... -- 1.7.7.3

On 07/20/2012 08:24 AM, Osier Yang wrote:
This introduces a new API to list the storage pool objects, 4 groups of flags are provided to filter the returned pools:
* Active or not
* Autostarting or not
* Persistent or not
* And the pool type.
include/libvirt/libvirt.h.in: New enum virConnectListAllStoragePoolFlags; Declare the API. python/generator.py: Skip the generating src/driver.h: (virDrvConnectListAllStoragePools) src/libvirt.c: Implementation for the API. src/libvirt_public.syms: Export the symbol.
+++ b/include/libvirt/libvirt.h.in @@ -2471,6 +2471,38 @@ int virConnectListDefinedStoragePools(virConnectPtr conn, int maxnames);
/* + * virConnectListAllStoragePoolsFlags: + * + * Flags used to filter the returned pools. Flags in each group + * are exclusive attribute for a pool.
In virConnectListAllDomainsFlags, we used a different wording: Flags used to tune pools returned by virConnectListAllStoragePools(). Note that these flags come in groups; if all bits from a group are 0, then that group is not used to filter results.
+++ b/src/libvirt.c @@ -11215,6 +11215,83 @@ virStoragePoolGetConnect (virStoragePoolPtr pool) }
/** + * virConnectListAllStoragePools: + * @conn: Pointer to the hypervisor connection. + * @pools: Pointer to a variable to store the array containing storage pool + * objects or NULL if the list is not required (just returns number + * of pools). + * @flags: bitwise-OR of virConnectListAllStoragePoolsFlags. + * + * Collect the list of storage pools, and allocate an array to store those + * objects. This API solves the race inherent between virConnectListStoragePools + * and virConnectListDefinedStoragePools.
It would also be worth enhancing the documentation of those two functions to point out the race, and cross-reference to this function. For a prior example, see how commit 747f64ee did things.
+ * + * By default, this API covers all storage pools; it is also possible + * to return the filtered objects with flags. Filters are provided in groups, + * where each group contains bits that describe mutually exclusive attributes + * of a storage pool.
The wording in the prior example was: Normally, all storage pools are returned; however, @flags can be used to filter the results for a smaller list of targeted pools. The valid flags are divided into groups, where each group contains bits that describe mutually exclusive attributes of a pool, and where all bits within a group describe all possible pools.
+ * + * The first group of @flags is VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE and + * VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE to fitler the pools by state.
s/fitler/filter/
@@ -11256,9 +11333,11 @@ error: * @names: array of char * to fill with pool names (allocated by caller) * @maxnames: size of the names array * - * Provides the list of names of active storage pools - * upto maxnames. If there are more than maxnames, the - * remaining names will be silently ignored. + * Provides the list of names of active storage pools upto maxnames.
s/upto/up to/
+ * If there are more than maxnames, the remaining names will be silently + * ignored. + * + * For more control over the results, see virConnectListAllStoragePools(). * * Returns 0 on success, -1 on error
This lists the cross-reference, but not the fact that there is an inherent race. Based on the prior example, this should be something like: Returns the number of pools found or -1 in case of error. Note that this command is inherently racy; a pool can be started between a call to virConnectNumOfStoragePools() and this call; you are only guaranteed that all currently active pools were listed if the return is less than @maxnames.
+++ b/src/libvirt_public.syms @@ -544,4 +544,9 @@ LIBVIRT_0.9.13 { virDomainSnapshotRef; } LIBVIRT_0.9.11;
+LIBVIRT_0.9.14 { + global: + virConnectListAllStoragePools; +} LIBVIRT_0.9.13;
Merge conflict with Guido's patch a91067f. Should be easy to resolve. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

src/conf/virobjectlist.c: Add virStoragePoolMatch to filter the pools; Add virStoragePoolList to iterate over the pool objects with filter. src/conf/virobjectlist.h: Declare virStoragePoolMatch, virStoragePoolList, and the macros for filters. src/libvirt_private.syms: Export helper virStoragePoolList. --- src/conf/virobjectlist.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++ src/conf/virobjectlist.h | 36 ++++++++++++++ src/libvirt_private.syms | 1 + 3 files changed, 155 insertions(+), 0 deletions(-) diff --git a/src/conf/virobjectlist.c b/src/conf/virobjectlist.c index 91eb660..fb5f974 100644 --- a/src/conf/virobjectlist.c +++ b/src/conf/virobjectlist.c @@ -29,6 +29,7 @@ #include "internal.h" #include "virhash.h" #include "domain_conf.h" +#include "storage_conf.h" #include "memory.h" #include "datatypes.h" #include "virterror_internal.h" @@ -134,6 +135,64 @@ cleanup: } #undef MATCH +#define MATCH(FLAG) (flags & (FLAG)) +static bool +virStoragePoolMatch (virStoragePoolObjPtr poolobj, + unsigned int flags) +{ + /* filter by active state */ + if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE) && + !((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE) && + virStoragePoolObjIsActive(poolobj)) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE) && + !virStoragePoolObjIsActive(poolobj)))) + return false; + + /* filter by persistence */ + if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_PERSISTENT) && + !((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_PERSISTENT) && + poolobj->configFile) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_TRANSIENT) && + !poolobj->configFile))) + return false; + + /* filter by autostart option */ + if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_AUTOSTART) && + !((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_AUTOSTART) && + poolobj->autostart) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_NO_AUTOSTART) && + !poolobj->autostart))) + return false; + + /* filter by pool type */ + if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_POOL_TYPE)) { + if (!((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_DIR) && + (poolobj->def->type == VIR_STORAGE_POOL_DIR)) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FS) && + (poolobj->def->type == VIR_STORAGE_POOL_FS)) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_NETFS) && + (poolobj->def->type == VIR_STORAGE_POOL_NETFS)) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_LOGICAL) && + (poolobj->def->type == VIR_STORAGE_POOL_LOGICAL)) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_DISK) && + (poolobj->def->type == VIR_STORAGE_POOL_DISK)) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI) && + (poolobj->def->type == VIR_STORAGE_POOL_ISCSI)) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_SCSI) && + (poolobj->def->type == VIR_STORAGE_POOL_SCSI)) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_MPATH) && + (poolobj->def->type == VIR_STORAGE_POOL_MPATH)) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_RBD) && + (poolobj->def->type == VIR_STORAGE_POOL_RBD)) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG) && + (poolobj->def->type == VIR_STORAGE_POOL_SHEEPDOG)))) + return false; + } + + return true; +} +#undef MATCH + int virDomainList(virConnectPtr conn, virHashTablePtr domobjs, @@ -222,3 +281,62 @@ cleanup: } return ret; } + +int +virStoragePoolList(virConnectPtr conn, + virStoragePoolObjList poolobjs, + virStoragePoolPtr **pools, + unsigned int flags) +{ + virStoragePoolPtr *tmp_pools = NULL; + virStoragePoolPtr pool = NULL; + int npools = 0; + int ret = -1; + int i; + + if (pools) { + if (VIR_ALLOC_N(tmp_pools, poolobjs.count + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + } + + for (i = 0; i < poolobjs.count; i++) { + virStoragePoolObjPtr poolobj = poolobjs.objs[i]; + virStoragePoolObjLock(poolobj); + if (virStoragePoolMatch(poolobj, flags)) { + if (pools) { + if (!(pool = virGetStoragePool(conn, + poolobj->def->name, + poolobj->def->uuid))) { + virStoragePoolObjUnlock(poolobj); + goto cleanup; + } + tmp_pools[npools++] = pool; + } else { + npools++; + } + } + virStoragePoolObjUnlock(poolobj); + } + + if (tmp_pools) { + /* trim the array to the final size */ + ignore_value(VIR_REALLOC_N(tmp_pools, npools + 1)); + *pools = tmp_pools; + tmp_pools = NULL; + } + + ret = npools; + +cleanup: + if (tmp_pools) { + for (i = 0; i < poolobjs.count; i++) { + if (tmp_pools[i]) + virStoragePoolFree(tmp_pools[i]); + } + } + + VIR_FREE(tmp_pools); + return ret; +} diff --git a/src/conf/virobjectlist.h b/src/conf/virobjectlist.h index 510a900..b93cd19 100644 --- a/src/conf/virobjectlist.h +++ b/src/conf/virobjectlist.h @@ -27,6 +27,7 @@ # include "internal.h" # include "virhash.h" # include "domain_conf.h" +# include "storage_conf.h" # define VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE \ (VIR_CONNECT_LIST_DOMAINS_ACTIVE | \ @@ -74,6 +75,36 @@ (VIR_DOMAIN_SNAPSHOT_FILTERS_METADATA | \ VIR_DOMAIN_SNAPSHOT_FILTERS_LEAVES) +# define VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE \ + (VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE | \ + VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE) + +# define VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_PERSISTENT \ + (VIR_CONNECT_LIST_STORAGE_POOLS_PERSISTENT | \ + VIR_CONNECT_LIST_STORAGE_POOLS_TRANSIENT) + +# define VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_AUTOSTART \ + (VIR_CONNECT_LIST_STORAGE_POOLS_AUTOSTART | \ + VIR_CONNECT_LIST_STORAGE_POOLS_NO_AUTOSTART) + +# define VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_POOL_TYPE \ + (VIR_CONNECT_LIST_STORAGE_POOLS_DIR | \ + VIR_CONNECT_LIST_STORAGE_POOLS_FS | \ + VIR_CONNECT_LIST_STORAGE_POOLS_NETFS | \ + VIR_CONNECT_LIST_STORAGE_POOLS_LOGICAL | \ + VIR_CONNECT_LIST_STORAGE_POOLS_DISK | \ + VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI | \ + VIR_CONNECT_LIST_STORAGE_POOLS_SCSI | \ + VIR_CONNECT_LIST_STORAGE_POOLS_MPATH | \ + VIR_CONNECT_LIST_STORAGE_POOLS_RBD | \ + VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG) + +# define VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ALL \ + (VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE | \ + VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_PERSISTENT | \ + VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_AUTOSTART | \ + VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_POOL_TYPE) + int virDomainList(virConnectPtr conn, virHashTablePtr domobjs, virDomainPtr **domains, unsigned int flags); @@ -83,4 +114,9 @@ int virDomainListSnapshots(virDomainSnapshotObjListPtr snapshots, virDomainSnapshotPtr **snaps, unsigned int flags); +int virStoragePoolList(virConnectPtr conn, + virStoragePoolObjList poolobjs, + virStoragePoolPtr **pools, + unsigned int flags); + #endif /* __VIR_OBJECT_LIST_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index e66d358..18b3185 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1246,6 +1246,7 @@ virDBusGetSystemBus; # virobjectlist.h virDomainList; virDomainListSnapshots; +virStoragePoolList; # virfile.h -- 1.7.7.3

On 07/20/2012 08:24 AM, Osier Yang wrote:
src/conf/virobjectlist.c: Add virStoragePoolMatch to filter the pools; Add virStoragePoolList to iterate over the pool objects with filter.
src/conf/virobjectlist.h: Declare virStoragePoolMatch, virStoragePoolList, and the macros for filters.
src/libvirt_private.syms: Export helper virStoragePoolList. --- src/conf/virobjectlist.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++ src/conf/virobjectlist.h | 36 ++++++++++++++ src/libvirt_private.syms | 1 + 3 files changed, 155 insertions(+), 0 deletions(-)
+#define MATCH(FLAG) (flags & (FLAG)) +static bool +virStoragePoolMatch (virStoragePoolObjPtr poolobj,
No space before (. ACK. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 07/20/2012 10:24 AM, Osier Yang wrote:
src/conf/virobjectlist.c: Add virStoragePoolMatch to filter the pools; Add virStoragePoolList to iterate over the pool objects with filter.
Again, I disagree with the decision to put driver-specific functions such as virStoragePoolMatch and virStoragePoolList in a common file.

The RPC generator doesn't support returning list of object, this patch do the work manually. * daemon/remote.c: Implement the server side handler remoteDispatchConnectListAllStoragePools * src/remote/remote_driver.c: Add remote driver handler remoteConnectListAllStoragePools. * src/remote/remote_protocol.x: New RPC procedure REMOTE_PROC_CONNECT_LIST_ALL_STORAGE_POOLS and structs to represent the args and ret for it. * src/remote_protocol-structs: Likewise. --- daemon/remote.c | 54 +++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 64 ++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 12 +++++++- src/remote_protocol-structs | 12 ++++++++ 4 files changed, 141 insertions(+), 1 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 9334221..060c5a0 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -3952,6 +3952,60 @@ cleanup: return rv; } +static int +remoteDispatchConnectListAllStoragePools(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_connect_list_all_storage_pools_args *args, + remote_connect_list_all_storage_pools_ret *ret) +{ + virStoragePoolPtr *pools = NULL; + int npools = 0; + int i; + int rv = -1; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if ((npools = virConnectListAllStoragePools(priv->conn, + args->need_results ? &pools : NULL, + args->flags)) < 0) + goto cleanup; + + if (pools && npools) { + if (VIR_ALLOC_N(ret->pools.pools_val, npools) < 0) { + virReportOOMError(); + goto cleanup; + } + + ret->pools.pools_len = npools; + + for (i = 0; i < npools; i++) + make_nonnull_storage_pool(ret->pools.pools_val + i, pools[i]); + } else { + ret->pools.pools_len = 0; + ret->pools.pools_val = NULL; + } + + ret->ret = npools; + + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (pools) { + for (i = 0; i < npools; i++) + virStoragePoolFree(pools[i]); + VIR_FREE(pools); + } + return rv; +} + /*----- Helpers. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index d91ae87..ab821d5 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -2652,6 +2652,69 @@ done: return rv; } +static int +remoteConnectListAllStoragePools (virConnectPtr conn, + virStoragePoolPtr **pools, + unsigned int flags) +{ + int rv = -1; + int i; + virStoragePoolPtr *tmp_pools = NULL; + remote_connect_list_all_storage_pools_args args; + remote_connect_list_all_storage_pools_ret ret; + + struct private_data *priv = conn->privateData; + + remoteDriverLock(priv); + + args.need_results = !!pools; + args.flags = flags; + + memset(&ret, 0, sizeof(ret)); + if (call(conn, + priv, + 0, + REMOTE_PROC_CONNECT_LIST_ALL_STORAGE_POOLS, + (xdrproc_t) xdr_remote_connect_list_all_storage_pools_args, + (char *) &args, + (xdrproc_t) xdr_remote_connect_list_all_storage_pools_ret, + (char *) &ret) == -1) + goto done; + + if (pools) { + if (VIR_ALLOC_N(tmp_pools, ret.pools.pools_len + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + for (i = 0; i < ret.pools.pools_len; i++) { + tmp_pools[i] = get_nonnull_storage_pool(conn, ret.pools.pools_val[i]); + if (!tmp_pools[i]) { + virReportOOMError(); + goto cleanup; + } + } + *pools = tmp_pools; + tmp_pools = NULL; + } + + rv = ret.ret; + +cleanup: + if (tmp_pools) { + for (i = 0; i < ret.pools.pools_len; i++) + if (tmp_pools[i]) + virStoragePoolFree(tmp_pools[i]); + VIR_FREE(tmp_pools); + } + + xdr_free((xdrproc_t) xdr_remote_connect_list_all_storage_pools_ret, (char *) &ret); + +done: + remoteDriverUnlock(priv); + return rv; +} + /*----------------------------------------------------------------------*/ static virDrvOpenStatus ATTRIBUTE_NONNULL (1) @@ -5401,6 +5464,7 @@ static virStorageDriver storage_driver = { .listPools = remoteListStoragePools, /* 0.4.1 */ .numOfDefinedPools = remoteNumOfDefinedStoragePools, /* 0.4.1 */ .listDefinedPools = remoteListDefinedStoragePools, /* 0.4.1 */ + .listAllPools = remoteConnectListAllStoragePools, /* 0.9.14 */ .findPoolSources = remoteFindStoragePoolSources, /* 0.4.5 */ .poolLookupByName = remoteStoragePoolLookupByName, /* 0.4.1 */ .poolLookupByUUID = remoteStoragePoolLookupByUUID, /* 0.4.1 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 8f1d9b5..dfd67bc 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -2518,6 +2518,15 @@ struct remote_connect_list_all_domains_ret { unsigned int ret; }; +struct remote_connect_list_all_storage_pools_args { + int need_results; + unsigned int flags; +}; + +struct remote_connect_list_all_storage_pools_ret { + remote_nonnull_storage_pool pools<>; + unsigned int ret; +}; /*----- Protocol. -----*/ @@ -2844,7 +2853,8 @@ enum remote_procedure { REMOTE_PROC_CONNECT_LIST_ALL_DOMAINS = 273, /* skipgen skipgen priority:high */ REMOTE_PROC_DOMAIN_LIST_ALL_SNAPSHOTS = 274, /* skipgen skipgen priority:high */ REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_ALL_CHILDREN = 275, /* skipgen skipgen priority:high */ - REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE = 276 /* autogen autogen */ + REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE = 276, /* autogen autogen */ + REMOTE_PROC_CONNECT_LIST_ALL_STORAGE_POOLS = 277 /* skipgen skipgen priority:high */ /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 511284c..25cb819 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1974,6 +1974,17 @@ struct remote_connect_list_all_domains_ret { } domains; u_int ret; }; +struct remote_connect_list_all_storage_pools_args { + int need_results; + u_int flags; +}; +struct remote_connect_list_all_storage_pools_ret { + struct { + u_int pools_len; + remote_nonnull_domain * pools_val; + } pools; + u_int ret; +}; enum remote_procedure { REMOTE_PROC_OPEN = 1, REMOTE_PROC_CLOSE = 2, @@ -2251,4 +2262,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_LIST_ALL_SNAPSHOTS = 274, REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_ALL_CHILDREN = 275, REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE = 276, + REMOTE_PROC_CONNECT_LIST_ALL_STORAGE_POOLS = 277, }; -- 1.7.7.3

src/storage/storage_driver.c: Implement listAllStoragePools. --- src/storage/storage_driver.c | 19 +++++++++++++++++++ 1 files changed, 19 insertions(+), 0 deletions(-) diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index c9b8021..0974879 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -42,6 +42,7 @@ #include "util.h" #include "storage_driver.h" #include "storage_conf.h" +#include "virobjectlist.h" #include "memory.h" #include "storage_backend.h" #include "logging.h" @@ -2287,6 +2288,23 @@ cleanup: return ret; } +static int +storageListAllPools(virConnectPtr conn, + virStoragePoolPtr **pools, + unsigned int flags) +{ + virStorageDriverStatePtr driver = conn->storagePrivateData; + int ret = -1; + + virCheckFlags(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ALL, -1); + + storageDriverLock(driver); + ret = virStoragePoolList(conn, driver->pools, pools, flags); + storageDriverUnlock(driver); + + return ret; +} + static virStorageDriver storageDriver = { .name = "storage", .open = storageOpen, /* 0.4.0 */ @@ -2295,6 +2313,7 @@ static virStorageDriver storageDriver = { .listPools = storageListPools, /* 0.4.0 */ .numOfDefinedPools = storageNumDefinedPools, /* 0.4.0 */ .listDefinedPools = storageListDefinedPools, /* 0.4.0 */ + .listAllPools = storageListAllPools, /* 0.9.14 */ .findPoolSources = storageFindPoolSources, /* 0.4.0 */ .poolLookupByName = storagePoolLookupByName, /* 0.4.0 */ .poolLookupByUUID = storagePoolLookupByUUID, /* 0.4.0 */ -- 1.7.7.3

src/test/test_driver.c: Implement listAllStoragePools --- src/test/test_driver.c | 17 +++++++++++++++++ 1 files changed, 17 insertions(+), 0 deletions(-) diff --git a/src/test/test_driver.c b/src/test/test_driver.c index bf2c1c2..21164ca 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -3942,6 +3942,22 @@ no_memory: return -1; } +static int +testStorageListAllPools(virConnectPtr conn, + virStoragePoolPtr **pools, + unsigned int flags) +{ + testConnPtr privconn = conn->privateData; + int ret = -1; + + virCheckFlags(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ALL, -1); + + testDriverLock(privconn); + ret = virStoragePoolList(conn, privconn->pools, pools, flags); + testDriverUnlock(privconn); + + return ret; +} static int testStoragePoolIsActive(virStoragePoolPtr pool) { @@ -5660,6 +5676,7 @@ static virStorageDriver testStorageDriver = { .listPools = testStorageListPools, /* 0.5.0 */ .numOfDefinedPools = testStorageNumDefinedPools, /* 0.5.0 */ .listDefinedPools = testStorageListDefinedPools, /* 0.5.0 */ + .listAllPools = testStorageListAllPools, /* 0.9.14 */ .findPoolSources = testStorageFindPoolSources, /* 0.5.0 */ .poolLookupByName = testStoragePoolLookupByName, /* 0.5.0 */ .poolLookupByUUID = testStoragePoolLookupByUUID, /* 0.5.0 */ -- 1.7.7.3

tools/virsh.c: New helper function vshStringToArray, use the helper in cmdUndefine. --- tools/virsh.c | 107 +++++++++++++++++++++++++++++++++++---------------------- 1 files changed, 66 insertions(+), 41 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 40f3be3..9c3b565 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -3014,6 +3014,51 @@ static const vshCmdOptDef opts_undefine[] = { {NULL, 0, 0, NULL} }; +/* + * Convert the strings separated by ',' into array. The caller + * must free the returned array after use. + * + * Returns the length of the filled array on success, or -1 + * on error. + */ +static int +vshStringToArray(char *str, + char ***array) +{ + char *str_tok = NULL; + unsigned int nstr_tokens = 0; + char **arr = NULL; + + /* tokenize the string from user and save it's parts into an array */ + if (str) { + nstr_tokens = 1; + + /* count the delimiters */ + str_tok = str; + while (*str_tok) { + if (*str_tok == ',') + nstr_tokens++; + str_tok++; + } + + if (VIR_ALLOC_N(arr, nstr_tokens) < 0) { + virReportOOMError(); + return -1; + } + + /* tokenize the input string */ + nstr_tokens = 0; + str_tok = str; + do { + arr[nstr_tokens] = strsep(&str_tok, ","); + nstr_tokens++; + } while (str_tok); + } + + *array = arr; + return nstr_tokens; +} + static bool cmdUndefine(vshControl *ctl, const vshCmd *cmd) { @@ -3039,21 +3084,21 @@ cmdUndefine(vshControl *ctl, const vshCmd *cmd) int running; /* list of volumes to remove along with this domain */ const char *volumes_arg = NULL; - char *volumes = NULL; - char **volume_tokens = NULL; - char *volume_tok = NULL; - int nvolume_tokens = 0; + char *volumes_str = NULL; + char **volumes = NULL; + char *volume = NULL; + int volumes_len = 0; char *def = NULL; char *source = NULL; char *target = NULL; int vol_i; - int tok_i; xmlDocPtr doc = NULL; xmlXPathContextPtr ctxt = NULL; xmlNodePtr *vol_nodes = NULL; int nvolumes = 0; virStorageVolPtr vol = NULL; bool vol_del_failed = false; + int i; if (managed_save) { flags |= VIR_DOMAIN_UNDEFINE_MANAGED_SAVE; @@ -3072,7 +3117,7 @@ cmdUndefine(vshControl *ctl, const vshCmd *cmd) /* check if a string that should contain list of volumes to remove is present */ if (vshCommandOptString(cmd, "storage", &volumes_arg) > 0) { - volumes = vshStrdup(ctl, volumes_arg); + volumes_str = vshStrdup(ctl, volumes_arg); if (remove_all_storage) { vshError(ctl, _("Specified both --storage and --remove-all-storage")); @@ -3212,27 +3257,8 @@ out: if (remove_storage || remove_all_storage) { ret = false; - /* tokenize the string from user and save it's parts into an array */ - if (volumes) { - /* count the delimiters */ - volume_tok = volumes; - nvolume_tokens = 1; /* we need at least one member */ - while (*volume_tok) { - if (*volume_tok == ',') - nvolume_tokens++; - volume_tok++; - } - - volume_tokens = vshCalloc(ctl, nvolume_tokens, sizeof(char *)); - - /* tokenize the input string */ - nvolume_tokens = 0; - volume_tok = volumes; - do { - volume_tokens[nvolume_tokens] = strsep(&volume_tok, ","); - nvolume_tokens++; - } while (volume_tok); - } + if ((volumes_len = vshStringToArray(volumes_str, &volumes)) < 0) + goto cleanup; doc = virXMLParseStringCtxt(def, _("(domain_definition)"), &ctxt); if (!doc) @@ -3268,17 +3294,17 @@ out: /* lookup if volume was selected by user */ if (volumes) { - volume_tok = NULL; - for (tok_i = 0; tok_i < nvolume_tokens; tok_i++) { - if (volume_tokens[tok_i] && - (STREQ_NULLABLE(volume_tokens[tok_i], target) || - STREQ_NULLABLE(volume_tokens[tok_i], source))) { - volume_tok = volume_tokens[tok_i]; - volume_tokens[tok_i] = NULL; + volume = NULL; + for (i = 0; i < volumes_len; i++) { + if (volumes[i] && + (STREQ_NULLABLE(volumes[i], target) || + STREQ_NULLABLE(volumes[i], source))) { + volume = volumes[i]; + volumes[i] = NULL; break; } } - if (!volume_tok) + if (!volume) continue; } @@ -3311,16 +3337,16 @@ out: target, source); vol_del_failed = true; } - vshPrint(ctl, _("Volume '%s' removed.\n"), volume_tok?volume_tok:source); + vshPrint(ctl, _("Volume '%s' removed.\n"), volume ? volume :source); } /* print volumes specified by user that were not found in domain definition */ if (volumes) { - for (tok_i = 0; tok_i < nvolume_tokens; tok_i++) { - if (volume_tokens[tok_i]) + for (i = 0; i < volumes_len; i++) { + if (volumes[i]) vshPrint(ctl, _("Volume '%s' was not found in domain's " "definition.\n"), - volume_tokens[tok_i]); + volumes[i]); } } @@ -3331,8 +3357,8 @@ out: cleanup: VIR_FREE(source); VIR_FREE(target); + VIR_FREE(volumes_str); VIR_FREE(volumes); - VIR_FREE(volume_tokens); VIR_FREE(def); VIR_FREE(vol_nodes); if (vol) @@ -3343,7 +3369,6 @@ cleanup: return ret; } - /* * "start" command */ -- 1.7.7.3

The storage pool's management doesn't relate with a domain, it probably was a intention, but not achieved yet. And the fact is only active pools are listed by default. --- tools/virsh.pod | 9 ++++----- 1 files changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/virsh.pod b/tools/virsh.pod index 4bddf15..f79c945 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -2156,11 +2156,10 @@ Returns basic information about the I<pool> object. =item B<pool-list> [I<--inactive> | I<--all>] [I<--details>] -List pool objects known to libvirt. By default, only pools in use by -active domains are listed; I<--inactive> lists just the inactive -pools, and I<--all> lists all pools. The I<--details> option instructs -virsh to additionally display pool persistence and capacity related -information where available. +List pool objects known to libvirt. By default, only active pools +are listed; I<--inactive> lists just the inactive pools, and I<--all> +lists all pools. The I<--details> option instructs virsh to additionally +display pool persistence and capacity related information where available. =item B<pool-name> I<uuid> -- 1.7.7.3

tools/virsh.c: Change MATCH for common use. It's safe, only the new helpers to collect objects use it. --- tools/virsh.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 9c3b565..2d4567d 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -84,6 +84,8 @@ static char *progname; /* Default escape char Ctrl-] as per telnet */ #define CTRL_CLOSE_BRACKET "^]" +#define MATCH(FLAG) (flags & (FLAG)) + /** * The log configuration */ @@ -1042,7 +1044,6 @@ vshDomainListFree(vshDomainListPtr domlist) VIR_FREE(domlist); } -#define MATCH(FLAG) (flags & (FLAG)) static vshDomainListPtr vshDomainListCollect(vshControl *ctl, unsigned int flags) { @@ -1263,7 +1264,6 @@ cleanup: VIR_FREE(ids); return list; } -#undef MATCH static const vshCmdOptDef opts_list[] = { -- 1.7.7.3

tools/virsh.c: * vshStoragePoolSorter to sort the pool list by pool name. * struct vshStoragePoolList to present the pool list, pool info is collected by list->poolinfo if 'details' is specified by user. * vshStoragePoolListFree to free the pool list * vshStoragePoolListCollect to collect the pool list, new API virStorageListAllPools is tried first, if it's not supported, fall back to older APIs. * New options --persistent, --transient, --autostart, --no-autostart and --type for pool-list. --persistent or --transient is to filter the returned pool list by whether the pool is persistent or not. --autostart or --no-autostart is to filter the returned pool list by whether the pool is autostarting or not. --type is to filter the pools by pool types. E.g. % virsh pool-list --all --persistent --type dir,disk tools/virsh.pod: * Add documentations for the new options. --- tools/virsh.c | 442 ++++++++++++++++++++++++++++++++++++++++++------------- tools/virsh.pod | 24 +++- 2 files changed, 362 insertions(+), 104 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 2d4567d..ab64918 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -10868,6 +10868,233 @@ cmdPoolDumpXML(vshControl *ctl, const vshCmd *cmd) return ret; } +static int +vshStoragePoolSorter(const void *a, const void *b) +{ + virStoragePoolPtr *pa = (virStoragePoolPtr *) a; + virStoragePoolPtr *pb = (virStoragePoolPtr *) b; + + if (*pa && !*pb) + return -1; + + if (!*pa) + return *pb != NULL; + + return strcasecmp(virStoragePoolGetName(*pa), + virStoragePoolGetName(*pb)); +} + +struct vshStoragePoolList { + virStoragePoolPtr *pools; + size_t npools; +}; +typedef struct vshStoragePoolList *vshStoragePoolListPtr; + +static void +vshStoragePoolListFree(vshStoragePoolListPtr list) +{ + int i; + + if (list && list->pools) { + for (i = 0; i < list->npools; i++) { + if (list->pools[i]) + virStoragePoolFree(list->pools[i]); + } + VIR_FREE(list->pools); + } + VIR_FREE(list); +} + +static vshStoragePoolListPtr +vshStoragePoolListCollect(vshControl *ctl, + unsigned int flags) +{ + vshStoragePoolListPtr list = vshMalloc(ctl, sizeof(*list)); + int i; + int ret; + char **names = NULL; + virStoragePoolPtr pool; + bool success = false; + size_t deleted = 0; + int persistent; + int autostart; + int nActivePools = 0; + int nInactivePools = 0; + int nAllPools = 0; + + /* try the list with flags support (0.9.14 and later) */ + if ((ret = virConnectListAllStoragePools(ctl->conn, + &list->pools, + flags)) >= 0) { + list->npools = ret; + goto finished; + } + + /* check if the command is actually supported */ + if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) { + virFreeError(last_error); + last_error = NULL; + 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_STORAGE_POOLS_ACTIVE | + VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE); + virFreeError(last_error); + last_error = NULL; + if ((ret = virConnectListAllStoragePools(ctl->conn, &list->pools, + newflags)) >= 0) { + list->npools = ret; + goto filter; + } + } + + /* there was an error during the first or second call */ + vshError(ctl, "%s", _("Failed to list pools")); + goto cleanup; + + +fallback: + /* fall back to old method (0.9.13 and older) */ + virResetLastError(); + + /* There is no way to get the pool type */ + if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_POOL_TYPE)) { + vshError(ctl, "%s", _("Filtering using --type is not supported " + "by this libvirt")); + goto cleanup; + } + + /* Get the number of active pools */ + if (!MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE) || + MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE)) { + if ((nActivePools = virConnectNumOfStoragePools(ctl->conn)) < 0) { + vshError(ctl, "%s", _("Failed to get the number of active pools ")); + goto cleanup; + } + } + + /* Get the number of inactive pools */ + if (!MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE) || + MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE)) { + if ((nInactivePools = virConnectNumOfDefinedStoragePools(ctl->conn)) < 0) { + vshError(ctl, "%s", _("Failed to get the number of inactive pools")); + goto cleanup; + } + } + + nAllPools = nActivePools + nInactivePools; + + if (nAllPools == 0) + return list; + + names = vshMalloc(ctl, sizeof(char *) * nAllPools); + + /* Retrieve a list of active storage pool names */ + if (!MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE) || + MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE)) { + if (virConnectListStoragePools(ctl->conn, + names, nActivePools) < 0) { + vshError(ctl, "%s", _("Failed to list active pools")); + goto cleanup; + } + } + + /* Add the inactive storage pools to the end of the name list */ + if (!MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE) || + MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE)) { + if (virConnectListDefinedStoragePools(ctl->conn, + &names[nActivePools], + nInactivePools) < 0) { + vshError(ctl, "%s", _("Failed to list inactive pools")); + goto cleanup; + } + } + + list->pools = vshMalloc(ctl, sizeof(virStoragePoolPtr) * (nAllPools)); + list->npools = 0; + + /* get active pools */ + for (i = 0; i < nActivePools; i++) { + if (!(pool = virStoragePoolLookupByName(ctl->conn, names[i]))) + continue; + list->pools[list->npools++] = pool; + } + + /* get inactive pools */ + for (i = 0; i < nInactivePools; i++) { + if (!(pool = virStoragePoolLookupByName(ctl->conn, names[i]))) + continue; + list->pools[list->npools++] = pool; + } + + /* truncate pools that weren't found */ + deleted = nAllPools - list->npools; + +filter: + /* filter list the list if the list was acquired by fallback means */ + for (i = 0; i < list->npools; i++) { + pool = list->pools[i]; + + /* persistence filter */ + if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_PERSISTENT)) { + if ((persistent = virStoragePoolIsPersistent(pool)) < 0) { + vshError(ctl, "%s", _("Failed to get pool persistence info")); + goto cleanup; + } + + if (!((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_PERSISTENT) && persistent) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_TRANSIENT) && !persistent))) + goto remove_entry; + } + + /* autostart filter */ + if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_AUTOSTART)) { + if (virStoragePoolGetAutostart(pool, &autostart) < 0) { + vshError(ctl, "%s", _("Failed to get pool autostart state")); + goto cleanup; + } + + if (!((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_AUTOSTART) && autostart) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_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 */ + virStoragePoolFree(list->pools[i]); + list->pools[i] = NULL; + deleted++; + } + +finished: + /* sort the list */ + if (list->pools && list->npools) + qsort(list->pools, list->npools, + sizeof(*list->pools), vshStoragePoolSorter); + + /* truncate the list if filter simulation deleted entries */ + if (deleted) + VIR_SHRINK_N(list->pools, list->npools, deleted); + + success = true; + +cleanup: + for (i = 0; i < nAllPools; i++) + VIR_FREE(names[i]); + + if (!success) { + vshStoragePoolListFree(list); + list = NULL; + } + + VIR_FREE(names); + return list; +} /* * "pool-list" command @@ -10881,7 +11108,12 @@ static const vshCmdInfo info_pool_list[] = { static const vshCmdOptDef opts_pool_list[] = { {"inactive", VSH_OT_BOOL, 0, N_("list inactive pools")}, {"all", VSH_OT_BOOL, 0, N_("list inactive & active pools")}, + {"transient", VSH_OT_BOOL, 0, N_("list transient pools")}, + {"persistent", VSH_OT_BOOL, 0, N_("list persistent pools")}, + {"autostart", VSH_OT_BOOL, 0, N_("list pools with autostart enabled")}, + {"no-autostart", VSH_OT_BOOL, 0, N_("list pools with autostart disabled")}, {"details", VSH_OT_BOOL, 0, N_("display extended details for pools")}, + {"type", VSH_OT_STRING, 0, N_("only list pool of specified type(s) (if supported)")}, {NULL, 0, 0, NULL} }; @@ -10889,10 +11121,8 @@ static bool cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) { virStoragePoolInfo info; - char **poolNames = NULL; int i, ret; - bool functionReturn; - int numActivePools = 0, numInactivePools = 0, numAllPools = 0; + bool functionReturn = false; size_t stringLength = 0, nameStrLength = 0; size_t autostartStrLength = 0, persistStrLength = 0; size_t stateStrLength = 0, capStrLength = 0; @@ -10906,84 +11136,103 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) char *available; }; struct poolInfoText *poolInfoTexts = NULL; - - /* Determine the options passed by the user */ - bool all = vshCommandOptBool(cmd, "all"); + unsigned int flags = VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE; + vshStoragePoolListPtr list = NULL; + const char *type = NULL; bool details = vshCommandOptBool(cmd, "details"); - bool inactive = vshCommandOptBool(cmd, "inactive"); - bool active = !inactive || all; - inactive |= all; + bool inactive, all; - /* Check the connection to libvirtd daemon is still working */ - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; + inactive = vshCommandOptBool(cmd, "inactive"); + all = vshCommandOptBool(cmd, "all"); - /* Retrieve the number of active storage pools */ - if (active) { - numActivePools = virConnectNumOfStoragePools(ctl->conn); - if (numActivePools < 0) { - vshError(ctl, "%s", _("Failed to list active pools")); - return false; - } - } + if (inactive) + flags = VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE; - /* Retrieve the number of inactive storage pools */ - if (inactive) { - numInactivePools = virConnectNumOfDefinedStoragePools(ctl->conn); - if (numInactivePools < 0) { - vshError(ctl, "%s", _("Failed to list inactive pools")); - return false; - } - } + if (all) + flags = VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE | + VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE; - /* Determine the total number of pools to list */ - numAllPools = numActivePools + numInactivePools; + if (vshCommandOptBool(cmd, "autostart")) + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_AUTOSTART; - /* Allocate memory for arrays of storage pool names and info */ - poolNames = vshCalloc(ctl, numAllPools, sizeof(*poolNames)); - poolInfoTexts = - vshCalloc(ctl, numAllPools, sizeof(*poolInfoTexts)); + if (vshCommandOptBool(cmd, "no-autostart")) + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_NO_AUTOSTART; - /* Retrieve a list of active storage pool names */ - if (active) { - if (virConnectListStoragePools(ctl->conn, - poolNames, numActivePools) < 0) { - vshError(ctl, "%s", _("Failed to list active pools")); - VIR_FREE(poolInfoTexts); - VIR_FREE(poolNames); - return false; - } + if (vshCommandOptBool(cmd, "persistent")) + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_PERSISTENT; + + if (vshCommandOptBool(cmd, "transient")) + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_TRANSIENT; + + if (vshCommandOptString(cmd, "type", &type) < 0) { + vshError(ctl, "%s", _("Invalid argument for 'type'")); + return false; } - /* Add the inactive storage pools to the end of the name list */ - if (inactive) { - if (virConnectListDefinedStoragePools(ctl->conn, - &poolNames[numActivePools], - numInactivePools) < 0) { - vshError(ctl, "%s", _("Failed to list inactive pools")); - VIR_FREE(poolInfoTexts); - VIR_FREE(poolNames); - return false; + if (type) { + int poolType = -1; + char **poolTypes = NULL; + int npoolTypes = 0; + + npoolTypes = vshStringToArray((char *)type, &poolTypes); + + for (i = 0; i < npoolTypes; i++) { + if ((poolType = virStoragePoolTypeFromString(poolTypes[i])) < 0) { + vshError(ctl, "%s", _("Invalid pool type")); + VIR_FREE(poolTypes); + return false; + } + + switch(poolType) { + case VIR_STORAGE_POOL_DIR: + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_DIR; + break; + case VIR_STORAGE_POOL_FS: + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_FS; + break; + case VIR_STORAGE_POOL_NETFS: + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_NETFS; + break; + case VIR_STORAGE_POOL_LOGICAL: + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_LOGICAL; + break; + case VIR_STORAGE_POOL_DISK: + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_DISK; + break; + case VIR_STORAGE_POOL_ISCSI: + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI; + break; + case VIR_STORAGE_POOL_SCSI: + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_SCSI; + break; + case VIR_STORAGE_POOL_MPATH: + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_MPATH; + break; + case VIR_STORAGE_POOL_RBD: + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_RBD; + break; + default: + break; + } } + VIR_FREE(poolTypes); } - /* Sort the storage pool names */ - qsort(poolNames, numAllPools, sizeof(*poolNames), vshNameSorter); + /* Check the connection to libvirtd daemon is still working */ + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(list = vshStoragePoolListCollect(ctl, flags))) + goto cleanup; + + poolInfoTexts = vshCalloc(ctl, list->npools, sizeof(*poolInfoTexts)); /* Collect the storage pool information for display */ - for (i = 0; i < numAllPools; i++) { + for (i = 0; i < list->npools; i++) { int autostart = 0, persistent = 0; - /* Retrieve a pool object, looking it up by name */ - virStoragePoolPtr pool = virStoragePoolLookupByName(ctl->conn, - poolNames[i]); - if (!pool) { - VIR_FREE(poolNames[i]); - continue; - } - /* Retrieve the autostart status of the pool */ - if (virStoragePoolGetAutostart(pool, &autostart) < 0) + if (virStoragePoolGetAutostart(list->pools[i], &autostart) < 0) poolInfoTexts[i].autostart = vshStrdup(ctl, _("no autostart")); else poolInfoTexts[i].autostart = vshStrdup(ctl, autostart ? @@ -10991,7 +11240,7 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) /* Retrieve the persistence status of the pool */ if (details) { - persistent = virStoragePoolIsPersistent(pool); + persistent = virStoragePoolIsPersistent(list->pools[i]); vshDebug(ctl, VSH_ERR_DEBUG, "Persistent flag value: %d\n", persistent); if (persistent < 0) @@ -11007,7 +11256,7 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) } /* Collect further extended information about the pool */ - if (virStoragePoolGetInfo(pool, &info) != 0) { + if (virStoragePoolGetInfo(list->pools[i], &info) != 0) { /* Something went wrong retrieving pool info, cope with it */ vshError(ctl, "%s", _("Could not retrieve pool information")); poolInfoTexts[i].state = vshStrdup(ctl, _("unknown")); @@ -11049,28 +11298,25 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) val = prettyCapacity(info.capacity, &unit); ret = virAsprintf(&poolInfoTexts[i].capacity, "%.2lf %s", val, unit); - if (ret < 0) { + if (ret < 0) /* An error occurred creating the string, return */ goto asprintf_failure; - } /* Create the allocation output string */ val = prettyCapacity(info.allocation, &unit); ret = virAsprintf(&poolInfoTexts[i].allocation, "%.2lf %s", val, unit); - if (ret < 0) { + if (ret < 0) /* An error occurred creating the string, return */ goto asprintf_failure; - } /* Create the available space output string */ val = prettyCapacity(info.available, &unit); ret = virAsprintf(&poolInfoTexts[i].available, "%.2lf %s", val, unit); - if (ret < 0) { + if (ret < 0) /* An error occurred creating the string, return */ goto asprintf_failure; - } } else { /* Capacity related information isn't available */ poolInfoTexts[i].capacity = vshStrdup(ctl, _("-")); @@ -11094,16 +11340,16 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) availStrLength = stringLength; } else { /* --details option was not specified, only active/inactive - * state strings are used */ - if (info.state == VIR_STORAGE_POOL_INACTIVE) - poolInfoTexts[i].state = vshStrdup(ctl, _("inactive")); - else + * state strings are used */ + if (virStoragePoolIsActive(list->pools[i])) poolInfoTexts[i].state = vshStrdup(ctl, _("active")); - } + else + poolInfoTexts[i].state = vshStrdup(ctl, _("inactive")); + } } /* Keep the length of name string if longest so far */ - stringLength = strlen(poolNames[i]); + stringLength = strlen(virStoragePoolGetName(list->pools[i])); if (stringLength > nameStrLength) nameStrLength = stringLength; @@ -11116,9 +11362,6 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) stringLength = strlen(poolInfoTexts[i].autostart); if (stringLength > autostartStrLength) autostartStrLength = stringLength; - - /* Free the pool object */ - virStoragePoolFree(pool); } /* If the --details option wasn't selected, we output the pool @@ -11134,9 +11377,10 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) vshPrintExtra(ctl, "-----------------------------------------\n"); /* Output old style pool info */ - for (i = 0; i < numAllPools; i++) { + for (i = 0; i < list->npools; i++) { + const char *name = virStoragePoolGetName(list->pools[i]); vshPrint(ctl, "%-20s %-10s %-10s\n", - poolNames[i], + name, poolInfoTexts[i].state, poolInfoTexts[i].autostart); } @@ -11228,9 +11472,9 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) vshPrintExtra(ctl, "\n"); /* Display the pool info rows */ - for (i = 0; i < numAllPools; i++) { + for (i = 0; i < list->npools; i++) { vshPrint(ctl, outputStr, - poolNames[i], + virStoragePoolGetName(list->pools[i]), poolInfoTexts[i].state, poolInfoTexts[i].autostart, poolInfoTexts[i].persistent, @@ -11244,7 +11488,6 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) goto cleanup; asprintf_failure: - /* Display an appropriate error message then cleanup and return */ switch (errno) { case ENOMEM: @@ -11258,24 +11501,19 @@ asprintf_failure: functionReturn = false; cleanup: - - /* Safely free the memory allocated in this function */ - for (i = 0; i < numAllPools; i++) { - /* Cleanup the memory for one pool info structure */ - VIR_FREE(poolInfoTexts[i].state); - VIR_FREE(poolInfoTexts[i].autostart); - VIR_FREE(poolInfoTexts[i].persistent); - VIR_FREE(poolInfoTexts[i].capacity); - VIR_FREE(poolInfoTexts[i].allocation); - VIR_FREE(poolInfoTexts[i].available); - VIR_FREE(poolNames[i]); - } - - /* Cleanup the memory for the initial arrays*/ + if (list && list->npools) { + for (i = 0; i < list->npools; i++) { + VIR_FREE(poolInfoTexts[i].state); + VIR_FREE(poolInfoTexts[i].autostart); + VIR_FREE(poolInfoTexts[i].persistent); + VIR_FREE(poolInfoTexts[i].capacity); + VIR_FREE(poolInfoTexts[i].allocation); + VIR_FREE(poolInfoTexts[i].available); + } + } VIR_FREE(poolInfoTexts); - VIR_FREE(poolNames); - /* Return the desired value */ + vshStoragePoolListFree(list); return functionReturn; } diff --git a/tools/virsh.pod b/tools/virsh.pod index f79c945..b88df9c 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -2154,13 +2154,33 @@ variables, and defaults to C<vi>. Returns basic information about the I<pool> object. -=item B<pool-list> [I<--inactive> | I<--all>] [I<--details>] +=item B<pool-list> [I<--inactive>] [I<--all>] + [I<--persistent>] [I<--transient>] + [I<--autostart>] [I<--no-autostart>] + [[I<--details>] [<type>] List pool objects known to libvirt. By default, only active pools are listed; I<--inactive> lists just the inactive pools, and I<--all> -lists all pools. The I<--details> option instructs virsh to additionally +lists all pools. + +Except the default, I<--inactive>, and I<--all>, you may want to specify more +filtering flags. I<--persistent> is to list the persistent pools, I<--transient> +is to list the transient pools. I<--autostart> is to list the autostarting pools, +I<--no-autostart> is to list the pools with autostarting disabled. + +You may also want to list pools with specified types using I<type>, the +pool types must be separated by comma, e.g. --type dir,disk. The valid pool +types include 'dir', 'fs', 'netfs', 'logical', 'disk', 'iscsi', 'scsi', +'mpath', 'rbd', and 'sheepdog'. + +The I<--details> option instructs virsh to additionally display pool persistence and capacity related information where available. +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<pool-name> I<uuid> Convert the I<uuid> to a pool name. -- 1.7.7.3

--- tools/virsh.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index ab64918..7d7c9ca 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -18344,7 +18344,7 @@ cmdQemuMonitorCommand(vshControl *ctl, const vshCmd *cmd) if (virDomainQemuMonitorCommand(dom, monitor_cmd, &result, flags) < 0) goto cleanup; - printf("%s\n", result); + vshPrint(ctl, "%s\n", result); ret = true; -- 1.7.7.3

The implementation is done manually as the generator does not support wrapping lists of C pointers into Python objects. python/libvirt-override-api.xml: Document python/libvirt-override-virConnect.py: Add listAllStoragePools python/libvirt-override.c: Implementation for the wrapper. --- python/libvirt-override-api.xml | 6 ++++ python/libvirt-override-virConnect.py | 12 ++++++++ python/libvirt-override.c | 47 +++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 0 deletions(-) diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index 67ef36e..d16755c 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -306,6 +306,12 @@ <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> <return type='str *' info='the list of Names of None in case of error'/> </function> + <function name='virConnectListAllStoragePools' file='python'> + <info>returns list of all storage pools</info> + <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> + <arg name='flags' type='unsigned int' info='optional flags'/> + <return type='pool *' info='the list of pools or None in case of error'/> + </function> <function name='virStoragePoolListVolumes' file='python'> <info>list the storage volumes, stores the pointers to the names in @names</info> <arg name='pool' type='virStoragePoolPtr' info='pointer to the storage pool'/> diff --git a/python/libvirt-override-virConnect.py b/python/libvirt-override-virConnect.py index 50177ab..87a737f 100644 --- a/python/libvirt-override-virConnect.py +++ b/python/libvirt-override-virConnect.py @@ -206,3 +206,15 @@ retlist.append(virDomain(self, _obj=domptr)) return retlist + + def listAllStoragePools(self, flags): + """Returns a list of storage pool objects""" + ret = libvirtmod.virConnectListAllStoragePools(self._o, flags) + if ret is None: + raise libvirtError("virConnectListAllStoragePools() failed", conn=self) + + retlist = list() + for poolptr in ret: + retlist.append(virStoragePool(self, _obj=poolptr)) + + return retlist diff --git a/python/libvirt-override.c b/python/libvirt-override.c index 8b41dff..0b1d509 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -2983,6 +2983,52 @@ libvirt_virConnectListDefinedStoragePools(PyObject *self ATTRIBUTE_UNUSED, return py_retval; } +static PyObject * +libvirt_virConnectListAllStoragePools(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + PyObject *pyobj_conn; + PyObject *py_retval = NULL; + PyObject *tmp = NULL; + virConnectPtr conn; + virStoragePoolPtr *pools = NULL; + int c_retval = 0; + int i; + unsigned int flags; + + if (!PyArg_ParseTuple(args, (char *)"Oi:virConnectListAllStoragePools", + &pyobj_conn, &flags)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virConnectListAllStoragePools(conn, &pools, flags); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) + return VIR_PY_NONE; + + if (!(py_retval = PyList_New(c_retval))) + goto cleanup; + + for (i = 0; i < c_retval; i++) { + if (!(tmp = libvirt_virStoragePoolPtrWrap(pools[i])) || + PyList_SetItem(py_retval, i, tmp) < 0) { + Py_XDECREF(tmp); + Py_DECREF(py_retval); + py_retval = NULL; + goto cleanup; + } + /* python steals the pointer */ + pools[i] = NULL; + } + +cleanup: + for (i = 0; i < c_retval; i++) + if (pools[i]) + virStoragePoolFree(pools[i]); + VIR_FREE(pools); + return py_retval; +} static PyObject * libvirt_virStoragePoolListVolumes(PyObject *self ATTRIBUTE_UNUSED, @@ -5874,6 +5920,7 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virDomainGetVcpuPinInfo", libvirt_virDomainGetVcpuPinInfo, METH_VARARGS, NULL}, {(char *) "virConnectListStoragePools", libvirt_virConnectListStoragePools, METH_VARARGS, NULL}, {(char *) "virConnectListDefinedStoragePools", libvirt_virConnectListDefinedStoragePools, METH_VARARGS, NULL}, + {(char *) "virConnectListAllStoragePools", libvirt_virConnectListAllStoragePools, METH_VARARGS, NULL}, {(char *) "virStoragePoolGetAutostart", libvirt_virStoragePoolGetAutostart, METH_VARARGS, NULL}, {(char *) "virStoragePoolListVolumes", libvirt_virStoragePoolListVolumes, METH_VARARGS, NULL}, {(char *) "virStoragePoolGetInfo", libvirt_virStoragePoolGetInfo, METH_VARARGS, NULL}, -- 1.7.7.3

Simply returns the storage volume objects. No supported filter flags. include/libvirt/libvirt.h.in: Declare the API python/generator.py: Skip the function for generating. virStoragePool.py will be added in later patch. src/driver.h: virDrvStoragePoolListVolumesFlags src/libvirt.c: Implementation for the API. src/libvirt_public.syms: Export the symbol to public --- include/libvirt/libvirt.h.in | 3 ++ python/generator.py | 1 + src/driver.h | 6 ++++- src/libvirt.c | 50 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 5 files changed, 60 insertions(+), 1 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index c7e810e..c5b16bf 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2570,6 +2570,9 @@ int virStoragePoolNumOfVolumes (virStoragePoolPtr pool) int virStoragePoolListVolumes (virStoragePoolPtr pool, char **const names, int maxnames); +int virStoragePoolListAllVolumes (virStoragePoolPtr pool, + virStorageVolPtr **vols, + unsigned int flags); virConnectPtr virStorageVolGetConnect (virStorageVolPtr vol); diff --git a/python/generator.py b/python/generator.py index 5934040..4b3f7e6 100755 --- a/python/generator.py +++ b/python/generator.py @@ -457,6 +457,7 @@ skip_function = ( 'virDomainListAllSnapshots', # overridden in virDomain.py 'virDomainSnapshotListAllChildren', # overridden in virDomainSnapshot.py 'virConnectListAllStoragePools', # overridden in virConnect.py + 'virStoragePoolListAllVolumes', # overridden in virStoragePool.py 'virStreamRecvAll', # Pure python libvirt-override-virStream.py 'virStreamSendAll', # Pure python libvirt-override-virStream.py diff --git a/src/driver.h b/src/driver.h index 7e3e8a1..ee1341f 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1284,7 +1284,10 @@ typedef int (*virDrvStoragePoolListVolumes) (virStoragePoolPtr pool, char **const names, int maxnames); - +typedef int + (*virDrvStoragePoolListAllVolumes) (virStoragePoolPtr pool, + virStorageVolPtr **vols, + unsigned int flags); typedef virStorageVolPtr (*virDrvStorageVolLookupByName) (virStoragePoolPtr pool, @@ -1392,6 +1395,7 @@ struct _virStorageDriver { virDrvStoragePoolSetAutostart poolSetAutostart; virDrvStoragePoolNumOfVolumes poolNumOfVolumes; virDrvStoragePoolListVolumes poolListVolumes; + virDrvStoragePoolListAllVolumes poolListAllVolumes; virDrvStorageVolLookupByName volLookupByName; virDrvStorageVolLookupByKey volLookupByKey; diff --git a/src/libvirt.c b/src/libvirt.c index 541b1c3..7780534 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -12385,6 +12385,54 @@ error: return -1; } +/** + * virStoragePoolListAllVolumes: + * @pool: Pointer to storage pool + * @vols: Pointer to a variable to store the array containing storage volume + * objects or NULL if the list is not required (just returns number + * of volumes). + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Collect the list of storage volumes, and allocate an array to store those + * objects. + * + * Returns the number of storage volumes found or -1 and sets @vols to + * NULL in case of error. On success, the array stored into @vols is + * guaranteed to have an extra allocated element set to NULL but not included + * in the return count, to make iteration easier. The caller is responsible + * for calling virStorageVolFree() on each array element, then calling + * free() on @vols. + */ +int +virStoragePoolListAllVolumes(virStoragePoolPtr pool, + virStorageVolPtr **vols, + unsigned int flags) +{ + VIR_DEBUG("pool=%p, vols=%p, flags=%x", pool, vols, flags); + + virResetLastError(); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibConnError(VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (pool->conn->storageDriver && + pool->conn->storageDriver->poolListAllVolumes) { + int ret; + ret = pool->conn->storageDriver->poolListAllVolumes(pool, vols, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(pool->conn); + return -1; +} /** * virStoragePoolNumOfVolumes: @@ -12432,6 +12480,8 @@ error: * Fetch list of storage volume names, limiting to * at most maxnames. * + * To list the volume objects directly, see virStoragePoolListAllVolumes(). + * * Returns the number of names fetched, or -1 on error */ int diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 693a390..ea052ed 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -547,6 +547,7 @@ LIBVIRT_0.9.13 { LIBVIRT_0.9.14 { global: virConnectListAllStoragePools; + virStoragePoolListAllVolumes; } LIBVIRT_0.9.13; # .... define new API here using predicted next version number .... -- 1.7.7.3

The RPC generator doesn't returning support list of object, this patch do the work manually. * daemon/remote.c: Implemente the server side handler remoteDispatchStoragePoolListAllVolumes * src/remote/remote_driver.c: Add remote driver handler remoteStoragePoolListAllVolumes * src/remote/remote_protocol.x: New RPC procedure REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES and structs to represent the args and ret for it. * src/remote_protocol-structs: Likewise. --- daemon/remote.c | 58 ++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 66 ++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 12 +++++++- src/remote_protocol-structs | 13 ++++++++ 4 files changed, 148 insertions(+), 1 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 060c5a0..c1e30c0 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -4006,6 +4006,64 @@ cleanup: return rv; } +static int +remoteDispatchStoragePoolListAllVolumes(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_storage_pool_list_all_volumes_args *args, + remote_storage_pool_list_all_volumes_ret *ret) +{ + virStorageVolPtr *vols = NULL; + virStoragePoolPtr pool = NULL; + int nvols = 0; + int i; + int rv = -1; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if (!(pool = get_nonnull_storage_pool(priv->conn, args->pool))) + goto cleanup; + + if ((nvols = virStoragePoolListAllVolumes(pool, + args->need_results ? &vols : NULL, + args->flags)) < 0) + goto cleanup; + + if (vols && nvols) { + if (VIR_ALLOC_N(ret->vols.vols_val, nvols) < 0) { + virReportOOMError(); + goto cleanup; + } + + ret->vols.vols_len = nvols; + + for (i = 0; i < nvols; i++) + make_nonnull_storage_vol(ret->vols.vols_val + i, vols[i]); + } else { + ret->vols.vols_len = 0; + ret->vols.vols_val = NULL; + } + + ret->ret = nvols; + + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (vols) { + for (i = 0; i < nvols; i++) + virStorageVolFree(vols[i]); + VIR_FREE(vols); + } + return rv; +} + /*----- Helpers. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index ab821d5..179e7af 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -2715,6 +2715,71 @@ done: return rv; } +static int +remoteStoragePoolListAllVolumes(virStoragePoolPtr pool, + virStorageVolPtr **vols, + unsigned int flags) +{ + int rv = -1; + int i; + virStorageVolPtr *tmp_vols = NULL; + remote_storage_pool_list_all_volumes_args args; + remote_storage_pool_list_all_volumes_ret ret; + + struct private_data *priv = pool->conn->privateData; + + remoteDriverLock(priv); + + make_nonnull_storage_pool(&args.pool, pool); + args.need_results = !!vols; + args.flags = flags; + + memset(&ret, 0, sizeof(ret)); + if (call(pool->conn, + priv, + 0, + REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES, + (xdrproc_t) xdr_remote_storage_pool_list_all_volumes_args, + (char *) &args, + (xdrproc_t) xdr_remote_storage_pool_list_all_volumes_ret, + (char *) &ret) == -1) + goto done; + + if (vols) { + if (VIR_ALLOC_N(tmp_vols, ret.vols.vols_len + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + for (i = 0; i < ret.vols.vols_len; i++) { + tmp_vols[i] = get_nonnull_storage_vol(pool->conn, ret.vols.vols_val[i]); + if (!tmp_vols[i]) { + virReportOOMError(); + goto cleanup; + } + } + *vols = tmp_vols; + tmp_vols = NULL; + } + + rv = ret.ret; + +cleanup: + if (tmp_vols) { + for (i = 0; i < ret.vols.vols_len; i++) + if (tmp_vols[i]) + virStorageVolFree(tmp_vols[i]); + VIR_FREE(tmp_vols); + } + + xdr_free((xdrproc_t) xdr_remote_storage_pool_list_all_volumes_ret, (char *) &ret); + +done: + remoteDriverUnlock(priv); + return rv; +} + + /*----------------------------------------------------------------------*/ static virDrvOpenStatus ATTRIBUTE_NONNULL (1) @@ -5483,6 +5548,7 @@ static virStorageDriver storage_driver = { .poolSetAutostart = remoteStoragePoolSetAutostart, /* 0.4.1 */ .poolNumOfVolumes = remoteStoragePoolNumOfVolumes, /* 0.4.1 */ .poolListVolumes = remoteStoragePoolListVolumes, /* 0.4.1 */ + .poolListAllVolumes = remoteStoragePoolListAllVolumes, /* 0.9.14 */ .volLookupByName = remoteStorageVolLookupByName, /* 0.4.1 */ .volLookupByKey = remoteStorageVolLookupByKey, /* 0.4.1 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index dfd67bc..d090705 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1655,7 +1655,16 @@ struct remote_storage_pool_list_volumes_ret { remote_nonnull_string names<REMOTE_STORAGE_VOL_NAME_LIST_MAX>; /* insert@1 */ }; +struct remote_storage_pool_list_all_volumes_args { + remote_nonnull_storage_pool pool; + int need_results; + unsigned int flags; +}; +struct remote_storage_pool_list_all_volumes_ret { + remote_nonnull_storage_vol vols<>; + unsigned int ret; +}; /* Storage vol calls: */ @@ -2854,7 +2863,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_LIST_ALL_SNAPSHOTS = 274, /* skipgen skipgen priority:high */ REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_ALL_CHILDREN = 275, /* skipgen skipgen priority:high */ REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE = 276, /* autogen autogen */ - REMOTE_PROC_CONNECT_LIST_ALL_STORAGE_POOLS = 277 /* skipgen skipgen priority:high */ + REMOTE_PROC_CONNECT_LIST_ALL_STORAGE_POOLS = 277, /* skipgen skipgen priority:high */ + REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES = 278 /* skipgen skipgen priority:high */ /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 25cb819..9d81ad0 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1985,6 +1985,18 @@ struct remote_connect_list_all_storage_pools_ret { } pools; u_int ret; }; +struct remote_storage_pool_list_all_volumes_args { + remote_nonnull_storage_pool pool; + int need_results; + u_int flags; +}; +struct remote_storage_pool_list_all_volumes_ret { + struct { + u_int vols_len; + remote_nonnull_storage_vol * vols_val; + } vols; + u_int ret; +}; enum remote_procedure { REMOTE_PROC_OPEN = 1, REMOTE_PROC_CLOSE = 2, @@ -2263,4 +2275,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_ALL_CHILDREN = 275, REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE = 276, REMOTE_PROC_CONNECT_LIST_ALL_STORAGE_POOLS = 277, + REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES = 278, }; -- 1.7.7.3

src/storage/storage_driver.c: Implement poolListAllVolumes. --- src/storage/storage_driver.c | 67 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 67 insertions(+), 0 deletions(-) diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index 0974879..c630c2e 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -1154,6 +1154,72 @@ storagePoolListVolumes(virStoragePoolPtr obj, return -1; } +static int +storagePoolListAllVolumes(virStoragePoolPtr pool, + virStorageVolPtr **vols, + unsigned int flags) { + virStorageDriverStatePtr driver = pool->conn->storagePrivateData; + virStoragePoolObjPtr obj; + int i; + virStorageVolPtr *tmp_vols = NULL; + virStorageVolPtr vol = NULL; + int nvols = 0; + int ret = -1; + + virCheckFlags(0, -1); + + storageDriverLock(driver); + obj = virStoragePoolObjFindByUUID(&driver->pools, pool->uuid); + storageDriverUnlock(driver); + + if (!obj) { + virReportError(VIR_ERR_NO_STORAGE_POOL, "%s", + _("no storage pool with matching uuid")); + goto cleanup; + } + + if (!virStoragePoolObjIsActive(obj)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("storage pool is not active")); + goto cleanup; + } + + /* Just returns the volumes count */ + if (!vols) { + ret = obj->volumes.count; + goto cleanup; + } + + if (VIR_ALLOC_N(tmp_vols, obj->volumes.count + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + for (i = 0 ; i < obj->volumes.count; i++) { + if (!(vol = virGetStorageVol(pool->conn, obj->def->name, + obj->volumes.objs[i]->name, + obj->volumes.objs[i]->key))) + goto cleanup; + tmp_vols[nvols++] = vol; + } + + *vols = tmp_vols; + tmp_vols = NULL; + ret = nvols; + + cleanup: + if (tmp_vols) { + for (i = 0; i < obj->volumes.count; i++) { + if (tmp_vols[i]) + virStorageVolFree(tmp_vols[i]); + } + } + + if (obj) + virStoragePoolObjUnlock(obj); + + return ret; +} static virStorageVolPtr storageVolumeLookupByName(virStoragePoolPtr obj, @@ -2332,6 +2398,7 @@ static virStorageDriver storageDriver = { .poolSetAutostart = storagePoolSetAutostart, /* 0.4.0 */ .poolNumOfVolumes = storagePoolNumVolumes, /* 0.4.0 */ .poolListVolumes = storagePoolListVolumes, /* 0.4.0 */ + .poolListAllVolumes = storagePoolListAllVolumes, /* 0.9.14 */ .volLookupByName = storageVolumeLookupByName, /* 0.4.0 */ .volLookupByKey = storageVolumeLookupByKey, /* 0.4.0 */ -- 1.7.7.3

src/test/test_driver.c: Implement poolListAllVolumes. --- src/test/test_driver.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 67 insertions(+), 0 deletions(-) diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 21164ca..9b528f2 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -4553,6 +4553,72 @@ testStoragePoolListVolumes(virStoragePoolPtr pool, return -1; } +static int +testStoragePoolListAllVolumes(virStoragePoolPtr obj, + virStorageVolPtr **vols, + unsigned int flags) { + testConnPtr privconn = obj->conn->privateData; + virStoragePoolObjPtr pool; + int i; + virStorageVolPtr *tmp_vols = NULL; + virStorageVolPtr vol = NULL; + int nvols = 0; + int ret = -1; + + virCheckFlags(0, -1); + + testDriverLock(privconn); + pool = virStoragePoolObjFindByUUID(&privconn->pools, obj->uuid); + testDriverUnlock(privconn); + + if (!pool) { + testError(VIR_ERR_NO_STORAGE_POOL, "%s", + _("no storage pool with matching uuid")); + goto cleanup; + } + + if (!virStoragePoolObjIsActive(pool)) { + testError(VIR_ERR_OPERATION_INVALID, "%s", + _("storage pool is not active")); + goto cleanup; + } + + /* Just returns the volumes count */ + if (!vols) { + ret = pool->volumes.count; + goto cleanup; + } + + if (VIR_ALLOC_N(tmp_vols, pool->volumes.count + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + for (i = 0 ; i < pool->volumes.count; i++) { + if (!(vol = virGetStorageVol(obj->conn, pool->def->name, + pool->volumes.objs[i]->name, + pool->volumes.objs[i]->key))) + goto cleanup; + tmp_vols[nvols++] = vol; + } + + *vols = tmp_vols; + tmp_vols = NULL; + ret = nvols; + + cleanup: + if (tmp_vols) { + for (i = 0; i < pool->volumes.count; i++) { + if (tmp_vols[i]) + virStorageVolFree(tmp_vols[i]); + } + } + + if (pool) + virStoragePoolObjUnlock(pool); + + return ret; +} static virStorageVolPtr testStorageVolumeLookupByName(virStoragePoolPtr pool, @@ -5695,6 +5761,7 @@ static virStorageDriver testStorageDriver = { .poolSetAutostart = testStoragePoolSetAutostart, /* 0.5.0 */ .poolNumOfVolumes = testStoragePoolNumVolumes, /* 0.5.0 */ .poolListVolumes = testStoragePoolListVolumes, /* 0.5.0 */ + .poolListAllVolumes = testStoragePoolListAllVolumes, /* 0.9.14 */ .volLookupByName = testStorageVolumeLookupByName, /* 0.5.0 */ .volLookupByKey = testStorageVolumeLookupByKey, /* 0.5.0 */ -- 1.7.7.3

tools/virsh.c: * vshStorageVolSorter to sort storage vols by name * vshStorageVolumeListFree to free the volume objects list * vshStorageVolumeListCollect to collect the volume objects, trying to use new API first, fall back to older APIs if it's not supported. --- tools/virsh.c | 197 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 files changed, 150 insertions(+), 47 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 7d7c9ca..9556e16 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -12793,6 +12793,133 @@ cmdVolDumpXML(vshControl *ctl, const vshCmd *cmd) return ret; } +static int +vshStorageVolSorter(const void *a, const void *b) +{ + virStorageVolPtr *va = (virStorageVolPtr *) a; + virStorageVolPtr *vb = (virStorageVolPtr *) b; + + if (*va && !*vb) + return -1; + + if (!*va) + return *vb != NULL; + + return strcasecmp(virStorageVolGetName(*va), + virStorageVolGetName(*vb)); +} + +struct vshStorageVolList { + virStorageVolPtr *vols; + size_t nvols; +}; +typedef struct vshStorageVolList *vshStorageVolListPtr; + +static void +vshStorageVolListFree(vshStorageVolListPtr list) +{ + int i; + + if (list && list->vols) { + for (i = 0; i < list->nvols; i++) { + if (list->vols[i]) + virStorageVolFree(list->vols[i]); + } + VIR_FREE(list->vols); + } + VIR_FREE(list); +} + +static vshStorageVolListPtr +vshStorageVolListCollect(vshControl *ctl, + virStoragePoolPtr pool, + unsigned int flags) +{ + vshStorageVolListPtr list = vshMalloc(ctl, sizeof(*list)); + int i; + char **names = NULL; + virStorageVolPtr vol = NULL; + bool success = false; + size_t deleted = 0; + int nvols = 0; + int ret = -1; + + /* try the list with flags support (0.9.14 and later) */ + if ((ret = virStoragePoolListAllVolumes(pool, + &list->vols, + flags)) >= 0) { + list->nvols = ret; + goto finished; + } + + /* check if the command is actually supported */ + if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) { + virFreeError(last_error); + last_error = NULL; + goto fallback; + } + + /* there was an error during the call */ + vshError(ctl, "%s", _("Failed to list volumes")); + goto cleanup; + +fallback: + /* fall back to old method (0.9.13 and older) */ + virResetLastError(); + + /* Determine the number of volumes in the pool */ + if ((nvols = virStoragePoolNumOfVolumes(pool)) < 0) { + vshError(ctl, "%s", _("Failed to list storage volumes")); + goto cleanup; + } + + if (nvols == 0) { + success = true; + return list; + } + + /* Retrieve the list of volume names in the pool */ + names = vshCalloc(ctl, nvols, sizeof(*names)); + if ((nvols = virStoragePoolListVolumes(pool, names, nvols)) < 0) { + vshError(ctl, "%s", _("Failed to list storage volumes")); + goto cleanup; + } + + list->vols = vshMalloc(ctl, sizeof(virStorageVolPtr) * (nvols)); + list->nvols = 0; + + /* get the vols */ + for (i = 0; i < nvols; i++) { + if (!(vol = virStorageVolLookupByName(pool, names[i]))) + continue; + list->vols[list->nvols++] = vol; + } + + /* truncate the list for not found vols */ + deleted = nvols - list->nvols; + +finished: + /* sort the list */ + if (list->vols && list->nvols) + qsort(list->vols, list->nvols, sizeof(*list->vols), vshStorageVolSorter); + + if (deleted) + VIR_SHRINK_N(list->vols, list->nvols, deleted); + + success = true; + +cleanup: + for (i = 0; i < nvols; i++) + VIR_FREE(names[i]); + VIR_FREE(names); + + if (!success) { + vshStorageVolListFree(list); + list = NULL; + } + + return list; +} /* * "vol-list" command @@ -12814,14 +12941,13 @@ cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) { virStorageVolInfo volumeInfo; virStoragePoolPtr pool; - char **activeNames = NULL; char *outputStr = NULL; const char *unit; double val; bool details = vshCommandOptBool(cmd, "details"); - int numVolumes = 0, i; + int i; int ret; - bool functionReturn; + bool functionReturn = false; int stringLength = 0; size_t allocStrLength = 0, capStrLength = 0; size_t nameStrLength = 0, pathStrLength = 0; @@ -12833,6 +12959,7 @@ cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) char *type; }; struct volInfoText *volInfoTexts = NULL; + vshStorageVolListPtr list = NULL; /* Check the connection to libvirtd daemon is still working */ if (!vshConnectionUsability(ctl, ctl->conn)) @@ -12842,38 +12969,16 @@ cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) return false; - /* Determine the number of volumes in the pool */ - numVolumes = virStoragePoolNumOfVolumes(pool); - - if (numVolumes < 0) { - vshError(ctl, "%s", _("Failed to list storage volumes")); - virStoragePoolFree(pool); - return false; - } - - /* Retrieve the list of volume names in the pool */ - if (numVolumes > 0) { - activeNames = vshCalloc(ctl, numVolumes, sizeof(*activeNames)); - if ((numVolumes = virStoragePoolListVolumes(pool, activeNames, - numVolumes)) < 0) { - vshError(ctl, "%s", _("Failed to list active vols")); - VIR_FREE(activeNames); - virStoragePoolFree(pool); - return false; - } - - /* Sort the volume names */ - qsort(&activeNames[0], numVolumes, sizeof(*activeNames), vshNameSorter); + if (!(list = vshStorageVolListCollect(ctl, pool, 0))) + goto cleanup; - /* Set aside memory for volume information pointers */ - volInfoTexts = vshCalloc(ctl, numVolumes, sizeof(*volInfoTexts)); - } + if (list->nvols > 0) + volInfoTexts = vshCalloc(ctl, list->nvols, sizeof(*volInfoTexts)); /* Collect the rest of the volume information for display */ - for (i = 0; i < numVolumes; i++) { + for (i = 0; i < list->nvols; i++) { /* Retrieve volume info */ - virStorageVolPtr vol = virStorageVolLookupByName(pool, - activeNames[i]); + virStorageVolPtr vol = list->vols[i]; /* Retrieve the volume path */ if ((volInfoTexts[i].path = virStorageVolGetPath(vol)) == NULL) { @@ -12931,7 +13036,7 @@ cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) */ /* Keep the length of name string if longest so far */ - stringLength = strlen(activeNames[i]); + stringLength = strlen(virStorageVolGetName(list->vols[i])); if (stringLength > nameStrLength) nameStrLength = stringLength; @@ -12955,9 +13060,6 @@ cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) if (stringLength > allocStrLength) allocStrLength = stringLength; } - - /* Cleanup memory allocation */ - virStorageVolFree(vol); } /* If the --details option wasn't selected, we output the volume @@ -12970,8 +13072,8 @@ cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) /* The old output format */ vshPrintExtra(ctl, "%-20s %-40s\n", _("Name"), _("Path")); vshPrintExtra(ctl, "-----------------------------------------\n"); - for (i = 0; i < numVolumes; i++) { - vshPrint(ctl, "%-20s %-40s\n", activeNames[i], + for (i = 0; i < list->nvols; i++) { + vshPrint(ctl, "%-20s %-40s\n", virStorageVolGetName(list->vols[i]), volInfoTexts[i].path); } @@ -13042,9 +13144,9 @@ cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) vshPrintExtra(ctl, "\n"); /* Display the volume info rows */ - for (i = 0; i < numVolumes; i++) { + for (i = 0; i < list->nvols; i++) { vshPrint(ctl, outputStr, - activeNames[i], + virStorageVolGetName(list->vols[i]), volInfoTexts[i].path, volInfoTexts[i].type, volInfoTexts[i].capacity, @@ -13072,20 +13174,21 @@ asprintf_failure: cleanup: /* Safely free the memory allocated in this function */ - for (i = 0; i < numVolumes; i++) { - /* Cleanup the memory for one volume info structure per loop */ - VIR_FREE(volInfoTexts[i].path); - VIR_FREE(volInfoTexts[i].type); - VIR_FREE(volInfoTexts[i].capacity); - VIR_FREE(volInfoTexts[i].allocation); - VIR_FREE(activeNames[i]); + if (list && list->nvols) { + for (i = 0; i < list->nvols; i++) { + /* Cleanup the memory for one volume info structure per loop */ + VIR_FREE(volInfoTexts[i].path); + VIR_FREE(volInfoTexts[i].type); + VIR_FREE(volInfoTexts[i].capacity); + VIR_FREE(volInfoTexts[i].allocation); + } } /* Cleanup remaining memory */ VIR_FREE(outputStr); VIR_FREE(volInfoTexts); - VIR_FREE(activeNames); virStoragePoolFree(pool); + vshStorageVolListFree(list); /* Return the desired value */ return functionReturn; -- 1.7.7.3

The implementation is done manually as the generator does not support wrapping lists of C pointers into Python objects. python/libvirt-override-api.xml: Document python/libvirt-override-virStoragePool.py: * New file, includes implementation of listAllVolumes. python/libvirt-override.c: Implementation for the wrapper. --- python/libvirt-override-api.xml | 8 ++++- python/libvirt-override-virStoragePool.py | 11 ++++++ python/libvirt-override.c | 50 +++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletions(-) create mode 100644 python/libvirt-override-virStoragePool.py diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index d16755c..8a228fb 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -315,7 +315,13 @@ <function name='virStoragePoolListVolumes' file='python'> <info>list the storage volumes, stores the pointers to the names in @names</info> <arg name='pool' type='virStoragePoolPtr' info='pointer to the storage pool'/> - <return type='str *' info='the list of Names of None in case of error'/> + <return type='str *' info='the list of Names or None in case of error'/> + </function> + <function name='virStoragePoolListAllVolumes' file='python'> + <info>return list of storage volume objects</info> + <arg name='pool' type='virStoragePoolPtr' info='pointer to the storage pool'/> + <arg name='flags' type='unsigned int' info='optional flags'/> + <return type='volume *' info='the list of volumes or None in case of error'/> </function> <function name='virStoragePoolGetInfo' file='python'> <info>Extract information about a storage pool. Note that if the connection used to get the domain is limited only a partial set of the information can be extracted.</info> diff --git a/python/libvirt-override-virStoragePool.py b/python/libvirt-override-virStoragePool.py new file mode 100644 index 0000000..ffe160c --- /dev/null +++ b/python/libvirt-override-virStoragePool.py @@ -0,0 +1,11 @@ + def listAllVolumes(self, flags): + """List all storage volumes and returns a list of storage volume objects""" + ret = libvirtmod.virStoragePoolListAllVolumes(self._o, flags) + if ret is None: + raise libvirtError("virStoragePoolListAllVolumes() failed", conn=self) + + retlist = list() + for volptr in ret: + retlist.append(virStorageVol(self, _obj=volptr)) + + return retlist diff --git a/python/libvirt-override.c b/python/libvirt-override.c index 0b1d509..322a8d2 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -3083,6 +3083,55 @@ libvirt_virStoragePoolListVolumes(PyObject *self ATTRIBUTE_UNUSED, } static PyObject * +libvirt_virStoragePoolListAllVolumes(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + PyObject *py_retval = NULL; + PyObject *tmp = NULL; + virStoragePoolPtr pool; + virStorageVolPtr *vols = NULL; + int c_retval = 0; + int i; + unsigned int flags; + PyObject *pyobj_pool; + + if (!PyArg_ParseTuple(args, (char *)"Oi:virStoragePoolListAllVolumes", + &pyobj_pool, &flags)) + return NULL; + + pool = (virStoragePoolPtr) PyvirStoragePool_Get(pyobj_pool); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virStoragePoolListAllVolumes(pool, &vols, flags); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) + return VIR_PY_NONE; + + if (!(py_retval = PyList_New(c_retval))) + goto cleanup; + + for (i = 0; i < c_retval; i++) { + if (!(tmp = libvirt_virStorageVolPtrWrap(vols[i])) || + PyList_SetItem(py_retval, i, tmp) < 0) { + Py_XDECREF(tmp); + Py_DECREF(py_retval); + py_retval = NULL; + goto cleanup; + } + /* python steals the pointer */ + vols[i] = NULL; + } + +cleanup: + for (i = 0; i < c_retval; i++) + if (vols[i]) + virStorageVolFree(vols[i]); + VIR_FREE(vols); + return py_retval; +} + + +static PyObject * libvirt_virStoragePoolGetAutostart(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { PyObject *py_retval; int c_retval, autostart; @@ -5923,6 +5972,7 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virConnectListAllStoragePools", libvirt_virConnectListAllStoragePools, METH_VARARGS, NULL}, {(char *) "virStoragePoolGetAutostart", libvirt_virStoragePoolGetAutostart, METH_VARARGS, NULL}, {(char *) "virStoragePoolListVolumes", libvirt_virStoragePoolListVolumes, METH_VARARGS, NULL}, + {(char *) "virStoragePoolListAllVolumes", libvirt_virStoragePoolListAllVolumes, METH_VARARGS, NULL}, {(char *) "virStoragePoolGetInfo", libvirt_virStoragePoolGetInfo, METH_VARARGS, NULL}, {(char *) "virStorageVolGetInfo", libvirt_virStorageVolGetInfo, METH_VARARGS, NULL}, {(char *) "virStoragePoolGetUUID", libvirt_virStoragePoolGetUUID, METH_VARARGS, NULL}, -- 1.7.7.3

This is to list the network objects, supported filtering flags are: active|inactive, persistent|transient, autostart|no-autostart. include/libvirt/libvirt.h.in: Declare enum virConnectListAllNetworkFlags and virConnectListAllNetworks. python/generator.py: Skip auto-generating src/driver.h: (virDrvConnectListAllNetworks) src/libvirt.c: Implement the public API src/libvirt_public.syms: Export the symbol to public --- include/libvirt/libvirt.h.in | 20 ++++++++++++ python/generator.py | 1 + src/driver.h | 5 +++ src/libvirt.c | 68 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 5 files changed, 95 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index c5b16bf..15a9a1b 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2196,6 +2196,26 @@ int virConnectNumOfDefinedNetworks (virConnectPtr conn); int virConnectListDefinedNetworks (virConnectPtr conn, char **const names, int maxnames); +/* + * virConnectListAllNetworks: + * + * Flags used to filter the returned networks. Flags in each group + * are exclusive attributes of a network. + */ +typedef enum { + VIR_CONNECT_LIST_NETWORKS_INACTIVE = 1 << 0, + VIR_CONNECT_LIST_NETWORKS_ACTIVE = 1 << 1, + + VIR_CONNECT_LIST_NETWORKS_PERSISTENT = 1 << 2, + VIR_CONNECT_LIST_NETWORKS_TRANSIENT = 1 << 3, + + VIR_CONNECT_LIST_NETWORKS_AUTOSTART = 1 << 4, + VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART = 1 << 5, +} virConnectListAllNetworksFlags; + +int virConnectListAllNetworks (virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags); /* * Lookup network by name or uuid diff --git a/python/generator.py b/python/generator.py index 4b3f7e6..44b56c2 100755 --- a/python/generator.py +++ b/python/generator.py @@ -458,6 +458,7 @@ skip_function = ( 'virDomainSnapshotListAllChildren', # overridden in virDomainSnapshot.py 'virConnectListAllStoragePools', # overridden in virConnect.py 'virStoragePoolListAllVolumes', # overridden in virStoragePool.py + 'virConnectListAllNetworks', # overridden in virConnect.py 'virStreamRecvAll', # Pure python libvirt-override-virStream.py 'virStreamSendAll', # Pure python libvirt-override-virStream.py diff --git a/src/driver.h b/src/driver.h index ee1341f..68a1f04 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1055,6 +1055,10 @@ typedef int (*virDrvListDefinedNetworks) (virConnectPtr conn, char **const names, int maxnames); +typedef int + (*virDrvListAllNetworks) (virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags); typedef virNetworkPtr (*virDrvNetworkLookupByUUID) (virConnectPtr conn, const unsigned char *uuid); @@ -1113,6 +1117,7 @@ struct _virNetworkDriver { virDrvListNetworks listNetworks; virDrvNumOfDefinedNetworks numOfDefinedNetworks; virDrvListDefinedNetworks listDefinedNetworks; + virDrvListAllNetworks listAllNetworks; virDrvNetworkLookupByUUID networkLookupByUUID; virDrvNetworkLookupByName networkLookupByName; virDrvNetworkCreateXML networkCreateXML; diff --git a/src/libvirt.c b/src/libvirt.c index 7780534..622a590 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -9588,6 +9588,74 @@ virNetworkGetConnect (virNetworkPtr net) } /** + * virConnectListAllNetworks: + * @conn: Pointer to the hypervisor connection. + * @nets: Pointer to a variable to store the array containing the network + * objects or NULL if the list is not required (just returns number + * of networks). + * @flags: bitwise-OR of virConnectListAllNetworksFlags. + * + * Collect the list of networks, and allocate an array to store those + * objects. This API solves the race inherent between virConnectListNetworks + * and virConnectListDefinedNetworks. + * + * By default, this API covers all networks; it is also possible to return + * the filtered objects with flags. Filters are provided in groups, where each + * group contains bits that describe mutually exclusive attributes of a network. + * + * The first group of @flags is VIR_CONNECT_LIST_NETWORKS_INACTIVE and + * VIR_CONNECT_LIST_NETWORKS_INACTIVE to fitler the networks by state. + * + * The second group of @flags is VIR_CONNECT_LIST_NETWORKS_PERSITENT + * and VIR_CONNECT_LIST_NETWORKS_TRANSICIENT, to filter the networks by + * whether they have persistent config or not. + * + * The third group of @flags is VIR_CONNECT_LIST_NETWORKS_AUTOSTART + * and VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART, to filter the networks by + * whether they are marked as autostart or not. + * + * Returns the number of networks found or -1 and sets @nets to NULL in case + * of error. On success, the array stored into @nets is guaranteed to have an + * extra allocated element set to NULL but not included in the return count, + * to make iteration easier. The caller is responsible for calling + * virStorageNetworkFree() on each array element, then calling free() on @nets. + */ +int +virConnectListAllNetworks(virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, nets=%p, flags=%x", conn, nets, flags); + + virResetLastError(); + + if (nets) + *nets = NULL; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (conn->networkDriver && + conn->networkDriver->listAllNetworks) { + int ret; + ret = conn->networkDriver->listAllNetworks(conn, nets, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} + + +/** * virConnectNumOfNetworks: * @conn: pointer to the hypervisor connection * diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index ea052ed..0ce120a 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -548,6 +548,7 @@ LIBVIRT_0.9.14 { global: virConnectListAllStoragePools; virStoragePoolListAllVolumes; + virConnectListAllNetworks; } LIBVIRT_0.9.13; # .... define new API here using predicted next version number .... -- 1.7.7.3

On 07/20/2012 10:25 AM, Osier Yang wrote:
This is to list the network objects, supported filtering flags are: active|inactive, persistent|transient, autostart|no-autostart.
include/libvirt/libvirt.h.in: Declare enum virConnectListAllNetworkFlags and virConnectListAllNetworks. python/generator.py: Skip auto-generating src/driver.h: (virDrvConnectListAllNetworks) src/libvirt.c: Implement the public API src/libvirt_public.syms: Export the symbol to public --- include/libvirt/libvirt.h.in | 20 ++++++++++++ python/generator.py | 1 + src/driver.h | 5 +++ src/libvirt.c | 68 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 5 files changed, 95 insertions(+), 0 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index c5b16bf..15a9a1b 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2196,6 +2196,26 @@ int virConnectNumOfDefinedNetworks (virConnectPtr conn); int virConnectListDefinedNetworks (virConnectPtr conn, char **const names, int maxnames); +/* + * virConnectListAllNetworks: + * + * Flags used to filter the returned networks. Flags in each group + * are exclusive attributes of a network. + */ +typedef enum { + VIR_CONNECT_LIST_NETWORKS_INACTIVE = 1 << 0, + VIR_CONNECT_LIST_NETWORKS_ACTIVE = 1 << 1, + + VIR_CONNECT_LIST_NETWORKS_PERSISTENT = 1 << 2, + VIR_CONNECT_LIST_NETWORKS_TRANSIENT = 1 << 3, + + VIR_CONNECT_LIST_NETWORKS_AUTOSTART = 1 << 4, + VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART = 1 << 5, +} virConnectListAllNetworksFlags; + +int virConnectListAllNetworks (virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags);
/* * Lookup network by name or uuid diff --git a/python/generator.py b/python/generator.py index 4b3f7e6..44b56c2 100755 --- a/python/generator.py +++ b/python/generator.py @@ -458,6 +458,7 @@ skip_function = ( 'virDomainSnapshotListAllChildren', # overridden in virDomainSnapshot.py 'virConnectListAllStoragePools', # overridden in virConnect.py 'virStoragePoolListAllVolumes', # overridden in virStoragePool.py + 'virConnectListAllNetworks', # overridden in virConnect.py
'virStreamRecvAll', # Pure python libvirt-override-virStream.py 'virStreamSendAll', # Pure python libvirt-override-virStream.py diff --git a/src/driver.h b/src/driver.h index ee1341f..68a1f04 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1055,6 +1055,10 @@ typedef int (*virDrvListDefinedNetworks) (virConnectPtr conn, char **const names, int maxnames); +typedef int + (*virDrvListAllNetworks) (virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags); typedef virNetworkPtr (*virDrvNetworkLookupByUUID) (virConnectPtr conn, const unsigned char *uuid); @@ -1113,6 +1117,7 @@ struct _virNetworkDriver { virDrvListNetworks listNetworks; virDrvNumOfDefinedNetworks numOfDefinedNetworks; virDrvListDefinedNetworks listDefinedNetworks; + virDrvListAllNetworks listAllNetworks; virDrvNetworkLookupByUUID networkLookupByUUID; virDrvNetworkLookupByName networkLookupByName; virDrvNetworkCreateXML networkCreateXML; diff --git a/src/libvirt.c b/src/libvirt.c index 7780534..622a590 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -9588,6 +9588,74 @@ virNetworkGetConnect (virNetworkPtr net) }
/** + * virConnectListAllNetworks: + * @conn: Pointer to the hypervisor connection. + * @nets: Pointer to a variable to store the array containing the network + * objects or NULL if the list is not required (just returns number + * of networks). + * @flags: bitwise-OR of virConnectListAllNetworksFlags. + * + * Collect the list of networks, and allocate an array to store those + * objects. This API solves the race inherent between virConnectListNetworks + * and virConnectListDefinedNetworks. + * + * By default, this API covers all networks; it is also possible to return + * the filtered objects with flags. Filters are provided in groups, where each + * group contains bits that describe mutually exclusive attributes of a network. + * + * The first group of @flags is VIR_CONNECT_LIST_NETWORKS_INACTIVE and + * VIR_CONNECT_LIST_NETWORKS_INACTIVE to fitler the networks by state.
s/fitler/filter/ Also replace one of the INACTIVEs with ACTIVE. (you may want to add "(up)" and "(down)" after each, just to make it clear exactly what state is being discussed.)
+ * + * The second group of @flags is VIR_CONNECT_LIST_NETWORKS_PERSITENT + * and VIR_CONNECT_LIST_NETWORKS_TRANSICIENT, to filter the networks by + * whether they have persistent config or not.
s/PERSITENT/PERSISTENT/ s/TRANSICIENT/TRANSIENT/ (is it necessary/desirable to explain the meaning of persistent and transient here? After all, in the end *everything* is transient, just depends on your point of reference :-)
+ * + * The third group of @flags is VIR_CONNECT_LIST_NETWORKS_AUTOSTART + * and VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART, to filter the networks by + * whether they are marked as autostart or not. + * + * Returns the number of networks found or -1 and sets @nets to NULL in case + * of error. On success, the array stored into @nets is guaranteed to have an + * extra allocated element set to NULL but not included in the return count, + * to make iteration easier. The caller is responsible for calling + * virStorageNetworkFree() on each array element, then calling free() on @nets.
s/virStorageNetworkFree/virNetworkFree/ I wonder if it's worth the clutter of having an extra API for each of these of the form virXXXFreeList()...
+ */ +int +virConnectListAllNetworks(virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, nets=%p, flags=%x", conn, nets, flags); + + virResetLastError(); + + if (nets) + *nets = NULL; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (conn->networkDriver && + conn->networkDriver->listAllNetworks) { + int ret; + ret = conn->networkDriver->listAllNetworks(conn, nets, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} + + +/** * virConnectNumOfNetworks: * @conn: pointer to the hypervisor connection * diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index ea052ed..0ce120a 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -548,6 +548,7 @@ LIBVIRT_0.9.14 { global: virConnectListAllStoragePools; virStoragePoolListAllVolumes; + virConnectListAllNetworks; } LIBVIRT_0.9.13;
# .... define new API here using predicted next version number ....
All pretty standard stuff. ACK with the typos fixed.

On 2012年07月24日 05:07, Laine Stump wrote:
On 07/20/2012 10:25 AM, Osier Yang wrote:
This is to list the network objects, supported filtering flags are: active|inactive, persistent|transient, autostart|no-autostart.
include/libvirt/libvirt.h.in: Declare enum virConnectListAllNetworkFlags and virConnectListAllNetworks. python/generator.py: Skip auto-generating src/driver.h: (virDrvConnectListAllNetworks) src/libvirt.c: Implement the public API src/libvirt_public.syms: Export the symbol to public --- include/libvirt/libvirt.h.in | 20 ++++++++++++ python/generator.py | 1 + src/driver.h | 5 +++ src/libvirt.c | 68 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 5 files changed, 95 insertions(+), 0 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index c5b16bf..15a9a1b 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2196,6 +2196,26 @@ int virConnectNumOfDefinedNetworks (virConnectPtr conn); int virConnectListDefinedNetworks (virConnectPtr conn, char **const names, int maxnames); +/* + * virConnectListAllNetworks: + * + * Flags used to filter the returned networks. Flags in each group + * are exclusive attributes of a network. + */ +typedef enum { + VIR_CONNECT_LIST_NETWORKS_INACTIVE = 1<< 0, + VIR_CONNECT_LIST_NETWORKS_ACTIVE = 1<< 1, + + VIR_CONNECT_LIST_NETWORKS_PERSISTENT = 1<< 2, + VIR_CONNECT_LIST_NETWORKS_TRANSIENT = 1<< 3, + + VIR_CONNECT_LIST_NETWORKS_AUTOSTART = 1<< 4, + VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART = 1<< 5, +} virConnectListAllNetworksFlags; + +int virConnectListAllNetworks (virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags);
/* * Lookup network by name or uuid diff --git a/python/generator.py b/python/generator.py index 4b3f7e6..44b56c2 100755 --- a/python/generator.py +++ b/python/generator.py @@ -458,6 +458,7 @@ skip_function = ( 'virDomainSnapshotListAllChildren', # overridden in virDomainSnapshot.py 'virConnectListAllStoragePools', # overridden in virConnect.py 'virStoragePoolListAllVolumes', # overridden in virStoragePool.py + 'virConnectListAllNetworks', # overridden in virConnect.py
'virStreamRecvAll', # Pure python libvirt-override-virStream.py 'virStreamSendAll', # Pure python libvirt-override-virStream.py diff --git a/src/driver.h b/src/driver.h index ee1341f..68a1f04 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1055,6 +1055,10 @@ typedef int (*virDrvListDefinedNetworks) (virConnectPtr conn, char **const names, int maxnames); +typedef int + (*virDrvListAllNetworks) (virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags); typedef virNetworkPtr (*virDrvNetworkLookupByUUID) (virConnectPtr conn, const unsigned char *uuid); @@ -1113,6 +1117,7 @@ struct _virNetworkDriver { virDrvListNetworks listNetworks; virDrvNumOfDefinedNetworks numOfDefinedNetworks; virDrvListDefinedNetworks listDefinedNetworks; + virDrvListAllNetworks listAllNetworks; virDrvNetworkLookupByUUID networkLookupByUUID; virDrvNetworkLookupByName networkLookupByName; virDrvNetworkCreateXML networkCreateXML; diff --git a/src/libvirt.c b/src/libvirt.c index 7780534..622a590 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -9588,6 +9588,74 @@ virNetworkGetConnect (virNetworkPtr net) }
/** + * virConnectListAllNetworks: + * @conn: Pointer to the hypervisor connection. + * @nets: Pointer to a variable to store the array containing the network + * objects or NULL if the list is not required (just returns number + * of networks). + * @flags: bitwise-OR of virConnectListAllNetworksFlags. + * + * Collect the list of networks, and allocate an array to store those + * objects. This API solves the race inherent between virConnectListNetworks + * and virConnectListDefinedNetworks. + * + * By default, this API covers all networks; it is also possible to return + * the filtered objects with flags. Filters are provided in groups, where each + * group contains bits that describe mutually exclusive attributes of a network. + * + * The first group of @flags is VIR_CONNECT_LIST_NETWORKS_INACTIVE and + * VIR_CONNECT_LIST_NETWORKS_INACTIVE to fitler the networks by state.
s/fitler/filter/
Also replace one of the INACTIVEs with ACTIVE. (you may want to add "(up)" and "(down)" after each, just to make it clear exactly what state is being discussed.)
+ * + * The second group of @flags is VIR_CONNECT_LIST_NETWORKS_PERSITENT + * and VIR_CONNECT_LIST_NETWORKS_TRANSICIENT, to filter the networks by + * whether they have persistent config or not.
s/PERSITENT/PERSISTENT/ s/TRANSICIENT/TRANSIENT/
Oops.
(is it necessary/desirable to explain the meaning of persistent and transient here? After all, in the end *everything* is transient, just depends on your point of reference :-)
Yeah, good point.
+ * + * The third group of @flags is VIR_CONNECT_LIST_NETWORKS_AUTOSTART + * and VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART, to filter the networks by + * whether they are marked as autostart or not. + * + * Returns the number of networks found or -1 and sets @nets to NULL in case + * of error. On success, the array stored into @nets is guaranteed to have an + * extra allocated element set to NULL but not included in the return count, + * to make iteration easier. The caller is responsible for calling + * virStorageNetworkFree() on each array element, then calling free() on @nets.
s/virStorageNetworkFree/virNetworkFree/
I wonder if it's worth the clutter of having an extra API for each of these of the form virXXXFreeList()...
IMO it should be the application's work.
+ */ +int +virConnectListAllNetworks(virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, nets=%p, flags=%x", conn, nets, flags); + + virResetLastError(); + + if (nets) + *nets = NULL; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (conn->networkDriver&& + conn->networkDriver->listAllNetworks) { + int ret; + ret = conn->networkDriver->listAllNetworks(conn, nets, flags); + if (ret< 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} + + +/** * virConnectNumOfNetworks: * @conn: pointer to the hypervisor connection * diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index ea052ed..0ce120a 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -548,6 +548,7 @@ LIBVIRT_0.9.14 { global: virConnectListAllStoragePools; virStoragePoolListAllVolumes; + virConnectListAllNetworks; } LIBVIRT_0.9.13;
# .... define new API here using predicted next version number ....
All pretty standard stuff. ACK with the typos fixed.
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

The RPC generator doesn't support returning list of object, this patch do the work manually. * daemon/remote.c: Implemente the server side handler remoteDispatchConnectListAllNetworks. * src/remote/remote_driver.c: Add remote driver handler remoteConnectListAllNetworks. * src/remote/remote_protocol.x: New RPC procedure REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS and structs to represent the args and ret for it. * src/remote_protocol-structs: Likewise. --- daemon/remote.c | 55 ++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 64 ++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 13 ++++++++- src/remote_protocol-structs | 12 ++++++++ 4 files changed, 143 insertions(+), 1 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index c1e30c0..d5c4b90 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -4064,6 +4064,61 @@ cleanup: return rv; } +static int +remoteDispatchConnectListAllNetworks(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_connect_list_all_networks_args *args, + remote_connect_list_all_networks_ret *ret) +{ + virNetworkPtr *nets = NULL; + int nnets = 0; + int i; + int rv = -1; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if ((nnets = virConnectListAllNetworks(priv->conn, + args->need_results ? &nets : NULL, + args->flags)) < 0) + goto cleanup; + + if (nets && nnets) { + if (VIR_ALLOC_N(ret->nets.nets_val, nnets) < 0) { + virReportOOMError(); + goto cleanup; + } + + ret->nets.nets_len = nnets; + + for (i = 0; i < nnets; i++) + make_nonnull_network(ret->nets.nets_val + i, nets[i]); + } else { + ret->nets.nets_len = 0; + ret->nets.nets_val = NULL; + } + + ret->ret = nnets; + + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (nets) { + for (i = 0; i < nnets; i++) + virNetworkFree(nets[i]); + VIR_FREE(nets); + } + return rv; +} + + /*----- Helpers. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 179e7af..afe6e60 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -2779,6 +2779,69 @@ done: return rv; } +static int +remoteConnectListAllNetworks(virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags) +{ + int rv = -1; + int i; + virNetworkPtr *tmp_nets = NULL; + remote_connect_list_all_networks_args args; + remote_connect_list_all_networks_ret ret; + + struct private_data *priv = conn->privateData; + + remoteDriverLock(priv); + + args.need_results = !!nets; + args.flags = flags; + + memset(&ret, 0, sizeof(ret)); + if (call(conn, + priv, + 0, + REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS, + (xdrproc_t) xdr_remote_connect_list_all_networks_args, + (char *) &args, + (xdrproc_t) xdr_remote_connect_list_all_networks_ret, + (char *) &ret) == -1) + goto done; + + if (nets) { + if (VIR_ALLOC_N(tmp_nets, ret.nets.nets_len + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + for (i = 0; i < ret.nets.nets_len; i++) { + tmp_nets[i] = get_nonnull_network (conn, ret.nets.nets_val[i]); + if (!tmp_nets[i]) { + virReportOOMError(); + goto cleanup; + } + } + *nets = tmp_nets; + tmp_nets = NULL; + } + + rv = ret.ret; + +cleanup: + if (tmp_nets) { + for (i = 0; i < ret.nets.nets_len; i++) + if (tmp_nets[i]) + virNetworkFree(tmp_nets[i]); + VIR_FREE(tmp_nets); + } + + xdr_free((xdrproc_t) xdr_remote_connect_list_all_networks_ret, (char *) &ret); + +done: + remoteDriverUnlock(priv); + return rv; +} + /*----------------------------------------------------------------------*/ @@ -5485,6 +5548,7 @@ static virNetworkDriver network_driver = { .listNetworks = remoteListNetworks, /* 0.3.0 */ .numOfDefinedNetworks = remoteNumOfDefinedNetworks, /* 0.3.0 */ .listDefinedNetworks = remoteListDefinedNetworks, /* 0.3.0 */ + .listAllNetworks = remoteConnectListAllNetworks, /* 0.9.14 */ .networkLookupByUUID = remoteNetworkLookupByUUID, /* 0.3.0 */ .networkLookupByName = remoteNetworkLookupByName, /* 0.3.0 */ .networkCreateXML = remoteNetworkCreateXML, /* 0.3.0 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index d090705..897775c 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1247,6 +1247,16 @@ struct remote_list_defined_networks_ret { remote_nonnull_string names<REMOTE_NETWORK_NAME_LIST_MAX>; /* insert@1 */ }; +struct remote_connect_list_all_networks_args { + int need_results; + unsigned int flags; +}; + +struct remote_connect_list_all_networks_ret { + remote_nonnull_network nets<>; + unsigned int ret; +}; + struct remote_network_lookup_by_uuid_args { remote_uuid uuid; }; @@ -2864,7 +2874,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_ALL_CHILDREN = 275, /* skipgen skipgen priority:high */ REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE = 276, /* autogen autogen */ REMOTE_PROC_CONNECT_LIST_ALL_STORAGE_POOLS = 277, /* skipgen skipgen priority:high */ - REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES = 278 /* skipgen skipgen priority:high */ + REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES = 278, /* skipgen skipgen priority:high */ + REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS = 279 /* skipgen skipgen priority:high */ /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 9d81ad0..315ec7f 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -632,6 +632,17 @@ struct remote_list_defined_domains_ret { remote_nonnull_string * names_val; } names; }; +struct remote_list_all_networks_args { + int need_results; + u_int flags; +}; +struct remote_list_all_networks_ret { + struct { + u_int nets_len; + remote_nonnull_network * nets_val; + } nets; + u_int ret; +}; struct remote_num_of_defined_domains_ret { int num; }; @@ -2276,4 +2287,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE = 276, REMOTE_PROC_CONNECT_LIST_ALL_STORAGE_POOLS = 277, REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES = 278, + REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS = 279, }; -- 1.7.7.3

src/conf/virobjectlist.c: Add virNetworkMatch to filter the networks; and virNetworkList to iterate over all the networks with the filter. src/conf/virobjectlist.h: Declare virNetworkList and define the macros for filters. src/libvirt_private.syms: Export virNetworkList. --- src/conf/virobjectlist.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++ src/conf/virobjectlist.h | 23 ++++++++++++ src/libvirt_private.syms | 1 + 3 files changed, 114 insertions(+), 0 deletions(-) diff --git a/src/conf/virobjectlist.c b/src/conf/virobjectlist.c index fb5f974..83b0d9c 100644 --- a/src/conf/virobjectlist.c +++ b/src/conf/virobjectlist.c @@ -191,6 +191,37 @@ virStoragePoolMatch (virStoragePoolObjPtr poolobj, return true; } + +static bool +virNetworkMatch (virNetworkObjPtr netobj, + unsigned int flags) +{ + /* filter by active state */ + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE) && + !((MATCH(VIR_CONNECT_LIST_NETWORKS_ACTIVE) && + virNetworkObjIsActive(netobj)) || + (MATCH(VIR_CONNECT_LIST_NETWORKS_INACTIVE) && + !virNetworkObjIsActive(netobj)))) + return false; + + /* filter by persistence */ + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_PERSISTENT) && + !((MATCH(VIR_CONNECT_LIST_NETWORKS_PERSISTENT) && + netobj->persistent) || + (MATCH(VIR_CONNECT_LIST_NETWORKS_TRANSIENT) && + !netobj->persistent))) + return false; + + /* filter by autostart option */ + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_AUTOSTART) && + !((MATCH(VIR_CONNECT_LIST_NETWORKS_AUTOSTART) && + netobj->autostart) || + (MATCH(VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART) && + !netobj->autostart))) + return false; + + return true; +} #undef MATCH int @@ -340,3 +371,62 @@ cleanup: VIR_FREE(tmp_pools); return ret; } + +int +virNetworkList(virConnectPtr conn, + virNetworkObjList netobjs, + virNetworkPtr **nets, + unsigned int flags) +{ + virNetworkPtr *tmp_nets = NULL; + virNetworkPtr net = NULL; + int nnets = 0; + int ret = -1; + int i; + + if (nets) { + if (VIR_ALLOC_N(tmp_nets, netobjs.count + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + } + + for (i = 0; i < netobjs.count; i++) { + virNetworkObjPtr netobj = netobjs.objs[i]; + virNetworkObjLock(netobj); + if (virNetworkMatch(netobj, flags)) { + if (nets) { + if (!(net = virGetNetwork(conn, + netobj->def->name, + netobj->def->uuid))) { + virNetworkObjUnlock(netobj); + goto cleanup; + } + tmp_nets[nnets++] = net; + } else { + nnets++; + } + } + virNetworkObjUnlock(netobj); + } + + if (tmp_nets) { + /* trim the array to the final size */ + ignore_value(VIR_REALLOC_N(tmp_nets, nnets + 1)); + *nets = tmp_nets; + tmp_nets = NULL; + } + + ret = nnets; + +cleanup: + if (tmp_nets) { + for (i = 0; i < netobjs.count; i++) { + if (tmp_nets[i]) + virNetworkFree(tmp_nets[i]); + } + } + + VIR_FREE(tmp_nets); + return ret; +} diff --git a/src/conf/virobjectlist.h b/src/conf/virobjectlist.h index b93cd19..431635e 100644 --- a/src/conf/virobjectlist.h +++ b/src/conf/virobjectlist.h @@ -28,6 +28,7 @@ # include "virhash.h" # include "domain_conf.h" # include "storage_conf.h" +# include "network_conf.h" # define VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE \ (VIR_CONNECT_LIST_DOMAINS_ACTIVE | \ @@ -105,6 +106,23 @@ VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_AUTOSTART | \ VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_POOL_TYPE) +# define VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE \ + (VIR_CONNECT_LIST_NETWORKS_ACTIVE | \ + VIR_CONNECT_LIST_NETWORKS_INACTIVE) + +# define VIR_CONNECT_LIST_NETWORKS_FILTERS_PERSISTENT \ + (VIR_CONNECT_LIST_NETWORKS_PERSISTENT | \ + VIR_CONNECT_LIST_NETWORKS_TRANSIENT) + +# define VIR_CONNECT_LIST_NETWORKS_FILTERS_AUTOSTART \ + (VIR_CONNECT_LIST_NETWORKS_AUTOSTART | \ + VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART) + +# define VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL \ + (VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE | \ + VIR_CONNECT_LIST_NETWORKS_FILTERS_PERSISTENT | \ + VIR_CONNECT_LIST_NETWORKS_FILTERS_AUTOSTART) + int virDomainList(virConnectPtr conn, virHashTablePtr domobjs, virDomainPtr **domains, unsigned int flags); @@ -119,4 +137,9 @@ int virStoragePoolList(virConnectPtr conn, virStoragePoolPtr **pools, unsigned int flags); +int virNetworkList(virConnectPtr conn, + virNetworkObjList netobjs, + virNetworkPtr **nets, + unsigned int flags); + #endif /* __VIR_OBJECT_LIST_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 18b3185..647ecf0 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1246,6 +1246,7 @@ virDBusGetSystemBus; # virobjectlist.h virDomainList; virDomainListSnapshots; +virNetworkList; virStoragePoolList; -- 1.7.7.3

On 07/20/2012 10:25 AM, Osier Yang wrote:
src/conf/virobjectlist.c: Add virNetworkMatch to filter the networks; and virNetworkList to iterate over all the networks with the filter.
src/conf/virobjectlist.h: Declare virNetworkList and define the macros for filters.
Before anything else - as I've said in a couple of earlier responses to this series (and I won't say it for the other iterations - you can just assume the same comment for all :-) - I don't think that driver-specific functions (virNetworkMatch, virNetworkList) should be in a common source file. If these functions have something in common, factor out that common part and put *that* in a common file. If a function is specific enough that it needs the name of the driver in the name, then it shouldn't be in a common file. I'll review the rest, ignoring that for the moment.
src/libvirt_private.syms: Export virNetworkList. --- src/conf/virobjectlist.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++ src/conf/virobjectlist.h | 23 ++++++++++++ src/libvirt_private.syms | 1 + 3 files changed, 114 insertions(+), 0 deletions(-)
diff --git a/src/conf/virobjectlist.c b/src/conf/virobjectlist.c index fb5f974..83b0d9c 100644 --- a/src/conf/virobjectlist.c +++ b/src/conf/virobjectlist.c @@ -191,6 +191,37 @@ virStoragePoolMatch (virStoragePoolObjPtr poolobj,
return true; } + +static bool +virNetworkMatch (virNetworkObjPtr netobj, + unsigned int flags) +{ + /* filter by active state */ + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE) && + !((MATCH(VIR_CONNECT_LIST_NETWORKS_ACTIVE) && + virNetworkObjIsActive(netobj)) || + (MATCH(VIR_CONNECT_LIST_NETWORKS_INACTIVE) && + !virNetworkObjIsActive(netobj)))) + return false; + + /* filter by persistence */ + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_PERSISTENT) && + !((MATCH(VIR_CONNECT_LIST_NETWORKS_PERSISTENT) && + netobj->persistent) || + (MATCH(VIR_CONNECT_LIST_NETWORKS_TRANSIENT) && + !netobj->persistent))) + return false; + + /* filter by autostart option */ + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_AUTOSTART) && + !((MATCH(VIR_CONNECT_LIST_NETWORKS_AUTOSTART) && + netobj->autostart) || + (MATCH(VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART) && + !netobj->autostart))) + return false; + + return true; +} #undef MATCH
int @@ -340,3 +371,62 @@ cleanup: VIR_FREE(tmp_pools); return ret; } + +int +virNetworkList(virConnectPtr conn, + virNetworkObjList netobjs,
Minor point - to be consistent with naming in existing network driver code, why not call it "networks" rather than "netobjs"?
+ virNetworkPtr **nets, + unsigned int flags) +{ + virNetworkPtr *tmp_nets = NULL; + virNetworkPtr net = NULL; + int nnets = 0; + int ret = -1; + int i; + + if (nets) { + if (VIR_ALLOC_N(tmp_nets, netobjs.count + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + } + + for (i = 0; i < netobjs.count; i++) { + virNetworkObjPtr netobj = netobjs.objs[i]; + virNetworkObjLock(netobj); + if (virNetworkMatch(netobj, flags)) { + if (nets) { + if (!(net = virGetNetwork(conn, + netobj->def->name, + netobj->def->uuid))) { + virNetworkObjUnlock(netobj); + goto cleanup; + } + tmp_nets[nnets++] = net; + } else { + nnets++;
I don't think you want this else clause. the index on netobjs (i) is incremented by the for(), and you only want the index on the output list to be incremented when you actually add something to it.
+ } + } + virNetworkObjUnlock(netobj); + } + + if (tmp_nets) { + /* trim the array to the final size */ + ignore_value(VIR_REALLOC_N(tmp_nets, nnets + 1)); + *nets = tmp_nets; + tmp_nets = NULL; + } + + ret = nnets; + +cleanup: + if (tmp_nets) { + for (i = 0; i < netobjs.count; i++) {
You only want to do this nnets times, not netobjs.count. Since it's NULL-initialized, there's no harm, but it may foster a misunderstanding of the code in the future).
+ if (tmp_nets[i]) + virNetworkFree(tmp_nets[i]); + } + } + + VIR_FREE(tmp_nets); + return ret; +} diff --git a/src/conf/virobjectlist.h b/src/conf/virobjectlist.h index b93cd19..431635e 100644 --- a/src/conf/virobjectlist.h +++ b/src/conf/virobjectlist.h @@ -28,6 +28,7 @@ # include "virhash.h" # include "domain_conf.h" # include "storage_conf.h" +# include "network_conf.h"
# define VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE \ (VIR_CONNECT_LIST_DOMAINS_ACTIVE | \ @@ -105,6 +106,23 @@ VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_AUTOSTART | \ VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_POOL_TYPE)
+# define VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE \ + (VIR_CONNECT_LIST_NETWORKS_ACTIVE | \ + VIR_CONNECT_LIST_NETWORKS_INACTIVE) + +# define VIR_CONNECT_LIST_NETWORKS_FILTERS_PERSISTENT \ + (VIR_CONNECT_LIST_NETWORKS_PERSISTENT | \ + VIR_CONNECT_LIST_NETWORKS_TRANSIENT) + +# define VIR_CONNECT_LIST_NETWORKS_FILTERS_AUTOSTART \ + (VIR_CONNECT_LIST_NETWORKS_AUTOSTART | \ + VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART) + +# define VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL \ + (VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE | \ + VIR_CONNECT_LIST_NETWORKS_FILTERS_PERSISTENT | \ + VIR_CONNECT_LIST_NETWORKS_FILTERS_AUTOSTART) + int virDomainList(virConnectPtr conn, virHashTablePtr domobjs, virDomainPtr **domains, unsigned int flags);
@@ -119,4 +137,9 @@ int virStoragePoolList(virConnectPtr conn, virStoragePoolPtr **pools, unsigned int flags);
+int virNetworkList(virConnectPtr conn, + virNetworkObjList netobjs, + virNetworkPtr **nets, + unsigned int flags); + #endif /* __VIR_OBJECT_LIST_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 18b3185..647ecf0 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1246,6 +1246,7 @@ virDBusGetSystemBus; # virobjectlist.h virDomainList; virDomainListSnapshots; +virNetworkList; virStoragePoolList;

On 2012年07月24日 04:53, Laine Stump wrote:
On 07/20/2012 10:25 AM, Osier Yang wrote:
src/conf/virobjectlist.c: Add virNetworkMatch to filter the networks; and virNetworkList to iterate over all the networks with the filter.
src/conf/virobjectlist.h: Declare virNetworkList and define the macros for filters.
Thanks for the reviewing, Laine.
Before anything else - as I've said in a couple of earlier responses to this series (and I won't say it for the other iterations - you can just assume the same comment for all :-) - I don't think that driver-specific functions (virNetworkMatch, virNetworkList) should be in a common source file. If these functions have something in common, factor out that common part and put *that* in a common file. If a function is specific enough that it needs the name of the driver in the name, then it shouldn't be in a common file.
I see what you concern, and agree with you driver specific stuffs should be separated into each driver. But for these list stuffs, I insist that keeping those function in a common file is better. They are of specific drivers indeed, but in common from function point of view. Or you prefer to have separate files like virDomainList.[ch], virStorageList.[ch], ..etc? Or folder the functions into conf/domain_conf.[ch], conf/storage_conf.[ch], etc? IMO either is not better than keeping them in common place. :-)
I'll review the rest, ignoring that for the moment.
src/libvirt_private.syms: Export virNetworkList. --- src/conf/virobjectlist.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++ src/conf/virobjectlist.h | 23 ++++++++++++ src/libvirt_private.syms | 1 + 3 files changed, 114 insertions(+), 0 deletions(-)
diff --git a/src/conf/virobjectlist.c b/src/conf/virobjectlist.c index fb5f974..83b0d9c 100644 --- a/src/conf/virobjectlist.c +++ b/src/conf/virobjectlist.c @@ -191,6 +191,37 @@ virStoragePoolMatch (virStoragePoolObjPtr poolobj,
return true; } + +static bool +virNetworkMatch (virNetworkObjPtr netobj, + unsigned int flags) +{ + /* filter by active state */ + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE)&& + !((MATCH(VIR_CONNECT_LIST_NETWORKS_ACTIVE)&& + virNetworkObjIsActive(netobj)) || + (MATCH(VIR_CONNECT_LIST_NETWORKS_INACTIVE)&& + !virNetworkObjIsActive(netobj)))) + return false; + + /* filter by persistence */ + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_PERSISTENT)&& + !((MATCH(VIR_CONNECT_LIST_NETWORKS_PERSISTENT)&& + netobj->persistent) || + (MATCH(VIR_CONNECT_LIST_NETWORKS_TRANSIENT)&& + !netobj->persistent))) + return false; + + /* filter by autostart option */ + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_AUTOSTART)&& + !((MATCH(VIR_CONNECT_LIST_NETWORKS_AUTOSTART)&& + netobj->autostart) || + (MATCH(VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART)&& + !netobj->autostart))) + return false; + + return true; +} #undef MATCH
int @@ -340,3 +371,62 @@ cleanup: VIR_FREE(tmp_pools); return ret; } + +int +virNetworkList(virConnectPtr conn, + virNetworkObjList netobjs,
Minor point - to be consistent with naming in existing network driver code, why not call it "networks" rather than "netobjs"?
I intended to keep consistent with other funcs in virobjectlist.c. If finally we prefer to have driver specific funcs separately, I will update it to "networks".
+ virNetworkPtr **nets, + unsigned int flags) +{ + virNetworkPtr *tmp_nets = NULL; + virNetworkPtr net = NULL; + int nnets = 0; + int ret = -1; + int i; + + if (nets) { + if (VIR_ALLOC_N(tmp_nets, netobjs.count + 1)< 0) { + virReportOOMError(); + goto cleanup; + } + } + + for (i = 0; i< netobjs.count; i++) { + virNetworkObjPtr netobj = netobjs.objs[i]; + virNetworkObjLock(netobj); + if (virNetworkMatch(netobj, flags)) { + if (nets) { + if (!(net = virGetNetwork(conn, + netobj->def->name, + netobj->def->uuid))) { + virNetworkObjUnlock(netobj); + goto cleanup; + } + tmp_nets[nnets++] = net; + } else { + nnets++;
I don't think you want this else clause. the index on netobjs (i) is incremented by the for(), and you only want the index on the output list to be incremented when you actually add something to it.
One design of the list APIs is to only return the object number. So the index is always needed. But this could be optimized as: if (nets) { if (!(net = virGetNetwork(conn, netobj->def->name, netobj->def->uuid))) { virNetworkObjUnlock(netobj); goto cleanup; } tmp_nets[nnets] = net; } nnets++;
+ } + } + virNetworkObjUnlock(netobj); + } + + if (tmp_nets) { + /* trim the array to the final size */ + ignore_value(VIR_REALLOC_N(tmp_nets, nnets + 1)); + *nets = tmp_nets; + tmp_nets = NULL; + } + + ret = nnets; + +cleanup: + if (tmp_nets) { + for (i = 0; i< netobjs.count; i++) {
You only want to do this nnets times, not netobjs.count. Since it's NULL-initialized, there's no harm, but it may foster a misunderstanding of the code in the future).
Agreed. Regards, Osier

On 07/24/2012 01:09 AM, Osier Yang wrote:
On 2012年07月24日 04:53, Laine Stump wrote:
On 07/20/2012 10:25 AM, Osier Yang wrote:
src/conf/virobjectlist.c: Add virNetworkMatch to filter the networks; and virNetworkList to iterate over all the networks with the filter.
src/conf/virobjectlist.h: Declare virNetworkList and define the macros for filters.
Thanks for the reviewing, Laine.
Before anything else - as I've said in a couple of earlier responses to this series (and I won't say it for the other iterations - you can just assume the same comment for all :-) - I don't think that driver-specific functions (virNetworkMatch, virNetworkList) should be in a common source file. If these functions have something in common, factor out that common part and put *that* in a common file. If a function is specific enough that it needs the name of the driver in the name, then it shouldn't be in a common file.
I see what you concern, and agree with you driver specific stuffs should be separated into each driver.
But for these list stuffs, I insist that keeping those function in a common file is better. They are of specific drivers indeed, but in common from function point of view.
"function point of view" how? Because they all build a list of pointers to objects? That argument doesn't hold - should all functions in libvirt that build a list of pointers to objects be put into the same source file? To be hyperbolic about it - should we put all functions that acquire and release a lock in the same file? Organizing the code in the manner you propose leads to a source tree where adding a new API requires touching an incredibly long list of files, and makes it difficult to split out pieces for use elsewhere. (I know that's already the case for several other pieces of libvirt, but why make the list longer? Each separate subsystem should be as self-contained as possible.) If you're concerned about maintenance of multiple functions that are all mostly a copy-paste of each other, rather than grouping all those functions together in one file, refactor it so that they all call a common function with appropriate args (which may require some callbacks). If the resulting utility function is more difficult to understand than the current straightforward functions, then it's not worth the bother.
Or you prefer to have separate files like virDomainList.[ch], virStorageList.[ch], ..etc?
No, I think that's overkill.
Or folder the functions into conf/domain_conf.[ch], conf/storage_conf.[ch], etc?
Where is the source data structure defined? If the data structure that is used to list of domains/networks/storage pools|volumes is defined in conf/*_conf.h, then the function that operates on that data structure to produce the output list should be defined in conf/*_conf.c. If the data structure is defined in ${driver}.h, then the function that operates on it should be defined in ${driver}.c. (I think for all examples in this current patchset, the answer is *_conf.c)
IMO either is not better than keeping them in common place. :-)
I'll review the rest, ignoring that for the moment.
src/libvirt_private.syms: Export virNetworkList. --- src/conf/virobjectlist.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++ src/conf/virobjectlist.h | 23 ++++++++++++ src/libvirt_private.syms | 1 + 3 files changed, 114 insertions(+), 0 deletions(-)
diff --git a/src/conf/virobjectlist.c b/src/conf/virobjectlist.c index fb5f974..83b0d9c 100644 --- a/src/conf/virobjectlist.c +++ b/src/conf/virobjectlist.c @@ -191,6 +191,37 @@ virStoragePoolMatch (virStoragePoolObjPtr poolobj,
return true; } + +static bool +virNetworkMatch (virNetworkObjPtr netobj, + unsigned int flags) +{ + /* filter by active state */ + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE)&& + !((MATCH(VIR_CONNECT_LIST_NETWORKS_ACTIVE)&& + virNetworkObjIsActive(netobj)) || + (MATCH(VIR_CONNECT_LIST_NETWORKS_INACTIVE)&& + !virNetworkObjIsActive(netobj)))) + return false; + + /* filter by persistence */ + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_PERSISTENT)&& + !((MATCH(VIR_CONNECT_LIST_NETWORKS_PERSISTENT)&& + netobj->persistent) || + (MATCH(VIR_CONNECT_LIST_NETWORKS_TRANSIENT)&& + !netobj->persistent))) + return false; + + /* filter by autostart option */ + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_AUTOSTART)&& + !((MATCH(VIR_CONNECT_LIST_NETWORKS_AUTOSTART)&& + netobj->autostart) || + (MATCH(VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART)&& + !netobj->autostart))) + return false; + + return true; +} #undef MATCH
int @@ -340,3 +371,62 @@ cleanup: VIR_FREE(tmp_pools); return ret; } + +int +virNetworkList(virConnectPtr conn, + virNetworkObjList netobjs,
Minor point - to be consistent with naming in existing network driver code, why not call it "networks" rather than "netobjs"?
I intended to keep consistent with other funcs in virobjectlist.c. If finally we prefer to have driver specific funcs separately, I will update it to "networks".
+ virNetworkPtr **nets, + unsigned int flags) +{ + virNetworkPtr *tmp_nets = NULL; + virNetworkPtr net = NULL; + int nnets = 0; + int ret = -1; + int i; + + if (nets) { + if (VIR_ALLOC_N(tmp_nets, netobjs.count + 1)< 0) { + virReportOOMError(); + goto cleanup; + } + } + + for (i = 0; i< netobjs.count; i++) { + virNetworkObjPtr netobj = netobjs.objs[i]; + virNetworkObjLock(netobj); + if (virNetworkMatch(netobj, flags)) { + if (nets) { + if (!(net = virGetNetwork(conn, + netobj->def->name, + netobj->def->uuid))) { + virNetworkObjUnlock(netobj); + goto cleanup; + } + tmp_nets[nnets++] = net; + } else { + nnets++;
I don't think you want this else clause. the index on netobjs (i) is incremented by the for(), and you only want the index on the output list to be incremented when you actually add something to it.
One design of the list APIs is to only return the object number. So the index is always needed. But this could be optimized as:
if (nets) { if (!(net = virGetNetwork(conn, netobj->def->name, netobj->def->uuid))) { virNetworkObjUnlock(netobj); goto cleanup; } tmp_nets[nnets] = net; } nnets++;
Never mind - I read through the code too quickly, and somehow mistakenly saw the else clause at the level of the Match, rather than one step further in (my brain had seen it as nnets being incremented even in the case of no match). I do prefer your modified version above, though.
+ } + } + virNetworkObjUnlock(netobj); + } + + if (tmp_nets) { + /* trim the array to the final size */ + ignore_value(VIR_REALLOC_N(tmp_nets, nnets + 1)); + *nets = tmp_nets; + tmp_nets = NULL; + } + + ret = nnets; + +cleanup: + if (tmp_nets) { + for (i = 0; i< netobjs.count; i++) {
You only want to do this nnets times, not netobjs.count. Since it's NULL-initialized, there's no harm, but it may foster a misunderstanding of the code in the future).
Agreed.
Regards, Osier

On 2012年07月25日 01:22, Laine Stump wrote:
On 07/24/2012 01:09 AM, Osier Yang wrote:
On 2012年07月24日 04:53, Laine Stump wrote:
On 07/20/2012 10:25 AM, Osier Yang wrote:
src/conf/virobjectlist.c: Add virNetworkMatch to filter the networks; and virNetworkList to iterate over all the networks with the filter.
src/conf/virobjectlist.h: Declare virNetworkList and define the macros for filters.
Thanks for the reviewing, Laine.
Before anything else - as I've said in a couple of earlier responses to this series (and I won't say it for the other iterations - you can just assume the same comment for all :-) - I don't think that driver-specific functions (virNetworkMatch, virNetworkList) should be in a common source file. If these functions have something in common, factor out that common part and put *that* in a common file. If a function is specific enough that it needs the name of the driver in the name, then it shouldn't be in a common file.
I see what you concern, and agree with you driver specific stuffs should be separated into each driver.
But for these list stuffs, I insist that keeping those function in a common file is better. They are of specific drivers indeed, but in common from function point of view.
"function point of view" how? Because they all build a list of pointers to objects? That argument doesn't hold - should all functions in libvirt that build a list of pointers to objects be put into the same source file? To be hyperbolic about it - should we put all functions that acquire and release a lock in the same file?
Organizing the code in the manner you propose leads to a source tree where adding a new API requires touching an incredibly long list of files, and makes it difficult to split out pieces for use elsewhere.
(I know that's already the case for several other pieces of libvirt, but why make the list longer? Each separate subsystem should be as self-contained as possible.)
Too much questions, and guess I will be trapped if saying no. So you win.
If you're concerned about maintenance of multiple functions that are all mostly a copy-paste of each other, rather than grouping all those functions together in one file, refactor it so that they all call a common function with appropriate args (which may require some callbacks). If the resulting utility function is more difficult to understand than the current straightforward functions, then it's not worth the bother.
I thought in that way when doing the patches, and don't think it worths.
Or you prefer to have separate files like virDomainList.[ch], virStorageList.[ch], ..etc?
No, I think that's overkill.
Yeah, that was the mainly reason for I intended to created a common file.
Or folder the functions into conf/domain_conf.[ch], conf/storage_conf.[ch], etc?
Where is the source data structure defined? If the data structure that is used to list of domains/networks/storage pools|volumes is defined in conf/*_conf.h, then the function that operates on that data structure to produce the output list should be defined in conf/*_conf.c. If the data structure is defined in ${driver}.h, then the function that operates on it should be defined in ${driver}.c. (I think for all examples in this current patchset, the answer is *_conf.c)
Well. You are a bit late (may be on vacation). virdomainlist.[ch] is already there. I'd want to see a 3rd opinion on this, if finally we want them be foldered into *_conf.c, I will be fine with it. We need to get rid of the existed virdomainlist.[ch] first.
IMO either is not better than keeping them in common place. :-)
I'll review the rest, ignoring that for the moment.
src/libvirt_private.syms: Export virNetworkList. --- src/conf/virobjectlist.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++ src/conf/virobjectlist.h | 23 ++++++++++++ src/libvirt_private.syms | 1 + 3 files changed, 114 insertions(+), 0 deletions(-)
diff --git a/src/conf/virobjectlist.c b/src/conf/virobjectlist.c index fb5f974..83b0d9c 100644 --- a/src/conf/virobjectlist.c +++ b/src/conf/virobjectlist.c @@ -191,6 +191,37 @@ virStoragePoolMatch (virStoragePoolObjPtr poolobj,
return true; } + +static bool +virNetworkMatch (virNetworkObjPtr netobj, + unsigned int flags) +{ + /* filter by active state */ + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE)&& + !((MATCH(VIR_CONNECT_LIST_NETWORKS_ACTIVE)&& + virNetworkObjIsActive(netobj)) || + (MATCH(VIR_CONNECT_LIST_NETWORKS_INACTIVE)&& + !virNetworkObjIsActive(netobj)))) + return false; + + /* filter by persistence */ + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_PERSISTENT)&& + !((MATCH(VIR_CONNECT_LIST_NETWORKS_PERSISTENT)&& + netobj->persistent) || + (MATCH(VIR_CONNECT_LIST_NETWORKS_TRANSIENT)&& + !netobj->persistent))) + return false; + + /* filter by autostart option */ + if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_AUTOSTART)&& + !((MATCH(VIR_CONNECT_LIST_NETWORKS_AUTOSTART)&& + netobj->autostart) || + (MATCH(VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART)&& + !netobj->autostart))) + return false; + + return true; +} #undef MATCH
int @@ -340,3 +371,62 @@ cleanup: VIR_FREE(tmp_pools); return ret; } + +int +virNetworkList(virConnectPtr conn, + virNetworkObjList netobjs,
Minor point - to be consistent with naming in existing network driver code, why not call it "networks" rather than "netobjs"?
I intended to keep consistent with other funcs in virobjectlist.c. If finally we prefer to have driver specific funcs separately, I will update it to "networks".
+ virNetworkPtr **nets, + unsigned int flags) +{ + virNetworkPtr *tmp_nets = NULL; + virNetworkPtr net = NULL; + int nnets = 0; + int ret = -1; + int i; + + if (nets) { + if (VIR_ALLOC_N(tmp_nets, netobjs.count + 1)< 0) { + virReportOOMError(); + goto cleanup; + } + } + + for (i = 0; i< netobjs.count; i++) { + virNetworkObjPtr netobj = netobjs.objs[i]; + virNetworkObjLock(netobj); + if (virNetworkMatch(netobj, flags)) { + if (nets) { + if (!(net = virGetNetwork(conn, + netobj->def->name, + netobj->def->uuid))) { + virNetworkObjUnlock(netobj); + goto cleanup; + } + tmp_nets[nnets++] = net; + } else { + nnets++;
I don't think you want this else clause. the index on netobjs (i) is incremented by the for(), and you only want the index on the output list to be incremented when you actually add something to it.
One design of the list APIs is to only return the object number. So the index is always needed. But this could be optimized as:
if (nets) { if (!(net = virGetNetwork(conn, netobj->def->name, netobj->def->uuid))) { virNetworkObjUnlock(netobj); goto cleanup; } tmp_nets[nnets] = net; } nnets++;
Never mind - I read through the code too quickly, and somehow mistakenly saw the else clause at the level of the Match, rather than one step further in (my brain had seen it as nnets being incremented even in the case of no match).
I do prefer your modified version above, though.
+ } + } + virNetworkObjUnlock(netobj); + } + + if (tmp_nets) { + /* trim the array to the final size */ + ignore_value(VIR_REALLOC_N(tmp_nets, nnets + 1)); + *nets = tmp_nets; + tmp_nets = NULL; + } + + ret = nnets; + +cleanup: + if (tmp_nets) { + for (i = 0; i< netobjs.count; i++) {
You only want to do this nnets times, not netobjs.count. Since it's NULL-initialized, there's no harm, but it may foster a misunderstanding of the code in the future).
Agreed.
Regards, Osier
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On 07/24/2012 08:52 PM, Osier Yang wrote:
Or folder the functions into conf/domain_conf.[ch], conf/storage_conf.[ch], etc?
Where is the source data structure defined? If the data structure that is used to list of domains/networks/storage pools|volumes is defined in conf/*_conf.h, then the function that operates on that data structure to produce the output list should be defined in conf/*_conf.c. If the data structure is defined in ${driver}.h, then the function that operates on it should be defined in ${driver}.c. (I think for all examples in this current patchset, the answer is *_conf.c)
Well. You are a bit late (may be on vacation). virdomainlist.[ch] is already there. I'd want to see a 3rd opinion on this, if finally we want them be foldered into *_conf.c, I will be fine with it. We need to get rid of the existed virdomainlist.[ch] first.
My recollection was that Peter originally added virdomainlist.c to solve a link error - our use of virGetDomain() caused a link failure when trying to build the LXC driver. LXC requires several functions from domain_conf.c, but apparently was not linking against the souce for datatypes.c, which made virGetDomain() the first instance of a linking problem. But in the meantime, we have refactored the Makefile, and how LXC is linked in the first place. I'm wondering if Daniel's commit 284143b makes it possible to use virGetDomain() directly from domain_conf.c in the first place. If that is the case, then the answer is 'get rid of virdomainlist.c/virobjectlist.c, and stick everything in the appropriate foo_conf.c instead'. If we still get a link failure for LXC in spite of using virGetDomain() directly from domain_conf.c, then it might be worth investigating that link failure first. Yeah, that doesn't quite answer the question (one file virobjectlist.c shared among multiple objects, vs. one file per object type), but hopefully it helps in figuring out a way forward. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 2012年07月31日 01:00, Eric Blake wrote:
On 07/24/2012 08:52 PM, Osier Yang wrote:
Or folder the functions into conf/domain_conf.[ch], conf/storage_conf.[ch], etc?
Where is the source data structure defined? If the data structure that is used to list of domains/networks/storage pools|volumes is defined in conf/*_conf.h, then the function that operates on that data structure to produce the output list should be defined in conf/*_conf.c. If the data structure is defined in ${driver}.h, then the function that operates on it should be defined in ${driver}.c. (I think for all examples in this current patchset, the answer is *_conf.c)
Well. You are a bit late (may be on vacation). virdomainlist.[ch] is already there. I'd want to see a 3rd opinion on this, if finally we want them be foldered into *_conf.c, I will be fine with it. We need to get rid of the existed virdomainlist.[ch] first.
My recollection was that Peter originally added virdomainlist.c to solve a link error - our use of virGetDomain() caused a link failure when trying to build the LXC driver. LXC requires several functions from domain_conf.c, but apparently was not linking against the souce for datatypes.c, which made virGetDomain() the first instance of a linking problem.
But in the meantime, we have refactored the Makefile, and how LXC is linked in the first place. I'm wondering if Daniel's commit 284143b makes it possible to use virGetDomain() directly from domain_conf.c in the first place. If that is the case, then the answer is 'get rid of virdomainlist.c/virobjectlist.c, and stick everything in the appropriate foo_conf.c instead'. If we still get a link failure for LXC in spite of using virGetDomain() directly from domain_conf.c, then it might be worth investigating that link failure first.
I tried, virGetDomain can be used without including virdomainlist.h, seems Daniel's commit fixed the link error.
Yeah, that doesn't quite answer the question (one file virobjectlist.c shared among multiple objects, vs. one file per object type), but hopefully it helps in figuring out a way forward.
I think your opinion is to destroy virdomainlist.h then. Assuming it as a 3rd opinion, I will go this way, and rebase the whole patch set. Thanks! Regards, Osier

src/network/bridge_driver.c: Implement listAllNetworks. --- src/network/bridge_driver.c | 18 ++++++++++++++++++ 1 files changed, 18 insertions(+), 0 deletions(-) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index bb2a765..6a3ed3f 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -47,6 +47,7 @@ #include "datatypes.h" #include "bridge_driver.h" #include "network_conf.h" +#include "virobjectlist.h" #include "driver.h" #include "buf.h" #include "virpidfile.h" @@ -2201,6 +2202,22 @@ static int networkListDefinedNetworks(virConnectPtr conn, char **const names, in return -1; } +static int +networkListAllNetworks(virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags) +{ + struct network_driver *driver = conn->networkPrivateData; + int ret = -1; + + virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1); + + networkDriverLock(driver); + ret = virNetworkList(conn, driver->networks, nets, flags); + networkDriverUnlock(driver); + + return ret; +} static int networkIsActive(virNetworkPtr net) { @@ -2689,6 +2706,7 @@ static virNetworkDriver networkDriver = { .listNetworks = networkListNetworks, /* 0.2.0 */ .numOfDefinedNetworks = networkNumDefinedNetworks, /* 0.2.0 */ .listDefinedNetworks = networkListDefinedNetworks, /* 0.2.0 */ + .listAllNetworks = networkListAllNetworks, /* 0.9.14 */ .networkLookupByUUID = networkLookupByUUID, /* 0.2.0 */ .networkLookupByName = networkLookupByName, /* 0.2.0 */ .networkCreateXML = networkCreate, /* 0.2.0 */ -- 1.7.7.3

On 07/20/2012 10:25 AM, Osier Yang wrote:
src/network/bridge_driver.c: Implement listAllNetworks. --- src/network/bridge_driver.c | 18 ++++++++++++++++++ 1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index bb2a765..6a3ed3f 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -47,6 +47,7 @@ #include "datatypes.h" #include "bridge_driver.h" #include "network_conf.h" +#include "virobjectlist.h" #include "driver.h" #include "buf.h" #include "virpidfile.h" @@ -2201,6 +2202,22 @@ static int networkListDefinedNetworks(virConnectPtr conn, char **const names, in return -1; }
+static int +networkListAllNetworks(virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags) +{ + struct network_driver *driver = conn->networkPrivateData; + int ret = -1; + + virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);
If you return with an error here, nets will be unset. Even though a *sane* caller would check the return value prior to dereferencing anything in nets, it would still be a good idea to to "*nets = NULL" before anything else. Otherwise, ACK.
+ + networkDriverLock(driver); + ret = virNetworkList(conn, driver->networks, nets, flags); + networkDriverUnlock(driver); + + return ret; +}
static int networkIsActive(virNetworkPtr net) { @@ -2689,6 +2706,7 @@ static virNetworkDriver networkDriver = { .listNetworks = networkListNetworks, /* 0.2.0 */ .numOfDefinedNetworks = networkNumDefinedNetworks, /* 0.2.0 */ .listDefinedNetworks = networkListDefinedNetworks, /* 0.2.0 */ + .listAllNetworks = networkListAllNetworks, /* 0.9.14 */ .networkLookupByUUID = networkLookupByUUID, /* 0.2.0 */ .networkLookupByName = networkLookupByName, /* 0.2.0 */ .networkCreateXML = networkCreate, /* 0.2.0 */

On 07/23/2012 03:12 PM, Laine Stump wrote:
On 07/20/2012 10:25 AM, Osier Yang wrote:
src/network/bridge_driver.c: Implement listAllNetworks. --- src/network/bridge_driver.c | 18 ++++++++++++++++++ 1 files changed, 18 insertions(+), 0 deletions(-)
+static int +networkListAllNetworks(virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags) +{ + struct network_driver *driver = conn->networkPrivateData; + int ret = -1; + + virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);
If you return with an error here, nets will be unset. Even though a *sane* caller would check the return value prior to dereferencing anything in nets, it would still be a good idea to to "*nets = NULL" before anything else.
Then again. libvirt.c _already_ did *nets=NULL before getting into this driver callback. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

src/test/test_driver.c: Implement listAllNetworks. --- src/test/test_driver.c | 17 +++++++++++++++++ 1 files changed, 17 insertions(+), 0 deletions(-) diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 9b528f2..ed8cd47 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -3037,6 +3037,22 @@ no_memory: return -1; } +static int +testNetworkListAllNetworks(virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags) +{ + testConnPtr privconn = conn->privateData; + int ret = -1; + + virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1); + + testDriverLock(privconn); + ret = virNetworkList(conn, privconn->networks, nets, flags); + testDriverUnlock(privconn); + + return ret; +} static int testNetworkIsActive(virNetworkPtr net) { @@ -5696,6 +5712,7 @@ static virNetworkDriver testNetworkDriver = { .listNetworks = testListNetworks, /* 0.3.2 */ .numOfDefinedNetworks = testNumDefinedNetworks, /* 0.3.2 */ .listDefinedNetworks = testListDefinedNetworks, /* 0.3.2 */ + .listAllNetworks = testNetworkListAllNetworks, /* 0.9.14 */ .networkLookupByUUID = testLookupNetworkByUUID, /* 0.3.2 */ .networkLookupByName = testLookupNetworkByName, /* 0.3.2 */ .networkCreateXML = testNetworkCreate, /* 0.3.2 */ -- 1.7.7.3

On 07/20/2012 10:25 AM, Osier Yang wrote:
src/test/test_driver.c: Implement listAllNetworks. --- src/test/test_driver.c | 17 +++++++++++++++++ 1 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 9b528f2..ed8cd47 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -3037,6 +3037,22 @@ no_memory: return -1; }
+static int +testNetworkListAllNetworks(virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags) +{ + testConnPtr privconn = conn->privateData; + int ret = -1;
Same comment as the bridge driver about initializing *nets, otherwise ACK.
+ + virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1); + + testDriverLock(privconn); + ret = virNetworkList(conn, privconn->networks, nets, flags); + testDriverUnlock(privconn); + + return ret; +}
static int testNetworkIsActive(virNetworkPtr net) { @@ -5696,6 +5712,7 @@ static virNetworkDriver testNetworkDriver = { .listNetworks = testListNetworks, /* 0.3.2 */ .numOfDefinedNetworks = testNumDefinedNetworks, /* 0.3.2 */ .listDefinedNetworks = testListDefinedNetworks, /* 0.3.2 */ + .listAllNetworks = testNetworkListAllNetworks, /* 0.9.14 */ .networkLookupByUUID = testLookupNetworkByUUID, /* 0.3.2 */ .networkLookupByName = testLookupNetworkByName, /* 0.3.2 */ .networkCreateXML = testNetworkCreate, /* 0.3.2 */

tools/virsh.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. --- tools/virsh.c | 347 +++++++++++++++++++++++++++++++++++++++++-------------- tools/virsh.pod | 12 ++- 2 files changed, 273 insertions(+), 86 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 9556e16..fb12d80 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -8862,6 +8862,227 @@ cleanup: return ret; } +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 strcasecmp(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.9.14 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) { + virFreeError(last_error); + last_error = NULL; + 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); + + virFreeError(last_error); + last_error = NULL; + 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) */ + virResetLastError(); + + /* 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 */ @@ -8874,117 +9095,73 @@ 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 (!vshConnectionUsability(ctl, ctl->conn)) return false; - 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]); - const char *autostartStr; - int autostart = 0; + if (no_autostart) + flags |= VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART; - /* this kind of work with networks is not atomic operation */ - if (!network) { - VIR_FREE(activeNames[i]); - continue; - } + if (!(list = vshNetworkListCollect(ctl, flags))) + return false; - if (virNetworkGetAutostart(network, &autostart) < 0) - autostartStr = _("no autostart"); - else - autostartStr = autostart ? _("yes") : _("no"); + vshPrintExtra(ctl, "%-20s %-10s %-13s %s\n", _("Name"), _("State"), + _("Autostart"), _("Persistent")); + vshPrintExtra(ctl, "--------------------------------------------------\n"); - vshPrint(ctl, "%-20s %-10s %-10s\n", - virNetworkGetName(network), - _("active"), - autostartStr); - virNetworkFree(network); - VIR_FREE(activeNames[i]); - } - for (i = 0; i < maxinactive; i++) { - virNetworkPtr network = virNetworkLookupByName(ctl->conn, inactiveNames[i]); + for (i = 0; i < list->nnets; i++) { + virNetworkPtr network = list->nets[i]; const char *autostartStr; - int autostart = 0; - - /* this kind of work with networks is not atomic operation */ - if (!network) { - VIR_FREE(inactiveNames[i]); - continue; - } + int is_autostart = 0; - if (virNetworkGetAutostart(network, &autostart) < 0) + if (virNetworkGetAutostart(network, &is_autostart) < 0) autostartStr = _("no autostart"); else - autostartStr = autostart ? _("yes") : _("no"); - - vshPrint(ctl, "%-20s %-10s %-10s\n", - inactiveNames[i], - _("inactive"), - autostartStr); + autostartStr = is_autostart ? _("yes") : _("no"); - virNetworkFree(network); - VIR_FREE(inactiveNames[i]); + vshPrint(ctl, "%-20s %-10s %-13s %s\n", + virNetworkGetName(network), + virNetworkIsActive(network) ? _("active") : _("inactive"), + autostartStr, + virNetworkIsPersistent(network) ? _("yes") : _("no")); } - VIR_FREE(activeNames); - VIR_FREE(inactiveNames); + + vshNetworkListFree(list); return true; } diff --git a/tools/virsh.pod b/tools/virsh.pod index b88df9c..750114c 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1902,10 +1902,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> -- 1.7.7.3

The implementation is done manually as the generator does not support wrapping lists of C pointers into Python objects. python/libvirt-override-api.xml: Document python/libvirt-override-virConnect.py: Implement listAllNetworks. python/libvirt-override.c: Implementation for the wrapper. --- python/libvirt-override-api.xml | 6 ++++ python/libvirt-override-virConnect.py | 12 ++++++++ python/libvirt-override.c | 48 +++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 0 deletions(-) diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index 8a228fb..5f51fc7 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -37,6 +37,12 @@ <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> <return type='str *' info='the list of Names or None in case of error'/> </function> + <function name='virConnectListAllNetworks' file='python'> + <info>returns list of all networks</info> + <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> + <arg name='flags' type='unsigned int' info='optional flags'/> + <return type='network *' info='the list of networks or None in case of error'/> + </function> <function name='virDomainLookupByUUID' file='python'> <info>Try to lookup a domain on the given hypervisor based on its UUID.</info> <return type='virDomainPtr' info='a new domain object or NULL in case of failure'/> diff --git a/python/libvirt-override-virConnect.py b/python/libvirt-override-virConnect.py index 87a737f..85db5fe 100644 --- a/python/libvirt-override-virConnect.py +++ b/python/libvirt-override-virConnect.py @@ -218,3 +218,15 @@ retlist.append(virStoragePool(self, _obj=poolptr)) return retlist + + def listAllNetworks(self, flags): + """Returns a list of network objects""" + ret = libvirtmod.virConnectListAllNetworks(self._o, flags) + if ret is None: + raise libvirtError("virConnectListAllNetworks() failed", conn=self) + + retlist = list() + for netptr in ret: + retlist.append(virNetwork(self, _obj=netptr)) + + return retlist diff --git a/python/libvirt-override.c b/python/libvirt-override.c index 322a8d2..5dd9657 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -2594,6 +2594,53 @@ libvirt_virConnectListDefinedNetworks(PyObject *self ATTRIBUTE_UNUSED, return py_retval; } +static PyObject * +libvirt_virConnectListAllNetworks(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + PyObject *pyobj_conn; + PyObject *py_retval = NULL; + PyObject *tmp = NULL; + virConnectPtr conn; + virNetworkPtr *nets = NULL; + int c_retval = 0; + int i; + unsigned int flags; + + if (!PyArg_ParseTuple(args, (char *)"Oi:virConnectListAllNetworks", + &pyobj_conn, &flags)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virConnectListAllNetworks(conn, &nets, flags); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) + return VIR_PY_NONE; + + if (!(py_retval = PyList_New(c_retval))) + goto cleanup; + + for (i = 0; i < c_retval; i++) { + if (!(tmp = libvirt_virNetworkPtrWrap(nets[i])) || + PyList_SetItem(py_retval, i, tmp) < 0) { + Py_XDECREF(tmp); + Py_DECREF(py_retval); + py_retval = NULL; + goto cleanup; + } + /* python steals the pointer */ + nets[i] = NULL; + } + +cleanup: + for (i = 0; i < c_retval; i++) + if (nets[i]) + virNetworkFree(nets[i]); + VIR_FREE(nets); + return py_retval; +} + static PyObject * libvirt_virNetworkGetUUID(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { @@ -5939,6 +5986,7 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virConnGetLastError", libvirt_virConnGetLastError, METH_VARARGS, NULL}, {(char *) "virConnectListNetworks", libvirt_virConnectListNetworks, METH_VARARGS, NULL}, {(char *) "virConnectListDefinedNetworks", libvirt_virConnectListDefinedNetworks, METH_VARARGS, NULL}, + {(char *) "virConnectListAllNetworks", libvirt_virConnectListAllNetworks, METH_VARARGS, NULL}, {(char *) "virNetworkGetUUID", libvirt_virNetworkGetUUID, METH_VARARGS, NULL}, {(char *) "virNetworkGetUUIDString", libvirt_virNetworkGetUUIDString, METH_VARARGS, NULL}, {(char *) "virNetworkLookupByUUID", libvirt_virNetworkLookupByUUID, METH_VARARGS, NULL}, -- 1.7.7.3

WITH_INTERFACE is not defined, it should be WITH_NETCF there to load the interface driver. Eric posted patch weeks ago to resolve the problems in the whole build system, but it's not finalised yet: https://www.redhat.com/archives/libvir-list/2012-June/msg01299.html I'm going to simply fix the wrong macro name here so that the interface driver could loaded, and continue the work on the listing API for interface driver. --- daemon/libvirtd.c | 2 +- tests/virdrivermoduletest.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 8c434a0..6dca9b0 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -378,7 +378,7 @@ static void daemonInitialize(void) # ifdef WITH_NWFILTER virDriverLoadModule("nwfilter"); # endif -# ifdef WITH_INTERFACE +# ifdef WITH_NETCF virDriverLoadModule("interface"); # endif # ifdef WITH_QEMU diff --git a/tests/virdrivermoduletest.c b/tests/virdrivermoduletest.c index 405574e..d1fd649 100644 --- a/tests/virdrivermoduletest.c +++ b/tests/virdrivermoduletest.c @@ -79,7 +79,7 @@ mymain(void) #ifdef WITH_NWFILTER TEST("nwfilter", NULL); #endif -#ifdef WITH_INTERFACE +#ifdef WITH_NETCF TEST("interface", NULL); #endif #ifdef WITH_QEMU -- 1.7.7.3

On 07/20/2012 10:25 PM, Osier Yang wrote:
WITH_INTERFACE is not defined, it should be WITH_NETCF there to load the interface driver.
Eric posted patch weeks ago to resolve the problems in the whole build system, but it's not finalised yet:
https://www.redhat.com/archives/libvir-list/2012-June/msg01299.html
I'm going to simply fix the wrong macro name here so that the interface driver could loaded, and continue the work on the listing API for interface driver. --- daemon/libvirtd.c | 2 +- tests/virdrivermoduletest.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 8c434a0..6dca9b0 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -378,7 +378,7 @@ static void daemonInitialize(void) # ifdef WITH_NWFILTER virDriverLoadModule("nwfilter"); # endif -# ifdef WITH_INTERFACE +# ifdef WITH_NETCF virDriverLoadModule("interface"); # endif # ifdef WITH_QEMU diff --git a/tests/virdrivermoduletest.c b/tests/virdrivermoduletest.c index 405574e..d1fd649 100644 --- a/tests/virdrivermoduletest.c +++ b/tests/virdrivermoduletest.c @@ -79,7 +79,7 @@ mymain(void) #ifdef WITH_NWFILTER TEST("nwfilter", NULL); #endif -#ifdef WITH_INTERFACE +#ifdef WITH_NETCF TEST("interface", NULL); #endif #ifdef WITH_QEMU
ACK, I need this patch, so I tested it, it's fine.

On 07/24/2012 08:05 AM, Guannan Ren wrote:
On 07/20/2012 10:25 PM, Osier Yang wrote:
WITH_INTERFACE is not defined, it should be WITH_NETCF there to load the interface driver.
Eric posted patch weeks ago to resolve the problems in the whole build system, but it's not finalised yet:
Indeed, I still need to find time to revisit that.
https://www.redhat.com/archives/libvir-list/2012-June/msg01299.html
I'm going to simply fix the wrong macro name here so that the interface driver could loaded, and continue the work on the listing API for interface driver. ---
-#ifdef WITH_INTERFACE +#ifdef WITH_NETCF TEST("interface", NULL); #endif #ifdef WITH_QEMU
ACK, I need this patch, so I tested it, it's fine.
And people are starting to complain about this in F17. I went ahead and pushed this patch now, so that we can get the fix into Fedora sooner rather than later while I still spend time on the more complete division of functionality between WITH_NETCF (library usage) vs. WITH_INTERFACE (driver module). -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

This is to list the interface objects, supported filtering flags are: active|inactive. include/libvirt/libvirt.h.in: Declare enum virConnectListAllInterfaceFlags and virConnectListAllInterfaces. python/generator.py: Skip auto-generating src/driver.h: (virDrvConnectListAllInterfaces) src/libvirt.c: Implement the public API src/libvirt_public.syms: Export the symbol to public --- include/libvirt/libvirt.h.in | 13 +++++++++ python/generator.py | 1 + src/driver.h | 5 +++ src/libvirt.c | 59 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 5 files changed, 79 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 15a9a1b..15e2363 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2303,6 +2303,19 @@ int virConnectNumOfDefinedInterfaces (virConnectPtr conn); int virConnectListDefinedInterfaces (virConnectPtr conn, char **const names, int maxnames); +/* + * virConnectListAllInterfaces: + * + * Flags used to filter the returned interfaces. + */ +typedef enum { + VIR_CONNECT_LIST_INTERFACES_INACTIVE = 1 << 0, + VIR_CONNECT_LIST_INTERFACES_ACTIVE = 1 << 1, +} virConnectListAllInterfacesFlags; + +int virConnectListAllInterfaces (virConnectPtr conn, + virInterfacePtr **ifaces, + unsigned int flags); virInterfacePtr virInterfaceLookupByName (virConnectPtr conn, const char *name); diff --git a/python/generator.py b/python/generator.py index 44b56c2..51c3fce 100755 --- a/python/generator.py +++ b/python/generator.py @@ -459,6 +459,7 @@ skip_function = ( 'virConnectListAllStoragePools', # overridden in virConnect.py 'virStoragePoolListAllVolumes', # overridden in virStoragePool.py 'virConnectListAllNetworks', # overridden in virConnect.py + 'virConnectListAllInterfaces', # overridden in virConnect.py 'virStreamRecvAll', # Pure python libvirt-override-virStream.py 'virStreamSendAll', # Pure python libvirt-override-virStream.py diff --git a/src/driver.h b/src/driver.h index 68a1f04..335ee86 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1146,6 +1146,10 @@ typedef int (*virDrvListDefinedInterfaces) (virConnectPtr conn, char **const names, int maxnames); +typedef int + (*virDrvListAllInterfaces) (virConnectPtr conn, + virInterfacePtr **ifaces, + unsigned int flags); typedef virInterfacePtr (*virDrvInterfaceLookupByName) (virConnectPtr conn, const char *name); @@ -1204,6 +1208,7 @@ struct _virInterfaceDriver { virDrvListInterfaces listInterfaces; virDrvNumOfDefinedInterfaces numOfDefinedInterfaces; virDrvListDefinedInterfaces listDefinedInterfaces; + virDrvListAllInterfaces listAllInterfaces; virDrvInterfaceLookupByName interfaceLookupByName; virDrvInterfaceLookupByMACString interfaceLookupByMACString; virDrvInterfaceGetXMLDesc interfaceGetXMLDesc; diff --git a/src/libvirt.c b/src/libvirt.c index 622a590..c50bb3d 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -10507,6 +10507,65 @@ virInterfaceGetConnect (virInterfacePtr iface) } /** + * virConnectListAllInterfaces: + * @conn: Pointer to the hypervisor connection. + * @ifaces: Pointer to a variable to store the array containing the interface + * objects or NULL if the list is not required (just returns number + * of interfaces). + * @flags: bitwise-OR of virConnectListAllInterfacesFlags. + * + * Collect the list of interfaces, and allocate an array to store those + * objects. This API solves the race inherent between virConnectListInterfaces + * and virConnectListDefinedInterfaces. + * + * By default, this API covers all interfaces; it is also possible to return + * the filtered objects with flags. Filters are provided in groups, where each + * group contains bits that describe mutually exclusive attributes of a interface. + * + * The only one group of @flags is VIR_CONNECT_LIST_INTERFACES_INACTIVE and + * VIR_CONNECT_LIST_INTERFACES_INACTIVE to fitler the interfaces by state. + * + * Returns the number of interfaces found or -1 and sets @ifaces to NULL in case + * of error. On success, the array stored into @ifaces is guaranteed to have an + * extra allocated element set to NULL but not included in the return count, + * to make iteration easier. The caller is responsible for calling + * virStorageInterfaceFree() on each array element, then calling free() on @ifaces. + */ +int +virConnectListAllInterfaces(virConnectPtr conn, + virInterfacePtr **ifaces, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, ifaces=%p, flags=%x", conn, ifaces, flags); + + virResetLastError(); + + if (ifaces) + *ifaces = NULL; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (conn->interfaceDriver && + conn->interfaceDriver->listAllInterfaces) { + int ret; + ret = conn->interfaceDriver->listAllInterfaces(conn, ifaces, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} + +/** * virConnectNumOfInterfaces: * @conn: pointer to the hypervisor connection * diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 0ce120a..298eaac 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -549,6 +549,7 @@ LIBVIRT_0.9.14 { virConnectListAllStoragePools; virStoragePoolListAllVolumes; virConnectListAllNetworks; + virConnectListAllInterfaces; } LIBVIRT_0.9.13; # .... define new API here using predicted next version number .... -- 1.7.7.3

The RPC generator doesn't support returning list of object yet, this patch do the work manually. * daemon/remote.c: Implemente the server side handler remoteDispatchConnectListAllInterfaces. * src/remote/remote_driver.c: Add remote driver handler remoteConnectListAllInterfaces. * src/remote/remote_protocol.x: New RPC procedure REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES and structs to represent the args and ret for it. * src/remote_protocol-structs: Likewise. --- daemon/remote.c | 54 +++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 64 ++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 13 ++++++++- src/remote_protocol-structs | 12 ++++++++ 4 files changed, 142 insertions(+), 1 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index d5c4b90..aec7b3c 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -4118,6 +4118,60 @@ cleanup: return rv; } +static int +remoteDispatchConnectListAllInterfaces(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_connect_list_all_interfaces_args *args, + remote_connect_list_all_interfaces_ret *ret) +{ + virInterfacePtr *ifaces = NULL; + int nifaces = 0; + int i; + int rv = -1; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if ((nifaces = virConnectListAllInterfaces(priv->conn, + args->need_results ? &ifaces : NULL, + args->flags)) < 0) + goto cleanup; + + if (ifaces && nifaces) { + if (VIR_ALLOC_N(ret->ifaces.ifaces_val, nifaces) < 0) { + virReportOOMError(); + goto cleanup; + } + + ret->ifaces.ifaces_len = nifaces; + + for (i = 0; i < nifaces; i++) + make_nonnull_interface(ret->ifaces.ifaces_val + i, ifaces[i]); + } else { + ret->ifaces.ifaces_len = 0; + ret->ifaces.ifaces_val = NULL; + } + + ret->ret = nifaces; + + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (ifaces) { + for (i = 0; i < nifaces; i++) + virInterfaceFree(ifaces[i]); + VIR_FREE(ifaces); + } + return rv; +} + /*----- Helpers. -----*/ diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index afe6e60..2b7c05e 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -2842,6 +2842,69 @@ done: return rv; } +static int +remoteConnectListAllInterfaces(virConnectPtr conn, + virInterfacePtr **ifaces, + unsigned int flags) +{ + int rv = -1; + int i; + virInterfacePtr *tmp_ifaces = NULL; + remote_connect_list_all_interfaces_args args; + remote_connect_list_all_interfaces_ret ret; + + struct private_data *priv = conn->privateData; + + remoteDriverLock(priv); + + args.need_results = !!ifaces; + args.flags = flags; + + memset(&ret, 0, sizeof(ret)); + if (call(conn, + priv, + 0, + REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES, + (xdrproc_t) xdr_remote_connect_list_all_interfaces_args, + (char *) &args, + (xdrproc_t) xdr_remote_connect_list_all_interfaces_ret, + (char *) &ret) == -1) + goto done; + + if (ifaces) { + if (VIR_ALLOC_N(tmp_ifaces, ret.ifaces.ifaces_len + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + for (i = 0; i < ret.ifaces.ifaces_len; i++) { + tmp_ifaces[i] = get_nonnull_interface (conn, ret.ifaces.ifaces_val[i]); + if (!tmp_ifaces[i]) { + virReportOOMError(); + goto cleanup; + } + } + *ifaces = tmp_ifaces; + tmp_ifaces = NULL; + } + + rv = ret.ret; + +cleanup: + if (tmp_ifaces) { + for (i = 0; i < ret.ifaces.ifaces_len; i++) + if (tmp_ifaces[i]) + virInterfaceFree(tmp_ifaces[i]); + VIR_FREE(tmp_ifaces); + } + + xdr_free((xdrproc_t) xdr_remote_connect_list_all_interfaces_ret, (char *) &ret); + +done: + remoteDriverUnlock(priv); + return rv; +} + /*----------------------------------------------------------------------*/ @@ -5572,6 +5635,7 @@ static virInterfaceDriver interface_driver = { .listInterfaces = remoteListInterfaces, /* 0.7.2 */ .numOfDefinedInterfaces = remoteNumOfDefinedInterfaces, /* 0.7.2 */ .listDefinedInterfaces = remoteListDefinedInterfaces, /* 0.7.2 */ + .listAllInterfaces = remoteConnectListAllInterfaces, /* 0.9.14 */ .interfaceLookupByName = remoteInterfaceLookupByName, /* 0.7.2 */ .interfaceLookupByMACString = remoteInterfaceLookupByMACString, /* 0.7.2 */ .interfaceGetXMLDesc = remoteInterfaceGetXMLDesc, /* 0.7.2 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 897775c..e4f0d62 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1409,6 +1409,16 @@ struct remote_list_defined_interfaces_ret { remote_nonnull_string names<REMOTE_DEFINED_INTERFACE_NAME_LIST_MAX>; /* insert@1 */ }; +struct remote_connect_list_all_interfaces_args { + int need_results; + unsigned int flags; +}; + +struct remote_connect_list_all_interfaces_ret { + remote_nonnull_interface ifaces<>; + unsigned int ret; +}; + struct remote_interface_lookup_by_name_args { remote_nonnull_string name; }; @@ -2875,7 +2885,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE = 276, /* autogen autogen */ REMOTE_PROC_CONNECT_LIST_ALL_STORAGE_POOLS = 277, /* skipgen skipgen priority:high */ REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES = 278, /* skipgen skipgen priority:high */ - REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS = 279 /* skipgen skipgen priority:high */ + REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS = 279, /* skipgen skipgen priority:high */ + REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 280 /* skipgen skipgen priority:high */ /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 315ec7f..2640fd1 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1036,6 +1036,17 @@ struct remote_list_defined_interfaces_ret { remote_nonnull_string * names_val; } names; }; +struct remote_connect_list_all_interfaces_args { + int need_results; + u_int flags; +}; +struct remote_connect_list_all_interfaces_ret { + struct { + u_int ifaces_len; + remote_nonnull_interface * ifaces_val; + } pools; + u_int ret; +}; struct remote_interface_lookup_by_name_args { remote_nonnull_string name; }; @@ -2288,4 +2299,5 @@ enum remote_procedure { REMOTE_PROC_CONNECT_LIST_ALL_STORAGE_POOLS = 277, REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES = 278, REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS = 279, + REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 280, }; -- 1.7.7.3

This is not that ideal as API for other objects, as it's still O(n). Because interface driver uses netcf APIs to manage the stuffs, instead of by itself. And netcf APIs don't return a object. It provides APIs like old libvirt APIs: ncf_number_of_interfaces ncf_list_interfaces ncf_lookup_by_name ...... Perhaps we should further hack netcf to let it provide an API to return the object, but it could be a later patch. And anyway, we will still befinit from the new API for the simplification, and no race like the old APIs. src/interface/netcf_driver.c: Implement listAllInterfaces --- src/interface/netcf_driver.c | 135 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 135 insertions(+), 0 deletions(-) diff --git a/src/interface/netcf_driver.c b/src/interface/netcf_driver.c index 39fa721..ea3eef2 100644 --- a/src/interface/netcf_driver.c +++ b/src/interface/netcf_driver.c @@ -259,6 +259,140 @@ static int interfaceListDefinedInterfaces(virConnectPtr conn, char **const names } +static int +interfaceListAllInterfaces(virConnectPtr conn, + virInterfacePtr **ifaces, + unsigned int flags) +{ + struct interface_driver *driver = conn->interfacePrivateData; + int count; + int i; + struct netcf_if *iface = NULL; + virInterfacePtr *tmp_iface_objs = NULL; + virInterfacePtr iface_obj = NULL; + unsigned int status; + int niface_objs = 0; + int ret = -1; + char **names; + + virCheckFlags(VIR_CONNECT_LIST_INTERFACES_ACTIVE | + VIR_CONNECT_LIST_INTERFACES_INACTIVE, -1); + + interfaceDriverLock(driver); + + /* List all interfaces, in case of we might support new filter flags + * except active|inactive in future. + */ + count = ncf_num_of_interfaces(driver->netcf, NETCF_IFACE_ACTIVE | + NETCF_IFACE_INACTIVE); + if (count < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + virReportError(netcf_to_vir_err(errcode), + _("failed to get number of host interfaces: %s%s%s"), + errmsg, details ? " - " : "", + details ? details : ""); + return -1; + } + + if (count == 0) + return 0; + + if (VIR_ALLOC_N(names, count) < 0) { + virReportOOMError(); + return -1; + } + + if ((count = ncf_list_interfaces(driver->netcf, count, names, + NETCF_IFACE_ACTIVE | + NETCF_IFACE_INACTIVE)) < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + virReportError(netcf_to_vir_err(errcode), + _("failed to list host interfaces: %s%s%s"), + errmsg, details ? " - " : "", + details ? details : ""); + goto cleanup; + } + + if (ifaces) { + if (VIR_ALLOC_N(tmp_iface_objs, count + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + } + + for (i = 0; i < count; i++) { + iface = ncf_lookup_by_name(driver->netcf, names[i]); + if (!iface) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + if (errcode != NETCF_NOERROR) { + virReportError(netcf_to_vir_err(errcode), + _("couldn't find interface named '%s': %s%s%s"), + names[i], errmsg, + details ? " - " : "", details ? details : ""); + } else { + virReportError(VIR_ERR_NO_INTERFACE, + _("couldn't find interface named '%s'"), names[i]); + } + goto cleanup; + } + + if (ncf_if_status(iface, &status) < 0) { + const char *errmsg, *details; + int errcode = ncf_error(driver->netcf, &errmsg, &details); + virReportError(netcf_to_vir_err(errcode), + _("failed to get status of interface %s: %s%s%s"), + names[i], errmsg, details ? " - " : "", + details ? details : ""); + goto cleanup; + } + + /* XXX: Filter the result, need to be splitted once new fitler flags + * except active|inactive are supported. + */ + if (((status & NETCF_IFACE_ACTIVE) && + (flags & VIR_CONNECT_LIST_INTERFACES_ACTIVE)) || + ((status & NETCF_IFACE_INACTIVE) && + (flags & VIR_CONNECT_LIST_INTERFACES_INACTIVE))) { + if (ifaces) { + iface_obj = virGetInterface(conn, ncf_if_name(iface), + ncf_if_mac_string(iface)); + tmp_iface_objs[niface_objs] = iface_obj; + } + niface_objs++; + } + } + + if (tmp_iface_objs) { + /* trim the array to the final size */ + ignore_value(VIR_REALLOC_N(tmp_iface_objs, niface_objs + 1)); + *ifaces = tmp_iface_objs; + tmp_iface_objs = NULL; + } + + ret = niface_objs; + +cleanup: + ncf_if_free(iface); + + for (i = 0; i < count; i++) + VIR_FREE(names[i]); + VIR_FREE(names); + + if (tmp_iface_objs) { + for (i = 0; i < count; i++) { + if (tmp_iface_objs[i]) + virInterfaceFree(tmp_iface_objs[i]); + } + } + + interfaceDriverUnlock(driver); + return ret; +} + + static virInterfacePtr interfaceLookupByName(virConnectPtr conn, const char *name) { @@ -642,6 +776,7 @@ static virInterfaceDriver interfaceDriver = { .listInterfaces = interfaceListInterfaces, /* 0.7.0 */ .numOfDefinedInterfaces = interfaceNumOfDefinedInterfaces, /* 0.7.0 */ .listDefinedInterfaces = interfaceListDefinedInterfaces, /* 0.7.0 */ + .listAllInterfaces = interfaceListAllInterfaces, /* 0.9.14 */ .interfaceLookupByName = interfaceLookupByName, /* 0.7.0 */ .interfaceLookupByMACString = interfaceLookupByMACString, /* 0.7.0 */ .interfaceGetXMLDesc = interfaceGetXMLDesc, /* 0.7.0 */ -- 1.7.7.3

tools/virsh.c: * vshInterfaceSorter to sort interfaces by name * vshInterfaceListFree to free the interface objects list. * vshInterfaceListCollect to collect the interface objects, trying to use new API first, fall back to older APIs if it's not supported. --- tools/virsh.c | 258 ++++++++++++++++++++++++++++++++++++++++----------------- 1 files changed, 183 insertions(+), 75 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index fb12d80..8e191f4 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -9310,6 +9310,174 @@ cmdNetworkUuid(vshControl *ctl, const vshCmd *cmd) return true; } +static int +vshInterfaceSorter(const void *a, const void *b) +{ + virInterfacePtr *ia = (virInterfacePtr *) a; + virInterfacePtr *ib = (virInterfacePtr *) b; + + if (*ia && !*ib) + return -1; + + if (!*ia) + return *ib != NULL; + + return strcasecmp(virInterfaceGetName(*ia), + virInterfaceGetName(*ib)); +} + +struct vshInterfaceList { + virInterfacePtr *ifaces; + size_t nifaces; +}; +typedef struct vshInterfaceList *vshInterfaceListPtr; + +static void +vshInterfaceListFree(vshInterfaceListPtr list) +{ + int i; + + if (list && list->nifaces) { + for (i = 0; i < list->nifaces; i++) { + if (list->ifaces[i]) + virInterfaceFree(list->ifaces[i]); + } + VIR_FREE(list->ifaces); + } + VIR_FREE(list); +} + +static vshInterfaceListPtr +vshInterfaceListCollect(vshControl *ctl, + unsigned int flags) +{ + vshInterfaceListPtr list = vshMalloc(ctl, sizeof(*list)); + int i; + int ret; + char **activeNames = NULL; + char **inactiveNames = NULL; + virInterfacePtr iface; + bool success = false; + size_t deleted = 0; + int nActiveIfaces = 0; + int nInactiveIfaces = 0; + int nAllIfaces = 0; + + /* try the list with flags support (0.9.14 and later) */ + if ((ret = virConnectListAllInterfaces(ctl->conn, + &list->ifaces, + flags)) >= 0) { + list->nifaces = ret; + goto finished; + } + + /* check if the command is actually supported */ + if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) { + virFreeError(last_error); + last_error = NULL; + goto fallback; + } + + /* there was an error during the first or second call */ + vshError(ctl, "%s", _("Failed to list interfaces")); + goto cleanup; + + +fallback: + /* fall back to old method (0.9.13 and older) */ + virResetLastError(); + + if (flags & VIR_CONNECT_LIST_INTERFACES_ACTIVE) { + nActiveIfaces = virConnectNumOfInterfaces(ctl->conn); + if (nActiveIfaces < 0) { + vshError(ctl, "%s", _("Failed to list active interfaces")); + goto cleanup; + } + if (nActiveIfaces) { + activeNames = vshMalloc(ctl, sizeof(char *) * nActiveIfaces); + + if ((nActiveIfaces = virConnectListInterfaces(ctl->conn, activeNames, + nActiveIfaces)) < 0) { + vshError(ctl, "%s", _("Failed to list active interfaces")); + goto cleanup; + } + } + } + + if (flags & VIR_CONNECT_LIST_INTERFACES_INACTIVE) { + nInactiveIfaces = virConnectNumOfDefinedInterfaces(ctl->conn); + if (nInactiveIfaces < 0) { + vshError(ctl, "%s", _("Failed to list inactive interfaces")); + goto cleanup; + } + if (nInactiveIfaces) { + inactiveNames = vshMalloc(ctl, sizeof(char *) * nInactiveIfaces); + + if ((nInactiveIfaces = + virConnectListDefinedInterfaces(ctl->conn, inactiveNames, + nInactiveIfaces)) < 0) { + vshError(ctl, "%s", _("Failed to list inactive interfaces")); + goto cleanup; + } + } + } + + nAllIfaces = nActiveIfaces + nInactiveIfaces; + if (nAllIfaces == 0) { + VIR_FREE(activeNames); + VIR_FREE(inactiveNames); + return list; + } + + list->ifaces = vshMalloc(ctl, sizeof(virInterfacePtr) * (nAllIfaces)); + list->nifaces = 0; + + /* get active interfaces */ + for (i = 0; i < nActiveIfaces; i++) { + if (!(iface = virInterfaceLookupByName(ctl->conn, activeNames[i]))) + continue; + list->ifaces[list->nifaces++] = iface; + } + + /* get inactive interfaces */ + for (i = 0; i < nInactiveIfaces; i++) { + if (!(iface = virInterfaceLookupByName(ctl->conn, inactiveNames[i]))) + continue; + list->ifaces[list->nifaces++] = iface; + } + + /* truncate interfaces that weren't found */ + deleted = nAllIfaces - list->nifaces; + +finished: + /* sort the list */ + if (list->ifaces && list->nifaces) + qsort(list->ifaces, list->nifaces, + sizeof(*list->ifaces), vshInterfaceSorter); + + /* truncate the list if filter simulation deleted entries */ + if (deleted) + VIR_SHRINK_N(list->ifaces, list->nifaces, deleted); + + success = true; + +cleanup: + for (i = 0; i < nActiveIfaces; i++) + VIR_FREE(activeNames[i]); + + for (i = 0; i < nInactiveIfaces; i++) + VIR_FREE(inactiveNames[i]); + + VIR_FREE(activeNames); + VIR_FREE(inactiveNames); + + if (!success) { + vshInterfaceListFree(list); + list = NULL; + } + + return list; +} /**************************************************************************/ /* @@ -9331,97 +9499,37 @@ cmdInterfaceList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) { 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; + unsigned int flags = VIR_CONNECT_LIST_INTERFACES_ACTIVE; + vshInterfaceListPtr list = NULL; + int i; + + if (inactive) + flags = VIR_CONNECT_LIST_INTERFACES_INACTIVE; + if (all) + flags = VIR_CONNECT_LIST_INTERFACES_INACTIVE | + VIR_CONNECT_LIST_INTERFACES_ACTIVE; if (!vshConnectionUsability(ctl, ctl->conn)) return false; - if (active) { - maxactive = virConnectNumOfInterfaces(ctl->conn); - if (maxactive < 0) { - vshError(ctl, "%s", _("Failed to list active interfaces")); - return false; - } - if (maxactive) { - activeNames = vshMalloc(ctl, sizeof(char *) * maxactive); - - if ((maxactive = virConnectListInterfaces(ctl->conn, activeNames, - maxactive)) < 0) { - vshError(ctl, "%s", _("Failed to list active interfaces")); - VIR_FREE(activeNames); - return false; - } - - qsort(&activeNames[0], maxactive, sizeof(char *), vshNameSorter); - } - } - if (inactive) { - maxinactive = virConnectNumOfDefinedInterfaces(ctl->conn); - if (maxinactive < 0) { - vshError(ctl, "%s", _("Failed to list inactive interfaces")); - VIR_FREE(activeNames); - return false; - } - if (maxinactive) { - inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive); - - if ((maxinactive = - virConnectListDefinedInterfaces(ctl->conn, inactiveNames, - maxinactive)) < 0) { - vshError(ctl, "%s", _("Failed to list inactive interfaces")); - VIR_FREE(activeNames); - VIR_FREE(inactiveNames); - return false; - } + if (!(list = vshInterfaceListCollect(ctl, flags))) + return false; - qsort(&inactiveNames[0], maxinactive, sizeof(char*), vshNameSorter); - } - } vshPrintExtra(ctl, "%-20s %-10s %s\n", _("Name"), _("State"), _("MAC Address")); vshPrintExtra(ctl, "--------------------------------------------\n"); - for (i = 0; i < maxactive; i++) { - virInterfacePtr iface = - virInterfaceLookupByName(ctl->conn, activeNames[i]); - - /* this kind of work with interfaces is not atomic */ - if (!iface) { - VIR_FREE(activeNames[i]); - continue; - } + for (i = 0; i < list->nifaces; i++) { + virInterfacePtr iface = list->ifaces[i]; vshPrint(ctl, "%-20s %-10s %s\n", virInterfaceGetName(iface), - _("active"), + virInterfaceIsActive(iface) ? _("active") : _("inactive"), virInterfaceGetMACString(iface)); - virInterfaceFree(iface); - VIR_FREE(activeNames[i]); } - for (i = 0; i < maxinactive; i++) { - virInterfacePtr iface = - virInterfaceLookupByName(ctl->conn, inactiveNames[i]); - /* this kind of work with interfaces is not atomic */ - if (!iface) { - VIR_FREE(inactiveNames[i]); - continue; - } - - vshPrint(ctl, "%-20s %-10s %s\n", - virInterfaceGetName(iface), - _("inactive"), - virInterfaceGetMACString(iface)); - virInterfaceFree(iface); - VIR_FREE(inactiveNames[i]); - } - VIR_FREE(activeNames); - VIR_FREE(inactiveNames); + vshInterfaceListFree(list); return true; - } /* -- 1.7.7.3

The implementation is done manually as the generator does not support wrapping lists of C pointers into Python objects. python/libvirt-override-api.xml: Document python/libvirt-override-virConnect.py: * New file, includes implementation of listAllInterfaces. python/libvirt-override.c: Implementation for the wrapper. --- python/libvirt-override-api.xml | 6 ++++ python/libvirt-override-virConnect.py | 12 ++++++++ python/libvirt-override.c | 48 +++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 0 deletions(-) diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index 5f51fc7..ab6f407 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -416,6 +416,12 @@ <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> <return type='str *' info='the list of Names of None in case of error'/> </function> + <function name='virConnectListAllInterfaces' file='python'> + <info>returns list of all interfaces</info> + <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> + <arg name='flags' type='unsigned int' info='optional flags'/> + <return type='interface *' info='the list of interfaces or None in case of error'/> + </function> <function name='virConnectBaselineCPU' file='python'> <info>Computes the most feature-rich CPU which is compatible with all given host CPUs.</info> <return type='char *' info='XML description of the computed CPU or NULL on error.'/> diff --git a/python/libvirt-override-virConnect.py b/python/libvirt-override-virConnect.py index 85db5fe..ffa1a3c 100644 --- a/python/libvirt-override-virConnect.py +++ b/python/libvirt-override-virConnect.py @@ -230,3 +230,15 @@ retlist.append(virNetwork(self, _obj=netptr)) return retlist + + def listAllInterfaces(self, flags): + """Returns a list of interface objects""" + ret = libvirtmod.virConnectListAllInterfaces(self._o, flags) + if ret is None: + raise libvirtError("virConnectListAllInterfaces() failed", conn=self) + + retlist = list() + for ifaceptr in ret: + retlist.append(virInterface(self, _obj=ifaceptr)) + + return retlist diff --git a/python/libvirt-override.c b/python/libvirt-override.c index 5dd9657..98ed40f 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -3824,6 +3824,53 @@ libvirt_virConnectListDefinedInterfaces(PyObject *self ATTRIBUTE_UNUSED, static PyObject * +libvirt_virConnectListAllInterfaces(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + PyObject *pyobj_conn; + PyObject *py_retval = NULL; + PyObject *tmp = NULL; + virConnectPtr conn; + virInterfacePtr *ifaces = NULL; + int c_retval = 0; + int i; + unsigned int flags; + + if (!PyArg_ParseTuple(args, (char *)"Oi:virConnectListAllInterfaces", + &pyobj_conn, &flags)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virConnectListAllInterfaces(conn, &ifaces, flags); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) + return VIR_PY_NONE; + + if (!(py_retval = PyList_New(c_retval))) + goto cleanup; + + for (i = 0; i < c_retval; i++) { + if (!(tmp = libvirt_virInterfacePtrWrap(ifaces[i])) || + PyList_SetItem(py_retval, i, tmp) < 0) { + Py_XDECREF(tmp); + Py_DECREF(py_retval); + py_retval = NULL; + goto cleanup; + } + /* python steals the pointer */ + ifaces[i] = NULL; + } + +cleanup: + for (i = 0; i < c_retval; i++) + if (ifaces[i]) + virInterfaceFree(ifaces[i]); + VIR_FREE(ifaces); + return py_retval; +} + +static PyObject * libvirt_virConnectBaselineCPU(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { PyObject *pyobj_conn; @@ -6045,6 +6092,7 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virConnectListNWFilters", libvirt_virConnectListNWFilters, METH_VARARGS, NULL}, {(char *) "virConnectListInterfaces", libvirt_virConnectListInterfaces, METH_VARARGS, NULL}, {(char *) "virConnectListDefinedInterfaces", libvirt_virConnectListDefinedInterfaces, METH_VARARGS, NULL}, + {(char *) "virConnectListAllInterfaces", libvirt_virConnectListAllInterfaces, METH_VARARGS, NULL}, {(char *) "virConnectBaselineCPU", libvirt_virConnectBaselineCPU, METH_VARARGS, NULL}, {(char *) "virDomainGetJobInfo", libvirt_virDomainGetJobInfo, METH_VARARGS, NULL}, {(char *) "virDomainSnapshotListNames", libvirt_virDomainSnapshotListNames, METH_VARARGS, NULL}, -- 1.7.7.3

This is to list the node device objects, supports to filter the results by capability types. include/libvirt/libvirt.h.in: Declare enum virConnectListAllNodeDeviceFlags and virConnectListAllNodeDevices. python/generator.py: Skip auto-generating src/driver.h: (virDrvConnectListAllNodeDevices) src/libvirt.c: Implement the public API src/libvirt_public.syms: Export the symbol to public --- include/libvirt/libvirt.h.in | 25 +++++++++++++++++ python/generator.py | 1 + src/driver.h | 4 +++ src/libvirt.c | 59 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 5 files changed, 90 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 15e2363..cfdb162 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2750,6 +2750,31 @@ int virNodeListDevices (virConnectPtr conn, char **const names, int maxnames, unsigned int flags); +/* + * virConnectListAllNodeDevices: + * + * Flags used to filter the returned node devices. Flags in each group + * are exclusive. + */ +typedef enum { + /* Reserved the first 6 bits for the possibility of persistent + * node device support in future. + */ + + VIR_CONNECT_LIST_NODE_DEVICES_CAP_SYSTEM = 1 << 6, + VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV = 1 << 7, + VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_DEV = 1 << 8, + VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_INTERFACE = 1 << 9, + VIR_CONNECT_LIST_NODE_DEVICES_CAP_NET = 1 << 10, + VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_HOST = 1 << 11, + VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_TARGET = 1 << 12, + VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI = 1 << 13, + VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE = 1 << 14, +} virConnectListAllNodeDeviceFlags; + +int virConnectListAllNodeDevices (virConnectPtr conn, + virNodeDevicePtr **devices, + unsigned int flags); virNodeDevicePtr virNodeDeviceLookupByName (virConnectPtr conn, const char *name); diff --git a/python/generator.py b/python/generator.py index 51c3fce..6f50fa0 100755 --- a/python/generator.py +++ b/python/generator.py @@ -460,6 +460,7 @@ skip_function = ( 'virStoragePoolListAllVolumes', # overridden in virStoragePool.py 'virConnectListAllNetworks', # overridden in virConnect.py 'virConnectListAllInterfaces', # overridden in virConnect.py + 'virConnectListAllNodeDevices', # overridden in virConnect.py 'virStreamRecvAll', # Pure python libvirt-override-virStream.py 'virStreamSendAll', # Pure python libvirt-override-virStream.py diff --git a/src/driver.h b/src/driver.h index 335ee86..102684c 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1456,6 +1456,9 @@ typedef int (*virDevMonListDevices)(virConnectPtr conn, char **const names, int maxnames, unsigned int flags); +typedef int (*virDevMonListAllNodeDevices)(virConnectPtr conn, + virNodeDevicePtr **devices, + unsigned int flags); typedef virNodeDevicePtr (*virDevMonDeviceLookupByName)(virConnectPtr conn, const char *name); @@ -1489,6 +1492,7 @@ struct _virDeviceMonitor { virDrvClose close; virDevMonNumOfDevices numOfDevices; virDevMonListDevices listDevices; + virDevMonListAllNodeDevices listAllNodeDevices; virDevMonDeviceLookupByName deviceLookupByName; virDevMonDeviceGetXMLDesc deviceGetXMLDesc; virDevMonDeviceGetParent deviceGetParent; diff --git a/src/libvirt.c b/src/libvirt.c index c50bb3d..6d4cd76 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -13559,6 +13559,65 @@ error: return -1; } +/** + * virConnectListAllNodeDevices: + * @conn: Pointer to the hypervisor connection. + * @devices: Pointer to a variable to store the array containing the node + * device objects or NULL if the list is not required (just returns + * number of node devices). + * @flags: bitwise-OR of virConnectListAllNodeDevices. + * + * Collect the list of node devices, and allocate an array to store those + * objects. + * + * By default, this API covers all node devices; it is also possible to return + * the filtered objects with flags. Filters are provided in groups, where each + * group contains bits that describe mutually exclusive attributes of a node + * device. + * + * Only one group of the @flags is supported. It supports to filter the node + * devices by capability type. + * + * Returns the number of node devices found or -1 and sets @devices to NULL in + * case of error. On success, the array stored into @devices is guaranteed to + * have an extra allocated element set to NULL but not included in the return + * count, to make iteration easier. The caller is responsible for calling + * virNodeDeviceFree() on each array element, then calling free() on + * @devices. + */ +int +virConnectListAllNodeDevices(virConnectPtr conn, + virNodeDevicePtr **devices, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, devices=%p, flags=%x", conn, devices, flags); + + virResetLastError(); + + if (devices) + *devices = NULL; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (conn->deviceMonitor && + conn->deviceMonitor->listAllNodeDevices) { + int ret; + ret = conn->deviceMonitor->listAllNodeDevices(conn, devices, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} /** * virNodeListDevices: diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 298eaac..d45e38f 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -550,6 +550,7 @@ LIBVIRT_0.9.14 { virStoragePoolListAllVolumes; virConnectListAllNetworks; virConnectListAllInterfaces; + virConnectListAllNodeDevices; } LIBVIRT_0.9.13; # .... define new API here using predicted next version number .... -- 1.7.7.3

The RPC generator doesn't support returning list of object yet, this patch do the work manually. * daemon/remote.c: Implemente the server side handler remoteDispatchConnectListAllNodeDevices. * src/remote/remote_driver.c: Add remote driver handler remoteConnectListAllNodeDevices. * src/remote/remote_protocol.x: New RPC procedure REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES and --- daemon/remote.c | 53 ++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 64 ++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 14 ++++++++- src/remote_protocol-structs | 12 ++++++++ 4 files changed, 142 insertions(+), 1 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index aec7b3c..5a16dbe 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -4172,6 +4172,59 @@ cleanup: return rv; } +static int +remoteDispatchConnectListAllNodeDevices(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_connect_list_all_node_devices_args *args, + remote_connect_list_all_node_devices_ret *ret) +{ + virNodeDevicePtr *devices = NULL; + int ndevices = 0; + int i; + int rv = -1; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if ((ndevices = virConnectListAllNodeDevices(priv->conn, + args->need_results ? &devices : NULL, + args->flags)) < 0) + goto cleanup; + + if (devices && ndevices) { + if (VIR_ALLOC_N(ret->devices.devices_val, ndevices) < 0) { + virReportOOMError(); + goto cleanup; + } + + ret->devices.devices_len = ndevices; + + for (i = 0; i < ndevices; i++) + make_nonnull_node_device(ret->devices.devices_val + i, devices[i]); + } else { + ret->devices.devices_len = 0; + ret->devices.devices_val = NULL; + } + + ret->ret = ndevices; + + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (devices) { + for (i = 0; i < ndevices; i++) + virNodeDeviceFree(devices[i]); + VIR_FREE(devices); + } + return rv; +} /*----- Helpers. -----*/ diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 2b7c05e..22aad2f 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -2905,6 +2905,69 @@ done: return rv; } +static int +remoteConnectListAllNodeDevices(virConnectPtr conn, + virNodeDevicePtr **devices, + unsigned int flags) +{ + int rv = -1; + int i; + virNodeDevicePtr *tmp_devices = NULL; + remote_connect_list_all_node_devices_args args; + remote_connect_list_all_node_devices_ret ret; + + struct private_data *priv = conn->privateData; + + remoteDriverLock(priv); + + args.need_results = !!devices; + args.flags = flags; + + memset(&ret, 0, sizeof(ret)); + if (call(conn, + priv, + 0, + REMOTE_PROC_CONNECT_LIST_ALL_NODE_DEVICES, + (xdrproc_t) xdr_remote_connect_list_all_node_devices_args, + (char *) &args, + (xdrproc_t) xdr_remote_connect_list_all_node_devices_ret, + (char *) &ret) == -1) + goto done; + + if (devices) { + if (VIR_ALLOC_N(tmp_devices, ret.devices.devices_len + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + for (i = 0; i < ret.devices.devices_len; i++) { + tmp_devices[i] = get_nonnull_node_device(conn, ret.devices.devices_val[i]); + if (!tmp_devices[i]) { + virReportOOMError(); + goto cleanup; + } + } + *devices = tmp_devices; + tmp_devices = NULL; + } + + rv = ret.ret; + +cleanup: + if (tmp_devices) { + for (i = 0; i < ret.devices.devices_len; i++) + if (tmp_devices[i]) + virNodeDeviceFree(tmp_devices[i]); + VIR_FREE(tmp_devices); + } + + xdr_free((xdrproc_t) xdr_remote_connect_list_all_node_devices_ret, (char *) &ret); + +done: + remoteDriverUnlock(priv); + return rv; +} + /*----------------------------------------------------------------------*/ @@ -5717,6 +5780,7 @@ static virDeviceMonitor dev_monitor = { .close = remoteDevMonClose, /* 0.5.0 */ .numOfDevices = remoteNodeNumOfDevices, /* 0.5.0 */ .listDevices = remoteNodeListDevices, /* 0.5.0 */ + .listAllNodeDevices = remoteConnectListAllNodeDevices, /* 0.9.14 */ .deviceLookupByName = remoteNodeDeviceLookupByName, /* 0.5.0 */ .deviceGetXMLDesc = remoteNodeDeviceGetXMLDesc, /* 0.5.0 */ .deviceGetParent = remoteNodeDeviceGetParent, /* 0.5.0 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index e4f0d62..d25e22c 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -2557,6 +2557,16 @@ struct remote_connect_list_all_storage_pools_ret { unsigned int ret; }; +struct remote_connect_list_all_node_devices_args { + int need_results; + unsigned int flags; +}; + +struct remote_connect_list_all_node_devices_ret { + remote_nonnull_node_device devices<>; + unsigned int ret; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -2886,7 +2896,9 @@ enum remote_procedure { REMOTE_PROC_CONNECT_LIST_ALL_STORAGE_POOLS = 277, /* skipgen skipgen priority:high */ REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES = 278, /* skipgen skipgen priority:high */ REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS = 279, /* skipgen skipgen priority:high */ - REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 280 /* skipgen skipgen priority:high */ + REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 280, /* skipgen skipgen priority:high */ + + REMOTE_PROC_CONNECT_LIST_ALL_NODE_DEVICES = 281 /* skipgen skipgen priority:high */ /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 2640fd1..545186d 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2019,6 +2019,17 @@ struct remote_storage_pool_list_all_volumes_ret { } vols; u_int ret; }; +struct remote_connect_list_all_node_devices_args { + int need_results; + u_int flags; +}; +struct remote_connect_list_all_node_devices_ret { + struct { + u_int devices_len; + remote_nonnull_node_device * devices_val; + } devices; + u_int ret; +}; enum remote_procedure { REMOTE_PROC_OPEN = 1, REMOTE_PROC_CLOSE = 2, @@ -2300,4 +2311,5 @@ enum remote_procedure { REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES = 278, REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS = 279, REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 280, + REMOTE_PROC_CONNECT_LIST_ALL_NODE_DEVICES = 281, }; -- 1.7.7.3

src/conf/virobjectlist.h: * New macro VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_CAP * Declare virNodeDeviceList src/conf/virobjectlist.c: * New helpers virNodeDeviceCapMatch, virNodeDeviceMatch. virNodeDeviceCapMatch looks up the list of all the caps the device support, to see if the device support the cap type. * Implement virNodeDeviceList src/libvirt_private.syms: * Export virNodeDeviceList --- src/conf/virobjectlist.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++ src/conf/virobjectlist.h | 17 ++++++++ src/libvirt_private.syms | 2 + 3 files changed, 122 insertions(+), 0 deletions(-) diff --git a/src/conf/virobjectlist.c b/src/conf/virobjectlist.c index 83b0d9c..55c236c 100644 --- a/src/conf/virobjectlist.c +++ b/src/conf/virobjectlist.c @@ -30,6 +30,7 @@ #include "virhash.h" #include "domain_conf.h" #include "storage_conf.h" +#include "node_device_conf.h" #include "memory.h" #include "datatypes.h" #include "virterror_internal.h" @@ -135,6 +136,20 @@ cleanup: } #undef MATCH +static bool +virNodeDeviceCapMatch(virNodeDeviceObjPtr devobj, + int type) +{ + virNodeDevCapsDefPtr cap = NULL; + + for (cap = devobj->def->caps; cap; cap = cap->next) { + if (type == cap->type) + return true; + } + + return false; +} + #define MATCH(FLAG) (flags & (FLAG)) static bool virStoragePoolMatch (virStoragePoolObjPtr poolobj, @@ -222,6 +237,36 @@ virNetworkMatch (virNetworkObjPtr netobj, return true; } + +static bool +virNodeDeviceMatch (virNodeDeviceObjPtr devobj, + unsigned int flags) +{ + /* filter by cap type */ + if (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_CAP)) { + if (!((MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_SYSTEM) && + virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_SYSTEM)) || + (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV) && + virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_PCI_DEV)) || + (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_DEV) && + virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_USB_DEV)) || + (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_INTERFACE) && + virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_USB_INTERFACE)) || + (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_NET) && + virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_NET)) || + (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_HOST) && + virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_SCSI_HOST)) || + (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_TARGET) && + virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_SCSI_TARGET)) || + (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI) && + virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_SCSI)) || + (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE) && + virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_STORAGE)))) + return false; + } + + return true; +} #undef MATCH int @@ -430,3 +475,61 @@ cleanup: VIR_FREE(tmp_nets); return ret; } + +int +virNodeDeviceList(virConnectPtr conn, + virNodeDeviceObjList devobjs, + virNodeDevicePtr **devices, + unsigned int flags) +{ + virNodeDevicePtr *tmp_devices = NULL; + virNodeDevicePtr device = NULL; + int ndevices = 0; + int ret = -1; + int i; + + if (devices) { + if (VIR_ALLOC_N(tmp_devices, devobjs.count + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + } + + for (i = 0; i < devobjs.count; i++) { + virNodeDeviceObjPtr devobj = devobjs.objs[i]; + virNodeDeviceObjLock(devobj); + if (virNodeDeviceMatch(devobj, flags)) { + if (devices) { + if (!(device = virGetNodeDevice(conn, + devobj->def->name))) { + virNodeDeviceObjUnlock(devobj); + goto cleanup; + } + tmp_devices[ndevices++] = device; + } else { + ndevices++; + } + } + virNodeDeviceObjUnlock(devobj); + } + + if (tmp_devices) { + /* trim the array to the final size */ + ignore_value(VIR_REALLOC_N(tmp_devices, ndevices + 1)); + *devices = tmp_devices; + tmp_devices = NULL; + } + + ret = ndevices; + +cleanup: + if (tmp_devices) { + for (i = 0; i < devobjs.count; i++) { + if (tmp_devices[i]) + virNodeDeviceFree(tmp_devices[i]); + } + } + + VIR_FREE(tmp_devices); + return ret; +} diff --git a/src/conf/virobjectlist.h b/src/conf/virobjectlist.h index 431635e..e62d454 100644 --- a/src/conf/virobjectlist.h +++ b/src/conf/virobjectlist.h @@ -29,6 +29,7 @@ # include "domain_conf.h" # include "storage_conf.h" # include "network_conf.h" +# include "node_device_conf.h" # define VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE \ (VIR_CONNECT_LIST_DOMAINS_ACTIVE | \ @@ -123,6 +124,17 @@ VIR_CONNECT_LIST_NETWORKS_FILTERS_PERSISTENT | \ VIR_CONNECT_LIST_NETWORKS_FILTERS_AUTOSTART) +# define VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_CAP \ + (VIR_CONNECT_LIST_NODE_DEVICES_CAP_SYSTEM | \ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV | \ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_DEV | \ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_INTERFACE | \ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_NET | \ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_HOST | \ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_TARGET | \ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI | \ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE) + int virDomainList(virConnectPtr conn, virHashTablePtr domobjs, virDomainPtr **domains, unsigned int flags); @@ -142,4 +154,9 @@ int virNetworkList(virConnectPtr conn, virNetworkPtr **nets, unsigned int flags); +int virNodeDeviceList(virConnectPtr conn, + virNodeDeviceObjList devobjs, + virNodeDevicePtr **devices, + unsigned int flags); + #endif /* __VIR_OBJECT_LIST_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 647ecf0..43557d9 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -817,6 +817,7 @@ virPortGroupFindByName; # node_device_conf.h +virNodeDevCapTypeFromString; virNodeDevCapTypeToString; virNodeDevCapsDefFree; virNodeDeviceAssignDef; @@ -1247,6 +1248,7 @@ virDBusGetSystemBus; virDomainList; virDomainListSnapshots; virNetworkList; +virNodeDeviceList; virStoragePoolList; -- 1.7.7.3

This simply implements listAllNodeDevices using helper virNodeDeviceList src/node_device/node_device_driver.h: * Declare nodeListAllNodeDevices. src/node_device/node_device_driver.c: * Implement nodeListAllNodeDevices. src/node_device/node_device_hal.c: * Hook listAllNodeDevices to nodeListAllNodeDevices. src/node_device/node_device_udev.c * Hook listAllNodeDevices to nodeListAllNodeDevices. --- src/node_device/node_device_driver.c | 16 ++++++++++++++++ src/node_device/node_device_driver.h | 3 +++ src/node_device/node_device_hal.c | 1 + src/node_device/node_device_udev.c | 1 + 4 files changed, 21 insertions(+), 0 deletions(-) diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 83db775..52df49e 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -37,6 +37,7 @@ #include "node_device_conf.h" #include "node_device_hal.h" #include "node_device_driver.h" +#include "virobjectlist.h" #include "util.h" #define VIR_FROM_THIS VIR_FROM_NODEDEV @@ -183,6 +184,21 @@ nodeListDevices(virConnectPtr conn, return -1; } +int +nodeListAllNodeDevices(virConnectPtr conn, + virNodeDevicePtr **devices, + unsigned int flags) +{ + virDeviceMonitorStatePtr driver = conn->devMonPrivateData; + int ret = -1; + + virCheckFlags(VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_CAP, -1); + + nodeDeviceLock(driver); + ret = virNodeDeviceList(conn, driver->devs, devices, flags); + nodeDeviceUnlock(driver); + return ret; +} virNodeDevicePtr nodeDeviceLookupByName(virConnectPtr conn, const char *name) diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h index 673e95b..deab618 100644 --- a/src/node_device/node_device_driver.h +++ b/src/node_device/node_device_driver.h @@ -73,6 +73,9 @@ int read_wwn_linux(int host, const char *file, char **wwn); int nodeNumOfDevices(virConnectPtr conn, const char *cap, unsigned int flags); int nodeListDevices(virConnectPtr conn, const char *cap, char **const names, int maxnames, unsigned int flags); +int nodeListAllNodeDevices(virConnectPtr conn, + virNodeDevicePtr **devices, + unsigned int flags); virNodeDevicePtr nodeDeviceLookupByName(virConnectPtr conn, const char *name); char *nodeDeviceGetXMLDesc(virNodeDevicePtr dev, unsigned int flags); char *nodeDeviceGetParent(virNodeDevicePtr dev); diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index 7f8b076..c06f977 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -770,6 +770,7 @@ static virDeviceMonitor halDeviceMonitor = { .close = halNodeDrvClose, /* 0.5.0 */ .numOfDevices = nodeNumOfDevices, /* 0.5.0 */ .listDevices = nodeListDevices, /* 0.5.0 */ + .listAllNodeDevices = nodeListAllNodeDevices, /* 0.9.14 */ .deviceLookupByName = nodeDeviceLookupByName, /* 0.5.0 */ .deviceGetXMLDesc = nodeDeviceGetXMLDesc, /* 0.5.0 */ .deviceGetParent = nodeDeviceGetParent, /* 0.5.0 */ diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index aa96abd..33dd3e9 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -1757,6 +1757,7 @@ static virDeviceMonitor udevDeviceMonitor = { .close = udevNodeDrvClose, /* 0.7.3 */ .numOfDevices = nodeNumOfDevices, /* 0.7.3 */ .listDevices = nodeListDevices, /* 0.7.3 */ + .listAllNodeDevices = nodeListAllNodeDevices, /* 0.9.14 */ .deviceLookupByName = nodeDeviceLookupByName, /* 0.7.3 */ .deviceGetXMLDesc = nodeDeviceGetXMLDesc, /* 0.7.3 */ .deviceGetParent = nodeDeviceGetParent, /* 0.7.3 */ -- 1.7.7.3

The implementation is done manually as the generator does not support wrapping lists of C pointers into Python objects. python/libvirt-override-api.xml: Document python/libvirt-override-virConnect.py: * Implementation for listAllNodeDevices. python/libvirt-override.c: Implementation for the wrapper. --- python/libvirt-override-api.xml | 6 ++++ python/libvirt-override-virConnect.py | 13 +++++++++ python/libvirt-override.c | 48 +++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 0 deletions(-) diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index ab6f407..a3d6bbb 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -346,6 +346,12 @@ <arg name='flags' type='unsigned int' info='flags (unused; pass 0)'/> <return type='str *' info='the list of Names or None in case of error'/> </function> + <function name='virConnectListAllNodeDevices' file='python'> + <info>returns list of all host node devices</info> + <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> + <arg name='flags' type='unsigned int' info='optional flags'/> + <return type='device *' info='the list of host node device or None in case of error'/> + </function> <function name='virNodeDeviceListCaps' file='python'> <info>list the node device's capabilities</info> <arg name='dev' type='virNodeDevicePtr' info='pointer to the node device'/> diff --git a/python/libvirt-override-virConnect.py b/python/libvirt-override-virConnect.py index ffa1a3c..c34cd63 100644 --- a/python/libvirt-override-virConnect.py +++ b/python/libvirt-override-virConnect.py @@ -242,3 +242,16 @@ retlist.append(virInterface(self, _obj=ifaceptr)) return retlist + + def listAllDevices(self, flags): + """Returns a list of host node device objects""" + ret = libvirtmod.virConnectListAllNodeDevices(self._o, flags) + if ret is None: + raise libvirtError("virConnectListAllNodeDevices() failed", conn=self) + + retlist = list() + for devptr in ret: + retlist.append(virNodeDevice(self, _obj=devptr)) + + return retlist + diff --git a/python/libvirt-override.c b/python/libvirt-override.c index 98ed40f..6449639 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -3383,6 +3383,53 @@ libvirt_virNodeListDevices(PyObject *self ATTRIBUTE_UNUSED, } static PyObject * +libvirt_virConnectListAllNodeDevices(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + PyObject *pyobj_conn; + PyObject *py_retval = NULL; + PyObject *tmp = NULL; + virConnectPtr conn; + virNodeDevicePtr *devices = NULL; + int c_retval = 0; + int i; + unsigned int flags; + + if (!PyArg_ParseTuple(args, (char *)"Oi:virConnectListAllNodeDevices", + &pyobj_conn, &flags)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virConnectListAllNodeDevices(conn, &devices, flags); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) + return VIR_PY_NONE; + + if (!(py_retval = PyList_New(c_retval))) + goto cleanup; + + for (i = 0; i < c_retval; i++) { + if (!(tmp = libvirt_virNodeDevicePtrWrap(devices[i])) || + PyList_SetItem(py_retval, i, tmp) < 0) { + Py_XDECREF(tmp); + Py_DECREF(py_retval); + py_retval = NULL; + goto cleanup; + } + /* python steals the pointer */ + devices[i] = NULL; + } + +cleanup: + for (i = 0; i < c_retval; i++) + if (devices[i]) + virNodeDeviceFree(devices[i]); + VIR_FREE(devices); + return py_retval; +} + +static PyObject * libvirt_virNodeDeviceListCaps(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { PyObject *py_retval; @@ -6079,6 +6126,7 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virEventInvokeHandleCallback", libvirt_virEventInvokeHandleCallback, METH_VARARGS, NULL}, {(char *) "virEventInvokeTimeoutCallback", libvirt_virEventInvokeTimeoutCallback, METH_VARARGS, NULL}, {(char *) "virNodeListDevices", libvirt_virNodeListDevices, METH_VARARGS, NULL}, + {(char *) "virConnectListAllNodeDevices", libvirt_virConnectListAllNodeDevices, METH_VARARGS, NULL}, {(char *) "virNodeDeviceListCaps", libvirt_virNodeDeviceListCaps, METH_VARARGS, NULL}, {(char *) "virSecretGetUUID", libvirt_virSecretGetUUID, METH_VARARGS, NULL}, {(char *) "virSecretGetUUIDString", libvirt_virSecretGetUUIDString, METH_VARARGS, NULL}, -- 1.7.7.3

Output of commands like '%virsh nodedev-list --tree --cap pci' could be empty. Remove the useless checking. --- tools/virsh.c | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 8e191f4..8b85a7a 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -14213,9 +14213,8 @@ cmdNodeListDevices(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) virNodeDeviceFree(dev); } for (i = 0 ; i < num_devices ; i++) { - if (parents[i] == NULL && - vshTreePrint(ctl, vshNodeListLookup, &arrays, num_devices, - i) < 0) + if (vshTreePrint(ctl, vshNodeListLookup, + &arrays, num_devices, i) < 0) ret = false; } for (i = 0 ; i < num_devices ; i++) { -- 1.7.7.3

tools/virsh.c: * vshNodeDeviceSorter to sort node devices by name * vshNodeDeviceListFree to free the node device objects list. * vshNodeDeviceListCollect to collect the node device objects, trying to use new API first, fall back to older APIs if it's not supported. * Change option --cap to accept multiple capability types. tools/virsh.pod * Update document for --cap --- tools/virsh.c | 301 ++++++++++++++++++++++++++++++++++++++++++++++++------- tools/virsh.pod | 8 +- 2 files changed, 269 insertions(+), 40 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 8b85a7a..5a5d388 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -63,6 +63,7 @@ #include "virnetdevbandwidth.h" #include "util/bitmap.h" #include "conf/domain_conf.h" +#include "conf/node_device_conf.h" #include "virtypedparam.h" #include "intprops.h" #include "conf/virobjectlist.h" @@ -14151,6 +14152,187 @@ vshNodeListLookup(int devid, bool parent, void *opaque) return arrays->names[devid]; } +static int +vshNodeDeviceSorter(const void *a, const void *b) +{ + virNodeDevicePtr *na = (virNodeDevicePtr *) a; + virNodeDevicePtr *nb = (virNodeDevicePtr *) b; + + if (*na && !*nb) + return -1; + + if (!*na) + return *nb != NULL; + + return strcasecmp(virNodeDeviceGetName(*na), + virNodeDeviceGetName(*nb)); +} + +struct vshNodeDeviceList { + virNodeDevicePtr *devices; + size_t ndevices; +}; +typedef struct vshNodeDeviceList *vshNodeDeviceListPtr; + +static void +vshNodeDeviceListFree(vshNodeDeviceListPtr list) +{ + int i; + + if (list && list->ndevices) { + for (i = 0; i < list->ndevices; i++) { + if (list->devices[i]) + virNodeDeviceFree(list->devices[i]); + } + VIR_FREE(list->devices); + } + VIR_FREE(list); +} + +static vshNodeDeviceListPtr +vshNodeDeviceListCollect(vshControl *ctl, + char **capnames, + int ncapnames, + unsigned int flags) +{ + vshNodeDeviceListPtr list = vshMalloc(ctl, sizeof(*list)); + int i; + int ret; + virNodeDevicePtr device; + bool success = false; + size_t deleted = 0; + int ndevices = 0; + char **names = NULL; + + /* try the list with flags support (0.9.14 and later) */ + if ((ret = virConnectListAllNodeDevices(ctl->conn, + &list->devices, + flags)) >= 0) { + list->ndevices = ret; + goto finished; + } + + /* check if the command is actually supported */ + if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) { + virFreeError(last_error); + last_error = NULL; + goto fallback; + } + + /* there was an error during the call */ + vshError(ctl, "%s", _("Failed to list node devices")); + goto cleanup; + + +fallback: + /* fall back to old method (0.9.13 and older) */ + virResetLastError(); + + ndevices = virNodeNumOfDevices(ctl->conn, NULL, 0); + if (ndevices < 0) { + vshError(ctl, "%s", _("Failed to count node devices")); + goto cleanup; + } + + if (ndevices == 0) + return list; + + names = vshMalloc(ctl, sizeof(char *) * ndevices); + + ndevices = virNodeListDevices(ctl->conn, NULL, names, ndevices, 0); + if (ndevices < 0) { + vshError(ctl, "%s", _("Failed to list node devices")); + goto cleanup; + } + + list->devices = vshMalloc(ctl, sizeof(virNodeDevicePtr) * (ndevices)); + list->ndevices = 0; + + /* get the node devices */ + for (i = 0; i < ndevices ; i++) { + if (!(device = virNodeDeviceLookupByName(ctl->conn, names[i]))) + continue; + list->devices[list->ndevices++] = device; + } + + /* truncate domains that weren't found */ + deleted = ndevices - list->ndevices; + + if (!capnames) + goto finished; + + /* filter the list if the list was acquired by fallback means */ + for (i = 0; i < list->ndevices; i++) { + char **caps = NULL; + int ncaps = 0; + bool match = false; + + device = list->devices[i]; + + if ((ncaps = virNodeDeviceNumOfCaps(device)) < 0) { + vshError(ctl, "%s", _("Failed to get capability numbers " + "of the device")); + goto cleanup; + } + + caps = vshMalloc(ctl, sizeof(char *) * ncaps); + + if ((ncaps = virNodeDeviceListCaps(device, caps, ncaps)) < 0) { + vshError(ctl, "%s", _("Failed to get capability names of the device")); + VIR_FREE(caps); + goto cleanup; + } + + int j, k; + for (j = 0; j < ncaps; j++) { + for (k = 0; k < ncapnames; k++) { + if (STREQ(caps[j], capnames[k])) { + match = true; + break; + } + } + } + + VIR_FREE(caps); + + if (!match) + goto remove_entry; + + /* the device matched all filters, it may stay */ + continue; + +remove_entry: + /* the device has to be removed as it failed one of the filters */ + virNodeDeviceFree(list->devices[i]); + list->devices[i] = NULL; + deleted++; + } + +finished: + /* sort the list */ + if (list->devices && list->ndevices) + qsort(list->devices, list->ndevices, + sizeof(*list->devices), vshNodeDeviceSorter); + + /* truncate the list if filter simulation deleted entries */ + if (deleted) + VIR_SHRINK_N(list->devices, list->ndevices, deleted); + + success = true; + +cleanup: + for (i = 0; i < ndevices; i++) + VIR_FREE(names[i]); + VIR_FREE(names); + + if (!success) { + vshNodeDeviceListFree(list); + list = NULL; + } + + return list; +} + /* * "nodedev-list" command */ @@ -14162,73 +14344,118 @@ static const vshCmdInfo info_node_list_devices[] = { static const vshCmdOptDef opts_node_list_devices[] = { {"tree", VSH_OT_BOOL, 0, N_("list devices in a tree")}, - {"cap", VSH_OT_STRING, VSH_OFLAG_NONE, N_("capability name")}, + {"cap", VSH_OT_STRING, VSH_OFLAG_NONE, N_("capability names, separated by comma")}, {NULL, 0, 0, NULL} }; static bool cmdNodeListDevices(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) { - const char *cap = NULL; - char **devices; - int num_devices, i; + const char *cap_str = NULL; + int i; bool tree = vshCommandOptBool(cmd, "tree"); bool ret = true; + unsigned int flags = 0; + char **caps = NULL; + int ncaps = 0; + vshNodeDeviceListPtr list = NULL; + int cap_type = -1; if (!vshConnectionUsability(ctl, ctl->conn)) return false; - if (vshCommandOptString(cmd, "cap", &cap) <= 0) - cap = NULL; + ignore_value(vshCommandOptString(cmd, "cap", &cap_str)); - num_devices = virNodeNumOfDevices(ctl->conn, cap, 0); - if (num_devices < 0) { - vshError(ctl, "%s", _("Failed to count node devices")); - return false; - } else if (num_devices == 0) { - return true; + if (cap_str) { + ncaps = vshStringToArray((char *)cap_str, &caps); + + for (i = 0; i < ncaps; i++) + for (i = 0; i < ncaps; i++) { + if ((cap_type = virNodeDevCapTypeFromString(caps[i])) < 0) { + vshError(ctl, "%s", _("Invalid capability type")); + VIR_FREE(caps); + return false; + } + + switch(cap_type) { + case VIR_NODE_DEV_CAP_SYSTEM: + flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_SYSTEM; + break; + case VIR_NODE_DEV_CAP_PCI_DEV: + flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV; + break; + case VIR_NODE_DEV_CAP_USB_DEV: + flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_DEV; + break; + case VIR_NODE_DEV_CAP_USB_INTERFACE: + flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_INTERFACE; + break; + case VIR_NODE_DEV_CAP_NET: + flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_NET; + break; + case VIR_NODE_DEV_CAP_SCSI_HOST: + flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_HOST; + break; + case VIR_NODE_DEV_CAP_SCSI_TARGET: + flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_TARGET; + break; + case VIR_NODE_DEV_CAP_SCSI: + flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI; + break; + case VIR_NODE_DEV_CAP_STORAGE: + flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE; + break; + default: + break; + } + } } - devices = vshMalloc(ctl, sizeof(char *) * num_devices); - num_devices = - virNodeListDevices(ctl->conn, cap, devices, num_devices, 0); - if (num_devices < 0) { - vshError(ctl, "%s", _("Failed to list node devices")); - VIR_FREE(devices); - return false; + if (!(list = vshNodeDeviceListCollect(ctl, caps, ncaps, flags))) { + ret = false; + goto cleanup; } - qsort(&devices[0], num_devices, sizeof(char*), vshNameSorter); + if (tree) { - char **parents = vshMalloc(ctl, sizeof(char *) * num_devices); - struct vshNodeList arrays = { devices, parents }; + char **parents = vshMalloc(ctl, sizeof(char *) * list->ndevices); + char **names = vshMalloc(ctl, sizeof(char *) * list->ndevices); + struct vshNodeList arrays = { names, parents }; + + for (i = 0; i < list->ndevices; i++) + names[i] = vshStrdup(ctl, virNodeDeviceGetName(list->devices[i])); - for (i = 0; i < num_devices; i++) { - virNodeDevicePtr dev = virNodeDeviceLookupByName(ctl->conn, devices[i]); - if (dev && STRNEQ(devices[i], "computer")) { + for (i = 0; i < list->ndevices; i++) { + virNodeDevicePtr dev = list->devices[i]; + if (STRNEQ(names[i], "computer")) { const char *parent = virNodeDeviceGetParent(dev); parents[i] = parent ? vshStrdup(ctl, parent) : NULL; } else { parents[i] = NULL; } - virNodeDeviceFree(dev); } - for (i = 0 ; i < num_devices ; i++) { - if (vshTreePrint(ctl, vshNodeListLookup, - &arrays, num_devices, i) < 0) + + for (i = 0 ; i < list->ndevices; i++) { + if (vshTreePrint(ctl, vshNodeListLookup, &arrays, + list->ndevices, i) < 0) ret = false; } - for (i = 0 ; i < num_devices ; i++) { - VIR_FREE(devices[i]); + + for (i = 0 ; i < list->ndevices; i++) VIR_FREE(parents[i]); - } VIR_FREE(parents); + + for (i = 0; i < list->ndevices; i++) + VIR_FREE(names[i]); + VIR_FREE(names); } else { - for (i = 0; i < num_devices; i++) { - vshPrint(ctl, "%s\n", devices[i]); - VIR_FREE(devices[i]); - } + for (i = 0; i < list->ndevices; i++) + vshPrint(ctl, "%s\n", virNodeDeviceGetName(list->devices[i])); } - VIR_FREE(devices); + +cleanup: + VIR_FREE(cap_str); + VIR_FREE(caps); + vshNodeDeviceListFree(list); return ret; } diff --git a/tools/virsh.pod b/tools/virsh.pod index 750114c..6d60b05 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1824,9 +1824,11 @@ libvirt (such as whether device reset is supported). =item B<nodedev-list> I<cap> I<--tree> List all of the devices available on the node that are known by libvirt. -If I<cap> is used, the list is filtered to show only the nodes that -include the given capability. If I<--tree> is used, the output is -formatted in a tree representing parents of each node. +I<cap> is used to filter the list by capability types, the types must be +separated by comma, e.g. --cap pci,scsi, valid capability types include +'system', 'pci', 'usb_device', 'usb', 'net', 'scsi_host', 'scsi_target', +'scsi', 'storage'. If I<--tree> is used, the output is formatted in a tree +representing parents of each node. =item B<nodedev-reattach> I<nodedev> -- 1.7.7.3

This is to list the network fitler objects. No flags are supported include/libvirt/libvirt.h.in: Declare enum virConnectListAllNWFilterFlags and virConnectListAllNWFilters. python/generator.py: Skip auto-generating src/driver.h: (virDrvConnectListAllNWFilters) src/libvirt.c: Implement the public API src/libvirt_public.syms: Export the symbol to public --- include/libvirt/libvirt.h.in | 4 ++- python/generator.py | 1 + src/driver.h | 5 ++++ src/libvirt.c | 50 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 5 files changed, 60 insertions(+), 1 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index cfdb162..aea4d8a 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -4041,7 +4041,9 @@ int virConnectNumOfNWFilters (virConnectPtr conn); int virConnectListNWFilters (virConnectPtr conn, char **const names, int maxnames); - +int virConnectListAllNWFilters(virConnectPtr conn, + virNWFilterPtr **filters, + unsigned int flags); /* * Lookup nwfilter by name or uuid */ diff --git a/python/generator.py b/python/generator.py index 6f50fa0..00e242f 100755 --- a/python/generator.py +++ b/python/generator.py @@ -461,6 +461,7 @@ skip_function = ( 'virConnectListAllNetworks', # overridden in virConnect.py 'virConnectListAllInterfaces', # overridden in virConnect.py 'virConnectListAllNodeDevices', # overridden in virConnect.py + 'virConnectListAllNWFilters', # overridden in virConnect.py 'virStreamRecvAll', # Pure python libvirt-override-virStream.py 'virStreamSendAll', # Pure python libvirt-override-virStream.py diff --git a/src/driver.h b/src/driver.h index 102684c..5ace502 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1611,6 +1611,10 @@ typedef int (*virDrvConnectListNWFilters) (virConnectPtr conn, char **const names, int maxnames); +typedef int + (*virDrvConnectListAllNWFilters) (virConnectPtr conn, + virNWFilterPtr **filters, + unsigned int flags); typedef virNWFilterPtr (*virDrvNWFilterLookupByName) (virConnectPtr conn, const char *name); @@ -1648,6 +1652,7 @@ struct _virNWFilterDriver { virDrvConnectNumOfNWFilters numOfNWFilters; virDrvConnectListNWFilters listNWFilters; + virDrvConnectListAllNWFilters listAllNWFilters; virDrvNWFilterLookupByName nwfilterLookupByName; virDrvNWFilterLookupByUUID nwfilterLookupByUUID; virDrvNWFilterDefineXML defineXML; diff --git a/src/libvirt.c b/src/libvirt.c index 6d4cd76..ff02c88 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -15931,6 +15931,56 @@ error: return -1; } +/** + * virConnectListAllNWFilters: + * @conn: Pointer to the hypervisor connection. + * @filters: Pointer to a variable to store the array containing the network + * filter objects or NULL if the list is not required (just returns + * number of network filters). + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Collect the list of network filters, and allocate an array to store those + * objects. + * + * Returns the number of network filters found or -1 and sets @filters to NULL + * in case of error. On success, the array stored into @filters is guaranteed to + * have an extra allocated element set to NULL but not included in the return count, + * to make iteration easier. The caller is responsible for calling + * virNWFilterFree() on each array element, then calling free() on @filters. + */ +int +virConnectListAllNWFilters(virConnectPtr conn, + virNWFilterPtr **filters, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, filters=%p, flags=%x", conn, filters, flags); + + virResetLastError(); + + if (filters) + *filters = NULL; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (conn->nwfilterDriver && + conn->nwfilterDriver->listAllNWFilters) { + int ret; + ret = conn->nwfilterDriver->listAllNWFilters(conn, filters, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} /** * virConnectListNWFilters: diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index d45e38f..ab5f156 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -551,6 +551,7 @@ LIBVIRT_0.9.14 { virConnectListAllNetworks; virConnectListAllInterfaces; virConnectListAllNodeDevices; + virConnectListAllNWFilters; } LIBVIRT_0.9.13; # .... define new API here using predicted next version number .... -- 1.7.7.3

The RPC generator doesn't support returning list of object yet, this patch do the work manually. * daemon/remote.c: Implemente the server side handler remoteDispatchConnectListAllNWFilters. * src/remote/remote_driver.c: Add remote driver handler remoteConnectListAllNWFilters. * src/remote/remote_protocol.x: New RPC procedure REMOTE_PROC_CONNECT_LIST_ALL_NWFILTERS and structs to represent the args and ret for it. * src/remote_protocol-structs: Likewise. --- daemon/remote.c | 54 ++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 63 ++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 13 ++++++++- src/remote_protocol-structs | 12 ++++++++ 4 files changed, 141 insertions(+), 1 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 5a16dbe..9de0629 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -4226,6 +4226,60 @@ cleanup: return rv; } +static int +remoteDispatchConnectListAllNWFilters(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_connect_list_all_nwfilters_args *args, + remote_connect_list_all_nwfilters_ret *ret) +{ + virNWFilterPtr *filters = NULL; + int nfilters = 0; + int i; + int rv = -1; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if ((nfilters = virConnectListAllNWFilters(priv->conn, + args->need_results ? &filters : NULL, + args->flags)) < 0) + goto cleanup; + + if (filters && nfilters) { + if (VIR_ALLOC_N(ret->filters.filters_val, nfilters) < 0) { + virReportOOMError(); + goto cleanup; + } + + ret->filters.filters_len = nfilters; + + for (i = 0; i < nfilters; i++) + make_nonnull_nwfilter(ret->filters.filters_val + i, filters[i]); + } else { + ret->filters.filters_len = 0; + ret->filters.filters_val = NULL; + } + + ret->ret = nfilters; + + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (filters) { + for (i = 0; i < nfilters; i++) + virNWFilterFree(filters[i]); + VIR_FREE(filters); + } + return rv; +} + /*----- Helpers. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 22aad2f..ee6caf4 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -2968,6 +2968,68 @@ done: return rv; } +static int +remoteConnectListAllNWFilters(virConnectPtr conn, + virNWFilterPtr **filters, + unsigned int flags) +{ + int rv = -1; + int i; + virNWFilterPtr *tmp_filters = NULL; + remote_connect_list_all_nwfilters_args args; + remote_connect_list_all_nwfilters_ret ret; + + struct private_data *priv = conn->privateData; + + remoteDriverLock(priv); + + args.need_results = !!filters; + args.flags = flags; + + memset(&ret, 0, sizeof(ret)); + if (call(conn, + priv, + 0, + REMOTE_PROC_CONNECT_LIST_ALL_NWFILTERS, + (xdrproc_t) xdr_remote_connect_list_all_nwfilters_args, + (char *) &args, + (xdrproc_t) xdr_remote_connect_list_all_nwfilters_ret, + (char *) &ret) == -1) + goto done; + + if (filters) { + if (VIR_ALLOC_N(tmp_filters, ret.filters.filters_len + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + for (i = 0; i < ret.filters.filters_len; i++) { + tmp_filters[i] = get_nonnull_nwfilter (conn, ret.filters.filters_val[i]); + if (!tmp_filters[i]) { + virReportOOMError(); + goto cleanup; + } + } + *filters = tmp_filters; + tmp_filters = NULL; + } + + rv = ret.ret; + +cleanup: + if (tmp_filters) { + for (i = 0; i < ret.filters.filters_len; i++) + if (tmp_filters[i]) + virNWFilterFree(tmp_filters[i]); + VIR_FREE(tmp_filters); + } + + xdr_free((xdrproc_t) xdr_remote_connect_list_all_nwfilters_ret, (char *) &ret); + +done: + remoteDriverUnlock(priv); + return rv; +} /*----------------------------------------------------------------------*/ @@ -5801,6 +5863,7 @@ static virNWFilterDriver nwfilter_driver = { .undefine = remoteNWFilterUndefine, /* 0.8.0 */ .numOfNWFilters = remoteNumOfNWFilters, /* 0.8.0 */ .listNWFilters = remoteListNWFilters, /* 0.8.0 */ + .listAllNWFilters = remoteConnectListAllNWFilters, /* 0.9.14 */ }; diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index d25e22c..4b8b8b1 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1345,6 +1345,16 @@ struct remote_list_nwfilters_ret { remote_nonnull_string names<REMOTE_NWFILTER_NAME_LIST_MAX>; /* insert@1 */ }; +struct remote_connect_list_all_nwfilters_args { + int need_results; + unsigned int flags; +}; + +struct remote_connect_list_all_nwfilters_ret { + remote_nonnull_nwfilter filters<>; + unsigned int ret; +}; + struct remote_nwfilter_lookup_by_uuid_args { remote_uuid uuid; }; @@ -2898,7 +2908,8 @@ enum remote_procedure { REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS = 279, /* skipgen skipgen priority:high */ REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 280, /* skipgen skipgen priority:high */ - REMOTE_PROC_CONNECT_LIST_ALL_NODE_DEVICES = 281 /* skipgen skipgen priority:high */ + REMOTE_PROC_CONNECT_LIST_ALL_NODE_DEVICES = 281, /* skipgen skipgen priority:high */ + REMOTE_PROC_CONNECT_LIST_ALL_NWFILTERS = 282 /* skipgen skipgen priority:high */ /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 545186d..56004ab 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -984,6 +984,17 @@ struct remote_list_nwfilters_ret { remote_nonnull_string * names_val; } names; }; +struct remote_connect_list_all_nwfilters_args { + int need_results; + u_int flags; +}; +struct remote_connect_list_all_nwfilters_ret { + struct { + u_int filters_len; + remote_nonnull_nwfilter * filters_val; + } filters; + u_int ret; +}; struct remote_nwfilter_lookup_by_uuid_args { remote_uuid uuid; }; @@ -2312,4 +2323,5 @@ enum remote_procedure { REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS = 279, REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 280, REMOTE_PROC_CONNECT_LIST_ALL_NODE_DEVICES = 281, + REMOTE_PROC_CONNECT_LIST_ALL_NWFILTERS = 282, }; -- 1.7.7.3

Simply returns the object list. No filtering. src/nwfilter/nwfilter_driver.c: Implement listAllNWFilters --- src/nwfilter/nwfilter_driver.c | 57 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 57 insertions(+), 0 deletions(-) diff --git a/src/nwfilter/nwfilter_driver.c b/src/nwfilter/nwfilter_driver.c index 58d91f9..93520e1 100644 --- a/src/nwfilter/nwfilter_driver.c +++ b/src/nwfilter/nwfilter_driver.c @@ -335,6 +335,62 @@ nwfilterListNWFilters(virConnectPtr conn, } +static int +nwfilterListAllNWFilters(virConnectPtr conn, + virNWFilterPtr **filters, + unsigned int flags) { + virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData; + virNWFilterPtr *tmp_filters = NULL; + int nfilters = 0; + virNWFilterPtr filter = NULL; + virNWFilterObjPtr obj = NULL; + int i; + int ret = -1; + + virCheckFlags(0, -1); + + nwfilterDriverLock(driver); + + if (!filters) { + ret = driver->nwfilters.count; + goto cleanup; + } + + if (VIR_ALLOC_N(tmp_filters, driver->nwfilters.count + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + for (i = 0 ; i < driver->nwfilters.count; i++) { + obj = driver->nwfilters.objs[i]; + virNWFilterObjLock(obj); + if (!(filter = virGetNWFilter(conn, obj->def->name, + obj->def->uuid))) { + virNWFilterObjUnlock(obj); + goto cleanup; + } + virNWFilterObjUnlock(obj); + tmp_filters[nfilters++] = filter; + } + + *filters = tmp_filters; + tmp_filters = NULL; + ret = nfilters; + + cleanup: + nwfilterDriverUnlock(driver); + if (tmp_filters) { + for (i = 0; i < driver->nwfilters.count; i ++) { + if (tmp_filters[i]) + virNWFilterFree(tmp_filters[i]); + } + } + VIR_FREE(tmp_filters); + + return ret; +} + + static virNWFilterPtr nwfilterDefine(virConnectPtr conn, const char *xml) @@ -470,6 +526,7 @@ static virNWFilterDriver nwfilterDriver = { .close = nwfilterClose, /* 0.8.0 */ .numOfNWFilters = nwfilterNumNWFilters, /* 0.8.0 */ .listNWFilters = nwfilterListNWFilters, /* 0.8.0 */ + .listAllNWFilters = nwfilterListAllNWFilters, /* 0.9.14 */ .nwfilterLookupByName = nwfilterLookupByName, /* 0.8.0 */ .nwfilterLookupByUUID = nwfilterLookupByUUID, /* 0.8.0 */ .defineXML = nwfilterDefine, /* 0.8.0 */ -- 1.7.7.3

tools/virsh.c: * vshNWFilterSorter to sort network filters by name * vshNWFilterListFree to free the network filter objects list. * vshNWFilterListCollect to collect the network filter objects, trying to use new API first, fall back to older APIs if it's not supported. --- tools/virsh.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 134 insertions(+), 30 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 5a5d388..b5c4d97 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -10420,6 +10420,134 @@ cmdNWFilterDumpXML(vshControl *ctl, const vshCmd *cmd) return ret; } +static int +vshNWFilterSorter(const void *a, const void *b) +{ + virNWFilterPtr *fa = (virNWFilterPtr *) a; + virNWFilterPtr *fb = (virNWFilterPtr *) b; + + if (*fa && !*fb) + return -1; + + if (!*fa) + return *fb != NULL; + + return strcasecmp(virNWFilterGetName(*fa), + virNWFilterGetName(*fb)); +} + +struct vshNWFilterList { + virNWFilterPtr *filters; + size_t nfilters; +}; +typedef struct vshNWFilterList *vshNWFilterListPtr; + +static void +vshNWFilterListFree(vshNWFilterListPtr list) +{ + int i; + + if (list && list->nfilters) { + for (i = 0; i < list->nfilters; i++) { + if (list->filters[i]) + virNWFilterFree(list->filters[i]); + } + VIR_FREE(list->filters); + } + VIR_FREE(list); +} + +static vshNWFilterListPtr +vshNWFilterListCollect(vshControl *ctl, + unsigned int flags) +{ + vshNWFilterListPtr list = vshMalloc(ctl, sizeof(*list)); + int i; + int ret; + virNWFilterPtr filter; + bool success = false; + size_t deleted = 0; + int nfilters = 0; + char **names = NULL; + + /* try the list with flags support (0.9.14 and later) */ + if ((ret = virConnectListAllNWFilters(ctl->conn, + &list->filters, + flags)) >= 0) { + list->nfilters = ret; + goto finished; + } + + /* check if the command is actually supported */ + if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) { + virFreeError(last_error); + last_error = NULL; + goto fallback; + } + + /* there was an error during the call */ + vshError(ctl, "%s", _("Failed to list node filters")); + goto cleanup; + + +fallback: + /* fall back to old method (0.9.13 and older) */ + virResetLastError(); + + nfilters = virConnectNumOfNWFilters(ctl->conn); + if (nfilters < 0) { + vshError(ctl, "%s", _("Failed to count network filters")); + goto cleanup; + } + + if (nfilters == 0) + return list; + + names = vshMalloc(ctl, sizeof(char *) * nfilters); + + nfilters = virConnectListNWFilters(ctl->conn, names, nfilters); + if (nfilters < 0) { + vshError(ctl, "%s", _("Failed to list network filters")); + goto cleanup; + } + + list->filters = vshMalloc(ctl, sizeof(virNWFilterPtr) * (nfilters)); + list->nfilters = 0; + + /* get the network filters */ + for (i = 0; i < nfilters ; i++) { + if (!(filter = virNWFilterLookupByName(ctl->conn, names[i]))) + continue; + list->filters[list->nfilters++] = filter; + } + + /* truncate network filters that weren't found */ + deleted = nfilters - list->nfilters; + +finished: + /* sort the list */ + if (list->filters && list->nfilters) + qsort(list->filters, list->nfilters, + sizeof(*list->filters), vshNWFilterSorter); + + /* truncate the list for not found filter objects */ + if (deleted) + VIR_SHRINK_N(list->filters, list->nfilters, deleted); + + success = true; + +cleanup: + for (i = 0; i < nfilters; i++) + VIR_FREE(names[i]); + VIR_FREE(names); + + if (!success) { + vshNWFilterListFree(list); + list = NULL; + } + + return list; +} /* * "nwfilter-list" command */ @@ -10436,57 +10564,33 @@ static const vshCmdOptDef opts_nwfilter_list[] = { static bool cmdNWFilterList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) { - int numfilters, i; - char **names; + int i; char uuid[VIR_UUID_STRING_BUFLEN]; + vshNWFilterListPtr list = NULL; if (!vshConnectionUsability(ctl, ctl->conn)) return false; - numfilters = virConnectNumOfNWFilters(ctl->conn); - if (numfilters < 0) { - vshError(ctl, "%s", _("Failed to list network filters")); - return false; - } - - names = vshMalloc(ctl, sizeof(char *) * numfilters); - - if ((numfilters = virConnectListNWFilters(ctl->conn, names, - numfilters)) < 0) { - vshError(ctl, "%s", _("Failed to list network filters")); - VIR_FREE(names); + if (!(list = vshNWFilterListCollect(ctl, 0))) return false; - } - - qsort(&names[0], numfilters, sizeof(char *), vshNameSorter); vshPrintExtra(ctl, "%-36s %-20s \n", _("UUID"), _("Name")); vshPrintExtra(ctl, "----------------------------------------------------------------\n"); - for (i = 0; i < numfilters; i++) { - virNWFilterPtr nwfilter = - virNWFilterLookupByName(ctl->conn, names[i]); - - /* this kind of work with networks is not atomic operation */ - if (!nwfilter) { - VIR_FREE(names[i]); - continue; - } + for (i = 0; i < list->nfilters; i++) { + virNWFilterPtr nwfilter = list->filters[i]; virNWFilterGetUUIDString(nwfilter, uuid); vshPrint(ctl, "%-36s %-20s\n", uuid, virNWFilterGetName(nwfilter)); - virNWFilterFree(nwfilter); - VIR_FREE(names[i]); } - VIR_FREE(names); + vshNWFilterListFree(list); return true; } - /* * "nwfilter-edit" command */ -- 1.7.7.3

The implementation is done manually as the generator does not support wrapping lists of C pointers into Python objects. python/libvirt-override-api.xml: Document python/libvirt-override-virConnect.py: * Implementation for listAllNWFilters. python/libvirt-override.c: Implementation for the wrapper. --- python/libvirt-override-api.xml | 6 ++++ python/libvirt-override-virConnect.py | 11 +++++++ python/libvirt-override.c | 48 +++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 0 deletions(-) diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index a3d6bbb..b8ab823 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -396,6 +396,12 @@ <arg name='conn' type='virConnectPtr' info='virConnect connection'/> <return type='str *' info='the list of network filter IDs or None in case of error'/> </function> + <function name='virConnectListAllNWFilters' file='python'> + <info>returns list of all network fitlers</info> + <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> + <arg name='flags' type='unsigned int' info='optional flags'/> + <return type='nwfilter *' info='the list of network filters or None in case of error'/> + </function> <function name='virNWFilterLookupByUUID' file='python'> <info>Try to lookup a network filter on the given hypervisor based on its UUID.</info> <return type='virNWFilterPtr' info='a new network filter object or NULL in case of failure'/> diff --git a/python/libvirt-override-virConnect.py b/python/libvirt-override-virConnect.py index c34cd63..caca982 100644 --- a/python/libvirt-override-virConnect.py +++ b/python/libvirt-override-virConnect.py @@ -255,3 +255,14 @@ return retlist + def listAllNWFilters(self, flags): + """Returns a list of network filter objects""" + ret = libvirtmod.virConnectListAllNWFilters(self._o, flags) + if ret is None: + raise libvirtError("virConnectListAllNWFilters() failed", conn=self) + + retlist = list() + for filter_ptr in ret: + retlist.append(virNWFilter(self, _obj=filter_ptr)) + + return retlist diff --git a/python/libvirt-override.c b/python/libvirt-override.c index 6449639..bdf5d12 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -3764,6 +3764,53 @@ libvirt_virConnectListNWFilters(PyObject *self ATTRIBUTE_UNUSED, } static PyObject * +libvirt_virConnectListAllNWFilters(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + PyObject *pyobj_conn; + PyObject *py_retval = NULL; + PyObject *tmp = NULL; + virConnectPtr conn; + virNWFilterPtr *filters = NULL; + int c_retval = 0; + int i; + unsigned int flags; + + if (!PyArg_ParseTuple(args, (char *)"Oi:virConnectListAllNWFilters", + &pyobj_conn, &flags)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virConnectListAllNWFilters(conn, &filters, flags); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) + return VIR_PY_NONE; + + if (!(py_retval = PyList_New(c_retval))) + goto cleanup; + + for (i = 0; i < c_retval; i++) { + if (!(tmp = libvirt_virNWFilterPtrWrap(filters[i])) || + PyList_SetItem(py_retval, i, tmp) < 0) { + Py_XDECREF(tmp); + Py_DECREF(py_retval); + py_retval = NULL; + goto cleanup; + } + /* python steals the pointer */ + filters[i] = NULL; + } + +cleanup: + for (i = 0; i < c_retval; i++) + if (filters[i]) + virNWFilterFree(filters[i]); + VIR_FREE(filters); + return py_retval; +} + +static PyObject * libvirt_virConnectListInterfaces(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { PyObject *py_retval; @@ -6138,6 +6185,7 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virNWFilterGetUUIDString", libvirt_virNWFilterGetUUIDString, METH_VARARGS, NULL}, {(char *) "virNWFilterLookupByUUID", libvirt_virNWFilterLookupByUUID, METH_VARARGS, NULL}, {(char *) "virConnectListNWFilters", libvirt_virConnectListNWFilters, METH_VARARGS, NULL}, + {(char *) "virConnectListAllNWFilters", libvirt_virConnectListAllNWFilters, METH_VARARGS, NULL}, {(char *) "virConnectListInterfaces", libvirt_virConnectListInterfaces, METH_VARARGS, NULL}, {(char *) "virConnectListDefinedInterfaces", libvirt_virConnectListDefinedInterfaces, METH_VARARGS, NULL}, {(char *) "virConnectListAllInterfaces", libvirt_virConnectListAllInterfaces, METH_VARARGS, NULL}, -- 1.7.7.3

This is to list the secret objects. No flags are supported include/libvirt/libvirt.h.in: Declare enum virConnectListAllSecretFlags and virConnectListAllSecrets. python/generator.py: Skip auto-generating src/driver.h: (virDrvConnectListAllSecrets) src/libvirt.c: Implement the public API src/libvirt_public.syms: Export the symbol to public --- include/libvirt/libvirt.h.in | 3 ++ python/generator.py | 1 + src/driver.h | 5 ++++ src/libvirt.c | 50 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 5 files changed, 60 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index aea4d8a..c67c89b 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -3164,6 +3164,9 @@ int virConnectNumOfSecrets (virConnectPtr conn); int virConnectListSecrets (virConnectPtr conn, char **uuids, int maxuuids); +int virConnectListAllSecrets(virConnectPtr conn, + virSecretPtr **secrets, + unsigned int flags); virSecretPtr virSecretLookupByUUID(virConnectPtr conn, const unsigned char *uuid); virSecretPtr virSecretLookupByUUIDString(virConnectPtr conn, diff --git a/python/generator.py b/python/generator.py index 00e242f..447ff47 100755 --- a/python/generator.py +++ b/python/generator.py @@ -462,6 +462,7 @@ skip_function = ( 'virConnectListAllInterfaces', # overridden in virConnect.py 'virConnectListAllNodeDevices', # overridden in virConnect.py 'virConnectListAllNWFilters', # overridden in virConnect.py + 'virConnectListAllSecrets', # overridden in virConnect.py 'virStreamRecvAll', # Pure python libvirt-override-virStream.py 'virStreamSendAll', # Pure python libvirt-override-virStream.py diff --git a/src/driver.h b/src/driver.h index 5ace502..8c1d799 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1540,6 +1540,10 @@ typedef int (*virDrvListSecrets) (virConnectPtr conn, char **uuids, int maxuuids); +typedef int + (*virDrvListAllSecrets) (virConnectPtr conn, + virSecretPtr **secrets, + unsigned int flags); typedef struct _virSecretDriver virSecretDriver; typedef virSecretDriver *virSecretDriverPtr; @@ -1561,6 +1565,7 @@ struct _virSecretDriver { virDrvNumOfSecrets numOfSecrets; virDrvListSecrets listSecrets; + virDrvListAllSecrets listAllSecrets; virDrvSecretLookupByUUID lookupByUUID; virDrvSecretLookupByUsage lookupByUsage; virDrvSecretDefineXML defineXML; diff --git a/src/libvirt.c b/src/libvirt.c index ff02c88..009e99f 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -14350,6 +14350,56 @@ error: } /** + * virConnectListAllSecrets: + * @conn: Pointer to the hypervisor connection. + * @secrets: Pointer to a variable to store the array containing the secret + * objects or NULL if the list is not required (just returns the + * number of secrets). + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Collect the list of secrets, and allocate an array to store those objects. + * + * Returns the number of secrets found or -1 and sets @secrets to NULL in case + * of error. On success, the array stored into @secrets is guaranteed to + * have an extra allocated element set to NULL but not included in the return count, + * to make iteration easier. The caller is responsible for calling + * virSecretFree() on each array element, then calling free() on @secrets. + */ +int +virConnectListAllSecrets(virConnectPtr conn, + virSecretPtr **secrets, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, secrets=%p, flags=%x", conn, secrets, flags); + + virResetLastError(); + + if (secrets) + *secrets = NULL; + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (conn->secretDriver && + conn->secretDriver->listAllSecrets) { + int ret; + ret = conn->secretDriver->listAllSecrets(conn, secrets, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} + +/** * virConnectListSecrets: * @conn: virConnect connection * @uuids: Pointer to an array to store the UUIDs diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index ab5f156..33b6446 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -552,6 +552,7 @@ LIBVIRT_0.9.14 { virConnectListAllInterfaces; virConnectListAllNodeDevices; virConnectListAllNWFilters; + virConnectListAllSecrets; } LIBVIRT_0.9.13; # .... define new API here using predicted next version number .... -- 1.7.7.3

The RPC generator doesn't support returning list of object yet, this patch do the work manually. * daemon/remote.c: Implemente the server side handler remoteDispatchConnectListAllSecrets. * src/remote/remote_driver.c: Add remote driver handler remoteConnectListAllSecrets. * src/remote/remote_protocol.x: New RPC procedure REMOTE_PROC_CONNECT_LIST_ALL_SECRETS and structs to represent the args and ret for it. * src/remote_protocol-structs: Likewise. --- daemon/remote.c | 54 +++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 64 ++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 13 ++++++++- src/remote_protocol-structs | 12 ++++++++ 4 files changed, 142 insertions(+), 1 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 9de0629..d381dd9 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -4280,6 +4280,60 @@ cleanup: return rv; } +static int +remoteDispatchConnectListAllSecrets(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_connect_list_all_secrets_args *args, + remote_connect_list_all_secrets_ret *ret) +{ + virSecretPtr *secrets = NULL; + int nsecrets = 0; + int i; + int rv = -1; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if ((nsecrets = virConnectListAllSecrets(priv->conn, + args->need_results ? &secrets : NULL, + args->flags)) < 0) + goto cleanup; + + if (secrets && nsecrets) { + if (VIR_ALLOC_N(ret->secrets.secrets_val, nsecrets) < 0) { + virReportOOMError(); + goto cleanup; + } + + ret->secrets.secrets_len = nsecrets; + + for (i = 0; i < nsecrets; i++) + make_nonnull_secret(ret->secrets.secrets_val + i, secrets[i]); + } else { + ret->secrets.secrets_len = 0; + ret->secrets.secrets_val = NULL; + } + + ret->ret = nsecrets; + + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (secrets) { + for (i = 0; i < nsecrets; i++) + virSecretFree(secrets[i]); + VIR_FREE(secrets); + } + return rv; +} + /*----- Helpers. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index ee6caf4..075cec1 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -3031,6 +3031,69 @@ done: return rv; } +static int +remoteConnectListAllSecrets(virConnectPtr conn, + virSecretPtr **secrets, + unsigned int flags) +{ + int rv = -1; + int i; + virSecretPtr *tmp_secrets = NULL; + remote_connect_list_all_secrets_args args; + remote_connect_list_all_secrets_ret ret; + + struct private_data *priv = conn->privateData; + + remoteDriverLock(priv); + + args.need_results = !!secrets; + args.flags = flags; + + memset(&ret, 0, sizeof(ret)); + if (call(conn, + priv, + 0, + REMOTE_PROC_CONNECT_LIST_ALL_SECRETS, + (xdrproc_t) xdr_remote_connect_list_all_secrets_args, + (char *) &args, + (xdrproc_t) xdr_remote_connect_list_all_secrets_ret, + (char *) &ret) == -1) + goto done; + + if (secrets) { + if (VIR_ALLOC_N(tmp_secrets, ret.secrets.secrets_len + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + for (i = 0; i < ret.secrets.secrets_len; i++) { + tmp_secrets[i] = get_nonnull_secret (conn, ret.secrets.secrets_val[i]); + if (!tmp_secrets[i]) { + virReportOOMError(); + goto cleanup; + } + } + *secrets = tmp_secrets; + tmp_secrets = NULL; + } + + rv = ret.ret; + +cleanup: + if (tmp_secrets) { + for (i = 0; i < ret.secrets.secrets_len; i++) + if (tmp_secrets[i]) + virSecretFree(tmp_secrets[i]); + VIR_FREE(tmp_secrets); + } + + xdr_free((xdrproc_t) xdr_remote_connect_list_all_secrets_ret, (char *) &ret); + +done: + remoteDriverUnlock(priv); + return rv; +} + /*----------------------------------------------------------------------*/ static virDrvOpenStatus ATTRIBUTE_NONNULL (1) @@ -5827,6 +5890,7 @@ static virSecretDriver secret_driver = { .close = remoteSecretClose, /* 0.7.1 */ .numOfSecrets = remoteNumOfSecrets, /* 0.7.1 */ .listSecrets = remoteListSecrets, /* 0.7.1 */ + .listAllSecrets = remoteConnectListAllSecrets, /* 0.9.14 */ .lookupByUUID = remoteSecretLookupByUUID, /* 0.7.1 */ .lookupByUsage = remoteSecretLookupByUsage, /* 0.7.1 */ .defineXML = remoteSecretDefineXML, /* 0.7.1 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 4b8b8b1..d884fc5 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1937,6 +1937,16 @@ struct remote_list_secrets_ret { remote_nonnull_string uuids<REMOTE_SECRET_UUID_LIST_MAX>; /* insert@1 */ }; +struct remote_connect_list_all_secrets_args { + int need_results; + unsigned int flags; +}; + +struct remote_connect_list_all_secrets_ret { + remote_nonnull_secret secrets<>; + unsigned int ret; +}; + struct remote_secret_lookup_by_uuid_args { remote_uuid uuid; }; @@ -2909,7 +2919,8 @@ enum remote_procedure { REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 280, /* skipgen skipgen priority:high */ REMOTE_PROC_CONNECT_LIST_ALL_NODE_DEVICES = 281, /* skipgen skipgen priority:high */ - REMOTE_PROC_CONNECT_LIST_ALL_NWFILTERS = 282 /* skipgen skipgen priority:high */ + REMOTE_PROC_CONNECT_LIST_ALL_NWFILTERS = 282, /* skipgen skipgen priority:high */ + REMOTE_PROC_CONNECT_LIST_ALL_SECRETS = 283 /* skipgen skipgen priority:high */ /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 56004ab..d65f7eb 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1461,6 +1461,17 @@ struct remote_list_secrets_ret { remote_nonnull_string * uuids_val; } uuids; }; +struct remote_list_all_secrets_args { + int need_results; + u_int flags; +}; +struct remote_list_all_secrets_ret { + struct { + u_int secrets_len; + remote_nonnull_network * secrets_val; + } secrets; + u_int ret; +}; struct remote_secret_lookup_by_uuid_args { remote_uuid uuid; }; @@ -2324,4 +2335,5 @@ enum remote_procedure { REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 280, REMOTE_PROC_CONNECT_LIST_ALL_NODE_DEVICES = 281, REMOTE_PROC_CONNECT_LIST_ALL_NWFILTERS = 282, + REMOTE_PROC_CONNECT_LIST_ALL_SECRETS = 283, }; -- 1.7.7.3

Simply returns the object list. No filtering. src/secret/secret_driver.c: Implement listAllSecrets --- src/secret/secret_driver.c | 58 +++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 57 insertions(+), 1 deletions(-) diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c index af3bfcf..a2b2383 100644 --- a/src/secret/secret_driver.c +++ b/src/secret/secret_driver.c @@ -601,7 +601,6 @@ cleanup: return -1; } - static const char * secretUsageIDForDef(virSecretDefPtr def) { @@ -620,6 +619,62 @@ secretUsageIDForDef(virSecretDefPtr def) } } +static int +secretListAllSecrets(virConnectPtr conn, + virSecretPtr **secrets, + unsigned int flags) { + virSecretDriverStatePtr driver = conn->secretPrivateData; + virSecretPtr *tmp_secrets = NULL; + int nsecrets = 0; + virSecretPtr secret = NULL; + virSecretEntryPtr entry = NULL; + int i = 0; + int ret = -1; + + virCheckFlags(0, -1); + + secretDriverLock(driver); + + for (entry = driver->secrets; entry != NULL; entry = entry ->next) + nsecrets++; + + if (!secrets) { + ret = nsecrets; + goto cleanup; + } + + if (VIR_ALLOC_N(tmp_secrets, nsecrets + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + for (entry = driver->secrets; entry != NULL; entry = entry ->next) { + if (!(secret = virGetSecret(conn, + entry->def->uuid, + entry->def->usage_type, + secretUsageIDForDef(entry->def)))) + goto cleanup; + tmp_secrets[i++] = secret; + } + + *secrets = tmp_secrets; + tmp_secrets = NULL; + ret = i; + + cleanup: + secretDriverUnlock(driver); + if (tmp_secrets) { + for (i = 0; i < nsecrets; i ++) { + if (tmp_secrets[i]) + virSecretFree(tmp_secrets[i]); + } + } + VIR_FREE(tmp_secrets); + + return ret; +} + + static virSecretPtr secretLookupByUUID(virConnectPtr conn, const unsigned char *uuid) { @@ -1072,6 +1127,7 @@ static virSecretDriver secretDriver = { .close = secretClose, /* 0.7.1 */ .numOfSecrets = secretNumOfSecrets, /* 0.7.1 */ .listSecrets = secretListSecrets, /* 0.7.1 */ + .listAllSecrets = secretListAllSecrets, /* 0.9.14 */ .lookupByUUID = secretLookupByUUID, /* 0.7.1 */ .lookupByUsage = secretLookupByUsage, /* 0.7.1 */ .defineXML = secretDefineXML, /* 0.7.1 */ -- 1.7.7.3

tools/virsh.c: * vshSecretSorter to sort secret object by name * vshSecretListFree to free the secret objects list. * vshSecretListCollect to collect the secret objects, trying to use new API first, fall back to older APIs if it's not supported. --- tools/virsh.c | 192 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 files changed, 153 insertions(+), 39 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index b5c4d97..2c92839 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -495,16 +495,6 @@ _vshStrdup(vshControl *ctl, const char *s, const char *filename, int line) #define realloc use_vshRealloc_instead_of_realloc #define strdup use_vshStrdup_instead_of_strdup -static int -vshNameSorter(const void *a, const void *b) -{ - const char **sa = (const char**)a; - const char **sb = (const char**)b; - - /* User visible sort, so we want locale-specific case comparison. */ - return strcasecmp(*sa, *sb); -} - static double prettyCapacity(unsigned long long val, const char **unit) { @@ -13987,6 +13977,139 @@ cleanup: return ret; } +static int +vshSecretSorter(const void *a, const void *b) +{ + virSecretPtr *sa = (virSecretPtr *) a; + virSecretPtr *sb = (virSecretPtr *) b; + char uuid_sa[VIR_UUID_STRING_BUFLEN]; + char uuid_sb[VIR_UUID_STRING_BUFLEN]; + + if (*sa && !*sb) + return -1; + + if (!*sa) + return *sb != NULL; + + virSecretGetUUIDString(*sa, uuid_sa); + virSecretGetUUIDString(*sb, uuid_sb); + + return strcasecmp(uuid_sa, uuid_sb); +} + +struct vshSecretList { + virSecretPtr *secrets; + size_t nsecrets; +}; +typedef struct vshSecretList *vshSecretListPtr; + +static void +vshSecretListFree(vshSecretListPtr list) +{ + int i; + + if (list && list->nsecrets) { + for (i = 0; i < list->nsecrets; i++) { + if (list->secrets[i]) + virSecretFree(list->secrets[i]); + } + VIR_FREE(list->secrets); + } + VIR_FREE(list); +} + +static vshSecretListPtr +vshSecretListCollect(vshControl *ctl, + unsigned int flags) +{ + vshSecretListPtr list = vshMalloc(ctl, sizeof(*list)); + int i; + int ret; + virSecretPtr secret; + bool success = false; + size_t deleted = 0; + int nsecrets = 0; + char **uuids = NULL; + + /* try the list with flags support (0.9.14 and later) */ + if ((ret = virConnectListAllSecrets(ctl->conn, + &list->secrets, + flags)) >= 0) { + list->nsecrets = ret; + goto finished; + } + + /* check if the command is actually supported */ + if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) { + virFreeError(last_error); + last_error = NULL; + goto fallback; + } + + /* there was an error during the call */ + vshError(ctl, "%s", _("Failed to list node secrets")); + goto cleanup; + + +fallback: + /* fall back to old method (0.9.13 and older) */ + virResetLastError(); + + nsecrets = virConnectNumOfSecrets(ctl->conn); + if (nsecrets < 0) { + vshError(ctl, "%s", _("Failed to count secrets")); + goto cleanup; + } + + if (nsecrets == 0) + return list; + + uuids = vshMalloc(ctl, sizeof(char *) * nsecrets); + + nsecrets = virConnectListSecrets(ctl->conn, uuids, nsecrets); + if (nsecrets < 0) { + vshError(ctl, "%s", _("Failed to list secrets")); + goto cleanup; + } + + list->secrets = vshMalloc(ctl, sizeof(virSecretPtr) * (nsecrets)); + list->nsecrets = 0; + + /* get the secrets */ + for (i = 0; i < nsecrets ; i++) { + if (!(secret = virSecretLookupByUUIDString(ctl->conn, uuids[i]))) + continue; + list->secrets[list->nsecrets++] = secret; + } + + /* truncate secrets that weren't found */ + deleted = nsecrets - list->nsecrets; + +finished: + /* sort the list */ + if (list->secrets && list->nsecrets) + qsort(list->secrets, list->nsecrets, + sizeof(*list->secrets), vshSecretSorter); + + /* truncate the list for not found secret objects */ + if (deleted) + VIR_SHRINK_N(list->secrets, list->nsecrets, deleted); + + success = true; + +cleanup: + for (i = 0; i < nsecrets; i++) + VIR_FREE(uuids[i]); + VIR_FREE(uuids); + + if (!success) { + vshSecretListFree(list); + list = NULL; + } + + return list; +} + /* * "secret-list" command */ @@ -13999,59 +14122,50 @@ static const vshCmdInfo info_secret_list[] = { static bool cmdSecretList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) { - int maxuuids = 0, i; - char **uuids = NULL; + int i; + vshSecretListPtr list = NULL; + bool ret = false; if (!vshConnectionUsability(ctl, ctl->conn)) return false; - maxuuids = virConnectNumOfSecrets(ctl->conn); - if (maxuuids < 0) { - vshError(ctl, "%s", _("Failed to list secrets")); - return false; - } - uuids = vshMalloc(ctl, sizeof(*uuids) * maxuuids); - - maxuuids = virConnectListSecrets(ctl->conn, uuids, maxuuids); - if (maxuuids < 0) { - vshError(ctl, "%s", _("Failed to list secrets")); - VIR_FREE(uuids); + if (!(list = vshSecretListCollect(ctl, 0))) return false; - } - - qsort(uuids, maxuuids, sizeof(char *), vshNameSorter); vshPrintExtra(ctl, "%-36s %s\n", _("UUID"), _("Usage")); vshPrintExtra(ctl, "-----------------------------------------------------------\n"); - for (i = 0; i < maxuuids; i++) { - virSecretPtr sec = virSecretLookupByUUIDString(ctl->conn, uuids[i]); + for (i = 0; i < list->nsecrets; i++) { + virSecretPtr sec = list->secrets[i]; const char *usageType = NULL; - if (!sec) { - VIR_FREE(uuids[i]); - continue; - } - switch (virSecretGetUsageType(sec)) { case VIR_SECRET_USAGE_TYPE_VOLUME: usageType = _("Volume"); break; } + char uuid[VIR_UUID_STRING_BUFLEN]; + if (virSecretGetUUIDString(list->secrets[i], uuid) < 0) { + vshError(ctl, "%s", _("Failed to get uuid of secret")); + goto cleanup; + } + if (usageType) { vshPrint(ctl, "%-36s %s %s\n", - uuids[i], usageType, + uuid, usageType, virSecretGetUsageID(sec)); } else { vshPrint(ctl, "%-36s %s\n", - uuids[i], _("Unused")); + uuid, _("Unused")); } - virSecretFree(sec); - VIR_FREE(uuids[i]); } - VIR_FREE(uuids); - return true; + + ret = true; + +cleanup: + vshSecretListFree(list); + return ret; } -- 1.7.7.3

The implementation is done manually as the generator does not support wrapping lists of C pointers into Python objects. python/libvirt-override-api.xml: Document python/libvirt-override-virConnect.py: Implementation for listAllSecrets. python/libvirt-override.c: Implementation for the wrapper. --- python/libvirt-override-api.xml | 6 ++++ python/libvirt-override-virConnect.py | 12 ++++++++ python/libvirt-override.c | 48 +++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 0 deletions(-) diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index b8ab823..4f609ee 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -368,6 +368,12 @@ <arg name='conn' type='virConnectPtr' info='virConnect connection'/> <return type='str *' info='the list of secret IDs or None in case of error'/> </function> + <function name='virConnectListAllSecrets' file='python'> + <info>returns list of all interfaces</info> + <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> + <arg name='flags' type='unsigned int' info='optional flags'/> + <return type='secret *' info='the list of secrets or None in case of error'/> + </function> <function name='virSecretSetValue' file='libvirt' module='libvirt'> <info>Associates a value with a secret.</info> <return type='int' info='0 on success, -1 on failure.'/> diff --git a/python/libvirt-override-virConnect.py b/python/libvirt-override-virConnect.py index caca982..6bec66d 100644 --- a/python/libvirt-override-virConnect.py +++ b/python/libvirt-override-virConnect.py @@ -266,3 +266,15 @@ retlist.append(virNWFilter(self, _obj=filter_ptr)) return retlist + + def listAllSecrets(self, flags): + """Returns a list of secret objects""" + ret = libvirtmod.virConnectListAllSecrets(self._o, flags) + if ret is None: + raise libvirtError("virConnectListAllSecrets() failed", conn=self) + + retlist = list() + for secret_ptr in ret: + retlist.append(virSecret(self, _obj=secret_ptr)) + + return retlist diff --git a/python/libvirt-override.c b/python/libvirt-override.c index bdf5d12..0098773 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -3592,6 +3592,53 @@ libvirt_virConnectListSecrets(PyObject *self ATTRIBUTE_UNUSED, } static PyObject * +libvirt_virConnectListAllSecrets(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + PyObject *pyobj_conn; + PyObject *py_retval = NULL; + PyObject *tmp = NULL; + virConnectPtr conn; + virSecretPtr *secrets = NULL; + int c_retval = 0; + int i; + unsigned int flags; + + if (!PyArg_ParseTuple(args, (char *)"Oi:virConnectListAllSecrets", + &pyobj_conn, &flags)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virConnectListAllSecrets(conn, &secrets, flags); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) + return VIR_PY_NONE; + + if (!(py_retval = PyList_New(c_retval))) + goto cleanup; + + for (i = 0; i < c_retval; i++) { + if (!(tmp = libvirt_virSecretPtrWrap(secrets[i])) || + PyList_SetItem(py_retval, i, tmp) < 0) { + Py_XDECREF(tmp); + Py_DECREF(py_retval); + py_retval = NULL; + goto cleanup; + } + /* python steals the pointer */ + secrets[i] = NULL; + } + +cleanup: + for (i = 0; i < c_retval; i++) + if (secrets[i]) + virSecretFree(secrets[i]); + VIR_FREE(secrets); + return py_retval; +} + +static PyObject * libvirt_virSecretGetValue(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { PyObject *py_retval; @@ -6179,6 +6226,7 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virSecretGetUUIDString", libvirt_virSecretGetUUIDString, METH_VARARGS, NULL}, {(char *) "virSecretLookupByUUID", libvirt_virSecretLookupByUUID, METH_VARARGS, NULL}, {(char *) "virConnectListSecrets", libvirt_virConnectListSecrets, METH_VARARGS, NULL}, + {(char *) "virConnectListAllSecrets", libvirt_virConnectListAllSecrets, METH_VARARGS, NULL}, {(char *) "virSecretGetValue", libvirt_virSecretGetValue, METH_VARARGS, NULL}, {(char *) "virSecretSetValue", libvirt_virSecretSetValue, METH_VARARGS, NULL}, {(char *) "virNWFilterGetUUID", libvirt_virNWFilterGetUUID, METH_VARARGS, NULL}, -- 1.7.7.3
participants (5)
-
Daniel P. Berrange
-
Eric Blake
-
Guannan Ren
-
Laine Stump
-
Osier Yang