Here's the patch with those issues addressed (also merged with latest upstream - avoids internal.h merge conflict) ... Dave On Fri, 2008-08-22 at 09:50 +0100, Daniel P. Berrange wrote: > On Thu, Aug 21, 2008 at 10:29:43AM -0400, David Lively wrote: > > Hi Folks - > > Here's my second pass at storage pool discovery. I've taken Daniel's > > suggestion and made it return a single XML doc containing <source> > > elements rather than an array of <pool> docs (and also incorporated > > suggestions from Daniel V and Jim M). > > Note that the storage <source> <name> patch is closely related > > (without it, the <source> docs returned for logical pools aren't > > correct). > > Excellant, I think this patch looks more or less good to commit now. > > > +static char * > > +virStorageBackendFileSystemNetDiscoverPools(virConnectPtr conn, > > + const char *srcSpec, > > + unsigned int flags ATTRIBUTE_UNUSED) > > ... > > > + const char *prog[] = { SHOWMOUNT, "--no-headers", "--exports", NULL, NULL }; > > + const char *start_tag = "<SourceList>\n"; > > + const char *end_tag = "</SourceList>\n"; > > I'd prefer that to be <sources> - we avoid capitals in the > XML element names everywhere else, and in the few cases of > joining words use an underscore, but I think plural form is > OK for this. > > > +static char * > > +virStorageBackendLogicalDiscoverPools(virConnectPtr conn, > > + const char *srcSpec ATTRIBUTE_UNUSED, > > + unsigned int flags ATTRIBUTE_UNUSED) > > > > + const char *prog[] = { VGS, "--noheadings", "-o", "vg_name", NULL }; > > + const char *start_tag = "<SourceList>\n"; > > + const char *end_tag = "</SourceList>\n"; > > We should #define these two tags in storage_backend.h so each driver doesn't > need to dup them > > > Daniel
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..5308fa9 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 * virConnectDiscoverStoragePools(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..3d06d76 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 * virConnectDiscoverStoragePools(virConnectPtr conn, + const char *type, + const char *srcSpec, + unsigned int flags); + +/* * Lookup pool by name or uuid */ virStoragePoolPtr virStoragePoolLookupByName (virConnectPtr conn, diff --git a/qemud/remote.c b/qemud/remote.c index b5a6ec9..43b3a56 100644 --- a/qemud/remote.c +++ b/qemud/remote.c @@ -2958,6 +2958,27 @@ remoteDispatchListStoragePools (struct qemud_server *server ATTRIBUTE_UNUSED, } static int +remoteDispatchDiscoverStoragePools (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + remote_discover_storage_pools_args *args, + remote_discover_storage_pools_ret *ret) +{ + CHECK_CONN(client); + + ret->xml = + virConnectDiscoverStoragePools (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..6915d5a 100644 --- a/qemud/remote_dispatch_localvars.h +++ b/qemud/remote_dispatch_localvars.h @@ -137,6 +137,8 @@ remote_domain_attach_device_args lv_remote_domain_attach_device_args; remote_num_of_networks_ret lv_remote_num_of_networks_ret; remote_storage_pool_get_info_args lv_remote_storage_pool_get_info_args; remote_storage_pool_get_info_ret lv_remote_storage_pool_get_info_ret; +remote_discover_storage_pools_args lv_remote_discover_storage_pools_args; +remote_discover_storage_pools_ret lv_remote_discover_storage_pools_ret; remote_list_storage_pools_args lv_remote_list_storage_pools_args; remote_list_storage_pools_ret lv_remote_list_storage_pools_ret; remote_domain_restore_args lv_remote_domain_restore_args; diff --git a/qemud/remote_dispatch_proc_switch.h b/qemud/remote_dispatch_proc_switch.h index ebb2433..1850b92 100644 --- a/qemud/remote_dispatch_proc_switch.h +++ b/qemud/remote_dispatch_proc_switch.h @@ -41,6 +41,15 @@ case REMOTE_PROC_AUTH_SASL_STEP: case REMOTE_PROC_CLOSE: fn = (dispatch_fn) remoteDispatchClose; break; +case REMOTE_PROC_DISCOVER_STORAGE_POOLS: + fn = (dispatch_fn) remoteDispatchDiscoverStoragePools; + args_filter = (xdrproc_t) xdr_remote_discover_storage_pools_args; + args = (char *) &lv_remote_discover_storage_pools_args; + memset (&lv_remote_discover_storage_pools_args, 0, sizeof lv_remote_discover_storage_pools_args); + ret_filter = (xdrproc_t) xdr_remote_discover_storage_pools_ret; + ret = (char *) &lv_remote_discover_storage_pools_ret; + memset (&lv_remote_discover_storage_pools_ret, 0, sizeof lv_remote_discover_storage_pools_ret); + break; case REMOTE_PROC_DOMAIN_ATTACH_DEVICE: fn = (dispatch_fn) remoteDispatchDomainAttachDevice; args_filter = (xdrproc_t) xdr_remote_domain_attach_device_args; diff --git a/qemud/remote_dispatch_prototypes.h b/qemud/remote_dispatch_prototypes.h index 1d9d794..134ec43 100644 --- a/qemud/remote_dispatch_prototypes.h +++ b/qemud/remote_dispatch_prototypes.h @@ -8,6 +8,7 @@ static int remoteDispatchAuthSaslInit (struct qemud_server *server, struct qemud static int remoteDispatchAuthSaslStart (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_auth_sasl_start_args *args, remote_auth_sasl_start_ret *ret); static int remoteDispatchAuthSaslStep (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_auth_sasl_step_args *args, remote_auth_sasl_step_ret *ret); static int remoteDispatchClose (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, void *ret); +static int remoteDispatchDiscoverStoragePools (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_discover_storage_pools_args *args, remote_discover_storage_pools_ret *ret); static int remoteDispatchDomainAttachDevice (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_attach_device_args *args, void *ret); static int remoteDispatchDomainBlockPeek (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_block_peek_args *args, remote_domain_block_peek_ret *ret); static int remoteDispatchDomainBlockStats (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_block_stats_args *args, remote_domain_block_stats_ret *ret); diff --git a/qemud/remote_protocol.c b/qemud/remote_protocol.c index 39a20c2..63d903e 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_discover_storage_pools_args (XDR *xdrs, remote_discover_storage_pools_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_discover_storage_pools_ret (XDR *xdrs, remote_discover_storage_pools_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..02195ea 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_discover_storage_pools_args { + remote_nonnull_string type; + remote_string srcSpec; + u_int flags; +}; +typedef struct remote_discover_storage_pools_args remote_discover_storage_pools_args; + +struct remote_discover_storage_pools_ret { + remote_nonnull_string xml; +}; +typedef struct remote_discover_storage_pools_ret remote_discover_storage_pools_ret; + struct remote_storage_pool_lookup_by_uuid_args { remote_uuid uuid; }; @@ -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_discover_storage_pools_args (XDR *, remote_discover_storage_pools_args*); +extern bool_t xdr_remote_discover_storage_pools_ret (XDR *, remote_discover_storage_pools_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_discover_storage_pools_args (); +extern bool_t xdr_remote_discover_storage_pools_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..0c26821 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_discover_storage_pools_args { + remote_nonnull_string type; + remote_string srcSpec; + unsigned flags; +}; + +struct remote_discover_storage_pools_ret { + remote_nonnull_string xml; +}; + struct remote_storage_pool_lookup_by_uuid_args { remote_uuid uuid; }; diff --git a/src/driver.h b/src/driver.h index eb428a0..3576964 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 * + (*virDrvConnectDiscoverStoragePools) (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; + virDrvConnectDiscoverStoragePools discoverPools; virDrvStoragePoolLookupByName poolLookupByName; virDrvStoragePoolLookupByUUID poolLookupByUUID; virDrvStoragePoolLookupByVolume poolLookupByVolume; diff --git a/src/internal.h b/src/internal.h index 1ecec05..d8bafde 100644 --- a/src/internal.h +++ b/src/internal.h @@ -362,4 +362,12 @@ 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; +}; + #endif /* __VIR_INTERNAL_H__ */ diff --git a/src/libvirt.c b/src/libvirt.c index c31a619..6de2b2e 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -4007,7 +4007,7 @@ virStoragePoolGetConnect (virStoragePoolPtr pool) * Returns the number of pools found, or -1 on error */ int -virConnectNumOfStoragePools (virConnectPtr conn) +virConnectNumOfStoragePools (virConnectPtr conn) { DEBUG("conn=%p", conn); @@ -4036,7 +4036,7 @@ virConnectNumOfStoragePools (virConnectPtr conn) * Returns 0 on success, -1 on error */ int -virConnectListStoragePools (virConnectPtr conn, +virConnectListStoragePools (virConnectPtr conn, char **const names, int maxnames) { @@ -4125,6 +4125,50 @@ virConnectListDefinedStoragePools(virConnectPtr conn, /** + * virConnectDiscoverStoragePools: + * @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. eg 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 * +virConnectDiscoverStoragePools(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->discoverPools) + return conn->storageDriver->discoverPools (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 diff --git a/src/remote_internal.c b/src/remote_internal.c index 4d173e3..b207fdc 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 * +remoteDiscoverStoragePools (virConnectPtr conn, + const char *type, + const char *srcSpec, + unsigned int flags) +{ + remote_discover_storage_pools_args args; + remote_discover_storage_pools_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_DISCOVER_STORAGE_POOLS, + (xdrproc_t) xdr_remote_discover_storage_pools_args, (char *) &args, + (xdrproc_t) xdr_remote_discover_storage_pools_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_discover_storage_pools_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, + .discoverPools = remoteDiscoverStoragePools, .poolLookupByUUID = remoteStoragePoolLookupByUUID, .poolLookupByName = remoteStoragePoolLookupByName, .poolLookupByVolume = remoteStoragePoolLookupByVolume, diff --git a/src/storage_backend.h b/src/storage_backend.h index 797ca01..ac9989e 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 * (*virStorageBackendDiscoverPools)(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; + virStorageBackendDiscoverPools discoverPools; virStorageBackendStartPool startPool; virStorageBackendBuildPool buildPool; virStorageBackendRefreshPool refreshPool; diff --git a/src/storage_backend_fs.c b/src/storage_backend_fs.c index 36bfac4..a531d0f 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,139 @@ static int virStorageBackendProbeFile(virConnectPtr conn, } #if WITH_STORAGE_FS +struct _virNetfsDiscoverState { + const char *host; + virStringList *list; +}; + +typedef struct _virNetfsDiscoverState virNetfsDiscoverState; + +static int +virStorageBackendFileSystemNetDiscoverPoolsFunc(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 slash): %s"), path); + return -1; + } + name += 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>\n", + 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 * +virStorageBackendFileSystemNetDiscoverPools(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, len; + virStringList *p; + 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, + virStorageBackendFileSystemNetDiscoverPoolsFunc, + &state, &exitstatus) < 0) + goto cleanup; + + /* Turn list of strings into final document */ + len = strlen(SOURCES_START_TAG) + strlen(SOURCES_END_TAG); + for (p = state.list; p; p = p->next) + len += p->len; + if (VIR_ALLOC_N(retval, len+1) < 0) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("retval (%d bytes)"), len); + goto cleanup; + } + strcpy(retval, SOURCES_START_TAG); + len = strlen(SOURCES_START_TAG); + for (p = state.list; p; p = p->next) { + strcpy(retval + len, p->val); + len += p->len; + } + strcpy(retval + len, SOURCES_END_TAG); + + cleanup: + xmlFreeDoc(doc); + xmlXPathFreeContext(xpath_ctxt); + VIR_FREE(state.host); + while (state.list) { + p = state.list->next; + VIR_FREE(state.list); + state.list = p; + } + + return retval; +} + + /** * @conn connection to report errors against * @pool storage pool to check for status @@ -1114,6 +1252,7 @@ virStorageBackend virStorageBackendNetFileSystem = { .buildPool = virStorageBackendFileSystemBuild, .startPool = virStorageBackendFileSystemStart, + .discoverPools = virStorageBackendFileSystemNetDiscoverPools, .refreshPool = virStorageBackendFileSystemRefresh, .stopPool = virStorageBackendFileSystemStop, .deletePool = virStorageBackendFileSystemDelete, diff --git a/src/storage_backend_logical.c b/src/storage_backend_logical.c index eb362c6..3ffb1f9 100644 --- a/src/storage_backend_logical.c +++ b/src/storage_backend_logical.c @@ -259,6 +259,90 @@ virStorageBackendLogicalRefreshPoolFunc(virConnectPtr conn ATTRIBUTE_UNUSED, static int +virStorageBackendLogicalDiscoverPoolsFunc(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>\n", 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 * +virStorageBackendLogicalDiscoverPools(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, len; + virStringList *p; + char *retval = NULL; + + if (virStorageBackendRunProgRegex(conn, NULL, prog, 1, regexes, vars, + virStorageBackendLogicalDiscoverPoolsFunc, + &descs, &exitstatus) < 0) + return NULL; + + /* Turn list of strings into final document */ + len = strlen(SOURCES_START_TAG) + strlen(SOURCES_END_TAG); + for (p = descs; p; p = p->next) + len += p->len; + if (VIR_ALLOC_N(retval, len+1) < 0) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("retval (%d bytes)"), len); + goto cleanup; + } + strcpy(retval, SOURCES_START_TAG); + len = strlen(SOURCES_START_TAG); + for (p = descs; p; p = p->next) { + strcpy(retval + len, p->val); + len += p->len; + } + strcpy(retval + len, SOURCES_END_TAG); + + cleanup: + while (descs) { + p = descs->next; + VIR_FREE(descs); + descs = p; + } + + return retval; +} + + +static int virStorageBackendLogicalStartPool(virConnectPtr conn, virStoragePoolObjPtr pool) { @@ -537,6 +621,7 @@ virStorageBackendLogicalDeleteVol(virConnectPtr conn, virStorageBackend virStorageBackendLogical = { .type = VIR_STORAGE_POOL_LOGICAL, + .discoverPools = virStorageBackendLogicalDiscoverPools, .startPool = virStorageBackendLogicalStartPool, .buildPool = virStorageBackendLogicalBuildPool, .refreshPool = virStorageBackendLogicalRefreshPool, diff --git a/src/storage_driver.c b/src/storage_driver.c index 45f2635..642f9e1 100644 --- a/src/storage_driver.c +++ b/src/storage_driver.c @@ -386,6 +386,30 @@ storageListDefinedPools(virConnectPtr conn, return -1; } +static char * +storagePoolDiscover(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->discoverPools) + return backend->discoverPools(conn, srcSpec, flags); + + return NULL; +} + + static virStoragePoolPtr storagePoolCreate(virConnectPtr conn, const char *xml, @@ -1212,6 +1236,7 @@ static virStorageDriver storageDriver = { storageListPools, storageNumDefinedPools, storageListDefinedPools, + storagePoolDiscover, storagePoolLookupByName, storagePoolLookupByUUID, storagePoolLookupByVolume, diff --git a/src/virsh.c b/src/virsh.c index 67d9658..08fb425 100644 --- a/src/virsh.c +++ b/src/virsh.c @@ -3422,6 +3422,138 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) return TRUE; } +/* + * "pool-discover-as" command + */ +static vshCmdInfo info_pool_discover_as[] = { + {"syntax", "pool-discover-as <type> [options]"}, + {"help", gettext_noop("discover pools")}, + {"desc", gettext_noop("Returns discover of pools.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_pool_discover_as[] = { + {"type", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("type of storage pool to discover")}, + {"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 +cmdPoolDiscoverAs(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) { + int hostlen = strlen(host); + char *port = vshCommandOptString(cmd, "port", &found); + int ret; + if (!found) { + port = strrchr(host, ':'); + if (port) { + if (*(++port)) + hostlen = (int)(port - host - 1); + else + port = NULL; + } + } + ret = port ? + asprintf(&srcSpec, + "<source><host name='%.*s' port='%s'/></source>", + hostlen, host, port) : + asprintf(&srcSpec, + "<source><host name='%.*s'/></source>", + 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 = virConnectDiscoverStoragePools(ctl->conn, type, srcSpec, 0); + free(srcSpec); + if (srcList == NULL) { + vshError(ctl, FALSE, "%s", _("Failed to discover pools")); + return FALSE; + } + vshPrint(ctl, "%s", srcList); + free(srcList); + + return TRUE; +} + + +/* + * "pool-discover" command + */ +static vshCmdInfo info_pool_discover[] = { + {"syntax", "pool-discover <type> [srcSpec]"}, + {"help", gettext_noop("discover pools")}, + {"desc", gettext_noop("Returns discover of pools.")}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_pool_discover[] = { + {"type", VSH_OT_DATA, VSH_OFLAG_REQ, + gettext_noop("type of storage pool 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 +cmdPoolDiscover(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 = virConnectDiscoverStoragePools(ctl->conn, type, srcSpec, 0); + free(srcSpec); + if (srcList == NULL) { + vshError(ctl, FALSE, "%s", _("Failed to discover pools")); + return FALSE; + } + vshPrint(ctl, "%s", srcList); + free(srcList); + + return TRUE; +} + + static double prettyCapacity(unsigned long long val, const char **unit) { @@ -5388,6 +5520,8 @@ static const vshCmdDef commands[] = { {"pool-define-as", cmdPoolDefineAs, opts_pool_define_as, info_pool_define_as}, {"pool-destroy", cmdPoolDestroy, opts_pool_destroy, info_pool_destroy}, {"pool-delete", cmdPoolDelete, opts_pool_delete, info_pool_delete}, + {"pool-discover", cmdPoolDiscover, opts_pool_discover, info_pool_discover}, + {"pool-discover-as", cmdPoolDiscoverAs, opts_pool_discover_as, info_pool_discover_as}, {"pool-dumpxml", cmdPoolDumpXML, opts_pool_dumpxml, info_pool_dumpxml}, {"pool-edit", cmdPoolEdit, opts_pool_edit, info_pool_edit}, {"pool-info", cmdPoolInfo, opts_pool_info, info_pool_info},
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list