xenconfig: support xl<->xml conversion of rbd disk devices

The target= setting in xl disk configuration can be used to encode
meta info that is meaningful to a backend. Leverage this fact to
support qdisk network disk types such as rbd. E.g. <disk> config
such as

   <disk type='network' device='disk'>
     <driver name='qemu' type='raw'/>
     <source protocol='rbd' name='pool/image'>
       <host name='mon1.example.org' port='6321'/>
       <host name='mon2.example.org' port='6322'/>
       <host name='mon3.example.org' port='6322'/>
     </source>
     <target dev='hdb' bus='ide'/>
     <address type='drive' controller='0' bus='0' target='0' unit='1'/>
   </disk>

can be converted to the following xl config (and vice versa)

  disk = [ "format=raw,vdev=hdb,access=rw,backendtype=qdisk,
            target=rbd:pool/image:auth_supported=none:mon_host=mon1.example.org\\:6321\\;mon2.example.org\\:6322\\;mon3.example.org\\:6322"
         ]

Note that in xl disk config, a literal backslash in target= must
be escaped with a backslash. Conversion of <auth> config is not
handled in this patch, but can be done in a follow-up patch.

Also add a test for the conversions.

Signed-off-by: Jim Fehlig <jfehlig@suse.com>
This commit is contained in:
Jim Fehlig 2016-02-10 17:39:18 -07:00
parent a44f1f85f9
commit 6604a3dd9f
4 changed files with 224 additions and 6 deletions

View File

@ -246,6 +246,32 @@ xenParseXLSpice(virConfPtr conf, virDomainDefPtr def)
return -1;
}
static int
xenParseXLDiskSrc(virDomainDiskDefPtr disk, char *srcstr)
{
char *tmpstr = NULL;
int ret = -1;
if (STRPREFIX(srcstr, "rbd:")) {
tmpstr = virStringReplace(srcstr, "\\\\", "\\");
virDomainDiskSetType(disk, VIR_STORAGE_TYPE_NETWORK);
disk->src->protocol = VIR_STORAGE_NET_PROTOCOL_RBD;
ret = virStorageSourceParseRBDColonString(tmpstr, disk->src);
} else {
if (virDomainDiskSetSource(disk, srcstr) < 0)
goto cleanup;
ret = 0;
}
cleanup:
VIR_FREE(tmpstr);
return ret;
}
/*
* For details on xl disk config syntax, see
* docs/misc/xl-disk-configuration.txt in the Xen sources. The important
@ -311,10 +337,10 @@ xenParseXLDisk(virConfPtr conf, virDomainDefPtr def)
if (!(disk = virDomainDiskDefNew(NULL)))
goto fail;
if (VIR_STRDUP(disk->dst, libxldisk->vdev) < 0)
if (xenParseXLDiskSrc(disk, libxldisk->pdev_path) < 0)
goto fail;
if (virDomainDiskSetSource(disk, libxldisk->pdev_path) < 0)
if (VIR_STRDUP(disk->dst, libxldisk->vdev) < 0)
goto fail;
disk->src->readonly = !libxldisk->readwrite;
@ -358,7 +384,8 @@ xenParseXLDisk(virConfPtr conf, virDomainDefPtr def)
case LIBXL_DISK_BACKEND_UNKNOWN:
if (virDomainDiskSetDriver(disk, "qemu") < 0)
goto fail;
virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
if (virDomainDiskGetType(disk) == VIR_STORAGE_TYPE_NONE)
virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
break;
case LIBXL_DISK_BACKEND_TAP:
@ -578,14 +605,115 @@ xenFormatXLOS(virConfPtr conf, virDomainDefPtr def)
}
static char *
xenFormatXLDiskSrcNet(virStorageSourcePtr src)
{
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);
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 (virBufferCheckError(&buf) < 0)
goto cleanup;
ret = virBufferContentAndReset(&buf);
break;
}
cleanup:
virBufferFreeAndReset(&buf);
return ret;
}
static int
xenFormatXLDiskSrc(virStorageSourcePtr src, char **srcstr)
{
int actualType = virStorageSourceGetActualType(src);
*srcstr = NULL;
if (virStorageSourceIsEmpty(src))
return 0;
switch ((virStorageType) actualType) {
case VIR_STORAGE_TYPE_BLOCK:
case VIR_STORAGE_TYPE_FILE:
case VIR_STORAGE_TYPE_DIR:
if (VIR_STRDUP(*srcstr, src->path) < 0)
return -1;
break;
case VIR_STORAGE_TYPE_NETWORK:
if (!(*srcstr = xenFormatXLDiskSrcNet(src)))
return -1;
break;
case VIR_STORAGE_TYPE_VOLUME:
case VIR_STORAGE_TYPE_NONE:
case VIR_STORAGE_TYPE_LAST:
break;
}
return 0;
}
static int
xenFormatXLDisk(virConfValuePtr list, virDomainDiskDefPtr disk)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
virConfValuePtr val, tmp;
const char *src = virDomainDiskGetSource(disk);
int format = virDomainDiskGetFormat(disk);
const char *driver = virDomainDiskGetDriver(disk);
char *target = NULL;
/* format */
virBufferAddLit(&buf, "format=");
@ -637,8 +765,18 @@ xenFormatXLDisk(virConfValuePtr list, virDomainDiskDefPtr disk)
if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
virBufferAddLit(&buf, "devtype=cdrom,");
/* target */
virBufferAsprintf(&buf, "target=%s", src);
/*
* target
* From $xensrc/docs/misc/xl-disk-configuration.txt:
* When this parameter is specified by name, ie with the "target="
* syntax in the configuration file, it consumes the whole rest of the
* <diskspec> including trailing whitespaces. Therefore in that case
* it must come last.
*/
if (xenFormatXLDiskSrc(disk->src, &target) < 0)
goto cleanup;
virBufferAsprintf(&buf, "target=%s", target);
if (virBufferCheckError(&buf) < 0)
goto cleanup;
@ -658,6 +796,7 @@ xenFormatXLDisk(virConfValuePtr list, virDomainDiskDefPtr disk)
return 0;
cleanup:
VIR_FREE(target);
virBufferFreeAndReset(&buf);
return -1;
}

