mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-14 12:58:33 +03:00
storage: Allow multiple hosts for a storage pool
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>
This commit is contained in:
parent
9d2ac5453e
commit
122fa379de
1
AUTHORS
1
AUTHORS
@ -233,6 +233,7 @@ Patches have also been contributed by:
|
|||||||
MATSUDA Daiki <matsudadik@intellilink.co.jp>
|
MATSUDA Daiki <matsudadik@intellilink.co.jp>
|
||||||
Jan Kiszka <jan.kiszka@siemens.com>
|
Jan Kiszka <jan.kiszka@siemens.com>
|
||||||
Ryan Woodsmall <rwoodsmall@gmail.com>
|
Ryan Woodsmall <rwoodsmall@gmail.com>
|
||||||
|
Wido den Hollander <wido@widodh.nl>
|
||||||
|
|
||||||
[....send patches to get your name here....]
|
[....send patches to get your name here....]
|
||||||
|
|
||||||
|
@ -276,7 +276,11 @@ virStoragePoolSourceClear(virStoragePoolSourcePtr source)
|
|||||||
if (!source)
|
if (!source)
|
||||||
return;
|
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++) {
|
for (i = 0 ; i < source->ndevice ; i++) {
|
||||||
VIR_FREE(source->devices[i].freeExtents);
|
VIR_FREE(source->devices[i].freeExtents);
|
||||||
VIR_FREE(source->devices[i].path);
|
VIR_FREE(source->devices[i].path);
|
||||||
@ -404,6 +408,7 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
|
|||||||
char *authType = NULL;
|
char *authType = NULL;
|
||||||
int nsource, i;
|
int nsource, i;
|
||||||
virStoragePoolOptionsPtr options;
|
virStoragePoolOptionsPtr options;
|
||||||
|
char *name = NULL;
|
||||||
char *port = NULL;
|
char *port = NULL;
|
||||||
|
|
||||||
relnode = ctxt->node;
|
relnode = ctxt->node;
|
||||||
@ -431,17 +436,34 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
|
|||||||
VIR_FREE(format);
|
VIR_FREE(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
source->host.name = virXPathString("string(./host/@name)", ctxt);
|
source->nhost = virXPathNodeSet("./host", ctxt, &nodeset);
|
||||||
port = virXPathString("string(./host/@port)", ctxt);
|
|
||||||
if (port) {
|
if (source->nhost) {
|
||||||
if (virStrToLong_i(port, NULL, 10, &source->host.port) < 0) {
|
if (VIR_ALLOC_N(source->hosts, source->nhost) < 0) {
|
||||||
virStorageReportError(VIR_ERR_XML_ERROR,
|
virReportOOMError();
|
||||||
_("Invalid port number: %s"),
|
|
||||||
port);
|
|
||||||
goto cleanup;
|
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);
|
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 (options->flags & VIR_STORAGE_POOL_SOURCE_HOST) {
|
||||||
if (!ret->source.host.name) {
|
if (!ret->source.nhost) {
|
||||||
virStorageReportError(VIR_ERR_XML_ERROR,
|
virStorageReportError(VIR_ERR_XML_ERROR,
|
||||||
"%s",
|
"%s",
|
||||||
_("missing storage pool source host name"));
|
_("missing storage pool source host name"));
|
||||||
@ -801,12 +823,13 @@ virStoragePoolSourceFormat(virBufferPtr buf,
|
|||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
virBufferAddLit(buf," <source>\n");
|
virBufferAddLit(buf," <source>\n");
|
||||||
if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) &&
|
if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) && src->nhost) {
|
||||||
src->host.name) {
|
for (i = 0; i < src->nhost; i++) {
|
||||||
virBufferAsprintf(buf, " <host name='%s'", src->host.name);
|
virBufferAsprintf(buf, " <host name='%s'", src->hosts[i].name);
|
||||||
if (src->host.port)
|
if (src->hosts[i].port)
|
||||||
virBufferAsprintf(buf, " port='%d'", src->host.port);
|
virBufferAsprintf(buf, " port='%d'", src->hosts[i].port);
|
||||||
virBufferAddLit(buf, "/>\n");
|
virBufferAddLit(buf, "/>\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) &&
|
if ((options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) &&
|
||||||
@ -1678,7 +1701,8 @@ int virStoragePoolSourceFindDuplicate(virStoragePoolObjListPtr pools,
|
|||||||
break;
|
break;
|
||||||
case VIR_STORAGE_POOL_NETFS:
|
case VIR_STORAGE_POOL_NETFS:
|
||||||
if ((STREQ(pool->def->source.dir, def->source.dir)) \
|
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;
|
matchpool = pool;
|
||||||
break;
|
break;
|
||||||
case VIR_STORAGE_POOL_SCSI:
|
case VIR_STORAGE_POOL_SCSI:
|
||||||
@ -1689,13 +1713,15 @@ int virStoragePoolSourceFindDuplicate(virStoragePoolObjListPtr pools,
|
|||||||
{
|
{
|
||||||
matchpool = virStoragePoolSourceFindDuplicateDevices(pool, def);
|
matchpool = virStoragePoolSourceFindDuplicateDevices(pool, def);
|
||||||
if (matchpool) {
|
if (matchpool) {
|
||||||
if (STREQ(matchpool->def->source.host.name, def->source.host.name)) {
|
if (matchpool->def->source.nhost == 1 && def->source.nhost == 1) {
|
||||||
if ((matchpool->def->source.initiator.iqn) && (def->source.initiator.iqn)) {
|
if (STREQ(matchpool->def->source.hosts[0].name, def->source.hosts[0].name)) {
|
||||||
if (STREQ(matchpool->def->source.initiator.iqn, def->source.initiator.iqn))
|
if ((matchpool->def->source.initiator.iqn) && (def->source.initiator.iqn)) {
|
||||||
break;
|
if (STREQ(matchpool->def->source.initiator.iqn, def->source.initiator.iqn))
|
||||||
matchpool = NULL;
|
break;
|
||||||
|
matchpool = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
matchpool = NULL;
|
matchpool = NULL;
|
||||||
}
|
}
|
||||||
|
@ -212,8 +212,9 @@ struct _virStoragePoolSourceDevice {
|
|||||||
typedef struct _virStoragePoolSource virStoragePoolSource;
|
typedef struct _virStoragePoolSource virStoragePoolSource;
|
||||||
typedef virStoragePoolSource *virStoragePoolSourcePtr;
|
typedef virStoragePoolSource *virStoragePoolSourcePtr;
|
||||||
struct _virStoragePoolSource {
|
struct _virStoragePoolSource {
|
||||||
/* An optional host */
|
/* An optional (maybe multiple) host(s) */
|
||||||
virStoragePoolSourceHost host;
|
size_t nhost;
|
||||||
|
virStoragePoolSourceHostPtr hosts;
|
||||||
|
|
||||||
/* And either one or more devices ... */
|
/* And either one or more devices ... */
|
||||||
int ndevice;
|
int ndevice;
|
||||||
|
@ -544,8 +544,12 @@ esxStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
|
|||||||
if (esxVI_LocalDatastoreInfo_DynamicCast(info) != NULL) {
|
if (esxVI_LocalDatastoreInfo_DynamicCast(info) != NULL) {
|
||||||
def.type = VIR_STORAGE_POOL_DIR;
|
def.type = VIR_STORAGE_POOL_DIR;
|
||||||
} else if ((nasInfo = esxVI_NasDatastoreInfo_DynamicCast(info)) != NULL) {
|
} 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.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;
|
def.source.dir = nasInfo->nas->remotePath;
|
||||||
|
|
||||||
if (STRCASEEQ(nasInfo->nas->type, "NFS")) {
|
if (STRCASEEQ(nasInfo->nas->type, "NFS")) {
|
||||||
|
@ -206,7 +206,13 @@ virStorageBackendFileSystemNetFindPoolSourcesFunc(virStoragePoolObjPtr pool ATTR
|
|||||||
if (!(src = virStoragePoolSourceListNewSource(&state->list)))
|
if (!(src = virStoragePoolSourceListNewSource(&state->list)))
|
||||||
goto cleanup;
|
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))) {
|
!(src->dir = strdup(path))) {
|
||||||
virReportOOMError();
|
virReportOOMError();
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -260,8 +266,14 @@ virStorageBackendFileSystemNetFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSE
|
|||||||
if (!source)
|
if (!source)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
state.host = source->host.name;
|
if (source->nhost != 1) {
|
||||||
prog[3] = source->host.name;
|
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,
|
if (virStorageBackendRunProgRegex(NULL, prog, 1, regexes, vars,
|
||||||
virStorageBackendFileSystemNetFindPoolSourcesFunc,
|
virStorageBackendFileSystemNetFindPoolSourcesFunc,
|
||||||
@ -387,7 +399,12 @@ virStorageBackendFileSystemMount(virStoragePoolObjPtr pool) {
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
|
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,
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
"%s", _("missing source host"));
|
"%s", _("missing source host"));
|
||||||
return -1;
|
return -1;
|
||||||
@ -415,7 +432,7 @@ virStorageBackendFileSystemMount(virStoragePoolObjPtr pool) {
|
|||||||
|
|
||||||
if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
|
if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
|
||||||
if (virAsprintf(&src, "%s:%s",
|
if (virAsprintf(&src, "%s:%s",
|
||||||
pool->def->source.host.name,
|
pool->def->source.hosts[0].name,
|
||||||
pool->def->source.dir) == -1) {
|
pool->def->source.dir) == -1) {
|
||||||
virReportOOMError();
|
virReportOOMError();
|
||||||
return -1;
|
return -1;
|
||||||
@ -452,7 +469,12 @@ virStorageBackendFileSystemUnmount(virStoragePoolObjPtr pool) {
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
|
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,
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
"%s", _("missing source host"));
|
"%s", _("missing source host"));
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -96,13 +96,19 @@ virStorageBackendISCSIPortal(virStoragePoolSourcePtr source)
|
|||||||
char ipaddr[NI_MAXHOST];
|
char ipaddr[NI_MAXHOST];
|
||||||
char *portal;
|
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)
|
ipaddr, sizeof(ipaddr)) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (virAsprintf(&portal, "%s:%d,1", ipaddr,
|
if (virAsprintf(&portal, "%s:%d,1", ipaddr,
|
||||||
source->host.port ?
|
source->hosts[0].port ?
|
||||||
source->host.port : 3260) < 0) {
|
source->hosts[0].port : 3260) < 0) {
|
||||||
virReportOOMError();
|
virReportOOMError();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -563,6 +569,12 @@ virStorageBackendISCSIFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
list.type)))
|
list.type)))
|
||||||
return NULL;
|
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)))
|
if (!(portal = virStorageBackendISCSIPortal(source)))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@ -581,7 +593,7 @@ virStorageBackendISCSIFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
virReportOOMError();
|
virReportOOMError();
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
list.sources[i].host = source->host;
|
list.sources[i].host = source->hosts[0];
|
||||||
list.sources[i].initiator = source->initiator;
|
list.sources[i].initiator = source->initiator;
|
||||||
list.sources[i].ndevice = 1;
|
list.sources[i].ndevice = 1;
|
||||||
list.sources[i].devices[0].path = targets[i];
|
list.sources[i].devices[0].path = targets[i];
|
||||||
@ -617,7 +629,13 @@ virStorageBackendISCSICheckPool(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
|
|
||||||
*isActive = false;
|
*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,
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
"%s", _("missing source host"));
|
"%s", _("missing source host"));
|
||||||
return -1;
|
return -1;
|
||||||
@ -649,7 +667,13 @@ virStorageBackendISCSIStartPool(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
int ret = -1;
|
int ret = -1;
|
||||||
const char *loginargv[] = { "--login", NULL };
|
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,
|
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
"%s", _("missing source host"));
|
"%s", _("missing source host"));
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -4053,14 +4053,14 @@ testStorageFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case VIR_STORAGE_POOL_NETFS:
|
case VIR_STORAGE_POOL_NETFS:
|
||||||
if (!source || !source->host.name) {
|
if (!source || !source->hosts[0].name) {
|
||||||
testError(VIR_ERR_INVALID_ARG,
|
testError(VIR_ERR_INVALID_ARG,
|
||||||
"%s", "hostname must be specified for netfs sources");
|
"%s", "hostname must be specified for netfs sources");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virAsprintf(&ret, defaultPoolSourcesNetFSXML,
|
if (virAsprintf(&ret, defaultPoolSourcesNetFSXML,
|
||||||
source->host.name) < 0)
|
source->hosts[0].name) < 0)
|
||||||
virReportOOMError();
|
virReportOOMError();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user