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). Dave
diff --git a/configure.in b/configure.in index 0513a72..f29a0fa 100644 --- a/configure.in +++ b/configure.in @@ -660,6 +660,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 1a8e68d..cce359f 100644 --- a/qemud/remote_protocol.c +++ b/qemud/remote_protocol.c @@ -1501,6 +1501,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 1ad0c54..b632761 100644 --- a/qemud/remote_protocol.h +++ b/qemud/remote_protocol.h @@ -836,6 +836,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; }; @@ -1336,6 +1348,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*); @@ -1515,6 +1529,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 340203c..f8fffcc 100644 --- a/qemud/remote_protocol.x +++ b/qemud/remote_protocol.x @@ -762,6 +762,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 e060a38..04792a4 100644 --- a/src/driver.h +++ b/src/driver.h @@ -448,6 +448,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); @@ -552,6 +557,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 5120ed4..c2deea6 100644 --- a/src/internal.h +++ b/src/internal.h @@ -365,6 +365,14 @@ 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; +}; + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/libvirt.c b/src/libvirt.c index 9cdec88..41500f4 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -3986,7 +3986,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); @@ -4015,7 +4015,7 @@ virConnectNumOfStoragePools (virConnectPtr conn) * Returns 0 on success, -1 on error */ int -virConnectListStoragePools (virConnectPtr conn, +virConnectListStoragePools (virConnectPtr conn, char **const names, int maxnames) { @@ -4104,6 +4104,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 e88c404..c678eeb 100644 --- a/src/remote_internal.c +++ b/src/remote_internal.c @@ -3044,6 +3044,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) @@ -4904,6 +4945,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..c97ed48 100644 --- a/src/storage_backend.h +++ b/src/storage_backend.h @@ -63,6 +63,7 @@ struct _virStorageBackendPoolOptions { virStoragePoolFormatFromString formatFromString; }; +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 +81,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..22acdbe 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,141 @@ 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 }; + const char *start_tag = "<SourceList>\n"; + const char *end_tag = "</SourceList>\n"; + 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(start_tag) + strlen(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, start_tag); + len = strlen(start_tag); + for (p = state.list; p; p = p->next) { + strcpy(retval + len, p->val); + len += p->len; + } + strcpy(retval + len, 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 +1254,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 0c4f6a5..890dcd2 100644 --- a/src/storage_backend_logical.c +++ b/src/storage_backend_logical.c @@ -259,6 +259,92 @@ 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 }; + const char *start_tag = "<SourceList>\n"; + const char *end_tag = "</SourceList>\n"; + 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(start_tag) + strlen(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, start_tag); + len = strlen(start_tag); + for (p = descs; p; p = p->next) { + strcpy(retval + len, p->val); + len += p->len; + } + strcpy(retval + len, end_tag); + + cleanup: + while (descs) { + p = descs->next; + VIR_FREE(descs); + descs = p; + } + + return retval; +} + + +static int virStorageBackendLogicalStartPool(virConnectPtr conn, virStoragePoolObjPtr pool) { @@ -524,6 +610,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