mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-11 17:12:51 +00:00
Merge pull request #1288 from monopole/inlineJson
Push json transform code down to plugin.
This commit is contained in:
1
go.sum
1
go.sum
@@ -121,6 +121,7 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 h1:QjA/9ArTfVTLfEhClDCG7SGrZkZixxWpwNCDiwJfh88=
|
||||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ func (th *KustTestHarness) LoadAndRunGenerator(
|
|||||||
|
|
||||||
func (th *KustTestHarness) LoadAndRunTransformer(
|
func (th *KustTestHarness) LoadAndRunTransformer(
|
||||||
config, input string) resmap.ResMap {
|
config, input string) resmap.ResMap {
|
||||||
resMap, err := th.runTransformer(config, input)
|
resMap, err := th.RunTransformer(config, input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
th.t.Fatalf("Err: %v", err)
|
th.t.Fatalf("Err: %v", err)
|
||||||
}
|
}
|
||||||
@@ -133,11 +133,11 @@ func (th *KustTestHarness) LoadAndRunTransformer(
|
|||||||
|
|
||||||
func (th *KustTestHarness) ErrorFromLoadAndRunTransformer(
|
func (th *KustTestHarness) ErrorFromLoadAndRunTransformer(
|
||||||
config, input string) error {
|
config, input string) error {
|
||||||
_, err := th.runTransformer(config, input)
|
_, err := th.RunTransformer(config, input)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (th *KustTestHarness) runTransformer(
|
func (th *KustTestHarness) RunTransformer(
|
||||||
config, input string) (resmap.ResMap, error) {
|
config, input string) (resmap.ResMap, error) {
|
||||||
transConfig, err := th.rf.RF().FromBytes([]byte(config))
|
transConfig, err := th.rf.RF().FromBytes([]byte(config))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -149,7 +149,7 @@ func (th *KustTestHarness) runTransformer(
|
|||||||
}
|
}
|
||||||
g, err := th.pl.LoadTransformer(th.ldr, transConfig)
|
g, err := th.pl.LoadTransformer(th.ldr, transConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
th.t.Fatalf("Err: %v", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
err = g.Transform(resMap)
|
err = g.Transform(resMap)
|
||||||
return resMap, err
|
return resMap, err
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package transformer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/gvk"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resid"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/transformers"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PatchJson6902Factory makes PatchJson6902 transformers
|
|
||||||
type PatchJson6902Factory struct {
|
|
||||||
loader ifc.Loader
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPatchJson6902Factory returns a new PatchJson6902Factory.
|
|
||||||
func NewPatchJson6902Factory(l ifc.Loader) PatchJson6902Factory {
|
|
||||||
return PatchJson6902Factory{loader: l}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakePatchJson6902Transformer returns a transformer for applying PatchJson6902 patch
|
|
||||||
func (f PatchJson6902Factory) MakePatchJson6902Transformer(patches []types.PatchJson6902) (transformers.Transformer, error) {
|
|
||||||
var ts []transformers.Transformer
|
|
||||||
for _, p := range patches {
|
|
||||||
t, err := f.makeOnePatchJson6902Transformer(p)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if t != nil {
|
|
||||||
ts = append(ts, t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return transformers.NewMultiTransformerWithConflictCheck(ts), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f PatchJson6902Factory) makeOnePatchJson6902Transformer(p types.PatchJson6902) (transformers.Transformer, error) {
|
|
||||||
if p.Target == nil {
|
|
||||||
return nil, fmt.Errorf("must specify the target field in patchesJson6902")
|
|
||||||
}
|
|
||||||
if p.Path == "" {
|
|
||||||
return nil, fmt.Errorf("must specify the path for a json patch file")
|
|
||||||
}
|
|
||||||
|
|
||||||
targetId := resid.NewResIdWithNamespace(
|
|
||||||
gvk.Gvk{
|
|
||||||
Group: p.Target.Group,
|
|
||||||
Version: p.Target.Version,
|
|
||||||
Kind: p.Target.Kind,
|
|
||||||
},
|
|
||||||
p.Target.Name,
|
|
||||||
p.Target.Namespace,
|
|
||||||
)
|
|
||||||
|
|
||||||
rawOp, err := f.loader.Load(p.Path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return newPatchJson6902JSONTransformer(targetId, rawOp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isJsonFormat(data []byte) bool {
|
|
||||||
return data[0] == '['
|
|
||||||
}
|
|
||||||
@@ -1,326 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package transformer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
"sigs.k8s.io/kustomize/v3/internal/loadertest"
|
|
||||||
"sigs.k8s.io/kustomize/v3/k8sdeps/kunstruct"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resmaptest"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
var rf = resource.NewFactory(
|
|
||||||
kunstruct.NewKunstructuredFactoryImpl())
|
|
||||||
|
|
||||||
func TestNewPatchJson6902FactoryNoTarget(t *testing.T) {
|
|
||||||
p := types.PatchJson6902{}
|
|
||||||
_, err := NewPatchJson6902Factory(nil).makeOnePatchJson6902Transformer(p)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("expected error")
|
|
||||||
}
|
|
||||||
if !strings.Contains(err.Error(), "must specify the target field in patchesJson6902") {
|
|
||||||
t.Fatalf("incorrect error returned: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewPatchJson6902FactoryConflict(t *testing.T) {
|
|
||||||
jsonPatch := []byte(`
|
|
||||||
target:
|
|
||||||
name: some-name
|
|
||||||
kind: Deployment
|
|
||||||
`)
|
|
||||||
p := types.PatchJson6902{}
|
|
||||||
err := yaml.Unmarshal(jsonPatch, &p)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("expected error %v", err)
|
|
||||||
}
|
|
||||||
f := NewPatchJson6902Factory(nil)
|
|
||||||
_, err = f.makeOnePatchJson6902Transformer(p)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("expected error")
|
|
||||||
}
|
|
||||||
if !strings.Contains(err.Error(), "must specify the path for a json patch file") {
|
|
||||||
t.Fatalf("incorrect error returned %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewPatchJson6902FactoryJSON(t *testing.T) {
|
|
||||||
ldr := loadertest.NewFakeLoader("/testpath")
|
|
||||||
operations := []byte(`[
|
|
||||||
{"op": "replace", "path": "/spec/template/spec/containers/0/name", "value": "my-nginx"},
|
|
||||||
{"op": "add", "path": "/spec/replica", "value": "3"},
|
|
||||||
{"op": "add", "path": "/spec/template/spec/containers/0/command", "value": ["arg1", "arg2", "arg3"]}
|
|
||||||
]`)
|
|
||||||
err := ldr.AddFile("/testpath/patch.json", operations)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to setup fake ldr.")
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonPatch := []byte(`
|
|
||||||
target:
|
|
||||||
kind: Deployment
|
|
||||||
name: some-name
|
|
||||||
path: patch.json
|
|
||||||
`)
|
|
||||||
p := types.PatchJson6902{}
|
|
||||||
err = yaml.Unmarshal(jsonPatch, &p)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("expected error")
|
|
||||||
}
|
|
||||||
|
|
||||||
tr, err := NewPatchJson6902Factory(ldr).makeOnePatchJson6902Transformer(p)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error : %v", err)
|
|
||||||
}
|
|
||||||
if tr == nil {
|
|
||||||
t.Fatal("the returned transformer should not be nil")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewPatchJson6902FactoryYAML(t *testing.T) {
|
|
||||||
ldr := loadertest.NewFakeLoader("/testpath")
|
|
||||||
operations := []byte(`
|
|
||||||
- op: replace
|
|
||||||
path: /spec/template/spec/containers/0/name
|
|
||||||
value: my-nginx
|
|
||||||
- op: add
|
|
||||||
path: /spec/replica
|
|
||||||
value: 3
|
|
||||||
- op: add
|
|
||||||
path: /spec/template/spec/containers/0/command
|
|
||||||
value: ["arg1", "arg2", "arg3"]
|
|
||||||
`)
|
|
||||||
err := ldr.AddFile("/testpath/patch.yaml", operations)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to setup fake ldr.")
|
|
||||||
}
|
|
||||||
jsonPatch := []byte(`
|
|
||||||
target:
|
|
||||||
name: some-name
|
|
||||||
kind: Deployment
|
|
||||||
path: patch.yaml
|
|
||||||
`)
|
|
||||||
p := types.PatchJson6902{}
|
|
||||||
err = yaml.Unmarshal(jsonPatch, &p)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error : %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tr, err := NewPatchJson6902Factory(ldr).makeOnePatchJson6902Transformer(p)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error : %v", err)
|
|
||||||
}
|
|
||||||
if tr == nil {
|
|
||||||
t.Fatal("the returned transformer should not be nil")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewPatchJson6902FactoryMulti(t *testing.T) {
|
|
||||||
ldr := loadertest.NewFakeLoader("/testpath")
|
|
||||||
operations := []byte(`[
|
|
||||||
{"op": "replace", "path": "/spec/template/spec/containers/0/name", "value": "my-nginx"},
|
|
||||||
{"op": "add", "path": "/spec/replica", "value": "3"}
|
|
||||||
]`)
|
|
||||||
err := ldr.AddFile("/testpath/patch.json", operations)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to setup fake ldr.")
|
|
||||||
}
|
|
||||||
|
|
||||||
operations = []byte(`
|
|
||||||
- op: add
|
|
||||||
path: /spec/template/spec/containers/0/command
|
|
||||||
value: ["arg1", "arg2", "arg3"]
|
|
||||||
`)
|
|
||||||
err = ldr.AddFile("/testpath/patch.yaml", operations)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to setup fake ldr.")
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonPatches := []byte(`
|
|
||||||
- target:
|
|
||||||
kind: foo
|
|
||||||
name: some-name
|
|
||||||
path: patch.json
|
|
||||||
|
|
||||||
- target:
|
|
||||||
kind: foo
|
|
||||||
name: some-name
|
|
||||||
path: patch.yaml
|
|
||||||
`)
|
|
||||||
var p []types.PatchJson6902
|
|
||||||
err = yaml.Unmarshal(jsonPatches, &p)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error : %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
f := NewPatchJson6902Factory(ldr)
|
|
||||||
tr, err := f.MakePatchJson6902Transformer(p)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error : %v", err)
|
|
||||||
}
|
|
||||||
if tr == nil {
|
|
||||||
t.Fatal("the returned transformer should not be nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
base := resmaptest_test.NewRmBuilder(t, rf).
|
|
||||||
Add(map[string]interface{}{
|
|
||||||
"kind": "foo",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "some-name",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"template": map[string]interface{}{
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"labels": map[string]interface{}{
|
|
||||||
"old-label": "old-value",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"image": "nginx",
|
|
||||||
"name": "nginx",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).ResMap()
|
|
||||||
expected := resmaptest_test.NewRmBuilder(t, rf).
|
|
||||||
Add(map[string]interface{}{
|
|
||||||
"kind": "foo",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "some-name",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"replica": "3",
|
|
||||||
"template": map[string]interface{}{
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"labels": map[string]interface{}{
|
|
||||||
"old-label": "old-value",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"image": "nginx",
|
|
||||||
"name": "my-nginx",
|
|
||||||
"command": []interface{}{
|
|
||||||
"arg1",
|
|
||||||
"arg2",
|
|
||||||
"arg3",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).ResMap()
|
|
||||||
err = tr.Transform(base)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error : %v", err)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(base, expected) {
|
|
||||||
err = expected.ErrorIfNotEqualSets(base)
|
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewPatchJson6902FactoryMultiConflict(t *testing.T) {
|
|
||||||
ldr := loadertest.NewFakeLoader("/testpath")
|
|
||||||
operations := []byte(`[
|
|
||||||
{"op": "add", "path": "/spec/replica", "value": "3"}
|
|
||||||
]`)
|
|
||||||
err := ldr.AddFile("/testpath/patch.json", operations)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to setup fake ldr.")
|
|
||||||
}
|
|
||||||
operations = []byte(`
|
|
||||||
- op: add
|
|
||||||
path: /spec/replica
|
|
||||||
value: 4
|
|
||||||
`)
|
|
||||||
err = ldr.AddFile("/testpath/patch.yaml", operations)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to setup fake ldr.")
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonPatches := []byte(`
|
|
||||||
- target:
|
|
||||||
kind: foo
|
|
||||||
name: somename
|
|
||||||
path: patch.json
|
|
||||||
|
|
||||||
- target:
|
|
||||||
kind: foo
|
|
||||||
name: somename
|
|
||||||
path: patch.yaml
|
|
||||||
`)
|
|
||||||
var p []types.PatchJson6902
|
|
||||||
err = yaml.Unmarshal(jsonPatches, &p)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error : %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
f := NewPatchJson6902Factory(ldr)
|
|
||||||
tr, err := f.MakePatchJson6902Transformer(p)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error : %v", err)
|
|
||||||
}
|
|
||||||
if tr == nil {
|
|
||||||
t.Fatal("the returned transformer should not be nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
m := resmaptest_test.NewRmBuilder(t, rf).
|
|
||||||
Add(map[string]interface{}{
|
|
||||||
"kind": "foo",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "somename",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"template": map[string]interface{}{
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"labels": map[string]interface{}{
|
|
||||||
"old-label": "old-value",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"image": "nginx",
|
|
||||||
"name": "nginx",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).ResMap()
|
|
||||||
|
|
||||||
err = tr.Transform(m)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("expected conflict")
|
|
||||||
}
|
|
||||||
if !strings.Contains(err.Error(), "found conflict between different patches") {
|
|
||||||
t.Fatalf("incorrect error happened %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package transformer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
jsonpatch "github.com/evanphx/json-patch"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resid"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/transformers"
|
|
||||||
"sigs.k8s.io/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
// patchJson6902JSONTransformer applies patches.
|
|
||||||
type patchJson6902JSONTransformer struct {
|
|
||||||
target resid.ResId
|
|
||||||
patch jsonpatch.Patch
|
|
||||||
rawOp []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ transformers.Transformer = &patchJson6902JSONTransformer{}
|
|
||||||
|
|
||||||
// newPatchJson6902JSONTransformer constructs a PatchJson6902 transformer.
|
|
||||||
func newPatchJson6902JSONTransformer(
|
|
||||||
id resid.ResId, rawOp []byte) (transformers.Transformer, error) {
|
|
||||||
op := rawOp
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if len(op) == 0 {
|
|
||||||
return nil, fmt.Errorf("json patch file is empty %v", id)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isJsonFormat(op) {
|
|
||||||
// if it isn't JSON, try to parse it as YAML
|
|
||||||
op, err = yaml.YAMLToJSON(rawOp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
decodedPatch, err := jsonpatch.DecodePatch(op)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(decodedPatch) == 0 {
|
|
||||||
return transformers.NewNoOpTransformer(), nil
|
|
||||||
}
|
|
||||||
return &patchJson6902JSONTransformer{target: id, patch: decodedPatch, rawOp: rawOp}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transform apply the json patches on top of the base resources.
|
|
||||||
func (t *patchJson6902JSONTransformer) Transform(m resmap.ResMap) error {
|
|
||||||
obj, err := m.GetById(t.target)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rawObj, err := obj.MarshalJSON()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
modifiedObj, err := t.patch.Apply(rawObj)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to apply json patch '%s'", string(t.rawOp))
|
|
||||||
}
|
|
||||||
err = obj.UnmarshalJSON(modifiedObj)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package transformer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/k8sdeps/kunstruct"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/gvk"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resid"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resmaptest"
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
|
||||||
)
|
|
||||||
|
|
||||||
var deploy = gvk.Gvk{Group: "apps", Version: "v1", Kind: "Deployment"}
|
|
||||||
|
|
||||||
func TestJsonPatchJSONTransformer_Transform(t *testing.T) {
|
|
||||||
rf := resource.NewFactory(
|
|
||||||
kunstruct.NewKunstructuredFactoryImpl())
|
|
||||||
m := resmaptest_test.NewRmBuilder(t, rf).
|
|
||||||
Add(map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "deploy1",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"template": map[string]interface{}{
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"labels": map[string]interface{}{
|
|
||||||
"old-label": "old-value",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "nginx",
|
|
||||||
"image": "nginx",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).ResMap()
|
|
||||||
|
|
||||||
operations := []byte(`[
|
|
||||||
{"op": "replace", "path": "/spec/template/spec/containers/0/name", "value": "my-nginx"},
|
|
||||||
{"op": "add", "path": "/spec/replica", "value": "3"},
|
|
||||||
{"op": "add", "path": "/spec/template/spec/containers/0/command", "value": ["arg1", "arg2", "arg3"]}
|
|
||||||
]`)
|
|
||||||
|
|
||||||
expected := resmaptest_test.NewRmBuilder(t, rf).
|
|
||||||
Add(map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "deploy1",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"replica": "3",
|
|
||||||
"template": map[string]interface{}{
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"labels": map[string]interface{}{
|
|
||||||
"old-label": "old-value",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"image": "nginx",
|
|
||||||
"name": "my-nginx",
|
|
||||||
"command": []interface{}{
|
|
||||||
"arg1",
|
|
||||||
"arg2",
|
|
||||||
"arg3",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).ResMap()
|
|
||||||
|
|
||||||
patchId := m.GetByIndex(0).OrgId()
|
|
||||||
|
|
||||||
jpt, err := newPatchJson6902JSONTransformer(patchId, operations)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error : %v", err)
|
|
||||||
}
|
|
||||||
err = jpt.Transform(m)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(m, expected) {
|
|
||||||
err = expected.ErrorIfNotEqualSets(m)
|
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestJsonPatchJSONTransformer_UnHappyTransform(t *testing.T) {
|
|
||||||
rf := resource.NewFactory(
|
|
||||||
kunstruct.NewKunstructuredFactoryImpl())
|
|
||||||
m := resmaptest_test.NewRmBuilder(t, rf).
|
|
||||||
Add(map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "deploy1",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"template": map[string]interface{}{
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"labels": map[string]interface{}{
|
|
||||||
"old-label": "old-value",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"name": "nginx",
|
|
||||||
"image": "nginx",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).ResMap()
|
|
||||||
|
|
||||||
operations := []byte(`[
|
|
||||||
{"op": "add", "path": "/spec/template/spec/containers/0/command/", "value": ["arg1", "arg2", "arg3"]}
|
|
||||||
]`)
|
|
||||||
|
|
||||||
jpt, err := newPatchJson6902JSONTransformer(
|
|
||||||
m.GetByIndex(0).OrgId(), operations)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error : %v", err)
|
|
||||||
}
|
|
||||||
err = jpt.Transform(m)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("expected error didn't happen")
|
|
||||||
}
|
|
||||||
if !strings.HasPrefix(
|
|
||||||
err.Error(), "failed to apply json patch") ||
|
|
||||||
!strings.Contains(err.Error(), string(operations)) {
|
|
||||||
t.Fatalf("expected error didn't happen, but got %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestJsonPatchJSONTransformer_EmptyPatchFile(t *testing.T) {
|
|
||||||
id := resid.NewResId(deploy, "deploy1")
|
|
||||||
operations := []byte(``)
|
|
||||||
|
|
||||||
_, err := newPatchJson6902JSONTransformer(id, operations)
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("expected an error")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if !strings.HasPrefix(err.Error(), "json patch file is empty") {
|
|
||||||
t.Fatalf("expected %s, but got %v", "json patch file is empty", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -147,15 +147,21 @@ func (kt *KustTarget) configureBuiltinPatchJson6902Transformer(
|
|||||||
tConfig *config.TransformerConfig) (
|
tConfig *config.TransformerConfig) (
|
||||||
result []transformers.Transformer, err error) {
|
result []transformers.Transformer, err error) {
|
||||||
var c struct {
|
var c struct {
|
||||||
Patches []types.PatchJson6902
|
Target types.PatchTarget `json:"target,omitempty" yaml:"target,omitempty"`
|
||||||
|
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||||
|
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
|
||||||
}
|
}
|
||||||
c.Patches = kt.kustomization.PatchesJson6902
|
for _, args := range kt.kustomization.PatchesJson6902 {
|
||||||
p := builtin.NewPatchJson6902TransformerPlugin()
|
c.Target = *args.Target
|
||||||
err = kt.configureBuiltinPlugin(p, c, "patchJson6902")
|
c.Path = args.Path
|
||||||
if err != nil {
|
c.JsonOp = "" // Not implemented for kustomization file yet.
|
||||||
return nil, err
|
p := builtin.NewPatchJson6902TransformerPlugin()
|
||||||
|
err = kt.configureBuiltinPlugin(p, c, "patchJson6902")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result = append(result, p)
|
||||||
}
|
}
|
||||||
result = append(result, p)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,16 +2,23 @@
|
|||||||
package builtin
|
package builtin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
jsonpatch "github.com/evanphx/json-patch"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/gvk"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/patch/transformer"
|
"sigs.k8s.io/kustomize/v3/pkg/resid"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/types"
|
"sigs.k8s.io/kustomize/v3/pkg/types"
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PatchJson6902TransformerPlugin struct {
|
type PatchJson6902TransformerPlugin struct {
|
||||||
ldr ifc.Loader
|
ldr ifc.Loader
|
||||||
Patches []types.PatchJson6902 `json:"patches,omitempty" yaml:"patches,omitempty"`
|
decodedPatch jsonpatch.Patch
|
||||||
|
Target types.PatchTarget `json:"target,omitempty" yaml:"target,omitempty"`
|
||||||
|
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||||
|
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//noinspection GoUnusedGlobalVariable
|
//noinspection GoUnusedGlobalVariable
|
||||||
@@ -22,15 +29,71 @@ func NewPatchJson6902TransformerPlugin() *PatchJson6902TransformerPlugin {
|
|||||||
func (p *PatchJson6902TransformerPlugin) Config(
|
func (p *PatchJson6902TransformerPlugin) Config(
|
||||||
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||||
p.ldr = ldr
|
p.ldr = ldr
|
||||||
p.Patches = nil
|
err = yaml.Unmarshal(c, p)
|
||||||
return yaml.Unmarshal(c, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PatchJson6902TransformerPlugin) Transform(m resmap.ResMap) error {
|
|
||||||
t, err := transformer.NewPatchJson6902Factory(p.ldr).
|
|
||||||
MakePatchJson6902Transformer(p.Patches)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return t.Transform(m)
|
if p.Target.Name == "" {
|
||||||
|
return fmt.Errorf("must specify the target name")
|
||||||
|
}
|
||||||
|
if p.Path == "" && p.JsonOp == "" {
|
||||||
|
return fmt.Errorf("empty file path and empty jsonOp")
|
||||||
|
}
|
||||||
|
if p.Path != "" {
|
||||||
|
if p.JsonOp != "" {
|
||||||
|
return fmt.Errorf("must specify a file path or jsonOp, not both")
|
||||||
|
}
|
||||||
|
rawOp, err := p.ldr.Load(p.Path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.JsonOp = string(rawOp)
|
||||||
|
if p.JsonOp == "" {
|
||||||
|
return fmt.Errorf("patch file '%s' empty seems to be empty", p.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.JsonOp[0] != '[' {
|
||||||
|
// if it doesn't seem to be JSON, imagine
|
||||||
|
// it is YAML, and convert to JSON.
|
||||||
|
op, err := yaml.YAMLToJSON([]byte(p.JsonOp))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.JsonOp = string(op)
|
||||||
|
}
|
||||||
|
p.decodedPatch, err = jsonpatch.DecodePatch([]byte(p.JsonOp))
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "decoding %s", p.JsonOp)
|
||||||
|
}
|
||||||
|
if len(p.decodedPatch) == 0 {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"patch appears to be empty; file=%s, JsonOp=%s", p.Path, p.JsonOp)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PatchJson6902TransformerPlugin) Transform(m resmap.ResMap) error {
|
||||||
|
id := resid.NewResIdWithNamespace(
|
||||||
|
gvk.Gvk{
|
||||||
|
Group: p.Target.Group,
|
||||||
|
Version: p.Target.Version,
|
||||||
|
Kind: p.Target.Kind,
|
||||||
|
},
|
||||||
|
p.Target.Name,
|
||||||
|
p.Target.Namespace,
|
||||||
|
)
|
||||||
|
obj, err := m.GetById(id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rawObj, err := obj.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
modifiedObj, err := p.decodedPatch.Apply(rawObj)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(
|
||||||
|
err, "failed to apply json patch '%s'", p.JsonOp)
|
||||||
|
}
|
||||||
|
return obj.UnmarshalJSON(modifiedObj)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,12 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
jsonpatch "github.com/evanphx/json-patch"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"sigs.k8s.io/kustomize/v3/pkg/gvk"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
"sigs.k8s.io/kustomize/v3/pkg/ifc"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/patch/transformer"
|
"sigs.k8s.io/kustomize/v3/pkg/resid"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/types"
|
"sigs.k8s.io/kustomize/v3/pkg/types"
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
@@ -14,7 +18,10 @@ import (
|
|||||||
|
|
||||||
type plugin struct {
|
type plugin struct {
|
||||||
ldr ifc.Loader
|
ldr ifc.Loader
|
||||||
Patches []types.PatchJson6902 `json:"patches,omitempty" yaml:"patches,omitempty"`
|
decodedPatch jsonpatch.Patch
|
||||||
|
Target types.PatchTarget `json:"target,omitempty" yaml:"target,omitempty"`
|
||||||
|
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||||
|
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//noinspection GoUnusedGlobalVariable
|
//noinspection GoUnusedGlobalVariable
|
||||||
@@ -23,15 +30,71 @@ var KustomizePlugin plugin
|
|||||||
func (p *plugin) Config(
|
func (p *plugin) Config(
|
||||||
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
ldr ifc.Loader, rf *resmap.Factory, c []byte) (err error) {
|
||||||
p.ldr = ldr
|
p.ldr = ldr
|
||||||
p.Patches = nil
|
err = yaml.Unmarshal(c, p)
|
||||||
return yaml.Unmarshal(c, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *plugin) Transform(m resmap.ResMap) error {
|
|
||||||
t, err := transformer.NewPatchJson6902Factory(p.ldr).
|
|
||||||
MakePatchJson6902Transformer(p.Patches)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return t.Transform(m)
|
if p.Target.Name == "" {
|
||||||
|
return fmt.Errorf("must specify the target name")
|
||||||
|
}
|
||||||
|
if p.Path == "" && p.JsonOp == "" {
|
||||||
|
return fmt.Errorf("empty file path and empty jsonOp")
|
||||||
|
}
|
||||||
|
if p.Path != "" {
|
||||||
|
if p.JsonOp != "" {
|
||||||
|
return fmt.Errorf("must specify a file path or jsonOp, not both")
|
||||||
|
}
|
||||||
|
rawOp, err := p.ldr.Load(p.Path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.JsonOp = string(rawOp)
|
||||||
|
if p.JsonOp == "" {
|
||||||
|
return fmt.Errorf("patch file '%s' empty seems to be empty", p.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.JsonOp[0] != '[' {
|
||||||
|
// if it doesn't seem to be JSON, imagine
|
||||||
|
// it is YAML, and convert to JSON.
|
||||||
|
op, err := yaml.YAMLToJSON([]byte(p.JsonOp))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.JsonOp = string(op)
|
||||||
|
}
|
||||||
|
p.decodedPatch, err = jsonpatch.DecodePatch([]byte(p.JsonOp))
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "decoding %s", p.JsonOp)
|
||||||
|
}
|
||||||
|
if len(p.decodedPatch) == 0 {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"patch appears to be empty; file=%s, JsonOp=%s", p.Path, p.JsonOp)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *plugin) Transform(m resmap.ResMap) error {
|
||||||
|
id := resid.NewResIdWithNamespace(
|
||||||
|
gvk.Gvk{
|
||||||
|
Group: p.Target.Group,
|
||||||
|
Version: p.Target.Version,
|
||||||
|
Kind: p.Target.Kind,
|
||||||
|
},
|
||||||
|
p.Target.Name,
|
||||||
|
p.Target.Namespace,
|
||||||
|
)
|
||||||
|
obj, err := m.GetById(id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rawObj, err := obj.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
modifiedObj, err := p.decodedPatch.Apply(rawObj)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(
|
||||||
|
err, "failed to apply json patch '%s'", p.JsonOp)
|
||||||
|
}
|
||||||
|
return obj.UnmarshalJSON(modifiedObj)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,117 @@
|
|||||||
package main_test
|
package main_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
"sigs.k8s.io/kustomize/v3/pkg/kusttest"
|
||||||
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPatchJson6902Transformer(t *testing.T) {
|
const target = `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
kind: Deployment
|
||||||
|
spec:
|
||||||
|
replica: 2
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx
|
||||||
|
`
|
||||||
|
|
||||||
|
func TestPatchJson6902TransformerMissingFile(t *testing.T) {
|
||||||
|
tc := plugins.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "PatchJson6902Transformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
_, err := th.RunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: PatchJson6902Transformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
target:
|
||||||
|
group: apps
|
||||||
|
version: v1
|
||||||
|
kind: Deployment
|
||||||
|
name: myDeploy
|
||||||
|
path: jsonpatch.json
|
||||||
|
`, target)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "cannot read file \"/app/jsonpatch.json\"") {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBadPatchJson6902Transformer(t *testing.T) {
|
||||||
|
tc := plugins.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "PatchJson6902Transformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
_, err := th.RunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: PatchJson6902Transformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
target:
|
||||||
|
group: apps
|
||||||
|
version: v1
|
||||||
|
kind: Deployment
|
||||||
|
name: myDeploy
|
||||||
|
jsonOp: 'thisIsNotAPatch'
|
||||||
|
`, target)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "cannot unmarshal string into Go value of type jsonpatch") {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBothEmptyJson6902Transformer(t *testing.T) {
|
||||||
|
tc := plugins.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "PatchJson6902Transformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
_, err := th.RunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: PatchJson6902Transformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
target:
|
||||||
|
group: apps
|
||||||
|
version: v1
|
||||||
|
kind: Deployment
|
||||||
|
name: myDeploy
|
||||||
|
`, target)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "empty file path and empty jsonOp") {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBothSpecifiedJson6902Transformer(t *testing.T) {
|
||||||
tc := plugins.NewEnvForTest(t).Set()
|
tc := plugins.NewEnvForTest(t).Set()
|
||||||
defer tc.Reset()
|
defer tc.Reset()
|
||||||
|
|
||||||
@@ -20,7 +124,45 @@ func TestPatchJson6902Transformer(t *testing.T) {
|
|||||||
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
th.WriteF("/app/jsonpatch.json", `[
|
th.WriteF("/app/jsonpatch.json", `[
|
||||||
{"op": "add", "path": "/spec/replica", "value": "3"}
|
{"op": "replace", "path": "/spec/template/spec/containers/0/name", "value": "my-nginx"},
|
||||||
|
{"op": "add", "path": "/spec/replica", "value": "999"},
|
||||||
|
{"op": "add", "path": "/spec/template/spec/containers/0/command", "value": ["arg1", "arg2", "arg3"]}
|
||||||
|
]`)
|
||||||
|
|
||||||
|
_, err := th.RunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: PatchJson6902Transformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
target:
|
||||||
|
group: apps
|
||||||
|
version: v1
|
||||||
|
kind: Deployment
|
||||||
|
name: myDeploy
|
||||||
|
path: jsonpatch.json
|
||||||
|
jsonOp: '[{"op": "add", "path": "/spec/template/spec/dnsPolicy", "value": "ClusterFirst"}]'
|
||||||
|
`, target)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "must specify a file path or jsonOp, not both") {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPatchJson6902TransformerFromJsonFile(t *testing.T) {
|
||||||
|
tc := plugins.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "PatchJson6902Transformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
th.WriteF("/app/jsonpatch.json", `[
|
||||||
|
{"op": "replace", "path": "/spec/template/spec/containers/0/name", "value": "my-nginx"},
|
||||||
|
{"op": "add", "path": "/spec/replica", "value": "999"},
|
||||||
|
{"op": "add", "path": "/spec/template/spec/containers/0/command", "value": ["arg1", "arg2", "arg3"]}
|
||||||
]`)
|
]`)
|
||||||
|
|
||||||
rm := th.LoadAndRunTransformer(`
|
rm := th.LoadAndRunTransformer(`
|
||||||
@@ -28,21 +170,13 @@ apiVersion: builtin
|
|||||||
kind: PatchJson6902Transformer
|
kind: PatchJson6902Transformer
|
||||||
metadata:
|
metadata:
|
||||||
name: notImportantHere
|
name: notImportantHere
|
||||||
patches:
|
target:
|
||||||
- target:
|
group: apps
|
||||||
group: apps
|
version: v1
|
||||||
version: v1
|
kind: Deployment
|
||||||
kind: Deployment
|
|
||||||
name: myDeploy
|
|
||||||
path: jsonpatch.json
|
|
||||||
`, `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
metadata:
|
|
||||||
name: myDeploy
|
name: myDeploy
|
||||||
kind: Deployment
|
path: jsonpatch.json
|
||||||
spec:
|
`, target)
|
||||||
replica: 1
|
|
||||||
`)
|
|
||||||
|
|
||||||
th.AssertActualEqualsExpected(rm, `
|
th.AssertActualEqualsExpected(rm, `
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
@@ -50,6 +184,109 @@ kind: Deployment
|
|||||||
metadata:
|
metadata:
|
||||||
name: myDeploy
|
name: myDeploy
|
||||||
spec:
|
spec:
|
||||||
replica: "3"
|
replica: "999"
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- command:
|
||||||
|
- arg1
|
||||||
|
- arg2
|
||||||
|
- arg3
|
||||||
|
image: nginx
|
||||||
|
name: my-nginx
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPatchJson6902TransformerFromYamlFile(t *testing.T) {
|
||||||
|
tc := plugins.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "PatchJson6902Transformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
th.WriteF("/app/jsonpatch.json", `
|
||||||
|
- op: add
|
||||||
|
path: /spec/template/spec/containers/0/command
|
||||||
|
value: ["arg1", "arg2", "arg3"]
|
||||||
|
`)
|
||||||
|
|
||||||
|
rm := th.LoadAndRunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: PatchJson6902Transformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
target:
|
||||||
|
group: apps
|
||||||
|
version: v1
|
||||||
|
kind: Deployment
|
||||||
|
name: myDeploy
|
||||||
|
path: jsonpatch.json
|
||||||
|
`, target)
|
||||||
|
|
||||||
|
th.AssertActualEqualsExpected(rm, `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
replica: 2
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- command:
|
||||||
|
- arg1
|
||||||
|
- arg2
|
||||||
|
- arg3
|
||||||
|
image: nginx
|
||||||
|
name: nginx
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPatchJson6902TransformerWithInline(t *testing.T) {
|
||||||
|
tc := plugins.NewEnvForTest(t).Set()
|
||||||
|
defer tc.Reset()
|
||||||
|
|
||||||
|
tc.BuildGoPlugin(
|
||||||
|
"builtin", "", "PatchJson6902Transformer")
|
||||||
|
|
||||||
|
th := kusttest_test.NewKustTestPluginHarness(t, "/app")
|
||||||
|
|
||||||
|
rm := th.LoadAndRunTransformer(`
|
||||||
|
apiVersion: builtin
|
||||||
|
kind: PatchJson6902Transformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
target:
|
||||||
|
group: apps
|
||||||
|
version: v1
|
||||||
|
kind: Deployment
|
||||||
|
name: myDeploy
|
||||||
|
jsonOp: '[{"op": "add", "path": "/spec/template/spec/dnsPolicy", "value": "ClusterFirst"}]'
|
||||||
|
`, target)
|
||||||
|
|
||||||
|
th.AssertActualEqualsExpected(rm, `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: myDeploy
|
||||||
|
spec:
|
||||||
|
replica: 2
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
old-label: old-value
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx
|
||||||
|
dnsPolicy: ClusterFirst
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user