currently libvirt has the capability to parse only one host and convert that
into URI formatted string, with the help of this patch libvirt will be able
to parse multiple hosts from the domain xml and can convert that into JSON
formatted string
before:
------
example.xml:
...
<disk type='network' device='disk'>
<driver name='qemu' type='qcow2' cache='none'/>
<source protocol='gluster' name='testvol/a.qcow2'>
<host name='1.2.3.4' port='24007'
transport="tcp"/>
</source>
<target dev='vda' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00'
slot='0x04' function='0x0'/>
</disk>
...
resultant string:
file=gluster://1.2.3.4:24007/testvol/a.qcow2, \
if=none,id=drive-virtio-disk0,format=qcow2,cache=none
after:
-----
example.xml:
...
<disk type='network' device='disk'>
<driver name='qemu' type='qcow2' cache='none'/>
<source protocol='gluster' name='testvol/a.qcow2'>
<host name='1.2.3.4' port='24009'
transport="tcp"/>
<host name='3.4.5.6' port="24008"/>
<host name='5.6.7.8' />
</source>
<target dev='vda' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00'
slot='0x04' function='0x0'/>
</disk>
...
resultant string:
-drive file=json:{
"file": {
"driver": "gluster",,
"volname": "testvol",,
"image-path": "/a.qcow2",,
"volfile-servers": [
{
"server": "1.2.3.4",,
"port": 24009,,
"transport": "tcp"
},,
{
"server": "3.4.5.6",,
"port": 24008,,
"transport": "tcp"
},,
{
"server": "5.6.7.8",,
"port": 24007,,
"transport": "tcp"
}
]
},,
"driver": "qcow2"
}
,if=none,id=drive-virtio-disk0,cache=none
if the number of hosts supplied is only one, then we use existing URI format
for backward compatibility and if number of hosts is greater than one we switch
to the new JSON format
this patch requires qemu latest patch
https://lists.gnu.org/archive/html/qemu-devel/2015-09/msg07062.html
Credits: Sincere thanks to Kevin Wolf <kwolf(a)redhat.com> and
"Deepak C Shetty" <deepakcs(a)redhat.com> for their support
Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever(a)redhat.com>
---
src/qemu/qemu_command.c | 192 ++++++++++++++++++++++++++++++++++++------------
1 file changed, 145 insertions(+), 47 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index bb1835c..8c1bf1a 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3256,16 +3256,106 @@ qemuNetworkDriveGetPort(int protocol,
return -1;
}
+#define QEMU_DEFAULT_GLUSTER_PORT 24007
+
+static virJSONValuePtr
+qemuBuildGlusterDriveJSON(virStorageSourcePtr src)
+{
+ virJSONValuePtr parent = NULL;
+ virJSONValuePtr object = NULL;
+ virJSONValuePtr dict_array = NULL;
+ int port;
+ int i;
+
+ if (!(parent = virJSONValueNewObject()))
+ return NULL;
+ /* 1. prepare { driver:"gluster", volname:"testvol",
image-path:"/a.img"} */
+ if (virJSONValueObjectAdd(parent,
+ "s:driver",
virStorageNetProtocolTypeToString(src->protocol),
+ "s:volname", src->volume,
+ "s:image-path", src->path,
+ NULL) < 0)
+ goto cleanup;
+
+ if (!(dict_array = virJSONValueNewArray()))
+ goto cleanup;
+ /* 2. prepare array [ {server:"1.2.3.4", port:24007,
transport:"tcp"} ,
+ * {server:"5.6.7.8", port:24008,
transport:"rdma"},
+ * {}, ... ] */
+ for (i = 0; i < src->nhosts; i++) {
+ if (!(object = virJSONValueNewObject()))
+ goto cleanup;
+ port = qemuNetworkDriveGetPort(src->protocol, src->hosts[i].port);
+ if (virJSONValueObjectAdd(object, "s:server", src->hosts[i].name,
+ "i:port", port ? port : QEMU_DEFAULT_GLUSTER_PORT ,
+ "s:transport",
+ virStorageNetHostTransportTypeToString(src->hosts[i].transport),
+ NULL) < 0)
+ goto cleanup;
+ if (virJSONValueArrayAppend(dict_array, object) < 0) {
+ virJSONValueFree(object);
+ goto cleanup;
+ }
+ }
+ /* 3. append 1 and 2
+ * { driver:"gluster", volname:"testvol",
image-path:"/a.img",
+ * volfile-servers :[ {server:"1.2.3.4", port:24007,
transport:"tcp"} ,
+ * {server:"5.6.7.8", port:24008,
transport:"rdma"},
+ * {}, ... ] }
+ */
+ if (virJSONValueObjectAppend(parent, "volfile-servers", dict_array) < 0)
{
+ virJSONValueFree(dict_array);
+ goto cleanup;
+ }
+ /* 4. assign key to 3
+ * { file: { driver:"gluster", volname:"testvol",
image-path:"/a.img",
+ * volfile-servers :[ {server:"1.2.3.4", port:24007,
transport:"tcp"} ,
+ * {server:"5.6.7.8", port:24008,
transport:"rdma"},
+ * {}, ... ] } }
+ */
+ if (!(object = virJSONValueNewObject()))
+ goto cleanup;
+ if (virJSONValueObjectAppend(object, "file", parent) < 0) {
+ virJSONValueFree(parent);
+ goto cleanup;
+ }
+ /* 5. append format to 4
+ * { file: { driver:"gluster", volname:"testvol",
image-path:"/a.img",
+ * volfile-servers :[ {server:"1.2.3.4", port:24007,
transport:"tcp"} ,
+ * {server:"5.6.7.8", port:24008,
transport:"rdma"},
+ * {}, ... ] }, driver:"qcow2" }
+ */
+ if (virJSONValueObjectAdd(object,
+ "s:driver", virStorageFileFormatTypeToString(src->format),
+ NULL) < 0)
+ goto cleanup;
+ else
+ /* since we have already captured the format type, let's make it '0'
to
+ * avoid further checks for format information
+ */
+ src->format = 0;
+
+ return object;
+
+cleanup:
+ virJSONValueFree(dict_array);
+ virJSONValueFree(parent);
+ virJSONValueFree(object);
+ return NULL;
+}
+
#define QEMU_DEFAULT_NBD_PORT "10809"
static char *
-qemuBuildNetworkDriveURI(virStorageSourcePtr src,
+qemuBuildNetworkDriveStr(virStorageSourcePtr src,
const char *username,
const char *secret)
{
char *ret = NULL;
+ char *str = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virURIPtr uri = NULL;
+ virJSONValuePtr json = NULL;
size_t i;
switch ((virStorageNetProtocol) src->protocol) {
@@ -3331,61 +3421,67 @@ qemuBuildNetworkDriveURI(virStorageSourcePtr src,
case VIR_STORAGE_NET_PROTOCOL_TFTP:
case VIR_STORAGE_NET_PROTOCOL_ISCSI:
case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
- 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) {
- if (VIR_STRDUP(uri->scheme,
- virStorageNetProtocolTypeToString(src->protocol)) <
0)
+ if (src->nhosts == 1) {
+ /* URI syntax generation */
+ if (VIR_ALLOC(uri) < 0)
goto cleanup;
- } else {
- if (virAsprintf(&uri->scheme, "%s+%s",
- virStorageNetProtocolTypeToString(src->protocol),
-
virStorageNetHostTransportTypeToString(src->hosts->transport)) < 0)
- goto cleanup;
- }
-
- if ((uri->port = qemuNetworkDriveGetPort(src->protocol,
src->hosts->port)) < 0)
- goto cleanup;
- if (src->path) {
- if (src->volume) {
- if (virAsprintf(&uri->path, "/%s%s",
- src->volume, src->path) < 0)
+ if (src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_TCP) {
+ if (VIR_STRDUP(uri->scheme,
+ virStorageNetProtocolTypeToString(src->protocol))
< 0)
goto cleanup;
} else {
- if (virAsprintf(&uri->path, "%s%s",
- src->path[0] == '/' ? "" :
"/",
- src->path) < 0)
+ if (virAsprintf(&uri->scheme, "%s+%s",
+ virStorageNetProtocolTypeToString(src->protocol),
+
virStorageNetHostTransportTypeToString(src->hosts->transport)) < 0)
goto cleanup;
}
- }
- if (src->hosts->socket &&
- virAsprintf(&uri->query, "socket=%s",
src->hosts->socket) < 0)
- goto cleanup;
+ if ((uri->port = qemuNetworkDriveGetPort(src->protocol,
src->hosts->port)) < 0)
+ goto cleanup;
- if (username) {
- if (secret) {
- if (virAsprintf(&uri->user, "%s:%s", username,
secret) < 0)
- goto cleanup;
- } else {
- if (VIR_STRDUP(uri->user, username) < 0)
- goto cleanup;
+ if (src->path) {
+ if (src->volume) {
+ if (virAsprintf(&uri->path, "/%s%s",
+ 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;
+ if (src->hosts->socket &&
+ virAsprintf(&uri->query, "socket=%s",
src->hosts->socket) < 0)
+ goto cleanup;
- ret = virURIFormat(uri);
+ if (username) {
+ if (secret) {
+ if (virAsprintf(&uri->user, "%s:%s", username,
secret) < 0)
+ goto cleanup;
+ } else {
+ if (VIR_STRDUP(uri->user, username) < 0)
+ goto cleanup;
+ }
+ }
+
+ if (VIR_STRDUP(uri->server, src->hosts->name) < 0)
+ goto cleanup;
+
+ ret = virURIFormat(uri);
+ } else {
+ /* switch to new json formated syntax */
+ if(!(json = qemuBuildGlusterDriveJSON(src)))
+ goto cleanup;
+
+ if (!(str = virJSONValueToString(json, false)))
+ goto cleanup;
+
+ if (virAsprintf (&ret, "json:%s", str) < 0)
+ goto cleanup;
+ }
break;
@@ -3472,7 +3568,9 @@ qemuBuildNetworkDriveURI(virStorageSourcePtr src,
}
cleanup:
+ VIR_FREE(str);
virBufferFreeAndReset(&buf);
+ virJSONValueFree(json);
virURIFree(uri);
return ret;
@@ -3530,7 +3628,7 @@ qemuGetDriveSourceString(virStorageSourcePtr src,
break;
case VIR_STORAGE_TYPE_NETWORK:
- if (!(*source = qemuBuildNetworkDriveURI(src, username, secret)))
+ if (!(*source = qemuBuildNetworkDriveStr(src, username, secret)))
goto cleanup;
break;
@@ -6391,7 +6489,7 @@ qemuBuildSCSIiSCSIHostdevDrvStr(virConnectPtr conn,
src.nhosts = iscsisrc->nhosts;
/* Rather than pull what we think we want - use the network disk code */
- source = qemuBuildNetworkDriveURI(&src, username, secret);
+ source = qemuBuildNetworkDriveStr(&src, username, secret);
cleanup:
VIR_FREE(secret);
--
2.1.0