[libvirt] [RFC PATCH 0/4] Implementation of a dependency relation between domains

This patch series adds a feature that enables libvirt domains to have other domains as dependencies. One possible target is the simulation of a complex computing system composed of multiple CPUs, each of which represented by a different libvirt domain. CPUs in this example are virtualized separately, by a dedicated QEMU instance, because all of them are booting independently. Moreover, if those CPU must share some physical property (for example power supply or ACPI), it is meaningful to consider them as a group. Another possible target is Asymmetric Multi Processor (AMP) systems. Where a master processor uses one or more slave processors to offload computation. Master and slave have often different architectures. This patch series makes possible to define the slave domains as dependencies of the master domain. And the whole system to be booted with one single libvirt command. A use-case for this libvirt extension are the recent patch series in QEMU that enable modeling an AMP-like system with multiple QEMU instances. [RFC v2 0/6] SDM Interface [RFC v2 0/6] QEMU shared-memory-backend [RFC v2 1/1] backend: multi-client-socket Features : ---------- - When a domain A depends on a domain B (A=>B), signals are forward-propagated from A to B. So, when a user asks the domain A to be: - instantiated - destroyed - suspended - resumed domain B will automatically receive the same signal. - Single-level dependency: By construction domain dependencies are restricted to one single level, so to avoid wrong recursive (infinite) domain dependencies. This is also because there is no clear benefit in supporting multiple level of dependencies between domains. More specifically, given to domains, A and B, if A depends on B (A=>B), then B can not have any dependency (B => C is forbidden). How to test this patch series : ------------------------------- The source code can be downloaded by: git clone https://git.virtualopensystems.com/dev/libvirt.git \ -b domain-dependency Note: The patch series relies on the commit 95ca4fe, but with the patch proposed by Michal Privoznik, "[PATCH]qemuBuildVideoCommandLine: Don't access def->videos without check" that resolves a critical bug. To add a dependency between two domains (for example between domaninA and domainB), it suffices to add in the XML description of the first one: domainA.xml: <devices> ... <domaindependency> /absolute/path/to/the/domainB.xml </domaindependency> ... </devices> Note: The two domains mus be virtualized thanks to QEMU, and be hosted on the same filesystem. Finally, instanciate domainA with the command: virsh create domainA.xml And observe that both domains are running in the same time with: virsh list You can trigger the implemented signals and check that both domains are working as one: virsh suspend domainA virsh resume domainA virsh destroy domainA Note: as mentioned, all signals are forward-propagated, so if you manipulate the domainB directly, domainA will not be affected. This work has been sponsored by Huawei Technologies Duesseldorf GmbH. Valentin BOUSSON (4): Add XML description of the new dependency device Add the inner structure managing dependency devices Add primitives for manipulation of dependency structures Implement signal propagation to dependancy domains docs/schemas/domaincommon.rng | 5 ++ src/conf/domain_conf.c | 83 +++++++++++++++++++++++++- src/conf/domain_conf.h | 18 ++++++ src/qemu/qemu_driver.c | 135 ++++++++++++++++++++++++++++++++++++++++-- src/qemu/qemu_hotplug.c | 1 + 5 files changed, 237 insertions(+), 5 deletions(-) -- 1.9.1

The RNG structure is modified in order a user can instantiate a domain with a new kind of device. By adding the device sub-tag <domaindependency>, the user can link to another XML file, describing the domain to depend on. For example, if a master domains specify in its XML description : <devices> .. <domaindependency> ~/slave_domain.xml </domaindependency> ... </devices> Then, the slave domain (described by the file slave_domain.xml) will be loaded in the meantime. The filepath must be absolute, because all the operations are done by the libvirt daemon. --- docs/schemas/domaincommon.rng | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 8c6287d..77e7667 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -4097,6 +4097,7 @@ <ref name="tpm"/> <ref name="shmem"/> <ref name="memorydev"/> + <ref name="domaindependency"/> </choice> </zeroOrMore> <optional> @@ -4609,6 +4610,10 @@ </element> </define> + <define name="domaindependency"> + <element name="domaindependency"/> + </define> + <define name="rng"> <element name="rng"> <attribute name="model"> -- 1.9.1

