]> xenbits.xensource.com Git - libvirt.git/commitdiff
Add storage pool source discovery support (patch from David Lively)
authorDaniel P. Berrange <berrange@redhat.com>
Wed, 27 Aug 2008 20:05:58 +0000 (20:05 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Wed, 27 Aug 2008 20:05:58 +0000 (20:05 +0000)
22 files changed:
ChangeLog
configure.in
include/libvirt/libvirt.h
include/libvirt/libvirt.h.in
libvirt.spec.in
qemud/remote.c
qemud/remote_dispatch_localvars.h
qemud/remote_dispatch_proc_switch.h
qemud/remote_dispatch_prototypes.h
qemud/remote_protocol.c
qemud/remote_protocol.h
qemud/remote_protocol.x
src/driver.h
src/internal.h
src/libvirt.c
src/libvirt_sym.version
src/remote_internal.c
src/storage_backend.h
src/storage_backend_fs.c
src/storage_backend_logical.c
src/storage_driver.c
src/virsh.c

index 5944ce755f3be03d8dd92662cbbc21f7996b6d4a..ffe607a90ef000d53177d2a7e2aee5d7bb33521a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+Wed Aug 27 20:50:00 EST 2008 Daniel P. Berrange <berrange@redhat.com>
+
+       Storage pool source discovery from David Lively
+
+       * include/libvirt/libvirt.h, include/libvirt/libvirt.h.in,
+       src/libvirt_sym.version, src/libvirt.c, src/driver.h: Add
+       the virConnectFindStoragePoolSources() API
+       * src/remote_internal.c, qemu/remote.c, src/remote_protocol.{c,h,x}
+       Implement remote protocol support for virConnectFindStoragePoolSources
+       * src/remote_dispatch_*.h: Re-generate from remote_protocol.x
+       * libvirt.spec.in:Add dep on nfs-utils
+       * configure.in: Check for showmount binary
+       * src/storage_backend.h, src/storage_driver.c: Generic impl
+       of storage discovery
+       * src/storage_backend_fs.c, src/storage_backend_logical.c: Add
+       specific impl of storage discovery for NFS and LVM
+       * src/virsh.c: Add command to discover storage pools
+
 Wed Aug 27 12:40:00 EST 2008 Daniel P. Berrange <berrange@redhat.com>
 
        * src/util.h, src/util.c: Allow virExec to take set of FDs
index 9479f1c91268e61c9d77211bc5391803a597b615..430a0979ed613f3b1b97cd72841ba892c9a9f35c 100644 (file)
@@ -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
index 9c3e1c27b12b251959e900860e1f379ab4743ebc..05cb68b028c3053b263754416ebb0160f3755f0f 100644 (file)
@@ -889,6 +889,14 @@ int                     virConnectListDefinedStoragePools(virConnectPtr conn,
                                                           char **const names,
                                                           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
  */
index f077a2662836d401c6b4f74d8dc30eec1b924f72..b91d729ffb1330e9c9874dead0272dfa8c84a948 100644 (file)
@@ -889,6 +889,14 @@ int                     virConnectListDefinedStoragePools(virConnectPtr conn,
                                                           char **const names,
                                                           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
  */
index d37c0e00a5971a7f74054b7908be9a9651c08778..bac84a5b399b63cbdffa38eaab68104741c845c3 100644 (file)
@@ -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
index b5a6ec9e621bd3098a18bedf76e61df4e8805df5..3e43dcfd4945421ca3a9e3f9be5b892dff108b1f 100644 (file)
@@ -2957,6 +2957,27 @@ remoteDispatchListStoragePools (struct qemud_server *server ATTRIBUTE_UNUSED,
     return 0;
 }
 
+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,
index d889c8aba4f85eb0f507ecba9325353ee4d3f7cf..18d71e9a19ac1cbd0a3885618c72eb484c6d70a0 100644 (file)
@@ -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;
index ebb24334ca958b496a05b279529d7ec87b4fea24..767b142bdcc83ef55576b3862d2560bbfa97f62c 100644 (file)
@@ -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;
index 1d9d79494e82fe0c5a40bf11952ea919ab22d460..950ad056539c6712be6b1b3df06a0083685ef579 100644 (file)
@@ -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);
index 39a20c24cfbe3c55dec6de59b4720208b50ce4f9..ea9a160565f041efaef7395184857c348aa591da 100644 (file)
@@ -1501,6 +1501,28 @@ xdr_remote_list_defined_storage_pools_ret (XDR *xdrs, remote_list_defined_storag
         return TRUE;
 }
 
+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)
 {
index 6950f830d2106a1d00cc77ec52eca18f1ad80e4b..e4b1487cb91b79067bfd7ab23abfbcdca1587382 100644 (file)
@@ -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 ();
index 82bd18e7524cfcce2d33687b4366ce8e24a4f77e..148fbd58073614b8899f52cb84fe41ba984e21a4 100644 (file)
@@ -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,
index eb428a0a519020b89ee24dea1df5b0b7f8ba2271..655cd05d4cad323e67eaa47dabeb886224fe908c 100644 (file)
@@ -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;
index 1ecec058604f222259a9b489115d3ea143cad0c1..d96504d5b9b10baba2d32680262d15a6e5ed3f4a 100644 (file)
@@ -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__ */
index c31a6197aa8d2e8e781a6706ed26ed75387d8aec..9bf9373e48a45c72c9dd29907000c680d10c556a 100644 (file)
@@ -36,6 +36,7 @@
 
 #include "uuid.h"
 #include "util.h"
+#include "memory.h"
 
 #ifdef WITH_TEST
 #include "test.h"
@@ -4124,6 +4125,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
@@ -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;
+    }
+}
index 6561bc9671f8b6f74f17841afb4f6eba2f30f479..b8c470c703054b45d1a77cbbea50f229bc864139 100644 (file)
        virConnectNumOfDefinedStoragePools;
        virConnectListStoragePools;
        virConnectListDefinedStoragePools;
-       virConnectDiscoverStoragePools;
+       virConnectFindStoragePoolSources;
        virStoragePoolLookupByName;
        virStoragePoolLookupByUUID;
        virStoragePoolLookupByUUIDString;
index 4d173e3b1dbca5d8d26f91486ff177059619a8a2..586b34366e3ad5ebfdd3994aa380be3c3a3cbf1d 100644 (file)
@@ -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,
index 797ca0178f91e9a1177aa32ebc2dc0063b1c48ac..a06746b396afa6e3cba8e7794a6a48764917a6f0 100644 (file)
@@ -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;
index 36bfac49b5bb92c18b573250bbba601794d41f95..63124df80ad9635a6594417e354c4008ba297771 100644 (file)
 #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,
index eb362c6fbb170735c766c843ea9f6119e14d0ba1..c30323acbf916bb7f0bf4c69821a4e0bce6498d5 100644 (file)
@@ -258,6 +258,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,
index 45f2635fbf4eef1a548552cd800d262837ff7d11..ec0b37f69df4a80d9acc89b8154d83d9ad0004d0 100644 (file)
@@ -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,
index 67d9658564a7b52a9000f88fa1e840abe9331ecb..eb5c65932301c0cf1522103d003e03407a9f30b9 100644 (file)
@@ -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},