storage backend: Add RBD (RADOS Block Device) support
authorWido den Hollander <wido@widodh.nl>
Wed, 4 Jan 2012 18:48:53 +0000 (19:48 +0100)
committerWido den Hollander <wido@widodh.nl>
Wed, 4 Jan 2012 18:49:02 +0000 (19:49 +0100)
Add a new storage backend to libvirt with RBD support.

This also introduces a new storage pool type 'NETWORK' to support future RBD a-like
type of storage pools.

The current storage pools al rely on a local directory or blockdevice being present

In this case we use librbd and NOT the kernel RBD driver to implement RBD, thus it will
only work with Qemu/KVM.

Signed-off-by: Wido den Hollander <wido@widodh.nl>

configure.ac
include/libvirt/libvirt.h.in
src/Makefile.am
src/conf/storage_conf.c
src/conf/storage_conf.h
src/storage/storage_backend.c
src/storage/storage_backend_rbd.c [new file with mode: 0644]
src/storage/storage_backend_rbd.h [new file with mode: 0644]
tools/virsh.c

index 46a9129..41c4c50 100644 (file)
@@ -1668,6 +1668,8 @@ AC_ARG_WITH([storage-mpath],
   AC_HELP_STRING([--with-storage-mpath], [with mpath backend for the storage driver @<:@default=check@:>@]),[],[with_storage_mpath=check])
 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])
 
 if test "$with_libvirtd" = "no"; then
   with_storage_dir=no
@@ -1677,6 +1679,7 @@ if test "$with_libvirtd" = "no"; then
   with_storage_scsi=no
   with_storage_mpath=no
   with_storage_disk=no
+  with_storage_rbd=no
 fi
 if test "$with_storage_dir" = "yes" ; then
   AC_DEFINE_UNQUOTED([WITH_STORAGE_DIR], 1, [whether directory backend for storage driver is enabled])
@@ -1835,6 +1838,22 @@ if test "$with_storage_mpath" = "check"; then
 fi
 AM_CONDITIONAL([WITH_STORAGE_MPATH], [test "$with_storage_mpath" = "yes"])
 
+if test "$with_storage_rbd" = "yes" || test "$with_storage_rbd" = "check"; then
+    AC_CHECK_HEADER([rbd/librbd.h], [LIBRBD_FOUND=yes; break;])
+
+    LIBRBD_LIBS="-lrbd -lrados -lcrypto"
+
+    if test "$LIBRBD_FOUND" = "yes"; then
+        with_storage_rbd=yes
+        LIBS="$LIBS $LIBRBD_LIBS"
+    else
+        with_storage_rbd=no
+    fi
+
+    AC_DEFINE_UNQUOTED([WITH_STORAGE_RBD], 1, [wether RBD backend for storage driver is enabled])
+fi
+AM_CONDITIONAL([WITH_STORAGE_RBD], [test "$with_storage_rbd" = "yes"])
+
 LIBPARTED_CFLAGS=
 LIBPARTED_LIBS=
 if test "$with_storage_disk" = "yes" ||
@@ -2582,6 +2601,7 @@ AC_MSG_NOTICE([   iSCSI: $with_storage_iscsi])
 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([])
 AC_MSG_NOTICE([Security Drivers])
 AC_MSG_NOTICE([])
index 7f26521..95e0ece 100644 (file)
@@ -2051,6 +2051,7 @@ typedef enum {
   VIR_STORAGE_VOL_FILE = 0,     /* Regular file based volumes */
   VIR_STORAGE_VOL_BLOCK = 1,    /* Block based volumes */
   VIR_STORAGE_VOL_DIR = 2,      /* Directory-passthrough based volume */
+  VIR_STORAGE_VOL_NETWORK = 3,  /* Network volumes like RBD (RADOS Block Device) */
 } virStorageVolType;
 
 typedef enum {
index 93bf54c..b6f92ad 100644 (file)
@@ -481,6 +481,9 @@ STORAGE_DRIVER_MPATH_SOURCES =                                      \
 STORAGE_DRIVER_DISK_SOURCES =                                  \
                storage/storage_backend_disk.h storage/storage_backend_disk.c
 
+STORAGE_DRIVER_RBD_SOURCES =                                   \
+               storage/storage_backend_rbd.h storage/storage_backend_rbd.c
+
 STORAGE_HELPER_DISK_SOURCES =                                  \
                storage/parthelper.c
 
@@ -1023,6 +1026,11 @@ if WITH_STORAGE_DISK
 libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_DISK_SOURCES)
 endif
 
