Skip to content

Commit de64ea6

Browse files
kaovilaiclaude
andcommitted
Add design document for namespace selection by label selector
This design proposal addresses issue #7492 by modifying Velero's backup behavior to include all resources from namespaces selected by labelSelector or orLabelSelectors, equivalent to explicitly listing them in includedNamespaces. Key design decisions: - Modify existing LabelSelector behavior (breaking change) - Precedence: (includedNamespaces ∪ labelSelector ∪ orLabelSelectors) - excludedNamespaces - Support full Kubernetes label selector syntax - Enhanced logging for namespace selection transparency 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 2dbfbc2 commit de64ea6

File tree

1 file changed

+330
-0
lines changed

1 file changed

+330
-0
lines changed
Lines changed: 330 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,330 @@
1+
# Design proposal: Namespace Selection by Label Selector for Velero Backups
2+
3+
## Abstract
4+
5+
This proposal modifies Velero's backup behavior to treat namespaces selected by `LabelSelector` or `OrLabelSelectors` as if they were explicitly listed in `includedNamespaces`, causing all resources within those namespaces to be included in the backup.
6+
Currently, when a namespace matches a label selector, only the namespace object itself and individually labeled resources are backed up, which is not the expected behavior for most users who want complete namespace backups.
7+
8+
## Background
9+
10+
Users frequently need to backup entire namespaces dynamically based on labels rather than maintaining static lists in `includedNamespaces`.
11+
The current `LabelSelector` behavior only includes resources that individually match the selector, making it difficult to achieve complete namespace backups through labeling.
12+
This creates operational overhead where users must either manually maintain namespace lists or label every resource within target namespaces.
13+
14+
Issue #7492 requests this functionality with strong community support (+5 reactions) and multiple real-world use cases from users managing multi-cluster environments where namespace lists vary dynamically.
15+
16+
## Goals
17+
18+
- Enable complete namespace backup through namespace label selection
19+
- Provide clear precedence rules when combining inclusion/exclusion methods
20+
- Support full Kubernetes label selector syntax including complex operators
21+
22+
## Non Goals
23+
24+
- Changing behavior of resource-level label selectors within namespaces (resources still respect individual selectors within selected namespaces)
25+
- Adding new API fields (we will modify existing `LabelSelector` behavior)
26+
- Supporting per-resource granular control within label-selected namespaces
27+
28+
## High-Level Design
29+
30+
When a namespace matches `spec.labelSelector` or any `spec.orLabelSelectors`, Velero will treat that namespace as if it were explicitly listed in `spec.includedNamespaces`.
31+
All resources within matching namespaces will be included in the backup, regardless of their individual labels.
32+
The final namespace selection follows the precedence: `(includedNamespaces ∪ labelSelector_matches ∪ orLabelSelector_matches) - excludedNamespaces`.
33+
34+
## Detailed Design
35+
36+
### Namespace Selection Logic
37+
38+
The namespace selection algorithm follows this formula:
39+
40+
```text
41+
Final Namespaces = (ExplicitIncludes ∪ LabelSelectorMatches ∪ OrLabelSelectorMatches) - ExplicitExcludes
42+
```
43+
44+
Where:
45+
46+
- `ExplicitIncludes`: Namespaces in `spec.includedNamespaces`
47+
- `LabelSelectorMatches`: Namespaces matching `spec.labelSelector`
48+
- `OrLabelSelectorMatches`: Namespaces matching any selector in `spec.orLabelSelectors[]`
49+
- `ExplicitExcludes`: Namespaces in `spec.excludedNamespaces` (highest precedence)
50+
51+
### Implementation Changes
52+
53+
#### Core Logic Modification
54+
55+
The primary change occurs in `pkg/backup/item_collector.go` in the `nsTracker.init()` method (lines 102-166).
56+
Currently, this method tracks namespaces for filtering but doesn't change the fundamental inclusion behavior.
57+
58+
**Current behavior:**
59+
```go
60+
// Namespace matches selector -> track for resource filtering only
61+
if nt.singleLabelSelector != nil && nt.singleLabelSelector.Matches(labels.Set(namespace.GetLabels())) {
62+
nt.track(namespace.GetName())
63+
}
64+
```
65+
66+
**New behavior:**
67+
```go
68+
// Namespace matches selector -> track AND include all resources in namespace
69+
if nt.singleLabelSelector != nil && nt.singleLabelSelector.Matches(labels.Set(namespace.GetLabels())) {
70+
nt.track(namespace.GetName())
71+
// This namespace now behaves like it's in includedNamespaces
72+
}
73+
```
74+
75+
#### Label Selector Support
76+
77+
Full Kubernetes label selector support including:
78+
79+
**Equality-based requirements:**
80+
- `key=value` (equality)
81+
- `key!=value` (inequality)
82+
83+
**Set-based requirements:**
84+
- `key in (value1,value2)` (set inclusion)
85+
- `key notin (value1,value2)` (set exclusion)
86+
- `key` (key exists)
87+
- `!key` (key does not exist)
88+
89+
**MatchExpressions support:**
90+
```yaml
91+
labelSelector:
92+
matchLabels:
93+
environment: production
94+
matchExpressions:
95+
- key: tier
96+
operator: In
97+
values: ["web", "api"]
98+
- key: deprecated
99+
operator: DoesNotExist
100+
```
101+
102+
### API Schema (No Changes Required)
103+
104+
The existing `BackupSpec` already supports the required fields:
105+
```go
106+
type BackupSpec struct {
107+
// ... existing fields ...
108+
LabelSelector *metav1.LabelSelector `json:"labelSelector,omitempty"`
109+
OrLabelSelectors []*metav1.LabelSelector `json:"orLabelSelectors,omitempty"`
110+
}
111+
```
112+
113+
### Example Usage Scenarios
114+
115+
#### Scenario 1: Basic Environment-Based Backup
116+
```yaml
117+
apiVersion: velero.io/v1
118+
kind: Backup
119+
metadata:
120+
name: production-backup
121+
spec:
122+
labelSelector:
123+
matchLabels:
124+
environment: production
125+
```
126+
Result: All namespaces with `environment=production` are completely backed up.
127+
128+
#### Scenario 2: Complex Selection with Exclusions
129+
```yaml
130+
spec:
131+
includedNamespaces: ["critical-ns"]
132+
labelSelector:
133+
matchExpressions:
134+
- key: backup-tier
135+
operator: In
136+
values: ["daily", "weekly"]
137+
- key: deprecated
138+
operator: DoesNotExist
139+
excludedNamespaces: ["temp-ns"]
140+
```
141+
Result: `critical-ns` + (namespaces with `backup-tier` in daily/weekly AND no `deprecated` label) - `temp-ns`.
142+
143+
#### Scenario 3: OrLabelSelectors Usage
144+
```yaml
145+
spec:
146+
orLabelSelectors:
147+
- matchLabels:
148+
backup: "true"
149+
- matchLabels:
150+
critical: "true"
151+
environment: "production"
152+
```
153+
Result: Namespaces with `backup=true` OR (`critical=true` AND `environment=production`).
154+
155+
### Logging and Observability
156+
157+
Enhanced logging will provide clear visibility into namespace selection:
158+
159+
```
160+
INFO Backup namespace selection:
161+
Explicitly included: [ns1, ns2]
162+
Selected by labelSelector 'environment=production': [ns3, ns4]
163+
Selected by orLabelSelectors: [ns5, ns6]
164+
Explicitly excluded: [ns2, temp-ns]
165+
Final included namespaces: [ns1, ns3, ns4, ns5, ns6]
166+
```
167+
168+
Backup status will include selected namespace information:
169+
```yaml
170+
status:
171+
phase: Completed
172+
namespaces:
173+
included: ["ns1", "ns3", "ns4", "ns5", "ns6"]
174+
explicitlyIncluded: ["ns1"]
175+
selectedByLabels: ["ns3", "ns4", "ns5", "ns6"]
176+
excluded: ["ns2", "temp-ns"]
177+
```
178+
179+
### Validation and Warnings
180+
181+
Warning messages for potentially confusing configurations:
182+
- "Namespace 'ns2' is both explicitly included and excluded - exclusion takes precedence"
183+
- "Using both labelSelector and orLabelSelectors - both will be evaluated"
184+
- "Complex label selectors may select unexpected namespaces - verify selection before running"
185+
186+
### Breaking Change Considerations
187+
188+
This is a **breaking change** from current behavior:
189+
- Existing backups using `labelSelector` will include more resources
190+
- Backup size and duration may increase
191+
- Current behavior has limited practical value, reducing migration impact
192+
193+
Migration considerations:
194+
- Document change prominently in release notes
195+
- Provide before/after examples
196+
- Consider deprecation warning in prior version
197+
198+
## Alternatives Considered
199+
200+
### Alternative 1: New NamespaceSelector Field
201+
```go
202+
type BackupSpec struct {
203+
NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty"`
204+
}
205+
```
206+
**Pros:** No breaking changes, clear separation of concerns
207+
**Cons:** Adds API complexity, community feedback against new fields
208+
209+
### Alternative 2: Boolean Flag to Change Behavior
210+
```go
211+
type BackupSpec struct {
212+
IncludeResourcesInLabeledNamespaces *bool `json:"includeResourcesInLabeledNamespaces,omitempty"`
213+
}
214+
```
215+
**Pros:** Backward compatible, explicit opt-in
216+
**Cons:** Complex configuration, confusing API surface
217+
218+
### Alternative 3: Separate Namespace and Resource Selectors
219+
Keep existing `labelSelector` for resources, add `namespaceSelector` for namespaces.
220+
**Cons:** Most complex option, unclear interaction patterns
221+
222+
**Decision:** Modify existing behavior (chosen approach) based on community feedback and limited utility of current behavior.
223+
224+
## Security Considerations
225+
226+
### RBAC Implications
227+
Users with permission to modify backup specs can now potentially backup additional namespaces through label manipulation.
228+
Existing RBAC controls on backup resources remain the primary security boundary.
229+
230+
### Label-based Access Control
231+
Organizations using label-based policies should ensure backup service accounts have appropriate namespace and resource access.
232+
No additional privileges are required beyond current backup operations.
233+
234+
### Sensitive Data Exposure
235+
The expanded scope of backups may include additional sensitive data.
236+
Users should audit namespace labels and exclusion rules to prevent unintended data exposure.
237+
238+
## Compatibility
239+
240+
### Backward Compatibility
241+
**Breaking Change:** Existing backups using `labelSelector` will behave differently.
242+
Impact assessment:
243+
- Current `labelSelector` usage is limited due to reduced utility
244+
- Most users already avoid this pattern in favor of explicit namespace listing
245+
- Change aligns behavior with user expectations
246+
247+
### API Compatibility
248+
No API schema changes required.
249+
Existing backup configurations remain syntactically valid but may produce different results.
250+
251+
### Velero Version Compatibility
252+
- Backups created with new behavior remain compatible with older Velero versions for restore
253+
- Backup metadata format unchanged
254+
- No changes to backup storage format
255+
256+
### Kubernetes Version Compatibility
257+
No changes to Kubernetes version requirements.
258+
Label selector functionality leverages existing Kubernetes APIs.
259+
260+
## Implementation
261+
262+
### Development Phases
263+
264+
**Phase 1: Core Logic Implementation**
265+
- Modify `nsTracker` behavior in `item_collector.go`
266+
- Update namespace selection algorithm
267+
- Add comprehensive unit tests
268+
- Timeline: 2 weeks
269+
270+
**Phase 2: Full Kubernetes Label Selector Support**
271+
- Implement support for all operator types (`In`, `NotIn`, `Exists`, `DoesNotExist`)
272+
- Add validation for complex selectors
273+
- Timeline: 1 week
274+
275+
**Phase 3: Enhanced Logging and Observability**
276+
- Add detailed namespace selection logging
277+
- Update backup status reporting
278+
- Add validation warnings
279+
- Timeline: 1 week
280+
281+
**Phase 4: Documentation and Testing**
282+
- Update user documentation with examples
283+
- Add integration and E2E tests
284+
- Create migration guide
285+
- Timeline: 2 weeks
286+
287+
### Testing Strategy
288+
289+
**Unit Tests:**
290+
- Namespace selection algorithm with all operator combinations
291+
- Precedence rules with various include/exclude patterns
292+
- Edge cases (empty selectors, wildcard usage, non-existent namespaces)
293+
294+
**Integration Tests:**
295+
- Backup creation with namespace selectors
296+
- Verification of complete namespace resource inclusion
297+
- Backup status and logging validation
298+
299+
**E2E Tests:**
300+
- Multi-namespace backup/restore scenarios
301+
- Cross-cluster restore operations
302+
- Performance testing with large namespace counts
303+
304+
### Resources
305+
306+
- **Primary Developer:** Tiger Kaovilai (@kaovilai)
307+
- **Reviewers:** Daniel Jiang, blackpiglet, shubham-pampattiwar
308+
- **Target Release:** Velero v1.18
309+
- **Estimated Effort:** 6 weeks total development + testing
310+
311+
## Open Issues
312+
313+
### Issue 1: Performance Impact with Large Cluster
314+
Large clusters with many namespaces may experience performance degradation during label selector evaluation.
315+
**Potential Solution:** Implement caching for namespace label queries, optimize selector evaluation.
316+
317+
### Issue 2: Label Change Detection
318+
Currently, Velero doesn't re-evaluate namespace selection if labels change between backup creation and execution.
319+
**Potential Solution:** Document current behavior, consider future enhancement for dynamic re-evaluation.
320+
321+
### Issue 3: Complex Selector User Education
322+
Users may create overly complex selectors that are difficult to understand or maintain.
323+
**Potential Solution:** Provide comprehensive documentation, examples, and possibly a selector validation tool.
324+
325+
### Issue 4: Interaction with Other Velero Features
326+
Need to verify behavior interaction with:
327+
- Resource policies
328+
- Item actions and plugins
329+
- Hooks and pre/post backup operations
330+
**Status:** Requires additional analysis and testing during implementation.

0 commit comments

Comments
 (0)