<transient/>
<address type='drive' controller='0' bus='1' unit='0'/>
</disk>
+ <disk type='network'>
+ <driver name="qemu" type="raw"/>
+ <source protocol="rbd" name="image_name2">
+ <host name="hostname" port="7000"/>
+ </source>
+ <target dev="hdd" bus="ide"/>
+ <auth username='myuser'>
+ <secret type='ceph' usage='mypassid'/>
+ </auth>
+ </disk>
<disk type='block' device='cdrom'>
<driver name='qemu' type='raw'/>
<target def='hdc' bus='ide'/>
"drive" controller, additional attributes
<code>controller</code>, <code>bus</code>,
and <code>unit</code> are available, each defaulting to 0.
-
+ </dd>
+ <dt><code>auth</code></dt>
+ <dd>If present, the <code>auth</code> element provides the
+ authentication credentials needed to access the source. It
+ includes a mandatory attribute <code>username</code>, which
+ identifies the username to use during authentication, as well
+ as a sub-element <code>secret</code> with mandatory
+ attribute <code>type</code>, to tie back to
+ a <a href="formatsecret.html">libvirt secret object</a> that
+ holds the actual password or other credentials (the domain XML
+ intentionally does not expose the password, only the reference
+ to the object that does manage the password). For now, the
+ only known secret <code>type</code> is "ceph", for Ceph RBD
+ network sources, and requires either an
+ attribute <code>uuid</code> with the UUID of the Ceph secret
+ object, or an attribute <code>usage</code> with the name
+ associated with the Ceph secret
+ object. <span class="since">libvirt 0.9.7</span>
</dd>
</dl>
#include "virfile.h"
#include "bitmap.h"
#include "count-one-bits.h"
+#include "secret_conf.h"
#define VIR_FROM_THIS VIR_FROM_DOMAIN
"rbd",
"sheepdog")
+VIR_ENUM_IMPL(virDomainDiskSecretType, VIR_DOMAIN_DISK_SECRET_TYPE_LAST,
+ "none",
+ "uuid",
+ "usage")
+
VIR_ENUM_IMPL(virDomainDiskIo, VIR_DOMAIN_DISK_IO_LAST,
"default",
"native",
VIR_FREE(def->dst);
VIR_FREE(def->driverName);
VIR_FREE(def->driverType);
+ VIR_FREE(def->auth.username);
+ if (def->auth.secretType == VIR_DOMAIN_DISK_SECRET_TYPE_USAGE)
+ VIR_FREE(def->auth.secret.usage);
virStorageEncryptionFree(def->encryption);
virDomainDeviceInfoClear(&def->info);
unsigned int flags)
{
virDomainDiskDefPtr def;
- xmlNodePtr cur, host;
+ xmlNodePtr cur, child;
char *type = NULL;
char *device = NULL;
char *snapshot = NULL;
virStorageEncryptionPtr encryption = NULL;
char *serial = NULL;
char *startupPolicy = NULL;
+ char *authUsername = NULL;
+ char *authUsage = NULL;
+ char *authUUID = NULL;
+ char *usageType = NULL;
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
_("missing name for disk source"));
goto error;
}
- host = cur->children;
- while (host != NULL) {
- if (host->type == XML_ELEMENT_NODE &&
- xmlStrEqual(host->name, BAD_CAST "host")) {
+ child = cur->children;
+ while (child != NULL) {
+ if (child->type == XML_ELEMENT_NODE &&
+ xmlStrEqual(child->name, BAD_CAST "host")) {
if (VIR_REALLOC_N(hosts, nhosts + 1) < 0) {
virReportOOMError();
goto error;
hosts[nhosts].port = NULL;
nhosts++;
- hosts[nhosts - 1].name = virXMLPropString(host, "name");
+ hosts[nhosts - 1].name = virXMLPropString(child, "name");
if (!hosts[nhosts - 1].name) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("missing name for host"));
goto error;
}
- hosts[nhosts - 1].port = virXMLPropString(host, "port");
+ hosts[nhosts - 1].port = virXMLPropString(child, "port");
if (!hosts[nhosts - 1].port) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("missing port for host"));
goto error;
}
}
- host = host->next;
+ child = child->next;
}
break;
default:
iotag = virXMLPropString(cur, "io");
ioeventfd = virXMLPropString(cur, "ioeventfd");
event_idx = virXMLPropString(cur, "event_idx");
+ } else if (xmlStrEqual(cur->name, BAD_CAST "auth")) {
+ authUsername = virXMLPropString(cur, "username");
+ if (authUsername == NULL) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("missing username for auth"));
+ goto error;
+ }
+
+ def->auth.secretType = VIR_DOMAIN_DISK_SECRET_TYPE_NONE;
+ child = cur->children;
+ while (child != NULL) {
+ if (child->type == XML_ELEMENT_NODE &&
+ xmlStrEqual(child->name, BAD_CAST "secret")) {
+ usageType = virXMLPropString(child, "type");
+ if (usageType == NULL) {
+ virDomainReportError(VIR_ERR_XML_ERROR,
+ _("missing type for secret"));
+ goto error;
+ }
+ if (virSecretUsageTypeTypeFromString(usageType) !=
+ VIR_SECRET_USAGE_TYPE_CEPH) {
+ virDomainReportError(VIR_ERR_XML_ERROR,
+ _("invalid secret type %s"),
+ usageType);
+ goto error;
+ }
+
+ authUUID = virXMLPropString(child, "uuid");
+ authUsage = virXMLPropString(child, "usage");
+
+ if (authUUID != NULL && authUsage != NULL) {
+ virDomainReportError(VIR_ERR_XML_ERROR,
+ _("only one of uuid and usage can be specfied"));
+ goto error;
+ }
+ if (authUUID != NULL) {
+ def->auth.secretType = VIR_DOMAIN_DISK_SECRET_TYPE_UUID;
+ if (virUUIDParse(authUUID,
+ def->auth.secret.uuid) < 0) {
+ virDomainReportError(VIR_ERR_XML_ERROR,
+ _("malformed uuid %s"),
+ authUUID);
+ goto error;
+ }
+ } else if (authUsage != NULL) {
+ def->auth.secretType = VIR_DOMAIN_DISK_SECRET_TYPE_USAGE;
+ def->auth.secret.usage = authUsage;
+ authUsage = NULL;
+ }
+ }
+ child = child->next;
+ }
} else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
def->readonly = 1;
} else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
hosts = NULL;
def->nhosts = nhosts;
nhosts = 0;
+ def->auth.username = authUsername;
+ authUsername = NULL;
def->driverName = driverName;
driverName = NULL;
def->driverType = driverType;
VIR_FREE(hosts);
VIR_FREE(protocol);
VIR_FREE(device);
+ VIR_FREE(authUsername);
+ VIR_FREE(usageType);
+ VIR_FREE(authUUID);
+ VIR_FREE(authUsage);
VIR_FREE(driverType);
VIR_FREE(driverName);
VIR_FREE(cachetag);
const char *event_idx = virDomainVirtioEventIdxTypeToString(def->event_idx);
const char *startupPolicy = virDomainStartupPolicyTypeToString(def->startupPolicy);
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
if (!type) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected disk type %d"), def->type);
virBufferAddLit(buf, "/>\n");
}
+ if (def->auth.username) {
+ virBufferEscapeString(buf, " <auth username='%s'>\n",
+ def->auth.username);
+ if (def->auth.secretType == VIR_DOMAIN_DISK_SECRET_TYPE_UUID) {
+ virUUIDFormat(def->auth.secret.uuid, uuidstr);
+ virBufferAsprintf(buf,
+ " <secret type='ceph' uuid='%s'/>\n",
+ uuidstr);
+ }
+ if (def->auth.secretType == VIR_DOMAIN_DISK_SECRET_TYPE_USAGE) {
+ virBufferEscapeString(buf,
+ " <secret type='ceph' usage='%s'/>\n",
+ def->auth.secret.usage);
+ }
+ virBufferAddLit(buf, " </auth>\n");
+ }
+
if (def->src || def->nhosts > 0 ||
def->startupPolicy) {
switch (def->type) {