On 10/05/2012 05:27 PM, Paolo Bonzini wrote:
Il 04/10/2012 15:31, Harsh Prateek Bora ha scritto:
> 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>
>
> Note: In the <host> element above, transport is an optional attribute.
> Valid transport values are tcp, unix or rdma. If none specified, tcp is assumed.
> If transport type is unix, host name specifies path to unix socket.
I would rather add a new attribute "socket" than overload the host name.
The host name for Unix sockets is really localhost.
After looking into the URI infra, I realized, it is better to have the
new attribute name as 'query' since socket=</path/to/socket> in
qemu-gluster commandline is nothing but a query in the whole URI
following by a '?' character.
Since, the _virURI struct in libvirt also has a member 'query' for the
query string in a URI, it makes sense to keep the XML attribute as
generic as that so that it can be used by others for related purpose.
Needless to say, users will have to specify sockets as
<host name='example.org' port='6000' transport='unix'
query='socket=/path/to/sock' />
Also, since the libvirt mandates the host element to be provided a name
and port, but the qemu-gluster commandline doesnt allow server-port for
the unix transport, it will have to be handled differently, otherwise
the virURIFormat will add in the server, port info into the URI.
If no objections, I will shared the updated patches soon.
Harsh
Paolo
> Signed-off-by: Harsh Prateek Bora <harsh(a)linux.vnet.ibm.com>
> ---
> docs/schemas/domaincommon.rng | 8 ++
> src/conf/domain_conf.c | 28 +++++-
> src/conf/domain_conf.h | 11 +++
> src/libvirt_private.syms | 2 +
> src/qemu/qemu_command.c | 204 ++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 251 insertions(+), 2 deletions(-)
>
> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
> index f47fdad..89d9b9f 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>
> @@ -1061,6 +1062,13 @@
> <attribute name="port">
> <ref name="unsignedInt"/>
> </attribute>
> + <attribute name="transport">
> + <choice>
> + <value>tcp</value>
> + <value>unix</value>
> + <value>rdma</value>
> + </choice>
> + </attribute>
> </element>
> </zeroOrMore>
> <empty/>
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index 33e1e7f..838f079 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",
> @@ -3460,6 +3466,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,6 +3573,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
> }
> hosts[nhosts].name = NULL;
> hosts[nhosts].port = NULL;
> + hosts[nhosts].transport =
VIR_DOMAIN_DISK_PROTO_TRANS_TCP;
> nhosts++;
>
> hosts[nhosts - 1].name = virXMLPropString(child,
"name");
> @@ -3580,6 +3588,17 @@ virDomainDiskDefParseXML(virCapsPtr caps,
> "%s", _("missing port
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;
> + }
> + }
> }
> child = child->next;
> }
> @@ -11756,8 +11775,13 @@ virDomainDiskDefFormat(virBufferPtr buf,
> for (i = 0; i < def->nhosts; i++) {
> virBufferEscapeString(buf, " <host
name='%s'",
> def->hosts[i].name);
> - virBufferEscapeString(buf, "
port='%s'/>\n",
> + virBufferEscapeString(buf, " port='%s'",
> def->hosts[i].port);
> + if (def->hosts[i].transport) {
> + virBufferAsprintf(buf, " transport='%s'",
> +
virDomainDiskProtocolTransportTypeToString(def->hosts[i].transport));
> + }
> + virBufferAddLit(buf, "/>\n");
> }
> virBufferAddLit(buf, " </source>\n");
> }
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index 14dead3..7ba7e9b 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,7 @@ typedef virDomainDiskHostDef *virDomainDiskHostDefPtr;
> struct _virDomainDiskHostDef {
> char *name;
> char *port;
> + int transport; /* enum virDomainDiskProtocolTransport */
> };
>
> enum virDomainDiskIo {
> @@ -2166,6 +2176,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..0bed2bc 100644
> --- a/src/qemu/qemu_command.c
> +++ b/src/qemu/qemu_command.c
> @@ -2021,6 +2021,168 @@ no_memory:
> return -1;
> }
>
> +static int qemuParseGlusterString(virDomainDiskDefPtr def)
> +{
> + char *host = NULL, *port = NULL, *volimg, *transp = NULL, *marker;
> +
> + if (STRPREFIX(def->src, "+")) {
> + transp = def->src;
> + transp++;
> + marker = strstr(def->src, "://");
> + *marker++ = '\0';
> + marker += 2;
> + } else {
> + /* transport type not specified, use tcp as default */
> + def->hosts->transport = VIR_DOMAIN_DISK_PROTO_TRANS_TCP;
> + marker = strstr(def->src, "://");
> + marker += 3;
> + }
> +
> + if (transp) {
> + def->hosts->transport =
virDomainDiskProtocolTransportTypeFromString(transp);
> + if (def->hosts->transport < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Invalid gluster transport type
'%s'"), transp);
> + return -1;
> + }
> + }
> +
> + /* now marker points to string which can start with one of the following:
> + * IPv6 address in square brackets followed by port (optional)
> + * <hostname> or <IPv4 address> followed by port (optional)
> + * '/' if its a unix socket followed by path to gluster disk
volume/image
> + */
> +
> + /* parse server, port */
> + if (def->hosts->transport != VIR_DOMAIN_DISK_PROTO_TRANS_UNIX) {
> + if (STRPREFIX(marker, "[")) {
> + /* IPv6 addr */
> + host = ++marker;
> + marker = strchr(host, ']');
> + if (!marker) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Cannot parse IPv6 addr for gluster host %s
"), host);
> + return -1;
> + }
> + *marker++ = '\0';
> + /* parse port if specified */
> + if (STRPREFIX(marker, ":")) {
> + port = ++marker;
> + marker = strchr(port, '/');
> + if (!marker) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Cannot parse filename for gluster disk %s
"), port);
> + return -1;
> + }
> + *marker++ = '\0';
> + } else {
> + marker++; /* port not specified, skip slash */
> + }
> + } else {
> + /* IPv4 address / hostname followed by port (optional) */
> + host = marker;
> + marker = strchr(host, '/'); /* skip to path to gluster disk
vol/img */
> + if (!marker) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Cannot parse filename for gluster disk %s
"), port);
> + return -1;
> + }
> + *marker++ = '\0';
> + port = strchr(host, ':');
> + if (port) {
> + /* port was specified with host, separate both */
> + *port++ = '\0';
> + }
> + }
> +
> + /* host points to hostname / IPv4 / IPv6 addr
> + * port points to port or NULL is port was not specified
> + */
> + } else {
> + /* transport type is unix, expect one more slash
> + * followed by path to gluster disk vol/img */
> + if (STRPREFIX(marker, "/")) {
> + marker++;
> + } else {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Gluster unix transport url starts with 3 slashes
i.e. gluster+unix:///"));
> + return -1;
> + }
> + }
> +
> + /* marker now points to path to gluster disk vol/img */
> + volimg = marker;
> +
> + /* if transport type = unix, path to gluster disk vol/img
> + * is followed by ?socket=<path/to/socket> */
> + if (def->hosts->transport == VIR_DOMAIN_DISK_PROTO_TRANS_UNIX) {
> + if (strstr(marker, "?socket=")) {
> + /* In libvirt xml, socket path is to be provided as
> + * <host name='/path/to/socket' port='0'>
> + */
> + host = strchr(marker, '=');
> + *host++ = '\0';
> + }
> + }
> +
> + if (VIR_ALLOC(def->hosts) < 0) {
> + virReportOOMError();
> + return -1;
> + }
> + def->nhosts = 1;
> + def->hosts->name = host;
> + if (port) {
> + def->hosts->port = port;
> + } else {
> + def->hosts->port = strdup("0");
> + }
> + if (!def->hosts->port) {
> + virReportOOMError();
> + return -1;
> + }
> + def->src = strdup(volimg);
> + if (!def->src) {
> + virReportOOMError();
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +qemuBuildGlusterString(virDomainDiskDefPtr disk, virBufferPtr opt)
> +{
> + int ret = 0;
> + virBufferAddLit(opt, "file=");
> + if (disk->nhosts != 1) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("gluster accepts only one host"));
> + ret = -1;
> + } else {
> + virBufferAsprintf(opt, "gluster+%s://",
> +
virDomainDiskProtocolTransportTypeToString(disk->hosts->transport));
> +
> + /* if transport type is not unix, specify server:port */
> + if (disk->hosts->transport != VIR_DOMAIN_DISK_PROTO_TRANS_UNIX) {
> + if (strstr(disk->hosts->name, ":")) {
> + /* if IPv6 addr, use square brackets to enclose it */
> + virBufferAsprintf(opt, "[%s]:%s", disk->hosts->name,
disk->hosts->port);
> + } else {
> + virBufferAsprintf(opt, "%s:%s", disk->hosts->name,
disk->hosts->port);
> + }
> + }
> +
> + /* append source path to gluster disk image */
> + virBufferAsprintf(opt, "/%s", disk->src);
> +
> + /* if transport type is unix, server name is path to unix socket, ignore
port */
> + if (disk->hosts->transport == VIR_DOMAIN_DISK_PROTO_TRANS_UNIX) {
> + virBufferAsprintf(opt, "?socket=%s",
disk->hosts->name);
> + }
> + }
> + return ret;
> +}
> +
> char *
> qemuBuildDriveStr(virConnectPtr conn ATTRIBUTE_UNUSED,
> virDomainDiskDefPtr disk,
> @@ -2162,6 +2324,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 +5410,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 +7117,21 @@ qemuParseCommandLineDisk(virCapsPtr caps,
> goto cleanup;
>
> VIR_FREE(p);
> + } else if (STRPREFIX(def->src, "gluster")) {
> + char *p = def->src;
> +
> + def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
> + def->protocol = VIR_DOMAIN_DISK_PROTOCOL_GLUSTER;
> + def->src = strdup(p + strlen("gluster"));
> + if (!def->src) {
> + virReportOOMError();
> + goto cleanup;
> + }
> +
> + if (qemuParseGlusterString(def) < 0)
> + goto cleanup;
> +
> + VIR_FREE(p);
> } else if (STRPREFIX(def->src, "sheepdog:")) {
> char *p = def->src;
> char *port, *vdi;
> @@ -8126,6 +8321,10 @@ 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;
> + val += strlen("gluster");
> } else if (STRPREFIX(val, "sheepdog:")) {
> disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
> disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG;
> @@ -8211,6 +8410,11 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
> goto no_memory;
> }
> break;
> + case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER:
> + if (qemuParseGlusterString(disk) < 0)
> + goto error;
> +
> + break;
> }
> }
>
>