diff mbox

[4/4] libxl: add support for rbd qdisk

Message ID 1455659159-11931-5-git-send-email-jfehlig@suse.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jim Fehlig Feb. 16, 2016, 9:45 p.m. UTC
xl/libxl already supports qemu's network-based block backends
such as nbd and rbd. libvirt has supported configuring such
<disk>s for long time too. This patch adds support for rbd
disks in the libxl driver by generating a rbd device URL from
the virDomainDiskDef object. The URL is passed to libxl via the
pdev_path field of libxl_device_disk struct. libxl then passes
the URL to qemu for cosumption by the rbd backend.

Signed-off-by: Jim Fehlig <jfehlig@suse.com>
---
 src/libxl/libxl_conf.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 191 insertions(+), 1 deletion(-)

Comments

Daniel P. Berrangé Feb. 26, 2016, 5:44 p.m. UTC | #1
On Tue, Feb 16, 2016 at 02:45:59PM -0700, Jim Fehlig wrote:
> xl/libxl already supports qemu's network-based block backends
> such as nbd and rbd. libvirt has supported configuring such
> <disk>s for long time too. This patch adds support for rbd
> disks in the libxl driver by generating a rbd device URL from
> the virDomainDiskDef object. The URL is passed to libxl via the
> pdev_path field of libxl_device_disk struct. libxl then passes
> the URL to qemu for cosumption by the rbd backend.
> 
> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
> ---
>  src/libxl/libxl_conf.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 191 insertions(+), 1 deletion(-)

ACK


Regards,
Daniel
diff mbox

Patch

diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c
index 48b77d2..5133299 100644
--- a/src/libxl/libxl_conf.c
+++ b/src/libxl/libxl_conf.c
@@ -46,6 +46,7 @@ 
 #include "libxl_conf.h"
 #include "libxl_utils.h"
 #include "virstoragefile.h"
+#include "base64.h"
 
 
 #define VIR_FROM_THIS VIR_FROM_LIBXL
@@ -920,17 +921,206 @@  libxlDomainGetEmulatorType(const virDomainDef *def)
     return ret;
 }
 
