mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-05-25 16:40:23 +00:00
Merge pull request #9821 from adam-jian-zhang/enhance-backup-filters-interface
extend backup resource policy
This commit is contained in:
1
changelogs/unreleased/9821-adam-jian-zhang
Normal file
1
changelogs/unreleased/9821-adam-jian-zhang
Normal file
@@ -0,0 +1 @@
|
||||
Fix issue #9811, add interface to support ClusterScopedFilterPolicy and NamespacedFilterPolicy
|
||||
@@ -54,6 +54,31 @@ type Action struct {
|
||||
Parameters map[string]any `yaml:"parameters,omitempty"`
|
||||
}
|
||||
|
||||
// ResourceFilter defines a filter for specific resource kinds.
|
||||
type ResourceFilter struct {
|
||||
Kinds []string `yaml:"kinds"`
|
||||
LabelSelector map[string]string `yaml:"labelSelector,omitempty"`
|
||||
OrLabelSelectors []map[string]string `yaml:"orLabelSelectors,omitempty"`
|
||||
Names []string `yaml:"names,omitempty"`
|
||||
ExcludedNames []string `yaml:"excludedNames,omitempty"`
|
||||
}
|
||||
|
||||
// IsCatchAll returns true if the filter is a catch-all entry (empty kinds or ["*"])
|
||||
func (rf *ResourceFilter) IsCatchAll() bool {
|
||||
return len(rf.Kinds) == 0 || (len(rf.Kinds) == 1 && rf.Kinds[0] == "*")
|
||||
}
|
||||
|
||||
// ClusterScopedFilterPolicy defines backup filters scoped globally to cluster-scoped resources.
|
||||
type ClusterScopedFilterPolicy struct {
|
||||
ResourceFilters []ResourceFilter `yaml:"resourceFilters"`
|
||||
}
|
||||
|
||||
// NamespacedFilterPolicy defines backup filters scoped to specific namespaces.
|
||||
type NamespacedFilterPolicy struct {
|
||||
Namespaces []string `yaml:"namespaces"`
|
||||
ResourceFilters []ResourceFilter `yaml:"resourceFilters"`
|
||||
}
|
||||
|
||||
// IncludeExcludePolicy defined policy to include or exclude resources based on the names
|
||||
type IncludeExcludePolicy struct {
|
||||
// The following fields have the same semantics as those from the spec of backup.
|
||||
@@ -95,17 +120,21 @@ type VolumePolicy struct {
|
||||
|
||||
// ResourcePolicies currently defined slice of volume policies to handle backup
|
||||
type ResourcePolicies struct {
|
||||
Version string `yaml:"version"`
|
||||
VolumePolicies []VolumePolicy `yaml:"volumePolicies"`
|
||||
IncludeExcludePolicy *IncludeExcludePolicy `yaml:"includeExcludePolicy"`
|
||||
Version string `yaml:"version"`
|
||||
VolumePolicies []VolumePolicy `yaml:"volumePolicies"`
|
||||
IncludeExcludePolicy *IncludeExcludePolicy `yaml:"includeExcludePolicy"`
|
||||
ClusterScopedFilterPolicy *ClusterScopedFilterPolicy `yaml:"clusterScopedFilterPolicy,omitempty"`
|
||||
NamespacedFilterPolicies []NamespacedFilterPolicy `yaml:"namespacedFilterPolicies,omitempty"`
|
||||
// we may support other resource policies in the future, and they could be added separately
|
||||
// OtherResourcePolicies []OtherResourcePolicy
|
||||
}
|
||||
|
||||
type Policies struct {
|
||||
version string
|
||||
volumePolicies []volPolicy
|
||||
includeExcludePolicy *IncludeExcludePolicy
|
||||
version string
|
||||
volumePolicies []volPolicy
|
||||
includeExcludePolicy *IncludeExcludePolicy
|
||||
clusterScopedFilterPolicy *ClusterScopedFilterPolicy
|
||||
namespacedFilterPolicies []NamespacedFilterPolicy
|
||||
// OtherPolicies
|
||||
}
|
||||
|
||||
@@ -158,6 +187,8 @@ func (p *Policies) BuildPolicy(resPolicies *ResourcePolicies) error {
|
||||
|
||||
p.version = resPolicies.Version
|
||||
p.includeExcludePolicy = resPolicies.IncludeExcludePolicy
|
||||
p.clusterScopedFilterPolicy = resPolicies.ClusterScopedFilterPolicy
|
||||
p.namespacedFilterPolicies = resPolicies.NamespacedFilterPolicies
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -235,6 +266,14 @@ func (p *Policies) GetIncludeExcludePolicy() *IncludeExcludePolicy {
|
||||
return p.includeExcludePolicy
|
||||
}
|
||||
|
||||
func (p *Policies) GetClusterScopedFilterPolicy() *ClusterScopedFilterPolicy {
|
||||
return p.clusterScopedFilterPolicy
|
||||
}
|
||||
|
||||
func (p *Policies) GetNamespacedFilterPolicies() []NamespacedFilterPolicy {
|
||||
return p.namespacedFilterPolicies
|
||||
}
|
||||
|
||||
func GetResourcePoliciesFromBackup(
|
||||
backup velerov1api.Backup,
|
||||
client crclient.Client,
|
||||
|
||||
@@ -19,6 +19,9 @@ package backup
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/gobwas/glob"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
"github.com/vmware-tanzu/velero/internal/hook"
|
||||
"github.com/vmware-tanzu/velero/internal/resourcepolicies"
|
||||
"github.com/vmware-tanzu/velero/internal/volume"
|
||||
@@ -34,6 +37,21 @@ type itemKey struct {
|
||||
name string
|
||||
}
|
||||
|
||||
// ResolvedResourceFilter holds the materialized filter state for one kind-group
|
||||
// within a namespace.
|
||||
type ResolvedResourceFilter struct {
|
||||
LabelSelector labels.Selector
|
||||
OrLabelSelectors []labels.Selector
|
||||
NameIE *collections.IncludesExcludes
|
||||
}
|
||||
|
||||
// ResolvedNamespaceFilter holds the materialized filter state for a namespace.
|
||||
// ResourceFilterMap is keyed by the resolved group-resource string.
|
||||
type ResolvedNamespaceFilter struct {
|
||||
ResourceFilterMap map[string]*ResolvedResourceFilter
|
||||
CatchAllFilter *ResolvedResourceFilter
|
||||
}
|
||||
|
||||
type SynchronizedVSList struct {
|
||||
sync.Mutex
|
||||
VolumeSnapshotList []*volume.Snapshot
|
||||
@@ -70,6 +88,27 @@ type Request struct {
|
||||
SkippedPVTracker *skipPVTracker
|
||||
VolumesInformation volume.BackupVolumesInformation
|
||||
WorkerPool *ItemBlockWorkerPool
|
||||
|
||||
// ClusterScopedFilterMap holds resolved global filters for cluster-scoped resources.
|
||||
// Key is the resolved group-resource string.
|
||||
ClusterScopedFilterMap map[string]*ResolvedResourceFilter
|
||||
|
||||
// NamespacedFilterMap holds resolved per-namespace filters.
|
||||
// Key is either an exact namespace name or a glob pattern.
|
||||
NamespacedFilterMap map[string]*ResolvedNamespaceFilter
|
||||
|
||||
// NamespacedFilterPatterns preserves the order of patterns for first-match semantics
|
||||
// and caches pre-compiled globs to avoid repeated compilation in the hot path.
|
||||
NamespacedFilterPatterns []NamespacedFilterPattern
|
||||
}
|
||||
|
||||
// NamespacedFilterPattern pairs a namespace pattern string with its pre-compiled
|
||||
// glob so that GetNamespaceFilter does not recompile on every call.
|
||||
// Compiled is nil for exact-match (non-glob) patterns, which are looked up
|
||||
// directly in NamespacedFilterMap.
|
||||
type NamespacedFilterPattern struct {
|
||||
Pattern string
|
||||
Compiled glob.Glob
|
||||
}
|
||||
|
||||
// BackupVolumesInformation contains the information needs by generating
|
||||
@@ -107,3 +146,25 @@ func (r *Request) FillVolumesInformation() {
|
||||
func (r *Request) StopWorkerPool() {
|
||||
r.WorkerPool.Stop()
|
||||
}
|
||||
|
||||
// GetNamespaceFilter returns the resolved filter for a namespace, or nil
|
||||
// if the namespace should use global filters. Uses first-match semantics
|
||||
// when multiple patterns could match the same namespace.
|
||||
func (r *Request) GetNamespaceFilter(namespace string) *ResolvedNamespaceFilter {
|
||||
if r.NamespacedFilterMap == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// First check for exact match
|
||||
if f, ok := r.NamespacedFilterMap[namespace]; ok {
|
||||
return f
|
||||
}
|
||||
|
||||
// Walk patterns in definition order using pre-compiled globs (no allocation per call)
|
||||
for _, p := range r.NamespacedFilterPatterns {
|
||||
if p.Compiled != nil && p.Compiled.Match(namespace) {
|
||||
return r.NamespacedFilterMap[p.Pattern]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user