View File

@ -0,0 +1,26 @@
name = "XenGuest2"
uuid = "c7a5fdb2-cdaf-9455-926a-d65c16db1809"
maxmem = 579
memory = 394
vcpus = 1
pae = 1
acpi = 1
apic = 1
hap = 0
viridian = 0
rtc_timeoffset = 0
localtime = 0
on_poweroff = "destroy"
on_reboot = "restart"
on_crash = "restart"
device_model = "/usr/lib/xen/bin/qemu-dm"
sdl = 0
vnc = 1
vncunused = 1
vnclisten = "127.0.0.1"
vif = [ "mac=00:16:3e:66:92:9c,bridge=xenbr1,script=vif-bridge,model=e1000" ]
parallel = "none"
serial = "none"
builder = "hvm"
boot = "d"
disk = [ "format=raw,vdev=hda,access=rw,backendtype=phy,target=/dev/HostVG/XenGuest2", "format=raw,vdev=hdb,access=rw,backendtype=qdisk,target=rbd:pool/image:auth_supported=none:mon_host=mon1.example.org\\:6321\\;mon2.example.org\\:6322\\;mon3.example.org\\:6322" ]

View File

@ -0,0 +1,52 @@
<domain type='xen'>
<name>XenGuest2</name>
<uuid>c7a5fdb2-cdaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>592896</memory>
<currentMemory unit='KiB'>403456</currentMemory>
<vcpu placement='static'>1</vcpu>
<os>
<type arch='x86_64' machine='xenfv'>hvm</type>
<loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
<boot dev='cdrom'/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<clock offset='variable' adjustment='0' basis='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<emulator>/usr/lib/xen/bin/qemu-dm</emulator>
<disk type='block' device='disk'>
<driver name='phy' type='raw'/>
<source dev='/dev/HostVG/XenGuest2'/>
<target dev='hda' bus='ide'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<disk type='network' device='disk'>
<driver name='qemu' type='raw'/>
<source protocol='rbd' name='pool/image'>
<host name='mon1.example.org' port='6321'/>
<host name='mon2.example.org' port='6322'/>
<host name='mon3.example.org' port='6322'/>
</source>
<target dev='hdb' bus='ide'/>
<address type='drive' controller='0' bus='0' target='0' unit='1'/>
</disk>
<controller type='ide' index='0'/>
<interface type='bridge'>
<mac address='00:16:3e:66:92:9c'/>
<source bridge='xenbr1'/>
<script path='vif-bridge'/>
<model type='e1000'/>
</interface>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1'>
<listen type='address' address='127.0.0.1'/>
</graphics>
</devices>
</domain>

View File

@ -217,6 +217,7 @@ mymain(void)
DO_TEST("paravirt-cmdline");
DO_TEST_FORMAT("paravirt-cmdline-extra-root");
DO_TEST_FORMAT("paravirt-cmdline-bogus-extra-root");
DO_TEST("rbd-multihost-noauth");
#ifdef LIBXL_HAVE_BUILDINFO_USBDEVICE_LIST
DO_TEST("fullvirt-multiusb");