2017-03-13 11:46:18 +00:00
|
|
|
/*
|
|
|
|
* qemu_block.c: helper functions for QEMU block subsystem
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library. If not, see
|
|
|
|
* <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "qemu_block.h"
|
|
|
|
#include "qemu_domain.h"
|
2017-09-25 09:44:00 +00:00
|
|
|
#include "qemu_alias.h"
|
2017-03-13 11:46:18 +00:00
|
|
|
|
|
|
|
#include "viralloc.h"
|
|
|
|
#include "virstring.h"
|
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
|
|
|
|
|
|
|
|
2017-07-25 15:32:38 +00:00
|
|
|
static int
|
|
|
|
qemuBlockNamedNodesArrayToHash(size_t pos ATTRIBUTE_UNUSED,
|
|
|
|
virJSONValuePtr item,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
virHashTablePtr table = opaque;
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
if (!(name = virJSONValueObjectGetString(item, "node-name")))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (virHashAddEntry(table, name, item) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-13 11:46:18 +00:00
|
|
|
static void
|
|
|
|
qemuBlockNodeNameBackingChainDataFree(qemuBlockNodeNameBackingChainDataPtr data)
|
|
|
|
{
|
|
|
|
if (!data)
|
|
|
|
return;
|
|
|
|
|
|
|
|
VIR_FREE(data->nodeformat);
|
|
|
|
VIR_FREE(data->nodestorage);
|
|
|
|
|
|
|
|
VIR_FREE(data->qemufilename);
|
2017-07-26 07:36:21 +00:00
|
|
|
|
2017-07-25 17:10:27 +00:00
|
|
|
VIR_FREE(data->drvformat);
|
|
|
|
VIR_FREE(data->drvstorage);
|
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
qemuBlockNodeNameBackingChainDataFree(data->backing);
|
2017-03-13 11:46:18 +00:00
|
|
|
|
|
|
|
VIR_FREE(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
qemuBlockNodeNameBackingChainDataHashEntryFree(void *opaque,
|
|
|
|
const void *name ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
qemuBlockNodeNameBackingChainDataFree(opaque);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
/* list of driver names of layers that qemu automatically adds into the
|
|
|
|
* backing chain */
|
|
|
|
static const char *qemuBlockDriversBlockjob[] = {
|
|
|
|
"mirror_top", "commit_top", NULL };
|
2017-03-13 11:46:18 +00:00
|
|
|
|
|
|
|
static bool
|
|
|
|
qemuBlockDriverMatch(const char *drvname,
|
|
|
|
const char **drivers)
|
|
|
|
{
|
|
|
|
while (*drivers) {
|
|
|
|
if (STREQ(drvname, *drivers))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
drivers++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
struct qemuBlockNodeNameGetBackingChainData {
|
|
|
|
virHashTablePtr nodenamestable;
|
|
|
|
virHashTablePtr disks;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-03-13 11:46:18 +00:00
|
|
|
static int
|
2017-07-26 07:36:21 +00:00
|
|
|
qemuBlockNodeNameGetBackingChainBacking(virJSONValuePtr next,
|
|
|
|
virHashTablePtr nodenamestable,
|
|
|
|
qemuBlockNodeNameBackingChainDataPtr *nodenamedata)
|
2017-03-13 11:46:18 +00:00
|
|
|
{
|
2017-07-26 07:36:21 +00:00
|
|
|
qemuBlockNodeNameBackingChainDataPtr data = NULL;
|
|
|
|
qemuBlockNodeNameBackingChainDataPtr backingdata = NULL;
|
|
|
|
virJSONValuePtr backing = virJSONValueObjectGetObject(next, "backing");
|
|
|
|
virJSONValuePtr parent = virJSONValueObjectGetObject(next, "parent");
|
|
|
|
virJSONValuePtr parentnodedata;
|
|
|
|
virJSONValuePtr nodedata;
|
|
|
|
const char *nodename = virJSONValueObjectGetString(next, "node-name");
|
2017-07-25 17:10:27 +00:00
|
|
|
const char *drvname = NULL;
|
|
|
|
const char *drvparent = NULL;
|
2017-07-26 07:36:21 +00:00
|
|
|
const char *parentnodename = NULL;
|
|
|
|
const char *filename = NULL;
|
|
|
|
int ret = -1;
|
2017-03-13 11:46:18 +00:00
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
if (!nodename)
|
2017-03-13 11:46:18 +00:00
|
|
|
return 0;
|
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
if ((nodedata = virHashLookup(nodenamestable, nodename)) &&
|
|
|
|
(drvname = virJSONValueObjectGetString(nodedata, "drv"))) {
|
|
|
|
|
|
|
|
/* qemu 2.9 reports layers in the backing chain which don't correspond
|
|
|
|
* to files. skip them */
|
|
|
|
if (qemuBlockDriverMatch(drvname, qemuBlockDriversBlockjob)) {
|
|
|
|
if (backing) {
|
|
|
|
return qemuBlockNodeNameGetBackingChainBacking(backing,
|
|
|
|
nodenamestable,
|
|
|
|
nodenamedata);
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-03-13 11:46:18 +00:00
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
if (parent &&
|
|
|
|
(parentnodename = virJSONValueObjectGetString(parent, "node-name"))) {
|
2017-07-25 17:10:27 +00:00
|
|
|
if ((parentnodedata = virHashLookup(nodenamestable, parentnodename))) {
|
2017-07-26 07:36:21 +00:00
|
|
|
filename = virJSONValueObjectGetString(parentnodedata, "file");
|
2017-07-25 17:10:27 +00:00
|
|
|
drvparent = virJSONValueObjectGetString(parentnodedata, "drv");
|
|
|
|
}
|
2017-07-26 07:36:21 +00:00
|
|
|
}
|
2017-03-13 11:46:18 +00:00
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
if (VIR_ALLOC(data) < 0)
|
|
|
|
goto cleanup;
|
2017-03-13 11:46:18 +00:00
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
if (VIR_STRDUP(data->nodeformat, nodename) < 0 ||
|
|
|
|
VIR_STRDUP(data->nodestorage, parentnodename) < 0 ||
|
2017-07-25 17:10:27 +00:00
|
|
|
VIR_STRDUP(data->qemufilename, filename) < 0 ||
|
|
|
|
VIR_STRDUP(data->drvformat, drvname) < 0 ||
|
|
|
|
VIR_STRDUP(data->drvstorage, drvparent) < 0)
|
2017-07-26 07:36:21 +00:00
|
|
|
goto cleanup;
|
2017-03-13 11:46:18 +00:00
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
if (backing &&
|
|
|
|
qemuBlockNodeNameGetBackingChainBacking(backing, nodenamestable,
|
|
|
|
&backingdata) < 0)
|
|
|
|
goto cleanup;
|
2017-03-13 11:46:18 +00:00
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
VIR_STEAL_PTR(data->backing, backingdata);
|
|
|
|
VIR_STEAL_PTR(*nodenamedata, data);
|
2017-03-13 11:46:18 +00:00
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
qemuBlockNodeNameBackingChainDataFree(data);
|
|
|
|
return ret;
|
2017-03-13 11:46:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2017-07-26 07:36:21 +00:00
|
|
|
qemuBlockNodeNameGetBackingChainDisk(size_t pos ATTRIBUTE_UNUSED,
|
|
|
|
virJSONValuePtr item,
|
|
|
|
void *opaque)
|
2017-03-13 11:46:18 +00:00
|
|
|
{
|
2017-07-26 07:36:21 +00:00
|
|
|
struct qemuBlockNodeNameGetBackingChainData *data = opaque;
|
|
|
|
const char *device = virJSONValueObjectGetString(item, "device");
|
|
|
|
qemuBlockNodeNameBackingChainDataPtr devicedata = NULL;
|
|
|
|
int ret = -1;
|
2017-03-13 11:46:18 +00:00
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
if (qemuBlockNodeNameGetBackingChainBacking(item, data->nodenamestable,
|
|
|
|
&devicedata) < 0)
|
|
|
|
goto cleanup;
|
2017-03-13 11:46:18 +00:00
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
if (devicedata &&
|
|
|
|
virHashAddEntry(data->disks, device, devicedata) < 0)
|
|
|
|
goto cleanup;
|
2017-03-13 11:46:18 +00:00
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
devicedata = NULL;
|
|
|
|
ret = 1; /* we don't really want to steal @item */
|
2017-03-13 11:46:18 +00:00
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
cleanup:
|
|
|
|
qemuBlockNodeNameBackingChainDataFree(devicedata);
|
2017-03-13 11:46:18 +00:00
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
return ret;
|
2017-03-13 11:46:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* qemuBlockNodeNameGetBackingChain:
|
2017-07-26 07:36:21 +00:00
|
|
|
* @namednodes: JSON array of data returned from 'query-named-block-nodes'
|
|
|
|
* @blockstats: JSON array of data returned from 'query-blockstats'
|
2017-03-13 11:46:18 +00:00
|
|
|
*
|
|
|
|
* Tries to reconstruct the backing chain from @json to allow detection of
|
|
|
|
* node names that were auto-assigned by qemu. This is a best-effort operation
|
|
|
|
* and may not be successful. The returned hash table contains the entries as
|
|
|
|
* qemuBlockNodeNameBackingChainDataPtr accessible by the node name. The fields
|
|
|
|
* then can be used to recover the full backing chain.
|
|
|
|
*
|
|
|
|
* Returns a hash table on success and NULL on failure.
|
|
|
|
*/
|
|
|
|
virHashTablePtr
|
2017-07-26 07:36:21 +00:00
|
|
|
qemuBlockNodeNameGetBackingChain(virJSONValuePtr namednodes,
|
|
|
|
virJSONValuePtr blockstats)
|
2017-03-13 11:46:18 +00:00
|
|
|
{
|
|
|
|
struct qemuBlockNodeNameGetBackingChainData data;
|
2017-07-26 07:36:21 +00:00
|
|
|
virHashTablePtr namednodestable = NULL;
|
|
|
|
virHashTablePtr disks = NULL;
|
2017-03-13 11:46:18 +00:00
|
|
|
virHashTablePtr ret = NULL;
|
|
|
|
|
|
|
|
memset(&data, 0, sizeof(data));
|
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
if (!(namednodestable = virHashCreate(50, virJSONValueHashFree)))
|
2017-03-13 11:46:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
if (virJSONValueArrayForeachSteal(namednodes,
|
|
|
|
qemuBlockNamedNodesArrayToHash,
|
|
|
|
namednodestable) < 0)
|
2017-03-13 11:46:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
if (!(disks = virHashCreate(50, qemuBlockNodeNameBackingChainDataHashEntryFree)))
|
2017-03-13 11:46:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
data.nodenamestable = namednodestable;
|
|
|
|
data.disks = disks;
|
2017-03-13 11:46:18 +00:00
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
if (virJSONValueArrayForeachSteal(blockstats,
|
|
|
|
qemuBlockNodeNameGetBackingChainDisk,
|
|
|
|
&data) < 0)
|
|
|
|
goto cleanup;
|
2017-03-13 11:46:18 +00:00
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
VIR_STEAL_PTR(ret, disks);
|
2017-03-13 11:46:18 +00:00
|
|
|
|
|
|
|
cleanup:
|
2017-07-26 07:36:21 +00:00
|
|
|
virHashFree(namednodestable);
|
|
|
|
virHashFree(disks);
|
2017-03-13 11:46:18 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2017-03-15 12:03:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
qemuBlockDiskClearDetectedNodes(virDomainDiskDefPtr disk)
|
|
|
|
{
|
|
|
|
virStorageSourcePtr next = disk->src;
|
|
|
|
|
2017-10-12 17:27:40 +00:00
|
|
|
while (virStorageSourceIsBacking(next)) {
|
2017-03-15 12:03:21 +00:00
|
|
|
VIR_FREE(next->nodeformat);
|
2017-07-25 16:11:58 +00:00
|
|
|
VIR_FREE(next->nodestorage);
|
2017-03-15 12:03:21 +00:00
|
|
|
|
|
|
|
next = next->backingStore;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuBlockDiskDetectNodes(virDomainDiskDefPtr disk,
|
2017-07-26 07:36:21 +00:00
|
|
|
virHashTablePtr disktable)
|
2017-03-15 12:03:21 +00:00
|
|
|
{
|
|
|
|
qemuBlockNodeNameBackingChainDataPtr entry = NULL;
|
|
|
|
virStorageSourcePtr src = disk->src;
|
2017-09-25 09:44:00 +00:00
|
|
|
char *alias = NULL;
|
|
|
|
int ret = -1;
|
2017-03-15 12:03:21 +00:00
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
/* don't attempt the detection if the top level already has node names */
|
|
|
|
if (src->nodeformat || src->nodestorage)
|
|
|
|
return 0;
|
2017-03-15 12:03:21 +00:00
|
|
|
|
2017-09-25 09:44:00 +00:00
|
|
|
if (!(alias = qemuAliasFromDisk(disk)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!(entry = virHashLookup(disktable, alias))) {
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2017-09-25 09:39:55 +00:00
|
|
|
|
2017-10-12 17:27:40 +00:00
|
|
|
while (virStorageSourceIsBacking(src) && entry) {
|
2017-07-25 16:11:58 +00:00
|
|
|
if (src->nodeformat || src->nodestorage) {
|
2017-03-15 12:03:21 +00:00
|
|
|
if (STRNEQ_NULLABLE(src->nodeformat, entry->nodeformat) ||
|
2017-07-25 16:11:58 +00:00
|
|
|
STRNEQ_NULLABLE(src->nodestorage, entry->nodestorage))
|
2017-09-25 09:44:00 +00:00
|
|
|
goto cleanup;
|
2017-03-15 12:03:21 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
if (VIR_STRDUP(src->nodeformat, entry->nodeformat) < 0 ||
|
2017-07-25 16:11:58 +00:00
|
|
|
VIR_STRDUP(src->nodestorage, entry->nodestorage) < 0)
|
2017-09-25 09:44:00 +00:00
|
|
|
goto cleanup;
|
2017-03-15 12:03:21 +00:00
|
|
|
}
|
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
entry = entry->backing;
|
2017-03-15 12:03:21 +00:00
|
|
|
src = src->backingStore;
|
|
|
|
}
|
|
|
|
|
2017-09-25 09:44:00 +00:00
|
|
|
ret = 0;
|
2017-03-15 12:03:21 +00:00
|
|
|
|
2017-09-25 09:44:00 +00:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(alias);
|
|
|
|
if (ret < 0)
|
|
|
|
qemuBlockDiskClearDetectedNodes(disk);
|
|
|
|
|
|
|
|
return ret;
|
2017-03-15 12:03:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuBlockNodeNamesDetect(virQEMUDriverPtr driver,
|
2017-04-07 11:06:24 +00:00
|
|
|
virDomainObjPtr vm,
|
|
|
|
qemuDomainAsyncJob asyncJob)
|
2017-03-15 12:03:21 +00:00
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
virHashTablePtr disktable = NULL;
|
|
|
|
virJSONValuePtr data = NULL;
|
2017-07-26 07:36:21 +00:00
|
|
|
virJSONValuePtr blockstats = NULL;
|
2017-03-15 12:03:21 +00:00
|
|
|
virDomainDiskDefPtr disk;
|
|
|
|
size_t i;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QUERY_NAMED_BLOCK_NODES))
|
|
|
|
return 0;
|
|
|
|
|
2017-04-07 11:06:24 +00:00
|
|
|
if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
|
|
|
|
return -1;
|
2017-03-15 12:03:21 +00:00
|
|
|
|
|
|
|
data = qemuMonitorQueryNamedBlockNodes(qemuDomainGetMonitor(vm));
|
2017-07-26 07:36:21 +00:00
|
|
|
blockstats = qemuMonitorQueryBlockstats(qemuDomainGetMonitor(vm));
|
2017-03-15 12:03:21 +00:00
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
if (qemuDomainObjExitMonitor(driver, vm) < 0 || !data || !blockstats)
|
2017-03-15 12:03:21 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
if (!(disktable = qemuBlockNodeNameGetBackingChain(data, blockstats)))
|
2017-03-15 12:03:21 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
for (i = 0; i < vm->def->ndisks; i++) {
|
|
|
|
disk = vm->def->disks[i];
|
|
|
|
|
2017-07-26 07:36:21 +00:00
|
|
|
if (qemuBlockDiskDetectNodes(disk, disktable) < 0)
|
2017-03-15 12:03:21 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virJSONValueFree(data);
|
2017-07-26 07:36:21 +00:00
|
|
|
virJSONValueFree(blockstats);
|
2017-03-15 12:03:21 +00:00
|
|
|
virHashFree(disktable);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2017-03-16 11:30:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* qemuBlockGetNodeData:
|
|
|
|
* @data: JSON object returned from query-named-block-nodes
|
|
|
|
*
|
|
|
|
* Returns a hash table organized by the node name of the JSON value objects of
|
|
|
|
* data for given qemu block nodes.
|
|
|
|
*
|
|
|
|
* Returns a filled virHashTablePtr on success NULL on error.
|
|
|
|
*/
|
|
|
|
virHashTablePtr
|
|
|
|
qemuBlockGetNodeData(virJSONValuePtr data)
|
|
|
|
{
|
|
|
|
virHashTablePtr ret = NULL;
|
|
|
|
|
|
|
|
if (!(ret = virHashCreate(50, virJSONValueHashFree)))
|
|
|
|
return NULL;
|
|
|
|
|
2017-07-25 15:32:38 +00:00
|
|
|
if (virJSONValueArrayForeachSteal(data,
|
|
|
|
qemuBlockNamedNodesArrayToHash, ret) < 0)
|
2017-03-16 11:30:16 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virHashFree(ret);
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-07-07 14:29:01 +00:00
|
|
|
|
|
|
|
|
2017-07-13 13:38:50 +00:00
|
|
|
/**
|
|
|
|
* qemuBlockStorageSourceGetURI:
|
|
|
|
* @src: disk storage source
|
|
|
|
*
|
|
|
|
* Formats a URI from a virStorageSource.
|
|
|
|
*/
|
|
|
|
virURIPtr
|
|
|
|
qemuBlockStorageSourceGetURI(virStorageSourcePtr src)
|
|
|
|
{
|
|
|
|
virURIPtr uri = NULL;
|
|
|
|
virURIPtr ret = NULL;
|
|
|
|
|
|
|
|
if (src->nhosts != 1) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("protocol '%s' accepts only one host"),
|
|
|
|
virStorageNetProtocolTypeToString(src->protocol));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(uri) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_TCP) {
|
|
|
|
uri->port = src->hosts->port;
|
|
|
|
|
|
|
|
if (VIR_STRDUP(uri->scheme,
|
|
|
|
virStorageNetProtocolTypeToString(src->protocol)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
if (virAsprintf(&uri->scheme, "%s+%s",
|
|
|
|
virStorageNetProtocolTypeToString(src->protocol),
|
|
|
|
virStorageNetHostTransportTypeToString(src->hosts->transport)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (src->path) {
|
|
|
|
if (src->volume) {
|
2017-10-23 14:39:49 +00:00
|
|
|
if (virAsprintf(&uri->path, "/%s/%s",
|
2017-07-13 13:38:50 +00:00
|
|
|
src->volume, src->path) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
if (virAsprintf(&uri->path, "%s%s",
|
|
|
|
src->path[0] == '/' ? "" : "/",
|
|
|
|
src->path) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_STRDUP(uri->server, src->hosts->name) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
VIR_STEAL_PTR(ret, uri);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virURIFree(uri);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-12 11:43:31 +00:00
|
|
|
/**
|
|
|
|
* qemuBlockStorageSourceBuildJSONSocketAddress
|
|
|
|
* @host: the virStorageNetHostDefPtr definition to build
|
|
|
|
* @legacy: use 'tcp' instead of 'inet' for compatibility reasons
|
|
|
|
*
|
|
|
|
* Formats @hosts into a json object conforming to the 'SocketAddress' type
|
|
|
|
* in qemu.
|
|
|
|
*
|
|
|
|
* This function can be used when only 1 src->nhosts is expected in order
|
|
|
|
* to build a command without the array indices after "server.". That is
|
|
|
|
* to see "server.type", "server.host", and "server.port" instead of
|
|
|
|
* "server.#.type", "server.#.host", and "server.#.port".
|
|
|
|
*
|
|
|
|
* Returns a virJSONValuePtr for a single server.
|
|
|
|
*/
|
|
|
|
static virJSONValuePtr
|
|
|
|
qemuBlockStorageSourceBuildJSONSocketAddress(virStorageNetHostDefPtr host,
|
|
|
|
bool legacy)
|
|
|
|
{
|
|
|
|
virJSONValuePtr server = NULL;
|
|
|
|
virJSONValuePtr ret = NULL;
|
|
|
|
const char *transport;
|
|
|
|
char *port = NULL;
|
|
|
|
|
|
|
|
switch ((virStorageNetHostTransport) host->transport) {
|
|
|
|
case VIR_STORAGE_NET_HOST_TRANS_TCP:
|
|
|
|
if (legacy)
|
|
|
|
transport = "tcp";
|
|
|
|
else
|
|
|
|
transport = "inet";
|
|
|
|
|
|
|
|
if (virAsprintf(&port, "%u", host->port) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virJSONValueObjectCreate(&server,
|
|
|
|
"s:type", transport,
|
|
|
|
"s:host", host->name,
|
|
|
|
"s:port", port,
|
|
|
|
NULL) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_STORAGE_NET_HOST_TRANS_UNIX:
|
|
|
|
if (virJSONValueObjectCreate(&server,
|
|
|
|
"s:type", "unix",
|
|
|
|
"s:socket", host->socket,
|
|
|
|
NULL) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_STORAGE_NET_HOST_TRANS_RDMA:
|
|
|
|
case VIR_STORAGE_NET_HOST_TRANS_LAST:
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("transport protocol '%s' is not yet supported"),
|
|
|
|
virStorageNetHostTransportTypeToString(host->transport));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_STEAL_PTR(ret, server);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(port);
|
|
|
|
virJSONValueFree(server);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-07 15:55:04 +00:00
|
|
|
/**
|
|
|
|
* qemuBlockStorageSourceBuildHostsJSONSocketAddress:
|
|
|
|
* @src: disk storage source
|
|
|
|
* @legacy: use 'tcp' instead of 'inet' for compatibility reasons
|
|
|
|
*
|
|
|
|
* Formats src->hosts into a json object conforming to the 'SocketAddress' type
|
|
|
|
* in qemu.
|
|
|
|
*/
|
2017-07-07 14:29:01 +00:00
|
|
|
static virJSONValuePtr
|
2017-07-07 15:55:04 +00:00
|
|
|
qemuBlockStorageSourceBuildHostsJSONSocketAddress(virStorageSourcePtr src,
|
|
|
|
bool legacy)
|
2017-07-07 14:29:01 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr servers = NULL;
|
|
|
|
virJSONValuePtr server = NULL;
|
|
|
|
virJSONValuePtr ret = NULL;
|
|
|
|
virStorageNetHostDefPtr host;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (!(servers = virJSONValueNewArray()))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
for (i = 0; i < src->nhosts; i++) {
|
|
|
|
host = src->hosts + i;
|
|
|
|
|
2017-09-12 11:43:31 +00:00
|
|
|
if (!(server = qemuBlockStorageSourceBuildJSONSocketAddress(host, legacy)))
|
|
|
|
goto cleanup;
|
2017-07-07 14:29:01 +00:00
|
|
|
|
|
|
|
if (virJSONValueArrayAppend(servers, server) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
server = NULL;
|
|
|
|
}
|
|
|
|
|
2017-07-07 15:55:04 +00:00
|
|
|
VIR_STEAL_PTR(ret, servers);
|
2017-07-07 14:29:01 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virJSONValueFree(servers);
|
|
|
|
virJSONValueFree(server);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-23 16:02:28 +00:00
|
|
|
/**
|
|
|
|
* qemuBlockStorageSourceBuildJSONInetSocketAddress
|
|
|
|
* @host: the virStorageNetHostDefPtr definition to build
|
|
|
|
*
|
|
|
|
* Formats @hosts into a json object conforming to the 'InetSocketAddress' type
|
|
|
|
* in qemu.
|
|
|
|
*
|
|
|
|
* Returns a virJSONValuePtr for a single server.
|
|
|
|
*/
|
|
|
|
static virJSONValuePtr
|
|
|
|
qemuBlockStorageSourceBuildJSONInetSocketAddress(virStorageNetHostDefPtr host)
|
|
|
|
{
|
|
|
|
virJSONValuePtr ret = NULL;
|
|
|
|
char *port = NULL;
|
|
|
|
|
|
|
|
if (host->transport != VIR_STORAGE_NET_HOST_TRANS_TCP) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("only TCP protocol can be converted to InetSocketAddress"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&port, "%u", host->port) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ignore_value(virJSONValueObjectCreate(&ret,
|
|
|
|
"s:host", host->name,
|
|
|
|
"s:port", port,
|
|
|
|
NULL));
|
|
|
|
|
|
|
|
VIR_FREE(port);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-23 16:16:53 +00:00
|
|
|
/**
|
|
|
|
* qemuBlockStorageSourceBuildHostsJSONInetSocketAddress:
|
|
|
|
* @src: disk storage source
|
|
|
|
*
|
|
|
|
* Formats src->hosts into a json object conforming to the 'InetSocketAddress'
|
|
|
|
* type in qemu.
|
|
|
|
*/
|
|
|
|
static virJSONValuePtr
|
|
|
|
qemuBlockStorageSourceBuildHostsJSONInetSocketAddress(virStorageSourcePtr src)
|
|
|
|
{
|
|
|
|
virJSONValuePtr servers = NULL;
|
|
|
|
virJSONValuePtr server = NULL;
|
|
|
|
virJSONValuePtr ret = NULL;
|
|
|
|
virStorageNetHostDefPtr host;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (!(servers = virJSONValueNewArray()))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
for (i = 0; i < src->nhosts; i++) {
|
|
|
|
host = src->hosts + i;
|
|
|
|
|
|
|
|
if (!(server = qemuBlockStorageSourceBuildJSONInetSocketAddress(host)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virJSONValueArrayAppend(servers, server) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
server = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_STEAL_PTR(ret, servers);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virJSONValueFree(servers);
|
|
|
|
virJSONValueFree(server);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-07 14:29:01 +00:00
|
|
|
static virJSONValuePtr
|
2017-07-07 16:00:04 +00:00
|
|
|
qemuBlockStorageSourceGetGlusterProps(virStorageSourcePtr src)
|
2017-07-07 14:29:01 +00:00
|
|
|
{
|
|
|
|
virJSONValuePtr servers = NULL;
|
|
|
|
virJSONValuePtr ret = NULL;
|
|
|
|
|
2017-07-07 15:55:04 +00:00
|
|
|
if (!(servers = qemuBlockStorageSourceBuildHostsJSONSocketAddress(src, true)))
|
2017-07-07 14:29:01 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* { driver:"gluster",
|
|
|
|
* volume:"testvol",
|
|
|
|
* path:"/a.img",
|
|
|
|
* server :[{type:"tcp", host:"1.2.3.4", port:24007},
|
|
|
|
* {type:"unix", socket:"/tmp/glusterd.socket"}, ...]}
|
|
|
|
*/
|
|
|
|
if (virJSONValueObjectCreate(&ret,
|
2017-07-07 16:00:04 +00:00
|
|
|
"s:driver", "gluster",
|
2017-07-07 14:29:01 +00:00
|
|
|
"s:volume", src->volume,
|
|
|
|
"s:path", src->path,
|
|
|
|
"a:server", servers, NULL) < 0)
|
|
|
|
virJSONValueFree(servers);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
qemu: Add qemu command line generation for a VxHS block device
The VxHS block device will only use the newer formatting options and
avoid the legacy URI syntax.
An excerpt for a sample QEMU command line is:
-drive file.driver=vxhs,file.vdisk-id=eb90327c-8302-4725-9e1b-4e85ed4dc251,\
file.server.type=tcp,file.server.host=192.168.0.1,\
file.server.port=9999,format=raw,if=none,id=drive-virtio-disk0,cache=none \
-device virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,\
id=virtio-disk0
Update qemuxml2argvtest with a simple test.
Signed-off-by: Ashish Mittal <Ashish.Mittal@veritas.com>
Signed-off-by: John Ferlan <jferlan@redhat.com>
2017-08-30 13:46:53 +00:00
|
|
|
static virJSONValuePtr
|
|
|
|
qemuBlockStorageSourceGetVxHSProps(virStorageSourcePtr src)
|
|
|
|
{
|
|
|
|
const char *protocol = virStorageNetProtocolTypeToString(src->protocol);
|
|
|
|
virJSONValuePtr server = NULL;
|
|
|
|
virJSONValuePtr ret = NULL;
|
|
|
|
|
|
|
|
if (src->nhosts != 1) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("VxHS protocol accepts only one host"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-10-23 16:02:28 +00:00
|
|
|
if (!(server = qemuBlockStorageSourceBuildJSONInetSocketAddress(&src->hosts[0])))
|
qemu: Add qemu command line generation for a VxHS block device
The VxHS block device will only use the newer formatting options and
avoid the legacy URI syntax.
An excerpt for a sample QEMU command line is:
-drive file.driver=vxhs,file.vdisk-id=eb90327c-8302-4725-9e1b-4e85ed4dc251,\
file.server.type=tcp,file.server.host=192.168.0.1,\
file.server.port=9999,format=raw,if=none,id=drive-virtio-disk0,cache=none \
-device virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,\
id=virtio-disk0
Update qemuxml2argvtest with a simple test.
Signed-off-by: Ashish Mittal <Ashish.Mittal@veritas.com>
Signed-off-by: John Ferlan <jferlan@redhat.com>
2017-08-30 13:46:53 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* VxHS disk specification example:
|
|
|
|
* { driver:"vxhs",
|
qemu: Add TLS support for Veritas HyperScale (VxHS)
Alter qemu command line generation in order to possibly add TLS for
a suitably configured domain.
Sample TLS args generated by libvirt -
-object tls-creds-x509,id=objvirtio-disk0_tls0,dir=/etc/pki/qemu,\
endpoint=client,verify-peer=yes \
-drive file.driver=vxhs,file.tls-creds=objvirtio-disk0_tls0,\
file.vdisk-id=eb90327c-8302-4725-9e1b-4e85ed4dc251,\
file.server.type=tcp,file.server.host=192.168.0.1,\
file.server.port=9999,format=raw,if=none,\
id=drive-virtio-disk0,cache=none \
-device virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,\
id=virtio-disk0
Update the qemuxml2argvtest with a couple of examples. One for a
simple case and the other a bit more complex where multiple VxHS disks
are added where at least one uses a VxHS that doesn't require TLS
credentials and thus sets the domain disk source attribute "tls = 'no'".
Update the hotplug to be able to handle processing the tlsAlias whether
it's to add the TLS object when hotplugging a disk or to remove the TLS
object when hot unplugging a disk. The hot plug/unplug code is largely
generic, but the addition code does make the VXHS specific checks only
because it needs to grab the correct config directory and generate the
object as the command line would do.
Signed-off-by: Ashish Mittal <Ashish.Mittal@veritas.com>
Signed-off-by: John Ferlan <jferlan@redhat.com>
2017-08-30 15:06:00 +00:00
|
|
|
* tls-creds:"objvirtio-disk0_tls0",
|
qemu: Add qemu command line generation for a VxHS block device
The VxHS block device will only use the newer formatting options and
avoid the legacy URI syntax.
An excerpt for a sample QEMU command line is:
-drive file.driver=vxhs,file.vdisk-id=eb90327c-8302-4725-9e1b-4e85ed4dc251,\
file.server.type=tcp,file.server.host=192.168.0.1,\
file.server.port=9999,format=raw,if=none,id=drive-virtio-disk0,cache=none \
-device virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,\
id=virtio-disk0
Update qemuxml2argvtest with a simple test.
Signed-off-by: Ashish Mittal <Ashish.Mittal@veritas.com>
Signed-off-by: John Ferlan <jferlan@redhat.com>
2017-08-30 13:46:53 +00:00
|
|
|
* vdisk-id:"eb90327c-8302-4725-4e85ed4dc251",
|
|
|
|
* server:{type:"tcp", host:"1.2.3.4", port:9999}}
|
|
|
|
*/
|
|
|
|
if (virJSONValueObjectCreate(&ret,
|
|
|
|
"s:driver", protocol,
|
qemu: Add TLS support for Veritas HyperScale (VxHS)
Alter qemu command line generation in order to possibly add TLS for
a suitably configured domain.
Sample TLS args generated by libvirt -
-object tls-creds-x509,id=objvirtio-disk0_tls0,dir=/etc/pki/qemu,\
endpoint=client,verify-peer=yes \
-drive file.driver=vxhs,file.tls-creds=objvirtio-disk0_tls0,\
file.vdisk-id=eb90327c-8302-4725-9e1b-4e85ed4dc251,\
file.server.type=tcp,file.server.host=192.168.0.1,\
file.server.port=9999,format=raw,if=none,\
id=drive-virtio-disk0,cache=none \
-device virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,\
id=virtio-disk0
Update the qemuxml2argvtest with a couple of examples. One for a
simple case and the other a bit more complex where multiple VxHS disks
are added where at least one uses a VxHS that doesn't require TLS
credentials and thus sets the domain disk source attribute "tls = 'no'".
Update the hotplug to be able to handle processing the tlsAlias whether
it's to add the TLS object when hotplugging a disk or to remove the TLS
object when hot unplugging a disk. The hot plug/unplug code is largely
generic, but the addition code does make the VXHS specific checks only
because it needs to grab the correct config directory and generate the
object as the command line would do.
Signed-off-by: Ashish Mittal <Ashish.Mittal@veritas.com>
Signed-off-by: John Ferlan <jferlan@redhat.com>
2017-08-30 15:06:00 +00:00
|
|
|
"S:tls-creds", src->tlsAlias,
|
qemu: Add qemu command line generation for a VxHS block device
The VxHS block device will only use the newer formatting options and
avoid the legacy URI syntax.
An excerpt for a sample QEMU command line is:
-drive file.driver=vxhs,file.vdisk-id=eb90327c-8302-4725-9e1b-4e85ed4dc251,\
file.server.type=tcp,file.server.host=192.168.0.1,\
file.server.port=9999,format=raw,if=none,id=drive-virtio-disk0,cache=none \
-device virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,\
id=virtio-disk0
Update qemuxml2argvtest with a simple test.
Signed-off-by: Ashish Mittal <Ashish.Mittal@veritas.com>
Signed-off-by: John Ferlan <jferlan@redhat.com>
2017-08-30 13:46:53 +00:00
|
|
|
"s:vdisk-id", src->path,
|
|
|
|
"a:server", server, NULL) < 0)
|
|
|
|
virJSONValueFree(server);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-13 13:48:06 +00:00
|
|
|
static virJSONValuePtr
|
|
|
|
qemuBlockStorageSourceGetCURLProps(virStorageSourcePtr src)
|
|
|
|
{
|
|
|
|
qemuDomainStorageSourcePrivatePtr srcPriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(src);
|
|
|
|
const char *passwordalias = NULL;
|
|
|
|
const char *username = NULL;
|
|
|
|
virJSONValuePtr ret = NULL;
|
|
|
|
virURIPtr uri = NULL;
|
|
|
|
char *uristr = NULL;
|
|
|
|
const char *driver;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Common options:
|
|
|
|
* url, readahead, timeout, username, password-secret, proxy-username,
|
|
|
|
* proxy-password-secret
|
|
|
|
*
|
|
|
|
* Options for http transport:
|
|
|
|
* cookie, cookie-secret
|
|
|
|
*
|
|
|
|
* Options for secure transport (ftps, https):
|
|
|
|
* sslverify
|
|
|
|
*/
|
|
|
|
|
|
|
|
driver = virStorageNetProtocolTypeToString(src->protocol);
|
|
|
|
|
|
|
|
if (!(uri = qemuBlockStorageSourceGetURI(src)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!(uristr = virURIFormat(uri)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (src->auth) {
|
|
|
|
username = src->auth->username;
|
|
|
|
passwordalias = srcPriv->secinfo->s.aes.alias;
|
|
|
|
}
|
|
|
|
|
|
|
|
ignore_value(virJSONValueObjectCreate(&ret,
|
|
|
|
"s:driver", driver,
|
|
|
|
"s:url", uristr,
|
|
|
|
"S:username", username,
|
|
|
|
"S:password-secret", passwordalias,
|
|
|
|
NULL));
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virURIFree(uri);
|
|
|
|
VIR_FREE(uristr);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-19 15:44:57 +00:00
|
|
|
static virJSONValuePtr
|
|
|
|
qemuBlockStorageSourceGetISCSIProps(virStorageSourcePtr src)
|
|
|
|
{
|
|
|
|
qemuDomainStorageSourcePrivatePtr srcPriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(src);
|
|
|
|
const char *protocol = virStorageNetProtocolTypeToString(src->protocol);
|
|
|
|
char *target = NULL;
|
|
|
|
char *lunStr = NULL;
|
|
|
|
char *username = NULL;
|
|
|
|
char *objalias = NULL;
|
|
|
|
char *portal = NULL;
|
|
|
|
unsigned int lun = 0;
|
|
|
|
virJSONValuePtr ret = NULL;
|
|
|
|
|
|
|
|
/* { driver:"iscsi",
|
|
|
|
* transport:"tcp", ("iser" also possible)
|
|
|
|
* portal:"example.com",
|
|
|
|
* target:"iqn.2017-04.com.example:iscsi-disks",
|
|
|
|
* lun:1,
|
|
|
|
* user:"username",
|
|
|
|
* password-secret:"secret-alias",
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (VIR_STRDUP(target, src->path) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/* Separate the target and lun */
|
|
|
|
if ((lunStr = strchr(target, '/'))) {
|
|
|
|
*(lunStr++) = '\0';
|
|
|
|
if (virStrToLong_ui(lunStr, NULL, 10, &lun) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse target for lunStr '%s'"),
|
|
|
|
target);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* combine host and port into portal */
|
|
|
|
if (virSocketAddrNumericFamily(src->hosts[0].name) == AF_INET6) {
|
|
|
|
if (virAsprintf(&portal, "[%s]:%u",
|
|
|
|
src->hosts[0].name, src->hosts[0].port) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
if (virAsprintf(&portal, "%s:%u",
|
|
|
|
src->hosts[0].name, src->hosts[0].port) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (src->auth) {
|
|
|
|
username = src->auth->username;
|
|
|
|
objalias = srcPriv->secinfo->s.aes.alias;
|
|
|
|
}
|
|
|
|
|
|
|
|
ignore_value(virJSONValueObjectCreate(&ret,
|
|
|
|
"s:driver", protocol,
|
|
|
|
"s:portal", portal,
|
|
|
|
"s:target", target,
|
|
|
|
"u:lun", lun,
|
|
|
|
"s:transport", "tcp",
|
|
|
|
"S:user", username,
|
|
|
|
"S:password-secret", objalias,
|
|
|
|
NULL));
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(target);
|
|
|
|
VIR_FREE(portal);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-13 13:48:06 +00:00
|
|
|
static virJSONValuePtr
|
|
|
|
qemuBlockStorageSourceGetNBDProps(virStorageSourcePtr src)
|
|
|
|
{
|
|
|
|
virJSONValuePtr serverprops;
|
|
|
|
virJSONValuePtr ret = NULL;
|
|
|
|
|
|
|
|
if (src->nhosts != 1) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("nbd protocol accepts only one host"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
serverprops = qemuBlockStorageSourceBuildJSONSocketAddress(&src->hosts[0],
|
|
|
|
false);
|
|
|
|
if (!serverprops)
|
|
|
|
return NULL;
|
|
|
|
|
2017-11-09 09:29:53 +00:00
|
|
|
if (virJSONValueObjectCreate(&ret,
|
|
|
|
"s:driver", "nbd",
|
|
|
|
"a:server", serverprops,
|
|
|
|
"S:export", src->path,
|
|
|
|
"S:tls-creds", src->tlsAlias,
|
|
|
|
NULL) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
serverprops = NULL;
|
2017-07-13 13:48:06 +00:00
|
|
|
|
2017-11-09 09:29:53 +00:00
|
|
|
cleanup:
|
|
|
|
virJSONValueFree(serverprops);
|
2017-07-13 13:48:06 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-23 16:16:53 +00:00
|
|
|
static virJSONValuePtr
|
|
|
|
qemuBlockStorageSourceGetRBDProps(virStorageSourcePtr src)
|
|
|
|
{
|
|
|
|
qemuDomainStorageSourcePrivatePtr srcPriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(src);
|
|
|
|
virJSONValuePtr servers = NULL;
|
|
|
|
virJSONValuePtr ret = NULL;
|
|
|
|
const char *username = NULL;
|
|
|
|
|
|
|
|
if (src->nhosts > 0 &&
|
|
|
|
!(servers = qemuBlockStorageSourceBuildHostsJSONInetSocketAddress(src)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (src->auth)
|
|
|
|
username = srcPriv->secinfo->s.aes.username;
|
|
|
|
|
2017-11-09 09:29:53 +00:00
|
|
|
if (virJSONValueObjectCreate(&ret,
|
|
|
|
"s:driver", "rbd",
|
|
|
|
"s:pool", src->volume,
|
|
|
|
"s:image", src->path,
|
|
|
|
"S:snapshot", src->snapshot,
|
|
|
|
"S:conf", src->configFile,
|
|
|
|
"A:server", servers,
|
|
|
|
"S:user", username,
|
|
|
|
NULL) < 0)
|
|
|
|
goto cleanup;
|
2017-10-23 16:16:53 +00:00
|
|
|
|
2017-11-09 09:29:53 +00:00
|
|
|
servers = NULL;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virJSONValueFree(servers);
|
2017-10-23 16:16:53 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-23 16:44:35 +00:00
|
|
|
static virJSONValuePtr
|
|
|
|
qemuBlockStorageSourceGetSheepdogProps(virStorageSourcePtr src)
|
|
|
|
{
|
|
|
|
virJSONValuePtr serverprops;
|
|
|
|
virJSONValuePtr ret = NULL;
|
|
|
|
|
|
|
|
if (src->nhosts != 1) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("sheepdog protocol accepts only one host"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
serverprops = qemuBlockStorageSourceBuildJSONSocketAddress(&src->hosts[0],
|
|
|
|
false);
|
|
|
|
if (!serverprops)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* libvirt does not support the 'snap-id' and 'tag' properties */
|
2017-11-09 09:29:53 +00:00
|
|
|
if (virJSONValueObjectCreate(&ret,
|
|
|
|
"s:driver", "sheepdog",
|
|
|
|
"a:server", serverprops,
|
|
|
|
"s:vdi", src->path,
|
|
|
|
NULL) < 0)
|
|
|
|
goto cleanup;
|
2017-10-23 16:44:35 +00:00
|
|
|
|
2017-11-09 09:29:53 +00:00
|
|
|
serverprops = NULL;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virJSONValueFree(serverprops);
|
2017-10-23 16:44:35 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-23 16:54:12 +00:00
|
|
|
|
|
|
|
static virJSONValuePtr
|
|
|
|
qemuBlockStorageSourceGetSshProps(virStorageSourcePtr src)
|
|
|
|
{
|
|
|
|
virJSONValuePtr serverprops;
|
|
|
|
virJSONValuePtr ret = NULL;
|
|
|
|
const char *username = NULL;
|
|
|
|
|
|
|
|
if (src->nhosts != 1) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("sheepdog protocol accepts only one host"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
serverprops = qemuBlockStorageSourceBuildJSONInetSocketAddress(&src->hosts[0]);
|
|
|
|
if (!serverprops)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (src->auth)
|
|
|
|
username = src->auth->username;
|
|
|
|
|
2017-11-09 09:29:53 +00:00
|
|
|
if (virJSONValueObjectCreate(&ret,
|
|
|
|
"s:driver", "ssh",
|
|
|
|
"s:path", src->path,
|
|
|
|
"a:server", serverprops,
|
|
|
|
"S:user", username,
|
|
|
|
NULL) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
serverprops = NULL;
|
2017-10-23 16:54:12 +00:00
|
|
|
|
2017-11-09 09:29:53 +00:00
|
|
|
cleanup:
|
|
|
|
virJSONValueFree(serverprops);
|
2017-10-23 16:54:12 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-07 15:37:42 +00:00
|
|
|
/**
|
|
|
|
* qemuBlockStorageSourceGetBackendProps:
|
|
|
|
* @src: disk source
|
|
|
|
*
|
|
|
|
* Creates a JSON object describing the underlying storage or protocol of a
|
|
|
|
* storage source. Returns NULL on error and reports an appropriate error message.
|
|
|
|
*/
|
|
|
|
virJSONValuePtr
|
|
|
|
qemuBlockStorageSourceGetBackendProps(virStorageSourcePtr src)
|
2017-07-07 14:29:01 +00:00
|
|
|
{
|
|
|
|
int actualType = virStorageSourceGetActualType(src);
|
|
|
|
virJSONValuePtr fileprops = NULL;
|
|
|
|
|
|
|
|
switch ((virStorageType) actualType) {
|
|
|
|
case VIR_STORAGE_TYPE_BLOCK:
|
|
|
|
case VIR_STORAGE_TYPE_FILE:
|
|
|
|
case VIR_STORAGE_TYPE_DIR:
|
2017-07-13 07:48:14 +00:00
|
|
|
if (virJSONValueObjectCreate(&fileprops,
|
|
|
|
"s:driver", "file",
|
|
|
|
"s:filename", src->path, NULL) < 0)
|
|
|
|
return NULL;
|
|
|
|
break;
|
|
|
|
|
2017-07-07 14:29:01 +00:00
|
|
|
case VIR_STORAGE_TYPE_VOLUME:
|
|
|
|
case VIR_STORAGE_TYPE_NONE:
|
|
|
|
case VIR_STORAGE_TYPE_LAST:
|
2017-11-09 09:13:26 +00:00
|
|
|
return NULL;
|
2017-07-07 14:29:01 +00:00
|
|
|
|
|
|
|
case VIR_STORAGE_TYPE_NETWORK:
|
2017-07-07 15:37:42 +00:00
|
|
|
switch ((virStorageNetProtocol) src->protocol) {
|
|
|
|
case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
|
2017-07-07 16:00:04 +00:00
|
|
|
if (!(fileprops = qemuBlockStorageSourceGetGlusterProps(src)))
|
2017-10-10 06:23:12 +00:00
|
|
|
return NULL;
|
2017-07-07 15:37:42 +00:00
|
|
|
break;
|
|
|
|
|
qemu: Add qemu command line generation for a VxHS block device
The VxHS block device will only use the newer formatting options and
avoid the legacy URI syntax.
An excerpt for a sample QEMU command line is:
-drive file.driver=vxhs,file.vdisk-id=eb90327c-8302-4725-9e1b-4e85ed4dc251,\
file.server.type=tcp,file.server.host=192.168.0.1,\
file.server.port=9999,format=raw,if=none,id=drive-virtio-disk0,cache=none \
-device virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,\
id=virtio-disk0
Update qemuxml2argvtest with a simple test.
Signed-off-by: Ashish Mittal <Ashish.Mittal@veritas.com>
Signed-off-by: John Ferlan <jferlan@redhat.com>
2017-08-30 13:46:53 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_VXHS:
|
|
|
|
if (!(fileprops = qemuBlockStorageSourceGetVxHSProps(src)))
|
2017-10-10 06:23:12 +00:00
|
|
|
return NULL;
|
qemu: Add qemu command line generation for a VxHS block device
The VxHS block device will only use the newer formatting options and
avoid the legacy URI syntax.
An excerpt for a sample QEMU command line is:
-drive file.driver=vxhs,file.vdisk-id=eb90327c-8302-4725-9e1b-4e85ed4dc251,\
file.server.type=tcp,file.server.host=192.168.0.1,\
file.server.port=9999,format=raw,if=none,id=drive-virtio-disk0,cache=none \
-device virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,\
id=virtio-disk0
Update qemuxml2argvtest with a simple test.
Signed-off-by: Ashish Mittal <Ashish.Mittal@veritas.com>
Signed-off-by: John Ferlan <jferlan@redhat.com>
2017-08-30 13:46:53 +00:00
|
|
|
break;
|
|
|
|
|
2017-07-07 15:37:42 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_HTTP:
|
|
|
|
case VIR_STORAGE_NET_PROTOCOL_HTTPS:
|
|
|
|
case VIR_STORAGE_NET_PROTOCOL_FTP:
|
|
|
|
case VIR_STORAGE_NET_PROTOCOL_FTPS:
|
|
|
|
case VIR_STORAGE_NET_PROTOCOL_TFTP:
|
2017-07-13 13:48:06 +00:00
|
|
|
if (!(fileprops = qemuBlockStorageSourceGetCURLProps(src)))
|
|
|
|
return NULL;
|
|
|
|
break;
|
|
|
|
|
2017-10-19 15:44:57 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_ISCSI:
|
|
|
|
if (!(fileprops = qemuBlockStorageSourceGetISCSIProps(src)))
|
|
|
|
return NULL;
|
|
|
|
break;
|
|
|
|
|
2017-07-13 13:48:06 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_NBD:
|
2017-07-13 13:48:06 +00:00
|
|
|
if (!(fileprops = qemuBlockStorageSourceGetNBDProps(src)))
|
|
|
|
return NULL;
|
|
|
|
break;
|
|
|
|
|
2017-07-13 13:48:06 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_RBD:
|
2017-10-23 16:16:53 +00:00
|
|
|
if (!(fileprops = qemuBlockStorageSourceGetRBDProps(src)))
|
|
|
|
return NULL;
|
|
|
|
break;
|
|
|
|
|
2017-07-13 13:48:06 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
|
2017-10-23 16:44:35 +00:00
|
|
|
if (!(fileprops = qemuBlockStorageSourceGetSheepdogProps(src)))
|
|
|
|
return NULL;
|
|
|
|
break;
|
|
|
|
|
2017-07-07 15:37:42 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_SSH:
|
2017-10-23 16:54:12 +00:00
|
|
|
if (!(fileprops = qemuBlockStorageSourceGetSshProps(src)))
|
|
|
|
return NULL;
|
|
|
|
break;
|
|
|
|
|
2017-07-07 15:37:42 +00:00
|
|
|
case VIR_STORAGE_NET_PROTOCOL_NONE:
|
|
|
|
case VIR_STORAGE_NET_PROTOCOL_LAST:
|
2017-11-09 09:13:26 +00:00
|
|
|
return NULL;
|
2017-07-07 14:29:01 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-10-09 06:55:15 +00:00
|
|
|
if (virJSONValueObjectAdd(fileprops, "S:node-name", src->nodestorage, NULL) < 0) {
|
|
|
|
virJSONValueFree(fileprops);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-10-10 06:23:12 +00:00
|
|
|
return fileprops;
|
2017-07-07 14:29:01 +00:00
|
|
|
}
|