+if WITH_STORAGE_RBD
+libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_RBD_SOURCES)
+libvirt_la_LIBADD += $(LIBRBD_LIBS)
+endif
+
 if WITH_NODE_DEVICES
 # Needed to keep automake quiet about conditionals
 if WITH_DRIVER_MODULES
@@ -1122,6 +1130,7 @@ EXTRA_DIST +=                                                     \
                $(STORAGE_DRIVER_SCSI_SOURCES)                  \
                $(STORAGE_DRIVER_MPATH_SOURCES)                 \
                $(STORAGE_DRIVER_DISK_SOURCES)                  \
+               $(STORAGE_DRIVER_RBD_SOURCES)                   \
                $(NODE_DEVICE_DRIVER_SOURCES)                   \
                $(NODE_DEVICE_DRIVER_HAL_SOURCES)               \
                $(NODE_DEVICE_DRIVER_UDEV_SOURCES)              \
index dadc115..a2b805c 100644 (file)
@@ -52,7 +52,7 @@ VIR_ENUM_IMPL(virStoragePool,
               VIR_STORAGE_POOL_LAST,
               "dir", "fs", "netfs",
               "logical", "disk", "iscsi",
-              "scsi", "mpath")
+              "scsi", "mpath", "rbd")
 
 VIR_ENUM_IMPL(virStoragePoolFormatFileSystem,
               VIR_STORAGE_POOL_FS_LAST,
@@ -110,6 +110,7 @@ enum {
     VIR_STORAGE_POOL_SOURCE_ADAPTER         = (1<<3),
     VIR_STORAGE_POOL_SOURCE_NAME            = (1<<4),
     VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN   = (1<<5),
+    VIR_STORAGE_POOL_SOURCE_NETWORK         = (1<<6),
 };
 
 
@@ -194,6 +195,15 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
             .formatToString = virStoragePoolFormatDiskTypeToString,
         }
     },
+    { .poolType = VIR_STORAGE_POOL_RBD,
+      .poolOptions = {
+             .flags = (VIR_STORAGE_POOL_SOURCE_HOST |
+                       VIR_STORAGE_POOL_SOURCE_NETWORK),
+        },
+       .volOptions = {
+            .formatToString = virStoragePoolFormatDiskTypeToString,
+        }
+    },
     { .poolType = VIR_STORAGE_POOL_MPATH,
       .volOptions = {
             .formatToString = virStoragePoolFormatDiskTypeToString,
@@ -293,6 +303,11 @@ virStoragePoolSourceClear(virStoragePoolSourcePtr source)
         VIR_FREE(source->auth.chap.login);
         VIR_FREE(source->auth.chap.passwd);
     }
+
+    if (source->authType == VIR_STORAGE_POOL_AUTH_CEPHX) {
+        VIR_FREE(source->auth.cephx.id);
+        VIR_FREE(source->auth.cephx.secret);
+    }
 }
 
 void
@@ -395,6 +410,26 @@ virStoragePoolDefParseAuthChap(xmlXPathContextPtr ctxt,
 }
 
 static int
+virStoragePoolDefParseAuthCephx(xmlXPathContextPtr ctxt,
+                               virStoragePoolAuthCephxPtr auth) {
+    auth->id = virXPathString("string(./auth/@id)", ctxt);
+    if (auth->id == NULL) {
+        virStorageReportError(VIR_ERR_XML_ERROR,
+                              "%s", _("missing auth id attribute"));
+        return -1;
+    }
+
+    auth->secret = virXPathString("string(./auth/@secret)", ctxt);
+    if (auth->secret == NULL) {
+        virStorageReportError(VIR_ERR_XML_ERROR,
+                              "%s", _("missing auth secret attribute"));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
 virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
                              virStoragePoolSourcePtr source,
                              int pool_type,
@@ -405,6 +440,7 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
     int nsource, i;
     virStoragePoolOptionsPtr options;
     char *port = NULL;
+       char *prefer_ipv6 = NULL;
 
     relnode = ctxt->node;
     ctxt->node = node;
@@ -414,6 +450,12 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
     }
 
     source->name = virXPathString("string(./name)", ctxt);
+    if (pool_type == VIR_STORAGE_POOL_RBD && source->name == NULL) {
+        virStorageReportError(VIR_ERR_XML_ERROR,
+                                  _("%s"), "missing mandatory 'name' field for RBD pool name");
+            VIR_FREE(source->name);
+            goto cleanup;
+    }
 
     if (options->formatFromString) {
         char *format = virXPathString("string(./format/@type)", ctxt);
@@ -441,7 +483,12 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
             goto cleanup;
         }
     }
