From 290b185518db62227f2458c3f6c673a158d3901a Mon Sep 17 00:00:00 2001 From: Nolan Brubaker Date: Thu, 29 Mar 2018 14:50:30 -0400 Subject: [PATCH] Compare backup and cluster objects before logging When restoring resources that raise an already exists error, check their equality before logging a message on the restore. If they're the same except for some metadata, don't generate a message. The restore process was modified so that if an object had an empty namespace string, no namespace key is created on the object. This was to avoid manipulating the copy of the current cluster's object by adding the target namespace. There are some cases right now that are known to not be equal via this method: - The `default` ServiceAccount in a namespace will not match, primarily because of differing default tokens. These will be handled in their own patch - IP addresses for Services are recorded in the backup object, but are either not present on the cluster object, or different. An issue for this already exists at https://github.com/heptio/ark/issues/354 - Endpoints have differing values for `renewTime`. This may be insubstantial, but isn't currently handled by the resetMetadataAndStatus function. - PersistentVolume objects in the backup have a `claimRef` section, while those in cluster do not. Signed-off-by: Nolan Brubaker --- pkg/restore/restore.go | 20 +++++++++++++++++--- pkg/restore/restore_test.go | 4 ---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/pkg/restore/restore.go b/pkg/restore/restore.go index 8a01b27816e..02c8013a208 100644 --- a/pkg/restore/restore.go +++ b/pkg/restore/restore.go @@ -31,6 +31,7 @@ import ( "github.com/sirupsen/logrus" "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -634,7 +635,10 @@ func (ctx *context) restoreResource(resource, namespace, resourcePath string) (a } // necessary because we may have remapped the namespace - obj.SetNamespace(namespace) + // if the namespace is blank, don't create the key + if namespace != "" { + obj.SetNamespace(namespace) + } // add an ark-restore label to each resource for easy ID addLabel(obj, api.RestoreLabelKey, ctx.restore.Name) @@ -642,8 +646,18 @@ func (ctx *context) restoreResource(resource, namespace, resourcePath string) (a ctx.infof("Restoring %s: %v", obj.GroupVersionKind().Kind, obj.GetName()) _, err = resourceClient.Create(obj) if apierrors.IsAlreadyExists(err) { - addToResult(&warnings, namespace, err) - continue + fromCluster, _ := resourceClient.Get(obj.GetName(), metav1.GetOptions{}) + // Remove insubstantial metadata + fromCluster, _ = resetMetadataAndStatus(fromCluster) + // Add the restore's label to the in-cluster object since we know that's different + addLabel(fromCluster, api.RestoreLabelKey, ctx.restore.Name) + + if equality.Semantic.DeepEqual(obj, fromCluster) { + continue + } else { + addToResult(&warnings, namespace, err) + continue + } } if err != nil { ctx.infof("error restoring %s: %v", obj.GetName(), err) diff --git a/pkg/restore/restore_test.go b/pkg/restore/restore_test.go index 39d02322ec1..4776f3dad31 100644 --- a/pkg/restore/restore_test.go +++ b/pkg/restore/restore_test.go @@ -942,10 +942,6 @@ func toUnstructured(objs ...runtime.Object) []unstructured.Unstructured { delete(metadata, "creationTimestamp") - if _, exists := metadata["namespace"]; !exists { - metadata["namespace"] = "" - } - delete(unstructuredObj.Object, "status") res = append(res, unstructuredObj)