mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 21:55:25 +00:00
storage: rbd: qemu: Add support for specifying internal RBD snapshots
Some storage systems have internal support for snapshots. Libvirt should be able to select a correct snapshot when starting a VM. This patch adds a XML element to select a storage source snapshot for the RBD protocol which supports this feature.
This commit is contained in:
parent
930b77598b
commit
0255660658
@ -1679,6 +1679,7 @@
|
|||||||
<driver name="qemu" type="raw"/>
|
<driver name="qemu" type="raw"/>
|
||||||
<source protocol="rbd" name="image_name2">
|
<source protocol="rbd" name="image_name2">
|
||||||
<host name="hostname" port="7000"/>
|
<host name="hostname" port="7000"/>
|
||||||
|
<snapshot name="snapname"/>
|
||||||
</source>
|
</source>
|
||||||
<target dev="hdc" bus="ide"/>
|
<target dev="hdc" bus="ide"/>
|
||||||
<auth username='myuser'>
|
<auth username='myuser'>
|
||||||
@ -1952,15 +1953,17 @@
|
|||||||
is only valid when the specified storage volume is of 'file' or
|
is only valid when the specified storage volume is of 'file' or
|
||||||
'block' type).
|
'block' type).
|
||||||
<p>
|
<p>
|
||||||
When the disk <code>type</code> is "network", the <code>source</code>
|
The <code>source</code> element may contain the following sub elements:
|
||||||
may have zero or more <code>host</code> sub-elements used to
|
|
||||||
specify the hosts to connect.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
<dt><code>host</code></dt>
|
<dt><code>host</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<p>
|
<p>
|
||||||
|
When the disk <code>type</code> is "network", the <code>source</code>
|
||||||
|
may have zero or more <code>host</code> sub-elements used to
|
||||||
|
specify the hosts to connect.
|
||||||
|
|
||||||
The <code>host</code> element supports 4 attributes, viz. "name",
|
The <code>host</code> element supports 4 attributes, viz. "name",
|
||||||
"port", "transport" and "socket", which specify the hostname,
|
"port", "transport" and "socket", which specify the hostname,
|
||||||
the port number, transport type and path to socket, respectively.
|
the port number, transport type and path to socket, respectively.
|
||||||
@ -2013,6 +2016,13 @@
|
|||||||
AF_UNIX socket.
|
AF_UNIX socket.
|
||||||
</p>
|
</p>
|
||||||
</dd>
|
</dd>
|
||||||
|
<dt><code>snapshot</code></dt>
|
||||||
|
<dd>
|
||||||
|
The <code>name</code> attribute of <code>snapshot</code> element can
|
||||||
|
optionally specify an internal snapshot name to be used as the
|
||||||
|
source for storage protocols.
|
||||||
|
Supported for 'rbd' <span class="since">since 1.2.11 (QEMU only).</span>
|
||||||
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -1452,6 +1452,14 @@
|
|||||||
</choice>
|
</choice>
|
||||||
</element>
|
</element>
|
||||||
</zeroOrMore>
|
</zeroOrMore>
|
||||||
|
<optional>
|
||||||
|
<element name="snapshot">
|
||||||
|
<attribute name="name">
|
||||||
|
<ref name="genericName"/>
|
||||||
|
</attribute>
|
||||||
|
<empty/>
|
||||||
|
</element>
|
||||||
|
</optional>
|
||||||
<empty/>
|
<empty/>
|
||||||
</element>
|
</element>
|
||||||
</interleave>
|
</interleave>
|
||||||
|
@ -3165,6 +3165,22 @@ virDomainDeviceDefPostParseInternal(virDomainDeviceDefPtr dev,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* verify disk source */
|
||||||
|
if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
|
||||||
|
virDomainDiskDefPtr disk = dev->data.disk;
|
||||||
|
|
||||||
|
/* internal snapshots are currently supported only with rbd: */
|
||||||
|
if (virStorageSourceGetActualType(disk->src) != VIR_STORAGE_TYPE_NETWORK &&
|
||||||
|
disk->src->protocol != VIR_STORAGE_NET_PROTOCOL_RBD) {
|
||||||
|
if (disk->src->snapshot) {
|
||||||
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||||
|
_("<snapshot> element is currently supported "
|
||||||
|
"only with 'rbd' disks"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5316,10 +5332,14 @@ virDomainDiskSourcePoolDefParse(xmlNodePtr node,
|
|||||||
|
|
||||||
int
|
int
|
||||||
virDomainDiskSourceParse(xmlNodePtr node,
|
virDomainDiskSourceParse(xmlNodePtr node,
|
||||||
|
xmlXPathContextPtr ctxt,
|
||||||
virStorageSourcePtr src)
|
virStorageSourcePtr src)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
char *protocol = NULL;
|
char *protocol = NULL;
|
||||||
|
xmlNodePtr saveNode = ctxt->node;
|
||||||
|
|
||||||
|
ctxt->node = node;
|
||||||
|
|
||||||
switch ((virStorageType)src->type) {
|
switch ((virStorageType)src->type) {
|
||||||
case VIR_STORAGE_TYPE_FILE:
|
case VIR_STORAGE_TYPE_FILE:
|
||||||
@ -5372,6 +5392,9 @@ virDomainDiskSourceParse(xmlNodePtr node,
|
|||||||
tmp[0] = '\0';
|
tmp[0] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* snapshot currently works only for remote disks */
|
||||||
|
src->snapshot = virXPathString("string(./snapshot/@name)", ctxt);
|
||||||
|
|
||||||
if (virDomainStorageHostParse(node, &src->hosts, &src->nhosts) < 0)
|
if (virDomainStorageHostParse(node, &src->hosts, &src->nhosts) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
break;
|
break;
|
||||||
@ -5397,6 +5420,7 @@ virDomainDiskSourceParse(xmlNodePtr node,
|
|||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
VIR_FREE(protocol);
|
VIR_FREE(protocol);
|
||||||
|
ctxt->node = saveNode;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5452,7 +5476,7 @@ virDomainDiskBackingStoreParse(xmlXPathContextPtr ctxt,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virDomainDiskSourceParse(source, backingStore) < 0 ||
|
if (virDomainDiskSourceParse(source, ctxt, backingStore) < 0 ||
|
||||||
virDomainDiskBackingStoreParse(ctxt, backingStore) < 0)
|
virDomainDiskBackingStoreParse(ctxt, backingStore) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@ -5562,7 +5586,7 @@ virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt,
|
|||||||
xmlStrEqual(cur->name, BAD_CAST "source")) {
|
xmlStrEqual(cur->name, BAD_CAST "source")) {
|
||||||
sourceNode = cur;
|
sourceNode = cur;
|
||||||
|
|
||||||
if (virDomainDiskSourceParse(cur, def->src) < 0)
|
if (virDomainDiskSourceParse(cur, ctxt, def->src) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
source = def->src->path;
|
source = def->src->path;
|
||||||
|
|
||||||
@ -5728,7 +5752,8 @@ virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt,
|
|||||||
_("mirror requires source element"));
|
_("mirror requires source element"));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (virDomainDiskSourceParse(mirrorNode, def->mirror) < 0)
|
if (virDomainDiskSourceParse(mirrorNode, ctxt,
|
||||||
|
def->mirror) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
ready = virXMLPropString(cur, "ready");
|
ready = virXMLPropString(cur, "ready");
|
||||||
@ -16142,11 +16167,12 @@ virDomainDiskSourceFormatInternal(virBufferPtr buf,
|
|||||||
|
|
||||||
VIR_FREE(path);
|
VIR_FREE(path);
|
||||||
|
|
||||||
if (src->nhosts == 0) {
|
if (src->nhosts == 0 && !src->snapshot) {
|
||||||
virBufferAddLit(buf, "/>\n");
|
virBufferAddLit(buf, "/>\n");
|
||||||
} else {
|
} else {
|
||||||
virBufferAddLit(buf, ">\n");
|
virBufferAddLit(buf, ">\n");
|
||||||
virBufferAdjustIndent(buf, 2);
|
virBufferAdjustIndent(buf, 2);
|
||||||
|
|
||||||
for (n = 0; n < src->nhosts; n++) {
|
for (n = 0; n < src->nhosts; n++) {
|
||||||
virBufferAddLit(buf, "<host");
|
virBufferAddLit(buf, "<host");
|
||||||
virBufferEscapeString(buf, " name='%s'",
|
virBufferEscapeString(buf, " name='%s'",
|
||||||
@ -16163,6 +16189,10 @@ virDomainDiskSourceFormatInternal(virBufferPtr buf,
|
|||||||
|
|
||||||
virBufferAddLit(buf, "/>\n");
|
virBufferAddLit(buf, "/>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virBufferEscapeString(buf, "<snapshot name='%s'/>\n",
|
||||||
|
src->snapshot);
|
||||||
|
|
||||||
virBufferAdjustIndent(buf, -2);
|
virBufferAdjustIndent(buf, -2);
|
||||||
virBufferAddLit(buf, "</source>\n");
|
virBufferAddLit(buf, "</source>\n");
|
||||||
}
|
}
|
||||||
|
@ -2492,6 +2492,7 @@ virDomainDiskRemove(virDomainDefPtr def, size_t i);
|
|||||||
virDomainDiskDefPtr
|
virDomainDiskDefPtr
|
||||||
virDomainDiskRemoveByName(virDomainDefPtr def, const char *name);
|
virDomainDiskRemoveByName(virDomainDefPtr def, const char *name);
|
||||||
int virDomainDiskSourceParse(xmlNodePtr node,
|
int virDomainDiskSourceParse(xmlNodePtr node,
|
||||||
|
xmlXPathContextPtr ctxt,
|
||||||
virStorageSourcePtr src);
|
virStorageSourcePtr src);
|
||||||
|
|
||||||
bool virDomainHasDiskMirror(virDomainObjPtr vm);
|
bool virDomainHasDiskMirror(virDomainObjPtr vm);
|
||||||
|
@ -107,6 +107,7 @@ void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
|
virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
|
||||||
|
xmlXPathContextPtr ctxt,
|
||||||
virDomainSnapshotDiskDefPtr def)
|
virDomainSnapshotDiskDefPtr def)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
@ -154,7 +155,7 @@ virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
|
|||||||
if (!def->src->path &&
|
if (!def->src->path &&
|
||||||
xmlStrEqual(cur->name, BAD_CAST "source")) {
|
xmlStrEqual(cur->name, BAD_CAST "source")) {
|
||||||
|
|
||||||
if (virDomainDiskSourceParse(cur, def->src) < 0)
|
if (virDomainDiskSourceParse(cur, ctxt, def->src) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
} else if (!def->src->format &&
|
} else if (!def->src->format &&
|
||||||
@ -352,7 +353,8 @@ virDomainSnapshotDefParse(xmlXPathContextPtr ctxt,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
def->ndisks = n;
|
def->ndisks = n;
|
||||||
for (i = 0; i < def->ndisks; i++) {
|
for (i = 0; i < def->ndisks; i++) {
|
||||||
if (virDomainSnapshotDiskDefParseXML(nodes[i], &def->disks[i]) < 0)
|
if (virDomainSnapshotDiskDefParseXML(nodes[i], ctxt,
|
||||||
|
&def->disks[i]) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
VIR_FREE(nodes);
|
VIR_FREE(nodes);
|
||||||
|
@ -2983,6 +2983,9 @@ qemuBuildNetworkDriveURI(virStorageSourcePtr src,
|
|||||||
|
|
||||||
virBufferStrcat(&buf, "rbd:", src->path, NULL);
|
virBufferStrcat(&buf, "rbd:", src->path, NULL);
|
||||||
|
|
||||||
|
if (src->snapshot)
|
||||||
|
virBufferEscape(&buf, '\\', ":", "@%s", src->snapshot);
|
||||||
|
|
||||||
if (username) {
|
if (username) {
|
||||||
virBufferEscape(&buf, '\\', ":", ":id=%s", username);
|
virBufferEscape(&buf, '\\', ":", ":id=%s", username);
|
||||||
virBufferEscape(&buf, '\\', ":",
|
virBufferEscape(&buf, '\\', ":",
|
||||||
|
@ -1848,6 +1848,7 @@ virStorageSourceCopy(const virStorageSource *src,
|
|||||||
VIR_STRDUP(ret->driverName, src->driverName) < 0 ||
|
VIR_STRDUP(ret->driverName, src->driverName) < 0 ||
|
||||||
VIR_STRDUP(ret->relPath, src->relPath) < 0 ||
|
VIR_STRDUP(ret->relPath, src->relPath) < 0 ||
|
||||||
VIR_STRDUP(ret->backingStoreRaw, src->backingStoreRaw) < 0 ||
|
VIR_STRDUP(ret->backingStoreRaw, src->backingStoreRaw) < 0 ||
|
||||||
|
VIR_STRDUP(ret->snapshot, src->snapshot) < 0 ||
|
||||||
VIR_STRDUP(ret->compat, src->compat) < 0)
|
VIR_STRDUP(ret->compat, src->compat) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@ -2280,6 +2281,13 @@ virStorageSourceParseRBDColonString(const char *rbdstr,
|
|||||||
*p = '\0';
|
*p = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* snapshot name */
|
||||||
|
if ((p = strchr(src->path, '@'))) {
|
||||||
|
if (VIR_STRDUP(src->snapshot, p + 1) < 0)
|
||||||
|
goto error;
|
||||||
|
*p = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
/* options */
|
/* options */
|
||||||
if (!options)
|
if (!options)
|
||||||
return 0; /* all done */
|
return 0; /* all done */
|
||||||
|
@ -238,6 +238,7 @@ struct _virStorageSource {
|
|||||||
char *path;
|
char *path;
|
||||||
int protocol; /* virStorageNetProtocol */
|
int protocol; /* virStorageNetProtocol */
|
||||||
char *volume; /* volume name for remote storage */
|
char *volume; /* volume name for remote storage */
|
||||||
|
char *snapshot; /* for storage systems supporting internal snapshots */
|
||||||
size_t nhosts;
|
size_t nhosts;
|
||||||
virStorageNetHostDefPtr hosts;
|
virStorageNetHostDefPtr hosts;
|
||||||
virStorageSourcePoolDefPtr srcpool;
|
virStorageSourcePoolDefPtr srcpool;
|
||||||
|
@ -5,4 +5,8 @@ unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -usb \
|
|||||||
-drive 'file=rbd:pool/image:auth_supported=none:\
|
-drive 'file=rbd:pool/image:auth_supported=none:\
|
||||||
mon_host=mon1.example.org\:6321\;mon2.example.org\:6322\;\
|
mon_host=mon1.example.org\:6321\;mon2.example.org\:6322\;\
|
||||||
mon3.example.org\:6322,if=virtio,format=raw' \
|
mon3.example.org\:6322,if=virtio,format=raw' \
|
||||||
|
-drive file=rbd:pool/image@asdf:auth_supported=none,if=virtio,format=raw \
|
||||||
|
-drive 'file=rbd:pool/image@foo:auth_supported=none:\
|
||||||
|
mon_host=mon1.example.org\:6321\;mon2.example.org\:6322\;\
|
||||||
|
mon3.example.org\:6322,if=virtio,format=raw' \
|
||||||
-net none -serial none -parallel none
|
-net none -serial none -parallel none
|
||||||
|
@ -29,6 +29,23 @@
|
|||||||
</source>
|
</source>
|
||||||
<target dev='vda' bus='virtio'/>
|
<target dev='vda' bus='virtio'/>
|
||||||
</disk>
|
</disk>
|
||||||
|
<disk type='network' device='disk'>
|
||||||
|
<driver name='qemu' type='raw'/>
|
||||||
|
<source protocol='rbd' name='pool/image'>
|
||||||
|
<snapshot name='asdf'/>
|
||||||
|
</source>
|
||||||
|
<target dev='vdb' bus='virtio'/>
|
||||||
|
</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'/>
|
||||||
|
<snapshot name='foo'/>
|
||||||
|
</source>
|
||||||
|
<target dev='vdc' bus='virtio'/>
|
||||||
|
</disk>
|
||||||
<controller type='usb' index='0'/>
|
<controller type='usb' index='0'/>
|
||||||
<controller type='ide' index='0'/>
|
<controller type='ide' index='0'/>
|
||||||
<controller type='pci' index='0' model='pci-root'/>
|
<controller type='pci' index='0' model='pci-root'/>
|
||||||
|
Loading…
Reference in New Issue
Block a user