On Wed, 2008-08-27 at 17:51 +0100, Daniel P. Berrange wrote: > On Mon, Aug 25, 2008 at 10:33:45AM -0400, David Lively wrote: > > After making the change I suggested above, it now feels a little strange > > because "Pool" is gone from the name. I'm starting to think > > "*Discover[Storage]PoolSources*" is the only good choice. It's rather > > long, but makes it clear we're talking about storage pool sources (as > > opposed to "storage sources", which feels a little ambiguous, or > > "storage pools" which isn't accurate since they're not (yet) pools). > > Discover is a bit of a long word - lets use 'Find' instead, so it makes > the API name a little shorter - and no worse than our existing longest > API name. In other words: > > virConnectFindStoragePoolSources() Sounds good. The attached patch uses this name (and others consistent with it), and should implement all the suggestions from Daniel V and Jim M. Thanks again to all three of you for the helpful comments. Dave
diff --git a/configure.in b/configure.in index 9479f1c..430a097 100644 --- a/configure.in +++ b/configure.in @@ -671,6 +671,11 @@ if test "$with_storage_fs" = "yes" -o "$with_storage_fs" = "check"; then fi fi AM_CONDITIONAL([WITH_STORAGE_FS], [test "$with_storage_fs" = "yes"]) +if test "$with_storage_fs" = "yes"; then + AC_PATH_PROG([SHOWMOUNT], [showmount], [], [$PATH:/sbin:/usr/sbin]) + AC_DEFINE_UNQUOTED([SHOWMOUNT], ["$SHOWMOUNT"], + [Location or name of the showmount program]) +fi AC_PATH_PROG([QEMU_IMG], [qemu-img], [], [$PATH:/sbin:/usr/sbin:/bin:/usr/bin]) if test -n "$QEMU_IMG" ; then diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h index 9c3e1c2..05cb68b 100644 --- a/include/libvirt/libvirt.h +++ b/include/libvirt/libvirt.h @@ -890,6 +890,14 @@ int virConnectListDefinedStoragePools(virConnectPtr conn, int maxnames); /* + * Query a host for storage pools of a particular type + */ +char * virConnectFindStoragePoolSources(virConnectPtr conn, + const char *type, + const char *srcSpec, + unsigned int flags); + +/* * Lookup pool by name or uuid */ virStoragePoolPtr virStoragePoolLookupByName (virConnectPtr conn, diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index f077a26..b91d729 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -890,6 +890,14 @@ int virConnectListDefinedStoragePools(virConnectPtr conn, int maxnames); /* + * Query a host for storage pools of a particular type + */ +char * virConnectFindStoragePoolSources(virConnectPtr conn, + const char *type, + const char *srcSpec, + unsigned int flags); + +/* * Lookup pool by name or uuid */ virStoragePoolPtr virStoragePoolLookupByName (virConnectPtr conn, diff --git a/libvirt.spec.in b/libvirt.spec.in index d37c0e0..bac84a5 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -55,6 +55,9 @@ Requires: PolicyKit >= 0.6 %endif # For mount/umount in FS driver BuildRequires: util-linux +# For showmount in FS driver (netfs discovery) +BuildRequires: nfs-utils +Requires: nfs-utils %if %{with_qemu} # From QEMU RPMs Requires: /usr/bin/qemu-img diff --git a/qemud/remote.c b/qemud/remote.c index b5a6ec9..3e43dcf 100644 --- a/qemud/remote.c +++ b/qemud/remote.c @@ -2958,6 +2958,27 @@ remoteDispatchListStoragePools (struct qemud_server *server ATTRIBUTE_UNUSED, } static int +remoteDispatchFindStoragePoolSources (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + remote_find_storage_pool_sources_args *args, + remote_find_storage_pool_sources_ret *ret) +{ + CHECK_CONN(client); + + ret->xml = + virConnectFindStoragePoolSources (client->conn, + args->type, + args->srcSpec ? *args->srcSpec : NULL, + args->flags); + if (ret->xml == NULL) + return -1; + + return 0; +} + + +static int remoteDispatchStoragePoolCreate (struct qemud_server *server ATTRIBUTE_UNUSED, struct qemud_client *client, remote_message_header *req, diff --git a/qemud/remote_dispatch_localvars.h b/qemud/remote_dispatch_localvars.h index d889c8a..18d71e9 100644 --- a/qemud/remote_dispatch_localvars.h +++ b/qemud/remote_dispatch_localvars.h @@ -80,6 +80,8 @@ remote_domain_resume_args lv_remote_domain_resume_args; remote_network_get_bridge_name_args lv_remote_network_get_bridge_name_args; remote_network_get_bridge_name_ret lv_remote_network_get_bridge_name_ret; remote_domain_destroy_args lv_remote_domain_destroy_args; +remote_find_storage_pool_sources_args lv_remote_find_storage_pool_sources_args; +remote_find_storage_pool_sources_ret lv_remote_find_storage_pool_sources_ret; remote_auth_sasl_step_args lv_remote_auth_sasl_step_args; remote_auth_sasl_step_ret lv_remote_auth_sasl_step_ret; remote_domain_migrate_finish_args lv_remote_domain_migrate_finish_args; diff --git a/qemud/remote_dispatch_proc_switch.h b/qemud/remote_dispatch_proc_switch.h index ebb2433..767b142 100644 --- a/qemud/remote_dispatch_proc_switch.h +++ b/qemud/remote_dispatch_proc_switch.h @@ -335,6 +335,15 @@ case REMOTE_PROC_DOMAIN_UNDEFINE: args = (char *) &lv_remote_domain_undefine_args; memset (&lv_remote_domain_undefine_args, 0, sizeof lv_remote_domain_undefine_args); break; +case REMOTE_PROC_FIND_STORAGE_POOL_SOURCES: + fn = (dispatch_fn) remoteDispatchFindStoragePoolSources; + args_filter = (xdrproc_t) xdr_remote_find_storage_pool_sources_args; + args = (char *) &lv_remote_find_storage_pool_sources_args; + memset (&lv_remote_find_storage_pool_sources_args, 0, sizeof lv_remote_find_storage_pool_sources_args); + ret_filter = (xdrproc_t) xdr_remote_find_storage_pool_sources_ret; + ret = (char *) &lv_remote_find_storage_pool_sources_ret; + memset (&lv_remote_find_storage_pool_sources_ret, 0, sizeof lv_remote_find_storage_pool_sources_ret); + break; case REMOTE_PROC_GET_CAPABILITIES: fn = (dispatch_fn) remoteDispatchGetCapabilities; ret_filter = (xdrproc_t) xdr_remote_get_capabilities_ret; diff --git a/qemud/remote_dispatch_prototypes.h b/qemud/remote_dispatch_prototypes.h index 1d9d794..950ad05 100644 --- a/qemud/remote_dispatch_prototypes.h +++ b/qemud/remote_dispatch_prototypes.h @@ -47,6 +47,7 @@ static int remoteDispatchDomainSetVcpus (struct qemud_server *server, struct qem static int remoteDispatchDomainShutdown (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_shutdown_args *args, void *ret); static int remoteDispatchDomainSuspend (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_suspend_args *args, void *ret); static int remoteDispatchDomainUndefine (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_undefine_args *args, void *ret); +static int remoteDispatchFindStoragePoolSources (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_find_storage_pool_sources_args *args, remote_find_storage_pool_sources_ret *ret); static int remoteDispatchGetCapabilities (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_get_capabilities_ret *ret); static int remoteDispatchGetHostname (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_get_hostname_ret *ret); static int remoteDispatchGetMaxVcpus (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_get_max_vcpus_args *args, remote_get_max_vcpus_ret *ret); diff --git a/qemud/remote_protocol.c b/qemud/remote_protocol.c index 39a20c2..ea9a160 100644 --- a/qemud/remote_protocol.c +++ b/qemud/remote_protocol.c @@ -1502,6 +1502,28 @@ xdr_remote_list_defined_storage_pools_ret (XDR *xdrs, remote_list_defined_storag } bool_t +xdr_remote_find_storage_pool_sources_args (XDR *xdrs, remote_find_storage_pool_sources_args *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->type)) + return FALSE; + if (!xdr_remote_string (xdrs, &objp->srcSpec)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_find_storage_pool_sources_ret (XDR *xdrs, remote_find_storage_pool_sources_ret *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->xml)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_storage_pool_lookup_by_uuid_args (XDR *xdrs, remote_storage_pool_lookup_by_uuid_args *objp) { diff --git a/qemud/remote_protocol.h b/qemud/remote_protocol.h index 6950f83..e4b1487 100644 --- a/qemud/remote_protocol.h +++ b/qemud/remote_protocol.h @@ -837,6 +837,18 @@ struct remote_list_defined_storage_pools_ret { }; typedef struct remote_list_defined_storage_pools_ret remote_list_defined_storage_pools_ret; +struct remote_find_storage_pool_sources_args { + remote_nonnull_string type; + remote_string srcSpec; + u_int flags; +}; +typedef struct remote_find_storage_pool_sources_args remote_find_storage_pool_sources_args; + +struct remote_find_storage_pool_sources_ret { + remote_nonnull_string xml; +}; +typedef struct remote_find_storage_pool_sources_ret remote_find_storage_pool_sources_ret; + struct remote_storage_pool_lookup_by_uuid_args { remote_uuid uuid; }; @@ -1146,7 +1158,7 @@ enum remote_procedure { REMOTE_PROC_LIST_STORAGE_POOLS = 72, REMOTE_PROC_NUM_OF_DEFINED_STORAGE_POOLS = 73, REMOTE_PROC_LIST_DEFINED_STORAGE_POOLS = 74, - REMOTE_PROC_DISCOVER_STORAGE_POOLS = 75, + REMOTE_PROC_FIND_STORAGE_POOL_SOURCES = 75, REMOTE_PROC_STORAGE_POOL_CREATE_XML = 76, REMOTE_PROC_STORAGE_POOL_DEFINE_XML = 77, REMOTE_PROC_STORAGE_POOL_CREATE = 78, @@ -1337,6 +1349,8 @@ extern bool_t xdr_remote_list_storage_pools_ret (XDR *, remote_list_storage_poo extern bool_t xdr_remote_num_of_defined_storage_pools_ret (XDR *, remote_num_of_defined_storage_pools_ret*); extern bool_t xdr_remote_list_defined_storage_pools_args (XDR *, remote_list_defined_storage_pools_args*); extern bool_t xdr_remote_list_defined_storage_pools_ret (XDR *, remote_list_defined_storage_pools_ret*); +extern bool_t xdr_remote_find_storage_pool_sources_args (XDR *, remote_find_storage_pool_sources_args*); +extern bool_t xdr_remote_find_storage_pool_sources_ret (XDR *, remote_find_storage_pool_sources_ret*); extern bool_t xdr_remote_storage_pool_lookup_by_uuid_args (XDR *, remote_storage_pool_lookup_by_uuid_args*); extern bool_t xdr_remote_storage_pool_lookup_by_uuid_ret (XDR *, remote_storage_pool_lookup_by_uuid_ret*); extern bool_t xdr_remote_storage_pool_lookup_by_name_args (XDR *, remote_storage_pool_lookup_by_name_args*); @@ -1516,6 +1530,8 @@ extern bool_t xdr_remote_list_storage_pools_ret (); extern bool_t xdr_remote_num_of_defined_storage_pools_ret (); extern bool_t xdr_remote_list_defined_storage_pools_args (); extern bool_t xdr_remote_list_defined_storage_pools_ret (); +extern bool_t xdr_remote_find_storage_pool_sources_args (); +extern bool_t xdr_remote_find_storage_pool_sources_ret (); extern bool_t xdr_remote_storage_pool_lookup_by_uuid_args (); extern bool_t xdr_remote_storage_pool_lookup_by_uuid_ret (); extern bool_t xdr_remote_storage_pool_lookup_by_name_args (); diff --git a/qemud/remote_protocol.x b/qemud/remote_protocol.x index 82bd18e..148fbd5 100644 --- a/qemud/remote_protocol.x +++ b/qemud/remote_protocol.x @@ -763,6 +763,16 @@ struct remote_list_defined_storage_pools_ret { remote_nonnull_string names<REMOTE_STORAGE_POOL_NAME_LIST_MAX>; }; +struct remote_find_storage_pool_sources_args { + remote_nonnull_string type; + remote_string srcSpec; + unsigned flags; +}; + +struct remote_find_storage_pool_sources_ret { + remote_nonnull_string xml; +}; + struct remote_storage_pool_lookup_by_uuid_args { remote_uuid uuid; }; @@ -1042,7 +1052,7 @@ enum remote_procedure { REMOTE_PROC_LIST_STORAGE_POOLS = 72, REMOTE_PROC_NUM_OF_DEFINED_STORAGE_POOLS = 73, REMOTE_PROC_LIST_DEFINED_STORAGE_POOLS = 74, - REMOTE_PROC_DISCOVER_STORAGE_POOLS = 75, + REMOTE_PROC_FIND_STORAGE_POOL_SOURCES = 75, REMOTE_PROC_STORAGE_POOL_CREATE_XML = 76, REMOTE_PROC_STORAGE_POOL_DEFINE_XML = 77, REMOTE_PROC_STORAGE_POOL_CREATE = 78, diff --git a/src/driver.h b/src/driver.h index eb428a0..655cd05 100644 --- a/src/driver.h +++ b/src/driver.h @@ -444,6 +444,11 @@ typedef int (*virDrvConnectListDefinedStoragePools) (virConnectPtr conn, char **const names, int maxnames); +typedef char * + (*virDrvConnectFindStoragePoolSources) (virConnectPtr conn, + const char *type, + const char *srcSpec, + unsigned int flags); typedef virStoragePoolPtr (*virDrvStoragePoolLookupByName) (virConnectPtr conn, const char *name); @@ -548,6 +553,7 @@ struct _virStorageDriver { virDrvConnectListStoragePools listPools; virDrvConnectNumOfDefinedStoragePools numOfDefinedPools; virDrvConnectListDefinedStoragePools listDefinedPools; + virDrvConnectFindStoragePoolSources findPoolSources; virDrvStoragePoolLookupByName poolLookupByName; virDrvStoragePoolLookupByUUID poolLookupByUUID; virDrvStoragePoolLookupByVolume poolLookupByVolume; diff --git a/src/internal.h b/src/internal.h index 1ecec05..d96504d 100644 --- a/src/internal.h +++ b/src/internal.h @@ -362,4 +362,16 @@ int __virDomainMigratePrepare (virConnectPtr dconn, char **cookie, int *cookiele int __virDomainMigratePerform (virDomainPtr domain, const char *cookie, int cookielen, const char *uri, unsigned long flags, const char *dname, unsigned long bandwidth); virDomainPtr __virDomainMigrateFinish (virConnectPtr dconn, const char *dname, const char *cookie, int cookielen, const char *uri, unsigned long flags); +typedef struct _virStringList virStringList; + +struct _virStringList { + char *val; + int len; + struct _virStringList *next; +}; + +char *virStringListJoin(const virStringList *list, const char *pre, + const char *post, const char *sep); +void virStringListFree(virStringList *list); + #endif /* __VIR_INTERNAL_H__ */ diff --git a/src/libvirt.c b/src/libvirt.c index c31a619..9bf9373 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -36,6 +36,7 @@ #include "uuid.h" #include "util.h" +#include "memory.h" #ifdef WITH_TEST #include "test.h" @@ -4125,6 +4126,50 @@ virConnectListDefinedStoragePools(virConnectPtr conn, /** + * virConnectFindStoragePoolSources: + * @conn: pointer to hypervisor connection + * @type: type of storage pool sources to discover + * @srcSpec: XML document specifying discovery source + * @flags: flags for discovery (unused, pass 0) + * + * Talks to a storage backend and attempts to auto-discover the set of + * available storage pool sources. e.g. For iSCSI this would be a set of + * iSCSI targets. For NFS this would be a list of exported paths. The + * srcSpec (optional for some storage pool types, e.g. local ones) is + * an instance of the storage pool's source element specifying where + * to look for the pools. + * + * srcSpec is not required for some types (e.g., those querying + * local storage resources only) + * + * Returns an xml document consisting of a SourceList element + * containing a source document appropriate to the given pool + * type for each discovered source. + */ +char * +virConnectFindStoragePoolSources(virConnectPtr conn, + const char *type, + const char *srcSpec, + unsigned int flags) +{ + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return NULL; + } + if (type == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return NULL; + } + + if (conn->storageDriver && conn->storageDriver->findPoolSources) + return conn->storageDriver->findPoolSources(conn, type, srcSpec, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + + +/** * virStoragePoolLookupByName: * @conn: pointer to hypervisor connection * @name: name of pool to fetch @@ -5234,3 +5279,45 @@ virStorageVolGetPath(virStorageVolPtr vol) virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); return NULL; } + + + + +/* Not for public use. Combines the elements of a virStringList + * into a single string. + */ +char *virStringListJoin(const virStringList *list, const char *pre, + const char *post, const char *sep) +{ + size_t pre_len = strlen(pre); + size_t sep_len = strlen(sep); + size_t len = pre_len + strlen(post); + const virStringList *p; + char *retval; + + for (p = list; p; p = p->next) + len += p->len + sep_len; + if (VIR_ALLOC_N(retval, len+1) < 0) + return NULL; + strcpy(retval, pre); + len = pre_len; + for (p = list; p; p = p->next) { + strcpy(retval + len, p->val); + len += p->len; + strcpy(retval + len, sep); + len += sep_len; + } + strcpy(retval + len, post); + + return retval; +} + + +void virStringListFree(virStringList *list) +{ + while (list) { + virStringList *p = list->next; + VIR_FREE(list); + list = p; + } +} diff --git a/src/libvirt_sym.version b/src/libvirt_sym.version index 6561bc9..b8c470c 100644 --- a/src/libvirt_sym.version +++ b/src/libvirt_sym.version @@ -107,7 +107,7 @@ virConnectNumOfDefinedStoragePools; virConnectListStoragePools; virConnectListDefinedStoragePools; - virConnectDiscoverStoragePools; + virConnectFindStoragePoolSources; virStoragePoolLookupByName; virStoragePoolLookupByUUID; virStoragePoolLookupByUUIDString; diff --git a/src/remote_internal.c b/src/remote_internal.c index 4d173e3..586b343 100644 --- a/src/remote_internal.c +++ b/src/remote_internal.c @@ -3079,6 +3079,47 @@ remoteListDefinedStoragePools (virConnectPtr conn, return ret.names.names_len; } +static char * +remoteFindStoragePoolSources (virConnectPtr conn, + const char *type, + const char *srcSpec, + unsigned int flags) +{ + remote_find_storage_pool_sources_args args; + remote_find_storage_pool_sources_ret ret; + GET_STORAGE_PRIVATE (conn, NULL); + const char *emptyString = ""; + char *retval; + + args.type = (char*)type; + /* + * I'd think the following would work here: + * args.srcSpec = (char**)&srcSpec; + * since srcSpec is a remote_string (not a remote_nonnull_string). + * + * But when srcSpec is NULL, this yields: + * libvir: Remote error : marshalling args + * + * So for now I'm working around this by turning NULL srcSpecs + * into empty strings. + */ + args.srcSpec = srcSpec ? (char **)&srcSpec : (char **)&emptyString; + args.flags = flags; + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_FIND_STORAGE_POOL_SOURCES, + (xdrproc_t) xdr_remote_find_storage_pool_sources_args, (char *) &args, + (xdrproc_t) xdr_remote_find_storage_pool_sources_ret, (char *) &ret) == -1) + return NULL; + + retval = ret.xml; + ret.xml = NULL; /* To stop xdr_free free'ing it */ + + xdr_free ((xdrproc_t) xdr_remote_find_storage_pool_sources_ret, (char *) &ret); + + return retval; +} + static virStoragePoolPtr remoteStoragePoolLookupByUUID (virConnectPtr conn, const unsigned char *uuid) @@ -4940,6 +4981,7 @@ static virStorageDriver storage_driver = { .listPools = remoteListStoragePools, .numOfDefinedPools = remoteNumOfDefinedStoragePools, .listDefinedPools = remoteListDefinedStoragePools, + .findPoolSources = remoteFindStoragePoolSources, .poolLookupByUUID = remoteStoragePoolLookupByUUID, .poolLookupByName = remoteStoragePoolLookupByName, .poolLookupByVolume = remoteStoragePoolLookupByVolume, diff --git a/src/storage_backend.h b/src/storage_backend.h index 797ca01..a06746b 100644 --- a/src/storage_backend.h +++ b/src/storage_backend.h @@ -63,6 +63,10 @@ struct _virStorageBackendPoolOptions { virStoragePoolFormatFromString formatFromString; }; +#define SOURCES_START_TAG "<sources>" +#define SOURCES_END_TAG "</sources>" + +typedef char * (*virStorageBackendFindPoolSources)(virConnectPtr conn, const char *srcSpec, unsigned int flags); typedef int (*virStorageBackendStartPool)(virConnectPtr conn, virStoragePoolObjPtr pool); typedef int (*virStorageBackendBuildPool)(virConnectPtr conn, virStoragePoolObjPtr pool, unsigned int flags); typedef int (*virStorageBackendRefreshPool)(virConnectPtr conn, virStoragePoolObjPtr pool); @@ -80,6 +84,7 @@ typedef virStorageBackend *virStorageBackendPtr; struct _virStorageBackend { int type; + virStorageBackendFindPoolSources findPoolSources; virStorageBackendStartPool startPool; virStorageBackendBuildPool buildPool; virStorageBackendRefreshPool refreshPool; diff --git a/src/storage_backend_fs.c b/src/storage_backend_fs.c index 36bfac4..63124df 100644 --- a/src/storage_backend_fs.c +++ b/src/storage_backend_fs.c @@ -36,11 +36,16 @@ #include <mntent.h> #include <string.h> +#include <libxml/parser.h> +#include <libxml/tree.h> +#include <libxml/xpath.h> + #include "internal.h" #include "storage_backend_fs.h" #include "storage_conf.h" #include "util.h" #include "memory.h" +#include "xml.h" enum { VIR_STORAGE_POOL_FS_AUTO = 0, @@ -442,6 +447,129 @@ static int virStorageBackendProbeFile(virConnectPtr conn, } #if WITH_STORAGE_FS +struct _virNetfsDiscoverState { + const char *host; + virStringList *list; +}; + +typedef struct _virNetfsDiscoverState virNetfsDiscoverState; + +static int +virStorageBackendFileSystemNetFindPoolSourcesFunc(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, + char **const groups, + void *data) +{ + virNetfsDiscoverState *state = data; + virStringList *newItem; + const char *name, *path; + + path = groups[0]; + + name = strrchr(path, '/'); + if (name == NULL) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("invalid netfs path (no /): %s"), path); + return -1; + } + name += 1; + if (*name == '\0') { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("invalid netfs path (ends in /): %s"), path); + return -1; + } + + /* Append new XML desc to list */ + + if (VIR_ALLOC(newItem) != 0) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("new xml desc")); + return -1; + } + + if (asprintf(&newItem->val, + "<source><host name='%s'/><dir path='%s'/></source>", + state->host, path) <= 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("asprintf failed")); + VIR_FREE(newItem); + return -1; + } + + newItem->len = strlen(newItem->val); + newItem->next = state->list; + state->list = newItem; + + return 0; +} + +static char * +virStorageBackendFileSystemNetFindPoolSources(virConnectPtr conn, + const char *srcSpec, + unsigned int flags ATTRIBUTE_UNUSED) +{ + /* + * # showmount --no-headers -e HOSTNAME + * /tmp * + * /A dir demo1.foo.bar,demo2.foo.bar + * + * Extract directory name (including possible interior spaces ...). + */ + + const char *regexes[] = { + "^(/.*\\S) +\\S+$" + }; + int vars[] = { + 1 + }; + xmlDocPtr doc = NULL; + xmlXPathContextPtr xpath_ctxt = NULL; + virNetfsDiscoverState state = { .host = NULL, .list = NULL }; + const char *prog[] = { SHOWMOUNT, "--no-headers", "--exports", NULL, NULL }; + int exitstatus; + char *retval = NULL; + + doc = xmlReadDoc((const xmlChar *)srcSpec, "srcSpec.xml", NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOERROR | XML_PARSE_NOWARNING); + if (doc == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "%s", _("bad <source> spec")); + goto cleanup; + } + + xpath_ctxt = xmlXPathNewContext(doc); + if (xpath_ctxt == NULL) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("xpath_ctxt")); + goto cleanup; + } + + state.host = virXPathString(conn, "string(/source/host/@name)", xpath_ctxt); + if (!state.host || !state.host[0]) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, "%s", + _("missing <host> in <source> spec")); + goto cleanup; + } + prog[3] = state.host; + + if (virStorageBackendRunProgRegex(conn, NULL, prog, 1, regexes, vars, + virStorageBackendFileSystemNetFindPoolSourcesFunc, + &state, &exitstatus) < 0) + goto cleanup; + + retval = virStringListJoin(state.list, SOURCES_START_TAG, SOURCES_END_TAG, "\n"); + if (retval == NULL) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("retval")); + goto cleanup; + } + + cleanup: + xmlFreeDoc(doc); + xmlXPathFreeContext(xpath_ctxt); + VIR_FREE(state.host); + virStringListFree(state.list); + + return retval; +} + + /** * @conn connection to report errors against * @pool storage pool to check for status @@ -1114,6 +1242,7 @@ virStorageBackend virStorageBackendNetFileSystem = { .buildPool = virStorageBackendFileSystemBuild, .startPool = virStorageBackendFileSystemStart, + .findPoolSources = virStorageBackendFileSystemNetFindPoolSources, .refreshPool = virStorageBackendFileSystemRefresh, .stopPool = virStorageBackendFileSystemStop, .deletePool = virStorageBackendFileSystemDelete, diff --git a/src/storage_backend_logical.c b/src/storage_backend_logical.c index eb362c6..c30323a 100644 --- a/src/storage_backend_logical.c +++ b/src/storage_backend_logical.c @@ -259,6 +259,75 @@ virStorageBackendLogicalRefreshPoolFunc(virConnectPtr conn ATTRIBUTE_UNUSED, static int +virStorageBackendLogicalFindPoolSourcesFunc(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, + char **const groups, + void *data) +{ + virStringList **rest = data; + virStringList *newItem; + const char *name = groups[0]; + + /* Append new XML desc to list */ + + if (VIR_ALLOC(newItem) != 0) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("new xml desc")); + return -1; + } + + if (asprintf(&newItem->val, "<source><name>%s</name></source>", name) <= 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("asprintf failed")); + VIR_FREE(newItem); + return -1; + } + + newItem->len = strlen(newItem->val); + newItem->next = *rest; + *rest = newItem; + + return 0; +} + +static char * +virStorageBackendLogicalFindPoolSources(virConnectPtr conn, + const char *srcSpec ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + /* + * # sudo vgs --noheadings -o vg_name + * VolGroup00 + * VolGroup01 + */ + const char *regexes[] = { + "^\\s*(\\S+)\\s*$" + }; + int vars[] = { + 1 + }; + virStringList *descs = NULL; + const char *prog[] = { VGS, "--noheadings", "-o", "vg_name", NULL }; + int exitstatus; + char *retval = NULL; + + if (virStorageBackendRunProgRegex(conn, NULL, prog, 1, regexes, vars, + virStorageBackendLogicalFindPoolSourcesFunc, + &descs, &exitstatus) < 0) + return NULL; + + retval = virStringListJoin(descs, SOURCES_START_TAG, SOURCES_END_TAG, "\n"); + if (retval == NULL) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("retval")); + goto cleanup; + } + + cleanup: + virStringListFree(descs); + + return retval; +} + + +static int virStorageBackendLogicalStartPool(virConnectPtr conn, virStoragePoolObjPtr pool) { @@ -537,6 +606,7 @@ virStorageBackendLogicalDeleteVol(virConnectPtr conn, virStorageBackend virStorageBackendLogical = { .type = VIR_STORAGE_POOL_LOGICAL, + .findPoolSources = virStorageBackendLogicalFindPoolSources, .startPool = virStorageBackendLogicalStartPool, .buildPool = virStorageBackendLogicalBuildPool, .refreshPool = virStorageBackendLogicalRefreshPool, diff --git a/src/storage_driver.c b/src/storage_driver.c index 45f2635..ec0b37f 100644 --- a/src/storage_driver.c +++ b/src/storage_driver.c @@ -386,6 +386,30 @@ storageListDefinedPools(virConnectPtr conn, return -1; } +static char * +storageFindPoolSources(virConnectPtr conn, + const char *type, + const char *srcSpec, + unsigned int flags) +{ + int backend_type; + virStorageBackendPtr backend; + + backend_type = virStorageBackendFromString(type); + if (backend_type < 0) + return NULL; + + backend = virStorageBackendForType(backend_type); + if (backend == NULL) + return NULL; + + if (backend->findPoolSources) + return backend->findPoolSources(conn, srcSpec, flags); + + return NULL; +} + + static virStoragePoolPtr storagePoolCreate(virConnectPtr conn, const char *xml, @@ -1212,6 +1236,7 @@ static virStorageDriver storageDriver = { storageListPools, storageNumDefinedPools, storageListDefinedPools, + storageFindPoolSources, storagePoolLookupByName, storagePoolLookupByUUID, storagePoolLookupByVolume, diff --git a/src/virsh.c b/src/virsh.c index 67d9658..eb5c659 100644 --- a/src/virsh.c +++ b/src/virsh.c @@ -3422,6 +3422,139 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) return TRUE; } +/* + * "find-storage-pool-sources-as" command + */ +static const vshCmdInfo info_find_storage_pool_sources_as[] = { + {"syntax", "find-storage-pool-sources-as <type> [options]"}, + {"help", gettext_noop("find potential storage pool sources")}, + {"desc", gettext_noop("Returns XML <sources> document.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_find_storage_pool_sources_as[] = { + {"type", VSH_OT_DATA, VSH_OFLAG_REQ, + gettext_noop("type of storage pool sources to find")}, + {"host", VSH_OT_DATA, VSH_OFLAG_NONE, gettext_noop("optional host to query")}, + {"port", VSH_OT_DATA, VSH_OFLAG_NONE, gettext_noop("optional port to query")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdPoolDiscoverSourcesAs(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED) +{ + char *type, *host; + char *srcSpec = NULL; + char *srcList; + int found; + + type = vshCommandOptString(cmd, "type", &found); + if (!found) + return FALSE; + host = vshCommandOptString(cmd, "host", &found); + if (!found) + host = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (host) { + size_t hostlen = strlen(host); + char *port = vshCommandOptString(cmd, "port", &found); + int ret; + if (!found) { + port = strrchr(host, ':'); + if (port) { + if (*(++port)) + hostlen = port - host - 1; + else + port = NULL; + } + } + ret = port ? + asprintf(&srcSpec, + "<source><host name='%.*s' port='%s'/></source>", + (int)hostlen, host, port) : + asprintf(&srcSpec, + "<source><host name='%.*s'/></source>", + (int)hostlen, host); + if (ret < 0) { + switch (errno) { + case ENOMEM: + vshError(ctl, FALSE, "%s", _("Out of memory")); + break; + default: + vshError(ctl, FALSE, _("asprintf failed (errno %d)"), errno); + } + return FALSE; + } + } + + srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0); + free(srcSpec); + if (srcList == NULL) { + vshError(ctl, FALSE, _("Failed to find any %s pool sources"), type); + return FALSE; + } + vshPrint(ctl, "%s", srcList); + free(srcList); + + return TRUE; +} + + +/* + * "find-storage-pool-sources" command + */ +static const vshCmdInfo info_find_storage_pool_sources[] = { + {"syntax", "find-storage-pool-sources <type> [srcSpec]"}, + {"help", gettext_noop("discover potential storage pool sources")}, + {"desc", gettext_noop("Returns XML <sources> document.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_find_storage_pool_sources[] = { + {"type", VSH_OT_DATA, VSH_OFLAG_REQ, + gettext_noop("type of storage pool sources to discover")}, + {"srcSpec", VSH_OT_DATA, VSH_OFLAG_NONE, + gettext_noop("optional file of source xml to query for pools")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdPoolDiscoverSources(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED) +{ + char *type, *srcSpec, *srcSpecFile, *srcList; + int found; + + type = vshCommandOptString(cmd, "type", &found); + if (!found) + return FALSE; + srcSpecFile = vshCommandOptString(cmd, "srcSpec", &found); + if (!found) { + srcSpecFile = NULL; + srcSpec = NULL; + } + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (srcSpecFile && virFileReadAll(srcSpecFile, VIRSH_MAX_XML_FILE, &srcSpec) < 0) + return FALSE; + + srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0); + free(srcSpec); + if (srcList == NULL) { + vshError(ctl, FALSE, _("Failed to find any %s pool sources"), type); + return FALSE; + } + vshPrint(ctl, "%s", srcList); + free(srcList); + + return TRUE; +} + + static double prettyCapacity(unsigned long long val, const char **unit) { @@ -5362,6 +5495,10 @@ static const vshCmdDef commands[] = { {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat}, {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml}, {"edit", cmdEdit, opts_edit, info_edit}, + {"find-storage-pool-sources", cmdPoolDiscoverSources, + opts_find_storage_pool_sources, info_find_storage_pool_sources}, + {"find-storage-pool-sources-as", cmdPoolDiscoverSourcesAs, + opts_find_storage_pool_sources_as, info_find_storage_pool_sources_as}, {"freecell", cmdFreecell, opts_freecell, info_freecell}, {"hostname", cmdHostname, NULL, info_hostname}, {"list", cmdList, opts_list, info_list},
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list