[PATCH v2 0/4] backup: Allow configuring incremental backup per-disk individually

This series addresses some of the testing issues raised in the review of 4/4. Patches 1-3 are new adding testing of virDomainBackupAlignDisks. Peter Krempa (4): backupxml2xmltest: Remove output symlink of 'backup-pull-internal-invalid' virDomainBackupDiskDefFormat: Format internal disk state only when valid backupxml2xmltest: Call 'virDomainBackupAlignDisks' before formatting output backup: Allow configuring incremental backup per-disk individually docs/formatbackup.rst | 11 ++++ docs/schemas/domainbackup.rng | 23 +++++++++ src/conf/backup_conf.c | 51 ++++++++++++++++++- src/conf/backup_conf.h | 11 ++++ tests/domainbackupxml2xmlin/backup-pull.xml | 12 +++++ .../backup-pull-encrypted.xml | 7 +-- .../backup-pull-internal-invalid.xml | 38 +++++++++++++- .../backup-pull-seclabel.xml | 5 +- tests/domainbackupxml2xmlout/backup-pull.xml | 15 +++++- .../backup-push-encrypted.xml | 7 +-- .../backup-push-seclabel.xml | 5 +- tests/domainbackupxml2xmlout/backup-push.xml | 3 +- tests/domainbackupxml2xmlout/empty.xml | 8 ++- tests/genericxml2xmltest.c | 36 +++++++++++++ 14 files changed, 216 insertions(+), 16 deletions(-) mode change 120000 => 100644 tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml -- 2.26.2

Replace the output by a copy of the input file for further changes once we start testing virDomainBackupAlignDisks. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- .../backup-pull-internal-invalid.xml | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) mode change 120000 => 100644 tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml diff --git a/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml b/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml deleted file mode 120000 index 055ca37a0b..0000000000 --- a/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml +++ /dev/null @@ -1 +0,0 @@ -../domainbackupxml2xmlin/backup-pull-internal-invalid.xml \ No newline at end of file diff --git a/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml b/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml new file mode 100644 index 0000000000..ba8f7ca3ab --- /dev/null +++ b/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml @@ -0,0 +1,36 @@ +<domainbackup mode='pull'> + <incremental>1525889631</incremental> + <server transport='tcp' tls='yes' name='localhost' port='10809'/> + <disks> + <disk name='vda' backup='yes' state='running' type='file' exportname='test-vda' exportbitmap='blah'> + <driver type='qcow2'/> + <scratch file='/path/to/file'> + <encryption format='luks'> + <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccc2f80d6f'/> + </encryption> + </scratch> + </disk> + <disk name='vdb' backup='yes' state='complete' type='file' exportname='test-vda' exportbitmap='blah'> + <driver type='qcow2'/> + <scratch file='/path/to/file'> + <encryption format='luks'> + <secret type='passphrase' usage='/storage/backup/vdb'/> + </encryption> + </scratch> + </disk> + <disk name='vdc' backup='yes' state='running' type='block'> + <driver type='qcow2'/> + <scratch dev='/dev/block'> + <encryption format='luks'> + <secret type='passphrase' usage='/storage/backup/vdc'/> + </encryption> + </scratch> + </disk> + </disks> + <privateData> + <objects> + <secret type='tlskey' alias='test-tlskey'/> + <TLSx509 alias='test-tlsobj'/> + </objects> + </privateData> +</domainbackup> -- 2.26.2

On 7/7/20 10:23 AM, Peter Krempa wrote:
Replace the output by a copy of the input file for further changes once we start testing virDomainBackupAlignDisks.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- .../backup-pull-internal-invalid.xml | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) mode change 120000 => 100644 tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml
Reviewed-by: Eric Blake <eblake@redhat.com> -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3226 Virtualization: qemu.org | libvirt.org

Format the disk state only when it isn't _NONE. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/conf/backup_conf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conf/backup_conf.c b/src/conf/backup_conf.c index 781dd53f6b..5e4144d371 100644 --- a/src/conf/backup_conf.c +++ b/src/conf/backup_conf.c @@ -370,7 +370,7 @@ virDomainBackupDiskDefFormat(virBufferPtr buf, virBufferEscapeString(&attrBuf, " name='%s'", disk->name); virBufferAsprintf(&attrBuf, " backup='%s'", virTristateBoolTypeToString(disk->backup)); - if (internal) + if (internal && disk->state != VIR_DOMAIN_BACKUP_DISK_STATE_NONE) virBufferAsprintf(&attrBuf, " state='%s'", virDomainBackupDiskStateTypeToString(disk->state)); if (disk->backup == VIR_TRISTATE_BOOL_YES) { -- 2.26.2

On 7/7/20 10:23 AM, Peter Krempa wrote:
Format the disk state only when it isn't _NONE.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/conf/backup_conf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Eric Blake <eblake@redhat.com>
diff --git a/src/conf/backup_conf.c b/src/conf/backup_conf.c index 781dd53f6b..5e4144d371 100644 --- a/src/conf/backup_conf.c +++ b/src/conf/backup_conf.c @@ -370,7 +370,7 @@ virDomainBackupDiskDefFormat(virBufferPtr buf,
virBufferEscapeString(&attrBuf, " name='%s'", disk->name); virBufferAsprintf(&attrBuf, " backup='%s'", virTristateBoolTypeToString(disk->backup)); - if (internal) + if (internal && disk->state != VIR_DOMAIN_BACKUP_DISK_STATE_NONE) virBufferAsprintf(&attrBuf, " state='%s'", virDomainBackupDiskStateTypeToString(disk->state));
Pre-existing long line; do we care?
if (disk->backup == VIR_TRISTATE_BOOL_YES) {
-- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3226 Virtualization: qemu.org | libvirt.org

Call the post-processing function so that we can validate that it does the correct thing. virDomainBackupAlignDisks requires disk definitions to be present so let's fake them by copying disks from the backup definition and add one extra disk 'vdextradisk'. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- .../backup-pull-encrypted.xml | 1 + .../backup-pull-internal-invalid.xml | 1 + .../backup-pull-seclabel.xml | 1 + tests/domainbackupxml2xmlout/backup-pull.xml | 1 + .../backup-push-encrypted.xml | 1 + .../backup-push-seclabel.xml | 1 + tests/domainbackupxml2xmlout/backup-push.xml | 1 + tests/domainbackupxml2xmlout/empty.xml | 8 ++++- tests/genericxml2xmltest.c | 36 +++++++++++++++++++ 9 files changed, 50 insertions(+), 1 deletion(-) diff --git a/tests/domainbackupxml2xmlout/backup-pull-encrypted.xml b/tests/domainbackupxml2xmlout/backup-pull-encrypted.xml index ea9dcf72b9..3c3042111d 100644 --- a/tests/domainbackupxml2xmlout/backup-pull-encrypted.xml +++ b/tests/domainbackupxml2xmlout/backup-pull-encrypted.xml @@ -26,5 +26,6 @@ </encryption> </scratch> </disk> + <disk name='vdextradisk' backup='no'/> </disks> </domainbackup> diff --git a/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml b/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml index ba8f7ca3ab..9702978ce0 100644 --- a/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml +++ b/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml @@ -26,6 +26,7 @@ </encryption> </scratch> </disk> + <disk name='vdextradisk' backup='no'/> </disks> <privateData> <objects> diff --git a/tests/domainbackupxml2xmlout/backup-pull-seclabel.xml b/tests/domainbackupxml2xmlout/backup-pull-seclabel.xml index 450f007d3a..38330394f7 100644 --- a/tests/domainbackupxml2xmlout/backup-pull-seclabel.xml +++ b/tests/domainbackupxml2xmlout/backup-pull-seclabel.xml @@ -14,5 +14,6 @@ <seclabel model='dac' relabel='no'/> </scratch> </disk> + <disk name='vdextradisk' backup='no'/> </disks> </domainbackup> diff --git a/tests/domainbackupxml2xmlout/backup-pull.xml b/tests/domainbackupxml2xmlout/backup-pull.xml index 24fce9c0e7..4952270a5a 100644 --- a/tests/domainbackupxml2xmlout/backup-pull.xml +++ b/tests/domainbackupxml2xmlout/backup-pull.xml @@ -6,5 +6,6 @@ <scratch file='/path/to/file'/> </disk> <disk name='hda' backup='no'/> + <disk name='vdextradisk' backup='no'/> </disks> </domainbackup> diff --git a/tests/domainbackupxml2xmlout/backup-push-encrypted.xml b/tests/domainbackupxml2xmlout/backup-push-encrypted.xml index a955340964..2a5aad93cd 100644 --- a/tests/domainbackupxml2xmlout/backup-push-encrypted.xml +++ b/tests/domainbackupxml2xmlout/backup-push-encrypted.xml @@ -25,5 +25,6 @@ </encryption> </target> </disk> + <disk name='vdextradisk' backup='no'/> </disks> </domainbackup> diff --git a/tests/domainbackupxml2xmlout/backup-push-seclabel.xml b/tests/domainbackupxml2xmlout/backup-push-seclabel.xml index 9986889ba3..59af3e6a6c 100644 --- a/tests/domainbackupxml2xmlout/backup-push-seclabel.xml +++ b/tests/domainbackupxml2xmlout/backup-push-seclabel.xml @@ -13,5 +13,6 @@ <seclabel model='dac' relabel='no'/> </target> </disk> + <disk name='vdextradisk' backup='no'/> </disks> </domainbackup> diff --git a/tests/domainbackupxml2xmlout/backup-push.xml b/tests/domainbackupxml2xmlout/backup-push.xml index 1997c814ae..bc11a93d94 100644 --- a/tests/domainbackupxml2xmlout/backup-push.xml +++ b/tests/domainbackupxml2xmlout/backup-push.xml @@ -6,5 +6,6 @@ <target file='/path/to/file'/> </disk> <disk name='hda' backup='no'/> + <disk name='vdextradisk' backup='no'/> </disks> </domainbackup> diff --git a/tests/domainbackupxml2xmlout/empty.xml b/tests/domainbackupxml2xmlout/empty.xml index b1ba4953be..52d2b4f0af 100644 --- a/tests/domainbackupxml2xmlout/empty.xml +++ b/tests/domainbackupxml2xmlout/empty.xml @@ -1 +1,7 @@ -<domainbackup mode='push'/> +<domainbackup mode='push'> + <disks> + <disk name='vdextradisk' backup='yes' type='file'> + <target file='/fake/vdextradisk.qcow2.SUFFIX'/> + </disk> + </disks> +</domainbackup> diff --git a/tests/genericxml2xmltest.c b/tests/genericxml2xmltest.c index 2c1e8616dd..8b9b0bafb6 100644 --- a/tests/genericxml2xmltest.c +++ b/tests/genericxml2xmltest.c @@ -51,6 +51,23 @@ struct testCompareBackupXMLData { }; +static virDomainDiskDefPtr +testCompareBackupXMLGetFakeDomdisk(const char *dst) +{ + virDomainDiskDefPtr domdisk = NULL; + + if (!(domdisk = virDomainDiskDefNew(NULL))) + abort(); + + domdisk->dst = g_strdup(dst); + domdisk->src->type = VIR_STORAGE_TYPE_FILE; + domdisk->src->format = VIR_STORAGE_FILE_QCOW2; + domdisk->src->path = g_strdup_printf("/fake/%s.qcow2", dst); + + return domdisk; +} + + static int testCompareBackupXML(const void *opaque) { @@ -63,6 +80,8 @@ testCompareBackupXML(const void *opaque) g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER; g_autofree char *actual = NULL; unsigned int parseFlags = 0; + g_autoptr(virDomainDef) fakedef = NULL; + size_t i; if (data->internal) parseFlags |= VIR_DOMAIN_BACKUP_PARSE_INTERNAL; @@ -80,6 +99,23 @@ testCompareBackupXML(const void *opaque) return -1; } + /* create a fake definition and fill it with disks */ + if (!(fakedef = virDomainDefNew())) + return -1; + + fakedef->ndisks = backup->ndisks + 1; + fakedef->disks = g_new0(virDomainDiskDefPtr, fakedef->ndisks); + + for (i = 0; i < backup->ndisks; i++) + fakedef->disks[i] = testCompareBackupXMLGetFakeDomdisk(backup->disks[i].name); + + fakedef->disks[fakedef->ndisks -1 ] = testCompareBackupXMLGetFakeDomdisk("vdextradisk"); + + if (virDomainBackupAlignDisks(backup, fakedef, "SUFFIX") < 0) { + VIR_TEST_VERBOSE("failed to align backup def '%s'", file_in); + return -1; + } + if (virDomainBackupDefFormat(&buf, backup, data->internal) < 0) { VIR_TEST_VERBOSE("failed to format backup def '%s'", file_in); return -1; -- 2.26.2

On 7/7/20 10:23 AM, Peter Krempa wrote:
Call the post-processing function so that we can validate that it does the correct thing.
virDomainBackupAlignDisks requires disk definitions to be present so let's fake them by copying disks from the backup definition and add one extra disk 'vdextradisk'.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- More testing is always useful.
Reviewed-by: Eric Blake <eblake@redhat.com> -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3226 Virtualization: qemu.org | libvirt.org

The semantics of the backup operation don't strictly require that all disks being backed up are part of the same incremental part (when a disk was checkpointed/backed up separately or in a different VM), or even they may not have an previous checkpoint at all (e.g. when the disk was freshly hotplugged to the vm). In such cases we can still create a common checkpoint for all of them and backup differences according to configuration. This patch adds a per-disk configuration of the checkpoint to do the incremental backup from via the 'incremental' attribute and allows perform full backups via the 'backupmode' attribute. Note that no changes to the qemu driver are necessary to take advantage of this as we already obey the per-disk 'incremental' field. https://bugzilla.redhat.com/show_bug.cgi?id=1829829 Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- v2: - backupmode=full incremental="..." is now rejected by the RNG schema - test output changes as we now validate virDomainBackupAlignDisks - typo fix docs/formatbackup.rst | 11 +++++ docs/schemas/domainbackup.rng | 23 +++++++++ src/conf/backup_conf.c | 49 ++++++++++++++++++- src/conf/backup_conf.h | 11 +++++ tests/domainbackupxml2xmlin/backup-pull.xml | 12 +++++ .../backup-pull-encrypted.xml | 6 +-- .../backup-pull-internal-invalid.xml | 6 +-- .../backup-pull-seclabel.xml | 4 +- tests/domainbackupxml2xmlout/backup-pull.xml | 14 +++++- .../backup-push-encrypted.xml | 6 +-- .../backup-push-seclabel.xml | 4 +- tests/domainbackupxml2xmlout/backup-push.xml | 2 +- tests/domainbackupxml2xmlout/empty.xml | 2 +- 13 files changed, 133 insertions(+), 17 deletions(-) diff --git a/docs/formatbackup.rst b/docs/formatbackup.rst index 17431fe51a..1b9e6ebb22 100644 --- a/docs/formatbackup.rst +++ b/docs/formatbackup.rst @@ -69,6 +69,17 @@ were supplied). The following child elements and attributes are supported: should take part in the backup and using ``no`` excludes the disk from the backup. + ``backupmode`` + This attribute overrides the implied backup mode inherited from the + definition of the backup itself. Value ``full`` forces a full backup + even if the backup calls for an incremental backup, and ``incremental`` + coupled with the attribute ``incremental='CHECKPOINTNAME`` for the disk + forces an incremental backup from ``CHECKPOINTNAME``. + + ``incremental`` + An optional attribute giving the name of an existing checkpoint of the + domain which overrides the one set by the ``<incremental>`` element. + ``exportname`` Allows modification of the NBD export name for the given disk. By default equal to disk target. Valid only for pull mode backups. diff --git a/docs/schemas/domainbackup.rng b/docs/schemas/domainbackup.rng index c0e17f512b..579b62a658 100644 --- a/docs/schemas/domainbackup.rng +++ b/docs/schemas/domainbackup.rng @@ -96,6 +96,27 @@ </element> </define> + + <define name='backupDiskMode'> + <optional> + <choice> + <attribute name='backupmode'> + <value>full</value> + </attribute> + <group> + <optional> + <attribute name='backupmode'> + <value>incremental</value> + </attribute> + </optional> + <optional> + <attribute name='incremental'/> + </optional> + </group> + </choice> + </optional> + </define> + <define name='backupPushDriver'> <optional> <element name='driver'> @@ -134,6 +155,7 @@ <attribute name='name'> <ref name='diskTarget'/> </attribute> + <ref name='backupDiskMode'/> <choice> <group> <attribute name='backup'> @@ -203,6 +225,7 @@ <attribute name='name'> <ref name='diskTarget'/> </attribute> + <ref name='backupDiskMode'/> <optional> <attribute name='exportname'> <text/> diff --git a/src/conf/backup_conf.c b/src/conf/backup_conf.c index 5e4144d371..02319f7245 100644 --- a/src/conf/backup_conf.c +++ b/src/conf/backup_conf.c @@ -56,6 +56,13 @@ VIR_ENUM_IMPL(virDomainBackupDiskState, "cancelling", "cancelled"); +VIR_ENUM_DECL(virDomainBackupDiskBackupMode); +VIR_ENUM_IMPL(virDomainBackupDiskBackupMode, + VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_LAST, + "", + "full", + "incremental"); + void virDomainBackupDefFree(virDomainBackupDefPtr def) { @@ -100,6 +107,7 @@ virDomainBackupDiskDefParseXML(xmlNodePtr node, g_autofree char *driver = NULL; g_autofree char *backup = NULL; g_autofree char *state = NULL; + g_autofree char *backupmode = NULL; int tmp; xmlNodePtr srcNode; unsigned int storageSourceParseFlags = 0; @@ -137,6 +145,19 @@ virDomainBackupDiskDefParseXML(xmlNodePtr node, def->exportbitmap = virXMLPropString(node, "exportbitmap"); } + if ((backupmode = virXMLPropString(node, "backupmode"))) { + if ((tmp = virDomainBackupDiskBackupModeTypeFromString(backupmode)) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("invalid backupmode '%s' of disk '%s'"), + backupmode, def->name); + return -1; + } + + def->backupmode = tmp; + } + + def->incremental = virXMLPropString(node, "incremental"); + if (internal) { if (!(state = virXMLPropString(node, "state")) || (tmp = virDomainBackupDiskStateTypeFromString(state)) < 0) { @@ -376,6 +397,13 @@ virDomainBackupDiskDefFormat(virBufferPtr buf, if (disk->backup == VIR_TRISTATE_BOOL_YES) { virBufferAsprintf(&attrBuf, " type='%s'", virStorageTypeToString(disk->store->type)); + if (disk->backupmode != VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_DEFAULT) { + virBufferAsprintf(&attrBuf, " backupmode='%s'", + virDomainBackupDiskBackupModeTypeToString(disk->backupmode)); + } + + virBufferEscapeString(&attrBuf, " incremental='%s'", disk->incremental); + virBufferEscapeString(&attrBuf, " exportname='%s'", disk->exportname); virBufferEscapeString(&attrBuf, " exportbitmap='%s'", disk->exportbitmap); @@ -524,6 +552,16 @@ virDomainBackupAlignDisks(virDomainBackupDefPtr def, return -1; } + if (backupdisk->backupmode == VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_INCREMENTAL && + !backupdisk->incremental && + !def->incremental) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("'incremental' backup mode of disk '%s' requires setting 'incremental' field for disk or backup"), + backupdisk->name); + return -1; + } + + if (backupdisk->backup == VIR_TRISTATE_BOOL_YES && virDomainBackupDefAssignStore(backupdisk, domdisk->src, suffix) < 0) return -1; @@ -561,7 +599,16 @@ virDomainBackupAlignDisks(virDomainBackupDefPtr def, for (i = 0; i < def->ndisks; i++) { virDomainBackupDiskDefPtr backupdisk = &def->disks[i]; - if (def->incremental && !backupdisk->incremental) + if (backupdisk->backupmode == VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_DEFAULT) { + if (def->incremental || backupdisk->incremental) { + backupdisk->backupmode = VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_INCREMENTAL; + } else { + backupdisk->backupmode = VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_FULL; + } + } + + if (!backupdisk->incremental && + backupdisk->backupmode == VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_INCREMENTAL) backupdisk->incremental = g_strdup(def->incremental); } diff --git a/src/conf/backup_conf.h b/src/conf/backup_conf.h index aa2d6d4b68..bda2bdcfe4 100644 --- a/src/conf/backup_conf.h +++ b/src/conf/backup_conf.h @@ -45,12 +45,23 @@ typedef enum { VIR_DOMAIN_BACKUP_DISK_STATE_LAST } virDomainBackupDiskState; + +typedef enum { + VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_DEFAULT = 0, + VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_FULL, + VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_INCREMENTAL, + + VIR_DOMAIN_BACKUP_DISK_BACKUP_MODE_LAST +} virDomainBackupDiskBackupMode; + + /* Stores disk-backup information */ typedef struct _virDomainBackupDiskDef virDomainBackupDiskDef; typedef virDomainBackupDiskDef *virDomainBackupDiskDefPtr; struct _virDomainBackupDiskDef { char *name; /* name matching the <target dev='...' of the domain */ virTristateBool backup; /* whether backup is requested */ + virDomainBackupDiskBackupMode backupmode; char *incremental; /* name of the starting point checkpoint of an incremental backup */ char *exportname; /* name of the NBD export for pull mode backup */ char *exportbitmap; /* name of the bitmap exposed in NBD for pull mode backup */ diff --git a/tests/domainbackupxml2xmlin/backup-pull.xml b/tests/domainbackupxml2xmlin/backup-pull.xml index c0bea4771d..c51f0995ac 100644 --- a/tests/domainbackupxml2xmlin/backup-pull.xml +++ b/tests/domainbackupxml2xmlin/backup-pull.xml @@ -6,5 +6,17 @@ <scratch file='/path/to/file'/> </disk> <disk name='hda' backup='no'/> + <disk name='vdc' type='file' backupmode='full'> + <scratch file='/path/to/file'/> + </disk> + <disk name='vdd' type='file' backupmode='incremental'> + <scratch file='/path/to/file'/> + </disk> + <disk name='vde' type='file' backupmode='incremental' incremental='blah'> + <scratch file='/path/to/file'/> + </disk> + <disk name='vdf' type='file' incremental='bleh'> + <scratch file='/path/to/file'/> + </disk> </disks> </domainbackup> diff --git a/tests/domainbackupxml2xmlout/backup-pull-encrypted.xml b/tests/domainbackupxml2xmlout/backup-pull-encrypted.xml index 3c3042111d..42051d1d24 100644 --- a/tests/domainbackupxml2xmlout/backup-pull-encrypted.xml +++ b/tests/domainbackupxml2xmlout/backup-pull-encrypted.xml @@ -2,7 +2,7 @@ <incremental>1525889631</incremental> <server transport='tcp' tls='yes' name='localhost' port='10809'/> <disks> - <disk name='vda' backup='yes' type='file' exportname='test-vda' exportbitmap='blah'> + <disk name='vda' backup='yes' type='file' backupmode='incremental' incremental='1525889631' exportname='test-vda' exportbitmap='blah'> <driver type='qcow2'/> <scratch file='/path/to/file'> <encryption format='luks'> @@ -10,7 +10,7 @@ </encryption> </scratch> </disk> - <disk name='vdb' backup='yes' type='file' exportname='test-vda' exportbitmap='blah'> + <disk name='vdb' backup='yes' type='file' backupmode='incremental' incremental='1525889631' exportname='test-vda' exportbitmap='blah'> <driver type='qcow2'/> <scratch file='/path/to/file'> <encryption format='luks'> @@ -18,7 +18,7 @@ </encryption> </scratch> </disk> - <disk name='vdc' backup='yes' type='block'> + <disk name='vdc' backup='yes' type='block' backupmode='incremental' incremental='1525889631'> <driver type='qcow2'/> <scratch dev='/dev/block'> <encryption format='luks'> diff --git a/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml b/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml index 9702978ce0..092b6bf8a7 100644 --- a/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml +++ b/tests/domainbackupxml2xmlout/backup-pull-internal-invalid.xml @@ -2,7 +2,7 @@ <incremental>1525889631</incremental> <server transport='tcp' tls='yes' name='localhost' port='10809'/> <disks> - <disk name='vda' backup='yes' state='running' type='file' exportname='test-vda' exportbitmap='blah'> + <disk name='vda' backup='yes' state='running' type='file' backupmode='incremental' incremental='1525889631' exportname='test-vda' exportbitmap='blah'> <driver type='qcow2'/> <scratch file='/path/to/file'> <encryption format='luks'> @@ -10,7 +10,7 @@ </encryption> </scratch> </disk> - <disk name='vdb' backup='yes' state='complete' type='file' exportname='test-vda' exportbitmap='blah'> + <disk name='vdb' backup='yes' state='complete' type='file' backupmode='incremental' incremental='1525889631' exportname='test-vda' exportbitmap='blah'> <driver type='qcow2'/> <scratch file='/path/to/file'> <encryption format='luks'> @@ -18,7 +18,7 @@ </encryption> </scratch> </disk> - <disk name='vdc' backup='yes' state='running' type='block'> + <disk name='vdc' backup='yes' state='running' type='block' backupmode='incremental' incremental='1525889631'> <driver type='qcow2'/> <scratch dev='/dev/block'> <encryption format='luks'> diff --git a/tests/domainbackupxml2xmlout/backup-pull-seclabel.xml b/tests/domainbackupxml2xmlout/backup-pull-seclabel.xml index 38330394f7..385d949ae3 100644 --- a/tests/domainbackupxml2xmlout/backup-pull-seclabel.xml +++ b/tests/domainbackupxml2xmlout/backup-pull-seclabel.xml @@ -2,13 +2,13 @@ <incremental>1525889631</incremental> <server transport='tcp' name='localhost' port='10809'/> <disks> - <disk name='vda' backup='yes' type='file' exportname='test-vda' exportbitmap='blah'> + <disk name='vda' backup='yes' type='file' backupmode='incremental' incremental='1525889631' exportname='test-vda' exportbitmap='blah'> <driver type='qcow2'/> <scratch file='/path/to/file'> <seclabel model='dac' relabel='no'/> </scratch> </disk> - <disk name='vdb' backup='yes' type='block'> + <disk name='vdb' backup='yes' type='block' backupmode='incremental' incremental='1525889631'> <driver type='qcow2'/> <scratch dev='/dev/block'> <seclabel model='dac' relabel='no'/> diff --git a/tests/domainbackupxml2xmlout/backup-pull.xml b/tests/domainbackupxml2xmlout/backup-pull.xml index 4952270a5a..1762ba72b5 100644 --- a/tests/domainbackupxml2xmlout/backup-pull.xml +++ b/tests/domainbackupxml2xmlout/backup-pull.xml @@ -2,10 +2,22 @@ <incremental>1525889631</incremental> <server transport='tcp' name='localhost' port='10809'/> <disks> - <disk name='vda' backup='yes' type='file'> + <disk name='vda' backup='yes' type='file' backupmode='incremental' incremental='1525889631'> <scratch file='/path/to/file'/> </disk> <disk name='hda' backup='no'/> + <disk name='vdc' backup='yes' type='file' backupmode='full'> + <scratch file='/path/to/file'/> + </disk> + <disk name='vdd' backup='yes' type='file' backupmode='incremental' incremental='1525889631'> + <scratch file='/path/to/file'/> + </disk> + <disk name='vde' backup='yes' type='file' backupmode='incremental' incremental='blah'> + <scratch file='/path/to/file'/> + </disk> + <disk name='vdf' backup='yes' type='file' backupmode='incremental' incremental='bleh'> + <scratch file='/path/to/file'/> + </disk> <disk name='vdextradisk' backup='no'/> </disks> </domainbackup> diff --git a/tests/domainbackupxml2xmlout/backup-push-encrypted.xml b/tests/domainbackupxml2xmlout/backup-push-encrypted.xml index 2a5aad93cd..3b664b0dcb 100644 --- a/tests/domainbackupxml2xmlout/backup-push-encrypted.xml +++ b/tests/domainbackupxml2xmlout/backup-push-encrypted.xml @@ -1,7 +1,7 @@ <domainbackup mode='push'> <incremental>1525889631</incremental> <disks> - <disk name='vda' backup='yes' type='file'> + <disk name='vda' backup='yes' type='file' backupmode='incremental' incremental='1525889631'> <driver type='qcow2'/> <target file='/path/to/file'> <encryption format='luks'> @@ -9,7 +9,7 @@ </encryption> </target> </disk> - <disk name='vdb' backup='yes' type='file'> + <disk name='vdb' backup='yes' type='file' backupmode='incremental' incremental='1525889631'> <driver type='raw'/> <target file='/path/to/file'> <encryption format='luks'> @@ -17,7 +17,7 @@ </encryption> </target> </disk> - <disk name='vdc' backup='yes' type='block'> + <disk name='vdc' backup='yes' type='block' backupmode='incremental' incremental='1525889631'> <driver type='qcow2'/> <target dev='/dev/block'> <encryption format='luks'> diff --git a/tests/domainbackupxml2xmlout/backup-push-seclabel.xml b/tests/domainbackupxml2xmlout/backup-push-seclabel.xml index 59af3e6a6c..9a0d2b3061 100644 --- a/tests/domainbackupxml2xmlout/backup-push-seclabel.xml +++ b/tests/domainbackupxml2xmlout/backup-push-seclabel.xml @@ -1,13 +1,13 @@ <domainbackup mode='push'> <incremental>1525889631</incremental> <disks> - <disk name='vda' backup='yes' type='file'> + <disk name='vda' backup='yes' type='file' backupmode='incremental' incremental='1525889631'> <driver type='raw'/> <target file='/path/to/file'> <seclabel model='dac' relabel='no'/> </target> </disk> - <disk name='vdb' backup='yes' type='block'> + <disk name='vdb' backup='yes' type='block' backupmode='incremental' incremental='1525889631'> <driver type='qcow2'/> <target dev='/dev/block'> <seclabel model='dac' relabel='no'/> diff --git a/tests/domainbackupxml2xmlout/backup-push.xml b/tests/domainbackupxml2xmlout/backup-push.xml index bc11a93d94..317dcf6e47 100644 --- a/tests/domainbackupxml2xmlout/backup-push.xml +++ b/tests/domainbackupxml2xmlout/backup-push.xml @@ -1,7 +1,7 @@ <domainbackup mode='push'> <incremental>1525889631</incremental> <disks> - <disk name='vda' backup='yes' type='file'> + <disk name='vda' backup='yes' type='file' backupmode='incremental' incremental='1525889631'> <driver type='raw'/> <target file='/path/to/file'/> </disk> diff --git a/tests/domainbackupxml2xmlout/empty.xml b/tests/domainbackupxml2xmlout/empty.xml index 52d2b4f0af..b1cbd154ab 100644 --- a/tests/domainbackupxml2xmlout/empty.xml +++ b/tests/domainbackupxml2xmlout/empty.xml @@ -1,6 +1,6 @@ <domainbackup mode='push'> <disks> - <disk name='vdextradisk' backup='yes' type='file'> + <disk name='vdextradisk' backup='yes' type='file' backupmode='full'> <target file='/fake/vdextradisk.qcow2.SUFFIX'/> </disk> </disks> -- 2.26.2

On 7/7/20 10:23 AM, Peter Krempa wrote:
The semantics of the backup operation don't strictly require that all disks being backed up are part of the same incremental part (when a disk was checkpointed/backed up separately or in a different VM), or even they may not have an previous checkpoint at all (e.g. when the disk
s/an/a/
was freshly hotplugged to the vm).
In such cases we can still create a common checkpoint for all of them and backup differences according to configuration.
This patch adds a per-disk configuration of the checkpoint to do the incremental backup from via the 'incremental' attribute and allows perform full backups via the 'backupmode' attribute.
Note that no changes to the qemu driver are necessary to take advantage of this as we already obey the per-disk 'incremental' field.
https://bugzilla.redhat.com/show_bug.cgi?id=1829829
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- v2: - backupmode=full incremental="..." is now rejected by the RNG schema - test output changes as we now validate virDomainBackupAlignDisks - typo fix
Reviewed-by: Eric Blake <eblake@redhat.com> -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3226 Virtualization: qemu.org | libvirt.org
participants (2)
-
Eric Blake
-
Peter Krempa