This patch brings support to manage sheepdog pools and volumes to libvirt. It uses the "collie" command-line utility that comes with sheepdog for that. A sheepdog pool in libvirt maps to a sheepdog cluster. It needs a host and port to connect to, which in most cases is just going to be the default of localhost on port 7000. A sheepdog volume in libvirt maps to a sheepdog vdi. To create one specify the pool, a name and the capacity. Volumes can also be resized later. In the volume XML the vdi name has to be put into the <target><path>. To use the volume as a disk source for virtual machines specify the vdi name as "name" attribute of the <source>. The host and port information from the pool are specified inside the host tag. <disk type='network'> ... <source protocol="sheepdog" name="vdi_name"> <host name="localhost" port="7000"/> </source> </disk> To work right this patch parses the output of collie, so it relies on the raw output option. There recently was a bug which caused size information to be reported wrong. This is fixed upstream already and will be in the next release. Signed-off-by: Sebastian Wiedenroth <wiedi@xxxxxxxxxx> --- .gitignore | 1 + configure.ac | 32 +++ docs/drivers.html.in | 1 + docs/schemas/storagepool.rng | 17 ++ docs/schemas/storagevol.rng | 3 +- docs/storage.html.in | 62 +++++ libvirt.spec.in | 35 ++- po/POTFILES.in | 1 + src/Makefile.am | 8 + src/conf/storage_conf.c | 19 +- src/conf/storage_conf.h | 1 + src/storage/storage_backend.c | 6 + src/storage/storage_backend_sheepdog.c | 311 +++++++++++++++++++++++++ src/storage/storage_backend_sheepdog.h | 39 ++++ tests/Makefile.am | 13 ++ tests/storagebackendsheepdogtest.c | 214 +++++++++++++++++ tests/storagepoolxml2xmlin/pool-sheepdog.xml | 8 + tests/storagepoolxml2xmlout/pool-sheepdog.xml | 11 + tests/storagepoolxml2xmltest.c | 1 + tests/storagevolxml2xmlin/vol-sheepdog.xml | 10 + tests/storagevolxml2xmlout/vol-sheepdog.xml | 17 ++ tests/storagevolxml2xmltest.c | 1 + tools/virsh.c | 3 + 23 files changed, 799 insertions(+), 15 deletions(-) create mode 100644 src/storage/storage_backend_sheepdog.c create mode 100644 src/storage/storage_backend_sheepdog.h create mode 100644 tests/storagebackendsheepdogtest.c create mode 100644 tests/storagepoolxml2xmlin/pool-sheepdog.xml create mode 100644 tests/storagepoolxml2xmlout/pool-sheepdog.xml create mode 100644 tests/storagevolxml2xmlin/vol-sheepdog.xml create mode 100644 tests/storagevolxml2xmlout/vol-sheepdog.xml diff --git a/.gitignore b/.gitignore index cd978d2..098ba09 100644 --- a/.gitignore +++ b/.gitignore @@ -145,6 +145,7 @@ /tests/sockettest /tests/ssh /tests/statstest +/tests/storagebackendsheepdogtest /tests/utiltest /tests/virauthconfigtest /tests/virbuftest diff --git a/configure.ac b/configure.ac index c0ef9b1..13aa0e4 100644 --- a/configure.ac +++ b/configure.ac @@ -1825,6 +1825,8 @@ AC_ARG_WITH([storage-disk], AC_HELP_STRING([--with-storage-disk], [with GPartd Disk backend for the storage driver @<:@default=check@:>@]),[],[with_storage_disk=check]) AC_ARG_WITH([storage-rbd], AC_HELP_STRING([--with-storage-rbd], [with RADOS Block Device backend for the storage driver @<:@default=check@:>@]),[],[with_storage_rbd=check]) +AC_ARG_WITH([storage-sheepdog], + AC_HELP_STRING([--with-storage-sheepdog], [with Sheepdog backend for the storage driver @<:@default=check@:>@]),[],[with_storage_sheepdog=check]) if test "$with_libvirtd" = "no"; then with_storage_dir=no @@ -1835,6 +1837,7 @@ if test "$with_libvirtd" = "no"; then with_storage_mpath=no with_storage_disk=no with_storage_rbd=no + with_storage_sheepdog=no fi if test "$with_storage_dir" = "yes" ; then AC_DEFINE_UNQUOTED([WITH_STORAGE_DIR], 1, [whether directory backend for storage driver is enabled]) @@ -2009,6 +2012,34 @@ fi AM_CONDITIONAL([WITH_STORAGE_RBD], [test "$with_storage_rbd" = "yes"]) AC_SUBST([LIBRBD_LIBS]) +if test "$with_storage_sheepdog" = "yes" || + test "$with_storage_sheepdog" = "check"; then + AC_PATH_PROG([COLLIE], [collie], [], [$PATH:/sbin:/usr/sbin]) + + if test "$with_storage_sheepdog" = "yes"; then + if test -z "$COLLIE"; then + AC_MSG_ERROR([We need collie for Sheepdog storage driver]) + fi + else + if test -z "$COLLIE"; then + with_storage_sheepdog=no + fi + + if test "$with_storage_sheepdog" = "check"; then + with_storage_sheepdog=yes + fi + fi + + if test "$with_storage_sheepdog" = "yes"; then + AC_DEFINE_UNQUOTED([WITH_STORAGE_SHEEPDOG], 1, + [whether Sheepdog backend for storage driver is enabled]) + AC_DEFINE_UNQUOTED([COLLIE],["$COLLIE"],[Location of collie program]) + fi +fi +AM_CONDITIONAL([WITH_STORAGE_SHEEPDOG], + [test "$with_storage_sheepdog" = "yes"]) + + LIBPARTED_CFLAGS= LIBPARTED_LIBS= if test "$with_storage_disk" = "yes" || @@ -2824,6 +2855,7 @@ AC_MSG_NOTICE([ SCSI: $with_storage_scsi]) AC_MSG_NOTICE([ mpath: $with_storage_mpath]) AC_MSG_NOTICE([ Disk: $with_storage_disk]) AC_MSG_NOTICE([ RBD: $with_storage_rbd]) +AC_MSG_NOTICE([Sheepdog: $with_storage_sheepdog]) AC_MSG_NOTICE([]) AC_MSG_NOTICE([Security Drivers]) AC_MSG_NOTICE([]) diff --git a/docs/drivers.html.in b/docs/drivers.html.in index 8ad2c33..90b6196 100644 --- a/docs/drivers.html.in +++ b/docs/drivers.html.in @@ -43,6 +43,7 @@ <li><strong><a href="storage.html#StorageBackendSCSI">SCSI backend</a></strong></li> <li><strong><a href="storage.html#StorageBackendMultipath">Multipath backend</a></strong></li> <li><strong><a href="storage.html#StorageBackendRBD">RBD (RADOS Block Device) backend</a></strong></li> + <li><strong><a href="storage.html#StorageBackendSheepdog">Sheepdog backend</a></strong></li> </ul> </body> </html> diff --git a/docs/schemas/storagepool.rng b/docs/schemas/storagepool.rng index 75b6b51..039798a 100644 --- a/docs/schemas/storagepool.rng +++ b/docs/schemas/storagepool.rng @@ -20,6 +20,7 @@ <ref name='poolscsi'/> <ref name='poolmpath'/> <ref name='poolrbd'/> + <ref name='poolsheepdog'/> </choice> </element> </define> @@ -115,6 +116,15 @@ <ref name='sourcerbd'/> </define> + <define name='poolsheepdog'> + <attribute name='type'> + <value>sheepdog</value> + </attribute> + <ref name='commonmetadata'/> + <ref name='sizing'/> + <ref name='sourcesheepdog'/> + </define> + <define name='sourceinfovendor'> <optional> <element name='vendor'> @@ -496,6 +506,13 @@ </element> </define> + <define name='sourcesheepdog'> + <element name='source'> + <ref name='sourceinfohost'/> + <ref name='sourceinfoname'/> + </element> + </define> + <define name='name'> <data type='string'> <param name="pattern">[a-zA-Z0-9_\+\-]+</param> diff --git a/docs/schemas/storagevol.rng b/docs/schemas/storagevol.rng index 7a74331..0b9933d 100644 --- a/docs/schemas/storagevol.rng +++ b/docs/schemas/storagevol.rng @@ -67,7 +67,7 @@ <element name='target'> <optional> <element name='path'> - <ref name='absFilePath'/> + <data type='anyURI'/> </element> </optional> <ref name='format'/> @@ -144,6 +144,7 @@ <define name='formatfile'> <choice> + <value>unknown</value> <value>raw</value> <value>dir</value> <value>bochs</value> diff --git a/docs/storage.html.in b/docs/storage.html.in index b3484e8..26a949a 100644 --- a/docs/storage.html.in +++ b/docs/storage.html.in @@ -110,6 +110,9 @@ <li> <a href="#StorageBackendRBD">RBD (RADOS Block Device) backend</a> </li> + <li> + <a href="#StorageBackendSheepdog">Sheepdog backend</a> + </li> </ul> <h2><a name="StorageBackendDir">Directory pool</a></h2> @@ -565,5 +568,64 @@ The RBD pool does not use the volume format type element. </p> + <h2><a name="StorageBackendSheepdog">Sheepdog pools</a></h2> + <p> + This provides a pool based on a Sheepdog Cluster. + Sheepdog is a distributed storage system for QEMU/KVM. + It provides highly available block level storage volumes that + can be attached to QEMU/KVM virtual machines. + + The cluster must already be formatted. + + <span class="since">Since 0.9.13</span> + </p> + + <h3>Example pool input</h3> + <pre> + <pool type="sheepdog"> + <name>mysheeppool</name> + <source> + <name>mysheeppool</name> + <host name='localhost' port='7000'/> + </source> + </pool></pre> + + <h3>Example volume output</h3> + <pre> + <volume> + <name>myvol</name> + <key>sheep/myvol</key> + <source> + </source> + <capacity unit='bytes'>53687091200</capacity> + <allocation unit='bytes'>53687091200</allocation> + <target> + <path>sheepdog:myvol</path> + <format type='unknown'/> + <permissions> + <mode>00</mode> + <owner>0</owner> + <group>0</group> + </permissions> + </target> + </volume></pre> + + <h3>Example disk attachment</h3> + <p>Sheepdog images can be attached to Qemu guests. + Information about attaching a Sheepdog image to a + guest can be found + at the <a href="formatdomain.html#elementsDisks">format domain</a> + page.</p> + + <h3>Valid pool format types</h3> + <p> + The Sheepdog pool does not use the pool format type element. + </p> + + <h3>Valid volume format types</h3> + <p> + The Sheepdog pool does not use the volume format type element. + </p> + </body> </html> diff --git a/libvirt.spec.in b/libvirt.spec.in index 896ef51..e80259e 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -69,19 +69,24 @@ %define with_xenapi 0%{!?_without_xenapi:1} # Then the secondary host drivers, which run inside libvirtd -%define with_network 0%{!?_without_network:%{server_drivers}} -%define with_storage_fs 0%{!?_without_storage_fs:%{server_drivers}} -%define with_storage_lvm 0%{!?_without_storage_lvm:%{server_drivers}} -%define with_storage_iscsi 0%{!?_without_storage_iscsi:%{server_drivers}} -%define with_storage_disk 0%{!?_without_storage_disk:%{server_drivers}} -%define with_storage_mpath 0%{!?_without_storage_mpath:%{server_drivers}} +%define with_network 0%{!?_without_network:%{server_drivers}} +%define with_storage_fs 0%{!?_without_storage_fs:%{server_drivers}} +%define with_storage_lvm 0%{!?_without_storage_lvm:%{server_drivers}} +%define with_storage_iscsi 0%{!?_without_storage_iscsi:%{server_drivers}} +%define with_storage_disk 0%{!?_without_storage_disk:%{server_drivers}} +%define with_storage_mpath 0%{!?_without_storage_mpath:%{server_drivers}} %if 0%{?fedora} >= 16 -%define with_storage_rbd 0%{!?_without_storage_rbd:%{server_drivers}} +%define with_storage_rbd 0%{!?_without_storage_rbd:%{server_drivers}} %else -%define with_storage_rbd 0 +%define with_storage_rbd 0 %endif -%define with_numactl 0%{!?_without_numactl:%{server_drivers}} -%define with_selinux 0%{!?_without_selinux:%{server_drivers}} +%if 0%{?fedora} >= 17 +%define with_storage_sheepdog 0%{!?_without_storage_sheepdog:%{server_drivers}} +%else +%define with_storage_sheepdog 0 +%endif +%define with_numactl 0%{!?_without_numactl:%{server_drivers}} +%define with_selinux 0%{!?_without_selinux:%{server_drivers}} # A few optional bits off by default, we enable later %define with_polkit 0%{!?_without_polkit:0} @@ -224,6 +229,7 @@ %define with_storage_iscsi 0 %define with_storage_mpath 0 %define with_storage_rbd 0 +%define with_storage_sheepdog 0 %define with_storage_disk 0 %endif @@ -603,6 +609,10 @@ Requires: device-mapper # For RBD support Requires: ceph %endif +%if %{with_storage_sheepdog} +# For Sheepdog support +Requires: sheepdog +%endif %if %{with_cgconfig} Requires: libcgroup %endif @@ -1080,6 +1090,10 @@ of recent versions of Linux (and other OSes). %define _without_storage_rbd --without-storage-rbd %endif +%if ! %{with_storage_sheepdog} +%define _without_storage_sheepdog --without-storage-sheepdog +%endif + %if ! %{with_numactl} %define _without_numactl --without-numactl %endif @@ -1178,6 +1192,7 @@ autoreconf -if %{?_without_storage_disk} \ %{?_without_storage_mpath} \ %{?_without_storage_rbd} \ + %{?_without_storage_sheepdog} \ %{?_without_numactl} \ %{?_without_numad} \ %{?_without_capng} \ diff --git a/po/POTFILES.in b/po/POTFILES.in index 31246f7..33a2ace 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -108,6 +108,7 @@ src/storage/storage_backend_logical.c src/storage/storage_backend_mpath.c src/storage/storage_backend_rbd.c src/storage/storage_backend_scsi.c +src/storage/storage_backend_sheepdog.c src/storage/storage_driver.c src/test/test_driver.c src/uml/uml_conf.c diff --git a/src/Makefile.am b/src/Makefile.am index 2309984..7effcd6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -515,6 +515,9 @@ STORAGE_DRIVER_DISK_SOURCES = \ STORAGE_DRIVER_RBD_SOURCES = \ storage/storage_backend_rbd.h storage/storage_backend_rbd.c +STORAGE_DRIVER_SHEEPDOG_SOURCES = \ + storage/storage_backend_sheepdog.h storage/storage_backend_sheepdog.c + STORAGE_HELPER_DISK_SOURCES = \ storage/parthelper.c @@ -1019,6 +1022,10 @@ libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_RBD_SOURCES) libvirt_driver_storage_la_LIBADD += $(LIBRBD_LIBS) endif +if WITH_STORAGE_SHEEPDOG +libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_SHEEPDOG_SOURCES) +endif + if WITH_NODE_DEVICES # Needed to keep automake quiet about conditionals if WITH_DRIVER_MODULES @@ -1117,6 +1124,7 @@ EXTRA_DIST += \ $(STORAGE_DRIVER_MPATH_SOURCES) \ $(STORAGE_DRIVER_DISK_SOURCES) \ $(STORAGE_DRIVER_RBD_SOURCES) \ + $(STORAGE_DRIVER_SHEEPDOG_SOURCES) \ $(NODE_DEVICE_DRIVER_SOURCES) \ $(NODE_DEVICE_DRIVER_HAL_SOURCES) \ $(NODE_DEVICE_DRIVER_UDEV_SOURCES) \ diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index bf4567f..cd17db6 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -52,7 +52,7 @@ VIR_ENUM_IMPL(virStoragePool, VIR_STORAGE_POOL_LAST, "dir", "fs", "netfs", "logical", "disk", "iscsi", - "scsi", "mpath", "rbd") + "scsi", "mpath", "rbd", "sheepdog") VIR_ENUM_IMPL(virStoragePoolFormatFileSystem, VIR_STORAGE_POOL_FS_LAST, @@ -206,6 +206,17 @@ static virStoragePoolTypeInfo poolTypeInfo[] = { .formatToString = virStoragePoolFormatDiskTypeToString, } }, + { .poolType = VIR_STORAGE_POOL_SHEEPDOG, + .poolOptions = { + .flags = (VIR_STORAGE_POOL_SOURCE_HOST | + VIR_STORAGE_POOL_SOURCE_NETWORK | + VIR_STORAGE_POOL_SOURCE_NAME), + }, + .volOptions = { + .defaultFormat = VIR_STORAGE_FILE_RAW, + .formatToString = virStoragePoolFormatDiskTypeToString, + } + }, { .poolType = VIR_STORAGE_POOL_MPATH, .volOptions = { .formatToString = virStoragePoolFormatDiskTypeToString, @@ -1011,9 +1022,9 @@ virStoragePoolDefFormat(virStoragePoolDefPtr def) { if (virStoragePoolSourceFormat(&buf, options, &def->source) < 0) goto cleanup; - /* RBD devices are not local block devs nor files, so it doesn't + /* RBD and Sheepdog devices are not local block devs nor files, so it doesn't * have a target */ - if (def->type != VIR_STORAGE_POOL_RBD) { + if (def->type != VIR_STORAGE_POOL_RBD && def->type != VIR_STORAGE_POOL_SHEEPDOG) { virBufferAddLit(&buf," <target>\n"); if (def->target.path) @@ -1296,7 +1307,7 @@ virStorageVolDefFormat(virStoragePoolDefPtr pool, virBufferAddLit(&buf, "<volume>\n"); virBufferAsprintf(&buf," <name>%s</name>\n", def->name); - virBufferAsprintf(&buf," <key>%s</key>\n", def->key); + virBufferAsprintf(&buf," <key>%s</key>\n", def->key ? def->key : "(null)"); virBufferAddLit(&buf, " <source>\n"); if (def->source.nextent) { diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index 5733b57..dcf976f 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -121,6 +121,7 @@ enum virStoragePoolType { VIR_STORAGE_POOL_SCSI, /* SCSI HBA */ VIR_STORAGE_POOL_MPATH, /* Multipath devices */ VIR_STORAGE_POOL_RBD, /* RADOS Block Device */ + VIR_STORAGE_POOL_SHEEPDOG, /* Sheepdog device */ VIR_STORAGE_POOL_LAST, }; diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index e2e9b51..93964d6 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -80,6 +80,9 @@ #if WITH_STORAGE_RBD # include "storage_backend_rbd.h" #endif +#if WITH_STORAGE_SHEEPDOG +# include "storage_backend_sheepdog.h" +#endif #define VIR_FROM_THIS VIR_FROM_STORAGE @@ -109,6 +112,9 @@ static virStorageBackendPtr backends[] = { #if WITH_STORAGE_RBD &virStorageBackendRBD, #endif +#if WITH_STORAGE_SHEEPDOG + &virStorageBackendSheepdog, +#endif NULL }; diff --git a/src/storage/storage_backend_sheepdog.c b/src/storage/storage_backend_sheepdog.c new file mode 100644 index 0000000..68633d4 --- /dev/null +++ b/src/storage/storage_backend_sheepdog.c @@ -0,0 +1,311 @@ +/* + * storage_backend_sheepdog.c: storage backend for Sheepdog handling + * + * Copyright (C) 2012 Wido den Hollander + * Copyright (C) 2012 Frank Spijkerman + * Copyright (C) 2012 Sebastian Wiedenroth + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Wido den Hollander <wido@xxxxxxxxx> + * Frank Spijkerman <frank.spijkerman@xxxxxxxxx> + * Sebastian Wiedenroth <sebastian.wiedenroth@xxxxxxxxxxx> + */ + +#include <config.h> + +#include "virterror_internal.h" +#include "storage_backend_sheepdog.h" +#include "storage_conf.h" +#include "util/command.h" +#include "util.h" +#include "memory.h" +#include "logging.h" + +#define VIR_FROM_THIS VIR_FROM_STORAGE + +static int virStorageBackendSheepdogRefreshVol(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol); + +void virStorageBackendSheepdogAddHostArg(virCommandPtr cmd, + virStoragePoolObjPtr pool); + +int +virStorageBackendSheepdogParseNodeInfo(virStoragePoolDefPtr pool, + char *output) +{ + /* fields: + * node id/total, size, used, use%, [total vdi size] + * + * example output: + * 0 15245667872 117571104 0% + * Total 15245667872 117571104 0% 20972341 + */ + + const char *p, *next; + + pool->allocation = pool->capacity = pool->available = 0; + + p = output; + do { + char *end; + + if ((next = strchr(p, '\n'))) + ++next; + else + return -1; + + if (!STRPREFIX(p, "Total ")) + continue; + + p = p + 6; + + if (virStrToLong_ull(p, &end, 10, &pool->capacity) < 0) + return -1; + + if ((p = end + 1) > next) + return -1; + + if (virStrToLong_ull(p, &end, 10, &pool->allocation) < 0) + return -1; + + pool->available = pool->capacity - pool->allocation; + return 0; + + } while ((p = next)); + + return -1; +} + +void +virStorageBackendSheepdogAddHostArg(virCommandPtr cmd, + virStoragePoolObjPtr pool) +{ + const char *address = "localhost"; + int port = 7000; + if (pool->def->source.nhost > 0) { + if (pool->def->source.hosts[0].name != NULL) { + address = pool->def->source.hosts[0].name; + } + if (pool->def->source.hosts[0].port) { + port = pool->def->source.hosts[0].port; + } + } + virCommandAddArg(cmd, "-a"); + virCommandAddArgFormat(cmd, "%s", address); + virCommandAddArg(cmd, "-p"); + virCommandAddArgFormat(cmd, "%d", port); +} + + +static int +virStorageBackendSheepdogRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool) +{ + int ret; + char *output = NULL; + virCommandPtr cmd; + + cmd = virCommandNewArgList(COLLIE, "node", "info", "-r", NULL); + virStorageBackendSheepdogAddHostArg(cmd, pool); + virCommandSetOutputBuffer(cmd, &output); + ret = virCommandRun(cmd, NULL); + if (ret == 0) + ret = virStorageBackendSheepdogParseNodeInfo(pool->def, output); + + virCommandFree(cmd); + VIR_FREE(output); + return ret; +} + + +static int +virStorageBackendSheepdogDeleteVol(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + unsigned int flags) +{ + + virCheckFlags(0, -1); + + virCommandPtr cmd = virCommandNewArgList(COLLIE, "vdi", "delete", vol->name, NULL); + virStorageBackendSheepdogAddHostArg(cmd, pool); + int ret = virCommandRun(cmd, NULL); + + virCommandFree(cmd); + return ret; +} + + +static int +virStorageBackendSheepdogCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol) +{ + + int ret; + + if (vol->target.encryption != NULL) { + virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Sheepdog does not support encrypted volumes")); + return -1; + } + + virCommandPtr cmd = virCommandNewArgList(COLLIE, "vdi", "create", vol->name, NULL); + virCommandAddArgFormat(cmd, "%llu", vol->capacity); + virStorageBackendSheepdogAddHostArg(cmd, pool); + ret = virCommandRun(cmd, NULL); + + virStorageBackendSheepdogRefreshVol(conn, pool, vol); + + virCommandFree(cmd); + return ret; +} + + +int +virStorageBackendSheepdogParseVdiList(virStorageVolDefPtr vol, + char *output) +{ + /* fields: + * current/clone/snapshot, name, id, size, used, shared, creation time, vdi id, [tag] + * + * example output: + * s test 1 10 0 0 1336556634 7c2b25 + * s test 2 10 0 0 1336557203 7c2b26 + * = test 3 10 0 0 1336557216 7c2b27 + */ + + int id; + const char *p, *next; + + vol->allocation = vol->capacity = 0; + + p = output; + do { + char *end; + + if ((next = strchr(p, '\n'))) + ++next; + + /* ignore snapshots */ + if (*p != '=') + continue; + + /* skip space */ + if (p + 2 < next) { + p += 2; + } else { + return -1; + } + + /* skip name */ + while (*p != '\0' && *p != ' ') { + if (*p == '\\') + ++p; + ++p; + } + + if (virStrToLong_i(p, &end, 10, &id) < 0) + return -1; + + p = end + 1; + + if (virStrToLong_ull(p, &end, 10, &vol->capacity) < 0) + return -1; + + p = end + 1; + + if (virStrToLong_ull(p, &end, 10, &vol->allocation) < 0) + return -1; + + return 0; + } while ((p = next)); + + return -1; +} + +static int +virStorageBackendSheepdogRefreshVol(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol) +{ + int ret; + char *output = NULL; + + virCommandPtr cmd = virCommandNewArgList(COLLIE, "vdi", "list", vol->name, "-r", NULL); + virStorageBackendSheepdogAddHostArg(cmd, pool); + virCommandSetOutputBuffer(cmd, &output); + ret = virCommandRun(cmd, NULL); + + if (ret < 0) + goto cleanup; + + if ((ret = virStorageBackendSheepdogParseVdiList(vol, output)) < 0) + goto cleanup; + + vol->type = VIR_STORAGE_VOL_NETWORK; + + VIR_FREE(vol->key); + if (virAsprintf(&vol->key, "%s/%s", + pool->def->source.name, vol->name) == -1) { + virReportOOMError(); + goto cleanup; + } + + VIR_FREE(vol->target.path); + if (virAsprintf(&vol->target.path, "%s", vol->name) == -1) { + virReportOOMError(); + goto cleanup; + } + +cleanup: + virCommandFree(cmd); + return ret; +} + + +static int +virStorageBackendSheepdogResizeVol(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + unsigned long long capacity, + unsigned int flags) +{ + + virCheckFlags(0, -1); + + virCommandPtr cmd = virCommandNewArgList(COLLIE, "vdi", "resize", vol->name, NULL); + virCommandAddArgFormat(cmd, "%llu", capacity); + virStorageBackendSheepdogAddHostArg(cmd, pool); + int ret = virCommandRun(cmd, NULL); + + virCommandFree(cmd); + return ret; + +} + + + +virStorageBackend virStorageBackendSheepdog = { + .type = VIR_STORAGE_POOL_SHEEPDOG, + + .refreshPool = virStorageBackendSheepdogRefreshPool, + .createVol = virStorageBackendSheepdogCreateVol, + .refreshVol = virStorageBackendSheepdogRefreshVol, + .deleteVol = virStorageBackendSheepdogDeleteVol, + .resizeVol = virStorageBackendSheepdogResizeVol, +}; diff --git a/src/storage/storage_backend_sheepdog.h b/src/storage/storage_backend_sheepdog.h new file mode 100644 index 0000000..51ef7a4 --- /dev/null +++ b/src/storage/storage_backend_sheepdog.h @@ -0,0 +1,39 @@ +/* + * storage_backend_sheepog.h: storage backend for Sheepdog handling + * + * Copyright (C) 2012 Wido den Hollander + * Copyright (C) 2012 Frank Spijkerman + * Copyright (C) 2012 Sebastian Wiedenroth + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Wido den Hollander <wido@xxxxxxxxx> + * Frank Spijkerman <frank.spijkerman@xxxxxxxxx> + * Sebastian Wiedenroth <sebastian.wiedenroth@xxxxxxxxxxx> + */ + +#ifndef __VIR_STORAGE_BACKEND_SHEEPDOG_H__ +# define __VIR_STORAGE_BACKEND_SHEEPDOG_H__ + +# include "storage_backend.h" + +int virStorageBackendSheepdogParseNodeInfo(virStoragePoolDefPtr pool, + char *output); +int virStorageBackendSheepdogParseVdiList(virStorageVolDefPtr vol, + char *output); + +extern virStorageBackend virStorageBackendSheepdog; + +#endif /* __VIR_STORAGE_BACKEND_SHEEPDOG_H__ */ diff --git a/tests/Makefile.am b/tests/Makefile.am index e3bd6d1..a466480 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -141,6 +141,10 @@ if WITH_NETWORK test_programs += networkxml2argvtest endif +if WITH_STORAGE_SHEEPDOG +test_programs += storagebackendsheepdogtest +endif + test_programs += nwfilterxml2xmltest test_programs += storagevolxml2xmltest storagepoolxml2xmltest @@ -398,6 +402,15 @@ else EXTRA_DIST += networkxml2argvtest.c endif +if WITH_STORAGE_SHEEPDOG +storagebackendsheepdogtest_SOURCES = \ + storagebackendsheepdogtest.c \ + testutils.c testutils.h +storagebackendsheepdogtest_LDADD = ../src/libvirt_driver_storage.la $(LDADDS) +else +EXTRA_DIST += storagebackendsheepdogtest.c +endif + nwfilterxml2xmltest_SOURCES = \ nwfilterxml2xmltest.c \ testutils.c testutils.h diff --git a/tests/storagebackendsheepdogtest.c b/tests/storagebackendsheepdogtest.c new file mode 100644 index 0000000..0870829 --- /dev/null +++ b/tests/storagebackendsheepdogtest.c @@ -0,0 +1,214 @@ +/* + * storagebackendsheepdogtest.c: storage backend for Sheepdog handling + * + * Copyright (C) 2012 Sebastian Wiedenroth + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Sebastian Wiedenroth <sebastian.wiedenroth@xxxxxxxxxxx> + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> +#include <string.h> + +#include <sys/types.h> +#include <fcntl.h> + +#include "internal.h" +#include "testutils.h" +#include "storage/storage_backend_sheepdog.h" + + +typedef struct { + const char *output; + int expected_return; + uint64_t expected_capacity; + uint64_t expected_allocation; +} collie_test; + + +static int +test_node_info_parser(collie_test test, char *poolxml) +{ + int ret = -1; + char *output = NULL; + char *poolXmlData = NULL; + virStoragePoolDefPtr pool = NULL; + + if (virtTestLoadFile(poolxml, &poolXmlData) < 0) + goto cleanup; + + if (!(pool = virStoragePoolDefParseString(poolXmlData))) + goto cleanup; + + output = strdup(test.output); + if (!output) + goto cleanup; + + if (virStorageBackendSheepdogParseNodeInfo(pool, output) != + test.expected_return) + goto cleanup; + + if (test.expected_return) { + ret = 0; + goto cleanup; + } + + if (pool->capacity == test.expected_capacity && + pool->allocation == test.expected_allocation) + ret = 0; + + cleanup: + VIR_FREE(output); + VIR_FREE(poolXmlData); + virStoragePoolDefFree(pool); + return ret; +} + +static int +test_vdi_list_parser(collie_test test, char *poolxml, char *volxml) +{ + int ret = -1; + char *poolXmlData = NULL; + char *volXmlData = NULL; + char *output = NULL; + virStoragePoolDefPtr pool = NULL; + virStorageVolDefPtr vol = NULL; + + if (virtTestLoadFile(poolxml, &poolXmlData) < 0) + goto cleanup; + if (virtTestLoadFile(volxml, &volXmlData) < 0) + goto cleanup; + + if (!(pool = virStoragePoolDefParseString(poolXmlData))) + goto cleanup; + + if (!(vol = virStorageVolDefParseString(pool, volXmlData))) + goto cleanup; + + output = strdup(test.output); + if (!output) + goto cleanup; + + if (virStorageBackendSheepdogParseVdiList(vol, output) != + test.expected_return) + goto cleanup; + + if (test.expected_return) { + ret = 0; + goto cleanup; + } + + if (vol->capacity == test.expected_capacity && + vol->allocation == test.expected_allocation) + ret = 0; + + cleanup: + VIR_FREE(output); + VIR_FREE(poolXmlData); + VIR_FREE(volXmlData); + virStoragePoolDefFree(pool); + virStorageVolDefFree(vol); + return ret; +} + + +static int +mymain(void) +{ + int ret = -1; + char *poolxml = NULL; + char *volxml = NULL; + + collie_test node_info_tests[] = { + {"", -1, 0, 0}, + {"Total 15245667872 117571104 0% 20972341\n", 0, 15245667872, 117571104}, + {"To", -1, 0, 0}, + {"asdf\nasdf", -1, 0, 0}, + {"Total ", -1, 0, 0}, + {"Total 1", -1, 0, 0}, + {"Total 1\n", -1, 0, 0}, + {"Total 1 ", -1, 0, 0}, + {"Total 1 2", -1, 0, 0}, + {"Total 1 2 ", -1, 0, 0}, + {"Total 1 2\n", 0, 1, 2}, + {"Total 1 2 \n", 0, 1, 2}, + {"Total a 2 \n", -1, 0, 0}, + {"Total 1 b \n", -1, 0, 0}, + {"Total a b \n", -1, 0, 0}, + {"stuff\nTotal 1 2 \n", 0, 1, 2}, + {"0 1 2 3\nTotal 1 2 \n", 0, 1, 2}, + {NULL, 0, 0, 0} + }; + + collie_test vdi_list_tests[] = { + {"", -1, 0, 0}, + {"= test 3 10 20 0 1336557216 7c2b27\n", 0, 10, 20}, + {"= test\\ with\\ spaces 3 10 20 0 1336557216 7c2b27\n", 0, 10, 20}, + {"= backslashattheend\\\\ 3 10 20 0 1336557216 7c2b27\n", 0, 10, 20}, + {"s test 1 10 20 0 1336556634 7c2b25\n= test 3 50 60 0 1336557216 7c2b27\n", 0, 50, 60}, + {"=", -1, 0, 0}, + {"= test", -1, 0, 0}, + {"= test ", -1, 0, 0}, + {"= test 1", -1, 0, 0}, + {"= test 1 ", -1, 0, 0}, + {"= test 1 2", -1, 0, 0}, + {"= test 1 2 ", -1, 0, 0}, + {"= test 1 2 3", -1, 0, 0}, + {NULL, 0, 0, 0} + }; + + collie_test *test = node_info_tests; + + if (virAsprintf(&poolxml, "%s/storagepoolxml2xmlin/pool-sheepdog.xml", + abs_srcdir) < 0) + goto cleanup; + + if (virAsprintf(&volxml, "%s/storagevolxml2xmlin/vol-sheepdog.xml", + abs_srcdir) < 0) + goto cleanup; + + while (test->output != NULL) { + ret = test_node_info_parser(*test, poolxml); + virtTestResult("node_info_parser", ret, NULL); + ++test; + if (ret < 0) + return EXIT_FAILURE; + } + + test = vdi_list_tests; + + while (test->output != NULL) { + ret = test_vdi_list_parser(*test, poolxml, volxml); + virtTestResult("vdi_list_parser", ret, NULL); + ++test; + if (ret < 0) + return EXIT_FAILURE; + } + + ret = 0; + + cleanup: + VIR_FREE(poolxml); + VIR_FREE(volxml); + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +VIRT_TEST_MAIN(mymain) diff --git a/tests/storagepoolxml2xmlin/pool-sheepdog.xml b/tests/storagepoolxml2xmlin/pool-sheepdog.xml new file mode 100644 index 0000000..1287047 --- /dev/null +++ b/tests/storagepoolxml2xmlin/pool-sheepdog.xml @@ -0,0 +1,8 @@ +<pool type='sheepdog'> + <name>sheepdog</name> + <uuid>65fcba04-5b13-bd93-cff3-52ce48e11ad7</uuid> + <source> + <host name='localhost' port='7000'/> + <name>sheepdog</name> + </source> +</pool> diff --git a/tests/storagepoolxml2xmlout/pool-sheepdog.xml b/tests/storagepoolxml2xmlout/pool-sheepdog.xml new file mode 100644 index 0000000..000c068 --- /dev/null +++ b/tests/storagepoolxml2xmlout/pool-sheepdog.xml @@ -0,0 +1,11 @@ +<pool type='sheepdog'> + <name>sheepdog</name> + <uuid>65fcba04-5b13-bd93-cff3-52ce48e11ad7</uuid> + <capacity unit='bytes'>0</capacity> + <allocation unit='bytes'>0</allocation> + <available unit='bytes'>0</available> + <source> + <host name='localhost' port='7000'/> + <name>sheepdog</name> + </source> +</pool> diff --git a/tests/storagepoolxml2xmltest.c b/tests/storagepoolxml2xmltest.c index d73fc8a..8cac978 100644 --- a/tests/storagepoolxml2xmltest.c +++ b/tests/storagepoolxml2xmltest.c @@ -93,6 +93,7 @@ mymain(void) DO_TEST("pool-mpath"); DO_TEST("pool-iscsi-multiiqn"); DO_TEST("pool-iscsi-vendor-product"); + DO_TEST("pool-sheepdog"); return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/tests/storagevolxml2xmlin/vol-sheepdog.xml b/tests/storagevolxml2xmlin/vol-sheepdog.xml new file mode 100644 index 0000000..49e221c --- /dev/null +++ b/tests/storagevolxml2xmlin/vol-sheepdog.xml @@ -0,0 +1,10 @@ +<volume> + <name>test2</name> + <source> + </source> + <capacity unit='bytes'>1024</capacity> + <allocation unit='bytes'>0</allocation> + <target> + <path>sheepdog:test2</path> + </target> +</volume> diff --git a/tests/storagevolxml2xmlout/vol-sheepdog.xml b/tests/storagevolxml2xmlout/vol-sheepdog.xml new file mode 100644 index 0000000..2f19af8 --- /dev/null +++ b/tests/storagevolxml2xmlout/vol-sheepdog.xml @@ -0,0 +1,17 @@ +<volume> + <name>test2</name> + <key>(null)</key> + <source> + </source> + <capacity unit='bytes'>1024</capacity> + <allocation unit='bytes'>0</allocation> + <target> + <path>sheepdog:test2</path> + <format type='unknown'/> + <permissions> + <mode>0600</mode> + <owner>4294967295</owner> + <group>4294967295</group> + </permissions> + </target> +</volume> diff --git a/tests/storagevolxml2xmltest.c b/tests/storagevolxml2xmltest.c index 37c92cd..ee85988 100644 --- a/tests/storagevolxml2xmltest.c +++ b/tests/storagevolxml2xmltest.c @@ -112,6 +112,7 @@ mymain(void) DO_TEST("pool-disk", "vol-partition"); DO_TEST("pool-logical", "vol-logical"); DO_TEST("pool-logical", "vol-logical-backing"); + DO_TEST("pool-sheepdog", "vol-sheepdog"); return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/tools/virsh.c b/tools/virsh.c index 2b4cb2c..dd0261c 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -20696,6 +20696,9 @@ vshShowVersion(vshControl *ctl ATTRIBUTE_UNUSED) #ifdef WITH_STORAGE_RBD vshPrint(ctl, " RBD"); #endif +#ifdef WITH_STORAGE_SHEEPDOG + vshPrint(ctl, " Sheepdog"); +#endif vshPrint(ctl, "\n"); vshPrint(ctl, "%s", _(" Miscellaneous:")); -- 1.7.9.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list