From 55284dc29076d35cfcd37a72391ac996fdbc14cc Mon Sep 17 00:00:00 2001 From: Mengqi Yu Date: Mon, 2 Mar 2020 16:16:10 -0800 Subject: [PATCH 01/17] print to stderr when encoutnering errors --- functions/examples/injection-tshirt-sizes/image/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/functions/examples/injection-tshirt-sizes/image/main.go b/functions/examples/injection-tshirt-sizes/image/main.go index 30c998e17..0fa773ea1 100644 --- a/functions/examples/injection-tshirt-sizes/image/main.go +++ b/functions/examples/injection-tshirt-sizes/image/main.go @@ -20,6 +20,7 @@ func main() { Filters: []kio.Filter{filter{}}, // run the inject into the inputs Outputs: []kio.Writer{rw}} // copy the inputs to the output if err := p.Execute(); err != nil { + fmt.Fprint(os.Stderr, err) os.Exit(1) } } From d43fc9979c0b0ce2c34a4a243f5dd4741f21706a Mon Sep 17 00:00:00 2001 From: Michiel Bakker Date: Wed, 4 Mar 2020 13:45:23 +0100 Subject: [PATCH 02/17] Updated README to use 'bases' instead of 'resources' in overlays examples --- examples/helloWorld/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/helloWorld/README.md b/examples/helloWorld/README.md index fcd36bb4c..4e5819d76 100644 --- a/examples/helloWorld/README.md +++ b/examples/helloWorld/README.md @@ -148,7 +148,7 @@ commonLabels: org: acmeCorporation commonAnnotations: note: Hello, I am staging! -resources: +bases: - ../../base patchesStrategicMerge: - map.yaml @@ -189,7 +189,7 @@ commonLabels: org: acmeCorporation commonAnnotations: note: Hello, I am production! -resources: +bases: - ../../base patchesStrategicMerge: - deployment.yaml From 11ef1f39212e85f253fd259772d434b31071340c Mon Sep 17 00:00:00 2001 From: "Masih H. Derkani" <301855+masih@users.noreply.github.com> Date: Fri, 20 Mar 2020 10:11:22 +0000 Subject: [PATCH 03/17] Update inventory_object.md --- docs/inventory_object.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/inventory_object.md b/docs/inventory_object.md index e6ba4f8ad..ab2bc0575 100644 --- a/docs/inventory_object.md +++ b/docs/inventory_object.md @@ -56,7 +56,7 @@ The _inventory_ ConfigMap contains two special annotations: The value of this annotation is a hash that is computed from the list of items in the Inventory -Basically, this inventory object acts a record of objects that are applied as a group. +Basically, this inventory object acts as a record of objects that are applied as a group. This object can be consumed by a client such as [cli-experimental](https://github.com/kubernetes-sigs/cli-experimental). The client can recognize the inventory annotations and take proper actions From 443fa792c379dbc00af849f285c8f30eb5a77abd Mon Sep 17 00:00:00 2001 From: Phillip Wittrock Date: Mon, 23 Mar 2020 12:09:15 -0700 Subject: [PATCH 04/17] kyaml release 0.1.2 --- releasing/VERSIONS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/releasing/VERSIONS b/releasing/VERSIONS index 878bd9e39..16b246085 100644 --- a/releasing/VERSIONS +++ b/releasing/VERSIONS @@ -6,7 +6,7 @@ # kyaml version export kyaml_major=0 export kyaml_minor=1 -export kyaml_patch=1 +export kyaml_patch=2 # kstatus version export kstatus_major=0 @@ -21,7 +21,7 @@ export api_patch=3 # cmd/config version export cmd_config_major=0 export cmd_config_minor=1 -export cmd_config_patch=1 +export cmd_config_patch=2 # cmd/kubectl version export cmd_kubectl_major=0 From 51b29d702352f40d19c27498ded1a7fbd16c2f87 Mon Sep 17 00:00:00 2001 From: Kubernetes Prow Robot Date: Fri, 6 Mar 2020 15:45:34 -0800 Subject: [PATCH 05/17] Support various target and resource with go-getter --- api/go.mod | 1 + api/go.sum | 15 +++++ api/krusty/kustomizer_test.go | 3 +- api/loader/fileloader.go | 48 ++++++++++------ api/loader/fileloader_test.go | 10 ++-- api/loader/loader.go | 25 ++++++--- api/loader/resource.go | 103 ++++++++++++++++++++++++++++++++++ examples/remoteBuild.md | 53 ++++++++++++----- kustomize/go.sum | 15 +++++ 9 files changed, 228 insertions(+), 45 deletions(-) create mode 100644 api/loader/resource.go diff --git a/api/go.mod b/api/go.mod index 4fc747aef..a4ac97959 100644 --- a/api/go.mod +++ b/api/go.mod @@ -8,6 +8,7 @@ require ( github.com/golangci/golangci-lint v1.21.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/pkg/errors v0.8.1 + github.com/yujunz/go-getter v1.4.1-lite golang.org/x/tools v0.0.0-20191010075000-0337d82405ff gopkg.in/yaml.v2 v2.2.4 k8s.io/api v0.17.0 diff --git a/api/go.sum b/api/go.sum index c5aa6187d..96f0b5b0a 100644 --- a/api/go.sum +++ b/api/go.sum @@ -26,6 +26,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bombsimon/wsl v1.2.5 h1:9gTOkIwVtoDZywvX802SDHokeX4kW1cKnV8ZTVAPkRs= github.com/bombsimon/wsl v1.2.5/go.mod h1:43lEF/i0kpXbLCeDXL9LMT8c92HyBywXb0AsgMHYngM= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -176,6 +178,12 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= +github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -225,9 +233,12 @@ github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -318,6 +329,8 @@ github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiff github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= +github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/ultraware/funlen v0.0.2 h1:Av96YVBwwNSe4MLR7iI/BIa3VyI7/djnto/pK3Uxbdo= github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/whitespace v0.0.4 h1:If7Va4cM03mpgrNH9k49/VOicWpGoG70XPBFFODYDsg= @@ -330,6 +343,8 @@ github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOV github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yujunz/go-getter v1.4.1-lite h1:FhvNc94AXMZkfqUwfMKhnQEC9phkphSGdPTL7tIdhOM= +github.com/yujunz/go-getter v1.4.1-lite/go.mod h1:sbmqxXjyLunH1PkF3n7zSlnVeMvmYUuIl9ZVs/7NyCc= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= diff --git a/api/krusty/kustomizer_test.go b/api/krusty/kustomizer_test.go index d00ca1162..6742fff84 100644 --- a/api/krusty/kustomizer_test.go +++ b/api/krusty/kustomizer_test.go @@ -4,6 +4,7 @@ package krusty_test import ( + "strings" "testing" "sigs.k8s.io/kustomize/api/filesys" @@ -21,7 +22,7 @@ func TestEmptyFileSystem(t *testing.T) { if err == nil { t.Fatalf("expected error") } - if err.Error() != "'noSuchThing' doesn't exist" { + if !strings.Contains(err.Error(), "'noSuchThing' doesn't exist") { t.Fatalf("unexpected error: %v", err) } } diff --git a/api/loader/fileloader.go b/api/loader/fileloader.go index 930cea5b6..255522870 100644 --- a/api/loader/fileloader.go +++ b/api/loader/fileloader.go @@ -95,6 +95,13 @@ type fileLoader struct { // Used to clone repositories. cloner git.Cloner + // If this is non-nil, the files were + // obtained from the given resource + rscSpec *resourceSpec + + // Used to get resources + getter resourceGetter + // Used to clean up, as needed. cleaner func() error } @@ -127,20 +134,21 @@ func newLoaderOrDie( log.Fatalf("unable to make loader at '%s'; %v", path, err) } return newLoaderAtConfirmedDir( - lr, root, fSys, nil, git.ClonerUsingGitExec) + lr, root, fSys, nil, git.ClonerUsingGitExec, getResource) } // newLoaderAtConfirmedDir returns a new fileLoader with given root. func newLoaderAtConfirmedDir( lr LoadRestrictorFunc, root filesys.ConfirmedDir, fSys filesys.FileSystem, - referrer *fileLoader, cloner git.Cloner) *fileLoader { + referrer *fileLoader, cloner git.Cloner, getter resourceGetter) *fileLoader { return &fileLoader{ loadRestrictor: lr, root: root, referrer: referrer, fSys: fSys, cloner: cloner, + getter: getter, cleaner: func() error { return nil }, } } @@ -170,37 +178,44 @@ func (fl *fileLoader) New(path string) (ifc.Loader, error) { if path == "" { return nil, fmt.Errorf("new root cannot be empty") } - repoSpec, err := git.NewRepoSpecFromUrl(path) - if err == nil { + + ldr, errGet := newResourceGetter(path, fl.fSys, nil, fl.cloner, fl.getter) + if errGet == nil { + return ldr, nil + } + + repoSpec, errGit := git.NewRepoSpecFromUrl(path) + if errGit == nil { // Treat this as git repo clone request. - if err := fl.errIfRepoCycle(repoSpec); err != nil { - return nil, err + if errGit := fl.errIfRepoCycle(repoSpec); errGit != nil { + return nil, errGit } return newLoaderAtGitClone( - repoSpec, fl.fSys, fl, fl.cloner) + repoSpec, fl.fSys, fl, fl.cloner, fl.getter) } + if filepath.IsAbs(path) { return nil, fmt.Errorf("new root '%s' cannot be absolute", path) } - root, err := demandDirectoryRoot(fl.fSys, fl.root.Join(path)) - if err != nil { - return nil, err + root, errDir := demandDirectoryRoot(fl.fSys, fl.root.Join(path)) + if errDir != nil { + return nil, fmt.Errorf("Error loading %s with git: %v, dir: %v, get: %v", path, errGit, errDir, errGet) } - if err := fl.errIfGitContainmentViolation(root); err != nil { - return nil, err + if errDir := fl.errIfGitContainmentViolation(root); errDir != nil { + return nil, errDir } - if err := fl.errIfArgEqualOrHigher(root); err != nil { - return nil, err + if errDir := fl.errIfArgEqualOrHigher(root); errDir != nil { + return nil, errDir } return newLoaderAtConfirmedDir( - fl.loadRestrictor, root, fl.fSys, fl, fl.cloner), nil + fl.loadRestrictor, root, fl.fSys, fl, fl.cloner, fl.getter), nil } // newLoaderAtGitClone returns a new Loader pinned to a temporary // directory holding a cloned git repo. func newLoaderAtGitClone( repoSpec *git.RepoSpec, fSys filesys.FileSystem, - referrer *fileLoader, cloner git.Cloner) (ifc.Loader, error) { + referrer *fileLoader, cloner git.Cloner, getter resourceGetter) (ifc.Loader, error) { cleaner := repoSpec.Cleaner(fSys) err := cloner(repoSpec) if err != nil { @@ -230,6 +245,7 @@ func newLoaderAtGitClone( repoSpec: repoSpec, fSys: fSys, cloner: cloner, + getter: getter, cleaner: cleaner, }, nil } diff --git a/api/loader/fileloader_test.go b/api/loader/fileloader_test.go index 983bb41b3..ae3423f8d 100644 --- a/api/loader/fileloader_test.go +++ b/api/loader/fileloader_test.go @@ -388,7 +388,7 @@ whatever } l, err := newLoaderAtGitClone( repoSpec, fSys, nil, - git.DoNothingCloner(filesys.ConfirmedDir(coRoot))) + git.DoNothingCloner(filesys.ConfirmedDir(coRoot)), getNothing) if err != nil { t.Fatalf("unexpected err: %v\n", err) } @@ -467,7 +467,7 @@ func TestLoaderDisallowsLocalBaseFromRemoteOverlay(t *testing.T) { } l1, err = newLoaderAtGitClone( repoSpec, fSys, nil, - git.DoNothingCloner(filesys.ConfirmedDir(cloneRoot))) + git.DoNothingCloner(filesys.ConfirmedDir(cloneRoot)), getNothing) if err != nil { t.Fatalf("unexpected err: %v\n", err) } @@ -506,7 +506,7 @@ func TestLocalLoaderReferencingGitBase(t *testing.T) { } l1 := newLoaderAtConfirmedDir( RestrictionRootOnly, root, fSys, nil, - git.DoNothingCloner(filesys.ConfirmedDir(cloneRoot))) + git.DoNothingCloner(filesys.ConfirmedDir(cloneRoot)), getNothing) if l1.Root() != topDir { t.Fatalf("unexpected root %s", l1.Root()) } @@ -532,7 +532,7 @@ func TestRepoDirectCycleDetection(t *testing.T) { } l1 := newLoaderAtConfirmedDir( RestrictionRootOnly, root, fSys, nil, - git.DoNothingCloner(filesys.ConfirmedDir(cloneRoot))) + git.DoNothingCloner(filesys.ConfirmedDir(cloneRoot)), getNothing) p1 := "github.com/someOrg/someRepo/foo" rs1, err := git.NewRepoSpecFromUrl(p1) if err != nil { @@ -561,7 +561,7 @@ func TestRepoIndirectCycleDetection(t *testing.T) { } l0 := newLoaderAtConfirmedDir( RestrictionRootOnly, root, fSys, nil, - git.DoNothingCloner(filesys.ConfirmedDir(cloneRoot))) + git.DoNothingCloner(filesys.ConfirmedDir(cloneRoot)), getNothing) p1 := "github.com/someOrg/someRepo1" p2 := "github.com/someOrg/someRepo2" diff --git a/api/loader/loader.go b/api/loader/loader.go index c72a95965..ad4040afe 100644 --- a/api/loader/loader.go +++ b/api/loader/loader.go @@ -5,6 +5,8 @@ package loader import ( + "fmt" + "sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/api/ifc" "sigs.k8s.io/kustomize/api/internal/git" @@ -19,16 +21,23 @@ import ( func NewLoader( lr LoadRestrictorFunc, target string, fSys filesys.FileSystem) (ifc.Loader, error) { - repoSpec, err := git.NewRepoSpecFromUrl(target) - if err == nil { + + ldr, errGet := newResourceGetter(target, fSys, nil, git.ClonerUsingGitExec, getResource) + if errGet == nil { + return ldr, nil + } + + repoSpec, errGit := git.NewRepoSpecFromUrl(target) + if errGit == nil { // The target qualifies as a remote git target. return newLoaderAtGitClone( - repoSpec, fSys, nil, git.ClonerUsingGitExec) + repoSpec, fSys, nil, git.ClonerUsingGitExec, getResource) } - root, err := demandDirectoryRoot(fSys, target) - if err != nil { - return nil, err + + root, errDir := demandDirectoryRoot(fSys, target) + if errDir == nil { + return newLoaderAtConfirmedDir(lr, root, fSys, nil, git.ClonerUsingGitExec, getResource), nil } - return newLoaderAtConfirmedDir( - lr, root, fSys, nil, git.ClonerUsingGitExec), nil + + return nil, fmt.Errorf("Error creating new loader with git: %v, dir: %v, get: %v", errGit, errDir, errGet) } diff --git a/api/loader/resource.go b/api/loader/resource.go new file mode 100644 index 000000000..cf13d975f --- /dev/null +++ b/api/loader/resource.go @@ -0,0 +1,103 @@ +// Copyright 2020 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package loader + +import ( + "context" + "log" + "os" + + "github.com/yujunz/go-getter" + "sigs.k8s.io/kustomize/api/filesys" + "sigs.k8s.io/kustomize/api/ifc" + "sigs.k8s.io/kustomize/api/internal/git" +) + +type resourceSpec struct { + // Raw is the original resource in kustomization.yaml + Raw string + + // Dir is where the resource is saved + Dir filesys.ConfirmedDir +} + +// Getter is a function that can gets resource +type resourceGetter func(rs *resourceSpec) error + +func newResourceGetter(raw string, fSys filesys.FileSystem, referrer *fileLoader, cloner git.Cloner, getter resourceGetter) (ifc.Loader, error) { + rs := &resourceSpec{ + Raw: raw, + } + + cleaner := func() error { + return fSys.RemoveAll(rs.Dir.String()) + } + + if err := getter(rs); err != nil { + cleaner() + return nil, err + } + + // TODO(yujunz): check file or directory + + return &fileLoader{ + loadRestrictor: RestrictionRootOnly, + // TODO(yujunz): limit to getter root + root: rs.Dir, + referrer: referrer, + fSys: fSys, + cloner: cloner, + rscSpec: rs, + getter: getter, + cleaner: cleaner, + }, nil +} + +func getResource(rs *resourceSpec) error { + var err error + + rs.Dir, err = filesys.NewTmpConfirmedDir() + if err != nil { + return err + } + + // Get the pwd + pwd, err := os.Getwd() + if err != nil { + log.Fatalf("Error getting wd: %s", err) + } + + opts := []getter.ClientOption{} + client := &getter.Client{ + Ctx: context.TODO(), + Src: rs.Raw, + Dst: rs.Dir.String(), + Pwd: pwd, + Mode: getter.ClientModeAny, + Detectors: []getter.Detector{ + new(getter.GitHubDetector), + new(getter.GitDetector), + new(getter.BitBucketDetector), + }, + Options: opts, + } + return client.Get() +} + +func getNothing(rs *resourceSpec) error { + var err error + rs.Dir, err = filesys.NewTmpConfirmedDir() + if err != nil { + return err + } + + // Get the pwd + pwd, err := os.Getwd() + if err != nil { + log.Fatalf("Error getting wd: %s", err) + } + + _, err = getter.Detect(rs.Raw, pwd, []getter.Detector{}) + return err +} diff --git a/examples/remoteBuild.md b/examples/remoteBuild.md index d37cdbfb1..2c4a48714 100644 --- a/examples/remoteBuild.md +++ b/examples/remoteBuild.md @@ -2,10 +2,9 @@ `kustomize build` can be run on a URL. -The effect is the same as cloning the repo, checking out a particular -_ref_ (commit hash, branch name, release tag, etc.), -then running `kustomize build` against the desired -directory in the local copy. +A [lite version of go-getter module](https://github.com/yujunz/go-getter) is +leveraged to get remote content, then running `kustomize build` against the +desired directory in the local copy. To try this immediately, run a build against the kustomization in the [multibases](multibases/README.md) example. There's @@ -32,6 +31,18 @@ test 3 == \ echo $? ``` +The URL can be an archive + + +``` +target="https://github.com/kustless/kustomize-examples/archive/master.zip//kustomize-examples-master" +test 1 == \ + $(kustomize build $target | grep remote-cm | wc -l); \ + echo $? +``` + +Note the kustomize root path inside archive must be appended after `//`. + A base can be a URL: @@ -59,20 +70,32 @@ test 3 == \ The url should follow [hashicorp/go-getter URL format](https://github.com/hashicorp/go-getter#url-format). -Here are some example urls pointing to Github repos following this convention. -- a repo with a root level kustomization.yaml +Note that S3 and GCS are NOT supported to avoid introducing massive dependency. - `github.com/Liujingfang1/mysql` -- a repo with a root level kustomization.yaml on branch test +Here are some example urls - `github.com/Liujingfang1/mysql?ref=test` -- a subdirectory in a repo on version v1.0.6 + +``` +DEMO_HOME=$(mktemp -d) - `github.com/kubernetes-sigs/kustomize/examples/multibases?ref=v1.0.6` -- a subdirectory in a repo on branch repoUrl2 +cat <$DEMO_HOME/kustomization.yaml +resources: - `github.com/Liujingfang1/kustomize/examples/helloWorld?ref=repoUrl2` -- a subdirectory in a repo on commit `7050a45134e9848fca214ad7e7007e96e5042c03` +# a repo with a root level kustomization.yaml +- github.com/Liujingfang1/mysql - `github.com/Liujingfang1/kustomize/examples/helloWorld?ref=7050a45134e9848fca214ad7e7007e96e5042c03` +# a repo with a root level kustomization.yaml on branch test +- github.com/Liujingfang1/mysql?ref=test + +# a subdirectory in a repo on branch repoUrl2 +- github.com/Liujingfang1/kustomize/examples/helloWorld?ref=repoUrl2 + +# a subdirectory in a repo on commit `7050a45134e9848fca214ad7e7007e96e5042c03` +- github.com/Liujingfang1/kustomize/examples/helloWorld?ref=7050a45134e9848fca214ad7e7007e96e5042c03 + +# a subdirectory in a remote archive +- https://github.com/kustless/kustomize-examples/archive/master.zip//kustomize-examples-master + +EOF +``` diff --git a/kustomize/go.sum b/kustomize/go.sum index 2c7916b9f..caf262904 100644 --- a/kustomize/go.sum +++ b/kustomize/go.sum @@ -44,6 +44,8 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:l github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bombsimon/wsl v1.2.5 h1:9gTOkIwVtoDZywvX802SDHokeX4kW1cKnV8ZTVAPkRs= github.com/bombsimon/wsl v1.2.5/go.mod h1:43lEF/i0kpXbLCeDXL9LMT8c92HyBywXb0AsgMHYngM= @@ -278,8 +280,14 @@ github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpg github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= +github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -345,9 +353,12 @@ github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= @@ -470,6 +481,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= +github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/ultraware/funlen v0.0.2 h1:Av96YVBwwNSe4MLR7iI/BIa3VyI7/djnto/pK3Uxbdo= github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/whitespace v0.0.4 h1:If7Va4cM03mpgrNH9k49/VOicWpGoG70XPBFFODYDsg= @@ -486,6 +499,8 @@ github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSf github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yujunz/go-getter v1.4.1-lite h1:FhvNc94AXMZkfqUwfMKhnQEC9phkphSGdPTL7tIdhOM= +github.com/yujunz/go-getter v1.4.1-lite/go.mod h1:sbmqxXjyLunH1PkF3n7zSlnVeMvmYUuIl9ZVs/7NyCc= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= From 04bec8ed2ebef2e3e1a369897648c0ca13d85b26 Mon Sep 17 00:00:00 2001 From: Yujun Zhang Date: Tue, 24 Mar 2020 10:11:50 +0800 Subject: [PATCH 06/17] Rename `resourceGetter` to `remoteTargetGetter` for readability --- api/loader/fileloader.go | 12 ++++++------ api/loader/{resource.go => getter.go} | 14 ++++++-------- api/loader/loader.go | 6 +++--- plugin/builtin/imagetagtransformer/go.sum | 16 ++++++++++++++++ 4 files changed, 31 insertions(+), 17 deletions(-) rename api/loader/{resource.go => getter.go} (81%) diff --git a/api/loader/fileloader.go b/api/loader/fileloader.go index 255522870..8e5b3113a 100644 --- a/api/loader/fileloader.go +++ b/api/loader/fileloader.go @@ -97,10 +97,10 @@ type fileLoader struct { // If this is non-nil, the files were // obtained from the given resource - rscSpec *resourceSpec + rscSpec *remoteTargetSpec // Used to get resources - getter resourceGetter + getter remoteTargetGetter // Used to clean up, as needed. cleaner func() error @@ -134,14 +134,14 @@ func newLoaderOrDie( log.Fatalf("unable to make loader at '%s'; %v", path, err) } return newLoaderAtConfirmedDir( - lr, root, fSys, nil, git.ClonerUsingGitExec, getResource) + lr, root, fSys, nil, git.ClonerUsingGitExec, getRemoteTarget) } // newLoaderAtConfirmedDir returns a new fileLoader with given root. func newLoaderAtConfirmedDir( lr LoadRestrictorFunc, root filesys.ConfirmedDir, fSys filesys.FileSystem, - referrer *fileLoader, cloner git.Cloner, getter resourceGetter) *fileLoader { + referrer *fileLoader, cloner git.Cloner, getter remoteTargetGetter) *fileLoader { return &fileLoader{ loadRestrictor: lr, root: root, @@ -179,7 +179,7 @@ func (fl *fileLoader) New(path string) (ifc.Loader, error) { return nil, fmt.Errorf("new root cannot be empty") } - ldr, errGet := newResourceGetter(path, fl.fSys, nil, fl.cloner, fl.getter) + ldr, errGet := newLoaderAtGetter(path, fl.fSys, nil, fl.cloner, fl.getter) if errGet == nil { return ldr, nil } @@ -215,7 +215,7 @@ func (fl *fileLoader) New(path string) (ifc.Loader, error) { // directory holding a cloned git repo. func newLoaderAtGitClone( repoSpec *git.RepoSpec, fSys filesys.FileSystem, - referrer *fileLoader, cloner git.Cloner, getter resourceGetter) (ifc.Loader, error) { + referrer *fileLoader, cloner git.Cloner, getter remoteTargetGetter) (ifc.Loader, error) { cleaner := repoSpec.Cleaner(fSys) err := cloner(repoSpec) if err != nil { diff --git a/api/loader/resource.go b/api/loader/getter.go similarity index 81% rename from api/loader/resource.go rename to api/loader/getter.go index cf13d975f..5e663b932 100644 --- a/api/loader/resource.go +++ b/api/loader/getter.go @@ -14,7 +14,7 @@ import ( "sigs.k8s.io/kustomize/api/internal/git" ) -type resourceSpec struct { +type remoteTargetSpec struct { // Raw is the original resource in kustomization.yaml Raw string @@ -23,10 +23,10 @@ type resourceSpec struct { } // Getter is a function that can gets resource -type resourceGetter func(rs *resourceSpec) error +type remoteTargetGetter func(rs *remoteTargetSpec) error -func newResourceGetter(raw string, fSys filesys.FileSystem, referrer *fileLoader, cloner git.Cloner, getter resourceGetter) (ifc.Loader, error) { - rs := &resourceSpec{ +func newLoaderAtGetter(raw string, fSys filesys.FileSystem, referrer *fileLoader, cloner git.Cloner, getter remoteTargetGetter) (ifc.Loader, error) { + rs := &remoteTargetSpec{ Raw: raw, } @@ -39,8 +39,6 @@ func newResourceGetter(raw string, fSys filesys.FileSystem, referrer *fileLoader return nil, err } - // TODO(yujunz): check file or directory - return &fileLoader{ loadRestrictor: RestrictionRootOnly, // TODO(yujunz): limit to getter root @@ -54,7 +52,7 @@ func newResourceGetter(raw string, fSys filesys.FileSystem, referrer *fileLoader }, nil } -func getResource(rs *resourceSpec) error { +func getRemoteTarget(rs *remoteTargetSpec) error { var err error rs.Dir, err = filesys.NewTmpConfirmedDir() @@ -85,7 +83,7 @@ func getResource(rs *resourceSpec) error { return client.Get() } -func getNothing(rs *resourceSpec) error { +func getNothing(rs *remoteTargetSpec) error { var err error rs.Dir, err = filesys.NewTmpConfirmedDir() if err != nil { diff --git a/api/loader/loader.go b/api/loader/loader.go index ad4040afe..daab26943 100644 --- a/api/loader/loader.go +++ b/api/loader/loader.go @@ -22,7 +22,7 @@ func NewLoader( lr LoadRestrictorFunc, target string, fSys filesys.FileSystem) (ifc.Loader, error) { - ldr, errGet := newResourceGetter(target, fSys, nil, git.ClonerUsingGitExec, getResource) + ldr, errGet := newLoaderAtGetter(target, fSys, nil, git.ClonerUsingGitExec, getRemoteTarget) if errGet == nil { return ldr, nil } @@ -31,12 +31,12 @@ func NewLoader( if errGit == nil { // The target qualifies as a remote git target. return newLoaderAtGitClone( - repoSpec, fSys, nil, git.ClonerUsingGitExec, getResource) + repoSpec, fSys, nil, git.ClonerUsingGitExec, getRemoteTarget) } root, errDir := demandDirectoryRoot(fSys, target) if errDir == nil { - return newLoaderAtConfirmedDir(lr, root, fSys, nil, git.ClonerUsingGitExec, getResource), nil + return newLoaderAtConfirmedDir(lr, root, fSys, nil, git.ClonerUsingGitExec, getRemoteTarget), nil } return nil, fmt.Errorf("Error creating new loader with git: %v, dir: %v, get: %v", errGit, errDir, errGet) diff --git a/plugin/builtin/imagetagtransformer/go.sum b/plugin/builtin/imagetagtransformer/go.sum index 68a886f70..18e50f969 100644 --- a/plugin/builtin/imagetagtransformer/go.sum +++ b/plugin/builtin/imagetagtransformer/go.sum @@ -24,6 +24,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bombsimon/wsl v1.2.5/go.mod h1:43lEF/i0kpXbLCeDXL9LMT8c92HyBywXb0AsgMHYngM= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -143,6 +145,12 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= +github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= @@ -184,8 +192,12 @@ github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -261,6 +273,8 @@ github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiff github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= +github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/uudashr/gocognit v0.0.0-20190926065955-1655d0de0517/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM= @@ -270,6 +284,8 @@ github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOV github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yujunz/go-getter v1.4.1-lite h1:FhvNc94AXMZkfqUwfMKhnQEC9phkphSGdPTL7tIdhOM= +github.com/yujunz/go-getter v1.4.1-lite/go.mod h1:sbmqxXjyLunH1PkF3n7zSlnVeMvmYUuIl9ZVs/7NyCc= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= From efdd812cc10c11e17437b3693597fde7266463c8 Mon Sep 17 00:00:00 2001 From: Phillip Wittrock Date: Tue, 24 Mar 2020 11:18:46 -0700 Subject: [PATCH 07/17] refactor function filters --- kyaml/kio/filters/container.go | 84 ++++++++------- kyaml/kio/filters/container_test.go | 153 +++++++++++++++------------- kyaml/runfn/runfn.go | 127 +++++++++-------------- kyaml/runfn/runfn_test.go | 44 +++++--- 4 files changed, 206 insertions(+), 202 deletions(-) diff --git a/kyaml/kio/filters/container.go b/kyaml/kio/filters/container.go index c05a7a342..6602a08c4 100644 --- a/kyaml/kio/filters/container.go +++ b/kyaml/kio/filters/container.go @@ -389,8 +389,7 @@ type IsReconcilerFilter struct { func (c *IsReconcilerFilter) Filter(inputs []*yaml.RNode) ([]*yaml.RNode, error) { var out []*yaml.RNode for i := range inputs { - img, _ := GetContainerName(inputs[i]) - isContainerResource := img != "" + isContainerResource := GetFunctionSpec(inputs[i]) != nil if isContainerResource && !c.ExcludeReconcilers { out = append(out, inputs[i]) } @@ -408,52 +407,67 @@ const ( var functionAnnotationKeys = []string{FunctionAnnotationKey, oldFunctionAnnotationKey} -// GetFunction parses the config function from the object if it is found -func GetFunction(n *yaml.RNode, meta yaml.ResourceMeta) (*yaml.RNode, error) { +// getFunction parses the config function from the object if it is found +func getFunction(n *yaml.RNode, meta yaml.ResourceMeta) *FunctionSpec { + var fs FunctionSpec for _, s := range functionAnnotationKeys { fn := meta.Annotations[s] if fn != "" { - return yaml.Parse(fn) + _ = yaml.Unmarshal([]byte(fn), &fs) + return &fs } } - return n.Pipe(yaml.Lookup("metadata", "configFn")) + n, err := n.Pipe(yaml.Lookup("metadata", "configFn")) + if err != nil || yaml.IsEmpty(n) { + return nil + } + s, err := n.String() + if err != nil { + return nil + } + _ = yaml.Unmarshal([]byte(s), &fs) + return &fs } -// GetContainerName returns the container image for an API if one exists -func GetContainerName(n *yaml.RNode) (string, string) { - meta, _ := n.GetMeta() +type ContainerSpec struct { + Image string `json:"image,omitempty" yaml:"image,omitempty"` + Network ContainerNetwork `json:"network,omitempty" yaml:"network,omitempty"` +} + +type FunctionSpec struct { + Path string `json:"path,omitempty" yaml:"path,omitempty"` + Network string `json:"network,omitempty" yaml:"network,omitempty"` + Container ContainerSpec `json:"container,omitempty" yaml:"container,omitempty"` +} + +type ContainerNetwork struct { + Required bool `json:"required,omitempty" yaml:"required,omitempty"` +} + +// GetFunctionSpec returns the FunctionSpec for a resource. Returns +// nil if the resource does not have a FunctionSpec. +// +// The FunctionSpec is read from the resource metadata.annotation +// "config.kubernetes.io/function" +func GetFunctionSpec(n *yaml.RNode) *FunctionSpec { + meta, err := n.GetMeta() + if err != nil { + return nil + } // path to the function, this will be mounted into the container path := meta.Annotations[kioutil.PathAnnotation] - - fn, _ := GetFunction(n, meta) - if fn != nil { - image, _ := fn.Pipe(yaml.Lookup("container", "image")) - return yaml.GetValue(image), path + if fn := getFunction(n, meta); fn != nil { + fn.Network = "" + fn.Path = path + return fn } + // legacy function specification for backwards compatibility container := meta.Annotations["config.kubernetes.io/container"] if container != "" { - return container, path + return &FunctionSpec{ + Path: path, Container: ContainerSpec{Image: container}} } - - image, err := n.Pipe(yaml.Lookup("metadata", "configFn", "container", "image")) - if err != nil || yaml.IsMissingOrNull(image) { - return "", path - } - return yaml.GetValue(image), path -} - -// GetContainerNetworkRequired returns whether or not networking is required for the container -func GetContainerNetworkRequired(n *yaml.RNode) (bool, error) { - meta, err := n.GetMeta() - if err != nil { - return false, err - } - f, err := GetFunction(n, meta) - if err != nil { - return false, err - } - networkRequired, _ := f.Pipe(yaml.Lookup("container", "network", "required")) - return yaml.GetValue(networkRequired) == "true", nil + return nil } diff --git a/kyaml/kio/filters/container_test.go b/kyaml/kio/filters/container_test.go index 43e697e3b..bc5b35721 100644 --- a/kyaml/kio/filters/container_test.go +++ b/kyaml/kio/filters/container_test.go @@ -326,9 +326,71 @@ kind: Example metadata: annotations: config.kubernetes.io/function: |- - container: foo:v1.0.0 + container: + image: foo:v1.0.0 +`, + expectedFn: ` +container: + image: foo:v1.0.0`, + }, + + { + name: "network", + resource: ` +apiVersion: v1beta1 +kind: Example +metadata: + annotations: + config.kubernetes.io/function: |- + container: + image: foo:v1.0.0 + network: + required: true +`, + expectedFn: ` +container: + image: foo:v1.0.0 + network: + required: true +`, + }, + + { + name: "path", + resource: ` +apiVersion: v1beta1 +kind: Example +metadata: + annotations: + config.kubernetes.io/function: |- + path: foo + container: + image: foo:v1.0.0 +`, + // path should be erased + expectedFn: ` +container: + image: foo:v1.0.0 +`, + }, + + { + name: "network", + resource: ` +apiVersion: v1beta1 +kind: Example +metadata: + annotations: + config.kubernetes.io/function: |- + network: foo + container: + image: foo:v1.0.0 +`, + // network should be erased + expectedFn: ` +container: + image: foo:v1.0.0 `, - expectedFn: `container: foo:v1.0.0`, }, // legacy fn style @@ -338,9 +400,13 @@ apiVersion: v1beta1 kind: Example metadata: configFn: - container: foo:v1.0.0 + container: + image: foo:v1.0.0 +`, + expectedFn: ` +container: + image: foo:v1.0.0 `, - expectedFn: `container: foo:v1.0.0`, }, // no fn @@ -361,20 +427,19 @@ metadata: tt := tests[i] t.Run(tt.name, func(t *testing.T) { resource := yaml.MustParse(tt.resource) - meta, err := resource.GetMeta() - if !assert.NoError(t, err) { - t.FailNow() - } - fn, err := GetFunction(resource, meta) - if !assert.NoError(t, err) { - t.FailNow() - } + fn := GetFunctionSpec(resource) if tt.missingFn { if !assert.Nil(t, fn) { t.FailNow() } } else { - if !assert.Equal(t, strings.TrimSpace(fn.MustString()), strings.TrimSpace(tt.expectedFn)) { + b, err := yaml.Marshal(fn) + if !assert.NoError(t, err) { + t.FailNow() + } + if !assert.Equal(t, + strings.TrimSpace(tt.expectedFn), + strings.TrimSpace(string(b))) { t.FailNow() } } @@ -382,61 +447,6 @@ metadata: } } -func Test_GetContainerName(t *testing.T) { - // make sure gcr.io works - n, err := yaml.Parse(`apiVersion: v1beta1 -kind: MyThing -metadata: - configFn: - container: - image: gcr.io/foo/bar:something -`) - if !assert.NoError(t, err) { - return - } - c, _ := GetContainerName(n) - assert.Equal(t, "gcr.io/foo/bar:something", c) - - // container from config.kubernetes.io/container annotation - n, err = yaml.Parse(`apiVersion: v1 -kind: MyThing -metadata: - annotations: - config.kubernetes.io/container: gcr.io/foo/bar:something -`) - if !assert.NoError(t, err) { - return - } - c, _ = GetContainerName(n) - assert.Equal(t, "gcr.io/foo/bar:something", c) - - // container from config.kubernetes.io/function annotation - n, err = yaml.Parse(`apiVersion: v1 -kind: MyThing -metadata: - annotations: - config.kubernetes.io/function: | - container: - image: gcr.io/foo/bar:something -`) - if !assert.NoError(t, err) { - return - } - c, _ = GetContainerName(n) - assert.Equal(t, "gcr.io/foo/bar:something", c) - - // doesn't have a container - n, err = yaml.Parse(`apiVersion: v1 -kind: MyThing -metadata: -`) - if !assert.NoError(t, err) { - return - } - c, _ = GetContainerName(n) - assert.Equal(t, "", c) -} - func Test_GetContainerNetworkRequired(t *testing.T) { tests := []struct { input string @@ -501,9 +511,10 @@ metadata: if !assert.NoError(t, err) { return } - required, err := GetContainerNetworkRequired(cfg) - assert.NoError(t, err) - assert.Equal(t, tc.required, required) + + meta, _ := cfg.GetMeta() + fn := getFunction(cfg, meta) + assert.Equal(t, tc.required, fn.Container.Network.Required) } } diff --git a/kyaml/runfn/runfn.go b/kyaml/runfn/runfn.go index e64c6222d..ac45f080b 100644 --- a/kyaml/runfn/runfn.go +++ b/kyaml/runfn/runfn.go @@ -57,8 +57,10 @@ type RunFns struct { // and only use explicit sources NoFunctionsFromInput *bool - // for testing purposes only - containerFilterProvider func(string, string, string, *yaml.RNode) kio.Filter + // functionFilterProvider provides a filter to perform the function. + // this is a variable so it can be mocked in tests + functionFilterProvider func( + filter filters.FunctionSpec, api *yaml.RNode) kio.Filter } // Execute runs the command @@ -110,21 +112,21 @@ func (r RunFns) getNodesAndFilters() ( func (r RunFns) getFilters(nodes []*yaml.RNode) ([]kio.Filter, error) { var fltrs []kio.Filter - // implicit filters from the input Resources + // fns from annotations on the input resources f, err := r.getFunctionsFromInput(nodes) if err != nil { return nil, err } fltrs = append(fltrs, f...) - // explicit filters from a list of directories + // fns from directories specified on the struct f, err = r.getFunctionsFromFunctionPaths() if err != nil { return nil, err } fltrs = append(fltrs, f...) - // explicit filters from a list of directories + // explicit fns specified on the struct f, err = r.getFunctionsFromFunctions() if err != nil { return nil, err @@ -156,7 +158,6 @@ func (r RunFns) getFunctionsFromInput(nodes []*yaml.RNode) ([]kio.Filter, error) return nil, nil } - var fltrs []kio.Filter buff := &kio.PackageBuffer{} err := kio.Pipeline{ Inputs: []kio.Reader{&kio.PackageBuffer{Nodes: nodes}}, @@ -167,95 +168,50 @@ func (r RunFns) getFunctionsFromInput(nodes []*yaml.RNode) ([]kio.Filter, error) return nil, err } sortFns(buff) - for i := range buff.Nodes { - api := buff.Nodes[i] - network := "" - img, path := filters.GetContainerName(api) - - required, err := filters.GetContainerNetworkRequired(api) - if err != nil { - return nil, err - } - if required { - if !r.Network { - // TODO(eddizane): Provide error info about which function needs the network - return fltrs, errors.Errorf("network required but not enabled with --network") - } - network = r.NetworkName - } - - fltrs = append(fltrs, r.containerFilterProvider(img, path, network, api)) - } - return fltrs, nil + return r.getFunctionFilters(false, buff.Nodes...) } // getFunctionsFromFunctionPaths returns the set of functions read from r.FunctionPaths // as a slice of Filters func (r RunFns) getFunctionsFromFunctionPaths() ([]kio.Filter, error) { - var fltrs []kio.Filter buff := &kio.PackageBuffer{} for i := range r.FunctionPaths { err := kio.Pipeline{ - Inputs: []kio.Reader{kio.LocalPackageReader{PackagePath: r.FunctionPaths[i]}}, + Inputs: []kio.Reader{ + kio.LocalPackageReader{PackagePath: r.FunctionPaths[i]}, + }, Outputs: []kio.Writer{buff}, }.Execute() if err != nil { return nil, err } } - for i := range buff.Nodes { - api := buff.Nodes[i] - network := "" - img, path := filters.GetContainerName(api) - - required, err := filters.GetContainerNetworkRequired(api) - if err != nil { - return nil, err - } - if required { - if !r.Network { - // TODO(eddiezane): Provide error info about which function needs the network - return fltrs, errors.Errorf("network required but not enabled with --network") - } - network = r.NetworkName - } - - c := r.containerFilterProvider(img, path, network, api) - cf, ok := c.(*filters.ContainerFilter) - if ok { - // functions provided by FunctionPaths are globally scoped - cf.GlobalScope = true - } - fltrs = append(fltrs, c) - } - return fltrs, nil + return r.getFunctionFilters(true, buff.Nodes...) } // getFunctionsFromFunctions returns the set of explicitly provided functions as // Filters func (r RunFns) getFunctionsFromFunctions() ([]kio.Filter, error) { - var fltrs []kio.Filter - for i := range r.Functions { - api := r.Functions[i] - network := "" - img, path := filters.GetContainerName(api) + return r.getFunctionFilters(true, r.Functions...) +} - required, err := filters.GetContainerNetworkRequired(api) - if err != nil { - return nil, err - } - if required { +func (r RunFns) getFunctionFilters(global bool, fns ...*yaml.RNode) ( + []kio.Filter, error) { + var fltrs []kio.Filter + for i := range fns { + api := fns[i] + spec := filters.GetFunctionSpec(api) + if spec.Container.Network.Required { if !r.Network { - // TODO(eddizane): Provide error info about which function needs the network + // TODO(eddiezane): Provide error info about which function needs the network return fltrs, errors.Errorf("network required but not enabled with --network") } - network = r.NetworkName + spec.Network = r.NetworkName } - c := r.containerFilterProvider(img, path, network, api) + c := r.functionFilterProvider(*spec, api) cf, ok := c.(*filters.ContainerFilter) - if ok { - // functions provided by Functions are globally scoped + if global && ok { cf.GlobalScope = true } fltrs = append(fltrs, c) @@ -327,17 +283,26 @@ func (r *RunFns) init() { } } - // if containerFilterProvider hasn't been set, use the default - if r.containerFilterProvider == nil { - r.containerFilterProvider = func(image, path, network string, api *yaml.RNode) kio.Filter { - cf := &filters.ContainerFilter{ - Image: image, - Config: api, - Network: network, - StorageMounts: r.StorageMounts, - GlobalScope: r.GlobalScope, - } - return cf - } + // functionFilterProvider set the filter provider + if r.functionFilterProvider == nil { + r.functionFilterProvider = r.ffp } } + +// ffp provides function filters +func (r *RunFns) ffp(spec filters.FunctionSpec, api *yaml.RNode) kio.Filter { + if spec.Container.Image != "" { + return &filters.ContainerFilter{ + Image: spec.Container.Image, + Config: api, + Network: spec.Network, + StorageMounts: r.StorageMounts, + GlobalScope: r.GlobalScope, + } + } + return noOpFilter +} + +var noOpFilter = kio.FilterFunc(func(in []*yaml.RNode) ([]*yaml.RNode, error) { + return in, nil +}) diff --git a/kyaml/runfn/runfn_test.go b/kyaml/runfn/runfn_test.go index 52d6ae229..b11818dc7 100644 --- a/kyaml/runfn/runfn_test.go +++ b/kyaml/runfn/runfn_test.go @@ -47,10 +47,15 @@ func TestRunFns_init(t *testing.T) { api, err := yaml.Parse(`apiVersion: apps/v1 kind: `) + spec := filters.FunctionSpec{ + Container: filters.ContainerSpec{ + Image: "example.com:version", + }, + } if !assert.NoError(t, err) { return } - filter := instance.containerFilterProvider("example.com:version", "", "", api) + filter := instance.functionFilterProvider(spec, api) assert.Equal(t, &filters.ContainerFilter{Image: "example.com:version", Config: api}, filter) } @@ -69,7 +74,16 @@ kind: if !assert.NoError(t, err) { return } - filter := instance.containerFilterProvider("example.com:version", "", "", api) + + spec := filters.FunctionSpec{ + Container: filters.ContainerSpec{ + Image: "example.com:version", + }, + } + if !assert.NoError(t, err) { + return + } + filter := instance.functionFilterProvider(spec, api) assert.Equal(t, &filters.ContainerFilter{ Image: "example.com:version", Config: api, GlobalScope: true}, filter) } @@ -131,7 +145,7 @@ func TestRunFns_Execute__initDefault(t *testing.T) { tt := tests[i] t.Run(tt.name, func(t *testing.T) { (&tt.instance).init() - (&tt.instance).containerFilterProvider = nil + (&tt.instance).functionFilterProvider = nil if !assert.Equal(t, tt.expected, tt.instance) { t.FailNow() } @@ -505,7 +519,7 @@ func TestCmd_Execute(t *testing.T) { return } - instance := RunFns{Path: dir, containerFilterProvider: getFilterProvider(t)} + instance := RunFns{Path: dir, functionFilterProvider: getFilterProvider(t)} if !assert.NoError(t, instance.Execute()) { t.FailNow() } @@ -534,9 +548,9 @@ func TestCmd_Execute_setFunctionPaths(t *testing.T) { // run the functions, providing the path to the directory of filters instance := RunFns{ - FunctionPaths: []string{tmpF.Name()}, - Path: dir, - containerFilterProvider: getFilterProvider(t), + FunctionPaths: []string{tmpF.Name()}, + Path: dir, + functionFilterProvider: getFilterProvider(t), } // initialize the defaults instance.init() @@ -566,9 +580,9 @@ func TestCmd_Execute_setOutput(t *testing.T) { out := &bytes.Buffer{} instance := RunFns{ - Output: out, // write to out - Path: dir, - containerFilterProvider: getFilterProvider(t), + Output: out, // write to out + Path: dir, + functionFilterProvider: getFilterProvider(t), } // initialize the defaults instance.init() @@ -614,9 +628,9 @@ func TestCmd_Execute_setInput(t *testing.T) { } instance := RunFns{ - Input: input, // read from input - Path: outDir, - containerFilterProvider: getFilterProvider(t), + Input: input, // read from input + Path: outDir, + functionFilterProvider: getFilterProvider(t), } // initialize the defaults instance.init() @@ -659,8 +673,8 @@ func setupTest(t *testing.T) string { // getFilterProvider fakes the creation of a filter, replacing the ContainerFiler with // a filter to s/kind: Deployment/kind: StatefulSet/g. // this can be used to simulate running a filter. -func getFilterProvider(t *testing.T) func(string, string, string, *yaml.RNode) kio.Filter { - return func(s, _, _ string, node *yaml.RNode) kio.Filter { +func getFilterProvider(t *testing.T) func(filters.FunctionSpec, *yaml.RNode) kio.Filter { + return func(f filters.FunctionSpec, node *yaml.RNode) kio.Filter { // parse the filter from the input filter := yaml.YFilter{} b := &bytes.Buffer{} From 51a79d554c92e60a9563ec71507f6dfff411b59f Mon Sep 17 00:00:00 2001 From: Phillip Wittrock Date: Mon, 23 Mar 2020 11:13:35 -0700 Subject: [PATCH 08/17] Update go.mod and go.sum for kyaml based namespace transformer --- api/go.mod | 6 ++-- api/go.sum | 23 +++++++++---- kustomize/go.mod | 2 +- kustomize/go.sum | 6 ++++ plugin/builtin/imagetagtransformer/go.sum | 13 +++++++ plugin/builtin/namespacetransformer/go.mod | 4 ++- plugin/builtin/namespacetransformer/go.sum | 40 +++++++++++++++++----- 7 files changed, 75 insertions(+), 19 deletions(-) diff --git a/api/go.mod b/api/go.mod index a4ac97959..282c0f65a 100644 --- a/api/go.mod +++ b/api/go.mod @@ -4,16 +4,18 @@ go 1.13 require ( github.com/evanphx/json-patch v4.5.0+incompatible - github.com/go-openapi/spec v0.19.4 + github.com/go-openapi/spec v0.19.5 github.com/golangci/golangci-lint v1.21.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/pkg/errors v0.8.1 + github.com/stretchr/testify v1.4.0 github.com/yujunz/go-getter v1.4.1-lite golang.org/x/tools v0.0.0-20191010075000-0337d82405ff - gopkg.in/yaml.v2 v2.2.4 + gopkg.in/yaml.v2 v2.2.7 k8s.io/api v0.17.0 k8s.io/apimachinery v0.17.0 k8s.io/client-go v0.17.0 k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a + sigs.k8s.io/kustomize/kyaml v0.1.1 sigs.k8s.io/yaml v1.1.0 ) diff --git a/api/go.sum b/api/go.sum index 96f0b5b0a..1a62b887e 100644 --- a/api/go.sum +++ b/api/go.sum @@ -61,6 +61,8 @@ github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2H github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db h1:GYXWx7Vr3+zv833u+8IoXbNnQY0AdXsxAgI0kX7xcwA= github.com/go-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-lintpack/lintpack v0.5.2 h1:DI5mA3+eKdWeJ40nU4d6Wc26qmdG8RCi/btYq0TuRN0= github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= @@ -76,8 +78,8 @@ github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1 github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= -github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw= +github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= @@ -213,7 +215,6 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -286,6 +287,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d h1:BzRvVq1EHuIjxpijCEKpAxzKUUMurOQ4sknehIATRh8= github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d/go.mod h1:w5+eXa0mYznDkHaMCXA4XYffjlH+cy1oyKbfzJXa2Do= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e h1:MZM7FHLqUHYI0Y/mQAt3d2aYa0SiNms/hFqC9qJYolM= @@ -342,6 +344,8 @@ github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yujunz/go-getter v1.4.1-lite h1:FhvNc94AXMZkfqUwfMKhnQEC9phkphSGdPTL7tIdhOM= github.com/yujunz/go-getter v1.4.1-lite/go.mod h1:sbmqxXjyLunH1PkF3n7zSlnVeMvmYUuIl9ZVs/7NyCc= @@ -355,7 +359,6 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -402,7 +405,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69 h1:rOhMmluY6kLMhdnrivzec6lLgaVbMHMn2ISQXJeJ5EM= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -427,8 +429,6 @@ golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -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-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -463,6 +463,10 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM= +gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= @@ -487,6 +491,11 @@ mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphD mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f h1:Cq7MalBHYACRd6EesksG1Q8EoIAKOsiZviGKbOLIej4= mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw= +sigs.k8s.io/kustomize v1.0.11 h1:Yb+6DDt9+aR2AvQApvUaKS/ugteeG4MPyoFeUHiPOjk= +sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= +sigs.k8s.io/kustomize/kyaml v0.1.1 h1:nGUNYINljZNmlAS8uoobUv/wx/s3Pg8dNxYo+W7uYh0= +sigs.k8s.io/kustomize/kyaml v0.1.1/go.mod h1:/NdPPfrperSCGjm55cwEro1loBVtbtVIXSb7FguK6uk= +sigs.k8s.io/kustomize/kyaml v0.1.2 h1:l12+QGl+ETUHhP8/bZAi6TknU7H194fXL/9b2gUxZFY= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/kustomize/go.mod b/kustomize/go.mod index 1912aec9e..f30f91ab8 100644 --- a/kustomize/go.mod +++ b/kustomize/go.mod @@ -16,7 +16,7 @@ require ( sigs.k8s.io/kustomize/cmd/config v0.0.5 sigs.k8s.io/kustomize/cmd/kubectl v0.0.3 sigs.k8s.io/kustomize/kstatus v0.0.1 - sigs.k8s.io/kustomize/kyaml v0.0.6 + sigs.k8s.io/kustomize/kyaml v0.1.1 sigs.k8s.io/yaml v1.1.0 ) diff --git a/kustomize/go.sum b/kustomize/go.sum index caf262904..7658e17ba 100644 --- a/kustomize/go.sum +++ b/kustomize/go.sum @@ -665,8 +665,12 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d h1:LCPbGQ34PMrwad11aMZ+dbz5SAsq/0ySjRwQ8I9Qwd8= gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM= +gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -737,6 +741,8 @@ sigs.k8s.io/kustomize/kyaml v0.0.2/go.mod h1:rywm/rcR5LmCBghz9956tE45OdUPChFoXVV sigs.k8s.io/kustomize/kyaml v0.0.5/go.mod h1:waxTrzQRK9i6/5fR5HNo8xa4YwvWn8t85vMnOGFEZik= sigs.k8s.io/kustomize/kyaml v0.0.6 h1:KhQr7JwpCseFTSWCwqp4CJ4mY6Kx+i34tF4e0eNkcXw= sigs.k8s.io/kustomize/kyaml v0.0.6/go.mod h1:tDOfJjL6slQVBLHJ76XfXAFgAOEdfm04AW2HehYOp8k= +sigs.k8s.io/kustomize/kyaml v0.1.1 h1:nGUNYINljZNmlAS8uoobUv/wx/s3Pg8dNxYo+W7uYh0= +sigs.k8s.io/kustomize/kyaml v0.1.1/go.mod h1:/NdPPfrperSCGjm55cwEro1loBVtbtVIXSb7FguK6uk= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= sigs.k8s.io/testing_frameworks v0.1.2 h1:vK0+tvjF0BZ/RYFeZ1E6BYBwHJJXhjuZ3TdsEKH+UQM= diff --git a/plugin/builtin/imagetagtransformer/go.sum b/plugin/builtin/imagetagtransformer/go.sum index 18e50f969..1fa9a2d4f 100644 --- a/plugin/builtin/imagetagtransformer/go.sum +++ b/plugin/builtin/imagetagtransformer/go.sum @@ -56,6 +56,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -72,6 +74,8 @@ github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwoh github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw= +github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= @@ -241,6 +245,7 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d/go.mod h1:w5+eXa0mYznDkHaMCXA4XYffjlH+cy1oyKbfzJXa2Do= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= @@ -283,6 +288,8 @@ github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yujunz/go-getter v1.4.1-lite h1:FhvNc94AXMZkfqUwfMKhnQEC9phkphSGdPTL7tIdhOM= github.com/yujunz/go-getter v1.4.1-lite/go.mod h1:sbmqxXjyLunH1PkF3n7zSlnVeMvmYUuIl9ZVs/7NyCc= @@ -403,6 +410,10 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM= +gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= @@ -425,6 +436,8 @@ mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jC mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw= sigs.k8s.io/kustomize/api v0.3.1 h1:oqMIXvS6tFEUVuKIRUKDa05eC4Hh+cb9JYg8Zhp2d24= sigs.k8s.io/kustomize/api v0.3.1/go.mod h1:A+ATnlHqzictQfQC1q3KB/T6MSr0UWQsrrLxMWkge2E= +sigs.k8s.io/kustomize/kyaml v0.1.1 h1:nGUNYINljZNmlAS8uoobUv/wx/s3Pg8dNxYo+W7uYh0= +sigs.k8s.io/kustomize/kyaml v0.1.1/go.mod h1:/NdPPfrperSCGjm55cwEro1loBVtbtVIXSb7FguK6uk= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/plugin/builtin/namespacetransformer/go.mod b/plugin/builtin/namespacetransformer/go.mod index c5baea2ac..708261f60 100644 --- a/plugin/builtin/namespacetransformer/go.mod +++ b/plugin/builtin/namespacetransformer/go.mod @@ -3,6 +3,8 @@ module sigs.k8s.io/kustomize/plugin/builtin/namespacetransformer go 1.13 require ( - sigs.k8s.io/kustomize/api v0.3.1 + sigs.k8s.io/kustomize/api v0.0.0 sigs.k8s.io/yaml v1.1.0 ) + +replace sigs.k8s.io/kustomize/api v0.0.0 => ../../../api diff --git a/plugin/builtin/namespacetransformer/go.sum b/plugin/builtin/namespacetransformer/go.sum index 68a886f70..79bd6b0b3 100644 --- a/plugin/builtin/namespacetransformer/go.sum +++ b/plugin/builtin/namespacetransformer/go.sum @@ -24,6 +24,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bombsimon/wsl v1.2.5/go.mod h1:43lEF/i0kpXbLCeDXL9LMT8c92HyBywXb0AsgMHYngM= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -54,6 +56,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -68,8 +72,8 @@ github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1 github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= -github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw= +github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= @@ -143,6 +147,12 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= +github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= @@ -168,7 +178,6 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -184,8 +193,12 @@ github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -229,6 +242,7 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d/go.mod h1:w5+eXa0mYznDkHaMCXA4XYffjlH+cy1oyKbfzJXa2Do= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= @@ -261,6 +275,8 @@ github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiff github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= +github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/uudashr/gocognit v0.0.0-20190926065955-1655d0de0517/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM= @@ -269,7 +285,11 @@ github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yujunz/go-getter v1.4.1-lite h1:FhvNc94AXMZkfqUwfMKhnQEC9phkphSGdPTL7tIdhOM= +github.com/yujunz/go-getter v1.4.1-lite/go.mod h1:sbmqxXjyLunH1PkF3n7zSlnVeMvmYUuIl9ZVs/7NyCc= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -280,7 +300,6 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -328,7 +347,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69 h1:rOhMmluY6kLMhdnrivzec6lLgaVbMHMn2ISQXJeJ5EM= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -353,7 +371,6 @@ golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -387,6 +404,10 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM= +gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= @@ -407,8 +428,11 @@ k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw= -sigs.k8s.io/kustomize/api v0.3.1 h1:oqMIXvS6tFEUVuKIRUKDa05eC4Hh+cb9JYg8Zhp2d24= -sigs.k8s.io/kustomize/api v0.3.1/go.mod h1:A+ATnlHqzictQfQC1q3KB/T6MSr0UWQsrrLxMWkge2E= +sigs.k8s.io/kustomize v1.0.11 h1:Yb+6DDt9+aR2AvQApvUaKS/ugteeG4MPyoFeUHiPOjk= +sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= +sigs.k8s.io/kustomize/kyaml v0.1.1 h1:nGUNYINljZNmlAS8uoobUv/wx/s3Pg8dNxYo+W7uYh0= +sigs.k8s.io/kustomize/kyaml v0.1.1/go.mod h1:/NdPPfrperSCGjm55cwEro1loBVtbtVIXSb7FguK6uk= +sigs.k8s.io/kustomize/kyaml v0.1.2 h1:l12+QGl+ETUHhP8/bZAi6TknU7H194fXL/9b2gUxZFY= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= From 3def13d47992b19d72137e791f4325acdf822790 Mon Sep 17 00:00:00 2001 From: Phillip Wittrock Date: Mon, 23 Mar 2020 11:19:14 -0700 Subject: [PATCH 09/17] Support for FieldSpec based operations on kyaml objects --- api/filters/fsslice/doc.go | 6 + api/filters/fsslice/example_test.go | 62 +++++ api/filters/fsslice/fieldspec_filter.go | 145 ++++++++++ api/filters/fsslice/fsslice.go | 78 ++++++ api/filters/fsslice/fsslice_test.go | 354 ++++++++++++++++++++++++ 5 files changed, 645 insertions(+) create mode 100644 api/filters/fsslice/doc.go create mode 100644 api/filters/fsslice/example_test.go create mode 100644 api/filters/fsslice/fieldspec_filter.go create mode 100644 api/filters/fsslice/fsslice.go create mode 100644 api/filters/fsslice/fsslice_test.go diff --git a/api/filters/fsslice/doc.go b/api/filters/fsslice/doc.go new file mode 100644 index 000000000..407f11c47 --- /dev/null +++ b/api/filters/fsslice/doc.go @@ -0,0 +1,6 @@ +// Copyright 2020 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +// Package fsslice contains a yaml.Filter to modify a resource using an +// FsSlice to identify fields to be updated within the resource. +package fsslice diff --git a/api/filters/fsslice/example_test.go b/api/filters/fsslice/example_test.go new file mode 100644 index 000000000..ce14d4a58 --- /dev/null +++ b/api/filters/fsslice/example_test.go @@ -0,0 +1,62 @@ +// Copyright 2020 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package fsslice_test + +import ( + "bytes" + "log" + "os" + + "sigs.k8s.io/kustomize/api/filters/fsslice" + "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +func ExampleFilter() { + in := &kio.ByteReader{ + Reader: bytes.NewBufferString(` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + name: instance +`), + } + fltr := fsslice.Filter{ + CreateKind: yaml.ScalarNode, + SetValue: fsslice.SetScalar("green"), + FsSlice: []types.FieldSpec{ + {Path: "a/b", CreateIfNotPresent: true}, + }, + } + + err := kio.Pipeline{ + Inputs: []kio.Reader{in}, + Filters: []kio.Filter{kio.FilterAll(fltr)}, + Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}}, + }.Execute() + if err != nil { + log.Fatal(err) + } + + // Output: + // apiVersion: example.com/v1 + // kind: Foo + // metadata: + // name: instance + // a: + // b: green + // --- + // apiVersion: example.com/v1 + // kind: Bar + // metadata: + // name: instance + // a: + // b: green +} diff --git a/api/filters/fsslice/fieldspec_filter.go b/api/filters/fsslice/fieldspec_filter.go new file mode 100644 index 000000000..7ff2387f8 --- /dev/null +++ b/api/filters/fsslice/fieldspec_filter.go @@ -0,0 +1,145 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package fsslice + +import ( + "strings" + + "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/errors" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +// fieldSpecFilter applies a single fieldSpec to a single object +// fieldSpecFilter stores internal state and should not be reused +type fieldSpecFilter struct { + // FieldSpec contains the path to the value to set. + FieldSpec types.FieldSpec `yaml:"fieldSpec"` + + // Set the field using this function + SetValue SetFn + + // CreateKind defines the type of node to create if the field is not found + CreateKind yaml.Kind + + // path keeps internal state about the current path + path []string +} + +func (fltr fieldSpecFilter) Filter(obj *yaml.RNode) (*yaml.RNode, error) { + // check if the FieldSpec applies to the object + if match, err := isMatchGVK(fltr.FieldSpec, obj); !match || err != nil { + return obj, errors.Wrap(err) + } + fltr.path = strings.Split(fltr.FieldSpec.Path, "/") + if err := fltr.filter(obj); err != nil { + s, _ := obj.String() + return nil, errors.WrapPrefixf(err, + "obj %v at path %v", s, fltr.FieldSpec.Path) + } + return obj, nil +} + +func (fltr fieldSpecFilter) filter(obj *yaml.RNode) error { + if len(fltr.path) == 0 { + // found the field -- set its value + return fltr.SetValue(obj) + } + switch obj.YNode().Kind { + case yaml.SequenceNode: + return fltr.seq(obj) + case yaml.MappingNode: + return fltr.field(obj) + } + // not found -- this might be an error since the type doesn't match + + return errors.Errorf("unsupported yaml node") +} + +// field calls filter on the field matching the next path element +func (fltr fieldSpecFilter) field(obj *yaml.RNode) error { + fieldName, isSeq := isSequenceField(fltr.path[0]) + + // lookup the field matching the next path element + var lookupField yaml.Filter + switch { + case !fltr.FieldSpec.CreateIfNotPresent || fltr.CreateKind == 0 || isSeq: + // dont' create the field if we don't find it + lookupField = yaml.Lookup(fieldName) + case len(fltr.path) <= 1: + // create the field if it is missing: use the provided node kind + lookupField = yaml.LookupCreate(fltr.CreateKind, fieldName) + default: + // create the field if it is missing: must be a mapping node + lookupField = yaml.LookupCreate(yaml.MappingNode, fieldName) + } + + // locate (or maybe create) the field + field, err := obj.Pipe(lookupField) + if err != nil || field == nil { + return errors.WrapPrefixf(err, "fieldName: %s", fieldName) + } + + // copy the current fltr and change the path on the copy + var next = fltr + // call filter for the next path element on the matching field + next.path = fltr.path[1:] + return next.filter(field) +} + +// seq calls filter on all sequence elements +func (fltr fieldSpecFilter) seq(obj *yaml.RNode) error { + if err := obj.VisitElements(func(node *yaml.RNode) error { + // recurse on each element -- re-allocating a fieldSpecFilter is + // not strictly required, but is more consistent with field + // and less likely to have side effects + // keep the entire path -- it does not contain parts for sequences + return fltr.filter(node) + }); err != nil { + return errors.WrapPrefixf(err, + "visit traversal on path: %v", fltr.path) + } + + return nil +} + +// isSequenceField returns true if the path element is for a sequence field. +// isSequence also returns the path element with the '[]' suffix trimmed +func isSequenceField(name string) (string, bool) { + isSeq := strings.HasSuffix(name, "[]") + name = strings.TrimSuffix(name, "[]") + return name, isSeq +} + +// isMatchGVK returns true if the fs.GVK matches the obj GVK. +func isMatchGVK(fs types.FieldSpec, obj *yaml.RNode) (bool, error) { + meta, err := obj.GetMeta() + if err != nil { + return false, err + } + if fs.Kind != "" && fs.Kind != meta.Kind { + // kind doesn't match + return false, err + } + + // parse the group and version from the apiVersion field + var group, version string + parts := strings.SplitN(meta.APIVersion, "/", 2) + group = parts[0] + if len(parts) > 1 { + version = parts[1] + } + + if fs.Group != "" && fs.Group != group { + // group doesn't match + return false, nil + } + + if fs.Version != "" && fs.Version != version { + // version doesn't match + return false, nil + } + + return true, nil +} diff --git a/api/filters/fsslice/fsslice.go b/api/filters/fsslice/fsslice.go new file mode 100644 index 000000000..e5c896d19 --- /dev/null +++ b/api/filters/fsslice/fsslice.go @@ -0,0 +1,78 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package fsslice + +import ( + "strings" + + "sigs.k8s.io/kustomize/api/resid" + "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +// SetFn sets a value +type SetFn func(*yaml.RNode) error + +// SetScalar returns a SetFn to set a scalar value +func SetScalar(value string) SetFn { + return func(node *yaml.RNode) error { + return node.PipeE(yaml.FieldSetter{StringValue: value}) + } +} + +// SetEntry returns a SetFn to set an entry in a map +func SetEntry(key, value string) SetFn { + return func(node *yaml.RNode) error { + return node.PipeE(yaml.FieldSetter{ + Name: key, StringValue: value}) + } +} + +var _ yaml.Filter = Filter{} + +// Filter uses an FsSlice to modify fields on a single object +type Filter struct { + // FieldSpecList list of FieldSpecs to set + FsSlice types.FsSlice `yaml:"fsSlice"` + + // SetValue is called on each field that matches one of the FieldSpecs + SetValue SetFn + + // CreateKind is used to create fields that do not exist + CreateKind yaml.Kind +} + +func (fltr Filter) Filter(obj *yaml.RNode) (*yaml.RNode, error) { + for i := range fltr.FsSlice { + // apply this FieldSpec + // create a new filter for each iteration because they + // store internal state about the field paths + _, err := (&fieldSpecFilter{ + FieldSpec: fltr.FsSlice[i], + SetValue: fltr.SetValue, + CreateKind: fltr.CreateKind, + }).Filter(obj) + if err != nil { + return nil, err + } + } + return obj, nil +} + +// GetGVK parses the metadata into a GVK +func GetGVK(meta yaml.ResourceMeta) resid.Gvk { + // parse the group and version from the apiVersion field + var group, version string + parts := strings.SplitN(meta.APIVersion, "/", 2) + group = parts[0] + if len(parts) > 1 { + version = parts[1] + } + + return resid.Gvk{ + Group: group, + Version: version, + Kind: meta.Kind, + } +} diff --git a/api/filters/fsslice/fsslice_test.go b/api/filters/fsslice/fsslice_test.go new file mode 100644 index 000000000..a000fe14e --- /dev/null +++ b/api/filters/fsslice/fsslice_test.go @@ -0,0 +1,354 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package fsslice_test + +import ( + "bytes" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "sigs.k8s.io/kustomize/api/filters/fsslice" + "sigs.k8s.io/kustomize/api/resid" + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +type TestCase struct { + name string + input string + expected string + filter fsslice.Filter + fsSlice string + error string +} + +var tests = []TestCase{ + { + name: "update", + fsSlice: ` +- path: a/b + group: foo + kind: Bar +`, + input: ` +apiVersion: foo/v1beta1 +kind: Bar +a: + b: c +`, + expected: ` +apiVersion: foo/v1beta1 +kind: Bar +a: + b: e +`, + filter: fsslice.Filter{ + SetValue: fsslice.SetScalar("e"), + }, + }, + + { + name: "update-kind-not-match", + fsSlice: ` +- path: a/b + group: foo + kind: Bar1 +`, + input: ` +apiVersion: foo/v1beta1 +kind: Bar2 +a: + b: c +`, + expected: ` +apiVersion: foo/v1beta1 +kind: Bar2 +a: + b: c +`, + filter: fsslice.Filter{ + SetValue: fsslice.SetScalar("e"), + }, + }, + + { + name: "update-group-not-match", + fsSlice: ` +- path: a/b + group: foo1 + kind: Bar +`, + input: ` +apiVersion: foo2/v1beta1 +kind: Bar +a: + b: c +`, + expected: ` +apiVersion: foo2/v1beta1 +kind: Bar +a: + b: c +`, + filter: fsslice.Filter{ + SetValue: fsslice.SetScalar("e"), + }, + }, + + { + name: "update-version-not-match", + fsSlice: ` +- path: a/b + group: foo + version: v1beta1 + kind: Bar +`, + input: ` +apiVersion: foo/v1beta2 +kind: Bar +a: + b: c +`, + expected: ` +apiVersion: foo/v1beta2 +kind: Bar +a: + b: c +`, + filter: fsslice.Filter{ + SetValue: fsslice.SetScalar("e"), + }, + }, + + { + name: "bad-version", + fsSlice: ` +- path: a/b + group: foo + version: v1beta1 + kind: Bar +`, + input: ` +apiVersion: foo/v1beta2/something +kind: Bar +a: + b: c +`, + expected: ` +apiVersion: foo/v1beta2/something +kind: Bar +a: + b: c +`, + filter: fsslice.Filter{ + SetValue: fsslice.SetScalar("e"), + }, + }, + + { + name: "bad-meta", + fsSlice: ` +- path: a/b + group: foo + version: v1beta1 + kind: Bar +`, + input: ` +a: + b: c +`, + filter: fsslice.Filter{ + SetValue: fsslice.SetScalar("e"), + }, + error: "missing Resource metadata", + }, + + { + name: "miss-match-type", + fsSlice: ` +- path: a/b/c + kind: Bar +`, + input: ` +kind: Bar +a: + b: a +`, + error: "obj kind: Bar\na:\n b: a\n at path a/b/c: unsupported yaml node", + filter: fsslice.Filter{ + SetValue: fsslice.SetScalar("e"), + }, + }, + + { + name: "add", + fsSlice: ` +- path: a/b/c/d + group: foo + create: true + kind: Bar +`, + input: ` +apiVersion: foo/v1beta1 +kind: Bar +a: {} +`, + expected: ` +apiVersion: foo/v1beta1 +kind: Bar +a: {b: {c: {d: e}}} +`, + filter: fsslice.Filter{ + SetValue: fsslice.SetScalar("e"), + CreateKind: yaml.ScalarNode, + }, + }, + + { + name: "update-in-sequence", + fsSlice: ` +- path: a/b[]/c/d + group: foo + kind: Bar +`, + input: ` +apiVersion: foo/v1beta1 +kind: Bar +a: + b: + - c: + d: a +`, + expected: ` +apiVersion: foo/v1beta1 +kind: Bar +a: + b: + - c: + d: e +`, + filter: fsslice.Filter{ + SetValue: fsslice.SetScalar("e"), + }, + }, + + // Don't create a sequence + { + name: "empty-sequence-no-create", + fsSlice: ` +- path: a/b[]/c/d + group: foo + create: true + kind: Bar +`, + input: ` +apiVersion: foo/v1beta1 +kind: Bar +a: {} +`, + expected: ` +apiVersion: foo/v1beta1 +kind: Bar +a: {} +`, + filter: fsslice.Filter{ + SetValue: fsslice.SetScalar("e"), + CreateKind: yaml.ScalarNode, + }, + }, + + // Create a new field for an element in a sequence + { + name: "empty-sequence-create", + fsSlice: ` +- path: a/b[]/c/d + group: foo + create: true + kind: Bar +`, + input: ` +apiVersion: foo/v1beta1 +kind: Bar +a: + b: + - c: {} +`, + expected: ` +apiVersion: foo/v1beta1 +kind: Bar +a: + b: + - c: {d: e} +`, + filter: fsslice.Filter{ + SetValue: fsslice.SetScalar("e"), + CreateKind: yaml.ScalarNode, + }, + }, +} + +func TestFilter_Filter(t *testing.T) { + for i := range tests { + test := tests[i] + t.Run(test.name, func(t *testing.T) { + err := yaml.Unmarshal([]byte(test.fsSlice), &test.filter.FsSlice) + if !assert.NoError(t, err) { + t.FailNow() + } + + out := &bytes.Buffer{} + rw := &kio.ByteReadWriter{ + Reader: bytes.NewBufferString(test.input), + Writer: out, + OmitReaderAnnotations: true, + } + + // run the filter + err = kio.Pipeline{ + Inputs: []kio.Reader{rw}, + Filters: []kio.Filter{kio.FilterAll(test.filter)}, + Outputs: []kio.Writer{rw}, + }.Execute() + if test.error != "" { + if !assert.EqualError(t, err, test.error) { + t.FailNow() + } + // stop rest of test + return + } + + if !assert.NoError(t, err) { + t.FailNow() + } + + // check results + if !assert.Equal(t, + strings.TrimSpace(test.expected), + strings.TrimSpace(out.String())) { + t.FailNow() + } + }) + } +} + +func TestGetGVK(t *testing.T) { + obj, err := yaml.Parse(` +apiVersion: apps/v1 +kind: Deployment +`) + if !assert.NoError(t, err) { + t.FailNow() + } + meta, err := obj.GetMeta() + if !assert.NoError(t, err) { + t.FailNow() + } + + gvk := fsslice.GetGVK(meta) + expected := resid.Gvk{Group: "apps", Version: "v1", Kind: "Deployment"} + if !assert.Equal(t, expected, gvk) { + t.FailNow() + } +} From 7629a03dd6b9b37deea0ff62a078e800a7d07bbd Mon Sep 17 00:00:00 2001 From: Phillip Wittrock Date: Mon, 23 Mar 2020 11:15:03 -0700 Subject: [PATCH 10/17] namespace transformer implementation using kyaml --- api/filters/namespace/doc.go | 9 + api/filters/namespace/example_test.go | 50 ++++ api/filters/namespace/namespace.go | 171 ++++++++++++++ api/filters/namespace/namespace_test.go | 298 ++++++++++++++++++++++++ 4 files changed, 528 insertions(+) create mode 100644 api/filters/namespace/doc.go create mode 100644 api/filters/namespace/example_test.go create mode 100644 api/filters/namespace/namespace.go create mode 100644 api/filters/namespace/namespace_test.go diff --git a/api/filters/namespace/doc.go b/api/filters/namespace/doc.go new file mode 100644 index 000000000..539758b28 --- /dev/null +++ b/api/filters/namespace/doc.go @@ -0,0 +1,9 @@ +// Copyright 2020 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +// Package namespace contains a kio.Filter implementation of the kustomize +// namespace transformer. +// +// Special cases for known Kubernetes resources have been hardcoded in addition +// to those defined by the FsSlice. +package namespace diff --git a/api/filters/namespace/example_test.go b/api/filters/namespace/example_test.go new file mode 100644 index 000000000..04afc314e --- /dev/null +++ b/api/filters/namespace/example_test.go @@ -0,0 +1,50 @@ +// Copyright 2020 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package namespace_test + +import ( + "bytes" + "log" + "os" + + "sigs.k8s.io/kustomize/api/filters/namespace" + "sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig" + "sigs.k8s.io/kustomize/kyaml/kio" +) + +func ExampleFilter() { + fss := builtinconfig.MakeDefaultConfig().NameSpace + err := kio.Pipeline{ + Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + name: instance + namespace: bar +`)}}, + Filters: []kio.Filter{namespace.Filter{Namespace: "app", FsSlice: fss}}, + Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}}, + }.Execute() + if err != nil { + log.Fatal(err) + } + + // Output: + // apiVersion: example.com/v1 + // kind: Foo + // metadata: + // name: instance + // namespace: app + // --- + // apiVersion: example.com/v1 + // kind: Bar + // metadata: + // name: instance + // namespace: app +} diff --git a/api/filters/namespace/namespace.go b/api/filters/namespace/namespace.go new file mode 100644 index 000000000..34bb1fe2f --- /dev/null +++ b/api/filters/namespace/namespace.go @@ -0,0 +1,171 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package namespace + +import ( + "sigs.k8s.io/kustomize/api/filters/fsslice" + "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +type Filter struct { + // Namespace is the namespace to apply to the inputs + Namespace string `yaml:"namespace,omitempty"` + + // FsSlice contains the FieldSpecs to locate the namespace field + FsSlice types.FsSlice +} + +var _ kio.Filter = Filter{} + +func (ns Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { + for i := range nodes { + if err := ns.run(nodes[i]); err != nil { + return nil, err + } + } + return nodes, nil +} + +// Run runs the filter on a single node rather than a slice +func (ns Filter) run(node *yaml.RNode) error { + // hacks for hardcoded types -- :( + if err := ns.hacks(node); err != nil { + return err + } + + // Remove the fieldspecs that are for hardcoded fields. The fieldspecs + // exist for backwards compatibility with other implementations + // of this transformation. + // This implementation of the namespace transformation + // Does not use the fieldspecs for implementing cases which + // require hardcoded logic. + ns.FsSlice = ns.removeFieldSpecsForHacks(ns.FsSlice) + + // transformations based on data -- :) + return node.PipeE(fsslice.Filter{ + FsSlice: ns.FsSlice, + SetValue: fsslice.SetScalar(ns.Namespace), + CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode + }) +} + +// hacks applies the namespace transforms that are hardcoded rather +// than specified through FieldSpecs. +func (ns Filter) hacks(obj *yaml.RNode) error { + meta, err := obj.GetMeta() + if err != nil { + return err + } + + if err := ns.metaNamespaceHack(obj, meta); err != nil { + return err + } + + return ns.roleBindingHack(obj, meta) +} + +// metaNamespaceHack is a hack for implementing the namespace transform +// for the metadata.namespace field on namespace scoped resources. +// namespace scoped resources are determined by NOT being present +// in a blacklist of cluster-scoped resource types (by apiVersion and kind). +// +// This hack should be updated to allow individual resources to specify +// if they are cluster scoped through either an annotation on the resources, +// or through inlined OpenAPI on the resource as a YAML comment. +func (ns Filter) metaNamespaceHack(obj *yaml.RNode, meta yaml.ResourceMeta) error { + gvk := fsslice.GetGVK(meta) + if !gvk.IsNamespaceableKind() { + return nil + } + f := fsslice.Filter{ + FsSlice: []types.FieldSpec{ + {Path: metaNamespaceField, CreateIfNotPresent: true}, + }, + SetValue: fsslice.SetScalar(ns.Namespace), + CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode + } + _, err := f.Filter(obj) + return err +} + +// roleBindingHack is a hack for implementing the namespace transform +// for RoleBinding and ClusterRoleBinding resource types. +// RoleBinding and ClusterRoleBinding have namespace set on +// elements of the "subjects" field if and only if the subject elements +// "name" is "default". Otherwise the namespace is not set. +// +// Example: +// +// kind: RoleBinding +// subjects: +// - name: "default" # this will have the namespace set +// ... +// - name: "something-else" # this will not have the namespace set +// ... +func (ns Filter) roleBindingHack(obj *yaml.RNode, meta yaml.ResourceMeta) error { + if meta.Kind != roleBindingKind && meta.Kind != clusterRoleBindingKind { + return nil + } + + // Lookup the namespace field on all elements. + // We should change the fieldspec so this isn't necessary. + obj, err := obj.Pipe(yaml.Lookup(subjectsField)) + if err != nil || yaml.IsEmpty(obj) { + return err + } + + // add the namespace to each "subject" with name: default + err = obj.VisitElements(func(o *yaml.RNode) error { + // copied from kunstruct based kustomize NamespaceTransformer plugin + // The only case we need to force the namespace + // if for the "service account". "default" is + // kind of hardcoded here for right now. + name, err := o.Pipe( + yaml.Lookup("name"), yaml.Match("default"), + ) + if err != nil || yaml.IsEmpty(name) { + return err + } + + // set the namespace for the default account + v := yaml.NewScalarRNode(ns.Namespace) + return o.PipeE( + yaml.LookupCreate(yaml.ScalarNode, "namespace"), + yaml.FieldSetter{Value: v}, + ) + }) + + return err +} + +// removeFieldSpecsForHacks removes from the list fieldspecs that +// have hardcoded implementations +func (ns Filter) removeFieldSpecsForHacks(fs types.FsSlice) types.FsSlice { + var val types.FsSlice + for i := range fs { + // implemented by metaNamespaceHack + if fs[i].Path == metaNamespaceField { + continue + } + // implemented by roleBindingHack + if fs[i].Kind == roleBindingKind && fs[i].Path == subjectsField { + continue + } + // implemented by roleBindingHack + if fs[i].Kind == clusterRoleBindingKind && fs[i].Path == subjectsField { + continue + } + val = append(val, fs[i]) + } + return val +} + +const ( + metaNamespaceField = "metadata/namespace" + subjectsField = "subjects" + roleBindingKind = "RoleBinding" + clusterRoleBindingKind = "ClusterRoleBinding" +) diff --git a/api/filters/namespace/namespace_test.go b/api/filters/namespace/namespace_test.go new file mode 100644 index 000000000..a68a394e3 --- /dev/null +++ b/api/filters/namespace/namespace_test.go @@ -0,0 +1,298 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package namespace_test + +import ( + "bytes" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "sigs.k8s.io/kustomize/api/filters/namespace" + "sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig" + "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/kio" +) + +var tests = []TestCase{ + { + name: "add", + input: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + name: instance +`, + expected: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance + namespace: foo +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + name: instance + namespace: foo +`, + filter: namespace.Filter{Namespace: "foo"}, + }, + + { + name: "add-recurse", + input: ` +apiVersion: example.com/v1 +kind: Foo +--- +apiVersion: example.com/v1 +kind: Bar +`, + expected: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + namespace: foo +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + namespace: foo +`, + filter: namespace.Filter{Namespace: "foo"}, + }, + + { + name: "update", + input: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance + # update this namespace + namespace: bar +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + name: instance + namespace: bar +`, + expected: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance + # update this namespace + namespace: foo +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + name: instance + namespace: foo +`, + filter: namespace.Filter{Namespace: "foo"}, + }, + + { + name: "update-rolebinding", + input: ` +apiVersion: example.com/v1 +kind: RoleBinding +subjects: +- name: default +--- +apiVersion: example.com/v1 +kind: RoleBinding +subjects: +- name: default + namespace: foo +--- +apiVersion: example.com/v1 +kind: RoleBinding +subjects: +- name: something +--- +apiVersion: example.com/v1 +kind: RoleBinding +subjects: +- name: something + namespace: foo +`, + expected: ` +apiVersion: example.com/v1 +kind: RoleBinding +subjects: +- name: default + namespace: bar +metadata: + namespace: bar +--- +apiVersion: example.com/v1 +kind: RoleBinding +subjects: +- name: default + namespace: bar +metadata: + namespace: bar +--- +apiVersion: example.com/v1 +kind: RoleBinding +subjects: +- name: something +metadata: + namespace: bar +--- +apiVersion: example.com/v1 +kind: RoleBinding +subjects: +- name: something + namespace: foo +metadata: + namespace: bar +`, + filter: namespace.Filter{Namespace: "bar"}, + }, + + { + name: "update-clusterrolebinding", + input: ` +apiVersion: example.com/v1 +kind: ClusterRoleBinding +subjects: +- name: default +--- +apiVersion: example.com/v1 +kind: ClusterRoleBinding +subjects: +- name: default + namespace: foo +--- +apiVersion: example.com/v1 +kind: ClusterRoleBinding +subjects: +- name: something +--- +apiVersion: example.com/v1 +kind: ClusterRoleBinding +subjects: +- name: something + namespace: foo +`, + expected: ` +apiVersion: example.com/v1 +kind: ClusterRoleBinding +subjects: +- name: default + namespace: bar +--- +apiVersion: example.com/v1 +kind: ClusterRoleBinding +subjects: +- name: default + namespace: bar +--- +apiVersion: example.com/v1 +kind: ClusterRoleBinding +subjects: +- name: something +--- +apiVersion: example.com/v1 +kind: ClusterRoleBinding +subjects: +- name: something + namespace: foo +`, + filter: namespace.Filter{Namespace: "bar"}, + }, + + { + name: "data-fieldspecs", + input: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + name: instance +`, + expected: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance + namespace: foo +a: + b: + c: foo +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + name: instance + namespace: foo +a: + b: + c: foo +`, + filter: namespace.Filter{Namespace: "foo"}, + fsslice: []types.FieldSpec{ + { + Path: "a/b/c", + CreateIfNotPresent: true, + }, + }, + }, +} + +type TestCase struct { + name string + input string + expected string + filter namespace.Filter + fsslice types.FsSlice +} + +var config = builtinconfig.MakeDefaultConfig() + +func TestNamespace_Filter(t *testing.T) { + for i := range tests { + test := tests[i] + t.Run(test.name, func(t *testing.T) { + test.filter.FsSlice = append(config.NameSpace, test.fsslice...) + + out := &bytes.Buffer{} + rw := &kio.ByteReadWriter{ + Reader: bytes.NewBufferString(test.input), + Writer: out, + } + + // run the filter + err := kio.Pipeline{ + Inputs: []kio.Reader{rw}, + Filters: []kio.Filter{test.filter}, + Outputs: []kio.Writer{rw}, + }.Execute() + if !assert.NoError(t, err) { + t.FailNow() + } + + // check results + if !assert.Equal(t, + strings.TrimSpace(test.expected), + strings.TrimSpace(out.String())) { + t.FailNow() + } + }) + } +} From d41df982c55784eb55df73369320943a2b1bbc87 Mon Sep 17 00:00:00 2001 From: Phillip Wittrock Date: Mon, 23 Mar 2020 11:19:35 -0700 Subject: [PATCH 11/17] Util functions for kyaml <-> kunstruct compatibility --- api/filters/filtersutil/filtersutil.go | 77 +++++++++++++++++++++ api/filters/filtersutil/filtersutil_test.go | 60 ++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 api/filters/filtersutil/filtersutil.go create mode 100644 api/filters/filtersutil/filtersutil_test.go diff --git a/api/filters/filtersutil/filtersutil.go b/api/filters/filtersutil/filtersutil.go new file mode 100644 index 000000000..e238f7bc0 --- /dev/null +++ b/api/filters/filtersutil/filtersutil.go @@ -0,0 +1,77 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package filtersutil + +import ( + "encoding/json" + + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +// ApplyToJSON applies the filter to the json objects. +func ApplyToJSON(filter kio.Filter, objs ...marshalerUnmarshaler) error { + var nodes []*yaml.RNode + for i := range objs { + node, err := getRNode(objs[i]) + if err != nil { + return err + } + nodes = append(nodes, node) + l, err := filter.Filter([]*yaml.RNode{node}) + if err != nil { + return err + } + err = setRNode(objs[i], l[0]) + if err != nil { + return err + } + } + + _, err := filter.Filter(nodes) + if err != nil { + return err + } + + for i := range nodes { + err = setRNode(objs[i], nodes[i]) + if err != nil { + return err + } + } + + return nil +} + +type marshalerUnmarshaler interface { + json.Unmarshaler + json.Marshaler +} + +// getRNode converts k into an RNode +func getRNode(k json.Marshaler) (*yaml.RNode, error) { + j, err := k.MarshalJSON() + if err != nil { + return nil, err + } + return yaml.Parse(string(j)) +} + +// setRNode marshals node into k +func setRNode(k json.Unmarshaler, node *yaml.RNode) error { + s, err := node.String() + if err != nil { + return err + } + m := map[string]interface{}{} + if err := yaml.Unmarshal([]byte(s), &m); err != nil { + return err + } + + b, err := json.Marshal(m) + if err != nil { + return err + } + return k.UnmarshalJSON(b) +} diff --git a/api/filters/filtersutil/filtersutil_test.go b/api/filters/filtersutil/filtersutil_test.go new file mode 100644 index 000000000..97471e25e --- /dev/null +++ b/api/filters/filtersutil/filtersutil_test.go @@ -0,0 +1,60 @@ +package filtersutil_test + +import ( + "bytes" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "sigs.k8s.io/kustomize/api/filters/filtersutil" + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +func TestApplyToJSON(t *testing.T) { + instance1 := bytes.NewBufferString(`{"kind": "Foo"}`) + instance2 := bytes.NewBufferString(`{"kind": "Bar"}`) + err := filtersutil.ApplyToJSON( + kio.FilterFunc(func(nodes []*yaml.RNode) ([]*yaml.RNode, error) { + for i := range nodes { + set := yaml.SetField( + "foo", yaml.NewScalarRNode("bar")) + node := nodes[i] + err := node.PipeE(set) + if !assert.NoError(t, err) { + t.FailNow() + } + } + return nodes, nil + }), buffer{Buffer: instance1}, buffer{Buffer: instance2}, + ) + if !assert.NoError(t, err) { + t.FailNow() + } + + if !assert.Equal(t, + strings.TrimSpace(`{"foo":"bar","kind":"Foo"}`), + strings.TrimSpace(instance1.String())) { + t.FailNow() + } + + if !assert.Equal(t, + strings.TrimSpace(`{"foo":"bar","kind":"Bar"}`), + strings.TrimSpace(instance2.String())) { + t.FailNow() + } +} + +type buffer struct { + *bytes.Buffer +} + +func (buff buffer) UnmarshalJSON(b []byte) error { + buff.Reset() + buff.Write(b) + return nil +} + +func (buff buffer) MarshalJSON() ([]byte, error) { + return buff.Bytes(), nil +} From 81bbd2f2e30f7289b5900ac4dc623d99c601693f Mon Sep 17 00:00:00 2001 From: Phillip Wittrock Date: Mon, 23 Mar 2020 11:15:22 -0700 Subject: [PATCH 12/17] Enable using kyaml namespace transformer in builtin plugin --- api/builtins/NamespaceTransformer.go | 29 +++++++++++++++---- .../NamespaceTransformer.go | 29 +++++++++++++++---- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/api/builtins/NamespaceTransformer.go b/api/builtins/NamespaceTransformer.go index 1e8804e66..f4c4dbc17 100644 --- a/api/builtins/NamespaceTransformer.go +++ b/api/builtins/NamespaceTransformer.go @@ -6,6 +6,8 @@ package builtins import ( "fmt" + "sigs.k8s.io/kustomize/api/filters/filtersutil" + "sigs.k8s.io/kustomize/api/filters/namespace" "sigs.k8s.io/kustomize/api/transform" "sigs.k8s.io/kustomize/api/resid" @@ -19,6 +21,10 @@ import ( type NamespaceTransformerPlugin struct { types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"` + + // YAMLSupport can be set to true to use the kyaml filter instead of the + // kunstruct transformer + YAMLSupport bool } func (p *NamespaceTransformerPlugin) Config( @@ -39,12 +45,25 @@ func (p *NamespaceTransformerPlugin) Transform(m resmap.ResMap) error { } id := r.OrgId() - applicableFs := p.applicableFieldSpecs(id) - for _, fs := range applicableFs { - err := transform.MutateField( - r.Map(), fs.PathSlice(), fs.CreateIfNotPresent, - p.changeNamespace(r)) + if !p.YAMLSupport { + // use the old style transform + applicableFs := p.applicableFieldSpecs(id) + + for _, fs := range applicableFs { + err := transform.MutateField( + r.Map(), fs.PathSlice(), fs.CreateIfNotPresent, + p.changeNamespace(r)) + if err != nil { + return err + } + } + } else { + // use the new style transform + err := filtersutil.ApplyToJSON(namespace.Filter{ + Namespace: p.Namespace, + FsSlice: p.FieldSpecs, + }, r.Kunstructured) if err != nil { return err } diff --git a/plugin/builtin/namespacetransformer/NamespaceTransformer.go b/plugin/builtin/namespacetransformer/NamespaceTransformer.go index 3c5720cb3..53e2d7ef5 100644 --- a/plugin/builtin/namespacetransformer/NamespaceTransformer.go +++ b/plugin/builtin/namespacetransformer/NamespaceTransformer.go @@ -7,6 +7,8 @@ package main import ( "fmt" + "sigs.k8s.io/kustomize/api/filters/filtersutil" + "sigs.k8s.io/kustomize/api/filters/namespace" "sigs.k8s.io/kustomize/api/transform" "sigs.k8s.io/kustomize/api/resid" @@ -20,6 +22,10 @@ import ( type plugin struct { types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"` + + // YAMLSupport can be set to true to use the kyaml filter instead of the + // kunstruct transformer + YAMLSupport bool } //noinspection GoUnusedGlobalVariable @@ -43,12 +49,25 @@ func (p *plugin) Transform(m resmap.ResMap) error { } id := r.OrgId() - applicableFs := p.applicableFieldSpecs(id) - for _, fs := range applicableFs { - err := transform.MutateField( - r.Map(), fs.PathSlice(), fs.CreateIfNotPresent, - p.changeNamespace(r)) + if !p.YAMLSupport { + // use the old style transform + applicableFs := p.applicableFieldSpecs(id) + + for _, fs := range applicableFs { + err := transform.MutateField( + r.Map(), fs.PathSlice(), fs.CreateIfNotPresent, + p.changeNamespace(r)) + if err != nil { + return err + } + } + } else { + // use the new style transform + err := filtersutil.ApplyToJSON(namespace.Filter{ + Namespace: p.Namespace, + FsSlice: p.FieldSpecs, + }, r.Kunstructured) if err != nil { return err } From 85e9779bd6d44a376073a7edbb60932d50d7426b Mon Sep 17 00:00:00 2001 From: Phillip Wittrock Date: Tue, 24 Mar 2020 11:18:46 -0700 Subject: [PATCH 13/17] Refactor container functions --- kyaml/kio/filters/container.go | 78 +----------------------- kyaml/kio/filters/container_test.go | 4 +- kyaml/kio/filters/functiontypes.go | 94 +++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 78 deletions(-) create mode 100644 kyaml/kio/filters/functiontypes.go diff --git a/kyaml/kio/filters/container.go b/kyaml/kio/filters/container.go index 6602a08c4..6e3dee11f 100644 --- a/kyaml/kio/filters/container.go +++ b/kyaml/kio/filters/container.go @@ -389,85 +389,13 @@ type IsReconcilerFilter struct { func (c *IsReconcilerFilter) Filter(inputs []*yaml.RNode) ([]*yaml.RNode, error) { var out []*yaml.RNode for i := range inputs { - isContainerResource := GetFunctionSpec(inputs[i]) != nil - if isContainerResource && !c.ExcludeReconcilers { + isFnResource := GetFunctionSpec(inputs[i]) != nil + if isFnResource && !c.ExcludeReconcilers { out = append(out, inputs[i]) } - if !isContainerResource && c.IncludeNonReconcilers { + if !isFnResource && c.IncludeNonReconcilers { out = append(out, inputs[i]) } } return out, nil } - -const ( - FunctionAnnotationKey = "config.kubernetes.io/function" - oldFunctionAnnotationKey = "config.k8s.io/function" -) - -var functionAnnotationKeys = []string{FunctionAnnotationKey, oldFunctionAnnotationKey} - -// getFunction parses the config function from the object if it is found -func getFunction(n *yaml.RNode, meta yaml.ResourceMeta) *FunctionSpec { - var fs FunctionSpec - for _, s := range functionAnnotationKeys { - fn := meta.Annotations[s] - if fn != "" { - _ = yaml.Unmarshal([]byte(fn), &fs) - return &fs - } - } - n, err := n.Pipe(yaml.Lookup("metadata", "configFn")) - if err != nil || yaml.IsEmpty(n) { - return nil - } - s, err := n.String() - if err != nil { - return nil - } - _ = yaml.Unmarshal([]byte(s), &fs) - return &fs -} - -type ContainerSpec struct { - Image string `json:"image,omitempty" yaml:"image,omitempty"` - Network ContainerNetwork `json:"network,omitempty" yaml:"network,omitempty"` -} - -type FunctionSpec struct { - Path string `json:"path,omitempty" yaml:"path,omitempty"` - Network string `json:"network,omitempty" yaml:"network,omitempty"` - Container ContainerSpec `json:"container,omitempty" yaml:"container,omitempty"` -} - -type ContainerNetwork struct { - Required bool `json:"required,omitempty" yaml:"required,omitempty"` -} - -// GetFunctionSpec returns the FunctionSpec for a resource. Returns -// nil if the resource does not have a FunctionSpec. -// -// The FunctionSpec is read from the resource metadata.annotation -// "config.kubernetes.io/function" -func GetFunctionSpec(n *yaml.RNode) *FunctionSpec { - meta, err := n.GetMeta() - if err != nil { - return nil - } - - // path to the function, this will be mounted into the container - path := meta.Annotations[kioutil.PathAnnotation] - if fn := getFunction(n, meta); fn != nil { - fn.Network = "" - fn.Path = path - return fn - } - - // legacy function specification for backwards compatibility - container := meta.Annotations["config.kubernetes.io/container"] - if container != "" { - return &FunctionSpec{ - Path: path, Container: ContainerSpec{Image: container}} - } - return nil -} diff --git a/kyaml/kio/filters/container_test.go b/kyaml/kio/filters/container_test.go index bc5b35721..3ae8d901a 100644 --- a/kyaml/kio/filters/container_test.go +++ b/kyaml/kio/filters/container_test.go @@ -511,9 +511,7 @@ metadata: if !assert.NoError(t, err) { return } - - meta, _ := cfg.GetMeta() - fn := getFunction(cfg, meta) + fn := GetFunctionSpec(cfg) assert.Equal(t, tc.required, fn.Container.Network.Required) } } diff --git a/kyaml/kio/filters/functiontypes.go b/kyaml/kio/filters/functiontypes.go new file mode 100644 index 000000000..825a5f709 --- /dev/null +++ b/kyaml/kio/filters/functiontypes.go @@ -0,0 +1,94 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package filters + +import ( + "sigs.k8s.io/kustomize/kyaml/kio/kioutil" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +const ( + FunctionAnnotationKey = "config.kubernetes.io/function" + oldFunctionAnnotationKey = "config.k8s.io/function" +) + +var functionAnnotationKeys = []string{FunctionAnnotationKey, oldFunctionAnnotationKey} + +// FunctionSpec defines a spec for running a function +type FunctionSpec struct { + // Path defines the path for scoped functions + Path string `json:"path,omitempty" yaml:"path,omitempty"` + + // Network is the name of the network to use from a container + Network string `json:"network,omitempty" yaml:"network,omitempty"` + + // Container is the spec for running a function as a container + Container ContainerSpec `json:"container,omitempty" yaml:"container,omitempty"` +} + +// ContainerSpec defines a spec for running a function as a container +type ContainerSpec struct { + // Image is the container image to run + Image string `json:"image,omitempty" yaml:"image,omitempty"` + + // Network defines network specific configuration + Network ContainerNetwork `json:"network,omitempty" yaml:"network,omitempty"` +} + +// ContainerNetwork +type ContainerNetwork struct { + // Required specifies that function requires a network + Required bool `json:"required,omitempty" yaml:"required,omitempty"` +} + +// GetFunctionSpec returns the FunctionSpec for a resource. Returns +// nil if the resource does not have a FunctionSpec. +// +// The FunctionSpec is read from the resource metadata.annotation +// "config.kubernetes.io/function" +func GetFunctionSpec(n *yaml.RNode) *FunctionSpec { + meta, err := n.GetMeta() + if err != nil { + return nil + } + + // path to the function, this will be mounted into the container + path := meta.Annotations[kioutil.PathAnnotation] + if fn := getFunctionSpecFromAnnotation(n, meta); fn != nil { + fn.Network = "" + fn.Path = path + return fn + } + + // legacy function specification for backwards compatibility + container := meta.Annotations["config.kubernetes.io/container"] + if container != "" { + return &FunctionSpec{ + Path: path, Container: ContainerSpec{Image: container}} + } + return nil +} + +// getFunctionSpecFromAnnotation parses the config function from an annotation +// if it is found +func getFunctionSpecFromAnnotation(n *yaml.RNode, meta yaml.ResourceMeta) *FunctionSpec { + var fs FunctionSpec + for _, s := range functionAnnotationKeys { + fn := meta.Annotations[s] + if fn != "" { + _ = yaml.Unmarshal([]byte(fn), &fs) + return &fs + } + } + n, err := n.Pipe(yaml.Lookup("metadata", "configFn")) + if err != nil || yaml.IsEmpty(n) { + return nil + } + s, err := n.String() + if err != nil { + return nil + } + _ = yaml.Unmarshal([]byte(s), &fs) + return &fs +} From 7164e558315f0f5e891361359fd2d914fde0da19 Mon Sep 17 00:00:00 2001 From: Phillip Wittrock Date: Tue, 24 Mar 2020 20:12:39 -0700 Subject: [PATCH 14/17] Allow functions to enable the starlark filter (off by default) --- cmd/config/go.sum | 2 + cmd/config/internal/commands/run-fns.go | 106 ++++++++++++++++------- cmd/config/internal/commands/run_test.go | 38 ++++++++ kyaml/kio/filters/functiontypes.go | 11 +++ kyaml/runfn/runfn.go | 26 ++++-- kyaml/runfn/runfn_test.go | 65 ++++++++++++++ kyaml/starlark/starlark.go | 4 + 7 files changed, 215 insertions(+), 37 deletions(-) diff --git a/cmd/config/go.sum b/cmd/config/go.sum index 020858148..ae5ecee22 100644 --- a/cmd/config/go.sum +++ b/cmd/config/go.sum @@ -109,6 +109,7 @@ github.com/posener/complete/v2 v2.0.1-alpha.12 h1:0wvkuDfHb5vSZlNBYgpEH4XQHpF46M github.com/posener/complete/v2 v2.0.1-alpha.12/go.mod h1://JlL91cS2JV7rOl6LVHrRqBXoBUecJu3ILQPgbJiMQ= github.com/posener/script v1.0.4 h1:nSuXW5ZdmFnQIueLB2s0qvs4oNsUloM1Zydzh75v42w= github.com/posener/script v1.0.4/go.mod h1:Rg3ijooqulo05aGLyGsHoLmIOUzHUVK19WVgrYBPU/E= +github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d h1:K6eOUihrFLdZjZnA4XlRp864fmWXv9YTIk7VPLhRacA= github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d/go.mod h1:7DPO4domFU579Ga6E61sB9VFNaniPVwJP5C4bBCu3wA= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= @@ -135,6 +136,7 @@ github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mB github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= go.starlark.net v0.0.0-20190528202925-30ae18b8564f/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/cmd/config/internal/commands/run-fns.go b/cmd/config/internal/commands/run-fns.go index 170a41d76..fe24a97fd 100644 --- a/cmd/config/internal/commands/run-fns.go +++ b/cmd/config/internal/commands/run-fns.go @@ -40,6 +40,16 @@ func GetRunFnRunner(name string) *RunFnRunner { r.Command.Flags().StringVar( &r.Image, "image", "", "run this image as a function instead of discovering them.") + r.Command.Flags().BoolVar( + &r.EnableStar, "enable-star", false, "enable support for starlark functions.") + r.Command.Flags().MarkHidden("enable-star") + r.Command.Flags().StringVar( + &r.StarPath, "star-path", "", "run a starlark script as a function.") + r.Command.Flags().MarkHidden("star-path") + r.Command.Flags().StringVar( + &r.StarName, "star-name", "", "name of starlark program.") + r.Command.Flags().MarkHidden("star-name") + r.Command.Flags().BoolVar( &r.Network, "network", false, "enable network access for functions that declare it") r.Command.Flags().StringVar( @@ -59,6 +69,9 @@ type RunFnRunner struct { GlobalScope bool FnPaths []string Image string + EnableStar bool + StarPath string + StarName string RunFns runfn.RunFns Network bool NetworkName string @@ -68,34 +81,61 @@ func (r *RunFnRunner) runE(c *cobra.Command, args []string) error { return handleError(c, r.RunFns.Execute()) } -// getFunctions parses the commandline flags and arguments into explicit +// getContainerFunctions parses the commandline flags and arguments into explicit // Functions to run. -func (r *RunFnRunner) getFunctions(c *cobra.Command, args, dataItems []string) ( +func (r *RunFnRunner) getContainerFunctions(c *cobra.Command, args, dataItems []string) ( []*yaml.RNode, error) { - // if image isn't specified, then Functions is empty - if r.Image == "" { + if r.Image == "" && r.StarPath == "" { return nil, nil } - // create the function spec to set as an annotation - fn, err := yaml.Parse(`container: {}`) - if err != nil { - return nil, err - } - // TODO: add support network, volumes, etc based on flag values - err = fn.PipeE( - yaml.Lookup("container"), - yaml.SetField("image", yaml.NewScalarRNode(r.Image))) - if err != nil { - return nil, err - } - if r.Network { - err = fn.PipeE( - yaml.LookupCreate(yaml.MappingNode, "container", "network"), - yaml.SetField("required", yaml.NewScalarRNode("true"))) + var fn *yaml.RNode + var err error + + // if image isn't specified, then Functions is empty + if r.Image != "" { + // create the function spec to set as an annotation + fn, err = yaml.Parse(`container: {}`) if err != nil { return nil, err } + // TODO: add support network, volumes, etc based on flag values + err = fn.PipeE( + yaml.Lookup("container"), + yaml.SetField("image", yaml.NewScalarRNode(r.Image))) + if err != nil { + return nil, err + } + if r.Network { + err = fn.PipeE( + yaml.LookupCreate(yaml.MappingNode, "container", "network"), + yaml.SetField("required", yaml.NewScalarRNode("true"))) + if err != nil { + return nil, err + } + } + } else if r.EnableStar && r.StarPath != "" { + // create the function spec to set as an annotation + fn, err = yaml.Parse(`starlark: {}`) + if err != nil { + return nil, err + } + + err = fn.PipeE( + yaml.Lookup("starlark"), + yaml.SetField("path", yaml.NewScalarRNode(r.StarPath))) + if err != nil { + return nil, err + } + + err = fn.PipeE( + yaml.Lookup("starlark"), + yaml.SetField("name", yaml.NewScalarRNode(r.StarName))) + if err != nil { + return nil, err + } + } else { + return nil, nil } // create the function config @@ -160,7 +200,12 @@ data: {} } func (r *RunFnRunner) preRunE(c *cobra.Command, args []string) error { - if c.ArgsLenAtDash() >= 0 && r.Image == "" { + if r.EnableStar != (r.StarPath != "") { + return errors.Errorf("must specify --star-path with --enable-star") + } + + if c.ArgsLenAtDash() >= 0 && r.Image == "" && + !(r.EnableStar && r.StarPath != "") { return errors.Errorf("must specify --image") } @@ -173,7 +218,7 @@ func (r *RunFnRunner) preRunE(c *cobra.Command, args []string) error { return errors.Errorf("0 or 1 arguments supported, function arguments go after '--'") } - fns, err := r.getFunctions(c, args, dataItems) + fns, err := r.getContainerFunctions(c, args, dataItems) if err != nil { return err } @@ -196,14 +241,15 @@ func (r *RunFnRunner) preRunE(c *cobra.Command, args []string) error { } r.RunFns = runfn.RunFns{ - FunctionPaths: r.FnPaths, - GlobalScope: r.GlobalScope, - Functions: fns, - Output: output, - Input: input, - Path: path, - Network: r.Network, - NetworkName: r.NetworkName, + FunctionPaths: r.FnPaths, + GlobalScope: r.GlobalScope, + Functions: fns, + Output: output, + Input: input, + Path: path, + Network: r.Network, + NetworkName: r.NetworkName, + EnableStarlark: r.EnableStar, } // don't consider args for the function diff --git a/cmd/config/internal/commands/run_test.go b/cmd/config/internal/commands/run_test.go index aef76dbee..4a2062072 100644 --- a/cmd/config/internal/commands/run_test.go +++ b/cmd/config/internal/commands/run_test.go @@ -154,6 +154,44 @@ kind: Foo apiVersion: v1 `, }, + { + name: "star", + args: []string{"run", "dir", + "--enable-star", + "--star-path", "a/b/c", + "--star-name", "foo", + "--", "Foo", "g=h"}, + path: "dir", + expected: ` +metadata: + name: function-input + annotations: + config.kubernetes.io/function: | + starlark: {path: a/b/c, name: foo} +data: {g: h} +kind: Foo +apiVersion: v1 +`, + }, + { + name: "star-not-enabled", + args: []string{"run", "dir", + "--star-path", "a/b/c", + "--star-name", "foo", + "--", "Foo", "g=h"}, + path: "dir", + err: "must specify --star-path with --enable-star", + }, + { + name: "image-star-not-enabled", + args: []string{"run", "dir", + "--image", "some_image", + "--star-path", "a/b/c", + "--star-name", "foo", + "--", "Foo", "g=h"}, + path: "dir", + err: "must specify --star-path with --enable-star", + }, { name: "function paths", args: []string{"run", "dir", "--fn-path", "path1", "--fn-path", "path2"}, diff --git a/kyaml/kio/filters/functiontypes.go b/kyaml/kio/filters/functiontypes.go index 825a5f709..83f6f647c 100644 --- a/kyaml/kio/filters/functiontypes.go +++ b/kyaml/kio/filters/functiontypes.go @@ -25,6 +25,9 @@ type FunctionSpec struct { // Container is the spec for running a function as a container Container ContainerSpec `json:"container,omitempty" yaml:"container,omitempty"` + + // Starlark is the spec for running a function as a starlark script + Starlark StarlarkSpec `json:"starlark,omitempty" yaml:"starlark,omitempty"` } // ContainerSpec defines a spec for running a function as a container @@ -42,6 +45,14 @@ type ContainerNetwork struct { Required bool `json:"required,omitempty" yaml:"required,omitempty"` } +// StarlarkSpec defines how to run a function as a starlark program +type StarlarkSpec struct { + Name string `json:"name,omitempty" yaml:"name,omitempty"` + + // Path specifies a path to a starlark script + Path string `json:"path,omitempty" yaml:"path,omitempty"` +} + // GetFunctionSpec returns the FunctionSpec for a resource. Returns // nil if the resource does not have a FunctionSpec. // diff --git a/kyaml/runfn/runfn.go b/kyaml/runfn/runfn.go index ac45f080b..19d348486 100644 --- a/kyaml/runfn/runfn.go +++ b/kyaml/runfn/runfn.go @@ -15,6 +15,7 @@ import ( "sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio/filters" "sigs.k8s.io/kustomize/kyaml/kio/kioutil" + "sigs.k8s.io/kustomize/kyaml/starlark" "sigs.k8s.io/kustomize/kyaml/yaml" ) @@ -57,6 +58,12 @@ type RunFns struct { // and only use explicit sources NoFunctionsFromInput *bool + // EnableStarlark will enable functions run as starlark scripts + EnableStarlark bool + + // DisableContainers will disable functions run as containers + DisableContainers bool + // functionFilterProvider provides a filter to perform the function. // this is a variable so it can be mocked in tests functionFilterProvider func( @@ -208,8 +215,10 @@ func (r RunFns) getFunctionFilters(global bool, fns ...*yaml.RNode) ( } spec.Network = r.NetworkName } - c := r.functionFilterProvider(*spec, api) + if c == nil { + continue + } cf, ok := c.(*filters.ContainerFilter) if global && ok { cf.GlobalScope = true @@ -291,7 +300,7 @@ func (r *RunFns) init() { // ffp provides function filters func (r *RunFns) ffp(spec filters.FunctionSpec, api *yaml.RNode) kio.Filter { - if spec.Container.Image != "" { + if !r.DisableContainers && spec.Container.Image != "" { return &filters.ContainerFilter{ Image: spec.Container.Image, Config: api, @@ -300,9 +309,12 @@ func (r *RunFns) ffp(spec filters.FunctionSpec, api *yaml.RNode) kio.Filter { GlobalScope: r.GlobalScope, } } - return noOpFilter + if r.EnableStarlark && spec.Starlark.Path != "" { + return &starlark.Filter{ + Name: spec.Starlark.Name, + Path: spec.Starlark.Path, + FunctionConfig: api, + } + } + return nil } - -var noOpFilter = kio.FilterFunc(func(in []*yaml.RNode) ([]*yaml.RNode, error) { - return in, nil -}) diff --git a/kyaml/runfn/runfn_test.go b/kyaml/runfn/runfn_test.go index b11818dc7..f88349194 100644 --- a/kyaml/runfn/runfn_test.go +++ b/kyaml/runfn/runfn_test.go @@ -190,6 +190,10 @@ func TestRunFns_getFilters(t *testing.T) { name string // value to set for NoFunctionsFromInput noFunctionsFromInput *bool + + enableStarlark bool + + disableContainers bool }{ // Test // @@ -213,6 +217,26 @@ metadata: out: []string{"gcr.io/example.com/image:v1.0.0"}, }, + {name: "disable containers", + in: []f{ + { + path: filepath.Join("foo", "bar.yaml"), + value: ` +apiVersion: example.com/v1alpha1 +kind: ExampleFunction +metadata: + annotations: + config.kubernetes.io/function: | + container: + image: gcr.io/example.com/image:v1.0.0 + config.kubernetes.io/local-config: "true" +`, + }, + }, + out: nil, + disableContainers: true, + }, + // Test // // @@ -432,6 +456,45 @@ metadata: }, out: []string{"b", "a", "c"}, }, + + // Test + // + // + {name: "starlark-function", + in: []f{ + { + path: filepath.Join("foo", "bar.yaml"), + value: ` +apiVersion: example.com/v1alpha1 +kind: ExampleFunction +metadata: + annotations: + config.kubernetes.io/function: | + starlark: + path: a/b/c +`, + }, + }, + enableStarlark: true, + out: []string{"name: path: a/b/c url: program:"}, + }, + + {name: "starlark-function-disabled", + in: []f{ + { + path: filepath.Join("foo", "bar.yaml"), + value: ` +apiVersion: example.com/v1alpha1 +kind: ExampleFunction +metadata: + annotations: + config.kubernetes.io/function: | + starlark: + path: a/b/c +`, + }, + }, + }, } for i := range tests { @@ -484,6 +547,8 @@ metadata: // init the instance r := &RunFns{ + EnableStarlark: tt.enableStarlark, + DisableContainers: tt.disableContainers, FunctionPaths: fnPaths, Functions: parsedFns, Path: d, diff --git a/kyaml/starlark/starlark.go b/kyaml/starlark/starlark.go index b855098dd..c503e2203 100644 --- a/kyaml/starlark/starlark.go +++ b/kyaml/starlark/starlark.go @@ -35,6 +35,10 @@ type Filter struct { FunctionConfig *yaml.RNode } +func (sf *Filter) String() string { + return fmt.Sprintf("name: %v path: %v url: %v program: %v", sf.Name, sf.Path, sf.URL, sf.Program) +} + func (sf *Filter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) { if sf.URL != "" && sf.Path != "" || sf.URL != "" && sf.Program != "" || From f39f28d38f895a2cc466e530b9885e7e05b6657e Mon Sep 17 00:00:00 2001 From: Morten Torkildsen Date: Wed, 25 Mar 2020 20:25:43 -0700 Subject: [PATCH 15/17] Add annotations filter based on kyaml libraries --- api/builtins/AnnotationsTransformer.go | 33 ++- api/filters/annotations/annotations.go | 44 ++++ api/filters/annotations/annotations_test.go | 246 ++++++++++++++++++ api/filters/annotations/doc.go | 6 + api/filters/annotations/example_test.go | 55 ++++ .../AnnotationsTransformer.go | 33 ++- plugin/builtin/annotationstransformer/go.mod | 5 +- plugin/builtin/annotationstransformer/go.sum | 35 ++- 8 files changed, 433 insertions(+), 24 deletions(-) create mode 100644 api/filters/annotations/annotations.go create mode 100644 api/filters/annotations/annotations_test.go create mode 100644 api/filters/annotations/doc.go create mode 100644 api/filters/annotations/example_test.go diff --git a/api/builtins/AnnotationsTransformer.go b/api/builtins/AnnotationsTransformer.go index ebb433163..a9f42d2df 100644 --- a/api/builtins/AnnotationsTransformer.go +++ b/api/builtins/AnnotationsTransformer.go @@ -4,6 +4,8 @@ package builtins import ( + "sigs.k8s.io/kustomize/api/filters/annotations" + "sigs.k8s.io/kustomize/api/filters/filtersutil" "sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/transform" "sigs.k8s.io/kustomize/api/types" @@ -14,6 +16,10 @@ import ( type AnnotationsTransformerPlugin struct { Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"` FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"` + + // YAMLSupport can be set to true to use the kyaml filter instead of the + // kunstruct transformer + YAMLSupport bool } func (p *AnnotationsTransformerPlugin) Config( @@ -24,14 +30,27 @@ func (p *AnnotationsTransformerPlugin) Config( } func (p *AnnotationsTransformerPlugin) Transform(m resmap.ResMap) error { - t, err := transform.NewMapTransformer( - p.FieldSpecs, - p.Annotations, - ) - if err != nil { - return err + if p.YAMLSupport { + for _, r := range m.Resources() { + err := filtersutil.ApplyToJSON(annotations.Filter{ + Annotations: p.Annotations, + FsSlice: p.FieldSpecs, + }, r.Kunstructured) + if err != nil { + return err + } + } + return nil + } else { + t, err := transform.NewMapTransformer( + p.FieldSpecs, + p.Annotations, + ) + if err != nil { + return err + } + return t.Transform(m) } - return t.Transform(m) } func NewAnnotationsTransformerPlugin() resmap.TransformerPlugin { diff --git a/api/filters/annotations/annotations.go b/api/filters/annotations/annotations.go new file mode 100644 index 000000000..d834ecd02 --- /dev/null +++ b/api/filters/annotations/annotations.go @@ -0,0 +1,44 @@ +// Copyright 2020 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package annotations + +import ( + "sigs.k8s.io/kustomize/api/filters/fsslice" + "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +type Filter struct { + // Annotations is the set of annotations to apply to the inputs + Annotations map[string]string `yaml:"annotations,omitempty"` + + // FsSlice contains the FieldSpecs to locate the namespace field + FsSlice types.FsSlice +} + +var _ kio.Filter = Filter{} + +func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { + for i := range nodes { + if err := f.run(nodes[i]); err != nil { + return nil, err + } + } + return nodes, nil +} + +// run applies the filter to a single node. +func (f Filter) run(node *yaml.RNode) error { + for key, value := range f.Annotations { + if err := node.PipeE(fsslice.Filter{ + FsSlice: f.FsSlice, + SetValue: fsslice.SetEntry(key, value), + CreateKind: yaml.MappingNode, // Annotations are MappingNodes. + }); err != nil { + return err + } + } + return nil +} diff --git a/api/filters/annotations/annotations_test.go b/api/filters/annotations/annotations_test.go new file mode 100644 index 000000000..b370f56d0 --- /dev/null +++ b/api/filters/annotations/annotations_test.go @@ -0,0 +1,246 @@ +// Copyright 2020 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package annotations + +import ( + "bytes" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig" + "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +func TestAnnotations_Filter(t *testing.T) { + testCases := map[string]struct { + input string + expectedOutput string + filter Filter + fsslice types.FsSlice + }{ + "add": { + input: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + name: instance +`, + expectedOutput: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance + annotations: + sleater: kinney +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + name: instance + annotations: + sleater: kinney +`, + filter: Filter{Annotations: map[string]string{ + "sleater": "kinney", + }}, + }, + "update": { + input: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance + annotations: + foo: foo +`, + expectedOutput: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance + annotations: + foo: bar +`, + filter: Filter{Annotations: map[string]string{ + "foo": "bar", + }}, + }, + "data-fieldspecs": { + input: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + name: instance +`, + expectedOutput: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance + annotations: + sleater: kinney +a: + b: + sleater: kinney +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + name: instance + annotations: + sleater: kinney +a: + b: + sleater: kinney +`, + filter: Filter{Annotations: map[string]string{ + "sleater": "kinney", + }}, + fsslice: []types.FieldSpec{ + { + Path: "a/b", + CreateIfNotPresent: true, + }, + }, + }, + } + + for tn, tc := range testCases { + t.Run(tn, func(t *testing.T) { + config := builtinconfig.MakeDefaultConfig() + + filter := tc.filter + filter.FsSlice = append(config.CommonAnnotations, tc.fsslice...) + + var out bytes.Buffer + rw := kio.ByteReadWriter{ + Reader: bytes.NewBufferString(tc.input), + Writer: &out, + } + + err := kio.Pipeline{ + Inputs: []kio.Reader{&rw}, + Filters: []kio.Filter{filter}, + Outputs: []kio.Writer{&rw}, + }.Execute() + if !assert.NoError(t, err) { + t.FailNow() + } + + if !assert.Equal(t, + strings.TrimSpace(tc.expectedOutput), + strings.TrimSpace(out.String())) { + t.FailNow() + } + }) + } +} + +func TestAnnotations_Filter_Multiple(t *testing.T) { + input := ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + name: instance +` + annos := map[string]string{ + "sleater": "kinney", + "sonic": "youth", + } + config := builtinconfig.MakeDefaultConfig() + filter := Filter{Annotations: annos} + filter.FsSlice = config.CommonAnnotations + + var out bytes.Buffer + rw := kio.ByteReadWriter{ + Reader: bytes.NewBufferString(input), + Writer: &out, + } + + err := kio.Pipeline{ + Inputs: []kio.Reader{&rw}, + Filters: []kio.Filter{filter}, + Outputs: []kio.Writer{&rw}, + }.Execute() + if !assert.NoError(t, err) { + t.FailNow() + } + + assertHasAnnotation(t, out.String(), annos) +} + +func assertHasAnnotation(t *testing.T, y string, exp map[string]string) bool { + var out bytes.Buffer + rw := kio.ByteReadWriter{ + Reader: bytes.NewBufferString(y), + Writer: &out, + } + filter := &captureAnnotationFilter{ + annotations: make(map[string]annotations), + } + err := kio.Pipeline{ + Inputs: []kio.Reader{&rw}, + Filters: []kio.Filter{filter}, + Outputs: []kio.Writer{&rw}, + }.Execute() + if err != nil { + t.Error(err) + return false + } + + for name, annos := range filter.annotations { + for key, val := range exp { + v, found := annos[key] + if !found { + t.Errorf("expected annotation with key %s in object %s, but didn't find it", + key, name) + return false + } + if want, got := val, v; got != want { + t.Errorf("exected annotation %s in object %s to have value %s, but found %s", + key, name, want, got) + return false + } + } + } + return true +} + +type annotations map[string]string + +type captureAnnotationFilter struct { + annotations map[string]annotations +} + +func (c captureAnnotationFilter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, + error) { + for _, n := range nodes { + meta, err := n.GetMeta() + if err != nil { + return nodes, err + } + name := meta.Name + annos := meta.Annotations + c.annotations[name] = annos + } + return nodes, nil +} diff --git a/api/filters/annotations/doc.go b/api/filters/annotations/doc.go new file mode 100644 index 000000000..b1f6a0b66 --- /dev/null +++ b/api/filters/annotations/doc.go @@ -0,0 +1,6 @@ +// Copyright 2020 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +// Package annotations contains a kio.Filter implementation of the kustomize +// annotations transformer. +package annotations diff --git a/api/filters/annotations/example_test.go b/api/filters/annotations/example_test.go new file mode 100644 index 000000000..270193496 --- /dev/null +++ b/api/filters/annotations/example_test.go @@ -0,0 +1,55 @@ +// Copyright 2020 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package annotations + +import ( + "bytes" + "log" + "os" + + "sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig" + "sigs.k8s.io/kustomize/kyaml/kio" +) + +func ExampleFilter() { + fss := builtinconfig.MakeDefaultConfig().CommonAnnotations + err := kio.Pipeline{ + Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + name: instance +`)}}, + Filters: []kio.Filter{Filter{ + Annotations: map[string]string{ + "foo": "bar", + }, + FsSlice: fss, + }}, + Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}}, + }.Execute() + if err != nil { + log.Fatal(err) + } + + // Output: + // apiVersion: example.com/v1 + // kind: Foo + // metadata: + // name: instance + // annotations: + // foo: bar + // --- + // apiVersion: example.com/v1 + // kind: Bar + // metadata: + // name: instance + // annotations: + // foo: bar +} diff --git a/plugin/builtin/annotationstransformer/AnnotationsTransformer.go b/plugin/builtin/annotationstransformer/AnnotationsTransformer.go index 1f0c6d095..dc017c40e 100644 --- a/plugin/builtin/annotationstransformer/AnnotationsTransformer.go +++ b/plugin/builtin/annotationstransformer/AnnotationsTransformer.go @@ -5,6 +5,8 @@ package main import ( + "sigs.k8s.io/kustomize/api/filters/annotations" + "sigs.k8s.io/kustomize/api/filters/filtersutil" "sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/transform" "sigs.k8s.io/kustomize/api/types" @@ -15,6 +17,10 @@ import ( type plugin struct { Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"` FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"` + + // YAMLSupport can be set to true to use the kyaml filter instead of the + // kunstruct transformer + YAMLSupport bool } //noinspection GoUnusedGlobalVariable @@ -28,12 +34,25 @@ func (p *plugin) Config( } func (p *plugin) Transform(m resmap.ResMap) error { - t, err := transform.NewMapTransformer( - p.FieldSpecs, - p.Annotations, - ) - if err != nil { - return err + if p.YAMLSupport { + for _, r := range m.Resources() { + err := filtersutil.ApplyToJSON(annotations.Filter{ + Annotations: p.Annotations, + FsSlice: p.FieldSpecs, + }, r.Kunstructured) + if err != nil { + return err + } + } + return nil + } else { + t, err := transform.NewMapTransformer( + p.FieldSpecs, + p.Annotations, + ) + if err != nil { + return err + } + return t.Transform(m) } - return t.Transform(m) } diff --git a/plugin/builtin/annotationstransformer/go.mod b/plugin/builtin/annotationstransformer/go.mod index 604a0a542..c8ee4e60c 100644 --- a/plugin/builtin/annotationstransformer/go.mod +++ b/plugin/builtin/annotationstransformer/go.mod @@ -3,7 +3,8 @@ module sigs.k8s.io/kustomize/plugin/builtin/annotationstransformer go 1.13 require ( - gopkg.in/yaml.v2 v2.2.7 // indirect - sigs.k8s.io/kustomize/api v0.3.1 + sigs.k8s.io/kustomize/api v0.0.0 sigs.k8s.io/yaml v1.1.0 ) + +replace sigs.k8s.io/kustomize/api v0.0.0 => ../../../api diff --git a/plugin/builtin/annotationstransformer/go.sum b/plugin/builtin/annotationstransformer/go.sum index bd73d90e2..71e9193fe 100644 --- a/plugin/builtin/annotationstransformer/go.sum +++ b/plugin/builtin/annotationstransformer/go.sum @@ -24,6 +24,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bombsimon/wsl v1.2.5/go.mod h1:43lEF/i0kpXbLCeDXL9LMT8c92HyBywXb0AsgMHYngM= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -54,6 +56,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -68,8 +72,8 @@ github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1 github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= -github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw= +github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= @@ -143,6 +147,12 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= +github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= @@ -168,7 +178,6 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -184,8 +193,12 @@ github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -229,6 +242,7 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d/go.mod h1:w5+eXa0mYznDkHaMCXA4XYffjlH+cy1oyKbfzJXa2Do= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= @@ -261,6 +275,8 @@ github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiff github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= +github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/uudashr/gocognit v0.0.0-20190926065955-1655d0de0517/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM= @@ -269,7 +285,11 @@ github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yujunz/go-getter v1.4.1-lite h1:FhvNc94AXMZkfqUwfMKhnQEC9phkphSGdPTL7tIdhOM= +github.com/yujunz/go-getter v1.4.1-lite/go.mod h1:sbmqxXjyLunH1PkF3n7zSlnVeMvmYUuIl9ZVs/7NyCc= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -280,7 +300,6 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -328,7 +347,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69 h1:rOhMmluY6kLMhdnrivzec6lLgaVbMHMn2ISQXJeJ5EM= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -353,7 +371,6 @@ golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -389,6 +406,8 @@ gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM= +gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= @@ -409,8 +428,8 @@ k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw= -sigs.k8s.io/kustomize/api v0.3.1 h1:oqMIXvS6tFEUVuKIRUKDa05eC4Hh+cb9JYg8Zhp2d24= -sigs.k8s.io/kustomize/api v0.3.1/go.mod h1:A+ATnlHqzictQfQC1q3KB/T6MSr0UWQsrrLxMWkge2E= +sigs.k8s.io/kustomize/kyaml v0.1.1 h1:nGUNYINljZNmlAS8uoobUv/wx/s3Pg8dNxYo+W7uYh0= +sigs.k8s.io/kustomize/kyaml v0.1.1/go.mod h1:/NdPPfrperSCGjm55cwEro1loBVtbtVIXSb7FguK6uk= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= From 06e70f74c276fb3233b888f011d5c7ae37e9f8a2 Mon Sep 17 00:00:00 2001 From: Phillip Wittrock Date: Wed, 25 Mar 2020 16:00:10 -0700 Subject: [PATCH 16/17] Utilities for working with map[string]interface{} + yaml.Node --- kyaml/filtersutil/doc.go | 6 +++ kyaml/filtersutil/example_test.go | 58 +++++++++++++++++++++ kyaml/filtersutil/filtersutil.go | 83 +++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 kyaml/filtersutil/doc.go create mode 100644 kyaml/filtersutil/example_test.go create mode 100644 kyaml/filtersutil/filtersutil.go diff --git a/kyaml/filtersutil/doc.go b/kyaml/filtersutil/doc.go new file mode 100644 index 000000000..b5cb975fa --- /dev/null +++ b/kyaml/filtersutil/doc.go @@ -0,0 +1,6 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +// Package filtersutil provides utilities for working with yaml.Filter and +// kio.Filter interfaces. +package filtersutil diff --git a/kyaml/filtersutil/example_test.go b/kyaml/filtersutil/example_test.go new file mode 100644 index 000000000..3ac6415c9 --- /dev/null +++ b/kyaml/filtersutil/example_test.go @@ -0,0 +1,58 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package filtersutil_test + +import ( + "bytes" + "fmt" + "log" + "testing" + + "github.com/stretchr/testify/assert" + "sigs.k8s.io/kustomize/kyaml/filtersutil" + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +func TestApplyToJSON(t *testing.T) { + // testFilter sets `foo: bar` on each resource + testFilter := kio.FilterAll(yaml.FilterFunc( + func(node *yaml.RNode) (*yaml.RNode, error) { + set := yaml.SetField( + "foo", yaml.NewScalarRNode("bar")) + err := node.PipeE(set) + if !assert.NoError(t, err) { + t.FailNow() + } + return node, nil + })) + + obj1 := buffer{Buffer: bytes.NewBufferString(`{"kind": "Foo"}`)} + obj2 := buffer{Buffer: bytes.NewBufferString(`{"kind": "Bar"}`)} + err := filtersutil.ApplyToJSON(testFilter, obj1, obj2) + if err != nil { + log.Fatal(err) + } + + fmt.Println(obj1.String()) + fmt.Println(obj2.String()) + + // Output: + // {"foo":"bar","kind":"Foo"} + // {"foo":"bar","kind":"Bar"} +} + +type buffer struct { + *bytes.Buffer +} + +func (buff buffer) UnmarshalJSON(b []byte) error { + buff.Reset() + buff.Write(b) + return nil +} + +func (buff buffer) MarshalJSON() ([]byte, error) { + return buff.Bytes(), nil +} diff --git a/kyaml/filtersutil/filtersutil.go b/kyaml/filtersutil/filtersutil.go new file mode 100644 index 000000000..b01f961c0 --- /dev/null +++ b/kyaml/filtersutil/filtersutil.go @@ -0,0 +1,83 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package filtersutil + +import ( + "encoding/json" + + "sigs.k8s.io/kustomize/kyaml/errors" + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +// ApplyToJSON applies the filter to the json objects. +// +// ApplyToJSON marshals the objects into a slice of yaml.RNodes, runs +// the filter on the slice, and then unmarshals the values back. +// +// The filter must not create or delete objects because the objects +// are updated in place. +func ApplyToJSON(filter kio.Filter, objs ...marshalerUnmarshaler) error { + var nodes []*yaml.RNode + + // convert the json objects to rnodes + for i := range objs { + node, err := getRNode(objs[i]) + if err != nil { + return err + } + nodes = append(nodes, node) + } + + // apply the filter + nodes, err := filter.Filter(nodes) + if err != nil { + return err + } + if len(nodes) != len(objs) { + return errors.Errorf("filter cannot create or delete objects") + } + + // convert the rnodes to json objects + for i := range nodes { + err = setRNode(objs[i], nodes[0]) + if err != nil { + return err + } + } + + return nil +} + +type marshalerUnmarshaler interface { + json.Unmarshaler + json.Marshaler +} + +// getRNode converts k into an RNode +func getRNode(k json.Marshaler) (*yaml.RNode, error) { + j, err := k.MarshalJSON() + if err != nil { + return nil, err + } + return yaml.Parse(string(j)) +} + +// setRNode marshals node into k +func setRNode(k json.Unmarshaler, node *yaml.RNode) error { + s, err := node.String() + if err != nil { + return err + } + m := map[string]interface{}{} + if err := yaml.Unmarshal([]byte(s), &m); err != nil { + return err + } + + b, err := json.Marshal(m) + if err != nil { + return err + } + return k.UnmarshalJSON(b) +} From 2be48ca96a98fb946acf806a7cd6a0c19d492664 Mon Sep 17 00:00:00 2001 From: Jeffrey Regan Date: Thu, 26 Mar 2020 17:19:30 -0700 Subject: [PATCH 17/17] Function to set labels. --- api/filters/annotations/annotations.go | 40 +++-- api/filters/annotations/annotations_test.go | 169 ++++---------------- api/filters/filtersutil/filtersutil.go | 14 ++ api/filters/filtersutil/filtersutil_test.go | 26 +++ api/filters/labels/doc.go | 6 + api/filters/labels/example_test.go | 55 +++++++ api/filters/labels/labels.go | 43 +++++ api/filters/labels/labels_test.go | 139 ++++++++++++++++ api/filters/namespace/namespace.go | 14 +- api/filters/namespace/namespace_test.go | 24 +-- api/testutils/filtertest/runfilter.go | 30 ++++ 11 files changed, 371 insertions(+), 189 deletions(-) create mode 100644 api/filters/labels/doc.go create mode 100644 api/filters/labels/example_test.go create mode 100644 api/filters/labels/labels.go create mode 100644 api/filters/labels/labels_test.go create mode 100644 api/testutils/filtertest/runfilter.go diff --git a/api/filters/annotations/annotations.go b/api/filters/annotations/annotations.go index d834ecd02..b868d3acf 100644 --- a/api/filters/annotations/annotations.go +++ b/api/filters/annotations/annotations.go @@ -4,15 +4,18 @@ package annotations import ( + "sigs.k8s.io/kustomize/api/filters/filtersutil" "sigs.k8s.io/kustomize/api/filters/fsslice" "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/yaml" ) +type annoMap map[string]string + type Filter struct { // Annotations is the set of annotations to apply to the inputs - Annotations map[string]string `yaml:"annotations,omitempty"` + Annotations annoMap `yaml:"annotations,omitempty"` // FsSlice contains the FieldSpecs to locate the namespace field FsSlice types.FsSlice @@ -21,24 +24,19 @@ type Filter struct { var _ kio.Filter = Filter{} func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { - for i := range nodes { - if err := f.run(nodes[i]); err != nil { - return nil, err - } - } - return nodes, nil -} - -// run applies the filter to a single node. -func (f Filter) run(node *yaml.RNode) error { - for key, value := range f.Annotations { - if err := node.PipeE(fsslice.Filter{ - FsSlice: f.FsSlice, - SetValue: fsslice.SetEntry(key, value), - CreateKind: yaml.MappingNode, // Annotations are MappingNodes. - }); err != nil { - return err - } - } - return nil + keys := filtersutil.SortedMapKeys(f.Annotations) + _, err := kio.FilterAll(yaml.FilterFunc( + func(node *yaml.RNode) (*yaml.RNode, error) { + for _, k := range keys { + if err := node.PipeE(fsslice.Filter{ + FsSlice: f.FsSlice, + SetValue: fsslice.SetEntry(k, f.Annotations[k]), + CreateKind: yaml.MappingNode, // Annotations are MappingNodes. + }); err != nil { + return nil, err + } + } + return node, nil + })).Filter(nodes) + return nodes, err } diff --git a/api/filters/annotations/annotations_test.go b/api/filters/annotations/annotations_test.go index b370f56d0..e1acb5f6e 100644 --- a/api/filters/annotations/annotations_test.go +++ b/api/filters/annotations/annotations_test.go @@ -4,17 +4,17 @@ package annotations import ( - "bytes" "strings" "testing" "github.com/stretchr/testify/assert" "sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig" + filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest" "sigs.k8s.io/kustomize/api/types" - "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/yaml" ) +var annosFs = builtinconfig.MakeDefaultConfig().CommonAnnotations + func TestAnnotations_Filter(t *testing.T) { testCases := map[string]struct { input string @@ -28,11 +28,9 @@ apiVersion: example.com/v1 kind: Foo metadata: name: instance ---- -apiVersion: example.com/v1 -kind: Bar -metadata: - name: instance + annotations: + hero: batman + fiend: riddler `, expectedOutput: ` apiVersion: example.com/v1 @@ -40,17 +38,18 @@ kind: Foo metadata: name: instance annotations: - sleater: kinney ---- -apiVersion: example.com/v1 -kind: Bar -metadata: - name: instance - annotations: - sleater: kinney + hero: batman + fiend: riddler + auto: ford + bean: cannellini + clown: emmett kelley + dragon: smaug `, - filter: Filter{Annotations: map[string]string{ - "sleater": "kinney", + filter: Filter{Annotations: annoMap{ + "clown": "emmett kelley", + "auto": "ford", + "dragon": "smaug", + "bean": "cannellini", }}, }, "update": { @@ -60,7 +59,8 @@ kind: Foo metadata: name: instance annotations: - foo: foo + hero: batman + fiend: riddler `, expectedOutput: ` apiVersion: example.com/v1 @@ -68,10 +68,16 @@ kind: Foo metadata: name: instance annotations: - foo: bar + hero: superman + fiend: luthor + bean: cannellini + clown: emmett kelley `, - filter: Filter{Annotations: map[string]string{ - "foo": "bar", + filter: Filter{Annotations: annoMap{ + "clown": "emmett kelley", + "hero": "superman", + "fiend": "luthor", + "bean": "cannellini", }}, }, "data-fieldspecs": { @@ -107,7 +113,7 @@ a: b: sleater: kinney `, - filter: Filter{Annotations: map[string]string{ + filter: Filter{Annotations: annoMap{ "sleater": "kinney", }}, fsslice: []types.FieldSpec{ @@ -121,126 +127,13 @@ a: for tn, tc := range testCases { t.Run(tn, func(t *testing.T) { - config := builtinconfig.MakeDefaultConfig() - filter := tc.filter - filter.FsSlice = append(config.CommonAnnotations, tc.fsslice...) - - var out bytes.Buffer - rw := kio.ByteReadWriter{ - Reader: bytes.NewBufferString(tc.input), - Writer: &out, - } - - err := kio.Pipeline{ - Inputs: []kio.Reader{&rw}, - Filters: []kio.Filter{filter}, - Outputs: []kio.Writer{&rw}, - }.Execute() - if !assert.NoError(t, err) { - t.FailNow() - } - + filter.FsSlice = append(annosFs, tc.fsslice...) if !assert.Equal(t, strings.TrimSpace(tc.expectedOutput), - strings.TrimSpace(out.String())) { + strings.TrimSpace(filtertest_test.RunFilter(t, tc.input, filter))) { t.FailNow() } }) } } - -func TestAnnotations_Filter_Multiple(t *testing.T) { - input := ` -apiVersion: example.com/v1 -kind: Foo -metadata: - name: instance ---- -apiVersion: example.com/v1 -kind: Bar -metadata: - name: instance -` - annos := map[string]string{ - "sleater": "kinney", - "sonic": "youth", - } - config := builtinconfig.MakeDefaultConfig() - filter := Filter{Annotations: annos} - filter.FsSlice = config.CommonAnnotations - - var out bytes.Buffer - rw := kio.ByteReadWriter{ - Reader: bytes.NewBufferString(input), - Writer: &out, - } - - err := kio.Pipeline{ - Inputs: []kio.Reader{&rw}, - Filters: []kio.Filter{filter}, - Outputs: []kio.Writer{&rw}, - }.Execute() - if !assert.NoError(t, err) { - t.FailNow() - } - - assertHasAnnotation(t, out.String(), annos) -} - -func assertHasAnnotation(t *testing.T, y string, exp map[string]string) bool { - var out bytes.Buffer - rw := kio.ByteReadWriter{ - Reader: bytes.NewBufferString(y), - Writer: &out, - } - filter := &captureAnnotationFilter{ - annotations: make(map[string]annotations), - } - err := kio.Pipeline{ - Inputs: []kio.Reader{&rw}, - Filters: []kio.Filter{filter}, - Outputs: []kio.Writer{&rw}, - }.Execute() - if err != nil { - t.Error(err) - return false - } - - for name, annos := range filter.annotations { - for key, val := range exp { - v, found := annos[key] - if !found { - t.Errorf("expected annotation with key %s in object %s, but didn't find it", - key, name) - return false - } - if want, got := val, v; got != want { - t.Errorf("exected annotation %s in object %s to have value %s, but found %s", - key, name, want, got) - return false - } - } - } - return true -} - -type annotations map[string]string - -type captureAnnotationFilter struct { - annotations map[string]annotations -} - -func (c captureAnnotationFilter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, - error) { - for _, n := range nodes { - meta, err := n.GetMeta() - if err != nil { - return nodes, err - } - name := meta.Name - annos := meta.Annotations - c.annotations[name] = annos - } - return nodes, nil -} diff --git a/api/filters/filtersutil/filtersutil.go b/api/filters/filtersutil/filtersutil.go index e238f7bc0..09c1abd89 100644 --- a/api/filters/filtersutil/filtersutil.go +++ b/api/filters/filtersutil/filtersutil.go @@ -5,11 +5,25 @@ package filtersutil import ( "encoding/json" + "sort" "sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/yaml" ) +// SortedMapKeys returns a sorted slice of keys to the given map. +// Writing this function never gets old. +func SortedMapKeys(m map[string]string) []string { + keys := make([]string, len(m)) + i := 0 + for k := range m { + keys[i] = k + i++ + } + sort.Strings(keys) + return keys +} + // ApplyToJSON applies the filter to the json objects. func ApplyToJSON(filter kio.Filter, objs ...marshalerUnmarshaler) error { var nodes []*yaml.RNode diff --git a/api/filters/filtersutil/filtersutil_test.go b/api/filters/filtersutil/filtersutil_test.go index 97471e25e..685bec74e 100644 --- a/api/filters/filtersutil/filtersutil_test.go +++ b/api/filters/filtersutil/filtersutil_test.go @@ -11,6 +11,32 @@ import ( "sigs.k8s.io/kustomize/kyaml/yaml" ) +func TestSortedKeys(t *testing.T) { + testCases := map[string]struct { + input map[string]string + expected []string + }{ + "empty": { + input: map[string]string{}, + expected: []string{}}, + "one": { + input: map[string]string{"a": "aaa"}, + expected: []string{"a"}}, + "three": { + input: map[string]string{"c": "ccc", "b": "bbb", "a": "aaa"}, + expected: []string{"a", "b", "c"}}, + } + for tn, tc := range testCases { + t.Run(tn, func(t *testing.T) { + if !assert.Equal(t, + filtersutil.SortedMapKeys(tc.input), + tc.expected) { + t.FailNow() + } + }) + } +} + func TestApplyToJSON(t *testing.T) { instance1 := bytes.NewBufferString(`{"kind": "Foo"}`) instance2 := bytes.NewBufferString(`{"kind": "Bar"}`) diff --git a/api/filters/labels/doc.go b/api/filters/labels/doc.go new file mode 100644 index 000000000..978033c7e --- /dev/null +++ b/api/filters/labels/doc.go @@ -0,0 +1,6 @@ +// Copyright 2020 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +// Package labels contains a kio.Filter implementation of the kustomize +// labels transformer. +package labels diff --git a/api/filters/labels/example_test.go b/api/filters/labels/example_test.go new file mode 100644 index 000000000..b419b2810 --- /dev/null +++ b/api/filters/labels/example_test.go @@ -0,0 +1,55 @@ +// Copyright 2020 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package labels + +import ( + "bytes" + "log" + "os" + + "sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig" + "sigs.k8s.io/kustomize/kyaml/kio" +) + +func ExampleFilter() { + fss := builtinconfig.MakeDefaultConfig().CommonLabels + err := kio.Pipeline{ + Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + name: instance +`)}}, + Filters: []kio.Filter{Filter{ + Labels: map[string]string{ + "foo": "bar", + }, + FsSlice: fss, + }}, + Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}}, + }.Execute() + if err != nil { + log.Fatal(err) + } + + // Output: + // apiVersion: example.com/v1 + // kind: Foo + // metadata: + // name: instance + // labels: + // foo: bar + // --- + // apiVersion: example.com/v1 + // kind: Bar + // metadata: + // name: instance + // labels: + // foo: bar +} diff --git a/api/filters/labels/labels.go b/api/filters/labels/labels.go new file mode 100644 index 000000000..d9b0ad992 --- /dev/null +++ b/api/filters/labels/labels.go @@ -0,0 +1,43 @@ +// Copyright 2020 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package labels + +import ( + "sigs.k8s.io/kustomize/api/filters/filtersutil" + "sigs.k8s.io/kustomize/api/filters/fsslice" + "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +type labelMap map[string]string + +// Filter sets labels. +type Filter struct { + // Labels is the set of labels to apply to the inputs + Labels labelMap `yaml:"labels,omitempty"` + + // FsSlice identifies the label fields. + FsSlice types.FsSlice +} + +var _ kio.Filter = Filter{} + +func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { + keys := filtersutil.SortedMapKeys(f.Labels) + _, err := kio.FilterAll(yaml.FilterFunc( + func(node *yaml.RNode) (*yaml.RNode, error) { + for _, k := range keys { + if err := node.PipeE(fsslice.Filter{ + FsSlice: f.FsSlice, + SetValue: fsslice.SetEntry(k, f.Labels[k]), + CreateKind: yaml.MappingNode, // Labels are MappingNodes. + }); err != nil { + return nil, err + } + } + return node, nil + })).Filter(nodes) + return nodes, err +} diff --git a/api/filters/labels/labels_test.go b/api/filters/labels/labels_test.go new file mode 100644 index 000000000..2758dc215 --- /dev/null +++ b/api/filters/labels/labels_test.go @@ -0,0 +1,139 @@ +// Copyright 2020 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package labels + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig" + filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest" + "sigs.k8s.io/kustomize/api/types" +) + +var labelsFs = builtinconfig.MakeDefaultConfig().CommonLabels + +func TestLabels_Filter(t *testing.T) { + testCases := map[string]struct { + input string + expectedOutput string + filter Filter + fsSlice types.FsSlice + }{ + "add": { + input: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance + labels: + hero: batman + fiend: riddler +`, + expectedOutput: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance + labels: + hero: batman + fiend: riddler + auto: ford + bean: cannellini + clown: emmett kelley + dragon: smaug +`, + filter: Filter{Labels: labelMap{ + "clown": "emmett kelley", + "auto": "ford", + "dragon": "smaug", + "bean": "cannellini", + }}, + }, + "update": { + input: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance + labels: + hero: batman + fiend: riddler +`, + expectedOutput: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance + labels: + hero: superman + fiend: luthor + bean: cannellini + clown: emmett kelley +`, + filter: Filter{Labels: labelMap{ + "clown": "emmett kelley", + "hero": "superman", + "fiend": "luthor", + "bean": "cannellini", + }}, + }, + "data-fieldspecs": { + input: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + name: instance +`, + expectedOutput: ` +apiVersion: example.com/v1 +kind: Foo +metadata: + name: instance + labels: + sleater: kinney +a: + b: + sleater: kinney +--- +apiVersion: example.com/v1 +kind: Bar +metadata: + name: instance + labels: + sleater: kinney +a: + b: + sleater: kinney +`, + filter: Filter{Labels: labelMap{ + "sleater": "kinney", + }}, + fsSlice: []types.FieldSpec{ + { + Path: "a/b", + CreateIfNotPresent: true, + }, + }, + }, + } + + for tn, tc := range testCases { + t.Run(tn, func(t *testing.T) { + filter := tc.filter + filter.FsSlice = append(labelsFs, tc.fsSlice...) + if !assert.Equal(t, + strings.TrimSpace(tc.expectedOutput), + strings.TrimSpace(filtertest_test.RunFilter(t, tc.input, filter))) { + t.FailNow() + } + }) + } +} diff --git a/api/filters/namespace/namespace.go b/api/filters/namespace/namespace.go index 34bb1fe2f..c8a610b22 100644 --- a/api/filters/namespace/namespace.go +++ b/api/filters/namespace/namespace.go @@ -21,19 +21,14 @@ type Filter struct { var _ kio.Filter = Filter{} func (ns Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { - for i := range nodes { - if err := ns.run(nodes[i]); err != nil { - return nil, err - } - } - return nodes, nil + return kio.FilterAll(yaml.FilterFunc(ns.run)).Filter(nodes) } // Run runs the filter on a single node rather than a slice -func (ns Filter) run(node *yaml.RNode) error { +func (ns Filter) run(node *yaml.RNode) (*yaml.RNode, error) { // hacks for hardcoded types -- :( if err := ns.hacks(node); err != nil { - return err + return nil, err } // Remove the fieldspecs that are for hardcoded fields. The fieldspecs @@ -45,11 +40,12 @@ func (ns Filter) run(node *yaml.RNode) error { ns.FsSlice = ns.removeFieldSpecsForHacks(ns.FsSlice) // transformations based on data -- :) - return node.PipeE(fsslice.Filter{ + err := node.PipeE(fsslice.Filter{ FsSlice: ns.FsSlice, SetValue: fsslice.SetScalar(ns.Namespace), CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode }) + return node, err } // hacks applies the namespace transforms that are hardcoded rather diff --git a/api/filters/namespace/namespace_test.go b/api/filters/namespace/namespace_test.go index a68a394e3..f3d1613cc 100644 --- a/api/filters/namespace/namespace_test.go +++ b/api/filters/namespace/namespace_test.go @@ -4,15 +4,14 @@ package namespace_test import ( - "bytes" "strings" "testing" "github.com/stretchr/testify/assert" "sigs.k8s.io/kustomize/api/filters/namespace" "sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig" + filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest" "sigs.k8s.io/kustomize/api/types" - "sigs.k8s.io/kustomize/kyaml/kio" ) var tests = []TestCase{ @@ -270,27 +269,10 @@ func TestNamespace_Filter(t *testing.T) { test := tests[i] t.Run(test.name, func(t *testing.T) { test.filter.FsSlice = append(config.NameSpace, test.fsslice...) - - out := &bytes.Buffer{} - rw := &kio.ByteReadWriter{ - Reader: bytes.NewBufferString(test.input), - Writer: out, - } - - // run the filter - err := kio.Pipeline{ - Inputs: []kio.Reader{rw}, - Filters: []kio.Filter{test.filter}, - Outputs: []kio.Writer{rw}, - }.Execute() - if !assert.NoError(t, err) { - t.FailNow() - } - - // check results if !assert.Equal(t, strings.TrimSpace(test.expected), - strings.TrimSpace(out.String())) { + strings.TrimSpace( + filtertest_test.RunFilter(t, test.input, test.filter))) { t.FailNow() } }) diff --git a/api/testutils/filtertest/runfilter.go b/api/testutils/filtertest/runfilter.go new file mode 100644 index 000000000..aea5901fb --- /dev/null +++ b/api/testutils/filtertest/runfilter.go @@ -0,0 +1,30 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package filtertest_test + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" + "sigs.k8s.io/kustomize/kyaml/kio" +) + +func RunFilter(t *testing.T, input string, f kio.Filter) string { + var out bytes.Buffer + rw := kio.ByteReadWriter{ + Reader: bytes.NewBufferString(input), + Writer: &out, + } + + err := kio.Pipeline{ + Inputs: []kio.Reader{&rw}, + Filters: []kio.Filter{f}, + Outputs: []kio.Writer{&rw}, + }.Execute() + if !assert.NoError(t, err) { + t.FailNow() + } + return out.String() +}