#include "domain_conf.h"
#include "network/bridge_driver.h"
#include "virnetdevtap.h"
+#include "base64.h"
#include <sys/utsname.h>
#include <sys/stat.h>
return 0;
}
+static int
+qemuBuildRBDString(virConnectPtr conn,
+ virDomainDiskDefPtr disk,
+ virBufferPtr opt)
+{
+ int i, ret = 0;
+ virSecretPtr sec = NULL;
+ char *secret = NULL;
+ size_t secret_size;
+
+ virBufferAsprintf(opt, "rbd:%s", disk->src);
+ if (disk->auth.username) {
+ virBufferEscape(opt, ":", ":id=%s", disk->auth.username);
+ /* look up secret */
+ switch (disk->auth.secretType) {
+ case VIR_DOMAIN_DISK_SECRET_TYPE_UUID:
+ sec = virSecretLookupByUUID(conn,
+ disk->auth.secret.uuid);
+ break;
+ case VIR_DOMAIN_DISK_SECRET_TYPE_USAGE:
+ sec = virSecretLookupByUsage(conn,
+ VIR_SECRET_USAGE_TYPE_CEPH,
+ disk->auth.secret.usage);
+ break;
+ }
+
+ if (sec) {
+ char *base64 = NULL;
+
+ secret = (char *)conn->secretDriver->getValue(sec, &secret_size, 0,
+ VIR_SECRET_GET_VALUE_INTERNAL_CALL);
+ if (secret == NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("could not get the value of the secret for username %s"),
+ disk->auth.username);
+ goto error;
+ }
+ /* qemu/librbd wants it base64 encoded */
+ base64_encode_alloc(secret, secret_size, &base64);
+ if (!base64) {
+ virReportOOMError();
+ goto error;
+ }
+ virBufferEscape(opt, ":", ":key=%s:auth_supported=cephx none",
+ base64);
+ VIR_FREE(base64);
+ } else {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("rbd username '%s' specified but secret not found"),
+ disk->auth.username);
+ goto error;
+ }
+ }
+
+ if (disk->nhosts > 0) {
+ virBufferAddLit(opt, ":mon_host=");
+ for (i = 0; i < disk->nhosts; ++i) {
+ if (i) {
+ virBufferAddLit(opt, "\\;");
+ }
+ if (disk->hosts[i].port) {
+ virBufferAsprintf(opt, "%s\\:%s",
+ disk->hosts[i].name,
+ disk->hosts[i].port);
+ } else {
+ virBufferAsprintf(opt, "%s", disk->hosts[i].name);
+ }
+ }
+ }
+
+cleanup:
+ VIR_FREE(secret);
+ if (sec)
+ virUnrefSecret(sec);
+
+ return ret;
+
+error:
+ ret = -1;
+ goto cleanup;
+}
+
+static int qemuAddRBDHost(virDomainDiskDefPtr disk, char *hostport)
+{
+ char *port;
+
+ disk->nhosts++;
+ if (VIR_REALLOC_N(disk->hosts, disk->nhosts) < 0)
+ goto no_memory;
+
+ port = strstr(hostport, "\\:");
+ if (port) {
+ *port = '\0';
+ port += 2;
+ disk->hosts[disk->nhosts-1].port = strdup(port);
+ if (!disk->hosts[disk->nhosts-1].port)
+ goto no_memory;
+ } else {
+ disk->hosts[disk->nhosts-1].port = strdup("6789");
+ if (!disk->hosts[disk->nhosts-1].port)
+ goto no_memory;
+ }
+ disk->hosts[disk->nhosts-1].name = strdup(hostport);
+ if (!disk->hosts[disk->nhosts-1].name)
+ goto no_memory;
+ return 0;
+
+no_memory:
+ virReportOOMError();
+ VIR_FREE(disk->hosts[disk->nhosts-1].port);
+ VIR_FREE(disk->hosts[disk->nhosts-1].name);
+ return -1;
+}
+
+/* disk->src initially has everything after the rbd: prefix */
+static int qemuParseRBDString(virDomainDiskDefPtr disk)
+{
+ char *options = NULL;
+ char *p, *e, *next;
+
+ p = strchr(disk->src, ':');
+ if (p) {
+ options = strdup(p + 1);
+ if (!options)
+ goto no_memory;
+ *p = '\0';
+ }
+
+ /* options */
+ if (!options)
+ return 0; /* all done */
+
+ p = options;
+ while (*p) {
+ /* find : delimiter or end of string */
+ for (e = p; *e && *e != ':'; ++e) {
+ if (*e == '\\') {
+ e++;
+ if (*e == '\0')
+ break;
+ }
+ }
+ if (*e == '\0') {
+ next = e; /* last kv pair */
+ } else {
+ next = e + 1;
+ *e = '\0';
+ }
+
+ if (STRPREFIX(p, "id=")) {
+ disk->auth.username = strdup(p + strlen("id="));
+ if (!disk->auth.username)
+ goto no_memory;
+ }
+ if (STRPREFIX(p, "mon_host=")) {
+ char *h, *sep;
+
+ h = p + strlen("mon_host=");
+ while (h < e) {
+ for (sep = h; sep < e; ++sep) {
+ if (*sep == '\\' && (sep[1] == ',' ||
+ sep[1] == ';' ||
+ sep[1] == ' ')) {
+ *sep = '\0';
+ sep += 2;
+ break;
+ }
+ }
+ if (qemuAddRBDHost(disk, h) < 0) {
+ return -1;
+ }
+ h = sep;
+ }
+ }
+
+ p = next;
+ }
+ return 0;
+
+no_memory:
+ virReportOOMError();
+ return -1;
+}
char *
qemuBuildDriveStr(virConnectPtr conn ATTRIBUTE_UNUSED,
disk->hosts->name, disk->hosts->port);
break;
case VIR_DOMAIN_DISK_PROTOCOL_RBD:
- /* TODO: set monitor hostnames */
- virBufferAsprintf(&opt, "file=rbd:%s,", disk->src);
+ virBufferAddLit(&opt, "file=");
+ if (qemuBuildRBDString(conn, disk, &opt) < 0)
+ goto error;
+ virBufferAddChar(&opt, ',');
break;
case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
if (disk->nhosts == 0)
int last_good_net = -1;
bool hasHwVirt = false;
virCommandPtr cmd;
- bool has_rbd_hosts = false;
- virBuffer rbd_hosts = VIR_BUFFER_INITIALIZER;
bool emitBootindex = false;
int usbcontroller = 0;
bool usblegacy = false;
virDomainDiskDefPtr disk = def->disks[i];
int withDeviceArg = 0;
bool deviceFlagMasked = false;
- int j;
/* Unless we have -device, then USB disks need special
handling */
virCommandAddArg(cmd, optstr);
VIR_FREE(optstr);
- if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
- disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD) {
- for (j = 0 ; j < disk->nhosts ; j++) {
- if (!has_rbd_hosts) {
- virBufferAddLit(&rbd_hosts, "CEPH_ARGS=-m ");
- has_rbd_hosts = true;
- } else {
- virBufferAddLit(&rbd_hosts, ",");
- }
- virDomainDiskHostDefPtr host = &disk->hosts[j];
- if (host->port) {
- virBufferAsprintf(&rbd_hosts, "%s:%s",
- host->name,
- host->port);
- } else {
- virBufferAdd(&rbd_hosts, host->name, -1);
- }
- }
- }
-
if (!emitBootindex)
bootindex = 0;
else if (disk->bootIndex)
char *file;
const char *fmt;
virDomainDiskDefPtr disk = def->disks[i];
- int j;
if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
}
break;
case VIR_DOMAIN_DISK_PROTOCOL_RBD:
- if (virAsprintf(&file, "rbd:%s,", disk->src) < 0) {
- goto no_memory;
- }
- for (j = 0 ; j < disk->nhosts ; j++) {
- if (!has_rbd_hosts) {
- virBufferAddLit(&rbd_hosts, "CEPH_ARGS=-m ");
- has_rbd_hosts = true;
- } else {
- virBufferAddLit(&rbd_hosts, ",");
- }
- virDomainDiskHostDefPtr host = &disk->hosts[j];
- if (host->port) {
- virBufferAsprintf(&rbd_hosts, "%s:%s",
- host->name,
- host->port);
- } else {
- virBufferAdd(&rbd_hosts, host->name, -1);
+ {
+ virBuffer opt = VIR_BUFFER_INITIALIZER;
+ if (qemuBuildRBDString(conn, disk, &opt) < 0)
+ goto error;
+ if (virBufferError(&opt)) {
+ virReportOOMError();
+ goto error;
}
+ file = virBufferContentAndReset(&opt);
}
break;
case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
}
}
- if (has_rbd_hosts)
- virCommandAddEnvBuffer(cmd, &rbd_hosts);
-
if (qemuCapsGet(qemuCaps, QEMU_CAPS_FSDEV)) {
for (i = 0 ; i < def->nfss ; i++) {
char *optstr;
networkReleaseActualDevice(def->nets[i]);
for (i = 0; i <= last_good_net; i++)
virDomainConfNWFilterTeardown(def->nets[i]);
- virBufferFreeAndReset(&rbd_hosts);
virCommandFree(cmd);
return NULL;
}
static virDomainDiskDefPtr
qemuParseCommandLineDisk(virCapsPtr caps,
const char *val,
- int nvirtiodisk)
+ int nvirtiodisk,
+ bool old_style_ceph_args)
{
virDomainDiskDefPtr def = NULL;
char **keywords;
virReportOOMError();
goto cleanup;
}
+ /* old-style CEPH_ARGS env variable is parsed later */
+ if (!old_style_ceph_args && qemuParseRBDString(def) < 0)
+ goto cleanup;
VIR_FREE(p);
} else if (STRPREFIX(def->src, "sheepdog:")) {
int nvirtiodisk = 0;
qemuDomainCmdlineDefPtr cmd = NULL;
virDomainDiskDefPtr disk = NULL;
+ const char *ceph_args = qemuFindEnv(progenv, "CEPH_ARGS");
if (pidfile)
*pidfile = NULL;
disk->src = NULL;
break;
case VIR_DOMAIN_DISK_PROTOCOL_RBD:
- /* handled later since the hosts for all disks are in CEPH_ARGS */
+ /* old-style CEPH_ARGS env variable is parsed later */
+ if (!ceph_args && qemuParseRBDString(disk) < 0)
+ goto error;
break;
case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
/* disk->src must be [vdiname] or [host]:[port]:[vdiname] */
}
} else if (STREQ(arg, "-drive")) {
WANT_VALUE();
- if (!(disk = qemuParseCommandLineDisk(caps, val, nvirtiodisk)))
+ if (!(disk = qemuParseCommandLineDisk(caps, val, nvirtiodisk,
+ ceph_args != NULL)))
goto error;
if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
goto no_memory;
}
#undef WANT_VALUE
- if (def->ndisks > 0) {
- const char *ceph_args = qemuFindEnv(progenv, "CEPH_ARGS");
- if (ceph_args) {
- char *hosts, *port, *saveptr = NULL, *token;
- virDomainDiskDefPtr first_rbd_disk = NULL;
- for (i = 0 ; i < def->ndisks ; i++) {
- if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
- def->disks[i]->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD) {
- first_rbd_disk = def->disks[i];
- break;
- }
+ if (def->ndisks > 0 && ceph_args) {
+ char *hosts, *port, *saveptr = NULL, *token;
+ virDomainDiskDefPtr first_rbd_disk = NULL;
+ for (i = 0 ; i < def->ndisks ; i++) {
+ if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
+ def->disks[i]->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD) {
+ first_rbd_disk = def->disks[i];
+ break;
}
+ }
- if (!first_rbd_disk) {
- qemuReportError(VIR_ERR_INTERNAL_ERROR,
- _("CEPH_ARGS was set without an rbd disk"));
- goto error;
- }
+ if (!first_rbd_disk) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("CEPH_ARGS was set without an rbd disk"));
+ goto error;
+ }
- /* CEPH_ARGS should be: -m host1[:port1][,host2[:port2]]... */
- if (!STRPREFIX(ceph_args, "-m ")) {
- qemuReportError(VIR_ERR_INTERNAL_ERROR,
- _("could not parse CEPH_ARGS '%s'"), ceph_args);
- goto error;
- }
- hosts = strdup(strchr(ceph_args, ' ') + 1);
- if (!hosts)
+ /* CEPH_ARGS should be: -m host1[:port1][,host2[:port2]]... */
+ if (!STRPREFIX(ceph_args, "-m ")) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("could not parse CEPH_ARGS '%s'"), ceph_args);
+ goto error;
+ }
+ hosts = strdup(strchr(ceph_args, ' ') + 1);
+ if (!hosts)
+ goto no_memory;
+ first_rbd_disk->nhosts = 0;
+ token = strtok_r(hosts, ",", &saveptr);
+ while (token != NULL) {
+ if (VIR_REALLOC_N(first_rbd_disk->hosts, first_rbd_disk->nhosts + 1) < 0) {
+ VIR_FREE(hosts);
goto no_memory;
- first_rbd_disk->nhosts = 0;
- token = strtok_r(hosts, ",", &saveptr);
- while (token != NULL) {
- if (VIR_REALLOC_N(first_rbd_disk->hosts, first_rbd_disk->nhosts + 1) < 0) {
- VIR_FREE(hosts);
- goto no_memory;
- }
- port = strchr(token, ':');
- if (port) {
- *port++ = '\0';
- port = strdup(port);
- if (!port) {
- VIR_FREE(hosts);
- goto no_memory;
- }
- }
- first_rbd_disk->hosts[first_rbd_disk->nhosts].port = port;
- first_rbd_disk->hosts[first_rbd_disk->nhosts].name = strdup(token);
- if (!first_rbd_disk->hosts[first_rbd_disk->nhosts].name) {
+ }
+ port = strchr(token, ':');
+ if (port) {
+ *port++ = '\0';
+ port = strdup(port);
+ if (!port) {
VIR_FREE(hosts);
goto no_memory;
}
- first_rbd_disk->nhosts++;
- token = strtok_r(NULL, ",", &saveptr);
}
- VIR_FREE(hosts);
-
- if (first_rbd_disk->nhosts == 0) {
- qemuReportError(VIR_ERR_INTERNAL_ERROR,
- _("found no rbd hosts in CEPH_ARGS '%s'"), ceph_args);
- goto error;
+ first_rbd_disk->hosts[first_rbd_disk->nhosts].port = port;
+ first_rbd_disk->hosts[first_rbd_disk->nhosts].name = strdup(token);
+ if (!first_rbd_disk->hosts[first_rbd_disk->nhosts].name) {
+ VIR_FREE(hosts);
+ goto no_memory;
}
+ first_rbd_disk->nhosts++;
+ token = strtok_r(NULL, ",", &saveptr);
+ }
+ VIR_FREE(hosts);
+
+ if (first_rbd_disk->nhosts == 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("found no rbd hosts in CEPH_ARGS '%s'"), ceph_args);
+ goto error;
}
}