]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
storage: Allow multiple hosts for a storage pool
authorWido den Hollander <wido@widodh.nl>
Wed, 25 Apr 2012 10:43:09 +0000 (12:43 +0200)
committerDaniel Veillard <veillard@redhat.com>
Mon, 30 Apr 2012 10:44:44 +0000 (18:44 +0800)
The current storage pools for NFS and iSCSI only require one host to
connect to. Future storage pools like RBD and Sheepdog will require
multiple hosts.

This patch allows multiple source hosts and rewrites the current
storage drivers.

Signed-off-by: Wido den Hollander <wido@widodh.nl>
AUTHORS
src/conf/storage_conf.c
src/conf/storage_conf.h
src/esx/esx_storage_driver.c
src/storage/storage_backend_fs.c
src/storage/storage_backend_iscsi.c
src/test/test_driver.c

diff --git a/AUTHORS b/AUTHORS
index 20e1b4bd305448da939e07525aa7a328660e2d6a..06b830a1c8f7a76419258b8d98ae3740e468c38d 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -233,6 +233,7 @@ Patches have also been contributed by:
   MATSUDA Daiki        <matsudadik@intellilink.co.jp>
   Jan Kiszka           <jan.kiszka@siemens.com>
   Ryan Woodsmall       <rwoodsmall@gmail.com>
+  Wido den Hollander   <wido@widodh.nl>
 
   [....send patches to get your name here....]
 
index 75793277da9c9e0f346d45d818f9512f483b1460..6475181c5587d21f6da44eb4f14af6ddcdb4c9bd 100644 (file)
@@ -276,7 +276,11 @@ virStoragePoolSourceClear(virStoragePoolSourcePtr source)
     if (!source)
         return;
 
-    VIR_FREE(source->host.name);
+    for (i = 0 ; i < source->nhost ; i++) {
+        VIR_FREE(source->hosts[i].name);
+    }
+    VIR_FREE(source->hosts);
+
     for (i = 0 ; i < source->ndevice ; i++) {
         VIR_FREE(source->devices[i].freeExtents);
         VIR_FREE(source->devices[i].path);
@@ -404,6 +408,7 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
     char *authType = NULL;
     int nsource, i;
     virStoragePoolOptionsPtr options;
+    char *name = NULL;
     char *port = NULL;
 
     relnode = ctxt->node;
@@ -431,17 +436,34 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
         VIR_FREE(format);
     }
 