-
+    prefer_ipv6 = virXPathString("string(./host/@prefer_ipv6)", ctxt);
+    if (prefer_ipv6) {
+        if (strcasecmp(prefer_ipv6, "yes") == 0 || strcasecmp(prefer_ipv6, "y") == 0 || strcasecmp(prefer_ipv6, "true") == 0) {
+            source->host.prefer_ipv6 = true;
+        }
+    }
 
     source->initiator.iqn = virXPathString("string(./initiator/iqn/@name)", ctxt);
 
@@ -478,6 +525,8 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
     } else {
         if (STREQ(authType, "chap")) {
             source->authType = VIR_STORAGE_POOL_AUTH_CHAP;
+               } else if (STREQ(authType, "cephx")) {
+                       source->authType = VIR_STORAGE_POOL_AUTH_CEPHX;
         } else {
             virStorageReportError(VIR_ERR_XML_ERROR,
                                   _("unknown auth type '%s'"),
@@ -490,6 +539,11 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
         if (virStoragePoolDefParseAuthChap(ctxt, &source->auth.chap) < 0)
             goto cleanup;
     }
+    
+    if (source->authType == VIR_STORAGE_POOL_AUTH_CEPHX) {
+        if (virStoragePoolDefParseAuthCephx(ctxt, &source->auth.cephx) < 0)
+            goto cleanup;
+    }
 
     source->vendor = virXPathString("string(./vendor/@name)", ctxt);
     source->product = virXPathString("string(./product/@name)", ctxt);
@@ -717,6 +771,8 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) {
         }
     }
 
