From 0f063c4dbc95a550f542e857774c00f547de73d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wenkai=20Yin=28=E5=B0=B9=E6=96=87=E5=BC=80=29?= Date: Mon, 6 Feb 2023 13:55:04 +0800 Subject: [PATCH] Restore finalizer and managedFields (#5808) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restore finalizer and managedFields of metadata during the restoration Signed-off-by: Wenkai Yin(尹文开) --- changelogs/unreleased/5808-ywk253100 | 1 + pkg/builder/object_meta.go | 7 ++++ pkg/restore/restore.go | 22 +++++++++- pkg/restore/restore_test.go | 63 ++++++++++++++++++++++++++-- 4 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 changelogs/unreleased/5808-ywk253100 diff --git a/changelogs/unreleased/5808-ywk253100 b/changelogs/unreleased/5808-ywk253100 new file mode 100644 index 0000000000..b459e8958a --- /dev/null +++ b/changelogs/unreleased/5808-ywk253100 @@ -0,0 +1 @@ +Restore finalizer and managedFields of metadata during the restoration \ No newline at end of file diff --git a/pkg/builder/object_meta.go b/pkg/builder/object_meta.go index 6c01019b47..6df1afadc8 100644 --- a/pkg/builder/object_meta.go +++ b/pkg/builder/object_meta.go @@ -146,3 +146,10 @@ func WithGenerateName(val string) func(obj metav1.Object) { obj.SetGenerateName(val) } } + +// WithManagedFields is a functional option that applies the specified managed fields to an object. +func WithManagedFields(val []metav1.ManagedFieldsEntry) func(obj metav1.Object) { + return func(obj metav1.Object) { + obj.SetManagedFields(val) + } +} diff --git a/pkg/restore/restore.go b/pkg/restore/restore.go index afc1933d97..4a48d09f41 100644 --- a/pkg/restore/restore.go +++ b/pkg/restore/restore.go @@ -1415,6 +1415,24 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso } } + // restore the managedFields + withoutManagedFields := createdObj.DeepCopy() + createdObj.SetManagedFields(obj.GetManagedFields()) + patchBytes, err := generatePatch(withoutManagedFields, createdObj) + if err != nil { + ctx.log.Errorf("error generating patch for managed fields %s: %v", kube.NamespaceAndName(obj), err) + errs.Add(namespace, err) + return warnings, errs + } + if patchBytes != nil { + if _, err = resourceClient.Patch(name, patchBytes); err != nil { + ctx.log.Errorf("error patch for managed fields %s: %v", kube.NamespaceAndName(obj), err) + errs.Add(namespace, err) + return warnings, errs + } + ctx.log.Infof("the managed fields for %s is patched", kube.NamespaceAndName(obj)) + } + if groupResource == kuberesource.Pods { pod := new(v1.Pod) if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), pod); err != nil { @@ -1714,8 +1732,8 @@ func resetMetadata(obj *unstructured.Unstructured) (*unstructured.Unstructured, for k := range metadata { switch k { - case "name", "namespace", "labels", "annotations": - default: + case "generateName", "selfLink", "uid", "resourceVersion", "generation", "creationTimestamp", "deletionTimestamp", + "deletionGracePeriodSeconds", "ownerReferences": delete(metadata, k) } } diff --git a/pkg/restore/restore_test.go b/pkg/restore/restore_test.go index 029ab6f7f1..824d58a360 100644 --- a/pkg/restore/restore_test.go +++ b/pkg/restore/restore_test.go @@ -865,7 +865,7 @@ func TestRestoreItems(t *testing.T) { want []*test.APIResource }{ { - name: "metadata other than namespace/name/labels/annotations gets removed", + name: "metadata uid/resourceVersion/etc. gets removed", restore: defaultRestore().Result(), backup: defaultBackup().Result(), tarball: test.NewTarWriter(t). @@ -875,6 +875,7 @@ func TestRestoreItems(t *testing.T) { builder.WithLabels("key-1", "val-1"), builder.WithAnnotations("key-1", "val-1"), builder.WithFinalizers("finalizer-1"), + builder.WithUID("uid"), ). Result(), ). @@ -888,6 +889,7 @@ func TestRestoreItems(t *testing.T) { ObjectMeta( builder.WithLabels("key-1", "val-1", "velero.io/backup-name", "backup-1", "velero.io/restore-name", "restore-1"), builder.WithAnnotations("key-1", "val-1"), + builder.WithFinalizers("finalizer-1"), ). Result(), ), @@ -1105,6 +1107,53 @@ func TestRestoreItems(t *testing.T) { }), }, }, + { + name: "metadata managedFields gets restored", + restore: defaultRestore().Result(), + backup: defaultBackup().Result(), + tarball: test.NewTarWriter(t). + AddItems("pods", + builder.ForPod("ns-1", "pod-1"). + ObjectMeta( + builder.WithManagedFields([]metav1.ManagedFieldsEntry{ + { + Manager: "kubectl", + Operation: "Apply", + APIVersion: "v1", + FieldsType: "FieldsV1", + FieldsV1: &metav1.FieldsV1{ + Raw: []byte(`{"f:data": {"f:key":{}}}`), + }, + }, + }), + ). + Result(), + ). + Done(), + apiResources: []*test.APIResource{ + test.Pods(), + }, + want: []*test.APIResource{ + test.Pods( + builder.ForPod("ns-1", "pod-1"). + ObjectMeta( + builder.WithLabels("velero.io/backup-name", "backup-1", "velero.io/restore-name", "restore-1"), + builder.WithManagedFields([]metav1.ManagedFieldsEntry{ + { + Manager: "kubectl", + Operation: "Apply", + APIVersion: "v1", + FieldsType: "FieldsV1", + FieldsV1: &metav1.FieldsV1{ + Raw: []byte(`{"f:data": {"f:key":{}}}`), + }, + }, + }), + ). + Result(), + ), + }, + }, } for _, tc := range tests { @@ -2821,10 +2870,16 @@ func TestResetMetadata(t *testing.T) { expectedErr: true, }, { - name: "keep name, namespace, labels, annotations only", - obj: NewTestUnstructured().WithMetadata("name", "blah", "namespace", "labels", "annotations", "foo").Unstructured, + name: "keep name, namespace, labels, annotations, managedFields, finalizers", + obj: NewTestUnstructured().WithMetadata("name", "namespace", "labels", "annotations", "managedFields", "finalizers").Unstructured, + expectedErr: false, + expectedRes: NewTestUnstructured().WithMetadata("name", "namespace", "labels", "annotations", "managedFields", "finalizers").Unstructured, + }, + { + name: "remove uid, ownerReferences", + obj: NewTestUnstructured().WithMetadata("name", "namespace", "uid", "ownerReferences").Unstructured, expectedErr: false, - expectedRes: NewTestUnstructured().WithMetadata("name", "namespace", "labels", "annotations").Unstructured, + expectedRes: NewTestUnstructured().WithMetadata("name", "namespace").Unstructured, }, { name: "keep status",