Support overriding Schedule annotations via template.metadata.annotations (#10045)
Run the E2E test on kind / setup-test-matrix (push) Successful in 4s
e2e-test-kind.yaml / extract (push) Failing after 13s
Run the E2E test on kind / get-go-version (push) Failing after 14s
Run the E2E test on kind / build (push) Skipped
Run the E2E test on kind / run-e2e-test (push) Skipped
push.yml / extract (push) Successful in 14s
Main CI / get-go-version (push) Successful in 16s
Main CI / Build (push) Failing after 2m46s

* Support overriding Schedule annotations via template.metadata.annotations

Adds an Annotations field to BackupSpec.Metadata, mirroring the existing
Labels override. When Schedule.Spec.Template.Metadata.Annotations is set,
it is used for the resulting Backup's annotations instead of copying
Schedule.Annotations directly, allowing users to opt out of unwanted
annotations (e.g. ArgoCD tracking annotations) being propagated from
Schedule to Backup.

Fixes #5836

Signed-off-by: Lubron Zhan <lubronzhan@gmail.com>

* Rename changelog fragment to match PR number 10045

Signed-off-by: Lubron Zhan <lubronzhan@gmail.com>

---------

Signed-off-by: Lubron Zhan <lubronzhan@gmail.com>
Co-authored-by: Daniel Jiang <daniel.jiang@broadcom.com>
This commit is contained in:
Lubron
2026-07-29 15:55:51 +08:00
committed by GitHub
co-authored by Daniel Jiang
parent 5ca38aa075
commit 5691f7f29d
9 changed files with 128 additions and 6 deletions
+1
View File
@@ -0,0 +1 @@
Fix issue #5836, respect schedule.spec.template.metadata.annotations to override annotations copied from the Schedule to Backup objects, matching the existing behavior for labels
@@ -393,6 +393,11 @@ spec:
x-kubernetes-map-type: atomic
metadata:
properties:
annotations:
additionalProperties:
type: string
nullable: true
type: object
labels:
additionalProperties:
type: string
@@ -434,6 +434,11 @@ spec:
x-kubernetes-map-type: atomic
metadata:
properties:
annotations:
additionalProperties:
type: string
nullable: true
type: object
labels:
additionalProperties:
type: string
File diff suppressed because one or more lines are too long
+3
View File
@@ -23,6 +23,9 @@ import (
type Metadata struct {
Labels map[string]string `json:"labels,omitempty"`
// +optional
// +nullable
Annotations map[string]string `json:"annotations,omitempty"`
}
// BackupSpec defines the specification for a Velero backup.
@@ -895,6 +895,13 @@ func (in *Metadata) DeepCopyInto(out *Metadata) {
(*out)[key] = val
}
}
if in.Annotations != nil {
in, out := &in.Annotations, &out.Annotations
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Metadata.
+17 -2
View File
@@ -109,8 +109,23 @@ func (b *BackupBuilder) FromSchedule(schedule *velerov1api.Schedule) *BackupBuil
b.object.Spec = schedule.Spec.Template
b.ObjectMeta(WithLabelsMap(labels))
if schedule.Annotations != nil {
b.ObjectMeta(WithAnnotationsMap(schedule.Annotations))
var annotations map[string]string
// Check if there's explicit Annotations defined in the Schedule object template
// and if present then copy it to the backup object.
if schedule.Spec.Template.Metadata.Annotations != nil {
logger := logging.DefaultLogger(logging.LogLevelFlag(logrus.InfoLevel).Parse(), logging.NewFormatFlag().Parse())
annotations = schedule.Spec.Template.Metadata.Annotations
logger.WithFields(logrus.Fields{
"backup": fmt.Sprintf("%s/%s", b.object.GetNamespace(), b.object.GetName()),
"annotations": schedule.Spec.Template.Metadata.Annotations,
}).Info("Schedule.template.metadata.annotations set - using those annotations instead of schedule.annotations for backup object")
} else {
annotations = schedule.Annotations
}
if annotations != nil {
b.ObjectMeta(WithAnnotationsMap(annotations))
}
if boolptr.IsSetToTrue(schedule.Spec.UseOwnerReferencesInBackup) {
+84
View File
@@ -0,0 +1,84 @@
/*
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 (
"testing"
"github.com/stretchr/testify/assert"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
)
func TestBackupFromSchedule(t *testing.T) {
tests := []struct {
name string
schedule *velerov1api.Schedule
expectedLabels map[string]string
expectedAnnotations map[string]string
}{
{
name: "no schedule labels/annotations and no template overrides",
schedule: ForSchedule("velero", "test").
Result(),
expectedLabels: map[string]string{velerov1api.ScheduleNameLabel: "test"},
expectedAnnotations: nil,
},
{
name: "schedule labels/annotations are copied when no template override is set",
schedule: ForSchedule("velero", "test").
ObjectMeta(
WithLabels("schedule-label", "schedule-value"),
WithAnnotations("schedule-annotation", "schedule-value"),
).
Result(),
expectedLabels: map[string]string{
"schedule-label": "schedule-value",
velerov1api.ScheduleNameLabel: "test",
},
expectedAnnotations: map[string]string{"schedule-annotation": "schedule-value"},
},
{
name: "template.metadata.labels/annotations override schedule labels/annotations",
schedule: ForSchedule("velero", "test").
ObjectMeta(
WithLabels("schedule-label", "schedule-value"),
WithAnnotations("schedule-annotation", "schedule-value"),
).
Template(velerov1api.BackupSpec{
Metadata: velerov1api.Metadata{
Labels: map[string]string{"template-label": "template-value"},
Annotations: map[string]string{"template-annotation": "template-value"},
},
}).
Result(),
expectedLabels: map[string]string{
"template-label": "template-value",
velerov1api.ScheduleNameLabel: "test",
},
expectedAnnotations: map[string]string{"template-annotation": "template-value"},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
backup := ForBackup("velero", "test-backup").FromSchedule(test.schedule).Result()
assert.Equal(t, test.expectedLabels, backup.GetLabels())
assert.Equal(t, test.expectedAnnotations, backup.GetAnnotations())
})
}
}
+4 -2
View File
@@ -155,11 +155,13 @@ spec:
uploaderConfig:
# ParallelFilesUpload is the number of files parallel uploads to perform when using the uploader.
parallelFilesUpload: 10
# The labels you want on backup objects, created from this schedule (instead of copying the labels you have on schedule object itself).
# When this field is set, the labels from the Schedule resource are not copied to the Backup resource.
# The labels/annotations you want on backup objects, created from this schedule (instead of copying the labels/annotations you have on schedule object itself).
# When this field is set, the labels/annotations from the Schedule resource are not copied to the Backup resource.
metadata:
labels:
labelname: somelabelvalue
annotations:
annotationname: someannotationvalue
# Actions to perform at different times during a backup. The only hook supported is
# executing a command in a container in a pod using the pod exec API. Optional.
hooks: