From 02d1f16bbdc312df3962b4f4ca23713e6e96e2d7 Mon Sep 17 00:00:00 2001 From: Lev Klimin Date: Thu, 22 Feb 2024 10:56:07 +0300 Subject: [PATCH] Add ubuntu jammy build PR #62 https://git.yourcmc.ru/vitalif/vitastor/pulls/62 I accept Vitastor CLA agreement: https://git.yourcmc.ru/vitalif/vitastor/src/branch/master/CLA-en.md --- debian/build-vitastor-bookworm.sh | 2 +- debian/build-vitastor-bullseye.sh | 2 +- debian/build-vitastor-buster.sh | 2 +- debian/build-vitastor-ubuntu-jammy.sh | 7 + debian/libvirt.Dockerfile | 9 +- debian/vitastor.Dockerfile | 6 +- patches/libvirt-8.0-vitastor.diff | 692 ++++++++++++++++++++++++++ 7 files changed, 711 insertions(+), 9 deletions(-) create mode 100755 debian/build-vitastor-ubuntu-jammy.sh create mode 100644 patches/libvirt-8.0-vitastor.diff diff --git a/debian/build-vitastor-bookworm.sh b/debian/build-vitastor-bookworm.sh index 668381dc..d13cdaf5 100755 --- a/debian/build-vitastor-bookworm.sh +++ b/debian/build-vitastor-bookworm.sh @@ -3,5 +3,5 @@ cat < vitastor.Dockerfile > ../Dockerfile cd .. mkdir -p packages -sudo podman build --build-arg REL=bookworm -v `pwd`/packages:/root/packages -f Dockerfile . +sudo podman build --build-arg DISTRO=debian --build-arg REL=bookworm -v `pwd`/packages:/root/packages -f Dockerfile . rm Dockerfile diff --git a/debian/build-vitastor-bullseye.sh b/debian/build-vitastor-bullseye.sh index c5b2bb51..6e1c3047 100755 --- a/debian/build-vitastor-bullseye.sh +++ b/debian/build-vitastor-bullseye.sh @@ -3,5 +3,5 @@ cat < vitastor.Dockerfile > ../Dockerfile cd .. mkdir -p packages -sudo podman build --build-arg REL=bullseye -v `pwd`/packages:/root/packages -f Dockerfile . +sudo podman build --build-arg DISTRO=debian --build-arg REL=bullseye -v `pwd`/packages:/root/packages -f Dockerfile . rm Dockerfile diff --git a/debian/build-vitastor-buster.sh b/debian/build-vitastor-buster.sh index 235ad296..66d1526c 100755 --- a/debian/build-vitastor-buster.sh +++ b/debian/build-vitastor-buster.sh @@ -3,5 +3,5 @@ cat < vitastor.Dockerfile > ../Dockerfile cd .. mkdir -p packages -sudo podman build --build-arg REL=buster -v `pwd`/packages:/root/packages -f Dockerfile . +sudo podman build --build-arg DISTRO=debian --build-arg REL=buster -v `pwd`/packages:/root/packages -f Dockerfile . rm Dockerfile diff --git a/debian/build-vitastor-ubuntu-jammy.sh b/debian/build-vitastor-ubuntu-jammy.sh new file mode 100755 index 00000000..c4f988a1 --- /dev/null +++ b/debian/build-vitastor-ubuntu-jammy.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +cat < vitastor.Dockerfile > ../Dockerfile +cd .. +mkdir -p packages +sudo podman build --build-arg DISTRO=ubuntu --build-arg REL=jammy -v `pwd`/packages:/root/packages -f Dockerfile . +rm Dockerfile diff --git a/debian/libvirt.Dockerfile b/debian/libvirt.Dockerfile index 07a8883a..136d2288 100644 --- a/debian/libvirt.Dockerfile +++ b/debian/libvirt.Dockerfile @@ -1,13 +1,14 @@ # Build patched libvirt for Debian Buster or Bullseye/Sid inside a container -# cd ..; podman build --build-arg REL=bullseye -v `pwd`/packages:/root/packages -f debian/libvirt.Dockerfile . +# cd ..; podman build --build-arg DISTRO=debian --build-arg REL=bullseye -v `pwd`/packages:/root/packages -f debian/libvirt.Dockerfile . +ARG DISTRO= ARG REL= -FROM debian:$REL +FROM $DISTRO:$REL ARG REL= WORKDIR /root -RUN if [ "$REL" = "buster" -o "$REL" = "bullseye" ]; then \ +RUN if ([ "${DISTRO}" = "debian" ]) && ( [ "${REL}" = "buster" -o "${REL}" = "bullseye" ] ); then \ echo "deb http://deb.debian.org/debian $REL-backports main" >> /etc/apt/sources.list; \ echo >> /etc/apt/preferences; \ echo 'Package: *' >> /etc/apt/preferences; \ @@ -23,7 +24,7 @@ RUN apt-get -y build-dep libvirt0 RUN apt-get -y install libglusterfs-dev RUN apt-get --download-only source libvirt -ADD patches/libvirt-5.0-vitastor.diff patches/libvirt-7.0-vitastor.diff patches/libvirt-7.5-vitastor.diff patches/libvirt-7.6-vitastor.diff /root +ADD patches/libvirt-5.0-vitastor.diff patches/libvirt-7.0-vitastor.diff patches/libvirt-7.5-vitastor.diff patches/libvirt-7.6-vitastor.diff patches/libvirt-8.0-vitastor.diff /root RUN set -e; \ mkdir -p /root/packages/libvirt-$REL; \ rm -rf /root/packages/libvirt-$REL/*; \ diff --git a/debian/vitastor.Dockerfile b/debian/vitastor.Dockerfile index 072a7283..a736a50d 100644 --- a/debian/vitastor.Dockerfile +++ b/debian/vitastor.Dockerfile @@ -1,8 +1,10 @@ # Build Vitastor packages for Debian inside a container -# cd ..; podman build --build-arg REL=bullseye -v `pwd`/packages:/root/packages -f debian/vitastor.Dockerfile . +# cd ..; podman build --build-arg DISTRO=debian --build-arg REL=bullseye -v `pwd`/packages:/root/packages -f debian/vitastor.Dockerfile . +ARG DISTRO=debian ARG REL= -FROM debian:$REL +FROM $DISTRO:$REL +ARG DISTRO=debian ARG REL= WORKDIR /root diff --git a/patches/libvirt-8.0-vitastor.diff b/patches/libvirt-8.0-vitastor.diff new file mode 100644 index 00000000..6107486e --- /dev/null +++ b/patches/libvirt-8.0-vitastor.diff @@ -0,0 +1,692 @@ +commit d85024bd803b3b91f15578ed22de4ce31856626f +Author: Vitaliy Filippov +Date: Wed Jan 24 18:07:43 2024 +0300 + + Add Vitastor support + +diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng +index 7fa5c2b8b5..2d77f391e7 100644 +--- a/docs/schemas/domaincommon.rng ++++ b/docs/schemas/domaincommon.rng +@@ -1898,6 +1898,35 @@ + + + ++ ++ ++ ++ ++ vitastor ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +@@ -2154,6 +2183,7 @@ + + + ++ + + + +diff --git a/include/libvirt/libvirt-storage.h b/include/libvirt/libvirt-storage.h +index f89856b93e..a8cb9387e2 100644 +--- a/include/libvirt/libvirt-storage.h ++++ b/include/libvirt/libvirt-storage.h +@@ -246,6 +246,7 @@ typedef enum { + VIR_CONNECT_LIST_STORAGE_POOLS_ZFS = 1 << 17, + VIR_CONNECT_LIST_STORAGE_POOLS_VSTORAGE = 1 << 18, + VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI_DIRECT = 1 << 19, ++ VIR_CONNECT_LIST_STORAGE_POOLS_VITASTOR = 1 << 20, + } virConnectListAllStoragePoolsFlags; + + int virConnectListAllStoragePools(virConnectPtr conn, +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index 5691b8d2d5..6669e8451d 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -8293,7 +8293,8 @@ virDomainDiskSourceNetworkParse(xmlNodePtr node, + src->configFile = virXPathString("string(./config/@file)", ctxt); + + if (src->protocol == VIR_STORAGE_NET_PROTOCOL_HTTP || +- src->protocol == VIR_STORAGE_NET_PROTOCOL_HTTPS) ++ src->protocol == VIR_STORAGE_NET_PROTOCOL_HTTPS || ++ src->protocol == VIR_STORAGE_NET_PROTOCOL_VITASTOR) + src->query = virXMLPropString(node, "query"); + + if (virDomainStorageNetworkParseHosts(node, ctxt, &src->hosts, &src->nhosts) < 0) +@@ -31267,6 +31268,7 @@ virDomainStorageSourceTranslateSourcePool(virStorageSource *src, + + case VIR_STORAGE_POOL_MPATH: + case VIR_STORAGE_POOL_RBD: ++ case VIR_STORAGE_POOL_VITASTOR: + case VIR_STORAGE_POOL_SHEEPDOG: + case VIR_STORAGE_POOL_GLUSTER: + case VIR_STORAGE_POOL_LAST: +diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c +index a4271f1247..621c1b7b31 100644 +--- a/src/conf/domain_validate.c ++++ b/src/conf/domain_validate.c +@@ -508,7 +508,7 @@ virDomainDiskDefValidateSourceChainOne(const virStorageSource *src) + } + } + +- /* internal snapshots and config files are currently supported only with rbd: */ ++ /* internal snapshots are currently supported only with rbd: */ + if (virStorageSourceGetActualType(src) != VIR_STORAGE_TYPE_NETWORK && + src->protocol != VIR_STORAGE_NET_PROTOCOL_RBD) { + if (src->snapshot) { +@@ -517,11 +517,15 @@ virDomainDiskDefValidateSourceChainOne(const virStorageSource *src) + "only with 'rbd' disks")); + return -1; + } +- ++ } ++ /* config files are currently supported only with rbd and vitastor: */ ++ if (virStorageSourceGetActualType(src) != VIR_STORAGE_TYPE_NETWORK && ++ src->protocol != VIR_STORAGE_NET_PROTOCOL_RBD && ++ src->protocol != VIR_STORAGE_NET_PROTOCOL_VITASTOR) { + if (src->configFile) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _(" element is currently supported " +- "only with 'rbd' disks")); ++ "only with 'rbd' and 'vitastor' disks")); + return -1; + } + } +diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c +index 6690d26ffd..2255df9d28 100644 +--- a/src/conf/storage_conf.c ++++ b/src/conf/storage_conf.c +@@ -60,7 +60,7 @@ VIR_ENUM_IMPL(virStoragePool, + "logical", "disk", "iscsi", + "iscsi-direct", "scsi", "mpath", + "rbd", "sheepdog", "gluster", +- "zfs", "vstorage", ++ "zfs", "vstorage", "vitastor", + ); + + VIR_ENUM_IMPL(virStoragePoolFormatFileSystem, +@@ -246,6 +246,18 @@ static virStoragePoolTypeInfo poolTypeInfo[] = { + .formatToString = virStorageFileFormatTypeToString, + } + }, ++ {.poolType = VIR_STORAGE_POOL_VITASTOR, ++ .poolOptions = { ++ .flags = (VIR_STORAGE_POOL_SOURCE_HOST | ++ VIR_STORAGE_POOL_SOURCE_NETWORK | ++ VIR_STORAGE_POOL_SOURCE_NAME), ++ }, ++ .volOptions = { ++ .defaultFormat = VIR_STORAGE_FILE_RAW, ++ .formatFromString = virStorageVolumeFormatFromString, ++ .formatToString = virStorageFileFormatTypeToString, ++ } ++ }, + {.poolType = VIR_STORAGE_POOL_SHEEPDOG, + .poolOptions = { + .flags = (VIR_STORAGE_POOL_SOURCE_HOST | +@@ -546,6 +558,11 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt, + _("element 'name' is mandatory for RBD pool")); + return -1; + } ++ if (pool_type == VIR_STORAGE_POOL_VITASTOR && source->name == NULL) { ++ virReportError(VIR_ERR_XML_ERROR, "%s", ++ _("element 'name' is mandatory for Vitastor pool")); ++ return -1; ++ } + + if (options->formatFromString) { + g_autofree char *format = NULL; +@@ -1176,6 +1193,7 @@ virStoragePoolDefFormatBuf(virBuffer *buf, + /* RBD, Sheepdog, Gluster and Iscsi-direct devices are not local block devs nor + * files, so they don't have a target */ + if (def->type != VIR_STORAGE_POOL_RBD && ++ def->type != VIR_STORAGE_POOL_VITASTOR && + def->type != VIR_STORAGE_POOL_SHEEPDOG && + def->type != VIR_STORAGE_POOL_GLUSTER && + def->type != VIR_STORAGE_POOL_ISCSI_DIRECT) { +diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h +index aaecf138d6..97172db38b 100644 +--- a/src/conf/storage_conf.h ++++ b/src/conf/storage_conf.h +@@ -106,6 +106,7 @@ typedef enum { + VIR_STORAGE_POOL_GLUSTER, /* Gluster device */ + VIR_STORAGE_POOL_ZFS, /* ZFS */ + VIR_STORAGE_POOL_VSTORAGE, /* Virtuozzo Storage */ ++ VIR_STORAGE_POOL_VITASTOR, /* Vitastor */ + + VIR_STORAGE_POOL_LAST, + } virStoragePoolType; +@@ -466,6 +467,7 @@ VIR_ENUM_DECL(virStoragePartedFs); + VIR_CONNECT_LIST_STORAGE_POOLS_SCSI | \ + VIR_CONNECT_LIST_STORAGE_POOLS_MPATH | \ + VIR_CONNECT_LIST_STORAGE_POOLS_RBD | \ ++ VIR_CONNECT_LIST_STORAGE_POOLS_VITASTOR | \ + VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG | \ + VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER | \ + VIR_CONNECT_LIST_STORAGE_POOLS_ZFS | \ +diff --git a/src/conf/storage_source_conf.c b/src/conf/storage_source_conf.c +index d42f715f26..29d8da3d10 100644 +--- a/src/conf/storage_source_conf.c ++++ b/src/conf/storage_source_conf.c +@@ -86,6 +86,7 @@ VIR_ENUM_IMPL(virStorageNetProtocol, + "ssh", + "vxhs", + "nfs", ++ "vitastor", + ); + + +@@ -1265,6 +1266,7 @@ virStorageSourceNetworkDefaultPort(virStorageNetProtocol protocol) + case VIR_STORAGE_NET_PROTOCOL_GLUSTER: + return 24007; + ++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR: + case VIR_STORAGE_NET_PROTOCOL_RBD: + /* we don't provide a default for RBD */ + return 0; +diff --git a/src/conf/storage_source_conf.h b/src/conf/storage_source_conf.h +index c4a026881c..67568e9181 100644 +--- a/src/conf/storage_source_conf.h ++++ b/src/conf/storage_source_conf.h +@@ -128,6 +128,7 @@ typedef enum { + VIR_STORAGE_NET_PROTOCOL_SSH, + VIR_STORAGE_NET_PROTOCOL_VXHS, + VIR_STORAGE_NET_PROTOCOL_NFS, ++ VIR_STORAGE_NET_PROTOCOL_VITASTOR, + + VIR_STORAGE_NET_PROTOCOL_LAST + } virStorageNetProtocol; +diff --git a/src/conf/virstorageobj.c b/src/conf/virstorageobj.c +index 02903ac487..504df599fb 100644 +--- a/src/conf/virstorageobj.c ++++ b/src/conf/virstorageobj.c +@@ -1481,6 +1481,7 @@ virStoragePoolObjSourceFindDuplicateCb(const void *payload, + return 1; + break; + ++ case VIR_STORAGE_POOL_VITASTOR: + case VIR_STORAGE_POOL_RBD: + case VIR_STORAGE_POOL_LAST: + break; +@@ -1978,6 +1979,8 @@ virStoragePoolObjMatch(virStoragePoolObj *obj, + (obj->def->type == VIR_STORAGE_POOL_MPATH)) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_RBD) && + (obj->def->type == VIR_STORAGE_POOL_RBD)) || ++ (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_VITASTOR) && ++ (obj->def->type == VIR_STORAGE_POOL_VITASTOR)) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG) && + (obj->def->type == VIR_STORAGE_POOL_SHEEPDOG)) || + (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER) && +diff --git a/src/libvirt-storage.c b/src/libvirt-storage.c +index cbc522b300..b4760fa58d 100644 +--- a/src/libvirt-storage.c ++++ b/src/libvirt-storage.c +@@ -92,6 +92,7 @@ virStoragePoolGetConnect(virStoragePoolPtr pool) + * VIR_CONNECT_LIST_STORAGE_POOLS_SCSI + * VIR_CONNECT_LIST_STORAGE_POOLS_MPATH + * VIR_CONNECT_LIST_STORAGE_POOLS_RBD ++ * VIR_CONNECT_LIST_STORAGE_POOLS_VITASTOR + * VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG + * VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER + * VIR_CONNECT_LIST_STORAGE_POOLS_ZFS +diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c +index 1ac6253ad7..abe4587f94 100644 +--- a/src/libxl/libxl_conf.c ++++ b/src/libxl/libxl_conf.c +@@ -962,6 +962,7 @@ libxlMakeNetworkDiskSrcStr(virStorageSource *src, + case VIR_STORAGE_NET_PROTOCOL_SSH: + case VIR_STORAGE_NET_PROTOCOL_VXHS: + case VIR_STORAGE_NET_PROTOCOL_NFS: ++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR: + case VIR_STORAGE_NET_PROTOCOL_LAST: + case VIR_STORAGE_NET_PROTOCOL_NONE: + virReportError(VIR_ERR_NO_SUPPORT, +diff --git a/src/libxl/xen_xl.c b/src/libxl/xen_xl.c +index 7604e3d534..6453bb9776 100644 +--- a/src/libxl/xen_xl.c ++++ b/src/libxl/xen_xl.c +@@ -1506,6 +1506,7 @@ xenFormatXLDiskSrcNet(virStorageSource *src) + case VIR_STORAGE_NET_PROTOCOL_SSH: + case VIR_STORAGE_NET_PROTOCOL_VXHS: + case VIR_STORAGE_NET_PROTOCOL_NFS: ++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR: + case VIR_STORAGE_NET_PROTOCOL_LAST: + case VIR_STORAGE_NET_PROTOCOL_NONE: + virReportError(VIR_ERR_NO_SUPPORT, +diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c +index e5ff653a60..884ecc79ea 100644 +--- a/src/qemu/qemu_block.c ++++ b/src/qemu/qemu_block.c +@@ -943,6 +943,38 @@ qemuBlockStorageSourceGetRBDProps(virStorageSource *src, + } + + ++static virJSONValue * ++qemuBlockStorageSourceGetVitastorProps(virStorageSource *src) ++{ ++ virJSONValue *ret = NULL; ++ virStorageNetHostDef *host; ++ size_t i; ++ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER; ++ g_autofree char *etcd = NULL; ++ ++ for (i = 0; i < src->nhosts; i++) { ++ host = src->hosts + i; ++ if ((virStorageNetHostTransport)host->transport != VIR_STORAGE_NET_HOST_TRANS_TCP) { ++ return NULL; ++ } ++ virBufferAsprintf(&buf, i > 0 ? ",%s:%u" : "%s:%u", host->name, host->port); ++ } ++ if (src->nhosts > 0) { ++ etcd = virBufferContentAndReset(&buf); ++ } ++ ++ if (virJSONValueObjectCreate(&ret, ++ "S:etcd-host", etcd, ++ "S:etcd-prefix", src->query, ++ "S:config-path", src->configFile, ++ "s:image", src->path, ++ NULL) < 0) ++ return NULL; ++ ++ return ret; ++} ++ ++ + static virJSONValue * + qemuBlockStorageSourceGetSheepdogProps(virStorageSource *src) + { +@@ -1233,6 +1265,12 @@ qemuBlockStorageSourceGetBackendProps(virStorageSource *src, + return NULL; + break; + ++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR: ++ driver = "vitastor"; ++ if (!(fileprops = qemuBlockStorageSourceGetVitastorProps(src))) ++ return NULL; ++ break; ++ + case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG: + driver = "sheepdog"; + if (!(fileprops = qemuBlockStorageSourceGetSheepdogProps(src))) +@@ -2244,6 +2282,7 @@ qemuBlockGetBackingStoreString(virStorageSource *src, + + case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG: + case VIR_STORAGE_NET_PROTOCOL_RBD: ++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR: + case VIR_STORAGE_NET_PROTOCOL_VXHS: + case VIR_STORAGE_NET_PROTOCOL_NFS: + case VIR_STORAGE_NET_PROTOCOL_SSH: +@@ -2626,6 +2665,12 @@ qemuBlockStorageSourceCreateGetStorageProps(virStorageSource *src, + return -1; + break; + ++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR: ++ driver = "vitastor"; ++ if (!(location = qemuBlockStorageSourceGetVitastorProps(src))) ++ return -1; ++ break; ++ + case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG: + driver = "sheepdog"; + if (!(location = qemuBlockStorageSourceGetSheepdogProps(src))) +diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c +index d822533ccb..afe2087303 100644 +--- a/src/qemu/qemu_command.c ++++ b/src/qemu/qemu_command.c +@@ -1723,6 +1723,43 @@ qemuBuildNetworkDriveStr(virStorageSource *src, + ret = virBufferContentAndReset(&buf); + break; + ++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR: ++ if (strchr(src->path, ':')) { ++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, ++ _("':' not allowed in Vitastor source volume name '%s'"), ++ src->path); ++ return NULL; ++ } ++ ++ virBufferStrcat(&buf, "vitastor:image=", src->path, NULL); ++ ++ if (src->nhosts > 0) { ++ virBufferAddLit(&buf, ":etcd-host="); ++ for (i = 0; i < src->nhosts; i++) { ++ if (i) ++ virBufferAddLit(&buf, ","); ++ ++ /* assume host containing : is ipv6 */ ++ if (strchr(src->hosts[i].name, ':')) ++ virBufferEscape(&buf, '\\', ":", "[%s]", ++ src->hosts[i].name); ++ else ++ virBufferAsprintf(&buf, "%s", src->hosts[i].name); ++ ++ if (src->hosts[i].port) ++ virBufferAsprintf(&buf, "\\:%u", src->hosts[i].port); ++ } ++ } ++ ++ if (src->configFile) ++ virBufferEscape(&buf, '\\', ":", ":config-path=%s", src->configFile); ++ ++ if (src->query) ++ virBufferEscape(&buf, '\\', ":", ":etcd-prefix=%s", src->query); ++ ++ ret = virBufferContentAndReset(&buf); ++ break; ++ + case VIR_STORAGE_NET_PROTOCOL_VXHS: + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("VxHS protocol does not support URI syntax")); +diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c +index a8401bac30..3dc1fe6db0 100644 +--- a/src/qemu/qemu_domain.c ++++ b/src/qemu/qemu_domain.c +@@ -4731,7 +4731,8 @@ qemuDomainValidateStorageSource(virStorageSource *src, + if (src->query && + (actualType != VIR_STORAGE_TYPE_NETWORK || + (src->protocol != VIR_STORAGE_NET_PROTOCOL_HTTPS && +- src->protocol != VIR_STORAGE_NET_PROTOCOL_HTTP))) { ++ src->protocol != VIR_STORAGE_NET_PROTOCOL_HTTP && ++ src->protocol != VIR_STORAGE_NET_PROTOCOL_VITASTOR))) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("query is supported only with HTTP(S) protocols")); + return -1; +@@ -9919,6 +9920,7 @@ qemuDomainPrepareStorageSourceTLS(virStorageSource *src, + break; + + case VIR_STORAGE_NET_PROTOCOL_RBD: ++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR: + case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG: + case VIR_STORAGE_NET_PROTOCOL_GLUSTER: + case VIR_STORAGE_NET_PROTOCOL_ISCSI: +diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c +index f92e00f9c0..854a3fbc90 100644 +--- a/src/qemu/qemu_snapshot.c ++++ b/src/qemu/qemu_snapshot.c +@@ -393,6 +393,7 @@ qemuSnapshotPrepareDiskExternalInactive(virDomainSnapshotDiskDef *snapdisk, + case VIR_STORAGE_NET_PROTOCOL_NONE: + case VIR_STORAGE_NET_PROTOCOL_NBD: + case VIR_STORAGE_NET_PROTOCOL_RBD: ++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR: + case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG: + case VIR_STORAGE_NET_PROTOCOL_GLUSTER: + case VIR_STORAGE_NET_PROTOCOL_ISCSI: +@@ -485,6 +486,7 @@ qemuSnapshotPrepareDiskExternalActive(virDomainObj *vm, + case VIR_STORAGE_NET_PROTOCOL_NONE: + case VIR_STORAGE_NET_PROTOCOL_NBD: + case VIR_STORAGE_NET_PROTOCOL_RBD: ++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR: + case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG: + case VIR_STORAGE_NET_PROTOCOL_ISCSI: + case VIR_STORAGE_NET_PROTOCOL_HTTP: +@@ -638,6 +640,7 @@ qemuSnapshotPrepareDiskInternal(virDomainDiskDef *disk, + case VIR_STORAGE_NET_PROTOCOL_NONE: + case VIR_STORAGE_NET_PROTOCOL_NBD: + case VIR_STORAGE_NET_PROTOCOL_RBD: ++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR: + case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG: + case VIR_STORAGE_NET_PROTOCOL_GLUSTER: + case VIR_STORAGE_NET_PROTOCOL_ISCSI: +diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c +index 4df2c75a2b..5a5e48ef71 100644 +--- a/src/storage/storage_driver.c ++++ b/src/storage/storage_driver.c +@@ -1643,6 +1643,7 @@ storageVolLookupByPathCallback(virStoragePoolObj *obj, + + case VIR_STORAGE_POOL_GLUSTER: + case VIR_STORAGE_POOL_RBD: ++ case VIR_STORAGE_POOL_VITASTOR: + case VIR_STORAGE_POOL_SHEEPDOG: + case VIR_STORAGE_POOL_ZFS: + case VIR_STORAGE_POOL_LAST: +diff --git a/src/storage_file/storage_source_backingstore.c b/src/storage_file/storage_source_backingstore.c +index e48ae725ab..2017ccc88c 100644 +--- a/src/storage_file/storage_source_backingstore.c ++++ b/src/storage_file/storage_source_backingstore.c +@@ -284,6 +284,75 @@ virStorageSourceParseRBDColonString(const char *rbdstr, + } + + ++static int ++virStorageSourceParseVitastorColonString(const char *colonstr, ++ virStorageSource *src) ++{ ++ char *p, *e, *next; ++ g_autofree char *options = NULL; ++ ++ /* optionally skip the "vitastor:" prefix if provided */ ++ if (STRPREFIX(colonstr, "vitastor:")) ++ colonstr += strlen("vitastor:"); ++ ++ options = g_strdup(colonstr); ++ ++ p = options; ++ while (*p) { ++ /* find : delimiter or end of string */ ++ for (e = p; *e && *e != ':'; ++e) { ++ if (*e == '\\') { ++ e++; ++ if (*e == '\0') ++ break; ++ } ++ } ++ if (*e == '\0') { ++ next = e; /* last kv pair */ ++ } else { ++ next = e + 1; ++ *e = '\0'; ++ } ++ ++ if (STRPREFIX(p, "image=")) { ++ src->path = g_strdup(p + strlen("image=")); ++ } else if (STRPREFIX(p, "etcd-prefix=")) { ++ src->query = g_strdup(p + strlen("etcd-prefix=")); ++ } else if (STRPREFIX(p, "config-path=")) { ++ src->configFile = g_strdup(p + strlen("config-path=")); ++ } else if (STRPREFIX(p, "etcd-host=")) { ++ char *h, *sep; ++ ++ h = p + strlen("etcd-host="); ++ while (h < e) { ++ for (sep = h; sep < e; ++sep) { ++ if (*sep == '\\' && (sep[1] == ',' || ++ sep[1] == ';' || ++ sep[1] == ' ')) { ++ *sep = '\0'; ++ sep += 2; ++ break; ++ } ++ } ++ ++ if (virStorageSourceRBDAddHost(src, h) < 0) ++ return -1; ++ ++ h = sep; ++ } ++ } ++ ++ p = next; ++ } ++ ++ if (!src->path) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ + static int + virStorageSourceParseNBDColonString(const char *nbdstr, + virStorageSource *src) +@@ -396,6 +465,11 @@ virStorageSourceParseBackingColon(virStorageSource *src, + return -1; + break; + ++ case VIR_STORAGE_NET_PROTOCOL_VITASTOR: ++ if (virStorageSourceParseVitastorColonString(path, src) < 0) ++ return -1; ++ break; ++ + case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG: + case VIR_STORAGE_NET_PROTOCOL_LAST: + case VIR_STORAGE_NET_PROTOCOL_NONE: +@@ -984,6 +1058,54 @@ virStorageSourceParseBackingJSONRBD(virStorageSource *src, + return 0; + } + ++static int ++virStorageSourceParseBackingJSONVitastor(virStorageSource *src, ++ virJSONValue *json, ++ const char *jsonstr G_GNUC_UNUSED, ++ int opaque G_GNUC_UNUSED) ++{ ++ const char *filename; ++ const char *image = virJSONValueObjectGetString(json, "image"); ++ const char *conf = virJSONValueObjectGetString(json, "config-path"); ++ const char *etcd_prefix = virJSONValueObjectGetString(json, "etcd-prefix"); ++ virJSONValue *servers = virJSONValueObjectGetArray(json, "server"); ++ size_t nservers; ++ size_t i; ++ ++ src->type = VIR_STORAGE_TYPE_NETWORK; ++ src->protocol = VIR_STORAGE_NET_PROTOCOL_VITASTOR; ++ ++ /* legacy syntax passed via 'filename' option */ ++ if ((filename = virJSONValueObjectGetString(json, "filename"))) ++ return virStorageSourceParseVitastorColonString(filename, src); ++ ++ if (!image) { ++ virReportError(VIR_ERR_INVALID_ARG, "%s", ++ _("missing image name in Vitastor backing volume " ++ "JSON specification")); ++ return -1; ++ } ++ ++ src->path = g_strdup(image); ++ src->configFile = g_strdup(conf); ++ src->query = g_strdup(etcd_prefix); ++ ++ if (servers) { ++ nservers = virJSONValueArraySize(servers); ++ ++ src->hosts = g_new0(virStorageNetHostDef, nservers); ++ src->nhosts = nservers; ++ ++ for (i = 0; i < nservers; i++) { ++ if (virStorageSourceParseBackingJSONInetSocketAddress(src->hosts + i, ++ virJSONValueArrayGet(servers, i)) < 0) ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ + static int + virStorageSourceParseBackingJSONRaw(virStorageSource *src, + virJSONValue *json, +@@ -1162,6 +1284,7 @@ static const struct virStorageSourceJSONDriverParser jsonParsers[] = { + {"sheepdog", false, virStorageSourceParseBackingJSONSheepdog, 0}, + {"ssh", false, virStorageSourceParseBackingJSONSSH, 0}, + {"rbd", false, virStorageSourceParseBackingJSONRBD, 0}, ++ {"vitastor", false, virStorageSourceParseBackingJSONVitastor, 0}, + {"raw", true, virStorageSourceParseBackingJSONRaw, 0}, + {"nfs", false, virStorageSourceParseBackingJSONNFS, 0}, + {"vxhs", false, virStorageSourceParseBackingJSONVxHS, 0}, +diff --git a/src/test/test_driver.c b/src/test/test_driver.c +index 0e93b79922..b4d33f5f56 100644 +--- a/src/test/test_driver.c ++++ b/src/test/test_driver.c +@@ -7367,6 +7367,7 @@ testStorageVolumeTypeForPool(int pooltype) + case VIR_STORAGE_POOL_ISCSI_DIRECT: + case VIR_STORAGE_POOL_GLUSTER: + case VIR_STORAGE_POOL_RBD: ++ case VIR_STORAGE_POOL_VITASTOR: + return VIR_STORAGE_VOL_NETWORK; + case VIR_STORAGE_POOL_LOGICAL: + case VIR_STORAGE_POOL_DISK: +diff --git a/tests/storagepoolcapsschemadata/poolcaps-fs.xml b/tests/storagepoolcapsschemadata/poolcaps-fs.xml +index eee75af746..8bd0a57bdd 100644 +--- a/tests/storagepoolcapsschemadata/poolcaps-fs.xml ++++ b/tests/storagepoolcapsschemadata/poolcaps-fs.xml +@@ -204,4 +204,11 @@ + + + ++ ++ ++ ++ ++ ++ ++ + +diff --git a/tests/storagepoolcapsschemadata/poolcaps-full.xml b/tests/storagepoolcapsschemadata/poolcaps-full.xml +index 805950a937..852df0de16 100644 +--- a/tests/storagepoolcapsschemadata/poolcaps-full.xml ++++ b/tests/storagepoolcapsschemadata/poolcaps-full.xml +@@ -204,4 +204,11 @@ + + + ++ ++ ++ ++ ++ ++ ++ + +diff --git a/tests/storagepoolxml2argvtest.c b/tests/storagepoolxml2argvtest.c +index 449b745519..7f95cc8e08 100644 +--- a/tests/storagepoolxml2argvtest.c ++++ b/tests/storagepoolxml2argvtest.c +@@ -68,6 +68,7 @@ testCompareXMLToArgvFiles(bool shouldFail, + case VIR_STORAGE_POOL_GLUSTER: + case VIR_STORAGE_POOL_ZFS: + case VIR_STORAGE_POOL_VSTORAGE: ++ case VIR_STORAGE_POOL_VITASTOR: + case VIR_STORAGE_POOL_LAST: + default: + VIR_TEST_DEBUG("pool type '%s' has no xml2argv test", defTypeStr); +diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c +index d391257f6e..46799c4a90 100644 +--- a/tools/virsh-pool.c ++++ b/tools/virsh-pool.c +@@ -1213,6 +1213,9 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED) + case VIR_STORAGE_POOL_VSTORAGE: + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_VSTORAGE; + break; ++ case VIR_STORAGE_POOL_VITASTOR: ++ flags |= VIR_CONNECT_LIST_STORAGE_POOLS_VITASTOR; ++ break; + case VIR_STORAGE_POOL_LAST: + break; + }