diff --git a/api/filters/patchstrategicmerge/patchstrategicmerge_test.go b/api/filters/patchstrategicmerge/patchstrategicmerge_test.go index fd0120350..d9a0c2ab6 100644 --- a/api/filters/patchstrategicmerge/patchstrategicmerge_test.go +++ b/api/filters/patchstrategicmerge/patchstrategicmerge_test.go @@ -142,6 +142,234 @@ spec: - name: nginx args: - def +`, + }, + "remove mapping - directive": { + input: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: + containers: + - name: test + image: test +`, + patch: yaml.MustParse(` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: + containers: + - name: test + image: test + $patch: delete +`), + expected: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: + containers: [] +`, + }, + "replace mapping - directive": { + input: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: + containers: + - name: test + image: test +`, + patch: yaml.MustParse(` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: + $patch: replace + containers: + - name: new +`), + expected: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: + containers: + - name: new +`, + }, + "merge mapping - directive": { + input: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: + containers: + - name: test + image: test +`, + patch: yaml.MustParse(` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: + containers: + - name: test + image: test1 + $patch: merge +`), + expected: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: + containers: + - name: test + image: test1 +`, + }, + "remove list - directive": { + input: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: + containers: + - name: test + image: test +`, + patch: yaml.MustParse(` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: + containers: + - whatever + - $patch: delete +`), + expected: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: {} +`, + }, + "replace list - directive": { + input: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: + containers: + - name: test + image: test +`, + patch: yaml.MustParse(` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: + containers: + - name: replace + image: replace + - $patch: replace +`), + expected: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: + containers: + - name: replace + image: replace +`, + }, + "merge list - directive": { + input: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: + containers: + - name: test + image: test +`, + patch: yaml.MustParse(` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: + containers: + - name: test2 + image: test2 + - $patch: merge +`), + expected: ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myDeploy +spec: + template: + spec: + containers: + - name: test + image: test + - name: test2 + image: test2 `, }, } diff --git a/kustomize/go.mod b/kustomize/go.mod index 4b4df52b7..53eba1cce 100644 --- a/kustomize/go.mod +++ b/kustomize/go.mod @@ -22,3 +22,5 @@ exclude ( replace sigs.k8s.io/kustomize/cmd/config v0.8.1 => ../cmd/config replace sigs.k8s.io/kustomize/api v0.6.2 => ../api + +replace sigs.k8s.io/kustomize/kyaml v0.8.1 => ../kyaml diff --git a/kyaml/yaml/merge2/list_test.go b/kyaml/yaml/merge2/list_test.go index ad21a7e47..dd51e0c09 100644 --- a/kyaml/yaml/merge2/list_test.go +++ b/kyaml/yaml/merge2/list_test.go @@ -142,6 +142,109 @@ spec: - name: foo3 `, }, + {description: `merge k8s deployment containers -- $patch directive`, + source: ` + apiVersion: apps/v1 + kind: Deployment + spec: + template: + spec: + containers: + - name: foo1 + - name: foo2 + - name: foo3 + - $patch: merge +`, + dest: ` + apiVersion: apps/v1 + kind: Deployment + spec: + template: + spec: + containers: + - name: foo4 + - name: foo5 +`, + expected: ` + apiVersion: apps/v1 + kind: Deployment + spec: + template: + spec: + containers: + - name: foo1 + - name: foo2 + - name: foo3 + - name: foo4 + - name: foo5 +`, + }, + {description: `replace k8s deployment containers -- $patch directive`, + source: ` + apiVersion: apps/v1 + kind: Deployment + spec: + template: + spec: + containers: + - name: foo1 + - name: foo2 + - name: foo3 + - $patch: replace +`, + dest: ` + apiVersion: apps/v1 + kind: Deployment + spec: + template: + spec: + containers: + - name: foo4 + - name: foo5 +`, + expected: ` + apiVersion: apps/v1 + kind: Deployment + spec: + template: + spec: + containers: + - name: foo1 + - name: foo2 + - name: foo3 +`, + }, + {description: `remove k8s deployment containers -- $patch directive`, + source: ` + apiVersion: apps/v1 + kind: Deployment + spec: + template: + spec: + containers: + - name: foo1 + - name: foo2 + - name: foo3 + - $patch: delete +`, + dest: ` + apiVersion: apps/v1 + kind: Deployment + spec: + template: + spec: + containers: + - name: foo4 + - name: foo5 +`, + expected: ` + apiVersion: apps/v1 + kind: Deployment + spec: + template: + spec: {} +`, + }, {description: `replace List -- different value in dest`, source: ` diff --git a/kyaml/yaml/merge2/merge2.go b/kyaml/yaml/merge2/merge2.go index 632798a2b..8451ef914 100644 --- a/kyaml/yaml/merge2/merge2.go +++ b/kyaml/yaml/merge2/merge2.go @@ -61,7 +61,7 @@ func (m Merger) VisitMap(nodes walk.Sources, s *openapi.ResourceSchema) (*yaml.R return walk.ClearNode, nil } - ps, err := determineMappingNodePatchStrategy(nodes.Origin()) + ps, err := determineSmpDirective(nodes.Origin()) if err != nil { return nil, err } @@ -115,8 +115,20 @@ func (m Merger) VisitList(nodes walk.Sources, s *openapi.ResourceSchema, kind wa if nodes.Origin().IsTaggedNull() { return walk.ClearNode, nil } - // Recursively Merge dest - return nodes.Dest(), nil + + ps, err := determineSmpDirective(nodes.Origin()) + if err != nil { + return nil, err + } + + switch ps { + case smpDelete: + return walk.ClearNode, nil + case smpReplace: + return nodes.Origin(), nil + default: + return nodes.Dest(), nil + } } func (m Merger) SetStyle(sources walk.Sources) error { diff --git a/kyaml/yaml/merge2/smpdirective.go b/kyaml/yaml/merge2/smpdirective.go index 5d2a973b3..b5b2fbb7e 100644 --- a/kyaml/yaml/merge2/smpdirective.go +++ b/kyaml/yaml/merge2/smpdirective.go @@ -42,9 +42,31 @@ func determineSmpDirective(patch *yaml.RNode) (smpDirective, error) { } } -// TODO: what should this do? -func determineSequenceNodePatchStrategy(_ *yaml.RNode) (smpDirective, error) { - return smpMerge, nil +func determineSequenceNodePatchStrategy(patch *yaml.RNode) (smpDirective, error) { + // get the $patch element + node, err := patch.Pipe(yaml.GetElementByKey(strategicMergePatchDirectiveKey)) + // if there are more than 1 key/value pair in the map, then this $patch + // is not for the sequence + if err != nil || node == nil || node.YNode() == nil || len(node.Content()) > 2 { + return smpMerge, nil + } + // get the value + value, err := node.Pipe(yaml.Get(strategicMergePatchDirectiveKey)) + if err != nil || value == nil || value.YNode() == nil { + return smpMerge, nil + } + v := value.YNode().Value + if v == smpDelete.String() { + return smpDelete, elideSequencePatchDirective(patch, v) + } + if v == smpReplace.String() { + return smpReplace, elideSequencePatchDirective(patch, v) + } + if v == smpMerge.String() { + return smpMerge, elideSequencePatchDirective(patch, v) + } + return smpUnknown, fmt.Errorf( + "unknown patch strategy '%s'", v) } func determineMappingNodePatchStrategy(patch *yaml.RNode) (smpDirective, error) { @@ -54,18 +76,26 @@ func determineMappingNodePatchStrategy(patch *yaml.RNode) (smpDirective, error) } v := node.YNode().Value if v == smpDelete.String() { - return smpDelete, elidePatchDirective(patch) + return smpDelete, elideMappingPatchDirective(patch) } if v == smpReplace.String() { - return smpReplace, elidePatchDirective(patch) + return smpReplace, elideMappingPatchDirective(patch) } if v == smpMerge.String() { - return smpMerge, elidePatchDirective(patch) + return smpMerge, elideMappingPatchDirective(patch) } return smpUnknown, fmt.Errorf( "unknown patch strategy '%s'", v) } -func elidePatchDirective(patch *yaml.RNode) error { +func elideMappingPatchDirective(patch *yaml.RNode) error { return patch.PipeE(yaml.Clear(strategicMergePatchDirectiveKey)) } + +func elideSequencePatchDirective(patch *yaml.RNode, value string) error { + return patch.PipeE(yaml.ElementSetter{ + Element: nil, + Key: strategicMergePatchDirectiveKey, + Value: value, + }) +} diff --git a/kyaml/yaml/merge2/smpdirective_test.go b/kyaml/yaml/merge2/smpdirective_test.go index fbb719b9c..fce744fca 100644 --- a/kyaml/yaml/merge2/smpdirective_test.go +++ b/kyaml/yaml/merge2/smpdirective_test.go @@ -26,6 +26,45 @@ func Test_determineSmpDirective(t *testing.T) { - one - two - three +- $patch: merge +`, + expected: smpMerge, + elided: `- one +- two +- three +`, + }, + "list replace": { + patch: ` +- one +- two +- three +- $patch: replace +`, + expected: smpReplace, + elided: `- one +- two +- three +`, + }, + "list delete": { + patch: ` +- one +- two +- three +- $patch: delete +`, + expected: smpDelete, + elided: `- one +- two +- three +`, + }, + "list default": { + patch: ` +- one +- two +- three `, expected: smpMerge, elided: `- one