Skip to content

Commit

Permalink
Restore finalizer and managedFields (#5808)
Browse files Browse the repository at this point in the history
Restore finalizer and managedFields of metadata during the restoration

Signed-off-by: Wenkai Yin(尹文开) <[email protected]>
  • Loading branch information
ywk253100 authored Feb 6, 2023
1 parent dd66088 commit 0f063c4
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 6 deletions.
1 change: 1 addition & 0 deletions changelogs/unreleased/5808-ywk253100
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Restore finalizer and managedFields of metadata during the restoration
7 changes: 7 additions & 0 deletions pkg/builder/object_meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
22 changes: 20 additions & 2 deletions pkg/restore/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
}
}
Expand Down
63 changes: 59 additions & 4 deletions pkg/restore/restore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand All @@ -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(),
).
Expand All @@ -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(),
),
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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",
Expand Down

0 comments on commit 0f063c4

Please sign in to comment.