mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-08-28 11:56:42 +00:00
Run the E2E test on kind / setup-test-matrix (push) Failing after 4s
e2e-test-kind.yaml / extract (push) Failing after 11s
Run the E2E test on kind / get-go-version (push) Failing after 12s
Run the E2E test on kind / build (push) Skipped
Run the E2E test on kind / run-e2e-test (push) Skipped
push.yml / extract (push) Failing after 7s
Main CI / get-go-version (push) Failing after 8s
Main CI / Build (push) Skipped
* Report a measured zero incremental instead of erasing it A CBT incremental with an exactly zero delta -- nothing changed since the parent -- was reported identically to a backup that moved the whole device. `velero backup describe --details` printed only "Moved data Size (bytes): 3221225472" with no incremental line, and status.incrementalBytes was absent, for a run that transferred nothing. The best possible CBT outcome displayed as the worst, and was indistinguishable from a genuine full, a whole-device fallback, or a backup predating incremental accounting. The zero was being erased twice. Besides the API status fields, datapath.BackupResult also carried omitempty, and that struct crosses a JSON boundary from the data mover pod to the controller (see micro_service_watcher.go), so the value was destroyed before the controller could persist it. Every uploader always reports a figure there, so 0 internally always means "transferred nothing" -- dropping omitempty is sufficient and correct for that hop. The API fields move to *int64 rather than just dropping omitempty. The field shipped in v1.18.0-v1.18.2, so backups exist whose stored volume info has no incrementalSize at all; with a plain int64 those unmarshal to 0 and would render "Incremental data Size (bytes): 0", a false claim of a perfect incremental on a run that never measured one. nil means not measured, a pointer to 0 means measured zero. Both fields already carry +optional, so the generated CRD schema is unchanged and no regeneration is required. Display gates relax from > 0 to != nil in all three places, including volumesByPod.Add, whose signature takes *int64 now; the restore describer passes nil, which is correct since restores measure no incremental. Verified live: the same zero-delta scenario that reported <none> now reports 0 and renders "Incremental data Size (bytes): 0", while an older backup described with the new client still correctly prints no incremental line at all. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com> (cherry picked from commit 6c7aa9d588f6d5eab134d4ce19c92b838f45557c) Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com> * gofmt: fix import ordering in backup_test.go Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com> * Regenerate CRDs for IncrementalBytes pointer type make update-crd was missed in the original commit. Regenerated with the pinned controller-gen v0.16.5 to avoid unrelated version-annotation churn across other CRDs. Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com> * Add changelog for #10309 Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com> * Address review: make IncrementalBytes a pointer to preserve backward compat Per Lyndon-Li's review on #10309: dropping omitempty on the plain int64 field breaks compatibility with a data mover from release-1.17 or earlier that predates IncrementalBytes and never writes the key -- the new controller would unmarshal a zero value ("nothing transferred") instead of recognizing the field is simply absent ("not measured"). Switch to *int64 with omitempty restored: - an old mover's omitted key unmarshals to nil ("not measured") - a current mover's genuine zero still serializes the key, unmarshaling to a non-nil pointer to 0 ("measured zero") - nonzero values work exactly as before - an old controller can still unmarshal a numeric value from a new mover pkg/controller/data_upload_controller.go and pod_volume_backup_controller.go assign the wire-struct field directly to their already-*int64,omitempty CRD status field instead of re-wrapping it with ptr.To, since both are now the same pointer type. Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com> * Fix CI: update marshal-fail test assertions for IncrementalBytes pointer Both backup_micro_service_test.go files hardcoded the %v-formatted zero-value BackupResult struct in an error-message assertion. Now that IncrementalBytes is *int64, its zero value prints as <nil> instead of 0. Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com> --------- Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
195 lines
5.8 KiB
Go
195 lines
5.8 KiB
Go
/*
|
|
Copyright The Velero Contributors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package builder
|
|
|
|
import (
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"github.com/vmware-tanzu/velero/pkg/apis/velero/shared"
|
|
velerov2alpha1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
|
|
)
|
|
|
|
// DataUploadBuilder builds DataUpload objects
|
|
type DataUploadBuilder struct {
|
|
object *velerov2alpha1api.DataUpload
|
|
}
|
|
|
|
// ForDataUpload is the constructor for a DataUploadBuilder.
|
|
func ForDataUpload(ns, name string) *DataUploadBuilder {
|
|
return &DataUploadBuilder{
|
|
object: &velerov2alpha1api.DataUpload{
|
|
TypeMeta: metav1.TypeMeta{
|
|
APIVersion: velerov2alpha1api.SchemeGroupVersion.String(),
|
|
Kind: "DataUpload",
|
|
},
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Namespace: ns,
|
|
Name: name,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// Result returns the built DataUpload.
|
|
func (d *DataUploadBuilder) Result() *velerov2alpha1api.DataUpload {
|
|
return d.object
|
|
}
|
|
|
|
// BackupStorageLocation sets the DataUpload's backup storage location.
|
|
func (d *DataUploadBuilder) BackupStorageLocation(name string) *DataUploadBuilder {
|
|
d.object.Spec.BackupStorageLocation = name
|
|
return d
|
|
}
|
|
|
|
// Phase sets the DataUpload's phase.
|
|
func (d *DataUploadBuilder) Phase(phase velerov2alpha1api.DataUploadPhase) *DataUploadBuilder {
|
|
d.object.Status.Phase = phase
|
|
return d
|
|
}
|
|
|
|
// SnapshotID sets the DataUpload's SnapshotID.
|
|
func (d *DataUploadBuilder) SnapshotID(id string) *DataUploadBuilder {
|
|
d.object.Status.SnapshotID = id
|
|
return d
|
|
}
|
|
|
|
// DataMover sets the DataUpload's DataMover.
|
|
func (d *DataUploadBuilder) DataMover(dataMover string) *DataUploadBuilder {
|
|
d.object.Spec.DataMover = dataMover
|
|
return d
|
|
}
|
|
|
|
// SourceNamespace sets the DataUpload's SourceNamespace.
|
|
func (d *DataUploadBuilder) SourceNamespace(sourceNamespace string) *DataUploadBuilder {
|
|
d.object.Spec.SourceNamespace = sourceNamespace
|
|
return d
|
|
}
|
|
|
|
// SourcePVC sets the DataUpload's SourcePVC.
|
|
func (d *DataUploadBuilder) SourcePVC(sourcePVC string) *DataUploadBuilder {
|
|
d.object.Spec.SourcePVC = sourcePVC
|
|
return d
|
|
}
|
|
|
|
// SnapshotType sets the DataUpload's SnapshotType.
|
|
func (d *DataUploadBuilder) SnapshotType(SnapshotType velerov2alpha1api.SnapshotType) *DataUploadBuilder {
|
|
d.object.Spec.SnapshotType = SnapshotType
|
|
return d
|
|
}
|
|
|
|
// Cancel sets the DataUpload's Cancel.
|
|
func (d *DataUploadBuilder) Cancel(cancel bool) *DataUploadBuilder {
|
|
d.object.Spec.Cancel = cancel
|
|
return d
|
|
}
|
|
|
|
// OperationTimeout sets the DataUpload's OperationTimeout.
|
|
func (d *DataUploadBuilder) OperationTimeout(timeout metav1.Duration) *DataUploadBuilder {
|
|
d.object.Spec.OperationTimeout = timeout
|
|
return d
|
|
}
|
|
|
|
// DataMoverConfig sets the DataUpload's DataMoverConfig.
|
|
func (d *DataUploadBuilder) DataMoverConfig(config map[string]string) *DataUploadBuilder {
|
|
d.object.Spec.DataMoverConfig = config
|
|
return d
|
|
}
|
|
|
|
// CSISnapshot sets the DataUpload's CSISnapshot.
|
|
func (d *DataUploadBuilder) CSISnapshot(cSISnapshot *velerov2alpha1api.CSISnapshotSpec) *DataUploadBuilder {
|
|
d.object.Spec.CSISnapshot = cSISnapshot
|
|
return d
|
|
}
|
|
|
|
// StartTimestamp sets the DataUpload's StartTimestamp.
|
|
func (d *DataUploadBuilder) StartTimestamp(startTimestamp *metav1.Time) *DataUploadBuilder {
|
|
d.object.Status.StartTimestamp = startTimestamp
|
|
return d
|
|
}
|
|
|
|
// CompletionTimestamp sets the DataUpload's StartTimestamp.
|
|
func (d *DataUploadBuilder) CompletionTimestamp(completionTimestamp *metav1.Time) *DataUploadBuilder {
|
|
d.object.Status.CompletionTimestamp = completionTimestamp
|
|
return d
|
|
}
|
|
|
|
// Labels sets the DataUpload's Labels.
|
|
func (d *DataUploadBuilder) Labels(labels map[string]string) *DataUploadBuilder {
|
|
d.object.Labels = labels
|
|
return d
|
|
}
|
|
|
|
// Annotations sets the DataUpload's Annotations.
|
|
func (d *DataUploadBuilder) Annotations(annotations map[string]string) *DataUploadBuilder {
|
|
d.object.Annotations = annotations
|
|
return d
|
|
}
|
|
|
|
// Progress sets the DataUpload's Progress.
|
|
func (d *DataUploadBuilder) Progress(progress shared.DataMoveOperationProgress) *DataUploadBuilder {
|
|
d.object.Status.Progress = progress
|
|
return d
|
|
}
|
|
|
|
// IncrementalBytes sets the DataUpload's IncrementalBytes.
|
|
func (d *DataUploadBuilder) IncrementalBytes(incrementalBytes int64) *DataUploadBuilder {
|
|
d.object.Status.IncrementalBytes = &incrementalBytes
|
|
return d
|
|
}
|
|
|
|
// Node sets the DataUpload's Node.
|
|
func (d *DataUploadBuilder) Node(node string) *DataUploadBuilder {
|
|
d.object.Status.Node = node
|
|
return d
|
|
}
|
|
|
|
// NodeOS sets the DataUpload's Node OS.
|
|
func (d *DataUploadBuilder) NodeOS(nodeOS velerov2alpha1api.NodeOS) *DataUploadBuilder {
|
|
d.object.Status.NodeOS = nodeOS
|
|
return d
|
|
}
|
|
|
|
// AcceptedByNode sets the DataUpload's AcceptedByNode.
|
|
func (d *DataUploadBuilder) AcceptedByNode(node string) *DataUploadBuilder {
|
|
d.object.Status.AcceptedByNode = node
|
|
return d
|
|
}
|
|
|
|
// AcceptedTimestamp sets the DataUpload's AcceptedTimestamp.
|
|
func (d *DataUploadBuilder) AcceptedTimestamp(acceptedTimestamp *metav1.Time) *DataUploadBuilder {
|
|
d.object.Status.AcceptedTimestamp = acceptedTimestamp
|
|
return d
|
|
}
|
|
|
|
// Finalizers sets the DataUpload's Finalizers.
|
|
func (d *DataUploadBuilder) Finalizers(finalizers []string) *DataUploadBuilder {
|
|
d.object.Finalizers = finalizers
|
|
return d
|
|
}
|
|
|
|
// Message sets the DataUpload's Message.
|
|
func (d *DataUploadBuilder) Message(msg string) *DataUploadBuilder {
|
|
d.object.Status.Message = msg
|
|
return d
|
|
}
|
|
|
|
// TotalBytes sets the DataUpload's TotalBytes.
|
|
func (d *DataUploadBuilder) TotalBytes(size int64) *DataUploadBuilder {
|
|
d.object.Status.Progress.TotalBytes = size
|
|
return d
|
|
}
|