Skip to content

Commit 3bf4b0c

Browse files
stuggiclaude
andcommitted
Clarify backup vs restore: full backup, selective restore with labels
Update design to reflect the actual approach: - Backup: Full namespace backup (everything, optionally exclude PVCs) - Restore: Selective restore using webhook-added labels - Annotations: All prefixed with openstack.org/backup- Key changes: - openstack.org/backup → openstack.org/backup-restore - openstack.org/restore-order → openstack.org/backup-restore-order - Full namespace backup (no label selector) - Selective restore (uses labels added by webhooks) Rationale: - Backup everything to ensure complete snapshot - Use webhooks to label resources needing restore - CRD annotations declare restore behavior (not backup) - OADP restore filters by labels for selective recovery Example: Backup: Everything in namespace Restore Order 1: Only resources with labels: - openstack.org/backup-restore: "true" - openstack.org/backup-restore-order: "1" This makes the distinction clear: backup is comprehensive, restore is selective based on webhook-added labels. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent ca1aab5 commit 3bf4b0c

1 file changed

Lines changed: 66 additions & 47 deletions

File tree

docs/dev/backup-restore-webhook-design.md

Lines changed: 66 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,38 +6,39 @@ This document describes a webhook-based approach to backup and restore for OpenS
66

77
## Goals
88

9-
1. **Dynamic Resource Discovery**: No hardcoded lists of resources - CRD annotations declare what needs backup
10-
2. **Single Backup Mechanism**: Use OADP for all resources (CRs, Secrets, ConfigMaps, PVCs)
11-
3. **Declarative Restore Order**: Restore order defined in CRD annotations, not in code
12-
4. **Kubernetes-Native**: Leverage OADP label selectors for filtering
13-
5. **No Controller Required (Initially)**: Can be used manually with OADP Restore CRs
14-
6. **Optional Automation**: Golang controller for full automation (future enhancement)
9+
1. **Full Namespace Backup**: Backup everything in the namespace to ensure complete snapshot
10+
2. **Selective Restore**: Use webhook-added labels to restore only necessary resources
11+
3. **Dynamic Resource Discovery**: No hardcoded lists - CRD annotations declare what needs restore
12+
4. **Declarative Restore Order**: Restore order defined in CRD annotations, not in code
13+
5. **Kubernetes-Native**: Leverage OADP label selectors for filtering
14+
6. **No Controller Required (Initially)**: Can be used manually with OADP Restore CRs
15+
7. **Optional Automation**: Golang controller for full automation (future enhancement)
1516

1617
## Key Concepts
1718

1819
### CRD Annotations
1920

20-
CRD definitions declare backup/restore behavior using annotations:
21+
CRD definitions declare restore behavior using annotations (all prefixed with `openstack.org/backup-`):
2122

2223
```yaml
2324
apiVersion: apiextensions.k8s.io/v1
2425
kind: CustomResourceDefinition
2526
metadata:
2627
name: openstackcontrolplanes.core.openstack.org
2728
annotations:
28-
openstack.org/backup: "true"
29+
openstack.org/backup-restore: "true"
2930
openstack.org/backup-category: "controlplane"
30-
openstack.org/restore-order: "6"
31+
openstack.org/backup-restore-order: "6"
3132
```
3233
3334
**Annotations:**
34-
- `openstack.org/backup`: Whether instances of this CRD should be backed up (`"true"` or `"false"`)
35+
- `openstack.org/backup-restore`: Whether instances of this CRD should be restored (`"true"` or `"false"`)
3536
- `openstack.org/backup-category`: Category for selective backup/restore
3637
- `"controlplane"`: Control plane resources
3738
- `"dataplane"`: Data plane resources
3839
- `"infrastructure"`: Infrastructure resources (RabbitMQ, MariaDB configs)
3940
- `"all"`: General resources needed by all deployments
40-
- `openstack.org/restore-order`: Numeric order for restore sequence (e.g., `"1"`, `"2"`, `"3"`)
41+
- `openstack.org/backup-restore-order`: Numeric order for restore sequence (e.g., `"1"`, `"2"`, `"3"`)
4142

4243
### Mutating Webhooks
4344