A new field has been added in the internal domain definition (virDomainDeviceDef), in order to store the list of dependencies a domain refers to. The informations stored about one dependency are: - the absolute path of the XML description - the name of the domain These informations are needed to propagate different signals across the dependency relation. --- src/conf/domain_conf.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 85c4f55..d0b3333 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -136,6 +136,9 @@ typedef virDomainPanicDef *virDomainPanicDefPtr; typedef struct _virDomainMemoryDef virDomainMemoryDef; typedef virDomainMemoryDef *virDomainMemoryDefPtr; +typedef struct _virDomainDependencyDef virDomainDependencyDef; +typedef virDomainDependencyDef *virDomainDependencyDefPtr; + /* forward declarations virDomainChrSourceDef, required by * virDomainNetDef */ @@ -204,6 +207,7 @@ struct _virDomainDeviceDef { virDomainTPMDefPtr tpm; virDomainPanicDefPtr panic; virDomainMemoryDefPtr memory; + virDomainDependencyDefPtr dependency; } data; }; @@ -2042,6 +2046,15 @@ struct _virDomainMemoryDef { void virDomainMemoryDefFree(virDomainMemoryDefPtr def); +struct _virDomainDependencyDef { + char *filePath; + + unsigned char domainUuid[VIR_UUID_BUFLEN]; + char *domainName; + + virDomainDeviceInfo info; +}; + struct _virDomainIdMapEntry { unsigned int start; unsigned int target; @@ -2300,6 +2313,9 @@ struct _virDomainDef { size_t nseclabels; virSecurityLabelDefPtr *seclabels; + size_t ndomaindependencies; + virDomainDependencyDefPtr *domaindependencies; + size_t nrngs; virDomainRNGDefPtr *rngs; -- 1.9.1

In order to be able to create, modify, and destroy the internal fields that manage the dependency information in each domain, new primitives are added. Now, libvirt is able to parse the new <devicedependency> tag in the description of a domain, and then to create the associated structures. The QEMU driver is also modified in order to manage this new kind of device. --- src/conf/domain_conf.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++- src/conf/domain_conf.h | 2 ++ src/qemu/qemu_driver.c | 10 ++++-- src/qemu/qemu_hotplug.c | 1 + 4 files changed, 92 insertions(+), 4 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7d68096..7f5f623 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -233,7 +233,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST, "shmem", "tpm", "panic", - "memory") + "memory", + "domaindependency") VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST, "none", @@ -2064,6 +2065,19 @@ void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def) VIR_FREE(def); } +void virDomainDependencyDefFree(virDomainDependencyDefPtr def) +{ + if (!def) + return + virDomainDeviceInfoClear(&def->info); + + VIR_FREE(def->filePath); + VIR_FREE(def->domainName); + VIR_FREE(def->domainUuid); + + VIR_FREE(def); +} + void virDomainNVRAMDefFree(virDomainNVRAMDefPtr def) { if (!def) @@ -2326,6 +2340,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def) case VIR_DOMAIN_DEVICE_MEMORY: virDomainMemoryDefFree(def->data.memory); break; + case VIR_DOMAIN_DEVICE_DEPENDENCY: + virDomainDependencyDefFree(def->data.dependency); + break; case VIR_DOMAIN_DEVICE_LAST: case VIR_DOMAIN_DEVICE_NONE: break; @@ -3142,6 +3159,8 @@ virDomainDeviceGetInfo(virDomainDeviceDefPtr device) return &device->data.panic->info; case VIR_DOMAIN_DEVICE_MEMORY: return &device->data.memory->info; + case VIR_DOMAIN_DEVICE_DEPENDENCY: + return &device->data.dependency->info; /* The following devices do not contain virDomainDeviceInfo */ case VIR_DOMAIN_DEVICE_LEASE: @@ -3502,6 +3521,7 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def, case VIR_DOMAIN_DEVICE_LAST: case VIR_DOMAIN_DEVICE_RNG: case VIR_DOMAIN_DEVICE_MEMORY: + case VIR_DOMAIN_DEVICE_DEPENDENCY: break; } #endif @@ -11592,6 +11612,43 @@ virDomainMemballoonDefParseXML(xmlNodePtr node, goto cleanup; } +static virDomainDependencyDefPtr +virDomainDependencyDefParseXML(xmlNodePtr node, + xmlXPathContextPtr ctxt, + unsigned int flags) +{ + xmlNodePtr save = ctxt->node; + + virDomainDependencyDefPtr def; + if (VIR_ALLOC(def) < 0) { + return NULL; + } + + ctxt->node = node; + + def->filePath = NULL; + def->domainName = NULL; + for (int i = 0; i < VIR_UUID_BUFLEN; ++i) { + def->domainUuid[i] = '\0'; + } + def->filePath = virXPathString("string(.)", ctxt); + + if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0) { + goto error; + } + + ctxt->node = save; + return def; + + error: + virDomainDependencyDefFree(def); + def = NULL; + ctxt->node = save; + return NULL; +} + + + static virDomainNVRAMDefPtr virDomainNVRAMDefParseXML(xmlNodePtr node, unsigned int flags) @@ -12848,6 +12905,10 @@ virDomainDeviceDefParse(const char *xmlStr, if (!(dev->data.memory = virDomainMemoryDefParseXML(node, ctxt, flags))) goto error; break; + case VIR_DOMAIN_DEVICE_DEPENDENCY: + if (!(dev->data.dependency = virDomainDependencyDefParseXML(node, ctxt, flags))) + goto error; + break; case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_LAST: break; @@ -16379,6 +16440,24 @@ virDomainDefParseXML(xmlDocPtr xml, VIR_FREE(nodes); } + if ((n = virXPathNodeSet("./devices/domaindependency", ctxt, &nodes)) < 0) + goto error; + + if (n && VIR_ALLOC_N(def->domaindependencies, n) < 0) + goto error; + + def->ndomaindependencies = n; + if (n > 0) { + for (i = 0; i < n; i++) { + virDomainDependencyDefPtr dependency = virDomainDependencyDefParseXML(nodes[i], ctxt, flags); + if (!dependency) { + goto error; + } + def->domaindependencies[i] = dependency; + } + VIR_FREE(nodes); + } + /* Parse the RNG devices */ if ((n = virXPathNodeSet("./devices/rng", ctxt, &nodes)) < 0) goto error; @@ -18314,6 +18393,7 @@ virDomainDefCheckABIStability(virDomainDefPtr src, case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_SHMEM: case VIR_DOMAIN_DEVICE_MEMORY: + case VIR_DOMAIN_DEVICE_DEPENDENCY: break; } #endif @@ -23806,6 +23886,7 @@ virDomainDeviceDefCopy(virDomainDeviceDefPtr src, rc = virDomainMemoryDefFormat(&buf, src->data.memory, flags); break; case VIR_DOMAIN_DEVICE_NONE: + case VIR_DOMAIN_DEVICE_DEPENDENCY: case VIR_DOMAIN_DEVICE_SMARTCARD: case VIR_DOMAIN_DEVICE_MEMBALLOON: case VIR_DOMAIN_DEVICE_NVRAM: diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index d0b3333..95be6ad 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -176,6 +176,7 @@ typedef enum { VIR_DOMAIN_DEVICE_TPM, VIR_DOMAIN_DEVICE_PANIC, VIR_DOMAIN_DEVICE_MEMORY, + VIR_DOMAIN_DEVICE_DEPENDENCY, VIR_DOMAIN_DEVICE_LAST } virDomainDeviceType; @@ -2556,6 +2557,7 @@ int virDomainChrSourceDefCopy(virDomainChrSourceDefPtr src, void virDomainSoundCodecDefFree(virDomainSoundCodecDefPtr def); void virDomainSoundDefFree(virDomainSoundDefPtr def); void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def); +void virDomainDependencyDefFree(virDomainDependencyDefPtr def); void virDomainNVRAMDefFree(virDomainNVRAMDefPtr def); void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def); void virDomainVideoDefFree(virDomainVideoDefPtr def); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a0d6596..37eef7e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7598,6 +7599,7 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm, dev->data.memory = NULL; break; + case VIR_DOMAIN_DEVICE_DEPENDENCY: case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_FS: case VIR_DOMAIN_DEVICE_INPUT: @@ -7687,7 +7689,7 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm, case VIR_DOMAIN_DEVICE_MEMORY: ret = qemuDomainDetachMemoryDevice(driver, vm, dev->data.memory); break; + case VIR_DOMAIN_DEVICE_DEPENDENCY: case VIR_DOMAIN_DEVICE_FS: case VIR_DOMAIN_DEVICE_INPUT: case VIR_DOMAIN_DEVICE_SOUND: @@ -7811,6 +7813,7 @@ qemuDomainUpdateDeviceLive(virConnectPtr conn, case VIR_DOMAIN_DEVICE_NET: ret = qemuDomainChangeNet(driver, vm, dev); break; + case VIR_DOMAIN_DEVICE_DEPENDENCY: case VIR_DOMAIN_DEVICE_FS: case VIR_DOMAIN_DEVICE_INPUT: case VIR_DOMAIN_DEVICE_SOUND: @@ -7987,7 +7990,7 @@ qemuDomainAttachDeviceConfig(virQEMUCapsPtr qemuCaps, return -1; dev->data.memory = NULL; break; + case VIR_DOMAIN_DEVICE_DEPENDENCY: case VIR_DOMAIN_DEVICE_INPUT: case VIR_DOMAIN_DEVICE_SOUND: case VIR_DOMAIN_DEVICE_VIDEO: @@ -8124,6 +8127,7 @@ qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef, virDomainMemoryDefFree(virDomainMemoryRemove(vmdef, idx)); break; + case VIR_DOMAIN_DEVICE_DEPENDENCY: case VIR_DOMAIN_DEVICE_INPUT: case VIR_DOMAIN_DEVICE_SOUND: case VIR_DOMAIN_DEVICE_VIDEO: @@ -8212,7 +8216,7 @@ qemuDomainUpdateDeviceConfig(virQEMUCapsPtr qemuCaps, if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0) return -1; break; + case VIR_DOMAIN_DEVICE_DEPENDENCY: case VIR_DOMAIN_DEVICE_FS: case VIR_DOMAIN_DEVICE_INPUT: case VIR_DOMAIN_DEVICE_SOUND: diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index b580283..243d0fc 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -3319,6 +3319,7 @@ qemuDomainRemoveDevice(virQEMUDriverPtr driver, ret = qemuDomainRemoveMemoryDevice(driver, vm, dev->data.memory); break; + case VIR_DOMAIN_DEVICE_DEPENDENCY: case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_FS: -- 1.9.1

