[libvirt] [PATCH] storage backend: Add sheepdog support

Signed-off-by: Sebastian Wiedenroth <wiedi@frubar.net> --- This patch adds support for sheepdog pools and volumes. Thanks go to Frank Spijkerman who started the initial work on this and Wido den Hollander for his RBD support on which this is partly based. configure.ac | 23 ++ docs/drivers.html.in | 1 + docs/schemas/storagepool.rng | 17 ++ docs/schemas/storagevol.rng | 3 +- docs/storage.html.in | 62 +++++ po/POTFILES.in | 1 + src/Makefile.am | 8 + src/conf/storage_conf.c | 17 +- src/conf/storage_conf.h | 1 + src/storage/storage_backend.c | 6 + src/storage/storage_backend_sheepdog.c | 323 +++++++++++++++++++++++++ src/storage/storage_backend_sheepdog.h | 39 +++ tests/Makefile.am | 13 + tests/storagebackendsheepdogtest.c | 196 +++++++++++++++ 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 + 21 files changed, 757 insertions(+), 4 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/configure.ac b/configure.ac index dda764d..774a9dd 100644 --- a/configure.ac +++ b/configure.ac @@ -1807,6 +1807,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 @@ -1817,6 +1819,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]) @@ -1991,6 +1994,25 @@ 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" || @@ -2806,6 +2828,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 8edb877..83148ca 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..8730164 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 formated. + + <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 attachement</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/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 60f5442..82238b9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -506,6 +506,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 @@ -1009,6 +1012,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 @@ -1107,6 +1114,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..8ca6b1e 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) 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..b003856 --- /dev/null +++ b/src/storage/storage_backend_sheepdog.c @@ -0,0 +1,323 @@ +/* + * 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@widodh.nl> + * Frank Spijkerman <frank.spijkerman@avira.com> + * Sebastian Wiedenroth <sebastian.wiedenroth@skylime.net> + */ + +#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) +{ + /* 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 = virCommandNew(COLLIE); + virCommandAddArgList(cmd, "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 + ATTRIBUTE_UNUSED, + virStorageVolDefPtr vol, + unsigned int flags) +{ + + if (flags & VIR_STORAGE_VOL_DELETE_ZEROED) { + VIR_WARN("%s", _("This storage backend does not supported zeroed removal of volumes")); + } + + virCommandPtr cmd = virCommandNew(COLLIE); + + virCommandAddArgList(cmd, "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 + ATTRIBUTE_UNUSED, + virStorageVolDefPtr vol) +{ + + int ret; + + if (vol->target.encryption != NULL) { + virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("storage pool does not support encrypted volumes")); + return -1; + } + + virCommandPtr cmd = virCommandNew(COLLIE); + + virCommandAddArgList(cmd, "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) +{ + /* 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 != ' ' || (*p == ' ' && (*(p - 1) == '\\')))) + ++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 + ATTRIBUTE_UNUSED, + virStorageVolDefPtr vol) +{ + int ret; + + char *output = NULL; + + virCommandPtr cmd; + + cmd = virCommandNew(COLLIE); + virCommandAddArgList(cmd, "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, "sheepdog:%s", vol->name) == -1) { + virReportOOMError(); + goto cleanup; + } + + + +cleanup: + virCommandFree(cmd); + return ret; +} + + +static int +virStorageBackendSheepdogResizeVol(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool + ATTRIBUTE_UNUSED, + virStorageVolDefPtr vol, + unsigned long long capacity, + unsigned int flags) +{ + + virCheckFlags(0, -1); + + virCommandPtr cmd = virCommandNew(COLLIE); + + virCommandAddArgList(cmd, "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@widodh.nl> + * Frank Spijkerman <frank.spijkerman@avira.com> + * Sebastian Wiedenroth <sebastian.wiedenroth@skylime.net> + */ + +#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..a8f62a4 --- /dev/null +++ b/tests/storagebackendsheepdogtest.c @@ -0,0 +1,196 @@ +#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; + } + + ret = virStorageBackendSheepdogParseNodeInfo(pool, output); + + if (ret != test.expected_return) + goto cleanup; + + if (ret != 0) { + 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; + } + + ret = virStorageBackendSheepdogParseVdiList(vol, output); + + + if (ret != test.expected_return) + goto cleanup; + + if (ret != 0) { + 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}, + {"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 744b629..3f24a34 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -20229,6 +20229,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

On Tue, Jun 12, 2012 at 10:31:54AM +0200, Sebastian Wiedenroth wrote:
Signed-off-by: Sebastian Wiedenroth <wiedi@frubar.net>
Can you fill out the commit message with some descriptive text. At least illustrate the pool XML format and the volume XML format, describe what operations are supported, and illustrate how the data from the volume XML doc is to be used to create a corresponding <disk> element for a virtual machine.
---
This patch adds support for sheepdog pools and volumes. Thanks go to Frank Spijkerman who started the initial work on this and Wido den Hollander for his RBD support on which this is partly based.
Nice job, particularly like that you added test cases !
diff --git a/configure.ac b/configure.ac index dda764d..774a9dd 100644 --- a/configure.ac +++ b/configure.ac @@ -1807,6 +1807,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 @@ -1817,6 +1819,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]) @@ -1991,6 +1994,25 @@ 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"])
You're adding a requirement for the 'collie' command here, and a new '--with-storage-sheepdog' arg here. To go along with this you should modify the libvirt.spec.in, to have a Requires line on the RPM which provides 'collie', and also conditionally set the --without-storage-sheepdog arg so that it is only enabled for Fedora >= 16 (or whatever the min version was). If you arent' familiar with RPM specfiles, just look in the libvirt.spec.in file for any place mentioning 'with_storage_rbd' and copy that style. The sheepdog stuff will be pretty much exactly the same.
diff --git a/docs/storage.html.in b/docs/storage.html.in index b3484e8..8730164 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 formated. + + <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'/>
I think that host line is indented 2 spaces too many
+ </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 attachement</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/po/POTFILES.in b/po/POTFILES.in
diff --git a/src/storage/storage_backend_sheepdog.c b/src/storage/storage_backend_sheepdog.c new file mode 100644 index 0000000..b003856 --- /dev/null +++ b/src/storage/storage_backend_sheepdog.c +static int +virStorageBackendSheepdogDeleteVol(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool + ATTRIBUTE_UNUSED,
Can you make sure the ATTRIBUTE_UNUSED annotation is on the same line as the parameter it refers to - even if this makes the line go over 80 chars.
+ virStorageVolDefPtr vol, + unsigned int flags) +{ + + if (flags & VIR_STORAGE_VOL_DELETE_ZEROED) { + VIR_WARN("%s", _("This storage backend does not supported zeroed removal of volumes")); + }
It is preferrable to use the virCheckFlags() macro instead of this, so the caller gets a clear error.
+ + virCommandPtr cmd = virCommandNew(COLLIE); + + virCommandAddArgList(cmd, "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 + ATTRIBUTE_UNUSED,
Same here
+ virStorageVolDefPtr vol) +{ + + int ret; + + if (vol->target.encryption != NULL) { + virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("storage pool does not support encrypted volumes")); + return -1;
I'd suggest s/storage pool/Sheepdog/
+ } + + virCommandPtr cmd = virCommandNew(COLLIE); + + virCommandAddArgList(cmd, "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; +} + +static int +virStorageBackendSheepdogRefreshVol(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool + ATTRIBUTE_UNUSED,
And here
+ virStorageVolDefPtr vol) +{ + int ret; + + char *output = NULL; + + virCommandPtr cmd;
Can remove those 2 blank lines between variable decls.
+ + cmd = virCommandNew(COLLIE); + virCommandAddArgList(cmd, "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; + }
Does sheepdog associate any kind of globally unique UUID with storage volumes ? If so, it'd be desirable to use that as the key, instead of being name based, so that we have stronger uniqueness & stability guarentees.
+ + VIR_FREE(vol->target.path); + if (virAsprintf(&vol->target.path, "sheepdog:%s", vol->name) == -1) { + virReportOOMError(); + goto cleanup; + } + + + +cleanup: + virCommandFree(cmd); + return ret; +} + + +static int +virStorageBackendSheepdogResizeVol(virConnectPtr conn ATTRIBUTE_UNUSED, + virStoragePoolObjPtr pool + ATTRIBUTE_UNUSED,
And here
+ virStorageVolDefPtr vol, + unsigned long long capacity, + unsigned int flags) +{ + + virCheckFlags(0, -1); + + virCommandPtr cmd = virCommandNew(COLLIE); + + virCommandAddArgList(cmd, "vdi", "resize", vol->name, NULL); + virCommandAddArgFormat(cmd, "%llu", capacity); + virStorageBackendSheepdogAddHostArg(cmd, pool); + int ret = virCommandRun(cmd, NULL); + + virCommandFree(cmd); + return ret; + +} + +
All in all, i think this looks good Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Am 13.06.2012 um 15:52 schrieb Daniel P. Berrange:
On Tue, Jun 12, 2012 at 10:31:54AM +0200, Sebastian Wiedenroth wrote:
+ + cmd = virCommandNew(COLLIE); + virCommandAddArgList(cmd, "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; + }
Does sheepdog associate any kind of globally unique UUID with storage volumes ? If so, it'd be desirable to use that as the key, instead of being name based, so that we have stronger uniqueness & stability guarentees.
Sheepdog storage volumes do have a very short "vdi id" which is calculated from the hash of the name. So using the name, as collie does, should be fine.
All in all, i think this looks good
Thanks for the review. I'll repost a v2 after addressing the remaining issues. Best regards, Sebastian
participants (2)
-
Daniel P. Berrange
-
Sebastian Wiedenroth