diff --git a/api/builtins/PatchTransformer.go b/api/builtins/PatchTransformer.go index cb7a83c01..67e49fb05 100644 --- a/api/builtins/PatchTransformer.go +++ b/api/builtins/PatchTransformer.go @@ -8,6 +8,7 @@ import ( "strings" jsonpatch "github.com/evanphx/json-patch" + "github.com/pkg/errors" "sigs.k8s.io/kustomize/api/filters/patchjson6902" "sigs.k8s.io/kustomize/api/filters/patchstrategicmerge" "sigs.k8s.io/kustomize/api/resmap" @@ -101,7 +102,31 @@ func (p *PatchTransformerPlugin) transformStrategicMerge(m resmap.ResMap, patch patchCopy.SetGvk(res.GetGvk()) err := p.applySMPatch(res, patchCopy) if err != nil { - return err + // Check for an error string from UnmarshalJSON that's indicative + // of an object that's missing basic KRM fields, and thus may have been + // entirely deleted (an acceptable outcome). This error handling should + // be deleted along with use of ResMap and apimachinery functions like + // UnmarshalJSON. + if !strings.Contains(err.Error(), "Object 'Kind' is missing") { + // Some unknown error, let it through. + return err + } + if len(res.Map()) != 0 { + return errors.Wrapf( + err, "with unexpectedly non-empty object map of size %d", + len(res.Map())) + } + // Fall through to handle deleted object. + } + if len(res.Map()) == 0 { + // This means all fields have been removed from the object. + // This can happen if a patch required deletion of the + // entire resource (not just a part of it). This means + // the overall resmap must shrink by one. + err = m.Remove(res.CurId()) + if err != nil { + return err + } } } return nil diff --git a/plugin/builtin/patchtransformer/PatchTransformer.go b/plugin/builtin/patchtransformer/PatchTransformer.go index c2e917492..bde29cf61 100644 --- a/plugin/builtin/patchtransformer/PatchTransformer.go +++ b/plugin/builtin/patchtransformer/PatchTransformer.go @@ -9,6 +9,7 @@ import ( "strings" jsonpatch "github.com/evanphx/json-patch" + "github.com/pkg/errors" "sigs.k8s.io/kustomize/api/filters/patchjson6902" "sigs.k8s.io/kustomize/api/filters/patchstrategicmerge" "sigs.k8s.io/kustomize/api/resmap" @@ -105,7 +106,31 @@ func (p *plugin) transformStrategicMerge(m resmap.ResMap, patch *resource.Resour patchCopy.SetGvk(res.GetGvk()) err := p.applySMPatch(res, patchCopy) if err != nil { - return err + // Check for an error string from UnmarshalJSON that's indicative + // of an object that's missing basic KRM fields, and thus may have been + // entirely deleted (an acceptable outcome). This error handling should + // be deleted along with use of ResMap and apimachinery functions like + // UnmarshalJSON. + if !strings.Contains(err.Error(), "Object 'Kind' is missing") { + // Some unknown error, let it through. + return err + } + if len(res.Map()) != 0 { + return errors.Wrapf( + err, "with unexpectedly non-empty object map of size %d", + len(res.Map())) + } + // Fall through to handle deleted object. + } + if len(res.Map()) == 0 { + // This means all fields have been removed from the object. + // This can happen if a patch required deletion of the + // entire resource (not just a part of it). This means + // the overall resmap must shrink by one. + err = m.Remove(res.CurId()) + if err != nil { + return err + } } } return nil diff --git a/plugin/builtin/patchtransformer/PatchTransformer_test.go b/plugin/builtin/patchtransformer/PatchTransformer_test.go index ac1bbb750..84dcf85f3 100644 --- a/plugin/builtin/patchtransformer/PatchTransformer_test.go +++ b/plugin/builtin/patchtransformer/PatchTransformer_test.go @@ -508,6 +508,61 @@ spec: `) } +func TestPatchTransformerWithPatchDelete(t *testing.T) { + th := kusttest_test.MakeEnhancedHarness(t). + PrepBuiltin("PatchTransformer") + defer th.Reset() + + th.RunTransformerAndCheckResult(` +apiVersion: builtin +kind: PatchTransformer +metadata: + name: notImportantHere +target: + name: myDeploy + kind: Deployment +patch: |- + apiVersion: apps/v1 + metadata: + name: myDeploy + kind: Deployment + $patch: delete +`, someDeploymentResources, ` +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + new-label: new-value + name: yourDeploy +spec: + replica: 1 + template: + metadata: + labels: + new-label: new-value + spec: + containers: + - image: nginx:1.7.9 + name: nginx +--- +apiVersion: apps/v1 +kind: MyKind +metadata: + label: + old-label: old-value + name: myDeploy +spec: + template: + metadata: + labels: + old-label: old-value + spec: + containers: + - image: nginx + name: nginx +`) +} + const anIngressResource = `apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: diff --git a/plugin/builtin/patchtransformer/go.mod b/plugin/builtin/patchtransformer/go.mod index 9715015dc..3ed291da5 100644 --- a/plugin/builtin/patchtransformer/go.mod +++ b/plugin/builtin/patchtransformer/go.mod @@ -6,6 +6,7 @@ require ( github.com/evanphx/json-patch v4.5.0+incompatible sigs.k8s.io/kustomize/api v0.6.2 sigs.k8s.io/kustomize/kyaml v0.8.1 + github.com/pkg/errors v0.8.1 sigs.k8s.io/yaml v1.2.0 )