+    /* When we are working with a virtual disk we can skip the target path and permissions */
+    if (!(options->flags & VIR_STORAGE_POOL_SOURCE_NETWORK)) {
     if ((tmppath = virXPathString("string(./target/path)", ctxt)) == NULL) {
         virStorageReportError(VIR_ERR_XML_ERROR,
                               "%s", _("missing storage pool target path"));
@@ -731,6 +787,7 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) {
     if (virStorageDefParsePerms(ctxt, &ret->target.perms,
                                 "./target/permissions", 0700) < 0)
         goto cleanup;
+       }
 
     return ret;
 
@@ -860,6 +917,11 @@ virStoragePoolSourceFormat(virBufferPtr buf,
                           src->auth.chap.login,
                           src->auth.chap.passwd);
 
+    if (src->authType == VIR_STORAGE_POOL_AUTH_CEPHX)
+        virBufferAsprintf(buf,"    <auth type='chephx' id='%s' secret='%s'/>\n",
+                          src->auth.cephx.id,
+                          src->auth.cephx.secret);
+
     if (src->vendor != NULL) {
         virBufferEscapeString(buf,"    <vendor name='%s'/>\n", src->vendor);
     }
index 19bbd2c..9009298 100644 (file)
@@ -120,6 +120,7 @@ enum virStoragePoolType {
     VIR_STORAGE_POOL_ISCSI,    /* iSCSI targets */
     VIR_STORAGE_POOL_SCSI,     /* SCSI HBA */
     VIR_STORAGE_POOL_MPATH,    /* Multipath devices */
+       VIR_STORAGE_POOL_RBD,      /* RADOS Block Device */
 
     VIR_STORAGE_POOL_LAST,
 };
@@ -137,6 +138,7 @@ enum virStoragePoolDeviceType {
 enum virStoragePoolAuthType {
     VIR_STORAGE_POOL_AUTH_NONE,
     VIR_STORAGE_POOL_AUTH_CHAP,
+       VIR_STORAGE_POOL_AUTH_CEPHX,
 };
 
 typedef struct _virStoragePoolAuthChap virStoragePoolAuthChap;
@@ -146,6 +148,12 @@ struct _virStoragePoolAuthChap {
     char *passwd;
 };
 
+typedef struct _virStoragePoolAuthCephx virStoragePoolAuthCephx;
+typedef virStoragePoolAuthCephx *virStoragePoolAuthCephxPtr;
+struct _virStoragePoolAuthCephx {
+    char *id;
+    char *secret;
+};
 
 /*
  * For remote pools, info on how to reach the host
@@ -155,6 +163,7 @@ typedef virStoragePoolSourceHost *virStoragePoolSourceHostPtr;
 struct _virStoragePoolSourceHost {
     char *name;
     int port;
+    bool prefer_ipv6;
 };
 
 
@@ -234,6 +243,7 @@ struct _virStoragePoolSource {
     int authType;       /* virStoragePoolAuthType */
     union {
         virStoragePoolAuthChap chap;
+        virStoragePoolAuthCephx cephx;
     } auth;
 
     /* Vendor of the source */
index d7394e0..d858e6a 100644 (file)
@@ -77,6 +77,9 @@
 #if WITH_STORAGE_DIR
 # include "storage_backend_fs.h"
 #endif
+#if WITH_STORAGE_RBD
+# include "storage_backend_rbd.h"
+#endif
 
 #define VIR_FROM_THIS VIR_FROM_STORAGE
 
@@ -103,6 +106,9 @@ static virStorageBackendPtr backends[] = {
 #if WITH_STORAGE_DISK
     &virStorageBackendDisk,
 #endif
+#if WITH_STORAGE_RBD
+    &virStorageBackendRBD,
+#endif
     NULL
 };
 
diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c
new file mode 100644 (file)
index 0000000..56fc1af
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * storage_backend_rbd.c: storage backend for RBD (RADOS Block Device) handling
+ *
+ * Copyright (C) 2011 Wido den Hollander
+ *
+ * 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>
+ */
+
+#include <config.h>
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <string.h>
+#include <stdio.h>
+#include <regex.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "virterror_internal.h"
+#include "storage_backend_rbd.h"
+#include "storage_conf.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "rados/librados.h"
+#include "rbd/librbd.h"
+
+#define VIR_FROM_THIS VIR_FROM_STORAGE
+
+/*
+ * We use the build in secret management from libvirt
+ * In all methods we use conn->secretDriver to retreive the credentials to connect to the Ceph cluster
+ * This information could then also be passed down to the domain/volume configuration
+ */
+
+struct _virStorageBackendRBDPtr {
+    rados_t cluster;
+    rados_ioctx_t ioctx ;
+};
+
+typedef struct _virStorageBackendRBDPtr virStorageBackendRBDPtr;
+
+static int virStorageBackendRBDOpenRADOSConn(virStorageBackendRBDPtr *ptr, virConnectPtr conn, virStoragePoolObjPtr pool) {
+
+    if (pool->def->source.auth.cephx.secret != NULL && pool->def->source.auth.cephx.id != NULL) {
+        unsigned char *value;
+        size_t value_size;
+        char *rados_key;
+
+        rados_create(&ptr->cluster, pool->def->source.auth.cephx.id);
+        rados_conf_set(ptr->cluster, "auth_supported", "cephx");
+
+        virSecretPtr secret;
+        secret = virSecretLookupByUUIDString(conn, pool->def->source.auth.cephx.secret);
+
+        value = virSecretGetValue(secret, &value_size, 0);
+        base64_encode_alloc((char *)value, value_size, &rados_key);
+        VIR_FREE(value);
+
+        rados_conf_set(ptr->cluster, "key", rados_key);
+
+        VIR_FREE(rados_key);
+
+        virSecretFree(secret);
+    } else {
+        rados_create(&ptr->cluster, NULL);
+        rados_conf_set(ptr->cluster, "auth_supported", "none");
+    }
+
+    char mon_host[256];
+    if (pool->def->source.host.name != NULL && pool->def->source.host.port == NULL) {
+        sprintf(mon_host, "%s:6789", pool->def->source.host.name);
+    } else if (pool->def->source.host.name != NULL && pool->def->source.host.port != NULL) {
+        sprintf(mon_host, "%s:%d", pool->def->source.host.name, pool->def->source.host.port);
+    } else {
+        /* We should never get here! A hostname should always be present! */
+        virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("Missing mandatory monitor hostname, this should not happen!"));
+        return -1;
+    }
+
+    rados_conf_set(ptr->cluster, "mon_host", mon_host);
+
+    if (pool->def->source.host.prefer_ipv6) {
+        rados_conf_set(ptr->cluster, "ms_bind_ipv6", "true");
+    }
+
+    if (rados_connect(ptr->cluster) < 0) {
+        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("failed to connect to the RADOS cluster on hostname '%s'"),
+                               mon_host);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int virStorageBackendRBDCloseRADOSConn(virStorageBackendRBDPtr ptr) {
+    if (ptr.ioctx != NULL) {
+        rados_ioctx_destroy(ptr.ioctx);
+    }
+
+    if (ptr.cluster != NULL) {
+        rados_shutdown(ptr.cluster);
+    }
+    return 0;
+}
+
+static int volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol, virStoragePoolObjPtr pool, virStorageBackendRBDPtr ptr) {
+
+    rbd_image_t image;
+    if (rbd_open(ptr.ioctx, vol->name, &image, NULL) < 0) {
+        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("failed to open the RBD image '%s'"),
+                               vol->name);
+        return -1;
+    }
+
+    rbd_image_info_t info;
+    if (rbd_stat(image, &info, sizeof(info)) < 0) {
+        virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("failed to stat the RBD image"));
+        return -1;
+    }
+
+    vol->capacity = info.size;
+    vol->allocation = info.obj_size * info.num_objs;
+       vol->type = VIR_STORAGE_VOL_NETWORK;
+
+    VIR_FREE(vol->target.path);
+    if (virAsprintf(&vol->target.path, "%s/%s",
+                    pool->def->source.name,
+                    vol->name) == -1) {
+        virReportOOMError();
+        return -1;
+    }
+
+    VIR_FREE(vol->key);
+    vol->key = strdup(vol->target.path);
+    if (vol->key == NULL) {
+        virReportOOMError();
+        return -1;
+    }
+
+    rbd_close(image);
+}
+
+static int virStorageBackendRBDFindPoolSources(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, char **const groups, void *data) {
+    virStoragePoolSourceList sourceList;
+    char *retval = NULL;
+
+    memset(&sourceList, 0, sizeof(sourceList));
+    sourceList.type = VIR_STORAGE_POOL_RBD;
+    sourceList.nsources = 1;
+    retval = virStoragePoolSourceListFormat(&sourceList);
+    return retval;
+}
+
+static int virStorageBackendRBDRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool) {
+
+    virStorageBackendRBDPtr ptr;
+
+    if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, pool) < 0) {
+        return -1;
+    }
+
+    if (rados_ioctx_create(ptr.cluster, pool->def->source.name, &ptr.ioctx) < 0) {
+        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("failed to create the RBD IoCTX. Does the pool '%s' exist?"),
+                               pool->def->source.name);
+        return -1;
+    }
+
+    struct rados_cluster_stat_t stat;
+    if (rados_cluster_stat(ptr.cluster, &stat) < 0) {
+        virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("failed to stat the RADOS cluster"));
+        return -1;
+    }
+
+    struct rados_pool_stat_t poolstat;
+    if (rados_ioctx_pool_stat(ptr.ioctx, &poolstat) < 0) {
+        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+                              _("failed to stat the RADOS pool '%s'"),
+                              pool->def->source.name);
+        return -1;
+    }
+
+    pool->def->capacity = stat.kb * 1024;
+    pool->def->available = stat.kb_avail * 1024;
+    pool->def->allocation = poolstat.num_bytes;
+
+    VIR_REALLOC_N(pool->volumes.objs, pool->volumes.count + 1);
+
+    int num_images, i;
+    char *names, *name;
+    size_t max_size = 1024;
+
+    names = (char *) malloc(sizeof(char *) * 1024);
+    int len = rbd_list(ptr.ioctx, names, &max_size);
+
+    for (i = 0, num_images = 0, name = names; name < names + len; i++) {
+        virStorageVolDefPtr vol;
+        VIR_ALLOC(vol);
+
+        vol->name = strdup(name);
+        name += strlen(name) + 1;
+
+        volStorageBackendRBDRefreshVolInfo(vol, pool, ptr);
+        pool->volumes.objs[pool->volumes.count++] = vol;
+    }
+
+    virStorageBackendRBDCloseRADOSConn(ptr);
+
+    return 0;
+}
+
+static int virStorageBackendRBDDeleteVol(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol, unsigned int flags) {
+    virStorageBackendRBDPtr ptr;
+    rados_ioctx_t ioctx;
+
+    if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, pool) < 0) {
+        return -1;
+    }
+
+    if (rados_ioctx_create(ptr.cluster, pool->def->source.name, &ioctx) < 0) {
+        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("failed to create the RBD IoCTX. Does the pool '%s' exist?"),
+                               pool->def->source.name);
+        return -1;
+    }
+
+    if (rbd_remove(ioctx, vol->name) < 0) {
+        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("failed to remove volume '%s/%s'"),
+                               pool->def->source.name,
+                               vol->name);
+        return -1;
+    }
+
+    rados_ioctx_destroy(ioctx);
+    virStorageBackendRBDCloseRADOSConn(ptr);
+    return 0;
+}
+
+static int virStorageBackendRBDCreateVol(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol) {
+    virStorageBackendRBDPtr ptr;
+    rados_ioctx_t ioctx;
+    int order = 0;
+
+    if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, pool) < 0) {
+        return -1;
+    }
+
+    if (rados_ioctx_create(ptr.cluster, pool->def->source.name, &ioctx) < 0) {
+        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("failed to create the RBD IoCTX. Does the pool '%s' exist?"),
+                               pool->def->source.name);
+        return -1;
+    }
+
+    if (vol->target.encryption != NULL) {
+        virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                              "%s", _("storage pool does not support encrypted volumes"));
+        return -1;
+    }
+
+    vol->type = VIR_STORAGE_VOL_NETWORK;
+
+    if (rbd_create(ioctx, vol->name, vol->capacity, &order) < 0) {
+        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("failed to create volume '%s/%s'"),
+                               pool->def->source.name,
+                               vol->name);
+        return -1;
+    }
+
+    rados_ioctx_destroy(ioctx);
+    virStorageBackendRBDCloseRADOSConn(ptr);
+    return 0;
+}
+
+static int virStorageBackendRBDRefreshVol(virConnectPtr conn, virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, virStorageVolDefPtr vol) {
+    virStorageBackendRBDPtr ptr;
+
+    if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, pool) < 0) {
+        return -1;
+    }
+
+    if (rados_ioctx_create(ptr.cluster, pool->def->source.name, &ptr.ioctx) < 0) {
+        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("failed to create the RBD IoCTX. Does the pool '%s' exist?"),
+                               pool->def->source.name);
+        return -1;
+    }
+    
+    volStorageBackendRBDRefreshVolInfo(vol, pool, ptr);
+    virStorageBackendRBDCloseRADOSConn(ptr);
+
+    return 0;
+}
+
+static int virStorageBackendRBDBuildVol(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol, virStorageVolDefPtr inputvol) {
+    return 0;
+}
+
+static int virStorageBackendRBDBuildVolFrom(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol, virStorageVolDefPtr inputvol, unsigned int flags) {
+    return 0;
+}
+
+virStorageBackend virStorageBackendRBD = {
+    .type = VIR_STORAGE_POOL_RBD,
+
+    .findPoolSources = virStorageBackendRBDFindPoolSources,
+    .refreshPool = virStorageBackendRBDRefreshPool,
+    .buildVol = virStorageBackendRBDBuildVol,
+    .buildVolFrom = virStorageBackendRBDBuildVolFrom,
+    .createVol = virStorageBackendRBDCreateVol,
+    .refreshVol = virStorageBackendRBDRefreshVol,
+    .deleteVol = virStorageBackendRBDDeleteVol,
+};
diff --git a/src/storage/storage_backend_rbd.h b/src/storage/storage_backend_rbd.h
new file mode 100644 (file)
index 0000000..a624ba0
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * storage_backend_rbd.h: storage backend for RBD (RADOS Block Device) handling
+ *
+ * Copyright (C) 2011 Wido den Hollander
+ *
+ * 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>
+ */
+
+#ifndef __VIR_STORAGE_BACKEND_RBD_H__
+# define __VIR_STORAGE_BACKEND_RBD_H__
+
+# include "storage_backend.h"
+
+extern virStorageBackend virStorageBackendRBD;
+
+#endif /* __VIR_STORAGE_BACKEND_RBD_H__ */
index 02f2e0d..532fc66 100644 (file)
@@ -10839,6 +10839,10 @@ cmdVolInfo(vshControl *ctl, const vshCmd *cmd)
             vshPrint(ctl, "%-15s %s\n", _("Type:"), _("dir"));
             break;
 
+        case VIR_STORAGE_VOL_NETWORK:
+            vshPrint(ctl, "%-15s %s\n", _("Type:"), _("network"));
+            break;
+
         default:
             vshPrint(ctl, "%-15s %s\n", _("Type:"), _("unknown"));
         }
@@ -18159,6 +18163,9 @@ vshShowVersion(vshControl *ctl ATTRIBUTE_UNUSED)
 #ifdef WITH_STORAGE_LVM
     vshPrint(ctl, " LVM");
 #endif
+#ifdef WITH_STORAGE_RBD
+    vshPrint(ctl, " RBD");
+#endif
     vshPrint(ctl, "\n");
 
     vshPrint(ctl, "%s", _(" Miscellaneous:"));