mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 21:55:25 +00:00
Support leases in guest XML and lock manager
A lock manager may operate in various modes. The direct mode of operation is to obtain locks based on the resources associated with devices in the XML. The indirect mode is where the app creating the domain provides explicit leases for each resource that needs to be locked. This XML extension allows for listing resources in the XML <devices> ... <lease> <lockspace>somearea</lockspace> <key>thequickbrownfoxjumpsoverthelazydog</key> <target path='/some/lease/path' offset='23432'/> </lease> ... </devices> The 'lockspace' is a unique identifier for the lockspace which the lease is associated The 'key' is a unique identifier for the resource associated with the lease. The 'target' is the file on disk where the leases are held. * docs/schemas/domain.rng: Add lease schema * src/conf/domain_conf.c, src/conf/domain_conf.h: parsing and formatting for leases * tests/qemuxml2argvdata/qemuxml2argv-lease.args, tests/qemuxml2argvdata/qemuxml2argv-lease.xml, tests/qemuxml2xmltest.c: Test XML handling for leases
This commit is contained in:
parent
285c2fdf0f
commit
1ea83207c8
@ -1071,6 +1071,45 @@
|
|||||||
sub-element.
|
sub-element.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h4><a name="elementsLease">Device leases</a></h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
When using a lock manager, it may be desirable to record device leases
|
||||||
|
against a VM. The lock manager will ensure the VM won't start unless
|
||||||
|
the leases can be acquired.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
...
|
||||||
|
<devices>
|
||||||
|
...
|
||||||
|
<lease>
|
||||||
|
<lockspace>somearea</lockspace>
|
||||||
|
<key>somekey</key>
|
||||||
|
<target path='/some/lease/path' offset='1024'/>
|
||||||
|
</lease>
|
||||||
|
...
|
||||||
|
</devices>
|
||||||
|
...</pre>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt>lockspace</dt>
|
||||||
|
<dd>This is an arbitrary string, identifying the lockspace
|
||||||
|
within which the key is held. Lock managers may impose
|
||||||
|
extra restrictions on the format, or length of the lockspace
|
||||||
|
name.</dd>
|
||||||
|
<dt>key</dt>
|
||||||
|
<dd>This is an arbitrary string, uniquely identifying the
|
||||||
|
lease to be acquired. Lock managers may impose extra
|
||||||
|
restrictions on the format, or length of the key.
|
||||||
|
</dd>
|
||||||
|
<dt>target</dt>
|
||||||
|
<dd>This is the fully qualified path of the file associated
|
||||||
|
with the lockspace. The offset specifies where the lease
|
||||||
|
is stored within the file. If the lock manager does not
|
||||||
|
require a offset, just pass 0.
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
<h4><a name="elementsUSB">USB and PCI devices</a></h4>
|
<h4><a name="elementsUSB">USB and PCI devices</a></h4>
|
||||||
|
|
||||||
|
@ -586,6 +586,29 @@
|
|||||||
<ref name="address"/>
|
<ref name="address"/>
|
||||||
</optional>
|
</optional>
|
||||||
</define>
|
</define>
|
||||||
|
|
||||||
|
<define name="lease">
|
||||||
|
<element name="lease">
|
||||||
|
<interleave>
|
||||||
|
<element name="lockspace">
|
||||||
|
<text/>
|
||||||
|
</element>
|
||||||
|
<element name="key">
|
||||||
|
<text/>
|
||||||
|
</element>
|
||||||
|
<element name="target">
|
||||||
|
<attribute name="path">
|
||||||
|
<text/>
|
||||||
|
</attribute>
|
||||||
|
<optional>
|
||||||
|
<attribute name="offset">
|
||||||
|
<ref name="unsignedInt"/>
|
||||||
|
</attribute>
|
||||||
|
</optional>
|
||||||
|
</element>
|
||||||
|
</interleave>
|
||||||
|
</element>
|
||||||
|
</define>
|
||||||
<!--
|
<!--
|
||||||
A disk description can be either of type file or block
|
A disk description can be either of type file or block
|
||||||
The name of the attribute on the source element depends on the type
|
The name of the attribute on the source element depends on the type
|
||||||
@ -1962,6 +1985,7 @@
|
|||||||
<choice>
|
<choice>
|
||||||
<ref name="disk"/>
|
<ref name="disk"/>
|
||||||
<ref name="controller"/>
|
<ref name="controller"/>
|
||||||
|
<ref name="lease"/>
|
||||||
<ref name="filesystem"/>
|
<ref name="filesystem"/>
|
||||||
<ref name="interface"/>
|
<ref name="interface"/>
|
||||||
<ref name="input"/>
|
<ref name="input"/>
|
||||||
|
@ -102,6 +102,7 @@ VIR_ENUM_IMPL(virDomainLifecycleCrash, VIR_DOMAIN_LIFECYCLE_CRASH_LAST,
|
|||||||
|
|
||||||
VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
|
VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
|
||||||
"disk",
|
"disk",
|
||||||
|
"lease",
|
||||||
"filesystem",
|
"filesystem",
|
||||||
"interface",
|
"interface",
|
||||||
"input",
|
"input",
|
||||||
@ -642,6 +643,18 @@ void virDomainInputDefFree(virDomainInputDefPtr def)
|
|||||||
VIR_FREE(def);
|
VIR_FREE(def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void virDomainLeaseDefFree(virDomainLeaseDefPtr def)
|
||||||
|
{
|
||||||
|
if (!def)
|
||||||
|
return;
|
||||||
|
|
||||||
|
VIR_FREE(def->lockspace);
|
||||||
|
VIR_FREE(def->key);
|
||||||
|
VIR_FREE(def->path);
|
||||||
|
|
||||||
|
VIR_FREE(def);
|
||||||
|
}
|
||||||
|
|
||||||
void virDomainDiskDefFree(virDomainDiskDefPtr def)
|
void virDomainDiskDefFree(virDomainDiskDefPtr def)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
@ -903,6 +916,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
|
|||||||
case VIR_DOMAIN_DEVICE_DISK:
|
case VIR_DOMAIN_DEVICE_DISK:
|
||||||
virDomainDiskDefFree(def->data.disk);
|
virDomainDiskDefFree(def->data.disk);
|
||||||
break;
|
break;
|
||||||
|
case VIR_DOMAIN_DEVICE_LEASE:
|
||||||
|
virDomainLeaseDefFree(def->data.lease);
|
||||||
|
break;
|
||||||
case VIR_DOMAIN_DEVICE_NET:
|
case VIR_DOMAIN_DEVICE_NET:
|
||||||
virDomainNetDefFree(def->data.net);
|
virDomainNetDefFree(def->data.net);
|
||||||
break;
|
break;
|
||||||
@ -977,6 +993,10 @@ void virDomainDefFree(virDomainDefPtr def)
|
|||||||
if (!def)
|
if (!def)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
for (i = 0 ; i < def->nleases ; i++)
|
||||||
|
virDomainLeaseDefFree(def->leases[i]);
|
||||||
|
VIR_FREE(def->leases);
|
||||||
|
|
||||||
for (i = 0 ; i < def->ngraphics ; i++)
|
for (i = 0 ; i < def->ngraphics ; i++)
|
||||||
virDomainGraphicsDefFree(def->graphics[i]);
|
virDomainGraphicsDefFree(def->graphics[i]);
|
||||||
VIR_FREE(def->graphics);
|
VIR_FREE(def->graphics);
|
||||||
@ -1881,6 +1901,79 @@ virDomainDiskDefAssignAddress(virCapsPtr caps, virDomainDiskDefPtr def)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse the XML definition for a lease
|
||||||
|
*/
|
||||||
|
static virDomainLeaseDefPtr
|
||||||
|
virDomainLeaseDefParseXML(xmlNodePtr node)
|
||||||
|
{
|
||||||
|
virDomainLeaseDefPtr def;
|
||||||
|
xmlNodePtr cur;
|
||||||
|
char *lockspace = NULL;
|
||||||
|
char *key = NULL;
|
||||||
|
char *path = NULL;
|
||||||
|
char *offset = NULL;
|
||||||
|
|
||||||
|
if (VIR_ALLOC(def) < 0) {
|
||||||
|
virReportOOMError();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = node->children;
|
||||||
|
while (cur != NULL) {
|
||||||
|
if (cur->type == XML_ELEMENT_NODE) {
|
||||||
|
if ((key == NULL) &&
|
||||||
|
(xmlStrEqual(cur->name, BAD_CAST "key"))) {
|
||||||
|
key = (char *)xmlNodeGetContent(cur);
|
||||||
|
} else if ((lockspace == NULL) &&
|
||||||
|
(xmlStrEqual(cur->name, BAD_CAST "lockspace"))) {
|
||||||
|
lockspace = (char *)xmlNodeGetContent(cur);
|
||||||
|
} else if ((path == NULL) &&
|
||||||
|
(xmlStrEqual(cur->name, BAD_CAST "target"))) {
|
||||||
|
path = virXMLPropString(cur, "path");
|
||||||
|
offset = virXMLPropString(cur, "offset");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!key) {
|
||||||
|
virDomainReportError(VIR_ERR_XML_ERROR, "%s",
|
||||||
|
_("Missing 'key' element for lease"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (!path) {
|
||||||
|
virDomainReportError(VIR_ERR_XML_ERROR, "%s",
|
||||||
|
_("Missing 'target' element for lease"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset &&
|
||||||
|
virStrToLong_ull(offset, NULL, 10, &def->offset) < 0) {
|
||||||
|
virDomainReportError(VIR_ERR_XML_ERROR,
|
||||||
|
_("Malformed lease target offset %s"), offset);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
def->key = key;
|
||||||
|
def->lockspace = lockspace;
|
||||||
|
def->path = path;
|
||||||
|
path = key = lockspace = NULL;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(lockspace);
|
||||||
|
VIR_FREE(key);
|
||||||
|
VIR_FREE(path);
|
||||||
|
VIR_FREE(offset);
|
||||||
|
|
||||||
|
return def;
|
||||||
|
|
||||||
|
error:
|
||||||
|
virDomainLeaseDefFree(def);
|
||||||
|
def = NULL;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Parse the XML definition for a disk
|
/* Parse the XML definition for a disk
|
||||||
* @param node XML nodeset to parse for disk definition
|
* @param node XML nodeset to parse for disk definition
|
||||||
*/
|
*/
|
||||||
@ -4986,6 +5079,10 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps,
|
|||||||
if (!(dev->data.disk = virDomainDiskDefParseXML(caps, node,
|
if (!(dev->data.disk = virDomainDiskDefParseXML(caps, node,
|
||||||
NULL, flags)))
|
NULL, flags)))
|
||||||
goto error;
|
goto error;
|
||||||
|
} else if (xmlStrEqual(node->name, BAD_CAST "lease")) {
|
||||||
|
dev->type = VIR_DOMAIN_DEVICE_LEASE;
|
||||||
|
if (!(dev->data.lease = virDomainLeaseDefParseXML(node)))
|
||||||
|
goto error;
|
||||||
} else if (xmlStrEqual(node->name, BAD_CAST "filesystem")) {
|
} else if (xmlStrEqual(node->name, BAD_CAST "filesystem")) {
|
||||||
dev->type = VIR_DOMAIN_DEVICE_FS;
|
dev->type = VIR_DOMAIN_DEVICE_FS;
|
||||||
if (!(dev->data.fs = virDomainFSDefParseXML(node, flags)))
|
if (!(dev->data.fs = virDomainFSDefParseXML(node, flags)))
|
||||||
@ -5903,6 +6000,23 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
|
|||||||
}
|
}
|
||||||
VIR_FREE(nodes);
|
VIR_FREE(nodes);
|
||||||
|
|
||||||
|
/* analysis of the resource leases */
|
||||||
|
if ((n = virXPathNodeSet("./devices/lease", ctxt, &nodes)) < 0) {
|
||||||
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("cannot extract device leases"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (n && VIR_ALLOC_N(def->leases, n) < 0)
|
||||||
|
goto no_memory;
|
||||||
|
for (i = 0 ; i < n ; i++) {
|
||||||
|
virDomainLeaseDefPtr lease = virDomainLeaseDefParseXML(nodes[i]);
|
||||||
|
if (!lease)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
def->leases[def->nleases++] = lease;
|
||||||
|
}
|
||||||
|
VIR_FREE(nodes);
|
||||||
|
|
||||||
/* analysis of the filesystems */
|
/* analysis of the filesystems */
|
||||||
if ((n = virXPathNodeSet("./devices/filesystem", ctxt, &nodes)) < 0) {
|
if ((n = virXPathNodeSet("./devices/filesystem", ctxt, &nodes)) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
@ -7952,6 +8066,22 @@ virDomainLifecycleDefFormat(virBufferPtr buf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
virDomainLeaseDefFormat(virBufferPtr buf,
|
||||||
|
virDomainLeaseDefPtr def)
|
||||||
|
{
|
||||||
|
virBufferAddLit(buf, " <lease>\n");
|
||||||
|
virBufferEscapeString(buf, " <lockspace>%s</lockspace>\n", def->lockspace);
|
||||||
|
virBufferEscapeString(buf, " <key>%s</key>\n", def->key);
|
||||||
|
virBufferEscapeString(buf, " <target path='%s'", def->path);
|
||||||
|
if (def->offset)
|
||||||
|
virBufferAsprintf(buf, " offset='%llu'", def->offset);
|
||||||
|
virBufferAddLit(buf, "/>\n");
|
||||||
|
virBufferAddLit(buf, " </lease>\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
virDomainDiskDefFormat(virBufferPtr buf,
|
virDomainDiskDefFormat(virBufferPtr buf,
|
||||||
virDomainDiskDefPtr def,
|
virDomainDiskDefPtr def,
|
||||||
@ -9365,6 +9495,10 @@ char *virDomainDefFormat(virDomainDefPtr def,
|
|||||||
if (virDomainControllerDefFormat(&buf, def->controllers[n], flags) < 0)
|
if (virDomainControllerDefFormat(&buf, def->controllers[n], flags) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
for (n = 0 ; n < def->nleases ; n++)
|
||||||
|
if (virDomainLeaseDefFormat(&buf, def->leases[n]) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
for (n = 0 ; n < def->nfss ; n++)
|
for (n = 0 ; n < def->nfss ; n++)
|
||||||
if (virDomainFSDefFormat(&buf, def->fss[n], flags) < 0)
|
if (virDomainFSDefFormat(&buf, def->fss[n], flags) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
@ -123,6 +123,15 @@ struct _virDomainDeviceInfo {
|
|||||||
} addr;
|
} addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct _virDomainLeaseDef virDomainLeaseDef;
|
||||||
|
typedef virDomainLeaseDef *virDomainLeaseDefPtr;
|
||||||
|
struct _virDomainLeaseDef {
|
||||||
|
char *lockspace;
|
||||||
|
char *key;
|
||||||
|
char *path;
|
||||||
|
unsigned long long offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Two types of disk backends */
|
/* Two types of disk backends */
|
||||||
enum virDomainDiskType {
|
enum virDomainDiskType {
|
||||||
@ -825,6 +834,7 @@ enum virDomainSmbiosMode {
|
|||||||
/* Flags for the 'type' field in next struct */
|
/* Flags for the 'type' field in next struct */
|
||||||
enum virDomainDeviceType {
|
enum virDomainDeviceType {
|
||||||
VIR_DOMAIN_DEVICE_DISK,
|
VIR_DOMAIN_DEVICE_DISK,
|
||||||
|
VIR_DOMAIN_DEVICE_LEASE,
|
||||||
VIR_DOMAIN_DEVICE_FS,
|
VIR_DOMAIN_DEVICE_FS,
|
||||||
VIR_DOMAIN_DEVICE_NET,
|
VIR_DOMAIN_DEVICE_NET,
|
||||||
VIR_DOMAIN_DEVICE_INPUT,
|
VIR_DOMAIN_DEVICE_INPUT,
|
||||||
@ -845,6 +855,7 @@ struct _virDomainDeviceDef {
|
|||||||
union {
|
union {
|
||||||
virDomainDiskDefPtr disk;
|
virDomainDiskDefPtr disk;
|
||||||
virDomainControllerDefPtr controller;
|
virDomainControllerDefPtr controller;
|
||||||
|
virDomainLeaseDefPtr lease;
|
||||||
virDomainFSDefPtr fs;
|
virDomainFSDefPtr fs;
|
||||||
virDomainNetDefPtr net;
|
virDomainNetDefPtr net;
|
||||||
virDomainInputDefPtr input;
|
virDomainInputDefPtr input;
|
||||||
@ -1185,6 +1196,9 @@ struct _virDomainDef {
|
|||||||
int nchannels;
|
int nchannels;
|
||||||
virDomainChrDefPtr *channels;
|
virDomainChrDefPtr *channels;
|
||||||
|
|
||||||
|
int nleases;
|
||||||
|
virDomainLeaseDefPtr *leases;
|
||||||
|
|
||||||
/* Only 1 */
|
/* Only 1 */
|
||||||
virDomainChrDefPtr console;
|
virDomainChrDefPtr console;
|
||||||
virSecurityLabelDef seclabel;
|
virSecurityLabelDef seclabel;
|
||||||
|
4
tests/qemuxml2argvdata/qemuxml2argv-lease.args
Normal file
4
tests/qemuxml2argvdata/qemuxml2argv-lease.args
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S \
|
||||||
|
-M pc -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait \
|
||||||
|
-no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -cdrom /root/boot.iso -net none \
|
||||||
|
-serial none -parallel none -usb
|
36
tests/qemuxml2argvdata/qemuxml2argv-lease.xml
Normal file
36
tests/qemuxml2argvdata/qemuxml2argv-lease.xml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<domain type='qemu'>
|
||||||
|
<name>QEMUGuest1</name>
|
||||||
|
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
|
||||||
|
<memory>219200</memory>
|
||||||
|
<currentMemory>219200</currentMemory>
|
||||||
|
<vcpu>1</vcpu>
|
||||||
|
<os>
|
||||||
|
<type arch='i686' machine='pc'>hvm</type>
|
||||||
|
<boot dev='hd'/>
|
||||||
|
</os>
|
||||||
|
<clock offset='utc'/>
|
||||||
|
<on_poweroff>destroy</on_poweroff>
|
||||||
|
<on_reboot>restart</on_reboot>
|
||||||
|
<on_crash>destroy</on_crash>
|
||||||
|
<devices>
|
||||||
|
<emulator>/usr/bin/qemu</emulator>
|
||||||
|
<disk type='block' device='disk'>
|
||||||
|
<source dev='/dev/HostVG/QEMUGuest1'/>
|
||||||
|
<target dev='hda' bus='ide'/>
|
||||||
|
<address type='drive' controller='0' bus='0' unit='0'/>
|
||||||
|
</disk>
|
||||||
|
<disk type='file' device='cdrom'>
|
||||||
|
<source file='/root/boot.iso'/>
|
||||||
|
<target dev='hdc' bus='ide'/>
|
||||||
|
<readonly/>
|
||||||
|
<address type='drive' controller='0' bus='1' unit='0'/>
|
||||||
|
</disk>
|
||||||
|
<controller type='ide' index='0'/>
|
||||||
|
<lease>
|
||||||
|
<lockspace>somearea</lockspace>
|
||||||
|
<key>thequickbrownfoxjumpedoverthelazydog</key>
|
||||||
|
<target path='/some/lease/path' offset='1024'/>
|
||||||
|
</lease>
|
||||||
|
<memballoon model='virtio'/>
|
||||||
|
</devices>
|
||||||
|
</domain>
|
@ -181,6 +181,7 @@ mymain(void)
|
|||||||
DO_TEST("cputune");
|
DO_TEST("cputune");
|
||||||
|
|
||||||
DO_TEST("smp");
|
DO_TEST("smp");
|
||||||
|
DO_TEST("lease");
|
||||||
|
|
||||||
/* These tests generate different XML */
|
/* These tests generate different XML */
|
||||||
DO_TEST_DIFFERENT("balloon-device-auto");
|
DO_TEST_DIFFERENT("balloon-device-auto");
|
||||||
|
Loading…
Reference in New Issue
Block a user