From f0e71ba5435ffc98f41ad5c5355847d15b08b3fb Mon Sep 17 00:00:00 2001 From: Haiyan Meng Date: Tue, 5 Oct 2021 10:45:11 -0700 Subject: [PATCH] Skip pruning an object whose Group/Kind is not found --- pkg/apply/prune/prune.go | 13 ++++++---- pkg/apply/prune/prune_test.go | 49 +++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/pkg/apply/prune/prune.go b/pkg/apply/prune/prune.go index 2b23b34..72b12f3 100644 --- a/pkg/apply/prune/prune.go +++ b/pkg/apply/prune/prune.go @@ -166,14 +166,17 @@ func (po *PruneOptions) GetPruneObjs(inv inventory.InventoryInfo, for _, pruneID := range pruneIds { pruneObj, err := po.GetObject(pruneID) if err != nil { - // If prune object is not in cluster, no need to prune it--skip. - if apierrors.IsNotFound(err) { - klog.V(4).Infof("prune obj not in cluster--skip (%s/%s)", + if meta.IsNoMatchError(err) { + klog.V(4).Infof("skip pruning obj %s/%s: the resource type is unrecognized by the cluster (kind: %s, group %s)", + pruneID.Namespace, pruneID.Name, pruneID.GroupKind.Kind, pruneID.GroupKind.Group) + continue + } else if apierrors.IsNotFound(err) { + // If prune object is not in cluster, no need to prune it--skip. + klog.V(4).Infof("skip pruning obj %s/%s: not found in the cluster", pruneID.Namespace, pruneID.Name) continue - } else { - return nil, err } + return nil, err } pruneObjs = append(pruneObjs, pruneObj) } diff --git a/pkg/apply/prune/prune_test.go b/pkg/apply/prune/prune_test.go index ed4ce98..75cfab0 100644 --- a/pkg/apply/prune/prune_test.go +++ b/pkg/apply/prune/prune_test.go @@ -11,6 +11,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta/testrestmapper" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -110,6 +112,14 @@ var pdbDeleteFailure = &unstructured.Unstructured{ }, } +var crontabCRManifest = ` +apiVersion: "stable.example.com/v1" +kind: CronTab +metadata: + name: cron-tab-01 + namespace: test-namespace +` + // Returns a inventory object with the inventory set from // the passed "children". func createInventoryInfo(children ...*unstructured.Unstructured) inventory.InventoryInfo { @@ -549,6 +559,11 @@ func TestGetPruneObjs(t *testing.T) { prevInventory: []*unstructured.Unstructured{pod, pdb, namespace}, expectedObjs: []*unstructured.Unstructured{pod, namespace}, }, + "skip pruning objects whose resource types are unrecognized by the cluster": { + localObjs: []*unstructured.Unstructured{pdb}, + prevInventory: []*unstructured.Unstructured{testutil.Unstructured(t, crontabCRManifest), pdb, namespace}, + expectedObjs: []*unstructured.Unstructured{namespace}, + }, "local objs, inventory disjoint means inventory is pruned": { localObjs: []*unstructured.Unstructured{pdb}, prevInventory: []*unstructured.Unstructured{pod, namespace}, @@ -588,6 +603,40 @@ func TestGetPruneObjs(t *testing.T) { } } +func TestGetObject_NoMatchError(t *testing.T) { + po := PruneOptions{ + Client: fake.NewSimpleDynamicClient(scheme.Scheme, pod, namespace), + Mapper: testrestmapper.TestOnlyStaticRESTMapper(scheme.Scheme, + scheme.Scheme.PrioritizedVersionsAllGroups()...), + } + _, err := po.GetObject(testutil.ToIdentifier(t, crontabCRManifest)) + if err == nil { + t.Fatalf("expected GetObject() to return a NoKindMatchError, got nil") + } + if !meta.IsNoMatchError(err) { + t.Fatalf("expected GetObject() to return a NoKindMatchError, got %v", err) + } +} + +func TestGetObject_NotFoundError(t *testing.T) { + po := PruneOptions{ + Client: fake.NewSimpleDynamicClient(scheme.Scheme, pod, namespace), + Mapper: testrestmapper.TestOnlyStaticRESTMapper(scheme.Scheme, + scheme.Scheme.PrioritizedVersionsAllGroups()...), + } + objMeta, err := object.UnstructuredToObjMeta(pdb) + if err != nil { + t.Fatalf("unexpected error %s returned", err) + } + _, err = po.GetObject(objMeta) + if err == nil { + t.Fatalf("expected GetObject() to return a NotFound error, got nil") + } + if !apierrors.IsNotFound(err) { + t.Fatalf("expected GetObject() to return a NotFound error, got %v", err) + } +} + type optionsCaptureNamespaceClient struct { dynamic.ResourceInterface options metav1.DeleteOptions