-    source->host.name = virXPathString("string(./host/@name)", ctxt);
-    port = virXPathString("string(./host/@port)", ctxt);
-    if (port) {
-        if (virStrToLong_i(port, NULL, 10, &source->host.port) < 0) {
-            virStorageReportError(VIR_ERR_XML_ERROR,
-                                  _("Invalid port number: %s"),
-                                  port);
+    source->nhost = virXPathNodeSet("./host", ctxt, &nodeset);
+
+    if (source->nhost) {
+        if (VIR_ALLOC_N(source->hosts, source->nhost) < 0) {
+            virReportOOMError();
             goto cleanup;
         }
-    }
 
+        for (i = 0 ; i < source->nhost ; i++) {
+            name = virXMLPropString(nodeset[i], "name");
+            if (name == NULL) {
+                virStorageReportError(VIR_ERR_XML_ERROR,
+                        "%s", _("missing storage pool host name"));
+                goto cleanup;
+            }
+            source->hosts[i].name = name;
+
+            port = virXMLPropString(nodeset[i], "port");
+            if (port) {
+                if (virStrToLong_i(port, NULL, 10, &source->hosts[i].port) < 0) {
+                    virStorageReportError(VIR_ERR_XML_ERROR,
+                                          _("Invalid port number: %s"),
+                                          port);
+                    goto cleanup;
+                }
+            }
+        }
+    }
 
     source->initiator.iqn = virXPathString("string(./initiator/iqn/@name)", ctxt);
 
@@ -675,7 +697,7 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) {
     }
 
     if (options->flags & VIR_STORAGE_POOL_SOURCE_HOST) {
-        if (!ret->source.host.name) {
+        if (!ret->source.nhost) {
             virStorageReportError(VIR_ERR_XML_ERROR,
                                   "%s",
                                   _("missing storage pool source host name"));
@@ -801,12 +823,13 @@ virStoragePoolSourceFormat(virBufferPtr buf,
     int i, j;
 
     virBufferAddLit(buf,"  <source>\n");
-    if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) &&
-        src->host.name) {
-        virBufferAsprintf(buf, "    <host name='%s'", src->host.name);
-        if (src->host.port)
-            virBufferAsprintf(buf, " port='%d'", src->host.port);
-        virBufferAddLit(buf, "/>\n");
+    if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) && src->nhost) {
+        for (i = 0; i < src->nhost; i++) {
+            virBufferAsprintf(buf, " <host name='%s'", src->hosts[i].name);
+            if (src->hosts[i].port)
+                virBufferAsprintf(buf, " port='%d'", src->hosts[i].port);
+            virBufferAddLit(buf, "/>\n");
+        }
     }
 
     if ((options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) &&
@@ -1678,7 +1701,8 @@ int virStoragePoolSourceFindDuplicate(virStoragePoolObjListPtr pools,
             break;
         case VIR_STORAGE_POOL_NETFS:
             if ((STREQ(pool->def->source.dir, def->source.dir)) \
-                && (STREQ(pool->def->source.host.name, def->source.host.name)))
+                && (pool->def->source.nhost == 1 && def->source.nhost == 1) \
+                && (STREQ(pool->def->source.hosts[0].name, def->source.hosts[0].name)))
                 matchpool = pool;
             break;
         case VIR_STORAGE_POOL_SCSI:
@@ -1689,13 +1713,15 @@ int virStoragePoolSourceFindDuplicate(virStoragePoolObjListPtr pools,
         {
             matchpool = virStoragePoolSourceFindDuplicateDevices(pool, def);
             if (matchpool) {
-                if (STREQ(matchpool->def->source.host.name, def->source.host.name)) {
-                    if ((matchpool->def->source.initiator.iqn) && (def->source.initiator.iqn)) {
-                        if (STREQ(matchpool->def->source.initiator.iqn, def->source.initiator.iqn))
-                            break;
-                        matchpool = NULL;
+                if (matchpool->def->source.nhost == 1 && def->source.nhost == 1) {
+                    if (STREQ(matchpool->def->source.hosts[0].name, def->source.hosts[0].name)) {
+                        if ((matchpool->def->source.initiator.iqn) && (def->source.initiator.iqn)) {
+                            if (STREQ(matchpool->def->source.initiator.iqn, def->source.initiator.iqn))
+                                break;
+                            matchpool = NULL;
+                        }
+                        break;
                     }
-                    break;
                 }
                 matchpool = NULL;
             }
index 1ef929510e15afb167bbe4d1721466ddb94f256f..9222c4af36f28116daa0b3edfa260b41d862b6b0 100644 (file)
@@ -212,8 +212,9 @@ struct _virStoragePoolSourceDevice {
 typedef struct _virStoragePoolSource virStoragePoolSource;
 typedef virStoragePoolSource *virStoragePoolSourcePtr;
 struct _virStoragePoolSource {
-    /* An optional host */
-    virStoragePoolSourceHost host;
+    /* An optional (maybe multiple) host(s) */
+    size_t nhost;
+    virStoragePoolSourceHostPtr hosts;
 
     /* And either one or more devices ... */
     int ndevice;
index adf1edbfaaa953db35c929a924a61bf7a332864a..9b64891e0e10590adf032492a1ab1e3c4cfbcbb8 100644 (file)
@@ -544,8 +544,12 @@ esxStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
     if (esxVI_LocalDatastoreInfo_DynamicCast(info) != NULL) {
         def.type = VIR_STORAGE_POOL_DIR;
     } else if ((nasInfo = esxVI_NasDatastoreInfo_DynamicCast(info)) != NULL) {
+        if (VIR_ALLOC_N(def.source.hosts, 1) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
         def.type = VIR_STORAGE_POOL_NETFS;
-        def.source.host.name = nasInfo->nas->remoteHost;
+        def.source.hosts[0].name = nasInfo->nas->remoteHost;
         def.source.dir = nasInfo->nas->remotePath;
 
         if (STRCASEEQ(nasInfo->nas->type, "NFS")) {
index 1af12e67469bb4911067ed541a04bcf2d43251e3..169037b4b949636dfbec4c7930eedfefeab4ebb8 100644 (file)
@@ -206,7 +206,13 @@ virStorageBackendFileSystemNetFindPoolSourcesFunc(virStoragePoolObjPtr pool ATTR
     if (!(src = virStoragePoolSourceListNewSource(&state->list)))
         goto cleanup;
 
-    if (!(src->host.name = strdup(state->host)) ||
+    if (src->nhost != 1) {
+        virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                              _("Expected exactly 1 host for the storage pool"));
+        goto cleanup;
+    }
+
+    if (!(src->hosts[0].name = strdup(state->host)) ||
         !(src->dir = strdup(path))) {
         virReportOOMError();
         goto cleanup;
@@ -260,8 +266,14 @@ virStorageBackendFileSystemNetFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSE
     if (!source)
         goto cleanup;
 
-    state.host = source->host.name;
-    prog[3] = source->host.name;
+    if (source->nhost != 1) {
+        virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                              _("Expected exactly 1 host for the storage pool"));
+        goto cleanup;
+    }
+
+    state.host = source->hosts[0].name;
+    prog[3] = source->hosts[0].name;
 
     if (virStorageBackendRunProgRegex(NULL, prog, 1, regexes, vars,
                             virStorageBackendFileSystemNetFindPoolSourcesFunc,
@@ -387,7 +399,12 @@ virStorageBackendFileSystemMount(virStoragePoolObjPtr pool) {
     int ret;
 
     if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
-        if (pool->def->source.host.name == NULL) {
+        if (pool->def->source.nhost != 1) {
+            virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                                  _("Expected exactly 1 host for the storage pool"));
+            return -1;
+        }
+        if (pool->def->source.hosts[0].name == NULL) {
             virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("missing source host"));
             return -1;
@@ -415,7 +432,7 @@ virStorageBackendFileSystemMount(virStoragePoolObjPtr pool) {
 
     if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
         if (virAsprintf(&src, "%s:%s",
-                        pool->def->source.host.name,
+                        pool->def->source.hosts[0].name,
                         pool->def->source.dir) == -1) {
             virReportOOMError();
             return -1;
@@ -452,7 +469,12 @@ virStorageBackendFileSystemUnmount(virStoragePoolObjPtr pool) {
     int ret;
 
     if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
-        if (pool->def->source.host.name == NULL) {
+        if (pool->def->source.nhost != 1) {
+            virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                                  _("Expected exactly 1 host for the storage pool"));
+            return -1;
+        }
+        if (pool->def->source.hosts[0].name == NULL) {
             virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("missing source host"));
             return -1;
index f04473d3c489fcd2d6b05abbd703a7db916a13bf..22a34afab0a442cec8563643a82251ade05eb96e 100644 (file)
@@ -96,13 +96,19 @@ virStorageBackendISCSIPortal(virStoragePoolSourcePtr source)
     char ipaddr[NI_MAXHOST];
     char *portal;
 
-    if (virStorageBackendISCSITargetIP(source->host.name,
+    if (source->nhost != 1) {
+        virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                              _("Expected exactly 1 host for the storage pool"));
+        return NULL;
+    }
+
+    if (virStorageBackendISCSITargetIP(source->hosts[0].name,
                                        ipaddr, sizeof(ipaddr)) < 0)
         return NULL;
 
     if (virAsprintf(&portal, "%s:%d,1", ipaddr,
-                    source->host.port ?
-                    source->host.port : 3260) < 0) {
+                    source->hosts[0].port ?
+                    source->hosts[0].port : 3260) < 0) {
         virReportOOMError();
         return NULL;
     }
@@ -563,6 +569,12 @@ virStorageBackendISCSIFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
                                                       list.type)))
         return NULL;
 
+    if (source->nhost != 1) {
+        virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                              _("Expected exactly 1 host for the storage pool"));
+        goto cleanup;
+    }
+
     if (!(portal = virStorageBackendISCSIPortal(source)))
         goto cleanup;
 
@@ -581,7 +593,7 @@ virStorageBackendISCSIFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
             virReportOOMError();
             goto cleanup;
         }
-        list.sources[i].host = source->host;
+        list.sources[i].host = source->hosts[0];
         list.sources[i].initiator = source->initiator;
         list.sources[i].ndevice = 1;
         list.sources[i].devices[0].path = targets[i];
@@ -617,7 +629,13 @@ virStorageBackendISCSICheckPool(virConnectPtr conn ATTRIBUTE_UNUSED,
 
     *isActive = false;
 
-    if (pool->def->source.host.name == NULL) {
+    if (pool->def->source.nhost != 1) {
+         virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                               _("Expected exactly 1 host for the storage pool"));
+        return -1;
+    }
+
+    if (pool->def->source.hosts[0].name == NULL) {
         virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("missing source host"));
         return -1;
@@ -649,7 +667,13 @@ virStorageBackendISCSIStartPool(virConnectPtr conn ATTRIBUTE_UNUSED,
     int ret = -1;
     const char *loginargv[] = { "--login", NULL };
 
-    if (pool->def->source.host.name == NULL) {
+    if (pool->def->source.nhost != 1) {
+         virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                               _("Expected exactly 1 host for the storage pool"));
+        return -1;
+    }
+
+    if (pool->def->source.hosts[0].name == NULL) {
         virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("missing source host"));
         return -1;
index 39ac503d902b50f9866c88628bc676798f3d3ab7..73a7cb10af879daa43caa6fe88a56abac9e5559b 100644 (file)
@@ -4053,14 +4053,14 @@ testStorageFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
         break;
 
     case VIR_STORAGE_POOL_NETFS:
-        if (!source || !source->host.name) {
+        if (!source || !source->hosts[0].name) {
             testError(VIR_ERR_INVALID_ARG,
                       "%s", "hostname must be specified for netfs sources");
             goto cleanup;
         }
 
         if (virAsprintf(&ret, defaultPoolSourcesNetFSXML,
-                        source->host.name) < 0)
+                        source->hosts[0].name) < 0)
             virReportOOMError();
         break;