+static char *
+libxlGetSecretString(virConnectPtr conn,
+                     const char *scheme,
+                     bool encoded,
+                     virStorageAuthDefPtr authdef,
+                     virSecretUsageType secretUsageType)
+{
+    size_t secret_size;
+    virSecretPtr sec = NULL;
+    char *secret = NULL;
+    char uuidStr[VIR_UUID_STRING_BUFLEN];
+
+    /* look up secret */
+    switch (authdef->secretType) {
+    case VIR_STORAGE_SECRET_TYPE_UUID:
+        sec = virSecretLookupByUUID(conn, authdef->secret.uuid);
+        virUUIDFormat(authdef->secret.uuid, uuidStr);
+        break;
+    case VIR_STORAGE_SECRET_TYPE_USAGE:
+        sec = virSecretLookupByUsage(conn, secretUsageType,
+                                     authdef->secret.usage);
+        break;
+    }
+
+    if (!sec) {
+        if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_UUID) {
+            virReportError(VIR_ERR_NO_SECRET,
+                           _("%s no secret matches uuid '%s'"),
+                           scheme, uuidStr);
+        } else {
+            virReportError(VIR_ERR_NO_SECRET,
+                           _("%s no secret matches usage value '%s'"),
+                           scheme, authdef->secret.usage);
+        }
+        goto cleanup;
+    }
+
+    secret = (char *)conn->secretDriver->secretGetValue(sec, &secret_size, 0,
+                                                        VIR_SECRET_GET_VALUE_INTERNAL_CALL);
+    if (!secret) {
+        if (authdef->secretType == VIR_STORAGE_SECRET_TYPE_UUID) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("could not get value of the secret for "
+                             "username '%s' using uuid '%s'"),
+                           authdef->username, uuidStr);
+        } else {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("could not get value of the secret for "
+                             "username '%s' using usage value '%s'"),
+                           authdef->username, authdef->secret.usage);
+        }
+        goto cleanup;
+    }
+
+    if (encoded) {
+        char *base64 = NULL;
+
+        base64_encode_alloc(secret, secret_size, &base64);
+        VIR_FREE(secret);
+        if (!base64) {
+            virReportOOMError();
+            goto cleanup;
+        }
+        secret = base64;
+    }
+
+ cleanup:
+    virObjectUnref(sec);
+    return secret;
+}
+
+static char *
+libxlMakeNetworkDiskSrcStr(virStorageSourcePtr src,
+                           const char *username,
+                           const char *secret)
+{
+    char *ret = NULL;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    size_t i;
+
+    switch ((virStorageNetProtocol) src->protocol) {
+    case VIR_STORAGE_NET_PROTOCOL_NBD:
+    case VIR_STORAGE_NET_PROTOCOL_HTTP:
+    case VIR_STORAGE_NET_PROTOCOL_HTTPS:
+    case VIR_STORAGE_NET_PROTOCOL_FTP:
+    case VIR_STORAGE_NET_PROTOCOL_FTPS:
+    case VIR_STORAGE_NET_PROTOCOL_TFTP:
+    case VIR_STORAGE_NET_PROTOCOL_ISCSI:
+    case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
+    case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
+    case VIR_STORAGE_NET_PROTOCOL_LAST:
+    case VIR_STORAGE_NET_PROTOCOL_NONE:
+        virReportError(VIR_ERR_NO_SUPPORT,
+                       _("Unsupported network block protocol '%s'"),
+                       virStorageNetProtocolTypeToString(src->protocol));
+        goto cleanup;
+
+    case VIR_STORAGE_NET_PROTOCOL_RBD:
+        if (strchr(src->path, ':')) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("':' not allowed in RBD source volume name '%s'"),
+                           src->path);
+            goto cleanup;
+        }
+
+        virBufferStrcat(&buf, "rbd:", src->path, NULL);
+
+        if (username) {
+            virBufferEscape(&buf, '\\', ":", ":id=%s", username);
+            virBufferEscape(&buf, '\\', ":",
+                            ":key=%s:auth_supported=cephx\\;none",
+                            secret);
+        } else {
+            virBufferAddLit(&buf, ":auth_supported=none");
+        }
+
+        if (src->nhosts > 0) {
+            virBufferAddLit(&buf, ":mon_host=");
+            for (i = 0; i < src->nhosts; i++) {
+                if (i)
+                    virBufferAddLit(&buf, "\\;");
+
+                /* assume host containing : is ipv6 */
+                if (strchr(src->hosts[i].name, ':'))
+                    virBufferEscape(&buf, '\\', ":", "[%s]",
+                                    src->hosts[i].name);
+                else
+                    virBufferAsprintf(&buf, "%s", src->hosts[i].name);
+
+                if (src->hosts[i].port)
+                    virBufferAsprintf(&buf, "\\:%s", src->hosts[i].port);
+            }
+        }
+
+        if (src->configFile)
+            virBufferEscape(&buf, '\\', ":", ":conf=%s", src->configFile);
+
+        if (virBufferCheckError(&buf) < 0)
+            goto cleanup;
+
+        ret = virBufferContentAndReset(&buf);
+        break;
+    }
+
+ cleanup:
+    virBufferFreeAndReset(&buf);
+    return ret;
+}
+
+static int
+libxlMakeNetworkDiskSrc(virStorageSourcePtr src, char **srcstr)
+{
+    virConnectPtr conn = NULL;
+    char *secret = NULL;
+    char *username = NULL;
+    int ret = -1;
+
+    *srcstr = NULL;
+    if (src->auth && src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD) {
+        const char *protocol = virStorageNetProtocolTypeToString(src->protocol);
+
+        username = src->auth->username;
+        if (!(conn = virConnectOpen("xen:///system")))
+            goto cleanup;
+
+        if (!(secret = libxlGetSecretString(conn,
+                                            protocol,
+                                            true,
+                                            src->auth,
+                                            VIR_SECRET_USAGE_TYPE_CEPH)))
+            goto cleanup;
+    }
+
+    if (!(*srcstr = libxlMakeNetworkDiskSrcStr(src, username, secret)))
+            goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    VIR_FREE(secret);
+    virObjectUnref(conn);
+    return ret;
+}
 
 int
 libxlMakeDisk(virDomainDiskDefPtr l_disk, libxl_device_disk *x_disk)
 {
     const char *driver;
     int format;
+    int actual_type = virStorageSourceGetActualType(l_disk->src);
 
     libxl_device_disk_init(x_disk);
 
-    if (VIR_STRDUP(x_disk->pdev_path, virDomainDiskGetSource(l_disk)) < 0)
+    if (actual_type == VIR_STORAGE_TYPE_NETWORK) {
+        if (libxlMakeNetworkDiskSrc(l_disk->src, &x_disk->pdev_path) < 0)
+            return -1;
+    } else {
+        if (VIR_STRDUP(x_disk->pdev_path, virDomainDiskGetSource(l_disk)) < 0)
         return -1;
+    }
 
     if (VIR_STRDUP(x_disk->vdev, l_disk->dst) < 0)
         return -1;