Qemu accepts gluster protocol as supported storage backend beside others. This patch allows users to specify disks on gluster backends like this: <disk type='network' device='disk'> <driver name='qemu' type='raw'/> <source protocol='gluster' name='volume/image'> <host name='example.org' port='6000' transport='tcp'/> </source> <target dev='vda' bus='virtio'/> </disk> In the <host> element above, transport is a new optional attribute. Valid transport values are tcp, unix or rdma. If none specified, tcp is assumed. If transport type is unix, another new optional attribute socket specifies path to unix socket: <disk type='network' device='disk'> <driver name='qemu' type='raw'/> <source protocol='gluster' name='volume/image'> <host transport='unix' socket='/path/to/sock'/> </source> <target dev='vdb' bus='virtio'/> </disk> Signed-off-by: Harsh Prateek Bora <harsh@xxxxxxxxxxxxxxxxxx> --- docs/formatdomain.html.in | 24 +++++-- docs/schemas/domaincommon.rng | 35 ++++++++-- src/conf/domain_conf.c | 72 ++++++++++++++++---- src/conf/domain_conf.h | 12 ++++ src/libvirt_private.syms | 2 + src/qemu/qemu_command.c | 155 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 272 insertions(+), 28 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index bc4cc4a..be2ba55 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1369,10 +1369,10 @@ to the directory to use as the disk. If the disk <code>type</code> is "network", then the <code>protocol</code> attribute specifies the protocol to access to the requested image; possible values - are "nbd", "rbd", and "sheepdog". If the <code>protocol</code> - attribute is "rbd" or "sheepdog", an additional - attribute <code>name</code> is mandatory to specify which - image will be used. When the disk <code>type</code> is + are "nbd", "rbd", "sheepdog" or "gluster". If the + <code>protocol</code> attribute is "rbd", "sheepdog" or "gluster", an + additional attribute <code>name</code> is mandatory to specify which + volume/image will be used. When the disk <code>type</code> is "network", the <code>source</code> may have zero or more <code>host</code> sub-elements used to specify the hosts to connect. @@ -1600,9 +1600,11 @@ <span class='since'>Since 0.10.1</span> </dd> <dt><code>host</code></dt> - <dd>The <code>host</code> element has two attributes "name" and "port", - which specify the hostname and the port number. The meaning of this - element and the number of the elements depend on the protocol attribute. + <dd>The <code>host</code> element supports 4 attributes, viz. "name", + "port", "transport" and "socket", which specify the hostname, the port + number, transport type and path to socket, respectively. The meaning + of this element and the number of the elements depend on the protocol + attribute. <table class="top_table"> <tr> <th> Protocol </th> @@ -1624,7 +1626,15 @@ <td> one of the sheepdog servers (default is localhost:7000) </td> <td> zero or one </td> </tr> + <tr> + <td> gluster </td> + <td> a server running glusterd daemon </td> + <td> only one </td> + </tr> </table> + In case of gluster, valid values for transport attribute are tcp, rdma + or unix. If nothing is specified, tcp is assumed. If transport is unix, + socket attribute specifies path to unix socket. </dd> <dt><code>address</code></dt> <dd>If present, the <code>address</code> element ties the disk diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index f47fdad..ea6bc54 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1048,6 +1048,7 @@ <value>nbd</value> <value>rbd</value> <value>sheepdog</value> + <value>gluster</value> </choice> </attribute> <optional> @@ -1055,15 +1056,35 @@ </optional> <zeroOrMore> <element name="host"> - <attribute name="name"> - <ref name="dnsName"/> - </attribute> - <attribute name="port"> - <ref name="unsignedInt"/> - </attribute> + <choice> + <group> + <optional> + <attribute name="transport"> + <choice> + <value>tcp</value> + <value>rdma</value> + </choice> + </attribute> + </optional> + <attribute name="name"> + <ref name="dnsName"/> + </attribute> + <attribute name="port"> + <ref name="unsignedInt"/> + </attribute> + </group> + <group> + <attribute name="transport"> + <value>unix</value> + </attribute> + <attribute name="socket"> + <ref name="absFilePath"/> + </attribute> + </group> + </choice> </element> </zeroOrMore> - <empty/> + <empty/> </element> </optional> <ref name="diskspec"/> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 33e1e7f..64b7c06 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -214,7 +214,13 @@ VIR_ENUM_IMPL(virDomainDiskErrorPolicy, VIR_DOMAIN_DISK_ERROR_POLICY_LAST, VIR_ENUM_IMPL(virDomainDiskProtocol, VIR_DOMAIN_DISK_PROTOCOL_LAST, "nbd", "rbd", - "sheepdog") + "sheepdog", + "gluster") + +VIR_ENUM_IMPL(virDomainDiskProtocolTransport, VIR_DOMAIN_DISK_PROTO_TRANS_LAST, + "tcp", + "unix", + "rdma") VIR_ENUM_IMPL(virDomainDiskSecretType, VIR_DOMAIN_DISK_SECRET_TYPE_LAST, "none", @@ -994,6 +1000,7 @@ void virDomainDiskHostDefFree(virDomainDiskHostDefPtr def) VIR_FREE(def->name); VIR_FREE(def->port); + VIR_FREE(def->socket); } void virDomainControllerDefFree(virDomainControllerDefPtr def) @@ -3460,6 +3467,7 @@ virDomainDiskDefParseXML(virCapsPtr caps, char *source = NULL; char *target = NULL; char *protocol = NULL; + char *protocol_transport; char *trans = NULL; virDomainDiskHostDefPtr hosts = NULL; int nhosts = 0; @@ -3566,19 +3574,43 @@ virDomainDiskDefParseXML(virCapsPtr caps, } hosts[nhosts].name = NULL; hosts[nhosts].port = NULL; + hosts[nhosts].transport = VIR_DOMAIN_DISK_PROTO_TRANS_TCP; + hosts[nhosts].socket = NULL; nhosts++; - hosts[nhosts - 1].name = virXMLPropString(child, "name"); - if (!hosts[nhosts - 1].name) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing name for host")); - goto error; + /* transport can be tcp (default), unix or rdma. */ + protocol_transport = virXMLPropString(child, "transport"); + if (protocol_transport != NULL) { + hosts[nhosts - 1].transport = virDomainDiskProtocolTransportTypeFromString(protocol_transport); + if (hosts[nhosts - 1].transport < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown protocol transport type '%s'"), + protocol_transport); + goto error; + } } - hosts[nhosts - 1].port = virXMLPropString(child, "port"); - if (!hosts[nhosts - 1].port) { + hosts[nhosts - 1].socket = virXMLPropString(child, "socket"); + + if (hosts[nhosts - 1].transport == VIR_DOMAIN_DISK_PROTO_TRANS_UNIX && + hosts[nhosts - 1].socket == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing port for host")); - goto error; + "%s", _("missing socket for unix transport")); + } + + if (hosts[nhosts - 1].transport != VIR_DOMAIN_DISK_PROTO_TRANS_UNIX) { + + hosts[nhosts - 1].name = virXMLPropString(child, "name"); + if (!hosts[nhosts - 1].name) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing name for host")); + goto error; + } + hosts[nhosts - 1].port = virXMLPropString(child, "port"); + if (!hosts[nhosts - 1].port) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing port for host")); + goto error; + } } } child = child->next; @@ -11754,10 +11786,22 @@ virDomainDiskDefFormat(virBufferPtr buf, virBufferAddLit(buf, ">\n"); for (i = 0; i < def->nhosts; i++) { - virBufferEscapeString(buf, " <host name='%s'", - def->hosts[i].name); - virBufferEscapeString(buf, " port='%s'/>\n", - def->hosts[i].port); + virBufferAddLit(buf, " <host"); + if (def->hosts[i].name) { + virBufferEscapeString(buf, " name='%s'", def->hosts[i].name); + } + if (def->hosts[i].port) { + virBufferEscapeString(buf, " port='%s'", + def->hosts[i].port); + } + if (def->hosts[i].transport) { + virBufferAsprintf(buf, " transport='%s'", + virDomainDiskProtocolTransportTypeToString(def->hosts[i].transport)); + } + if (def->hosts[i].socket) { + virBufferEscapeString(buf, " socket='%s'", def->hosts[i].socket); + } + virBufferAddLit(buf, "/>\n"); } virBufferAddLit(buf, " </source>\n"); } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 14dead3..32cab91 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -456,10 +456,19 @@ enum virDomainDiskProtocol { VIR_DOMAIN_DISK_PROTOCOL_NBD, VIR_DOMAIN_DISK_PROTOCOL_RBD, VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG, + VIR_DOMAIN_DISK_PROTOCOL_GLUSTER, VIR_DOMAIN_DISK_PROTOCOL_LAST }; +enum virDomainDiskProtocolTransport { + VIR_DOMAIN_DISK_PROTO_TRANS_TCP, + VIR_DOMAIN_DISK_PROTO_TRANS_UNIX, + VIR_DOMAIN_DISK_PROTO_TRANS_RDMA, + + VIR_DOMAIN_DISK_PROTO_TRANS_LAST +}; + enum virDomainDiskTray { VIR_DOMAIN_DISK_TRAY_CLOSED, VIR_DOMAIN_DISK_TRAY_OPEN, @@ -481,6 +490,8 @@ typedef virDomainDiskHostDef *virDomainDiskHostDefPtr; struct _virDomainDiskHostDef { char *name; char *port; + int transport; /* enum virDomainDiskProtocolTransport */ + char *socket; /* path to unix socket */ }; enum virDomainDiskIo { @@ -2166,6 +2177,7 @@ VIR_ENUM_DECL(virDomainDiskBus) VIR_ENUM_DECL(virDomainDiskCache) VIR_ENUM_DECL(virDomainDiskErrorPolicy) VIR_ENUM_DECL(virDomainDiskProtocol) +VIR_ENUM_DECL(virDomainDiskProtocolTransport) VIR_ENUM_DECL(virDomainDiskIo) VIR_ENUM_DECL(virDomainDiskSecretType) VIR_ENUM_DECL(virDomainDiskTray) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index dab607a..8e70837 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -350,6 +350,8 @@ virDomainDiskInsertPreAlloced; virDomainDiskIoTypeFromString; virDomainDiskIoTypeToString; virDomainDiskPathByName; +virDomainDiskProtocolTransportTypeFromString; +virDomainDiskProtocolTransportTypeToString; virDomainDiskRemove; virDomainDiskRemoveByName; virDomainDiskTypeFromString; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 20730a9..256ae63 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -2021,6 +2021,127 @@ no_memory: return -1; } +static int qemuParseGlusterString(virDomainDiskDefPtr def) +{ + char *uritoparse = strdup(def->src); + char *transp = NULL; + char *sock = NULL; + virURIPtr uri = NULL; + uri = virURIParse(uritoparse); + + if (VIR_ALLOC(def->hosts) < 0) { + virReportOOMError(); + return -1; + } + + if (STREQ(uri->scheme, "gluster")) { + def->hosts->transport = VIR_DOMAIN_DISK_PROTO_TRANS_TCP; + } else if (strstr(uri->scheme, "+")) { + transp = strstr(uri->scheme, "+"); + transp++; + def->hosts->transport = virDomainDiskProtocolTransportTypeFromString(transp); + if (def->hosts->transport < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid gluster transport type '%s'"), transp); + return -1; + + } + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid transport/scheme '%s'"), uri->scheme); + } + + def->nhosts = 1; + def->hosts->name = strdup(uri->server); + if (!def->hosts->name) { + virReportOOMError(); + return -1; + } + + if (virAsprintf(&def->hosts->port, "%d", uri->port) < 0) { + virReportOOMError(); + return -1; + } + if(STRPREFIX(uri->query, "socket=")) { + sock = strstr(uri->query, "="); + sock++; + def->hosts->socket = strdup(sock); + if (!def->hosts->socket) { + virReportOOMError(); + return -1; + } + + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid query parameter '%s'"), uri->query); + + } + + def->src = strdup(uri->path); + if (!def->src) { + virReportOOMError(); + return -1; + } + + VIR_FREE(uritoparse); + + return 0; +} + +static int +qemuBuildGlusterString(virDomainDiskDefPtr disk, virBufferPtr opt) +{ + int ret = 0, port = 0; + char *tmpscheme = NULL; + char *volimg = NULL; + char *sock = NULL; + char *builturi = NULL; + + virBufferAddLit(opt, "file="); + if (disk->nhosts != 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("gluster accepts only one host")); + ret = -1; + } else { + + if (virAsprintf(&tmpscheme, "gluster+%s", + virDomainDiskProtocolTransportTypeToString(disk->hosts->transport)) < 0) { + virReportOOMError(); + return -1; + } + if (virAsprintf(&volimg, "/%s", disk->src) < 0) { + virReportOOMError(); + return -1; + } + + if (disk->hosts->port) { + port = atoi(disk->hosts->port); + } + + if (disk->hosts->socket) { + if (virAsprintf(&sock, "socket=%s", disk->hosts->socket) < 0) { + virReportOOMError(); + return -1; + } + } + virURI uri = { + .scheme = tmpscheme, /* gluster+<transport> */ + .server = disk->hosts->name, + .port = port, + .path = volimg, + .query = sock, + }; + + builturi = virURIFormat(&uri); + virBufferAsprintf(opt, "%s", builturi); + + VIR_FREE(tmpscheme); + VIR_FREE(volimg); + VIR_FREE(sock); + } + return ret; +} + char * qemuBuildDriveStr(virConnectPtr conn ATTRIBUTE_UNUSED, virDomainDiskDefPtr disk, @@ -2162,6 +2283,12 @@ qemuBuildDriveStr(virConnectPtr conn ATTRIBUTE_UNUSED, goto error; virBufferAddChar(&opt, ','); break; + case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER: + if (qemuBuildGlusterString(disk, &opt) < 0) + goto error; + virBufferAddChar(&opt, ','); + break; + case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG: if (disk->nhosts == 0) { virBufferEscape(&opt, ',', ",", "file=sheepdog:%s,", @@ -5242,6 +5369,18 @@ qemuBuildCommandLine(virConnectPtr conn, file = virBufferContentAndReset(&opt); } break; + case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER: + { + virBuffer opt = VIR_BUFFER_INITIALIZER; + if (qemuBuildGlusterString(disk, &opt) < 0) + goto error; + if (virBufferError(&opt)) { + virReportOOMError(); + goto error; + } + file = virBufferContentAndReset(&opt); + } + break; case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG: if (disk->nhosts == 0) { if (virAsprintf(&file, "sheepdog:%s,", disk->src) < 0) { @@ -6937,6 +7076,14 @@ qemuParseCommandLineDisk(virCapsPtr caps, goto cleanup; VIR_FREE(p); + } else if (STRPREFIX(def->src, "gluster")) { + + def->type = VIR_DOMAIN_DISK_TYPE_NETWORK; + def->protocol = VIR_DOMAIN_DISK_PROTOCOL_GLUSTER; + + if (qemuParseGlusterString(def) < 0) + goto cleanup; + } else if (STRPREFIX(def->src, "sheepdog:")) { char *p = def->src; char *port, *vdi; @@ -8126,6 +8273,9 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps, disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK; disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_RBD; val += strlen("rbd:"); + } else if (STRPREFIX(val, "gluster")) { + disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK; + disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_GLUSTER; } else if (STRPREFIX(val, "sheepdog:")) { disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK; disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG; @@ -8211,6 +8361,11 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps, goto no_memory; } break; + case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER: + if (qemuParseGlusterString(disk) < 0) + goto error; + + break; } } -- 1.7.11.7