@@ -64,27 +65,27 @@ In `keystone-operator/api/v1beta1/keystoneapi_webhook.go`:
6465
func (r *KeystoneAPI) ValidateCreate() error {
6566
// Existing validation logic...
6667
67-
// NEW: Add backup labels to user-provided resources
68-
if err := r.labelUserProvidedResources(); err != nil {
68+
// NEW: Add restore labels to user-provided resources
69+
if err := r.labelUserProvidedResourcesForRestore(); err != nil {
6970
return err
7071
}
7172
7273
return nil
7374
}
7475
75-
func (r *KeystoneAPI) labelUserProvidedResources() error {
76+
func (r *KeystoneAPI) labelUserProvidedResourcesForRestore() error {
7677
ctx := context.Background()
7778
7879
// Label Secret if user-provided (no ownerReferences)
7980
if r.Spec.Secret != "" {
80-
if err := labelResourceIfUserProvided(ctx, r.Namespace, "Secret", r.Spec.Secret); err != nil {
81+
if err := labelResourceForRestoreIfUserProvided(ctx, r.Namespace, "Secret", r.Spec.Secret); err != nil {
8182
return err
8283
}
8384
}
8485
8586
// Label CustomConfigSecret if user-provided
8687
if r.Spec.HttpdCustomization != nil && r.Spec.HttpdCustomization.CustomConfigSecret != "" {
87-
if err := labelResourceIfUserProvided(ctx, r.Namespace, "Secret",
88+
if err := labelResourceForRestoreIfUserProvided(ctx, r.Namespace, "Secret",
8889
r.Spec.HttpdCustomization.CustomConfigSecret); err != nil {
8990
return err
9091
}
@@ -94,7 +95,7 @@ func (r *KeystoneAPI) labelUserProvidedResources() error {
9495
for _, mount := range r.Spec.ExtraMounts {
9596
for _, vol := range mount.Propagation {
9697
if vol.ConfigMap != nil {
97-
if err := labelResourceIfUserProvided(ctx, r.Namespace, "ConfigMap",
98+
if err := labelResourceForRestoreIfUserProvided(ctx, r.Namespace, "ConfigMap",
9899
vol.ConfigMap.Name); err != nil {
99100
return err
100101
}
@@ -109,8 +110,8 @@ func (r *KeystoneAPI) labelUserProvidedResources() error {
109110
**Generic Helper Function (in lib-common):**
110111

111112
```go
112-
// labelResourceIfUserProvided adds backup label to resource if it has no ownerReferences
113-
func labelResourceIfUserProvided(ctx context.Context, namespace, kind, name string) error {
113+
// labelResourceForRestoreIfUserProvided adds restore labels to resource if it has no ownerReferences
114+
func labelResourceForRestoreIfUserProvided(ctx context.Context, namespace, kind, name string) error {
114115
// Get the resource
115116
var obj client.Object
116117
switch kind {
@@ -137,20 +138,20 @@ func labelResourceIfUserProvided(ctx context.Context, namespace, kind, name stri
137138
return nil
138139
}
139140
140-
// Add backup label (user-provided resource)
141+
// Add restore labels (user-provided resource)
141142
labels := obj.GetLabels()
142143
if labels == nil {
143144
labels = make(map[string]string)
144145
}
145146
146147
// Only add if not already labeled
147-
if labels["openstack.org/backup"] == "true" {
148+
if labels["openstack.org/backup-restore"] == "true" {
148149
return nil
149150
}
150151
151-
labels["openstack.org/backup"] = "true"
152+
labels["openstack.org/backup-restore"] = "true"
152153
labels["openstack.org/backup-category"] = "all"
153-
labels["openstack.org/restore-order"] = "1" // Secrets/ConfigMaps always order 1
154+
labels["openstack.org/backup-restore-order"] = "1" // Secrets/ConfigMaps always order 1
154155
obj.SetLabels(labels)
155156
156157
// Update the resource
@@ -168,9 +169,9 @@ func labelResourceIfUserProvided(ctx context.Context, namespace, kind, name stri
168169

169170
### OADP Integration
170171

171-
#### Single Backup
172+
#### Full Namespace Backup
172173

173-
One OADP Backup CR captures everything:
174+
One OADP Backup CR captures **everything** in the namespace (complete snapshot):
174175

175176
```yaml
176177
apiVersion: velero.io/v1
@@ -181,18 +182,34 @@ metadata:
181182
spec:
182183
includedNamespaces:
183184
- openstack
184-
labelSelector:
185-
matchLabels:
186-
openstack.org/backup: "true"
187-
snapshotVolumes: true
185+
# NO labelSelector - backup everything
186+
snapshotVolumes: true # Backup PVCs with CSI snapshots
188187
defaultVolumesToFsBackup: false
189188
storageLocation: velero-1
190189
ttl: 720h
191190
```
192191

193-
#### Multiple Restores (By Order)
192+
**Optional: Exclude large PVC data** (if storage is limited):
194193

195-
Multiple OADP Restore CRs, one per restore order:
194+
```yaml
195+
apiVersion: velero.io/v1
196+
kind: Backup
197+
metadata:
198+
name: openstack-backup-20260303-120000
199+
namespace: openshift-adp
200+
spec:
201+
includedNamespaces:
202+
- openstack
203+
# Backup all CRs, Secrets, ConfigMaps, but exclude PVC data
204+
snapshotVolumes: false # Skip PVC snapshots to reduce backup size
205+
defaultVolumesToFsBackup: false
206+
storageLocation: velero-1
207+
ttl: 720h
208+
```
209+
210+
#### Selective Restore (By Order)
211+
212+
Multiple OADP Restore CRs, one per restore order, using labels added by webhooks:
196213

197214
```yaml
198215
# Restore Order 1: Secrets, ConfigMaps, NADs
@@ -205,9 +222,9 @@ spec:
205222
backupName: openstack-backup-20260303-120000
206223
labelSelector:
207224
matchLabels:
208-
openstack.org/backup: "true"
209-
openstack.org/restore-order: "1"
210-
restorePVs: false
225+
openstack.org/backup-restore: "true"
226+
openstack.org/backup-restore-order: "1"
227+
restorePVs: false # Don't restore PVCs in this order
211228
---
212229
# Restore Order 2: TLS Issuers
213230
apiVersion: velero.io/v1
@@ -219,13 +236,15 @@ spec:
219236
backupName: openstack-backup-20260303-120000
220237
labelSelector:
221238
matchLabels:
222-
openstack.org/backup: "true"
223-
openstack.org/restore-order: "2"
239+
openstack.org/backup-restore: "true"
240+
openstack.org/backup-restore-order: "2"
224241
restorePVs: false
225242
---
226243
# And so on for each restore order...
227244
```
228245

246+
**Key Point**: Webhooks add `openstack.org/backup-restore: "true"` labels to resources that need restore. OADP restore uses these labels for selective restore, even though the backup contains everything.
247+
229248
## Restore Order
230249

231250
The restore sequence is critical for maintaining dependencies between resources.
@@ -253,8 +272,8 @@ The restore sequence is critical for maintaining dependencies between resources.
253272

254273
### Core Operator CRDs
255274

256-
| CRD | Backup | Category | Order | Notes |
257-
|-----|--------|----------|-------|-------|
275+
| CRD | Restore | Category | Order | Notes |
276+
|-----|---------|----------|-------|-------|
258277
| OpenStackControlPlane | true | controlplane | 6 | Main control plane CR |
259278
| OpenStackVersion | true | controlplane | 5 | Version tracking |
260279

@@ -312,36 +331,36 @@ Categories enable selective backup/restore scenarios:
312331
```yaml
313332
labelSelector:
314333
matchLabels:
315-
openstack.org/backup: "true"
334+
openstack.org/backup-restore: "true"
316335
openstack.org/backup-category: "controlplane"
317336
```
318-
Use case: Control plane disaster recovery
337+
Use case: Control plane disaster recovery (restore only control plane resources)
319338

320339
### Data Plane Only
321340
```yaml
322341
labelSelector:
323342
matchLabels:
324-
openstack.org/backup: "true"
343+
openstack.org/backup-restore: "true"
325344
openstack.org/backup-category: "dataplane"
326345
```
327-
Use case: Data plane node replacement
346+
Use case: Data plane node replacement (restore only data plane resources)
328347

329348
### Infrastructure Only
330349
```yaml
331350
labelSelector:
332351
matchLabels:
333-
openstack.org/backup: "true"
352+
openstack.org/backup-restore: "true"
334353
openstack.org/backup-category: "infrastructure"
335354
```
336-
Use case: Network/messaging configuration backup
355+
Use case: Network/messaging configuration recovery
337356

338-
### All Resources
357+
### All Labeled Resources
339358
```yaml
340359
labelSelector:
341360
matchLabels:
342-
openstack.org/backup: "true"
361+
openstack.org/backup-restore: "true"
343362
```
344-
Use case: Full cluster backup (default)
363+
Use case: Full restore of all labeled resources (default)
345364

346365
## Implementation Phases
347366

0 commit comments

Comments
 (0)