@@ -21,6 +21,7 @@ import (
2121 "context"
2222 "fmt"
2323 "os"
24+ "slices"
2425 "time"
2526
2627 snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v7/apis/volumesnapshot/v1"
@@ -31,6 +32,7 @@ import (
3132 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3233 "k8s.io/apimachinery/pkg/labels"
3334 kerrors "k8s.io/apimachinery/pkg/util/errors"
35+ "k8s.io/apimachinery/pkg/util/sets"
3436 "k8s.io/apimachinery/pkg/util/wait"
3537 "k8s.io/utils/clock"
3638 ctrl "sigs.k8s.io/controller-runtime"
@@ -63,6 +65,20 @@ const (
6365 backupResyncPeriod = time .Minute
6466)
6567
68+ var nonBackupNamespaceScopedResources = []string {
69+ // CSI VolumeSnapshot and VolumeSnapshotContent are intermediate resources.
70+ // Velero only handle the VS and VSC created during backup,
71+ // not during resource collecting.
72+ "volumesnapshots.snapshot.storage.k8s.io" ,
73+ }
74+
75+ var nonBackupClusterScopedResources = []string {
76+ // CSI VolumeSnapshot and VolumeSnapshotContent are intermediate resources.
77+ // Velero only handle the VS and VSC created during backup,
78+ // not during resource collecting.
79+ "volumesnapshotcontents.snapshot.storage.k8s.io" ,
80+ }
81+
6682type backupReconciler struct {
6783 ctx context.Context
6884 logger logrus.FieldLogger
@@ -481,19 +497,51 @@ func (b *backupReconciler) prepareBackupRequest(backup *velerov1api.Backup, logg
481497 request .Status .ValidationErrors = append (request .Status .ValidationErrors , validatedError )
482498 }
483499
484- // validate the included/excluded resources
485- for _ , err := range collections .ValidateIncludesExcludes (request .Spec .IncludedResources , request .Spec .ExcludedResources ) {
486- request .Status .ValidationErrors = append (request .Status .ValidationErrors , fmt .Sprintf ("Invalid included/excluded resource lists: %v" , err ))
487- }
488-
489- // validate the cluster-scoped included/excluded resources
490- for _ , err := range collections .ValidateScopedIncludesExcludes (request .Spec .IncludedClusterScopedResources , request .Spec .ExcludedClusterScopedResources ) {
491- request .Status .ValidationErrors = append (request .Status .ValidationErrors , fmt .Sprintf ("Invalid cluster-scoped included/excluded resource lists: %s" , err ))
492- }
500+ if collections .UseOldResourceFilters (request .Spec ) {
501+ // validate the included/excluded resources
502+ ieErr := collections .ValidateIncludesExcludes (request .Spec .IncludedResources , request .Spec .ExcludedResources )
503+ if len (ieErr ) > 0 {
504+ for _ , err := range ieErr {
505+ request .Status .ValidationErrors = append (request .Status .ValidationErrors , fmt .Sprintf ("Invalid included/excluded resource lists: %v" , err ))
506+ }
507+ } else {
508+ request .Spec .IncludedResources , request .Spec .ExcludedResources =
509+ modifyResourceIncludeExclude (
510+ request .Spec .IncludedResources ,
511+ request .Spec .ExcludedResources ,
512+ append (nonBackupNamespaceScopedResources , nonBackupClusterScopedResources ... ),
513+ )
514+ }
515+ } else {
516+ // validate the cluster-scoped included/excluded resources
517+ clusterErr := collections .ValidateScopedIncludesExcludes (request .Spec .IncludedClusterScopedResources , request .Spec .ExcludedClusterScopedResources )
518+ if len (clusterErr ) > 0 {
519+ for _ , err := range clusterErr {
520+ request .Status .ValidationErrors = append (request .Status .ValidationErrors , fmt .Sprintf ("Invalid cluster-scoped included/excluded resource lists: %s" , err ))
521+ }
522+ } else {
523+ request .Spec .IncludedClusterScopedResources , request .Spec .ExcludedClusterScopedResources =
524+ modifyResourceIncludeExclude (
525+ request .Spec .IncludedClusterScopedResources ,
526+ request .Spec .ExcludedClusterScopedResources ,
527+ nonBackupClusterScopedResources ,
528+ )
529+ }
493530
494- // validate the namespace-scoped included/excluded resources
495- for _ , err := range collections .ValidateScopedIncludesExcludes (request .Spec .IncludedNamespaceScopedResources , request .Spec .ExcludedNamespaceScopedResources ) {
496- request .Status .ValidationErrors = append (request .Status .ValidationErrors , fmt .Sprintf ("Invalid namespace-scoped included/excluded resource lists: %s" , err ))
531+ // validate the namespace-scoped included/excluded resources
532+ namespaceErr := collections .ValidateScopedIncludesExcludes (request .Spec .IncludedNamespaceScopedResources , request .Spec .ExcludedNamespaceScopedResources )
533+ if len (namespaceErr ) > 0 {
534+ for _ , err := range namespaceErr {
535+ request .Status .ValidationErrors = append (request .Status .ValidationErrors , fmt .Sprintf ("Invalid namespace-scoped included/excluded resource lists: %s" , err ))
536+ }
537+ } else {
538+ request .Spec .IncludedNamespaceScopedResources , request .Spec .ExcludedNamespaceScopedResources =
539+ modifyResourceIncludeExclude (
540+ request .Spec .IncludedNamespaceScopedResources ,
541+ request .Spec .ExcludedNamespaceScopedResources ,
542+ nonBackupNamespaceScopedResources ,
543+ )
544+ }
497545 }
498546
499547 // validate the included/excluded namespaces
@@ -932,3 +980,25 @@ func oldAndNewFilterParametersUsedTogether(backupSpec velerov1api.BackupSpec) bo
932980
933981 return haveOldResourceFilterParameters && haveNewResourceFilterParameters
934982}
983+
984+ func modifyResourceIncludeExclude (include , exclude , addedExclude []string ) (modifiedInclude , modifiedExclude []string ) {
985+ modifiedInclude = include
986+ modifiedExclude = exclude
987+
988+ excludeStrSet := sets .NewString (exclude ... )
989+ for _ , ex := range addedExclude {
990+ if ! excludeStrSet .Has (ex ) {
991+ modifiedExclude = append (modifiedExclude , ex )
992+ }
993+ }
994+
995+ for _ , exElem := range modifiedExclude {
996+ for inIndex , inElem := range modifiedInclude {
997+ if inElem == exElem {
998+ modifiedInclude = slices .Delete (modifiedInclude , inIndex , inIndex + 1 )
999+ }
1000+ }
1001+ }
1002+
1003+ return modifiedInclude , modifiedExclude
1004+ }
0 commit comments