From 5daef9b809575e8a7461d106b9b3655cec8871b0 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 e946b2780b06abfc393401811bc11b3e2f32ce80 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, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e05cf0f4..522e2867 100644 --- a/go.mod +++ b/go.mod @@ -170,6 +170,6 @@ replace github.com/vmware-tanzu/velero => github.com/openshift/velero v0.10.2-0. exclude github.com/kcp-dev/kcp/sdk v0.0.0-00010101000000-000000000000 -replace github.com/migtools/kubevirt-datamover-controller => github.com/migtools/kubevirt-datamover-controller v0.0.0-20260729163752-37185892c605 +replace github.com/migtools/kubevirt-datamover-controller => github.com/sseago/kubevirt-datamover-controller v0.0.0-20260825201137-9b046d66a00f replace github.com/vmware-tanzu/velero/pkg/apis => github.com/openshift/velero/pkg/apis v0.0.0-20260805134104-2091b09b93bb diff --git a/go.sum b/go.sum index 0a85311d..30bc2dca 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.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLGs= github.com/mattn/go-isatty v0.0.21/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= -github.com/migtools/kubevirt-datamover-controller v0.0.0-20260729163752-37185892c605 h1:6+jbDzfKRShcU1cp7TVrw8ZY/Ub9cAa7n5Geh6q55rk= -github.com/migtools/kubevirt-datamover-controller v0.0.0-20260729163752-37185892c605/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= @@ -396,6 +394,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.7.0 h1:uXe1MflJoHw58wAUvxVlcM7WpKtijWG7I1UidcGh6g4= github.com/spiffe/go-spiffe/v2 v2.7.0/go.mod h1:47Q0Q9/AqGha8QLHp+kxpH4Wca7X7EnOtlIJy3mxZ3U= +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 48096c56af829bad8995ffa05dd3d7f3eec54fe2 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 7c10afd216d758a80f1682e9a18c64c89927e9bf 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 522e2867..c3732594 100644 --- a/go.mod +++ b/go.mod @@ -170,6 +170,6 @@ replace github.com/vmware-tanzu/velero => github.com/openshift/velero v0.10.2-0. 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 replace github.com/vmware-tanzu/velero/pkg/apis => github.com/openshift/velero/pkg/apis v0.0.0-20260805134104-2091b09b93bb From 276241dff2b355e618fa0b9c2fda12b0ff841f9b 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 30bc2dca..8a2e3019 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.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLGs= github.com/mattn/go-isatty v0.0.21/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= +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= @@ -394,8 +396,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.7.0 h1:uXe1MflJoHw58wAUvxVlcM7WpKtijWG7I1UidcGh6g4= github.com/spiffe/go-spiffe/v2 v2.7.0/go.mod h1:47Q0Q9/AqGha8QLHp+kxpH4Wca7X7EnOtlIJy3mxZ3U= -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=