The VM Generation ID is a mechanism to provide a unique 128-bit, cryptographically random, and integer value identifier known as the GUID (Globally Unique Identifier) to the guest OS. The value is used to help notify the guest operating system when the virtual machine is executed with a different configuration. This patch adds support for a new "genid" XML element similar to the "uuid" element. The "genid" element can have two forms "<genid/>" or "<genid>$GUID</genid>". If the $GUID is not provided, libvirt will generate one. For the ABI checks add avoidance for the genid comparison if the appropriate flag is set. Since adding support for a generated GUID (or UUID like) value to be displayed only for an active guest, modifying the xml2xml test to include virrandommock.so is necessary since it will generate a "known" UUID value that can be compared against for the active test. Signed-off-by: John Ferlan <jferlan@xxxxxxxxxx> --- docs/formatdomain.html.in | 29 ++++++++++++ docs/schemas/domaincommon.rng | 8 ++++ src/conf/domain_conf.c | 59 ++++++++++++++++++++++++ src/conf/domain_conf.h | 3 ++ tests/qemuxml2argvdata/genid-auto.xml | 32 +++++++++++++ tests/qemuxml2argvdata/genid.xml | 32 +++++++++++++ tests/qemuxml2xmloutdata/genid-active.xml | 32 +++++++++++++ tests/qemuxml2xmloutdata/genid-auto-active.xml | 32 +++++++++++++ tests/qemuxml2xmloutdata/genid-auto-inactive.xml | 32 +++++++++++++ tests/qemuxml2xmloutdata/genid-inactive.xml | 32 +++++++++++++ tests/qemuxml2xmltest.c | 5 +- 11 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 tests/qemuxml2argvdata/genid-auto.xml create mode 100644 tests/qemuxml2argvdata/genid.xml create mode 100644 tests/qemuxml2xmloutdata/genid-active.xml create mode 100644 tests/qemuxml2xmloutdata/genid-auto-active.xml create mode 100644 tests/qemuxml2xmloutdata/genid-auto-inactive.xml create mode 100644 tests/qemuxml2xmloutdata/genid-inactive.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 5e99884dc5..fe9c3b19f0 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -34,6 +34,7 @@ <domain type='kvm' id='1'> <name>MyGuest</name> <uuid>4dea22b3-1d52-d8f3-2516-782e98ab3fa0</uuid> + <genid>43dc0cf8-809b-4adb-9bea-a9abb5f3d90e</genid> <title>A short description - title - of the domain</title> <description>Some human readable description</description> <metadata> @@ -61,6 +62,34 @@ specification. <span class="since">Since 0.0.1, sysinfo since 0.8.7</span></dd> + <dt><code>genid</code></dt> + <dd><span class="since">Since 4.3.0</span>, the <code>genid</code> + element can be used to add a Virtual Machine Generation ID which + exposes a 128-bit, cryptographically random, integer value identifier, + referred to as a Globally Unique Identifier (GUID) using the same + format as the <code>uuid</code>. The value is used to help notify + the guest operating system when the virtual machine is executed + with a different configuration, such as: + + <ul> + <li>snapshot execution</li> + <li>backup recovery</li> + <li>failover in a disaster recovery environment</li> + <li>creation from template (import, copy, clone)</li> + </ul> + + The guest operating system notices the change and is then able to + react as appropriate by marking its copies of distributed databases + as dirty, re-initializing its random number generator, etc. + + <p> + When a GUID value is not provided, e.g. using the XML syntax + <genid/>, then libvirt will automatically generate a GUID. + This is the recommended configuration since the hypervisor then + can handle changing the GUID value for specific state transitions. + Using a static GUID value may result in failures for starting from + snapshot, restoring from backup, starting a cloned domain, etc.</p></dd> + <dt><code>title</code></dt> <dd>The optional element <code>title</code> provides space for a short description of the domain. The title should not contain diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 4cab55f05d..1892a7c63c 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -502,6 +502,14 @@ <ref name="UUID"/> </element> </optional> + <optional> + <element name="genid"> + <choice> + <ref name="UUID"/> + <empty/> + </choice> + </element> + </optional> </interleave> </define> <define name="idmap"> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 385ba4ce8c..0fa9386270 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -18791,6 +18791,34 @@ virDomainDefParseXML(xmlDocPtr xml, VIR_FREE(tmp); } + /* Extract domain genid - a genid can either be provided or generated */ + if ((n = virXPathNodeSet("./genid", ctxt, &nodes)) < 0) + goto error; + + if (n > 0) { + if (n != 1) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("element 'genid' can only appear once")); + goto error; + } + def->genidRequested = true; + if (!(tmp = virXPathString("string(./genid[1])", ctxt))) { + if (virUUIDGenerate(def->genid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Failed to generate genid")); + goto error; + } + def->genidGenerated = true; + } else { + if (virUUIDParse(tmp, def->genid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("malformed genid element")); + goto error; + } + } + } + VIR_FREE(nodes); + /* Extract short description of domain (title) */ def->title = virXPathString("string(./title[1])", ctxt); if (def->title && strchr(def->title, '\n')) { @@ -21903,6 +21931,26 @@ virDomainDefCheckABIStabilityFlags(virDomainDefPtr src, goto error; } + if (src->genidRequested != dst->genidRequested) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Target domain requested genid does not match source")); + goto error; + } + + if (src->genidRequested && + !(flags & VIR_DOMAIN_DEF_ABI_CHECK_SKIP_GENID) && + memcmp(src->genid, dst->genid, VIR_UUID_BUFLEN) != 0) { + char guidsrc[VIR_UUID_STRING_BUFLEN]; + char guiddst[VIR_UUID_STRING_BUFLEN]; + + virUUIDFormat(src->genid, guidsrc); + virUUIDFormat(dst->genid, guiddst); + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target domain genid %s does not match source %s"), + guiddst, guidsrc); + goto error; + } + /* Not strictly ABI related, but we want to make sure domains * don't get silently re-named through the backdoor when passing * custom XML into various APIs, since this would create havoc @@ -26540,6 +26588,17 @@ virDomainDefFormatInternal(virDomainDefPtr def, virUUIDFormat(uuid, uuidstr); virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuidstr); + if (def->genidRequested) { + char genidstr[VIR_UUID_STRING_BUFLEN]; + + virUUIDFormat(def->genid, genidstr); + if (!def->genidGenerated || + !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE)) + virBufferAsprintf(buf, "<genid>%s</genid>\n", genidstr); + else + virBufferAddLit(buf, "<genid/>\n"); + } + virBufferEscapeString(buf, "<title>%s</title>\n", def->title); virBufferEscapeString(buf, "<description>%s</description>\n", diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index dc748162b9..dfd44bd9ff 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2947,6 +2947,9 @@ typedef enum { /* Set when domain lock must be released and there exists the possibility * that some external action could alter the value, such as cur_balloon. */ VIR_DOMAIN_DEF_ABI_CHECK_SKIP_VOLATILE = 1 << 0, + + /* Set when the ABI check should skip the genid comparison */ + VIR_DOMAIN_DEF_ABI_CHECK_SKIP_GENID = 1 << 1, } virDomainDefABICheckFlags; virDomainDeviceDefPtr virDomainDeviceDefParse(const char *xmlStr, diff --git a/tests/qemuxml2argvdata/genid-auto.xml b/tests/qemuxml2argvdata/genid-auto.xml new file mode 100644 index 0000000000..96ad9ddda8 --- /dev/null +++ b/tests/qemuxml2argvdata/genid-auto.xml @@ -0,0 +1,32 @@ +<domain type='qemu' id='1'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <genid/> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <acpi/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/genid.xml b/tests/qemuxml2argvdata/genid.xml new file mode 100644 index 0000000000..fc41f2dd28 --- /dev/null +++ b/tests/qemuxml2argvdata/genid.xml @@ -0,0 +1,32 @@ +<domain type='qemu' id='1'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <genid>e9392370-2917-565e-692b-d057f46512d6</genid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <acpi/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/genid-active.xml b/tests/qemuxml2xmloutdata/genid-active.xml new file mode 100644 index 0000000000..fc41f2dd28 --- /dev/null +++ b/tests/qemuxml2xmloutdata/genid-active.xml @@ -0,0 +1,32 @@ +<domain type='qemu' id='1'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <genid>e9392370-2917-565e-692b-d057f46512d6</genid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <acpi/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/genid-auto-active.xml b/tests/qemuxml2xmloutdata/genid-auto-active.xml new file mode 100644 index 0000000000..aeca0d7fc0 --- /dev/null +++ b/tests/qemuxml2xmloutdata/genid-auto-active.xml @@ -0,0 +1,32 @@ +<domain type='qemu' id='1'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <genid>00010203-0405-4607-8809-0a0b0c0d0e0f</genid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <acpi/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/genid-auto-inactive.xml b/tests/qemuxml2xmloutdata/genid-auto-inactive.xml new file mode 100644 index 0000000000..83c924395b --- /dev/null +++ b/tests/qemuxml2xmloutdata/genid-auto-inactive.xml @@ -0,0 +1,32 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <genid/> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <acpi/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/genid-inactive.xml b/tests/qemuxml2xmloutdata/genid-inactive.xml new file mode 100644 index 0000000000..8bd526a7a9 --- /dev/null +++ b/tests/qemuxml2xmloutdata/genid-inactive.xml @@ -0,0 +1,32 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <genid>e9392370-2917-565e-692b-d057f46512d6</genid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <acpi/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index d123180e79..0240dae051 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -276,6 +276,8 @@ mymain(void) setenv("PATH", "/bin", 1); DO_TEST("minimal", NONE); + DO_TEST("genid", NONE); + DO_TEST("genid-auto", NONE); DO_TEST("machine-core-on", NONE); DO_TEST("machine-core-off", NONE); DO_TEST("machine-loadparm-multiple-disks-nets-s390", NONE); @@ -1284,7 +1286,8 @@ mymain(void) } VIR_TEST_MAIN_PRELOAD(mymain, - abs_builddir "/.libs/virpcimock.so") + abs_builddir "/.libs/virpcimock.so", + abs_builddir "/.libs/virrandommock.so") #else -- 2.13.6 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list