From cedf215445bb342b84aff945cebe0f066a9b435f Mon Sep 17 00:00:00 2001 From: Jingfang Liu Date: Fri, 31 Aug 2018 10:21:58 -0700 Subject: [PATCH] add PatchJson6902Factory to make transformer --- pkg/patch/transformer/factory.go | 83 ++++++++++ pkg/patch/transformer/factory_test.go | 156 ++++++++++++++++++ pkg/patch/transformer/patchjson6902.go | 48 ------ pkg/patch/transformer/patchjson6902_test.go | 1 - pkg/patch/transformer/patchjson6902json.go | 54 ++---- .../transformer/patchjson6902json_test.go | 22 ++- pkg/patch/transformer/patchjson6902yaml.go | 47 +----- .../transformer/patchjson6902yaml_test.go | 15 +- pkg/patch/transformer/util.go | 47 ++++++ 9 files changed, 320 insertions(+), 153 deletions(-) create mode 100644 pkg/patch/transformer/factory.go create mode 100644 pkg/patch/transformer/factory_test.go delete mode 100644 pkg/patch/transformer/patchjson6902.go delete mode 100644 pkg/patch/transformer/patchjson6902_test.go create mode 100644 pkg/patch/transformer/util.go diff --git a/pkg/patch/transformer/factory.go b/pkg/patch/transformer/factory.go new file mode 100644 index 0000000000..2b7da3b003 --- /dev/null +++ b/pkg/patch/transformer/factory.go @@ -0,0 +1,83 @@ +/* +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" + yamlpatch "github.com/krishicks/yaml-patch" + "k8s.io/apimachinery/pkg/runtime/schema" + + "github.com/kubernetes-sigs/kustomize/pkg/loader" + "github.com/kubernetes-sigs/kustomize/pkg/patch" + "github.com/kubernetes-sigs/kustomize/pkg/resource" + "github.com/kubernetes-sigs/kustomize/pkg/transformers" +) + +// PatchJson6902Factory makes PatchJson6902 transformers. +type PatchJson6902Factory struct { + targetId resource.ResId + operationsYAML yamlpatch.Patch + operationsJSON jsonpatch.Patch +} + +// NewPatchJson6902Factory returns a new PatchJson6902Factory. +func NewPatchJson6902Factory(l loader.Loader, p patch.PatchJson6902) (*PatchJson6902Factory, error) { + + if p.Target == nil { + return nil, fmt.Errorf("must specify the target field in patchesJson6902") + } + if p.Path != "" && p.JsonPatch != nil { + return nil, fmt.Errorf("cannot specify path and jsonPath at the same time") + } + + targetId := resource.NewResIdWithPrefixNamespace( + schema.GroupVersionKind{ + Group: p.Target.Group, + Version: p.Target.Version, + Kind: p.Target.Kind, + }, + p.Target.Name, + "", + p.Target.Namespace, + ) + + if p.JsonPatch != nil { + return &PatchJson6902Factory{targetId: targetId, operationsYAML: p.JsonPatch}, nil + } + if p.Path != "" { + rawOp, err := l.Load(p.Path) + if err != nil { + return nil, err + } + patch, err := jsonpatch.DecodePatch(rawOp) + if err != nil { + return nil, err + } + return &PatchJson6902Factory{targetId: targetId, operationsJSON: patch}, nil + } + return nil, nil +} + +// MakePatchJson6902Transformer returns a transformer for applying Json6902 patch +func (f *PatchJson6902Factory) MakePatchJson6902Transformer() (transformers.Transformer, error) { + if f.operationsJSON != nil { + return newPatchJson6902JSONTransformer(f.targetId, f.operationsJSON) + } + return newPatchJson6902YAMLTransformer(f.targetId, f.operationsYAML) +} diff --git a/pkg/patch/transformer/factory_test.go b/pkg/patch/transformer/factory_test.go new file mode 100644 index 0000000000..bf87bdca11 --- /dev/null +++ b/pkg/patch/transformer/factory_test.go @@ -0,0 +1,156 @@ +/* +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 ( + "strings" + "testing" + + yaml "gopkg.in/yaml.v2" + + "github.com/kubernetes-sigs/kustomize/pkg/internal/loadertest" + "github.com/kubernetes-sigs/kustomize/pkg/patch" +) + +func TestNewPatchJson6902FactoryNull(t *testing.T) { + p := patch.PatchJson6902{ + Target: &patch.Target{ + Name: "some-name", + }, + } + f, err := NewPatchJson6902Factory(nil, p) + if err != nil { + t.Fatalf("unexpected error : %v", err) + } + if f != nil { + t.Fatal("a nil should be returned") + } +} + +func TestNewPatchJson6902FactoryNoTarget(t *testing.T) { + p := patch.PatchJson6902{} + _, err := NewPatchJson6902Factory(nil, 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 +jsonPatch: + - op: replace + path: /spec/template/spec/containers/0/name + value: my-nginx + - op: add + path: /spec/template/spec/containers/0/command + value: [arg1,arg2,arg3] +path: /some/dir/some/file +`) + p := patch.PatchJson6902{} + err := yaml.Unmarshal(jsonPatch, &p) + if err != nil { + t.Fatalf("expected error %v", err) + } + _, err = NewPatchJson6902Factory(nil, p) + if err == nil { + t.Fatal("expected error") + } + if !strings.Contains(err.Error(), "cannot specify path and jsonPath at the same time") { + 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: /testpath/patch.json +`) + p := patch.PatchJson6902{} + err = yaml.Unmarshal(jsonPatch, &p) + if err != nil { + t.Fatal("expected error") + } + + f, err := NewPatchJson6902Factory(ldr, p) + if err != nil { + t.Fatalf("unexpected error : %v", err) + } + if f == nil { + t.Fatalf("the returned factory shouldn't be nil ") + } + + _, err = f.MakePatchJson6902Transformer() + if err != nil { + t.Fatalf("unexpected error : %v", err) + } +} + +func TestNewPatchJson6902FactoryYAML(t *testing.T) { + jsonPatch := []byte(` +target: + name: some-name + kind: Deployment +jsonPatch: +- 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"] +`) + p := patch.PatchJson6902{} + err := yaml.Unmarshal(jsonPatch, &p) + if err != nil { + t.Fatalf("unexpected error : %v", err) + } + + f, err := NewPatchJson6902Factory(nil, p) + if err != nil { + t.Fatalf("unexpected error : %v", err) + } + if f == nil { + t.Fatalf("the returned factory shouldn't be nil ") + } + + _, err = f.MakePatchJson6902Transformer() + if err != nil { + t.Fatalf("unexpected error : %v", err) + } + +} diff --git a/pkg/patch/transformer/patchjson6902.go b/pkg/patch/transformer/patchjson6902.go deleted file mode 100644 index 96a026bafd..0000000000 --- a/pkg/patch/transformer/patchjson6902.go +++ /dev/null @@ -1,48 +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" - - "github.com/kubernetes-sigs/kustomize/pkg/loader" - "github.com/kubernetes-sigs/kustomize/pkg/patch" - "github.com/kubernetes-sigs/kustomize/pkg/transformers" -) - -// NewPatchJson6902Transformer constructs a PatchJson6902 transformer. -func NewPatchJson6902Transformer(l loader.Loader, p patch.PatchJson6902) (transformers.Transformer, error) { - if p.Target == nil { - return nil, fmt.Errorf("must specify the target field in patchesJson6902") - } - if p.Path != "" && p.JsonPatch != nil { - return nil, fmt.Errorf("cannot specify path and jsonPath at the same time") - } - - if p.JsonPatch != nil { - return NewPatchJson6902YAMLTransformer(p.Target, p.JsonPatch) - } - if p.Path != "" { - operations, err := l.Load(p.Path) - if err != nil { - return nil, err - } - return NewPatchJson6902JSONTransformer(p.Target, operations) - } - - return transformers.NewNoOpTransformer(), nil -} diff --git a/pkg/patch/transformer/patchjson6902_test.go b/pkg/patch/transformer/patchjson6902_test.go deleted file mode 100644 index 38ef5e169c..0000000000 --- a/pkg/patch/transformer/patchjson6902_test.go +++ /dev/null @@ -1 +0,0 @@ -package transformer diff --git a/pkg/patch/transformer/patchjson6902json.go b/pkg/patch/transformer/patchjson6902json.go index 1547c91d5d..c8844bc883 100644 --- a/pkg/patch/transformer/patchjson6902json.go +++ b/pkg/patch/transformer/patchjson6902json.go @@ -17,13 +17,8 @@ limitations under the License. package transformer import ( - "fmt" - "log" - jsonpatch "github.com/evanphx/json-patch" - "k8s.io/apimachinery/pkg/runtime/schema" - "github.com/kubernetes-sigs/kustomize/pkg/patch" "github.com/kubernetes-sigs/kustomize/pkg/resmap" "github.com/kubernetes-sigs/kustomize/pkg/resource" "github.com/kubernetes-sigs/kustomize/pkg/transformers" @@ -31,58 +26,31 @@ import ( // patchJson6902Transformer applies patches. type patchJson6902JSONTransformer struct { - target *patch.Target - operations []byte + target resource.ResId + patch jsonpatch.Patch } var _ transformers.Transformer = &patchJson6902JSONTransformer{} -// NewPatchJson6902JSONTransformer constructs a PatchJson6902 transformer. -func NewPatchJson6902JSONTransformer(t *patch.Target, o []byte) (transformers.Transformer, error) { - return &patchJson6902JSONTransformer{target: t, operations: o}, nil +// newPatchJson6902JSONTransformer constructs a PatchJson6902 transformer. +func newPatchJson6902JSONTransformer(t resource.ResId, p jsonpatch.Patch) (transformers.Transformer, error) { + if len(p) == 0 { + return transformers.NewNoOpTransformer(), nil + } + return &patchJson6902JSONTransformer{target: t, patch: p}, nil } // Transform apply the json patches on top of the base resources. func (t *patchJson6902JSONTransformer) Transform(baseResourceMap resmap.ResMap) error { - targetId := resource.NewResIdWithPrefixNamespace( - schema.GroupVersionKind{ - Group: t.target.Group, - Version: t.target.Version, - Kind: t.target.Kind, - }, - t.target.Name, - "", - t.target.Namespace, - ) - - matchedIds := baseResourceMap.FindByGVKN(targetId) - if targetId.Namespace() != "" { - ids := []resource.ResId{} - for _, id := range matchedIds { - if id.Namespace() == targetId.Namespace() { - ids = append(ids, id) - } - } - matchedIds = ids - } - if len(matchedIds) == 0 { - log.Printf("Couldn't find any object to apply the json patch %v, skipping it.", targetId) - return nil - } - if len(matchedIds) > 1 { - return fmt.Errorf("found multiple objects that the patch can apply %v", matchedIds) - } - - decodedPatch, err := jsonpatch.DecodePatch(t.operations) - if err != nil { + obj, err := findTargetObj(baseResourceMap, t.target) + if obj == nil { return err } - obj := baseResourceMap[matchedIds[0]] rawObj, err := obj.Unstructured.MarshalJSON() if err != nil { return err } - modifiedObj, err := decodedPatch.Apply(rawObj) + modifiedObj, err := t.patch.Apply(rawObj) if err != nil { return err } diff --git a/pkg/patch/transformer/patchjson6902json_test.go b/pkg/patch/transformer/patchjson6902json_test.go index d6b00260bf..5392095e55 100644 --- a/pkg/patch/transformer/patchjson6902json_test.go +++ b/pkg/patch/transformer/patchjson6902json_test.go @@ -20,14 +20,16 @@ import ( "reflect" "testing" - "github.com/kubernetes-sigs/kustomize/pkg/patch" + jsonpatch "github.com/evanphx/json-patch" + "github.com/kubernetes-sigs/kustomize/pkg/resmap" "github.com/kubernetes-sigs/kustomize/pkg/resource" ) func TestJsonPatchJSONTransformer_Transform(t *testing.T) { + id := resource.NewResId(deploy, "deploy1") base := resmap.ResMap{ - resource.NewResId(deploy, "deploy1"): resource.NewResourceFromMap( + id: resource.NewResourceFromMap( map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", @@ -54,21 +56,17 @@ func TestJsonPatchJSONTransformer_Transform(t *testing.T) { }), } - target := patch.Target{ - Group: "apps", - Version: "v1", - Kind: "Deployment", - Name: "deploy1", - } - 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"]} ]`) - + patch, err := jsonpatch.DecodePatch(operations) + if err != nil { + t.Fatalf("unexpected error : %v", err) + } expected := resmap.ResMap{ - resource.NewResId(deploy, "deploy1"): resource.NewResourceFromMap( + id: resource.NewResourceFromMap( map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", @@ -100,7 +98,7 @@ func TestJsonPatchJSONTransformer_Transform(t *testing.T) { }, }), } - jpt, err := NewPatchJson6902JSONTransformer(&target, operations) + jpt, err := newPatchJson6902JSONTransformer(id, patch) if err != nil { t.Fatalf("unexpected error : %v", err) } diff --git a/pkg/patch/transformer/patchjson6902yaml.go b/pkg/patch/transformer/patchjson6902yaml.go index 3bc1ccdb20..70542c3876 100644 --- a/pkg/patch/transformer/patchjson6902yaml.go +++ b/pkg/patch/transformer/patchjson6902yaml.go @@ -17,15 +17,9 @@ limitations under the License. package transformer import ( - "fmt" - "log" - "github.com/ghodss/yaml" yamlpatch "github.com/krishicks/yaml-patch" - "k8s.io/apimachinery/pkg/runtime/schema" - - "github.com/kubernetes-sigs/kustomize/pkg/patch" "github.com/kubernetes-sigs/kustomize/pkg/resmap" "github.com/kubernetes-sigs/kustomize/pkg/resource" "github.com/kubernetes-sigs/kustomize/pkg/transformers" @@ -33,49 +27,26 @@ import ( // patchJson6902Transformer applies patches. type patchJson6902YAMLTransformer struct { - target *patch.Target + target resource.ResId patch yamlpatch.Patch } var _ transformers.Transformer = &patchJson6902YAMLTransformer{} -// NewPatchJson6902YAMLTransformer constructs a PatchJson6902 transformer. -func NewPatchJson6902YAMLTransformer(t *patch.Target, p yamlpatch.Patch) (transformers.Transformer, error) { +// newPatchJson6902YAMLTransformer constructs a PatchJson6902 transformer. +func newPatchJson6902YAMLTransformer(t resource.ResId, p yamlpatch.Patch) (transformers.Transformer, error) { + if len(p) == 0 { + return transformers.NewNoOpTransformer(), nil + } return &patchJson6902YAMLTransformer{target: t, patch: p}, nil } // Transform apply the json patches on top of the base resources. func (t *patchJson6902YAMLTransformer) Transform(baseResourceMap resmap.ResMap) error { - targetId := resource.NewResIdWithPrefixNamespace( - schema.GroupVersionKind{ - Group: t.target.Group, - Version: t.target.Version, - Kind: t.target.Kind, - }, - t.target.Name, - "", - t.target.Namespace, - ) - - matchedIds := baseResourceMap.FindByGVKN(targetId) - if targetId.Namespace() != "" { - ids := []resource.ResId{} - for _, id := range matchedIds { - if id.Namespace() == targetId.Namespace() { - ids = append(ids, id) - } - } - matchedIds = ids - } - if len(matchedIds) == 0 { - log.Printf("Couldn't find any object to apply the json patch %v, skipping it.", targetId) - return nil - } - if len(matchedIds) > 1 { - return fmt.Errorf("found multiple objects that the patch can apply %v", matchedIds) + obj, err := findTargetObj(baseResourceMap, t.target) + if obj == nil { + return err } - - obj := baseResourceMap[matchedIds[0]] rawObj, err := yaml.Marshal(obj.Unstructured.Object) if err != nil { return err diff --git a/pkg/patch/transformer/patchjson6902yaml_test.go b/pkg/patch/transformer/patchjson6902yaml_test.go index 79ba7e52e0..4aed62a4a3 100644 --- a/pkg/patch/transformer/patchjson6902yaml_test.go +++ b/pkg/patch/transformer/patchjson6902yaml_test.go @@ -21,7 +21,6 @@ import ( "testing" yamlpatch "github.com/krishicks/yaml-patch" - "github.com/kubernetes-sigs/kustomize/pkg/patch" "github.com/kubernetes-sigs/kustomize/pkg/resmap" "github.com/kubernetes-sigs/kustomize/pkg/resource" "k8s.io/apimachinery/pkg/runtime/schema" @@ -30,8 +29,9 @@ import ( var deploy = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"} func TestJsonPatchYAMLTransformer_Transform(t *testing.T) { + id := resource.NewResId(deploy, "deploy1") base := resmap.ResMap{ - resource.NewResId(deploy, "deploy1"): resource.NewResourceFromMap( + id: resource.NewResourceFromMap( map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", @@ -58,13 +58,6 @@ func TestJsonPatchYAMLTransformer_Transform(t *testing.T) { }), } - target := patch.Target{ - Group: "apps", - Version: "v1", - Kind: "Deployment", - Name: "deploy1", - } - var image, replica, command interface{} image = "my-nginx" replica = "3" @@ -88,7 +81,7 @@ func TestJsonPatchYAMLTransformer_Transform(t *testing.T) { } expected := resmap.ResMap{ - resource.NewResId(deploy, "deploy1"): resource.NewResourceFromMap( + id: resource.NewResourceFromMap( map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", @@ -120,7 +113,7 @@ func TestJsonPatchYAMLTransformer_Transform(t *testing.T) { }, }), } - jpt, err := NewPatchJson6902YAMLTransformer(&target, patch) + jpt, err := newPatchJson6902YAMLTransformer(id, patch) if err != nil { t.Fatalf("unexpected error : %v", err) } diff --git a/pkg/patch/transformer/util.go b/pkg/patch/transformer/util.go new file mode 100644 index 0000000000..d6dcab5e2f --- /dev/null +++ b/pkg/patch/transformer/util.go @@ -0,0 +1,47 @@ +/* +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" + "log" + + "github.com/kubernetes-sigs/kustomize/pkg/resmap" + "github.com/kubernetes-sigs/kustomize/pkg/resource" +) + +func findTargetObj(m resmap.ResMap, targetId resource.ResId) (*resource.Resource, error) { + matchedIds := m.FindByGVKN(targetId) + if targetId.Namespace() != "" { + ids := []resource.ResId{} + for _, id := range matchedIds { + if id.Namespace() == targetId.Namespace() { + ids = append(ids, id) + } + } + matchedIds = ids + } + + if len(matchedIds) == 0 { + log.Printf("Couldn't find any object to apply the json patch %v, skipping it.", targetId) + return nil, nil + } + if len(matchedIds) > 1 { + return nil, fmt.Errorf("found multiple objects that the patch can apply %v", matchedIds) + } + return m[matchedIds[0]], nil +}