From e2839bbdecd1d8f0a4245589a8954c41d250f5ad Mon Sep 17 00:00:00 2001 From: Alvaro Romero Date: Fri, 25 Oct 2024 18:41:45 +0200 Subject: [PATCH] Include --annotations flag in backup and restore create commands This commit implements a new --annotations flag in the backup and restore create commands. This allows users to specify key-value pairs for annotations directly at the time of backup and restore creation, in the same way as the --labels flag. Signed-off-by: Alvaro Romero --- changelogs/unreleased/8354-alromeros | 1 + pkg/cmd/cli/backup/create.go | 5 ++++- pkg/cmd/cli/backup/create_test.go | 14 +++++++++++++- pkg/cmd/cli/restore/create.go | 10 +++++++--- pkg/cmd/cli/restore/create_test.go | 3 +++ 5 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 changelogs/unreleased/8354-alromeros diff --git a/changelogs/unreleased/8354-alromeros b/changelogs/unreleased/8354-alromeros new file mode 100644 index 0000000000..88bfae1b29 --- /dev/null +++ b/changelogs/unreleased/8354-alromeros @@ -0,0 +1 @@ +Include --annotations flag in backup and restore create commands diff --git a/pkg/cmd/cli/backup/create.go b/pkg/cmd/cli/backup/create.go index fc98ad17cf..6daacef7d8 100644 --- a/pkg/cmd/cli/backup/create.go +++ b/pkg/cmd/cli/backup/create.go @@ -94,6 +94,7 @@ type CreateOptions struct { IncludeNamespaceScopedResources flag.StringArray ExcludeNamespaceScopedResources flag.StringArray Labels flag.Map + Annotations flag.Map Selector flag.LabelSelector OrSelector flag.OrLabelSelector IncludeClusterResources flag.OptionalBool @@ -113,6 +114,7 @@ func NewCreateOptions() *CreateOptions { return &CreateOptions{ IncludeNamespaces: flag.NewStringArray("*"), Labels: flag.NewMap(), + Annotations: flag.NewMap(), SnapshotVolumes: flag.NewOptionalBool(nil), IncludeClusterResources: flag.NewOptionalBool(nil), } @@ -129,6 +131,7 @@ func (o *CreateOptions) BindFlags(flags *pflag.FlagSet) { flags.Var(&o.IncludeNamespaceScopedResources, "include-namespace-scoped-resources", "Namespaced resources to include in the backup, formatted as resource.group, such as deployments.apps(use '*' for all resources). Cannot work with include-resources, exclude-resources and include-cluster-resources.") flags.Var(&o.ExcludeNamespaceScopedResources, "exclude-namespace-scoped-resources", "Namespaced resources to exclude from the backup, formatted as resource.group, such as deployments.apps(use '*' for all resources). Cannot work with include-resources, exclude-resources and include-cluster-resources.") flags.Var(&o.Labels, "labels", "Labels to apply to the backup.") + flags.Var(&o.Annotations, "annotations", "Annotations to apply to the backup.") flags.StringVar(&o.StorageLocation, "storage-location", "", "Location in which to store the backup.") flags.StringSliceVar(&o.SnapshotLocations, "volume-snapshot-locations", o.SnapshotLocations, "List of locations (at most one per provider) where volume snapshots should be stored.") flags.VarP(&o.Selector, "selector", "l", "Only back up resources matching this label selector.") @@ -403,7 +406,7 @@ func (o *CreateOptions) BuildBackup(namespace string) (*velerov1api.Backup, erro } } - backup := backupBuilder.ObjectMeta(builder.WithLabelsMap(o.Labels.Data())).Result() + backup := backupBuilder.ObjectMeta(builder.WithLabelsMap(o.Labels.Data()), builder.WithAnnotationsMap(o.Annotations.Data())).Result() return backup, nil } diff --git a/pkg/cmd/cli/backup/create_test.go b/pkg/cmd/cli/backup/create_test.go index 640e5380ad..60ce69ea4f 100644 --- a/pkg/cmd/cli/backup/create_test.go +++ b/pkg/cmd/cli/backup/create_test.go @@ -43,6 +43,7 @@ import ( func TestCreateOptions_BuildBackup(t *testing.T) { o := NewCreateOptions() o.Labels.Set("velero.io/test=true") + o.Annotations.Set("velero.io/annTest=true") o.OrderedResources = "pods=p1,p2;persistentvolumeclaims=pvc1,pvc2" orders, err := ParseOrderedResources(o.OrderedResources) o.CSISnapshotTimeout = 20 * time.Minute @@ -75,6 +76,9 @@ func TestCreateOptions_BuildBackup(t *testing.T) { assert.Equal(t, map[string]string{ "velero.io/test": "true", }, backup.GetLabels()) + assert.Equal(t, map[string]string{ + "velero.io/annTest": "true", + }, backup.GetAnnotations()) assert.Equal(t, map[string]string{ "pods": "p1,p2", "persistentvolumeclaims": "pvc1,pvc2", @@ -113,8 +117,9 @@ func TestCreateOptions_BuildBackupFromSchedule(t *testing.T) { }, backup.GetAnnotations()) }) - t.Run("command line labels take precedence over schedule labels", func(t *testing.T) { + t.Run("command line labels and annotations take precedence over scheduled ones", func(t *testing.T) { o.Labels.Set("velero.io/test=yes,custom-label=true") + o.Annotations.Set("velero.io/test=yes,custom-annotation=true") backup, err := o.BuildBackup(cmdtest.VeleroNameSpace) assert.NoError(t, err) @@ -124,6 +129,10 @@ func TestCreateOptions_BuildBackupFromSchedule(t *testing.T) { velerov1api.ScheduleNameLabel: "test", "custom-label": "true", }, backup.GetLabels()) + assert.Equal(t, map[string]string{ + "velero.io/test": "yes", + "custom-annotation": "true", + }, backup.GetAnnotations()) }) } @@ -171,6 +180,7 @@ func TestCreateCommand(t *testing.T) { includeNamespaceScopedResources := "Endpoints,Event,PodTemplate" excludeNamespaceScopedResources := "Secret,MultiClusterIngress" labels := "c=foo" + annotations := "ann=foo" storageLocation := "bsl-name-1" snapshotLocations := "region=minio" selector := "a=pod" @@ -199,6 +209,7 @@ func TestCreateCommand(t *testing.T) { flags.Parse([]string{"--include-namespace-scoped-resources", includeNamespaceScopedResources}) flags.Parse([]string{"--exclude-namespace-scoped-resources", excludeNamespaceScopedResources}) flags.Parse([]string{"--labels", labels}) + flags.Parse([]string{"--annotations", annotations}) flags.Parse([]string{"--storage-location", storageLocation}) flags.Parse([]string{"--volume-snapshot-locations", snapshotLocations}) flags.Parse([]string{"--selector", selector}) @@ -248,6 +259,7 @@ func TestCreateCommand(t *testing.T) { require.Equal(t, includeNamespaceScopedResources, o.IncludeNamespaceScopedResources.String()) require.Equal(t, excludeNamespaceScopedResources, o.ExcludeNamespaceScopedResources.String()) require.True(t, test.CompareSlice(strings.Split(labels, ","), strings.Split(o.Labels.String(), ","))) + require.True(t, test.CompareSlice(strings.Split(annotations, ","), strings.Split(o.Annotations.String(), ","))) require.Equal(t, storageLocation, o.StorageLocation) require.Equal(t, snapshotLocations, strings.Split(o.SnapshotLocations[0], ",")[0]) require.Equal(t, selector, o.Selector.String()) diff --git a/pkg/cmd/cli/restore/create.go b/pkg/cmd/cli/restore/create.go index 6d4b25f0ab..17446f6983 100644 --- a/pkg/cmd/cli/restore/create.go +++ b/pkg/cmd/cli/restore/create.go @@ -84,6 +84,7 @@ type CreateOptions struct { RestoreVolumes flag.OptionalBool PreserveNodePorts flag.OptionalBool Labels flag.Map + Annotations flag.Map IncludeNamespaces flag.StringArray ExcludeNamespaces flag.StringArray ExistingResourcePolicy string @@ -107,6 +108,7 @@ type CreateOptions struct { func NewCreateOptions() *CreateOptions { return &CreateOptions{ Labels: flag.NewMap(), + Annotations: flag.NewMap(), IncludeNamespaces: flag.NewStringArray("*"), NamespaceMappings: flag.NewMap().WithEntryDelimiter(',').WithKeyValueDelimiter(':'), RestoreVolumes: flag.NewOptionalBool(nil), @@ -123,6 +125,7 @@ func (o *CreateOptions) BindFlags(flags *pflag.FlagSet) { flags.Var(&o.ExcludeNamespaces, "exclude-namespaces", "Namespaces to exclude from the restore.") flags.Var(&o.NamespaceMappings, "namespace-mappings", "Namespace mappings from name in the backup to desired restored name in the form src1:dst1,src2:dst2,...") flags.Var(&o.Labels, "labels", "Labels to apply to the restore.") + flags.Var(&o.Annotations, "annotations", "Annotations to apply to the restore.") flags.Var(&o.IncludeResources, "include-resources", "Resources to include in the restore, formatted as resource.group, such as storageclasses.storage.k8s.io (use '*' for all resources).") flags.Var(&o.ExcludeResources, "exclude-resources", "Resources to exclude from the restore, formatted as resource.group, such as storageclasses.storage.k8s.io.") flags.StringVar(&o.ExistingResourcePolicy, "existing-resource-policy", "", "Restore Policy to be used during the restore workflow, can be - none or update") @@ -309,9 +312,10 @@ func (o *CreateOptions) Run(c *cobra.Command, f client.Factory) error { restore := &api.Restore{ ObjectMeta: metav1.ObjectMeta{ - Namespace: f.Namespace(), - Name: o.RestoreName, - Labels: o.Labels.Data(), + Namespace: f.Namespace(), + Name: o.RestoreName, + Labels: o.Labels.Data(), + Annotations: o.Annotations.Data(), }, Spec: api.RestoreSpec{ BackupName: o.BackupName, diff --git a/pkg/cmd/cli/restore/create_test.go b/pkg/cmd/cli/restore/create_test.go index 2cf553d598..877de29d0c 100644 --- a/pkg/cmd/cli/restore/create_test.go +++ b/pkg/cmd/cli/restore/create_test.go @@ -65,6 +65,7 @@ func TestCreateCommand(t *testing.T) { restoreVolumes := "true" preserveNodePorts := "true" labels := "c=foo" + annotations := "ann=foo" includeNamespaces := "app1,app2" excludeNamespaces := "pod1,pod2,pod3" existingResourcePolicy := "none" @@ -88,6 +89,7 @@ func TestCreateCommand(t *testing.T) { flags.Parse([]string{"--restore-volumes", restoreVolumes}) flags.Parse([]string{"--preserve-nodeports", preserveNodePorts}) flags.Parse([]string{"--labels", labels}) + flags.Parse([]string{"--annotations", annotations}) flags.Parse([]string{"--existing-resource-policy", existingResourcePolicy}) flags.Parse([]string{"--include-namespaces", includeNamespaces}) flags.Parse([]string{"--exclude-namespaces", excludeNamespaces}) @@ -124,6 +126,7 @@ func TestCreateCommand(t *testing.T) { require.Equal(t, restoreVolumes, o.RestoreVolumes.String()) require.Equal(t, preserveNodePorts, o.PreserveNodePorts.String()) require.Equal(t, labels, o.Labels.String()) + require.Equal(t, annotations, o.Annotations.String()) require.Equal(t, includeNamespaces, o.IncludeNamespaces.String()) require.Equal(t, excludeNamespaces, o.ExcludeNamespaces.String()) require.Equal(t, existingResourcePolicy, o.ExistingResourcePolicy)