From ec8fe27c7e6de6f584529cb9d70cfad1a2392e6a Mon Sep 17 00:00:00 2001 From: Scott Seago Date: Wed, 26 Aug 2026 10:57:53 -0400 Subject: [PATCH 1/5] feat: add SkipQuiesce annotation logic to DataUpload creation Co-authored-by: aider (vertex_ai/gemini-3.1-pro-preview) --- kubevirt-datamover-plugin/vm/backup.go | 21 ++++++++- kubevirt-datamover-plugin/vm/backup_test.go | 51 +++++++++++++++++++-- 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/kubevirt-datamover-plugin/vm/backup.go b/kubevirt-datamover-plugin/vm/backup.go index 4d7e47af..0eb59f86 100644 --- a/kubevirt-datamover-plugin/vm/backup.go +++ b/kubevirt-datamover-plugin/vm/backup.go @@ -564,7 +564,7 @@ func (p *BackupPlugin) createDataUpload(vm *kvcore.VirtualMachine, backup *veler Labels: map[string]string{ velerov1.BackupNameLabel: controllercommon.SafeLabelValue(backup.Name), }, - Annotations: buildDataUploadAnnotations(vm, operationID), + Annotations: buildDataUploadAnnotations(vm, backup, operationID), OwnerReferences: []metav1.OwnerReference{ { APIVersion: "velero.io/v1", @@ -894,7 +894,7 @@ func (p *BackupPlugin) patchDataUploadCancel(namespace, name string, cancel bool // buildDataUploadAnnotations constructs the annotation map for a DataUpload CR. // It includes required controller annotations and propagates optional per-VM // annotations (like backup-pvc-size) from the VM to the DataUpload. -func buildDataUploadAnnotations(vm *kvcore.VirtualMachine, operationID string) map[string]string { +func buildDataUploadAnnotations(vm *kvcore.VirtualMachine, backup *velerov1.Backup, operationID string) map[string]string { annotations := map[string]string{ controllercommon.AnnotationVMName: vm.Name, controllercommon.AnnotationVMNamespace: vm.Namespace, @@ -909,6 +909,23 @@ func buildDataUploadAnnotations(vm *kvcore.VirtualMachine, operationID string) m } } + // Handle SkipQuiesce annotation + vmHasSkip := false + vmSkipVal := "" + if vm.Annotations != nil { + vmSkipVal, vmHasSkip = vm.Annotations[controllercommon.AnnotationSkipQuiesce] + } + + if vmHasSkip { + if vmSkipVal == "true" { + annotations[controllercommon.AnnotationSkipQuiesce] = "true" + } + } else { + if backup.Annotations != nil && backup.Annotations[controllercommon.AnnotationSkipQuiesce] == "true" { + annotations[controllercommon.AnnotationSkipQuiesce] = "true" + } + } + return annotations } diff --git a/kubevirt-datamover-plugin/vm/backup_test.go b/kubevirt-datamover-plugin/vm/backup_test.go index 93f0e2c4..54527662 100644 --- a/kubevirt-datamover-plugin/vm/backup_test.go +++ b/kubevirt-datamover-plugin/vm/backup_test.go @@ -1627,6 +1627,7 @@ func vmToUnstructured(t *testing.T, vm *kvcore.VirtualMachine) runtime.Unstructu func TestBuildDataUploadAnnotations(t *testing.T) { operationID := "test-op-123" + dummyBackup := &velerov1.Backup{} t.Run("includes required annotations", func(t *testing.T) { vm := &kvcore.VirtualMachine{ @@ -1636,7 +1637,7 @@ func TestBuildDataUploadAnnotations(t *testing.T) { }, } - annotations := buildDataUploadAnnotations(vm, operationID) + annotations := buildDataUploadAnnotations(vm, dummyBackup, operationID) assert.Equal(t, "my-vm", annotations[controllercommon.AnnotationVMName]) assert.Equal(t, "my-ns", annotations[controllercommon.AnnotationVMNamespace]) @@ -1655,7 +1656,7 @@ func TestBuildDataUploadAnnotations(t *testing.T) { }, } - annotations := buildDataUploadAnnotations(vm, operationID) + annotations := buildDataUploadAnnotations(vm, dummyBackup, operationID) assert.Equal(t, "50Gi", annotations["kubevirt-datamover.io/backup-pvc-size"]) assert.Equal(t, "my-vm", annotations[controllercommon.AnnotationVMName]) @@ -1672,8 +1673,52 @@ func TestBuildDataUploadAnnotations(t *testing.T) { }, } - annotations := buildDataUploadAnnotations(vm, operationID) + annotations := buildDataUploadAnnotations(vm, dummyBackup, operationID) assert.NotContains(t, annotations, "kubevirt-datamover.io/backup-pvc-size") }) + + t.Run("sets SkipQuiesce from VM when true", func(t *testing.T) { + vm := &kvcore.VirtualMachine{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + controllercommon.AnnotationSkipQuiesce: "true", + }, + }, + } + annotations := buildDataUploadAnnotations(vm, dummyBackup, operationID) + assert.Equal(t, "true", annotations[controllercommon.AnnotationSkipQuiesce]) + }) + + t.Run("does not set SkipQuiesce from VM when false", func(t *testing.T) { + vm := &kvcore.VirtualMachine{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + controllercommon.AnnotationSkipQuiesce: "false", + }, + }, + } + backup := &velerov1.Backup{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + controllercommon.AnnotationSkipQuiesce: "true", // Should be ignored because VM explicitly set it to false + }, + }, + } + annotations := buildDataUploadAnnotations(vm, backup, operationID) + assert.NotContains(t, annotations, controllercommon.AnnotationSkipQuiesce) + }) + + t.Run("sets SkipQuiesce from Backup when VM annotation is absent", func(t *testing.T) { + vm := &kvcore.VirtualMachine{} + backup := &velerov1.Backup{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + controllercommon.AnnotationSkipQuiesce: "true", + }, + }, + } + annotations := buildDataUploadAnnotations(vm, backup, operationID) + assert.Equal(t, "true", annotations[controllercommon.AnnotationSkipQuiesce]) + }) } From 300f588a6e663aa2edbda55e15aa5c42a82fc218 Mon Sep 17 00:00:00 2001 From: Scott Seago Date: Wed, 26 Aug 2026 11:07:26 -0400 Subject: [PATCH 2/5] update go.mod/go.sum to controller PR branch --- go.mod | 2 ++ go.sum | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 07e3989f..29351336 100644 --- a/go.mod +++ b/go.mod @@ -170,3 +170,5 @@ replace github.com/vmware-tanzu/velero => github.com/openshift/velero v0.10.2-0. replace github.com/kcp-dev/kcp/sdk v0.0.0-00010101000000-000000000000 => github.com/kcp-dev/kcp/sdk v0.27.1 exclude github.com/kcp-dev/kcp/sdk v0.0.0-00010101000000-000000000000 + +replace github.com/migtools/kubevirt-datamover-controller => github.com/sseago/kubevirt-datamover-controller v0.0.0-20260825201137-9b046d66a00f diff --git a/go.sum b/go.sum index fedf2eb9..3e3e6471 100644 --- a/go.sum +++ b/go.sum @@ -316,8 +316,6 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/migtools/kubevirt-datamover-controller v0.0.0-20260903012300-4d3903ae4508 h1:HYyietesdIe9lgZlNqO1ejq+kve4Eavdp1A7bBN7dAQ= -github.com/migtools/kubevirt-datamover-controller v0.0.0-20260903012300-4d3903ae4508/go.mod h1:zOlAYRuAi5zbxJEfB/RPJaS//T3UdxPi86o6uWJwDds= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -394,6 +392,8 @@ github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= +github.com/sseago/kubevirt-datamover-controller v0.0.0-20260825201137-9b046d66a00f h1:Q/ZhNSVd9wUVgkV+lunZ87D8rhTXbpVzBR7CMRsTSuw= +github.com/sseago/kubevirt-datamover-controller v0.0.0-20260825201137-9b046d66a00f/go.mod h1:iSmvYsXVwyOvelmwFM7kr9WZzlbycW6IbG57pJdioqo= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= From 378e3d7202739f081ba3c6ba9d80a858abd45add Mon Sep 17 00:00:00 2001 From: Scott Seago Date: Thu, 3 Sep 2026 15:22:16 -0400 Subject: [PATCH 3/5] feat: update SkipQuiesce annotation logic to support true, false, and auto Co-authored-by: aider (vertex_ai/gemini-3.1-pro-preview) --- kubevirt-datamover-plugin/vm/backup.go | 29 +++++--- kubevirt-datamover-plugin/vm/backup_test.go | 76 ++++++++++++++++++++- 2 files changed, 92 insertions(+), 13 deletions(-) diff --git a/kubevirt-datamover-plugin/vm/backup.go b/kubevirt-datamover-plugin/vm/backup.go index 0eb59f86..1daed0c8 100644 --- a/kubevirt-datamover-plugin/vm/backup.go +++ b/kubevirt-datamover-plugin/vm/backup.go @@ -910,22 +910,31 @@ func buildDataUploadAnnotations(vm *kvcore.VirtualMachine, backup *velerov1.Back } // Handle SkipQuiesce annotation - vmHasSkip := false - vmSkipVal := "" + effectiveSkipVal := "" + + // Check VM annotation first if vm.Annotations != nil { - vmSkipVal, vmHasSkip = vm.Annotations[controllercommon.AnnotationSkipQuiesce] + if val, ok := vm.Annotations[controllercommon.AnnotationSkipQuiesce]; ok { + if val == "true" || val == "false" || val == "auto" { + effectiveSkipVal = val + } + } } - if vmHasSkip { - if vmSkipVal == "true" { - annotations[controllercommon.AnnotationSkipQuiesce] = "true" - } - } else { - if backup.Annotations != nil && backup.Annotations[controllercommon.AnnotationSkipQuiesce] == "true" { - annotations[controllercommon.AnnotationSkipQuiesce] = "true" + // Fallback to Backup annotation if VM annotation is absent or invalid + if effectiveSkipVal == "" && backup.Annotations != nil { + if val, ok := backup.Annotations[controllercommon.AnnotationSkipQuiesce]; ok { + if val == "true" || val == "false" || val == "auto" { + effectiveSkipVal = val + } } } + // Only set on DataUpload if the effective value is "true" or "false" + if effectiveSkipVal == "true" || effectiveSkipVal == "false" { + annotations[controllercommon.AnnotationSkipQuiesce] = effectiveSkipVal + } + return annotations } diff --git a/kubevirt-datamover-plugin/vm/backup_test.go b/kubevirt-datamover-plugin/vm/backup_test.go index 54527662..40a2c49d 100644 --- a/kubevirt-datamover-plugin/vm/backup_test.go +++ b/kubevirt-datamover-plugin/vm/backup_test.go @@ -1690,7 +1690,7 @@ func TestBuildDataUploadAnnotations(t *testing.T) { assert.Equal(t, "true", annotations[controllercommon.AnnotationSkipQuiesce]) }) - t.Run("does not set SkipQuiesce from VM when false", func(t *testing.T) { + t.Run("sets SkipQuiesce from VM when false", func(t *testing.T) { vm := &kvcore.VirtualMachine{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ @@ -1706,11 +1706,36 @@ func TestBuildDataUploadAnnotations(t *testing.T) { }, } annotations := buildDataUploadAnnotations(vm, backup, operationID) + assert.Equal(t, "false", annotations[controllercommon.AnnotationSkipQuiesce]) + }) + + t.Run("does not set SkipQuiesce when VM is auto", func(t *testing.T) { + vm := &kvcore.VirtualMachine{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + controllercommon.AnnotationSkipQuiesce: "auto", + }, + }, + } + backup := &velerov1.Backup{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + controllercommon.AnnotationSkipQuiesce: "true", // Should be ignored because VM explicitly set it to auto + }, + }, + } + annotations := buildDataUploadAnnotations(vm, backup, operationID) assert.NotContains(t, annotations, controllercommon.AnnotationSkipQuiesce) }) - t.Run("sets SkipQuiesce from Backup when VM annotation is absent", func(t *testing.T) { - vm := &kvcore.VirtualMachine{} + t.Run("falls back to Backup when VM annotation is invalid", func(t *testing.T) { + vm := &kvcore.VirtualMachine{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + controllercommon.AnnotationSkipQuiesce: "invalid-value", + }, + }, + } backup := &velerov1.Backup{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{ @@ -1721,4 +1746,49 @@ func TestBuildDataUploadAnnotations(t *testing.T) { annotations := buildDataUploadAnnotations(vm, backup, operationID) assert.Equal(t, "true", annotations[controllercommon.AnnotationSkipQuiesce]) }) + + t.Run("sets SkipQuiesce from Backup when VM annotation is absent", func(t *testing.T) { + vm := &kvcore.VirtualMachine{} + backup := &velerov1.Backup{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + controllercommon.AnnotationSkipQuiesce: "false", + }, + }, + } + annotations := buildDataUploadAnnotations(vm, backup, operationID) + assert.Equal(t, "false", annotations[controllercommon.AnnotationSkipQuiesce]) + }) + + t.Run("does not set SkipQuiesce when Backup is auto and VM is absent", func(t *testing.T) { + vm := &kvcore.VirtualMachine{} + backup := &velerov1.Backup{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + controllercommon.AnnotationSkipQuiesce: "auto", + }, + }, + } + annotations := buildDataUploadAnnotations(vm, backup, operationID) + assert.NotContains(t, annotations, controllercommon.AnnotationSkipQuiesce) + }) + + t.Run("does not set SkipQuiesce when both are invalid", func(t *testing.T) { + vm := &kvcore.VirtualMachine{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + controllercommon.AnnotationSkipQuiesce: "invalid-vm", + }, + }, + } + backup := &velerov1.Backup{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + controllercommon.AnnotationSkipQuiesce: "invalid-backup", + }, + }, + } + annotations := buildDataUploadAnnotations(vm, backup, operationID) + assert.NotContains(t, annotations, controllercommon.AnnotationSkipQuiesce) + }) } From 73dda00bf2ceb9c98c2e37167b47fbb4f4fa5331 Mon Sep 17 00:00:00 2001 From: Scott Seago Date: Wed, 9 Sep 2026 15:18:31 -0400 Subject: [PATCH 4/5] updated go deps to pull in most recent controller commit Signed-off-by: Scott Seago --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 29351336..58517a59 100644 --- a/go.mod +++ b/go.mod @@ -171,4 +171,4 @@ replace github.com/kcp-dev/kcp/sdk v0.0.0-00010101000000-000000000000 => github. exclude github.com/kcp-dev/kcp/sdk v0.0.0-00010101000000-000000000000 -replace github.com/migtools/kubevirt-datamover-controller => github.com/sseago/kubevirt-datamover-controller v0.0.0-20260825201137-9b046d66a00f +replace github.com/migtools/kubevirt-datamover-controller => github.com/migtools/kubevirt-datamover-controller v0.0.0-20260904191729-4f588ce7dc71 From a9daf648b5dbde71541310c05299fda9797ff29f Mon Sep 17 00:00:00 2001 From: Scott Seago Date: Wed, 9 Sep 2026 16:26:44 -0400 Subject: [PATCH 5/5] go mod tidy Signed-off-by: Scott Seago --- go.sum | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go.sum b/go.sum index 3e3e6471..45d0851b 100644 --- a/go.sum +++ b/go.sum @@ -316,6 +316,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/migtools/kubevirt-datamover-controller v0.0.0-20260904191729-4f588ce7dc71 h1:qmD1V7wBfZJWx4F9XXps5wmEsxTKFN3ZDXwLlCt/IDA= +github.com/migtools/kubevirt-datamover-controller v0.0.0-20260904191729-4f588ce7dc71/go.mod h1:iSmvYsXVwyOvelmwFM7kr9WZzlbycW6IbG57pJdioqo= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -392,8 +394,6 @@ github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= -github.com/sseago/kubevirt-datamover-controller v0.0.0-20260825201137-9b046d66a00f h1:Q/ZhNSVd9wUVgkV+lunZ87D8rhTXbpVzBR7CMRsTSuw= -github.com/sseago/kubevirt-datamover-controller v0.0.0-20260825201137-9b046d66a00f/go.mod h1:iSmvYsXVwyOvelmwFM7kr9WZzlbycW6IbG57pJdioqo= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=