This patch implements the propagation of different signals across the dependency relation between domains: - CreateXML: When a domain with dependency is instanciated via this function, all the depencies it depends on are instanciated in the same time - Destroy: (When a domain with dependencies is destroyed, its dependencies are destroyed in the meantime) - Suspend (When a domain with dependencies is suspended, its dependencies are suspended in the meantime) - Resume (When a domain with dependencies is resumed, its dependencies are resumed in the meantime) --- src/qemu/qemu_driver.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 37eef7e..094b536 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1783,6 +1783,10 @@ static virDomainPtr qemuDomainCreateXML(virConnectPtr conn, virCapsPtr caps = NULL; unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE | VIR_DOMAIN_DEF_PARSE_ABI_UPDATE; + int i = 0; + char *buffer = NULL; + virDomainDefPtr def_slave = NULL; + virDomainObjPtr vm_slave = NULL; virCheckFlags(VIR_DOMAIN_START_PAUSED | VIR_DOMAIN_START_AUTODESTROY | @@ -1820,7 +1824,6 @@ static virDomainPtr qemuDomainCreateXML(virConnectPtr conn, NULL))) goto cleanup; virObjectRef(vm); - def = NULL; if (qemuProcessBeginJob(driver, vm) < 0) { qemuDomainRemoveInactive(driver, vm); @@ -1852,6 +1855,83 @@ static virDomainPtr qemuDomainCreateXML(virConnectPtr conn, } virDomainAuditStart(vm, "booted", true); + for (i=0; i < def->ndomaindependencies; ++i) { + /* Constant for creation of new domains from an XML descriptions is specified in + * ../tools/vsh.h:43 : # define VSH_MAX_XML_FILE (10*1024*1024) + */ + if (virFileReadAll(def->domaindependencies[i]->filePath, + 10*1024*1024, + &buffer) < 0) + goto cleanup; + + if (!(def_slave = virDomainDefParseString(buffer, caps, driver->xmlopt, + parse_flags))) + goto cleanup; + + if (virDomainCreateXMLEnsureACL(conn, def_slave) < 0) + goto cleanup; + + if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def_slave->emulator))) + goto cleanup; + + if (qemuDomainAssignAddresses(def_slave, qemuCaps, NULL) < 0) + goto cleanup; + + if (!(vm_slave = virDomainObjListAdd(driver->domains, + def_slave, + driver->xmlopt, + VIR_DOMAIN_OBJ_LIST_ADD_LIVE | VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE, + NULL))) + goto cleanup; + virObjectRef(vm_slave); + def_slave = NULL; + + if (qemuProcessBeginJob(driver, vm_slave) < 0) { + qemuDomainRemoveInactive(driver, vm_slave); + goto cleanup; + } + + if (qemuProcessStart(conn, driver, vm_slave, QEMU_ASYNC_JOB_START, + NULL, -1, NULL, NULL, + VIR_NETDEV_VPORT_PROFILE_OP_CREATE, + start_flags) < 0) { + virDomainAuditStart(vm_slave, "booted", false); + qemuProcessEndJob(driver, vm_slave); + qemuDomainRemoveInactive(driver, vm_slave); + goto cleanup; + } + + event = virDomainEventLifecycleNewFromObj(vm_slave, + VIR_DOMAIN_EVENT_STARTED, + VIR_DOMAIN_EVENT_STARTED_BOOTED); + + if (event && (flags & VIR_DOMAIN_START_PAUSED)) { + event2 = virDomainEventLifecycleNewFromObj(vm_slave, + VIR_DOMAIN_EVENT_SUSPENDED, + VIR_DOMAIN_EVENT_SUSPENDED_PAUSED); + } + virDomainAuditStart(vm_slave, "booted", true); + + /* Registering domain name for live dependency */ + if (VIR_ALLOC_N(def->domaindependencies[i]->domainName, strlen(vm_slave->def->name)+1) < 0) { + goto cleanup; + } + else { + if (virStrcpy(def->domaindependencies[i]->domainName, + vm_slave->def->name, + strlen(vm_slave->def->name)+1) == NULL) { + + } + else { + for (int j = 0; j < VIR_UUID_BUFLEN; ++j) { + def->domaindependencies[i]->domainUuid[j] = vm_slave->def->uuid[j]; + } + } + } + qemuProcessEndJob(driver,vm_slave); + } + def = NULL; + dom = virGetDomain(conn, vm->def->name, vm->def->uuid); if (dom) dom->id = vm->def->id; @@ -1861,6 +1941,8 @@ static virDomainPtr qemuDomainCreateXML(virConnectPtr conn, cleanup: virDomainDefFree(def); virDomainObjEndAPI(&vm); + virDomainDefFree(def_slave); + virDomainObjEndAPI(&vm_slave); if (event) { qemuDomainEventQueue(driver, event); qemuDomainEventQueue(driver, event2); @@ -1884,9 +1966,22 @@ static int qemuDomainSuspend(virDomainPtr dom) int state; virQEMUDriverConfigPtr cfg = NULL; + int i = 0; + if (!(vm = qemuDomObjFromDomain(dom))) return -1; + for (i = 0; i < vm->def->ndomaindependencies; ++i) { + if (qemuDomainSuspend(virGetDomain(dom->conn, + vm->def->domaindependencies[i]->domainName, + vm->def->domaindependencies[i]->domainUuid)) < 0) { + VIR_WARN("Problem to suspend domain %s.", vm->def->domaindependencies[i]->domainName); + } + else { + VIR_INFO("Domain %s successfully suspended.", vm->def->domaindependencies[i]->domainName); + } + } + if (virDomainSuspendEnsureACL(dom->conn, vm->def) < 0) goto cleanup; @@ -1960,9 +2055,23 @@ static int qemuDomainResume(virDomainPtr dom) int reason; virQEMUDriverConfigPtr cfg = NULL; + int i = 0; + if (!(vm = qemuDomObjFromDomain(dom))) return -1; + for (i = 0; i < vm->def->ndomaindependencies; ++i) { + if (qemuDomainResume(virGetDomain(dom->conn, + vm->def->domaindependencies[i]->domainName, + vm->def->domaindependencies[i]->domainUuid)) < 0) { + VIR_WARN("Problem to resume domain %s.", vm->def->domaindependencies[i]->domainName); + } + else { + VIR_INFO("Domain %s successfully resumed.", vm->def->domaindependencies[i]->domainName); + } + } + + cfg = virQEMUDriverGetConfig(driver); if (virDomainResumeEnsureACL(dom->conn, vm->def) < 0) @@ -2265,11 +2374,25 @@ qemuDomainDestroyFlags(virDomainPtr dom, qemuDomainObjPrivatePtr priv; unsigned int stopFlags = 0; + int i = 0; + virCheckFlags(VIR_DOMAIN_DESTROY_GRACEFUL, -1); if (!(vm = qemuDomObjFromDomain(dom))) return -1; + for (i = 0; i < vm->def->ndomaindependencies; ++i) { + /* The dependency domain is destroyed with the same flag as the parent */ + if (qemuDomainDestroyFlags(virGetDomain(dom->conn, + vm->def->domaindependencies[i]->domainName, + vm->def->domaindependencies[i]->domainUuid), flags) < 0) { + VIR_WARN("Problem occurs : impossible to destroy domain %s.", vm->def->domaindependencies[i]->domainName); + } + else { + VIR_INFO("Domain %s successfully destroyed.", vm->def->domaindependencies[i]->domainName); + } + } + priv = vm->privateData; if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0) -- 1.9.1

On Wed, Mar 23, 2016 at 09:55:18AM +0100, Valentin BOUSSON wrote:
This patch series adds a feature that enables libvirt domains to have other domains as dependencies.
One possible target is the simulation of a complex computing system composed of multiple CPUs, each of which represented by a different libvirt domain. CPUs in this example are virtualized separately, by a dedicated QEMU instance, because all of them are booting independently. Moreover, if those CPU must share some physical property (for example power supply or ACPI), it is meaningful to consider them as a group.
Another possible target is Asymmetric Multi Processor (AMP) systems. Where a master processor uses one or more slave processors to offload computation. Master and slave have often different architectures. This patch series makes possible to define the slave domains as dependencies of the master domain. And the whole system to be booted with one single libvirt command.
A use-case for this libvirt extension are the recent patch series in QEMU that enable modeling an AMP-like system with multiple QEMU instances.
[snip] I wish you had raised this for discussion before spending time & effort to implement it :-( Personally I don't really think this kind of thing belongs in libvirt at all. In any non-trivial system there are going to be dependancies on more than just domains having been started. For example, dependancies on networking or firewall setup. There may also be dependancy on actually waiting for the guest OS to startup. So in general I think this is the kind of thing belongs in the higher level management applications like oVirt and OpenStack which have visibility into the entire picture. This really goes back to our mantra that libvirt provides the mechanism only, while the application using libvirt provides the policy. Startup ordering between domains really is policy, not mechanism. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
participants (2)
-
Daniel P. Berrange
-
Valentin BOUSSON