Skip to content

Commit 0c3ac67

Browse files
committed
start using a namespaced label on restored objects, deprecate old label
Signed-off-by: Steve Kriss <steve@heptio.com>
1 parent 27003af commit 0c3ac67

File tree

4 files changed

+37
-65
lines changed

4 files changed

+37
-65
lines changed

docs/about.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Scheduled backups are saved with the name `<SCHEDULE NAME>-<TIMESTAMP>`, where `
2929

3030
The **restore** operation allows you to restore all of the objects and persistent volumes from a previously created backup. You can also restore only a filtered subset of objects and persistent volumes. Ark supports multiple namespace remapping--for example, in a single restore, objects in namespace "abc" can be recreated under namespace "def", and the objects in namespace "123" under "456".
3131

32-
The default name of a restore is `<BACKUP NAME>-<TIMESTAMP>`, where `<TIMESTAMP>` is formatted as *YYYYMMDDhhmmss*. You can also specify a custom name. A restored object also includes a label with key `ark-restore` and value `<RESTORE NAME>`.
32+
The default name of a restore is `<BACKUP NAME>-<TIMESTAMP>`, where `<TIMESTAMP>` is formatted as *YYYYMMDDhhmmss*. You can also specify a custom name. A restored object also includes a label with key `ark.heptio.com/restore-name` and value `<RESTORE NAME>`.
3333

3434
You can also run the Ark server in restore-only mode, which disables backup, schedule, and garbage collection functionality during disaster recovery.
3535

pkg/apis/ark/v1/constants.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ const (
2828
// RestoreLabelKey is the label key that's applied to all resources that
2929
// are created during a restore. This is applied for ease of identification
3030
// of restored resources. The value will be the restore's name.
31+
//
32+
// This label is DEPRECATED as of v0.10 and will be removed entirely as of
33+
// v1.0 and replaced with RestoreNameLabel ("ark.heptio.com/restore-name").
3134
RestoreLabelKey = "ark-restore"
3235

3336
// ClusterScopedDir is the name of the directory containing cluster-scoped

pkg/restore/restore.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -760,8 +760,9 @@ func (ctx *context) restoreResource(resource, namespace, resourcePath string) (a
760760
obj.SetNamespace(namespace)
761761
}
762762

763-
// add an ark-restore label to each resource for easy ID
764-
addLabel(obj, api.RestoreLabelKey, ctx.restore.Name)
763+
// label the resource with the restore's name for easy identification
764+
// of all cluster resources created by this restore
765+
addRestoreLabel(obj, ctx.restore.Name)
765766

766767
ctx.infof("Restoring %s: %v", obj.GroupVersionKind().Kind, name)
767768
createdObj, restoreErr := resourceClient.Create(obj)
@@ -782,8 +783,8 @@ func (ctx *context) restoreResource(resource, namespace, resourcePath string) (a
782783

783784
// We know the cluster won't have the restore name label, so
784785
// copy it over from the backup
785-
restoreName := obj.GetLabels()[api.RestoreLabelKey]
786-
addLabel(fromCluster, api.RestoreLabelKey, restoreName)
786+
restoreName := obj.GetLabels()[api.RestoreNameLabel]
787+
addRestoreLabel(fromCluster, restoreName)
787788

788789
if !equality.Semantic.DeepEqual(fromCluster, obj) {
789790
switch groupResource {
@@ -997,15 +998,20 @@ func resetMetadataAndStatus(obj *unstructured.Unstructured) (*unstructured.Unstr
997998
return obj, nil
998999
}
9991000

1000-
// addLabel applies the specified key/value to an object as a label.
1001-
func addLabel(obj *unstructured.Unstructured, key string, val string) {
1001+
// addRestoreLabel applies the specified key/value to an object as a label.
1002+
func addRestoreLabel(obj metav1.Object, restoreName string) {
10021003
labels := obj.GetLabels()
10031004

10041005
if labels == nil {
10051006
labels = make(map[string]string)
10061007
}
10071008

1008-
labels[key] = val
1009+
labels[api.RestoreNameLabel] = restoreName
1010+
1011+
// TODO(1.0): remove the below line, and remove the `RestoreLabelKey`
1012+
// constant from the API pkg, since it's been replaced with the
1013+
// namespaced label above.
1014+
labels[api.RestoreLabelKey] = restoreName
10091015

10101016
obj.SetLabels(labels)
10111017
}

pkg/restore/restore_test.go

Lines changed: 20 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -307,11 +307,12 @@ func TestNamespaceRemapping(t *testing.T) {
307307
WithFile("bak/resources/configmaps/namespaces/ns-1/cm-1.json", newTestConfigMap().WithNamespace("ns-1").ToJSON()).
308308
WithFile("bak/resources/namespaces/cluster/ns-1.json", newTestNamespace("ns-1").ToJSON())
309309
expectedNS = "ns-2"
310-
expectedObjs = toUnstructured(newTestConfigMap().WithNamespace("ns-2").WithArkLabel("").ConfigMap)
310+
expectedObjs = toUnstructured(newTestConfigMap().WithNamespace("ns-2").ConfigMap)
311311
)
312312

313313
resourceClient := &arktest.FakeDynamicClient{}
314314
for i := range expectedObjs {
315+
addRestoreLabel(&expectedObjs[i], "")
315316
resourceClient.On("Create", &expectedObjs[i]).Return(&expectedObjs[i], nil)
316317
}
317318

@@ -381,8 +382,8 @@ func TestRestoreResourceForNamespace(t *testing.T) {
381382
WithFile("configmaps/cm-1.json", newNamedTestConfigMap("cm-1").ToJSON()).
382383
WithFile("configmaps/cm-2.json", newNamedTestConfigMap("cm-2").ToJSON()),
383384
expectedObjs: toUnstructured(
384-
newNamedTestConfigMap("cm-1").WithArkLabel("my-restore").ConfigMap,
385-
newNamedTestConfigMap("cm-2").WithArkLabel("my-restore").ConfigMap,
385+
newNamedTestConfigMap("cm-1").ConfigMap,
386+
newNamedTestConfigMap("cm-2").ConfigMap,
386387
),
387388
},
388389
{
@@ -415,15 +416,15 @@ func TestRestoreResourceForNamespace(t *testing.T) {
415416
"ns-1": {"error decoding \"configmaps/cm-1-invalid.json\": invalid character 'h' in literal true (expecting 'r')"},
416417
},
417418
},
418-
expectedObjs: toUnstructured(newNamedTestConfigMap("cm-2").WithArkLabel("my-restore").ConfigMap),
419+
expectedObjs: toUnstructured(newNamedTestConfigMap("cm-2").ConfigMap),
419420
},
420421
{
421422
name: "matching label selector correctly includes",
422423
namespace: "ns-1",
423424
resourcePath: "configmaps",
424425
labelSelector: labels.SelectorFromSet(labels.Set(map[string]string{"foo": "bar"})),
425426
fileSystem: arktest.NewFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().WithLabels(map[string]string{"foo": "bar"}).ToJSON()),
426-
expectedObjs: toUnstructured(newTestConfigMap().WithLabels(map[string]string{"foo": "bar"}).WithArkLabel("my-restore").ConfigMap),
427+
expectedObjs: toUnstructured(newTestConfigMap().WithLabels(map[string]string{"foo": "bar"}).ConfigMap),
427428
},
428429
{
429430
name: "non-matching label selector correctly excludes",
@@ -440,15 +441,15 @@ func TestRestoreResourceForNamespace(t *testing.T) {
440441
fileSystem: arktest.NewFakeFileSystem().
441442
WithFile("configmaps/cm-1.json", newTestConfigMap().WithControllerOwner().ToJSON()).
442443
WithFile("configmaps/cm-2.json", newNamedTestConfigMap("cm-2").ToJSON()),
443-
expectedObjs: toUnstructured(newNamedTestConfigMap("cm-2").WithArkLabel("my-restore").ConfigMap),
444+
expectedObjs: toUnstructured(newNamedTestConfigMap("cm-2").ConfigMap),
444445
},
445446
{
446447
name: "namespace is remapped",
447448
namespace: "ns-2",
448449
resourcePath: "configmaps",
449450
labelSelector: labels.NewSelector(),
450451
fileSystem: arktest.NewFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().WithNamespace("ns-1").ToJSON()),
451-
expectedObjs: toUnstructured(newTestConfigMap().WithNamespace("ns-2").WithArkLabel("my-restore").ConfigMap),
452+
expectedObjs: toUnstructured(newTestConfigMap().WithNamespace("ns-2").ConfigMap),
452453
},
453454
{
454455
name: "custom restorer is correctly used",
@@ -464,7 +465,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
464465
selector: labels.Everything(),
465466
},
466467
},
467-
expectedObjs: toUnstructured(newTestConfigMap().WithLabels(map[string]string{"fake-restorer": "foo"}).WithArkLabel("my-restore").ConfigMap),
468+
expectedObjs: toUnstructured(newTestConfigMap().WithLabels(map[string]string{"fake-restorer": "foo"}).ConfigMap),
468469
},
469470
{
470471
name: "custom restorer for different group/resource is not used",
@@ -480,7 +481,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
480481
selector: labels.Everything(),
481482
},
482483
},
483-
expectedObjs: toUnstructured(newTestConfigMap().WithArkLabel("my-restore").ConfigMap),
484+
expectedObjs: toUnstructured(newTestConfigMap().ConfigMap),
484485
},
485486
{
486487
name: "cluster-scoped resources are skipped when IncludeClusterResources=false",
@@ -497,7 +498,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
497498
labelSelector: labels.NewSelector(),
498499
includeClusterResources: falsePtr,
499500
fileSystem: arktest.NewFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().ToJSON()),
500-
expectedObjs: toUnstructured(newTestConfigMap().WithArkLabel("my-restore").ConfigMap),
501+
expectedObjs: toUnstructured(newTestConfigMap().ConfigMap),
501502
},
502503
{
503504
name: "cluster-scoped resources are not skipped when IncludeClusterResources=true",
@@ -506,7 +507,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
506507
labelSelector: labels.NewSelector(),
507508
includeClusterResources: truePtr,
508509
fileSystem: arktest.NewFakeFileSystem().WithFile("persistentvolumes/pv-1.json", newTestPV().ToJSON()),
509-
expectedObjs: toUnstructured(newTestPV().WithArkLabel("my-restore").PersistentVolume),
510+
expectedObjs: toUnstructured(newTestPV().PersistentVolume),
510511
},
511512
{
512513
name: "namespaced resources are not skipped when IncludeClusterResources=true",
@@ -515,7 +516,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
515516
labelSelector: labels.NewSelector(),
516517
includeClusterResources: truePtr,
517518
fileSystem: arktest.NewFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().ToJSON()),
518-
expectedObjs: toUnstructured(newTestConfigMap().WithArkLabel("my-restore").ConfigMap),
519+
expectedObjs: toUnstructured(newTestConfigMap().ConfigMap),
519520
},
520521
{
521522
name: "cluster-scoped resources are not skipped when IncludeClusterResources=nil",
@@ -524,7 +525,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
524525
labelSelector: labels.NewSelector(),
525526
includeClusterResources: nil,
526527
fileSystem: arktest.NewFakeFileSystem().WithFile("persistentvolumes/pv-1.json", newTestPV().ToJSON()),
527-
expectedObjs: toUnstructured(newTestPV().WithArkLabel("my-restore").PersistentVolume),
528+
expectedObjs: toUnstructured(newTestPV().PersistentVolume),
528529
},
529530
{
530531
name: "namespaced resources are not skipped when IncludeClusterResources=nil",
@@ -533,7 +534,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
533534
labelSelector: labels.NewSelector(),
534535
includeClusterResources: nil,
535536
fileSystem: arktest.NewFakeFileSystem().WithFile("configmaps/cm-1.json", newTestConfigMap().ToJSON()),
536-
expectedObjs: toUnstructured(newTestConfigMap().WithArkLabel("my-restore").ConfigMap),
537+
expectedObjs: toUnstructured(newTestConfigMap().ConfigMap),
537538
},
538539
{
539540
name: "serviceaccounts are restored",
@@ -542,7 +543,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
542543
labelSelector: labels.NewSelector(),
543544
includeClusterResources: nil,
544545
fileSystem: arktest.NewFakeFileSystem().WithFile("serviceaccounts/sa-1.json", newTestServiceAccount().ToJSON()),
545-
expectedObjs: toUnstructured(newTestServiceAccount().WithArkLabel("my-restore").ServiceAccount),
546+
expectedObjs: toUnstructured(newTestServiceAccount().ServiceAccount),
546547
},
547548
{
548549
name: "non-mirror pods are restored",
@@ -566,7 +567,6 @@ func TestRestoreResourceForNamespace(t *testing.T) {
566567
WithKind("Pod").
567568
WithNamespace("ns-1").
568569
WithName("pod1").
569-
WithArkLabel("my-restore").
570570
Unstructured),
571571
},
572572
},
@@ -594,6 +594,7 @@ func TestRestoreResourceForNamespace(t *testing.T) {
594594
t.Run(test.name, func(t *testing.T) {
595595
resourceClient := &arktest.FakeDynamicClient{}
596596
for i := range test.expectedObjs {
597+
addRestoreLabel(&test.expectedObjs[i], "my-restore")
597598
resourceClient.On("Create", &test.expectedObjs[i]).Return(&test.expectedObjs[i], nil)
598599
}
599600

@@ -679,8 +680,7 @@ func TestRestoringExistingServiceAccount(t *testing.T) {
679680
m[k] = v
680681
}
681682
fromBackupWithLabel := &unstructured.Unstructured{Object: m}
682-
l := map[string]string{api.RestoreLabelKey: "my-restore"}
683-
fromBackupWithLabel.SetLabels(l)
683+
addRestoreLabel(fromBackupWithLabel, "my-restore")
684684
// resetMetadataAndStatus will strip the creationTimestamp before calling Create
685685
fromBackupWithLabel.SetCreationTimestamp(metav1.Time{Time: time.Time{}})
686686

@@ -922,7 +922,7 @@ status:
922922
}
923923

924924
resetMetadataAndStatus(unstructuredPV)
925-
addLabel(unstructuredPV, api.RestoreLabelKey, ctx.restore.Name)
925+
addRestoreLabel(unstructuredPV, ctx.restore.Name)
926926
unstructuredPV.Object["foo"] = "bar"
927927

928928
if test.expectPVCreation {
@@ -964,7 +964,7 @@ status:
964964
unstructuredPVC := &unstructured.Unstructured{Object: unstructuredPVCMap}
965965

966966
resetMetadataAndStatus(unstructuredPVC)
967-
addLabel(unstructuredPVC, api.RestoreLabelKey, ctx.restore.Name)
967+
addRestoreLabel(unstructuredPVC, ctx.restore.Name)
968968

969969
createdPVC := unstructuredPVC.DeepCopy()
970970
// just to ensure we have the data flowing correctly
@@ -1422,17 +1422,6 @@ func (obj *testUnstructured) WithName(name string) *testUnstructured {
14221422
return obj.WithMetadataField("name", name)
14231423
}
14241424

1425-
func (obj *testUnstructured) WithArkLabel(restoreName string) *testUnstructured {
1426-
ls := obj.GetLabels()
1427-
if ls == nil {
1428-
ls = make(map[string]string)
1429-
}
1430-
ls[api.RestoreLabelKey] = restoreName
1431-
obj.SetLabels(ls)
1432-
1433-
return obj
1434-
}
1435-
14361425
func (obj *testUnstructured) ToJSON() []byte {
14371426
bytes, err := json.Marshal(obj.Object)
14381427
if err != nil {
@@ -1514,14 +1503,6 @@ func newTestServiceAccount() *testServiceAccount {
15141503
}
15151504
}
15161505

1517-
func (sa *testServiceAccount) WithArkLabel(restoreName string) *testServiceAccount {
1518-
if sa.Labels == nil {
1519-
sa.Labels = make(map[string]string)
1520-
}
1521-
sa.Labels[api.RestoreLabelKey] = restoreName
1522-
return sa
1523-
}
1524-
15251506
func (sa *testServiceAccount) WithImagePullSecret(name string) *testServiceAccount {
15261507
secret := v1.LocalObjectReference{Name: name}
15271508
sa.ImagePullSecrets = append(sa.ImagePullSecrets, secret)
@@ -1558,14 +1539,6 @@ func newTestPV() *testPersistentVolume {
15581539
}
15591540
}
15601541

1561-
func (pv *testPersistentVolume) WithArkLabel(restoreName string) *testPersistentVolume {
1562-
if pv.Labels == nil {
1563-
pv.Labels = make(map[string]string)
1564-
}
1565-
pv.Labels[api.RestoreLabelKey] = restoreName
1566-
return pv
1567-
}
1568-
15691542
func (pv *testPersistentVolume) ToJSON() []byte {
15701543
bytes, _ := json.Marshal(pv.PersistentVolume)
15711544
return bytes
@@ -1620,16 +1593,6 @@ func newNamedTestConfigMap(name string) *testConfigMap {
16201593
}
16211594
}
16221595

1623-
func (cm *testConfigMap) WithArkLabel(restoreName string) *testConfigMap {
1624-
if cm.Labels == nil {
1625-
cm.Labels = make(map[string]string)
1626-
}
1627-
1628-
cm.Labels[api.RestoreLabelKey] = restoreName
1629-
1630-
return cm
1631-
}
1632-
16331596
func (cm *testConfigMap) WithNamespace(name string) *testConfigMap {
16341597
cm.Namespace = name
16351598
return cm

0 commit comments

Comments
 (0)