Changes common to all network disks:
-Make source name optional in the domain schema, since NBD doesn't use it
-Add a hostName type to the domain schema, and use it instead of genericName, which
doesn't include .
-Don't leak host names or ports
-Set the source protocol in qemuParseCommandline
Signed-off-by: Josh Durgin <joshd(a)hq.newdream.net>
---
docs/schemas/domain.rng | 11 +++-
src/conf/domain_conf.c | 25 +++++++-
src/conf/domain_conf.h | 1 +
src/qemu/qemu_conf.c | 143 ++++++++++++++++++++++++++++++++++++++++++++---
4 files changed, 165 insertions(+), 15 deletions(-)
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index 4463884..51aae14 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -626,11 +626,13 @@
<value>sheepdog</value>
</choice>
</attribute>
- <attribute name="name"/>
+ <optional>
+ <attribute name="name"/>
+ </optional>
<zeroOrMore>
<element name="host">
<attribute name="name">
- <ref name="genericName"/>
+ <ref name="hostName"/>
</attribute>
<attribute name="port">
<ref name="unsignedInt"/>
@@ -2024,6 +2026,11 @@
<param name="minInclusive">1</param>
</data>
</define>
+ <define name="hostName">
+ <data type="string">
+ <param name="pattern">[a-zA-Z0-9\.\-]+</param>
+ </data>
+ </define>
<define name="PortNumber">
<data type="short">
<param name="minInclusive">-1</param>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 5e2422b..6b4320a 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -508,21 +508,34 @@ void virDomainInputDefFree(virDomainInputDefPtr def)
void virDomainDiskDefFree(virDomainDiskDefPtr def)
{
+ unsigned int i;
+
if (!def)
return;
VIR_FREE(def->serial);
VIR_FREE(def->src);
- VIR_FREE(def->hosts);
VIR_FREE(def->dst);
VIR_FREE(def->driverName);
VIR_FREE(def->driverType);
virStorageEncryptionFree(def->encryption);
virDomainDeviceInfoClear(&def->info);
+ for (i = 0 ; i < def->nhosts ; i++)
+ virDomainDiskHostDefFree(&def->hosts[i]);
+
VIR_FREE(def);
}
+void virDomainDiskHostDefFree(virDomainDiskHostDefPtr def)
+{
+ if (!def)
+ return;
+
+ VIR_FREE(def->name);
+ VIR_FREE(def->port);
+}
+
void virDomainControllerDefFree(virDomainControllerDefPtr def)
{
if (!def)
@@ -1643,7 +1656,12 @@ virDomainDiskDefParseXML(virCapsPtr caps,
protocol);
goto error;
}
- source = virXMLPropString(cur, "name");
+ if (!(source = virXMLPropString(cur, "name")) &&
+ def->protocol != VIR_DOMAIN_DISK_PROTOCOL_NBD) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("missing name for disk
source"));
+ goto error;
+ }
host = cur->children;
while (host != NULL) {
if (host->type == XML_ELEMENT_NODE &&
@@ -1876,8 +1894,7 @@ cleanup:
VIR_FREE(target);
VIR_FREE(source);
while (nhosts > 0) {
- VIR_FREE(hosts[nhosts - 1].name);
- VIR_FREE(hosts[nhosts - 1].port);
+ virDomainDiskHostDefFree(&hosts[nhosts - 1]);
nhosts--;
}
VIR_FREE(hosts);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 6c97289..c1e39ba 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1070,6 +1070,7 @@ virDomainObjPtr virDomainFindByName(const virDomainObjListPtr doms,
void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def);
void virDomainInputDefFree(virDomainInputDefPtr def);
void virDomainDiskDefFree(virDomainDiskDefPtr def);
+void virDomainDiskHostDefFree(virDomainDiskHostDefPtr def);
void virDomainControllerDefFree(virDomainControllerDefPtr def);
void virDomainFSDefFree(virDomainFSDefPtr def);
void virDomainNetDefFree(virDomainNetDefPtr def);
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 55e193f..d1368dc 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -4010,6 +4010,8 @@ qemudBuildCommandLine(virConnectPtr conn,
int last_good_net = -1;
bool hasHwVirt = false;
virCommandPtr cmd;
+ bool has_rbd_hosts = false;
+ virBuffer rbd_hosts = VIR_BUFFER_INITIALIZER;
uname_normalize(&ut);
@@ -4550,6 +4552,7 @@ qemudBuildCommandLine(virConnectPtr conn,
int bootable = 0;
virDomainDiskDefPtr disk = def->disks[i];
int withDeviceArg = 0;
+ int j;
/* Unless we have -device, then USB disks need special
handling */
@@ -4599,6 +4602,27 @@ qemudBuildCommandLine(virConnectPtr conn,
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, "-m ");
+ has_rbd_hosts = true;
+ } else {
+ virBufferAddLit(&rbd_hosts, ",");
+ }
+ virDomainDiskHostDefPtr host = &disk->hosts[j];
+ if (host->port) {
+ virBufferVSprintf(&rbd_hosts, "%s:%s",
+ host->name,
+ host->port);
+ } else {
+ virBufferVSprintf(&rbd_hosts, "%s",
+ host->name);
+ }
+ }
+ }
+
if (withDeviceArg) {
if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
virCommandAddArg(cmd, "-global");
@@ -4621,6 +4645,7 @@ qemudBuildCommandLine(virConnectPtr conn,
char dev[NAME_MAX];
char file[PATH_MAX];
virDomainDiskDefPtr disk = def->disks[i];
+ int j;
if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
@@ -4684,6 +4709,23 @@ qemudBuildCommandLine(virConnectPtr conn,
break;
case VIR_DOMAIN_DISK_PROTOCOL_RBD:
snprintf(file, PATH_MAX, "rbd:%s,", disk->src);
+ for (j = 0 ; j < disk->nhosts ; j++) {
+ if (!has_rbd_hosts) {
+ virBufferAddLit(&rbd_hosts, "-m ");
+ has_rbd_hosts = true;
+ } else {
+ virBufferAddLit(&rbd_hosts, ",");
+ }
+ virDomainDiskHostDefPtr host = &disk->hosts[j];
+ if (host->port) {
+ virBufferVSprintf(&rbd_hosts, "%s:%s",
+ host->name,
+ host->port);
+ } else {
+ virBufferVSprintf(&rbd_hosts, "%s",
+ host->name);
+ }
+ }
break;
case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
if (disk->nhosts == 0)
@@ -4703,6 +4745,13 @@ qemudBuildCommandLine(virConnectPtr conn,
}
}
+ if (virBufferError(&rbd_hosts)) {
+ virBufferFreeAndReset(&rbd_hosts);
+ goto no_memory;
+ }
+ if (has_rbd_hosts)
+ virCommandAddEnvPair(cmd, "CEPH_ARGS",
virBufferContentAndReset(&rbd_hosts));
+
if (qemuCmdFlags & QEMUD_CMD_FLAG_FSDEV) {
for (i = 0 ; i < def->nfss ; i++) {
char *optstr;
@@ -5468,6 +5517,7 @@ static int qemuStringToArgvEnv(const char *args,
int envend;
int i;
const char *curr = args;
+ const char *start;
const char **progenv = NULL;
const char **progargv = NULL;
@@ -5475,14 +5525,22 @@ static int qemuStringToArgvEnv(const char *args,
while (curr && *curr != '\0') {
char *arg;
const char *next;
- if (*curr == '\'') {
- curr++;
- next = strchr(curr, '\'');
- } else if (*curr == '"') {
- curr++;
- next = strchr(curr, '"');
+
+ start = curr;
+ /* accept a space in CEPH_ARGS */
+ if (STRPREFIX(curr, "CEPH_ARGS=-m ")) {
+ start += strlen("CEPH_ARGS=-m ");
+ }
+ if (*start == '\'') {
+ if (start == curr)
+ curr++;
+ next = strchr(start + 1, '\'');
+ } else if (*start == '"') {
+ if (start == curr)
+ curr++;
+ next = strchr(start + 1, '"');
} else {
- next = strchr(curr, ' ');
+ next = strchr(start, ' ');
}
if (!next)
next = strchr(curr, '\n');
@@ -5712,6 +5770,7 @@ qemuParseCommandLineDisk(virCapsPtr caps,
char *host, *port;
def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+ def->protocol = VIR_DOMAIN_DISK_PROTOCOL_NBD;
host = def->src + strlen("nbd:");
port = strchr(host, ':');
if (!port) {
@@ -5743,6 +5802,7 @@ qemuParseCommandLineDisk(virCapsPtr caps,
char *p = def->src;
def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+ def->protocol = VIR_DOMAIN_DISK_PROTOCOL_RBD;
def->src = strdup(p + strlen("rbd:"));
if (!def->src) {
virReportOOMError();
@@ -5755,6 +5815,7 @@ qemuParseCommandLineDisk(virCapsPtr caps,
char *port, *vdi;
def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+ def->protocol = VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG;
def->src = strdup(p + strlen("sheepdog:"));
if (!def->src) {
virReportOOMError();
@@ -5870,7 +5931,8 @@ qemuParseCommandLineDisk(virCapsPtr caps,
}
if (!def->src &&
- def->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
+ def->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
+ def->type != VIR_DOMAIN_DISK_TYPE_NETWORK) {
qemuReportError(VIR_ERR_INTERNAL_ERROR,
_("missing file parameter in drive '%s'"),
val);
virDomainDiskDefFree(def);
@@ -6790,7 +6852,7 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
disk->src = NULL;
break;
case VIR_DOMAIN_DISK_PROTOCOL_RBD:
- /* TODO: set monitor hostnames */
+ /* handled later since the hosts for all disks are in CEPH_ARGS */
break;
case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
/* disk->src must be [vdiname] or [host]:[port]:[vdiname] */
@@ -7117,6 +7179,69 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
}
#undef WANT_VALUE
+ if (def->ndisks > 0) {
+ const char *ceph_args = qemuFindEnv(progenv, "CEPH_ARGS");
+ if (ceph_args) {
+ char *hosts, *port, *saveptr, *token;
+ virDomainDiskDefPtr first_rbd_disk = NULL;
+ for (i = 0 ; i < def->ndisks ; i++) {
+ virDomainDiskDefPtr disk = def->disks[i];
+ if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
+ disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD) {
+ first_rbd_disk = disk;
+ break;
+ }
+ }
+
+ 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)
+ 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) {
+ 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;
+ }
+ }
+ }
if (!nographics && def->ngraphics == 0) {
virDomainGraphicsDefPtr sdl;
--
1.5.6.5