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

Sebastian Wiedenroth sebastian.wiedenroth at skylime.net
Thu Jun 14 11:14:56 UTC 2012


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 is prefixed with "sheepdog:"
and 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 at frubar.net>
---
 configure.ac                                  |   23 ++
 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                       |   17 +-
 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            |  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 +
 22 files changed, 770 insertions(+), 14 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..e1dbbdf 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/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 2bcebcf..a562f4d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -509,6 +509,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
 
@@ -1012,6 +1015,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
@@ -1110,6 +1117,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..d324613
--- /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 at widodh.nl>
+ *         Frank Spijkerman <frank.spijkerman at avira.com>
+ *         Sebastian Wiedenroth <sebastian.wiedenroth at 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,
+                                   virStorageVolDefPtr vol,
+                                   unsigned int flags)
+{
+
+    virCheckFlags(0, -1);
+
+    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,
+                                   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 = 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,
+                                    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,
+                                   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 at widodh.nl>
+ *         Frank Spijkerman <frank.spijkerman at avira.com>
+ *         Sebastian Wiedenroth <sebastian.wiedenroth at 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 98305c0..0dbc9d9 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -20245,6 +20245,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






More information about the libvir-list mailing list