Compare commits

...

85 Commits

Author SHA1 Message Date
Jeff Regan
c45e05b7bd Update go.mod 2020-09-16 12:53:39 -07:00
Kubernetes Prow Robot
76bae738a0 Merge pull request #2932 from mstrYoda/master
add DisableNameSuffixHash parameter to edit Secret & ConfigMap
2020-09-16 10:29:20 -07:00
Jeff Regan
0770661b2a Merge pull request #2991 from monopole/goSumUpdates
Go sum updates
2020-09-15 17:34:23 -07:00
jregan
67d5871e87 Go sum updates 2020-09-15 17:02:40 -07:00
Jeff Regan
f98c683915 Merge pull request #2983 from Shell32-Natsu/allow-null
ignore null value in fieldspec
2020-09-15 17:02:20 -07:00
Jeff Regan
ffe9c9d947 Merge pull request #2990 from monopole/pinToKyamlv0_8_0
Pin to kyaml v0.8.0
2020-09-15 15:51:08 -07:00
jregan
4d42ffc7f8 Pin to kyaml v0.8.0 2020-09-15 15:26:29 -07:00
Jeff Regan
d7dc7d911e Merge pull request #2989 from monopole/minorFix
Generated changes.
2020-09-15 14:56:16 -07:00
jregan
04404ff61b Generated changes. 2020-09-15 14:55:08 -07:00
Jeff Regan
f864e15c68 Merge pull request #2974 from Shell32-Natsu/function-definition
remove not used args & use const string instead of literal
2020-09-15 14:34:25 -07:00
Jeff Regan
29a444fffc Merge pull request #2988 from Shell32-Natsu/env-flag
Add --env/-e flag to fn run
2020-09-15 14:31:40 -07:00
Donny Xia
327035a43a Add --env/-e flag 2020-09-15 11:49:26 -07:00
Kubernetes Prow Robot
ad7fed061e Merge pull request #2984 from phanimarupaka/FixCmdCfgIssues
Do not print package info in grep
2020-09-15 09:40:07 -07:00
Phani Teja Marupaka
cea2986574 Don not pring package info in grep 2020-09-15 00:15:52 -07:00
Kubernetes Prow Robot
00f0fd7109 Merge pull request #2978 from mortent/NamespaceabilityFromSchema
Determine namespaceability of resources from openapi schema
2020-09-14 21:10:06 -07:00
Kubernetes Prow Robot
1c6481d011 Merge pull request #2982 from mortent/UpdateCliUtils
Update cmd/config to use latest version of cli-utils
2020-09-14 13:27:24 -07:00
Donny Xia
f0bc926640 ignore null value in fieldspec 2020-09-14 13:20:20 -07:00
Morten Torkildsen
11d9ff5690 Update cmd/config to use latest version of cli-utils 2020-09-14 12:08:48 -07:00
Jeff Regan
6a0a909e73 Merge pull request #2976 from monopole/deferLive
Remove live; done testing.  Bring to sig-cli for discussion.
2020-09-14 11:00:48 -07:00
Kubernetes Prow Robot
bd8f0c88e5 Merge pull request #2967 from phanimarupaka/CfgTreeWithSubpackages
Print Krmfile data for cfg tree
2020-09-14 10:42:59 -07:00
Donny Xia
e5809e49cb remove not used args 2020-09-14 10:10:20 -07:00
Phani Teja Marupaka
880009b648 Print Krmfile data for cfg tree 2020-09-14 09:57:18 -07:00
Morten Torkildsen
d083c7f1d0 Determine namespaceability of resources from openapi schema 2020-09-12 15:01:42 -07:00
Jeffrey Regan
684ce141de Defer live testing. 2020-09-11 17:25:25 -07:00
Kubernetes Prow Robot
5c8c7a043a Merge pull request #2973 from phanimarupaka/CfgCommandsStdoutFixes
Format the output of cfg commands
2020-09-11 16:44:57 -07:00
Kubernetes Prow Robot
0fe7f65ef2 Merge pull request #2975 from monopole/addTest
Add test representing 2960
2020-09-11 16:10:57 -07:00
Jeffrey Regan
950c1de46d Add test representing 2960 2020-09-11 15:22:41 -07:00
Phani Teja Marupaka
fc690f14a8 Format the output of cfg commands 2020-09-11 14:49:18 -07:00
Jeff Regan
a6e03e4d11 Merge pull request #2920 from wyyxd2017/hato4
Technical details structure picture
2020-09-11 14:32:19 -07:00
Jeff Regan
60428be5fb Merge pull request #2944 from justinsb/alas_poor_grepfilter
Remove some obsolete references to GrepFilter
2020-09-11 14:16:30 -07:00
Jeff Regan
4d402d4875 Merge pull request #2969 from justinsb/fix_split_docs
Fix comment on SplitIndexNameValue
2020-09-11 14:13:43 -07:00
Jeff Regan
fbddd264be Merge pull request #2971 from etefera/fix-broken-patches-change
Fix unintended patches change in all Kustomization writes.
2020-09-11 13:33:09 -07:00
Eyob Tefera
d3c46d3f7c Move offending Write() tests to tests for fix. 2020-09-11 19:19:54 +00:00
Eyob Tefera
dda3984a8f Move kustomization fixing to before Write step. 2020-09-11 18:57:14 +00:00
Eyob Tefera
f889ca8885 Add set image test with patchesJson6902. 2020-09-11 18:48:48 +00:00
Justin SB
341bacb9a2 Fix comment on SplitIndexNameValue
It was incorrect and suggested some behaviour which isn't present.
Added test to verify the documented behaviour.
2020-09-11 11:39:49 -04:00
Kubernetes Prow Robot
badc1177d9 Merge pull request #2939 from ZhuGongpu/master
Add --log-steps flag
2020-09-09 19:05:44 -07:00
Kubernetes Prow Robot
1680cc72c0 Merge pull request #2953 from easimon/add_namespace_to_namespace_transformer
Add namespace name to namespace transformer defaults
2020-09-09 14:57:44 -07:00
Jeff Regan
2f89de86f8 Merge pull request #2956 from justinsb/fix_language
Replace language with more inclusive & accurate "hard-coded"
2020-09-09 11:33:53 -07:00
Jeff Regan
ab4e9c718b Merge pull request #2943 from Shell32-Natsu/clean-up-temp-dir
remove all temp dir
2020-09-09 11:20:17 -07:00
Kubernetes Prow Robot
288c03ddca Merge pull request #2959 from phanimarupaka/CatWithSubpkgs
Cat with subpackages
2020-09-09 10:49:08 -07:00
Justin SB
5c60285f25 Replace language with more inclusive & accurate "hard-coded"
hard-coded is probably more helpful to understanding the limitations
of the current approach.
2020-09-09 08:41:33 -04:00
Kubernetes Prow Robot
6df0a45368 Merge pull request #2958 from phanimarupaka/GrepWithSubpkgs
Grep with subpackages
2020-09-08 21:09:52 -07:00
Kubernetes Prow Robot
8206987580 Merge pull request #2957 from phanimarupaka/CountWithSubpkgs
Count with Subpackages
2020-09-08 20:53:52 -07:00
Kubernetes Prow Robot
6189ca9798 Merge pull request #2955 from phanimarupaka/FmtWithSubpkgs
Fmt with subpackages
2020-09-08 20:33:52 -07:00
Phani Teja Marupaka
b8c1601a93 Cat with subpackages 2020-09-08 18:42:31 -07:00
Phani Teja Marupaka
34d610a38d Fmt with subpackages 2020-09-08 17:07:55 -07:00
Phani Teja Marupaka
8e4c8464e7 Grep with subpackages 2020-09-08 16:59:23 -07:00
Phani Teja Marupaka
43ab7a8e71 Count with Subpackages 2020-09-08 16:33:00 -07:00
Kubernetes Prow Robot
d2f23a4b8b Merge pull request #2938 from phanimarupaka/OtherCfgCommandsWithSubPkgs
annotate, delete-setter, delete-subst With Subpackages
2020-09-08 16:25:52 -07:00
Phani Teja Marupaka
0dc36a4f7c Annotate With Subpackages
Delete Setters And Subst With Subpkgs
2020-09-08 15:52:57 -07:00
Kubernetes Prow Robot
678ae12115 Merge pull request #2946 from phanimarupaka/RefactorSubPkgsIteration
Refactor subpackages logic
2020-09-08 11:47:52 -07:00
Phani Teja Marupaka
c4d937322f Refactor subpackages logic 2020-09-08 11:23:54 -07:00
Kubernetes Prow Robot
a2adb835b6 Merge pull request #2941 from mortent/FixIgnoreFilesMatcher
Fix issue where ignoreFilesMatcher doesn't work correctly
2020-09-08 10:33:44 -07:00
Markus Dobel
01b5c4e9da Add namespace name to namespace transformer defaults 2020-09-08 11:24:58 +02:00
Justin SB
eb4c5dc035 Remove some obsolete references to GrepFilter
Looks like GrepFilter was generalized to Filter.
2020-09-04 13:41:16 -04:00
Morten Torkildsen
e976386931 Fix issue where ignoreFilesMatcher doesn't work correctly 2020-09-03 20:14:07 -07:00
Donny Xia
bae9986422 remove all temp dir 2020-09-03 12:03:12 -07:00
Jeff Regan
e7970d82a8 Merge pull request #2942 from Shell32-Natsu/addDonny
add Donny to maintainer
2020-09-03 11:52:14 -07:00
Donny Xia
9bdd489c96 add Donny to maintainer 2020-09-03 10:57:50 -07:00
Kubernetes Prow Robot
0f49fef5ed Merge pull request #2940 from phanimarupaka/FixSettersSubPkgsFriction
Fix setters subpkgs friction
2020-09-03 08:59:41 -07:00
Phani Teja Marupaka
8d74b8c3b5 Fix setters subpkgs friction 2020-09-02 23:06:26 -07:00
Gongpu Zhu
39a8798a87 Add --log-steps flag 2020-09-02 20:47:21 -07:00
Jeff Regan
980f407552 Merge pull request #2931 from Shell32-Natsu/image-tag-legacy
add legacy filter to image tag transformer
2020-09-02 13:02:53 -07:00
Donny Xia
9ca8f4602d add legacy filter to image tag transformer 2020-09-01 13:06:14 -07:00
Kubernetes Prow Robot
ba0f583ee5 Merge pull request #2911 from phanimarupaka/SetWithSubPackages
Setters/substitutions with subpackages
2020-09-01 11:23:51 -07:00
Phani Teja Marupaka
f432f4d75e Setters with subpackages 2020-09-01 10:54:08 -07:00
Jeff Regan
17793abacd Merge pull request #2930 from daniel-hutao/patch-1
fix “chart s” to “charts ”
2020-09-01 10:12:58 -07:00
Jeff Regan
64cd4ec1d5 Merge pull request #2929 from monopole/testExamplesAgainst_v3.8.2
Test examples against v3.8.2
2020-09-01 10:12:18 -07:00
Daniel (ht)
fb822984e3 fix “chart s” to “charts ”
fix “chart s” to “charts ”
2020-09-01 16:24:49 +08:00
jregan
6d2a737c29 Test examples against v3.8.2 2020-08-31 16:48:19 -07:00
Jeff Regan
6e7713281e Merge pull request #2928 from monopole/addGorepomod
Add more release instructions
2020-08-31 13:50:48 -07:00
jregan
6a7bb9e33e Add gorepomod tool to install list 2020-08-31 13:28:19 -07:00
Jeff Regan
0e9428c8b0 Merge pull request #2927 from monopole/unpinning
Unpinning after release releases
2020-08-31 12:47:28 -07:00
jregan
c838962432 fix module hashes 2020-08-31 12:08:16 -07:00
jregan
548d10ef08 unpin kyaml 2020-08-31 12:08:16 -07:00
jregan
2db8487f02 unpin cmd/config 2020-08-31 12:08:16 -07:00
jregan
b42f71a20f unpin api 2020-08-31 12:08:16 -07:00
Jeff Regan
e9824aa749 Merge pull request #2926 from monopole/fixAGoMod
Repair a go module spec.
2020-08-31 12:08:06 -07:00
jregan
92cc9fc5e1 Repair a go module spec. 2020-08-31 11:35:32 -07:00
wangyeyu
e53b4c9884 Technical details structure picture 2020-08-31 10:01:19 +08:00
Jeff Regan
e2973f6ecc Merge pull request #2915 from monopole/pinToKustomizeApiv_0_6_0
Pin to kustomize api v0.6.0
2020-08-29 09:42:26 -07:00
jregan
2bf9fc816d Pin to kustomize api v0.6.0 2020-08-29 08:55:29 -07:00
mstrYoda
257707d839 Merge branch 'master' of https://github.com/kubernetes-sigs/kustomize 2020-08-26 13:24:04 +03:00
mstrYoda
c1cd872df6 add DisableNameSuffixHash for secret and configmap 2020-08-26 13:22:26 +03:00
152 changed files with 71425 additions and 5681 deletions

View File

@@ -15,7 +15,8 @@ verify-kustomize: \
lint-kustomize \
test-unit-kustomize-all \
test-examples-kustomize-against-HEAD \
test-examples-kustomize-against-3.8.0
test-examples-kustomize-against-3.8.0 \
test-examples-kustomize-against-3.8.2
# The following target referenced by a file in
# https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/kustomize
@@ -26,7 +27,8 @@ prow-presubmit-check: \
test-unit-cmd-all \
test-go-mod \
test-examples-kustomize-against-HEAD \
test-examples-kustomize-against-3.8.0
test-examples-kustomize-against-3.8.0 \
test-examples-kustomize-against-3.8.2
.PHONY: verify-kustomize-e2e
verify-kustomize-e2e: test-examples-e2e-kustomize
@@ -45,17 +47,18 @@ $(MYGOBIN)/golangci-lint-kustomize:
GO111MODULE=on go build -tags=tools -o $(MYGOBIN)/golangci-lint-kustomize github.com/golangci/golangci-lint/cmd/golangci-lint; \
)
# Version pinned by api/go.mod
$(MYGOBIN)/gorepomod:
cd api; \
go install github.com/monopole/gorepomod
$(MYGOBIN)/mdrip:
cd api; \
go install github.com/monopole/mdrip
# Version pinned by api/go.mod
$(MYGOBIN)/stringer:
cd api; \
go install golang.org/x/tools/cmd/stringer
# Version pinned by api/go.mod
$(MYGOBIN)/goimports:
cd api; \
go install golang.org/x/tools/cmd/goimports
@@ -81,6 +84,7 @@ $(MYGOBIN)/kustomize:
install-tools: \
$(MYGOBIN)/goimports \
$(MYGOBIN)/golangci-lint-kustomize \
$(MYGOBIN)/gorepomod \
$(MYGOBIN)/mdrip \
$(MYGOBIN)/pluginator \
$(MYGOBIN)/stringer
@@ -245,6 +249,19 @@ test-examples-kustomize-against-3.8.0: $(MYGOBIN)/mdrip
cd kustomize; go install .; \
)
.PHONY:
test-examples-kustomize-against-3.8.2: $(MYGOBIN)/mdrip
( \
set -e; \
tag=v3.8.2; \
/bin/rm -f $(MYGOBIN)/kustomize; \
echo "Installing kustomize $$tag."; \
GO111MODULE=on go get sigs.k8s.io/kustomize/kustomize/v3@$${tag}; \
./hack/testExamplesAgainstKustomize.sh $$tag; \
echo "Reinstalling kustomize from HEAD."; \
cd kustomize; go install .; \
)
# linux only.
# This is for testing an example plugin that
# uses kubeval for validation.

View File

@@ -11,3 +11,4 @@ aliases:
- pwittrock
- mortent
- phanimarupaka
- Shell32-Natsu

View File

@@ -31,14 +31,15 @@ func (p *ImageTagTransformerPlugin) Config(
func (p *ImageTagTransformerPlugin) Transform(m resmap.ResMap) error {
for _, r := range m.Resources() {
// If you're here because someone expected any field containing
// the string "containers" or "initContainers" to get an image
// update (not just spec/template/spec/containers[], etc.) then
// a code change is needed. See api/filters/imagetag/legacy
// for the start of an implementation that won't use an
// allowlist like FsSlice, and instead walks the object looking
// for fields named containers or initContainers.
err := filtersutil.ApplyToJSON(imagetag.Filter{
// traverse all fields at first
err := filtersutil.ApplyToJSON(imagetag.LegacyFilter{
ImageTag: p.ImageTag,
}, r)
if err != nil {
return err
}
// then use user specified field specs
err = filtersutil.ApplyToJSON(imagetag.Filter{
ImageTag: p.ImageTag,
FsSlice: p.FieldSpecs,
}, r)

View File

@@ -51,6 +51,9 @@ func (fltr Filter) filter(obj *yaml.RNode) error {
// found the field -- set its value
return fltr.SetValue(obj)
}
if obj.IsTaggedNull() {
return nil
}
switch obj.YNode().Kind {
case yaml.SequenceNode:
return fltr.seq(obj)
@@ -67,7 +70,7 @@ func (fltr Filter) field(obj *yaml.RNode) error {
// lookup the field matching the next path element
var lookupField yaml.Filter
var kind yaml.Kind
tag := "" // TODO: change to yaml.NodeTagEmpty
tag := yaml.NodeTagEmpty
switch {
case !fltr.FieldSpec.CreateIfNotPresent || fltr.CreateKind == 0 || isSeq:
// dont' create the field if we don't find it
@@ -95,9 +98,10 @@ func (fltr Filter) field(obj *yaml.RNode) error {
return errors.WrapPrefixf(err, "fieldName: %s", fieldName)
}
// if the value exists, but is null, then change it to the creation type
// if the value exists, but is null and kind is set,
// then change it to the creation type
// TODO: update yaml.LookupCreate to support this
if field.YNode().Tag == yaml.NodeTagNull {
if field.YNode().Tag == yaml.NodeTagNull && yaml.IsCreate(kind) {
field.YNode().Kind = kind
field.YNode().Tag = tag
}

View File

@@ -433,7 +433,6 @@ spec:
SetValue: filtersutil.SetScalar("bar"),
CreateKind: yaml.ScalarNode,
},
error: "obj '' at path 'spec/containers/image': expected sequence or mapping node",
},
{
name: "filedname with slash '/'",

View File

@@ -168,6 +168,44 @@ metadata:
map:
name: newName
namespace: oldNs
`,
filter: Filter{
FieldSpec: types.FieldSpec{Path: "map"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
},
"null value": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
map:
name: null
`,
candidates: `
apiVersion: apps/v1
kind: Secret
metadata:
name: newName
---
apiVersion: apps/v1
kind: NotSecret
metadata:
name: newName2
`,
originalNames: []string{"oldName", ""},
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
map:
name: null
`,
filter: Filter{
FieldSpec: types.FieldSpec{Path: "map"},
@@ -217,27 +255,6 @@ func TestNamerefFilterUnhappy(t *testing.T) {
filter Filter
originalNames []string
}{
"invalid node type": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: null
`,
candidates: "",
originalNames: []string{},
expected: "obj '' at path 'ref/name': node is expected to be either a string or a slice of string or a map of string",
filter: Filter{
FieldSpec: types.FieldSpec{Path: "ref/name"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
},
"multiple match": {
input: `
apiVersion: apps/v1

View File

@@ -69,7 +69,7 @@ func (ns Filter) hacks(obj *yaml.RNode) error {
// 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).
// in a hard-coded list 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,

View File

@@ -188,6 +188,26 @@ data:
FieldSpec: types.FieldSpec{Path: "data/slice2"},
},
},
"null value": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
data:
FOO: null`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
data:
FOO: null`,
filter: Filter{
MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{}),
FieldSpec: types.FieldSpec{Path: "data/FOO"},
},
},
}
for tn, tc := range testCases {
@@ -260,20 +280,6 @@ data:
FieldSpec: types.FieldSpec{Path: "data"},
},
},
"null input": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
data:
FOO: null`,
expectedError: "obj '' at path 'data/FOO': invalid type encountered 0",
filter: Filter{
MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{}),
FieldSpec: types.FieldSpec{Path: "data/FOO"},
},
},
}
for tn, tc := range testCases {

View File

@@ -10,13 +10,13 @@ require (
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
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e
gopkg.in/yaml.v2 v2.3.0
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71
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.7.1
sigs.k8s.io/kustomize/kyaml v0.8.0
sigs.k8s.io/yaml v1.2.0
)

View File

@@ -307,6 +307,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@@ -526,6 +528,8 @@ golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff h1:XdBG6es/oFDr1HwaxkxgVve7NB281QhxgK/i4voubFs=
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e h1:aZzprAO9/8oim3qStq3wc1Xuxx4QmAGriC4VU4ojemQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@@ -584,8 +588,8 @@ 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/kyaml v0.7.1 h1:Ih6SJPvfKYfZaIFWUa2YAyg/0ZSTpA3LFjR/hv7+8ao=
sigs.k8s.io/kustomize/kyaml v0.7.1/go.mod h1:ne3F9JPhW2wrVaLslxBsEe6MQJQ9YK5rUutrdhBWXwI=
sigs.k8s.io/kustomize/kyaml v0.8.0 h1:/MqPML99XAm2pbrD/eTpePh5rnU5bpnuTPqb29LpSz4=
sigs.k8s.io/kustomize/kyaml v0.8.0/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=

View File

@@ -132,7 +132,7 @@ func TestRefVarTransformer(t *testing.T) {
' at path 'data/slice': invalid value type expect a string`,
},
{
description: "var replacement panic in nil",
description: "var replacement in nil",
given: given{
varMap: map[string]interface{}{},
fs: []types.FieldSpec{
@@ -150,7 +150,19 @@ func TestRefVarTransformer(t *testing.T) {
"nil": nil, // noticeably *not* a []string
}}).ResMap(),
},
errMessage: `obj '' at path 'data/nil': invalid type encountered 0`,
expected: expected{
res: resmaptest_test.NewRmBuilder(
t, resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())).
Add(map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "cm1",
},
"data": map[string]interface{}{
"nil": nil, // noticeably *not* a []string
}}).ResMap(),
},
},
}

View File

@@ -217,7 +217,7 @@ overview of each component with the following sections going into more details.
The overall structure is outlined in the following figure:
![overview](
https://sigs.k8s.io/kustomize/internal/tools/pictures/sys_arch.png)
https://github.com/kubernetes-sigs/kustomize/blob/master/api/internal/crawl/pictures/token_config.png)
#### Crawler
The leftmost component consists of a crawler with an http cache of GitHub

View File

@@ -271,6 +271,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@@ -470,6 +472,7 @@ golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDq
golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@@ -524,8 +527,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/kyaml v0.7.1 h1:Ih6SJPvfKYfZaIFWUa2YAyg/0ZSTpA3LFjR/hv7+8ao=
sigs.k8s.io/kustomize/kyaml v0.7.1/go.mod h1:ne3F9JPhW2wrVaLslxBsEe6MQJQ9YK5rUutrdhBWXwI=
sigs.k8s.io/kustomize/kyaml v0.8.0 h1:/MqPML99XAm2pbrD/eTpePh5rnU5bpnuTPqb29LpSz4=
sigs.k8s.io/kustomize/kyaml v0.8.0/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
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=

View File

@@ -8,6 +8,9 @@ const (
namespace:
- path: metadata/namespace
create: true
- path: metadata/name
kind: Namespace
create: true
- path: subjects
kind: RoleBinding
- path: subjects

View File

@@ -9,7 +9,7 @@ import (
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func TestNullValues(t *testing.T) {
func TestNullValues1(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("/app/deployment.yaml", `
apiVersion: apps/v1
@@ -62,3 +62,36 @@ spec:
name: example
`)
}
func TestNullValues2(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("deploy.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: test
spec:
template:
spec:
containers:
- name: test
volumes: null
`)
th.WriteK(".", `
resources:
- deploy.yaml
`)
m := th.Run(".", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: test
spec:
template:
spec:
containers:
- name: test
volumes: null
`)
}

View File

@@ -215,25 +215,25 @@ spec2:
template:
spec:
containers:
- image: nginx:v1
- image: nginx:v2
name: nginx3
- image: my-nginx:latest
- image: my-nginx:previous
name: nginx4
spec3:
template:
spec:
initContainers:
- image: postgres:alpine-9
- image: my-postgres:v3
name: postgresdb
- image: docker:17-git
- image: my-docker@sha256:25a0d4b4
name: init-docker
- image: myprivaterepohostname:1234/my/image:latest
- image: myprivaterepohostname:1234/my/image:v1.0.1
name: myImage
- image: myprivaterepohostname:1234/my/image
- image: myprivaterepohostname:1234/my/image:v1.0.1
name: myImage2
- image: my-app-image:v1
name: my-app
- image: gcr.io:8080/my-project/my-cool-app:latest
- image: my-cool-app:latest
name: my-cool-app
`)
}

View File

@@ -20,6 +20,9 @@ type remoteTargetSpec struct {
// Dir is where the resource is saved
Dir filesys.ConfirmedDir
// TempDir is the directory created to hold all resources, including Dir
TempDir filesys.ConfirmedDir
}
// Getter is a function that can gets resource
@@ -31,7 +34,7 @@ func newLoaderAtGetter(raw string, fSys filesys.FileSystem, referrer *fileLoader
}
cleaner := func() error {
return fSys.RemoveAll(rs.Dir.String())
return fSys.RemoveAll(rs.TempDir.String())
}
if err := getter(rs); err != nil {
@@ -55,12 +58,12 @@ func newLoaderAtGetter(raw string, fSys filesys.FileSystem, referrer *fileLoader
func getRemoteTarget(rs *remoteTargetSpec) error {
var err error
rs.Dir, err = filesys.NewTmpConfirmedDir()
rs.TempDir, err = filesys.NewTmpConfirmedDir()
if err != nil {
return err
}
rs.Dir = filesys.ConfirmedDir(rs.Dir.Join("repo"))
rs.Dir = filesys.ConfirmedDir(rs.TempDir.Join("repo"))
// Get the pwd
pwd, err := os.Getwd()

View File

@@ -39,7 +39,7 @@ var (
ExitOnError = &commands.ExitOnError
)
// AddCommands adds the cfg, fn and live commands to kustomize.
// AddCommands adds the cfg and fn commands to kustomize.
func AddCommands(root *cobra.Command, name string) *cobra.Command {
commands.ExitOnError = true
@@ -48,7 +48,6 @@ func AddCommands(root *cobra.Command, name string) *cobra.Command {
root.AddCommand(GetCfg(name))
root.AddCommand(GetFn(name))
root.AddCommand(GetLive(name))
root.AddCommand(&cobra.Command{
Use: "docs-merge",

View File

@@ -53,7 +53,7 @@ func GetLive(name string) *cobra.Command {
cmd.AddCommand(
applyCmd,
initcmd.NewCmdInit(ioStreams),
initcmd.NewCmdInit(f, ioStreams),
preview.GetPreviewRunner(f, ioStreams).Command,
diff.NewCmdDiff(f, ioStreams),
destroy.GetDestroyRunner(f, ioStreams).Command)

View File

@@ -14,6 +14,6 @@ require (
k8s.io/cli-runtime v0.17.3
k8s.io/client-go v0.17.3
k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd
sigs.k8s.io/cli-utils v0.19.2
sigs.k8s.io/kustomize/kyaml v0.7.1
sigs.k8s.io/cli-utils v0.20.1
sigs.k8s.io/kustomize/kyaml v0.8.0
)

View File

@@ -283,6 +283,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@@ -615,14 +617,12 @@ modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
sigs.k8s.io/cli-utils v0.19.2 h1:BwidWPZ3Qop4RBOl27MU8uN/BSEZPQ8rw1mwsNofXfw=
sigs.k8s.io/cli-utils v0.19.2/go.mod h1:ulIQPERYwkYksNriRknJRbGECDR/ZZROpkiThlXBtB4=
sigs.k8s.io/cli-utils v0.20.1 h1:S3IM4Rmely9oWNAeytx46PhngTwdRxsJ4ixtoGWPc3o=
sigs.k8s.io/cli-utils v0.20.1/go.mod h1:fQkEMmLXduMNmUf1+dgQ5GRJa4OrrLMw3qzAN8YXAU8=
sigs.k8s.io/controller-runtime v0.4.0 h1:wATM6/m+3w8lj8FXNaO6Fs/rq/vqoOjO1Q116Z9NPsg=
sigs.k8s.io/controller-runtime v0.4.0/go.mod h1:ApC79lpY3PHW9xj/w9pj+lYkLgwAAUZwfXkME1Lajns=
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
sigs.k8s.io/kustomize/kyaml v0.7.1 h1:Ih6SJPvfKYfZaIFWUa2YAyg/0ZSTpA3LFjR/hv7+8ao=
sigs.k8s.io/kustomize/kyaml v0.7.1/go.mod h1:ne3F9JPhW2wrVaLslxBsEe6MQJQ9YK5rUutrdhBWXwI=
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/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU=

View File

@@ -4,9 +4,12 @@
package commands
import (
"fmt"
"io"
"strings"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio"
@@ -31,6 +34,8 @@ func NewAnnotateRunner(parent string) *AnnotateRunner {
c.Flags().StringVar(&r.Name, "name", "", "Resource name to annotate")
c.Flags().StringVar(&r.Namespace, "namespace", "", "Resource namespace to annotate")
c.Flags().StringSliceVar(&r.Values, "kv", []string{}, "annotation as KEY=VALUE")
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", false,
"add annotations recursively in all the nested subpackages")
return r
}
@@ -39,13 +44,14 @@ func AnnotateCommand(parent string) *cobra.Command {
}
type AnnotateRunner struct {
Command *cobra.Command
Values []string
Kind string
Name string
ApiVersion string
Namespace string
Path string
Command *cobra.Command
Values []string
Kind string
Name string
ApiVersion string
Namespace string
Path string
RecurseSubPackages bool
}
func (r *AnnotateRunner) runE(c *cobra.Command, args []string) error {
@@ -55,16 +61,54 @@ func (r *AnnotateRunner) runE(c *cobra.Command, args []string) error {
rw := &kio.ByteReadWriter{Reader: c.InOrStdin(), Writer: c.OutOrStdout()}
input = []kio.Reader{rw}
output = []kio.Writer{rw}
} else {
rw := &kio.LocalPackageReadWriter{PackagePath: args[0], NoDeleteFiles: true}
input = []kio.Reader{rw}
output = []kio.Writer{rw}
return handleError(c, kio.Pipeline{
Inputs: input,
Filters: []kio.Filter{r},
Outputs: output,
}.Execute())
}
return handleError(c, kio.Pipeline{
e := executeCmdOnPkgs{
writer: c.OutOrStdout(),
needOpenAPI: false,
recurseSubPackages: r.RecurseSubPackages,
cmdRunner: r,
rootPkgPath: args[0],
}
err := e.execute()
if err != nil {
return err
}
return nil
}
func (r *AnnotateRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
rw := &kio.LocalPackageReadWriter{PackagePath: pkgPath, NoDeleteFiles: true, PackageFileName: openAPIFileName}
input := []kio.Reader{rw}
output := []kio.Writer{rw}
err = kio.Pipeline{
Inputs: input,
Filters: []kio.Filter{r},
Outputs: output,
}.Execute())
}.Execute()
if err != nil {
// return err if there is only package
if !r.RecurseSubPackages {
return err
} else {
// print error message and continue if there are multiple packages to annotate
fmt.Fprintf(w, "%s\n", err.Error())
}
} else {
fmt.Fprint(w, "added annotations in the package\n")
}
return nil
}
func (r *AnnotateRunner) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {

View File

@@ -12,7 +12,9 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/kyaml/copyutil"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/openapi"
)
func TestAnnotateCommand(t *testing.T) {
@@ -486,3 +488,77 @@ spec:
replicas: 3
`
)
func TestAnnotateSubPackages(t *testing.T) {
var tests = []struct {
name string
dataset string
packagePath string
args []string
expected string
}{
{
name: "annotate-recurse-subpackages",
dataset: "dataset-without-setters",
args: []string{"--kv", "foo=bar", "-R"},
expected: `${baseDir}/mysql/
added annotations in the package
${baseDir}/mysql/storage/
added annotations in the package
`,
},
{
name: "annotate-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql",
args: []string{"--kv", "foo=bar"},
expected: `${baseDir}/mysql/
added annotations in the package
`,
},
{
name: "annotate-nested-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql/storage",
args: []string{"--kv", "foo=bar"},
expected: `${baseDir}/mysql/storage/
added annotations in the package
`,
},
}
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
// reset the openAPI afterward
openapi.ResetOpenAPI()
defer openapi.ResetOpenAPI()
sourceDir := filepath.Join("test", "testdata", test.dataset)
baseDir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
copyutil.CopyDir(sourceDir, baseDir)
defer os.RemoveAll(baseDir)
runner := NewAnnotateRunner("")
actual := &bytes.Buffer{}
runner.Command.SetOut(actual)
runner.Command.SetArgs(append([]string{filepath.Join(baseDir, test.packagePath)}, test.args...))
err = runner.Command.Execute()
if !assert.NoError(t, err) {
t.FailNow()
}
// normalize path format for windows
actualNormalized := strings.Replace(
strings.Replace(actual.String(), "\\", "/", -1),
"//", "/", -1)
expected := strings.Replace(test.expected, "${baseDir}", baseDir, -1)
expectedNormalized := strings.Replace(expected, "\\", "/", -1)
if !assert.Equal(t, expectedNormalized, actualNormalized) {
t.FailNow()
}
})
}
}

View File

@@ -5,9 +5,11 @@ package commands
import (
"fmt"
"io"
"os"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio"
@@ -19,15 +21,14 @@ import (
func GetCatRunner(name string) *CatRunner {
r := &CatRunner{}
c := &cobra.Command{
Use: "cat DIR...",
Use: "cat DIR",
Short: commands.CatShort,
Long: commands.CatLong,
Example: commands.CatExamples,
RunE: r.runE,
Args: cobra.MaximumNArgs(1),
}
fixDocs(name, c)
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
"also print resources from subpackages.")
c.Flags().BoolVar(&r.Format, "format", true,
"format resource config yaml before printing.")
c.Flags().BoolVar(&r.KeepAnnotations, "annotate", false,
@@ -49,6 +50,8 @@ func GetCatRunner(name string) *CatRunner {
"if true, exclude non-local-config in the output.")
c.Flags().StringVar(&r.OutputDest, "dest", "",
"if specified, write output to a file rather than stdout")
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", true,
"print resources recursively in all the nested subpackages")
r.Command = c
return r
}
@@ -59,7 +62,6 @@ func CatCommand(name string) *cobra.Command {
// CatRunner contains the run function
type CatRunner struct {
IncludeSubpackages bool
Format bool
KeepAnnotations bool
WrapKind string
@@ -71,56 +73,102 @@ type CatRunner struct {
IncludeLocal bool
ExcludeNonLocal bool
Command *cobra.Command
RecurseSubPackages bool
}
func (r *CatRunner) runE(c *cobra.Command, args []string) error {
// if there is a function-config specified, emit it
var writer = c.OutOrStdout()
if r.OutputDest != "" {
o, err := os.Create(r.OutputDest)
if err != nil {
return errors.Wrap(err)
}
defer o.Close()
writer = o
}
if len(args) == 0 {
input := &kio.ByteReader{Reader: c.InOrStdin()}
// if there is a function-config specified, emit it
outputs, err := r.out(writer)
if err != nil {
return err
}
return handleError(c, kio.Pipeline{Inputs: []kio.Reader{input}, Filters: r.catFilters(), Outputs: outputs}.Execute())
}
e := executeCmdOnPkgs{
writer: writer,
needOpenAPI: false,
recurseSubPackages: r.RecurseSubPackages,
cmdRunner: r,
rootPkgPath: args[0],
skipPkgPathPrint: true,
}
return e.execute()
}
func (r *CatRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: openAPIFileName}
outputs, err := r.out(w)
if err != nil {
return err
}
err = kio.Pipeline{
Inputs: []kio.Reader{input},
Filters: r.catFilters(),
Outputs: outputs,
}.Execute()
if err != nil {
// return err if there is only package
if !r.RecurseSubPackages {
return err
} else {
// print error message and continue if there are multiple packages to annotate
fmt.Fprintf(w, "%s in package %q\n", err.Error(), pkgPath)
}
}
fmt.Fprintf(w, "---")
return nil
}
func (r *CatRunner) catFilters() []kio.Filter {
var fltrs []kio.Filter
// don't include reconcilers
fltrs = append(fltrs, &filters.IsLocalConfig{
IncludeLocalConfig: r.IncludeLocal,
ExcludeNonLocalConfig: r.ExcludeNonLocal,
})
if r.Format {
fltrs = append(fltrs, filters.FormatFilter{})
}
if r.StripComments {
fltrs = append(fltrs, filters.StripCommentsFilter{})
}
return fltrs
}
func (r *CatRunner) out(w io.Writer) ([]kio.Writer, error) {
var outputs []kio.Writer
var functionConfig *yaml.RNode
if r.FunctionConfig != "" {
configs, err := kio.LocalPackageReader{PackagePath: r.FunctionConfig,
OmitReaderAnnotations: !r.KeepAnnotations}.Read()
if err != nil {
return err
return outputs, err
}
if len(configs) != 1 {
return fmt.Errorf("expected exactly 1 functionConfig, found %d", len(configs))
return outputs, fmt.Errorf("expected exactly 1 functionConfig, found %d", len(configs))
}
functionConfig = configs[0]
}
var inputs []kio.Reader
for _, a := range args {
inputs = append(inputs, kio.LocalPackageReader{
PackagePath: a,
IncludeSubpackages: r.IncludeSubpackages,
})
}
if len(inputs) == 0 {
inputs = append(inputs, &kio.ByteReader{Reader: c.InOrStdin()})
}
var fltr []kio.Filter
// don't include reconcilers
fltr = append(fltr, &filters.IsLocalConfig{
IncludeLocalConfig: r.IncludeLocal,
ExcludeNonLocalConfig: r.ExcludeNonLocal,
})
if r.Format {
fltr = append(fltr, filters.FormatFilter{})
}
if r.StripComments {
fltr = append(fltr, filters.StripCommentsFilter{})
}
var out = c.OutOrStdout()
if r.OutputDest != "" {
o, err := os.Create(r.OutputDest)
if err != nil {
return handleError(c, errors.Wrap(err))
}
defer o.Close()
out = o
}
// remove this annotation explicitly, the ByteWriter won't clear it by
// default because it doesn't set it
clear := []string{"config.kubernetes.io/path"}
@@ -128,9 +176,8 @@ func (r *CatRunner) runE(c *cobra.Command, args []string) error {
clear = nil
}
var outputs []kio.Writer
outputs = append(outputs, kio.ByteWriter{
Writer: out,
Writer: w,
KeepReaderAnnotations: r.KeepAnnotations,
WrappingKind: r.WrapKind,
WrappingAPIVersion: r.WrapApiVersion,
@@ -139,5 +186,5 @@ func (r *CatRunner) runE(c *cobra.Command, args []string) error {
ClearAnnotations: clear,
})
return handleError(c, kio.Pipeline{Inputs: inputs, Filters: fltr, Outputs: outputs}.Execute())
return outputs, nil
}

View File

@@ -8,10 +8,13 @@ import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/kyaml/copyutil"
"sigs.k8s.io/kustomize/kyaml/openapi"
)
// TODO(pwittrock): write tests for reading / writing ResourceLists
@@ -112,7 +115,7 @@ metadata:
app: nginx
spec:
replicas: 3
`, b.String()) {
---`, b.String()) {
return
}
}
@@ -168,8 +171,7 @@ metadata:
annotations:
app: nginx
spec:
replicas: 3
`), 0600)
replicas: 3`), 0600)
if !assert.NoError(t, err) {
return
}
@@ -223,7 +225,7 @@ metadata:
app: nginx
spec:
replicas: 3
`, b.String()) {
---`, b.String()) {
return
}
}
@@ -305,7 +307,7 @@ metadata:
image: gcr.io/example/reconciler:v1
spec:
replicas: 3
`, b.String()) {
---`, b.String()) {
return
}
}
@@ -362,8 +364,7 @@ metadata:
annotations:
app: nginx
spec:
replicas: 3
`), 0600)
replicas: 3`), 0600)
if !assert.NoError(t, err) {
return
}
@@ -420,7 +421,7 @@ metadata:
app: nginx
spec:
replicas: 3
`, string(actual)) {
---`, string(actual)) {
return
}
}
@@ -477,8 +478,7 @@ metadata:
annotations:
app: nginx
spec:
replicas: 3
`), 0600)
replicas: 3`), 0600)
if !assert.NoError(t, err) {
return
}
@@ -536,7 +536,132 @@ metadata:
app: nginx
spec:
replicas: 3
`, string(actual)) {
---`, string(actual)) {
return
}
}
func TestCatSubPackages(t *testing.T) {
var tests = []struct {
name string
dataset string
packagePath string
args []string
expected string
}{
{
name: "cat-recurse-subpackages",
dataset: "dataset-without-setters",
expected: `# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-deployment
namespace: myspace
spec:
replicas: 3
template:
spec:
containers:
- name: mysql
image: mysql:1.7.9
---
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
name: storage-deployment
namespace: myspace
spec:
replicas: 4
template:
spec:
containers:
- name: storage
image: storage:1.7.7
---`,
},
{
name: "cat-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
args: []string{"-R=false"},
packagePath: "mysql",
expected: `# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-deployment
namespace: myspace
spec:
replicas: 3
template:
spec:
containers:
- name: mysql
image: mysql:1.7.9
---`,
},
{
name: "cat-nested-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql/storage",
args: []string{"-R=false"},
expected: `# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
name: storage-deployment
namespace: myspace
spec:
replicas: 4
template:
spec:
containers:
- name: storage
image: storage:1.7.7
---`,
},
}
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
// reset the openAPI afterward
openapi.ResetOpenAPI()
defer openapi.ResetOpenAPI()
sourceDir := filepath.Join("test", "testdata", test.dataset)
baseDir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
copyutil.CopyDir(sourceDir, baseDir)
defer os.RemoveAll(baseDir)
runner := commands.GetCatRunner("")
actual := &bytes.Buffer{}
runner.Command.SetOut(actual)
runner.Command.SetArgs(append([]string{filepath.Join(baseDir, test.packagePath)}, test.args...))
err = runner.Command.Execute()
if !assert.NoError(t, err) {
t.FailNow()
}
// normalize path format for windows
actualNormalized := strings.Replace(
strings.Replace(actual.String(), "\\", "/", -1),
"//", "/", -1)
expected := strings.Replace(test.expected, "${baseDir}", baseDir, -1)
expectedNormalized := strings.Replace(expected, "\\", "/", -1)
if !assert.Equal(t, expectedNormalized, actualNormalized) {
t.FailNow()
}
})
}
}

View File

@@ -5,7 +5,10 @@ package commands
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"path/filepath"
"strings"
"github.com/go-openapi/spec"
@@ -13,9 +16,7 @@ import (
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/setters"
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
)
@@ -59,6 +60,8 @@ func NewCreateSetterRunner(parent string) *CreateSetterRunner {
set.Flags().StringVar(&r.SchemaPath, "schema-path", "",
`openAPI schema file path for setter constraints -- file content `+
`e.g. {"type": "string", "maxLength": 15, "enum": ["allowedValue1", "allowedValue2"]}`)
set.Flags().BoolVarP(&r.CreateSetter.RecurseSubPackages, "recurse-subpackages", "R", false,
"creates setter recursively in all the nested subpackages")
set.Flags().MarkHidden("version")
fixDocs(parent, set)
r.Command = set
@@ -78,7 +81,7 @@ type CreateSetterRunner struct {
}
func (r *CreateSetterRunner) runE(c *cobra.Command, args []string) error {
return handleError(c, r.set(c, args))
return handleError(c, r.createSetter(c, args))
}
func (r *CreateSetterRunner) preRunE(c *cobra.Command, args []string) error {
@@ -111,42 +114,6 @@ func (r *CreateSetterRunner) preRunE(c *cobra.Command, args []string) error {
}
if setterVersion == "v2" {
var err error
r.OpenAPIFile, err = ext.GetOpenAPIFile(args)
if err != nil {
return err
}
if err := openapi.AddSchemaFromFile(r.OpenAPIFile); err != nil {
return err
}
// check if substitution with same name exists and throw error
ref, err := spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SubstitutionDefinitionPrefix + r.CreateSetter.Name)
if err != nil {
return err
}
subst, _ := openapi.Resolve(&ref)
// if substitution already exists with the input setter name, throw error
if subst != nil {
return errors.Errorf("substitution with name %s already exists, "+
"substitution and setter can't have same name", r.CreateSetter.Name)
}
// check if setter with same name exists and throw error
ref, err = spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SetterDefinitionPrefix + r.CreateSetter.Name)
if err != nil {
return err
}
setter, _ := openapi.Resolve(&ref)
// if setter already exists with the input setter name, throw error
if setter != nil {
return errors.Errorf("setter with name %s already exists, "+
"if you want to modify it, please delete the existing setter and recreate it", r.CreateSetter.Name)
}
r.CreateSetter.Description = r.Set.SetPartialField.Description
r.CreateSetter.SetBy = r.Set.SetPartialField.SetBy
r.CreateSetter.Type = r.Set.SetPartialField.Type
@@ -210,9 +177,20 @@ func (r *CreateSetterRunner) processSchema() error {
return nil
}
func (r *CreateSetterRunner) set(c *cobra.Command, args []string) error {
func (r *CreateSetterRunner) createSetter(c *cobra.Command, args []string) error {
if setterVersion == "v2" {
return r.CreateSetter.Create(r.OpenAPIFile, args[0])
e := executeCmdOnPkgs{
needOpenAPI: true,
writer: c.OutOrStdout(),
rootPkgPath: args[0],
recurseSubPackages: r.CreateSetter.RecurseSubPackages,
cmdRunner: r,
}
err := e.execute()
if err != nil {
return handleError(c, err)
}
return nil
}
rw := &kio.LocalPackageReadWriter{PackagePath: args[0]}
@@ -226,6 +204,41 @@ func (r *CreateSetterRunner) set(c *cobra.Command, args []string) error {
return nil
}
func (r *CreateSetterRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
r.CreateSetter = settersutil.SetterCreator{
Name: r.CreateSetter.Name,
SetBy: r.CreateSetter.SetBy,
Description: r.CreateSetter.Description,
Type: r.CreateSetter.Type,
Schema: r.CreateSetter.Schema,
FieldName: r.CreateSetter.FieldName,
FieldValue: r.CreateSetter.FieldValue,
Required: r.CreateSetter.Required,
RecurseSubPackages: r.CreateSetter.RecurseSubPackages,
OpenAPIFileName: openAPIFileName,
OpenAPIPath: filepath.Join(pkgPath, openAPIFileName),
ResourcesPath: pkgPath,
}
err = r.CreateSetter.Create()
if err != nil {
// return err if RecurseSubPackages is false
if !r.CreateSetter.RecurseSubPackages {
return err
} else {
// print error message and continue if RecurseSubPackages is true
fmt.Fprintf(w, "%s\n", err.Error())
}
} else {
fmt.Fprintf(w, "created setter %q\n", r.CreateSetter.Name)
}
return nil
}
// schemaFromFile reads the contents from schemaPath and returns schema
func schemaFromFile(schemaPath string) (*spec.Schema, error) {
sc := &spec.Schema{}

View File

@@ -7,12 +7,13 @@ import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/kyaml/copyutil"
"sigs.k8s.io/kustomize/kyaml/openapi"
)
@@ -43,6 +44,7 @@ spec:
apiVersion: v1alpha1
kind: Example
`,
out: `created setter "replicas"`,
expectedOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -81,6 +83,7 @@ spec:
apiVersion: v1alpha1
kind: Example
`,
out: `created setter "replicas"`,
expectedOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -122,7 +125,7 @@ openAPI:
- marker: ${my-tag-setter}
ref: '#/definitions/io.k8s.cli.setters.my-tag-setter'
`,
err: "substitution with name my-image already exists, substitution and setter can't have same name",
err: `substitution with name "my-image" already exists, substitution and setter can't have same name`,
},
{
@@ -140,7 +143,7 @@ openAPI:
name: my-image
value: "nginx"
`,
err: "setter with name my-image already exists, if you want to modify it, please delete the existing setter and recreate it",
err: `setter with name "my-image" already exists, if you want to modify it, please delete the existing setter and recreate it`,
},
{
@@ -159,6 +162,7 @@ spec:
apiVersion: v1alpha1
kind: Example
`,
out: `created setter "replicas"`,
expectedOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -200,6 +204,7 @@ spec:
apiVersion: v1alpha1
kind: Example
`,
out: `created setter replicas`,
expectedOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -254,6 +259,7 @@ spec:
apiVersion: v1alpha1
kind: Example
`,
out: `created setter "list"`,
expectedOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -354,6 +360,7 @@ spec:
apiVersion: v1alpha1
kind: Example
`,
out: `created setter replicas`,
expectedOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -400,6 +407,7 @@ spec:
apiVersion: v1alpha1
kind: Example
`,
out: `created setter "replicas"`,
expectedOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -437,6 +445,7 @@ spec:
apiVersion: v1alpha1
kind: Example
`,
out: `created setter "foo.bar"`,
expectedOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -587,6 +596,7 @@ spec:
apiVersion: v1alpha1
kind: Example
`,
out: `created setter "replicas"`,
expectedOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -712,6 +722,7 @@ spec:
apiVersion: v1alpha1
kind: Example
`,
out: `created setter "replicas"`,
expectedOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -742,13 +753,14 @@ spec:
openapi.ResetOpenAPI()
defer openapi.ResetOpenAPI()
f, err := ioutil.TempFile("", "k8s-cli-")
baseDir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
defer os.Remove(f.Name())
defer os.RemoveAll(baseDir)
err = ioutil.WriteFile(f.Name(), []byte(test.inputOpenAPI), 0600)
f := filepath.Join(baseDir, "Krmfile")
err = ioutil.WriteFile(f, []byte(test.inputOpenAPI), 0600)
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -768,13 +780,7 @@ spec:
test.args = append(test.args, "--schema-path", sch.Name())
}
old := ext.GetOpenAPIFile
defer func() { ext.GetOpenAPIFile = old }()
ext.GetOpenAPIFile = func(args []string) (s string, err error) {
return f.Name(), nil
}
r, err := ioutil.TempFile("", "k8s-cli-*.yaml")
r, err := ioutil.TempFile(baseDir, "k8s-cli-*.yaml")
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -787,7 +793,7 @@ spec:
runner := commands.NewCreateSetterRunner("")
out := &bytes.Buffer{}
runner.Command.SetOut(out)
runner.Command.SetArgs(append([]string{r.Name()}, test.args...))
runner.Command.SetArgs(append([]string{baseDir}, test.args...))
err = runner.Command.Execute()
if test.err != "" {
if !assert.NotNil(t, err) {
@@ -801,7 +807,14 @@ spec:
t.FailNow()
}
if !assert.Equal(t, test.out, out.String()) {
expectedOut := strings.Replace(test.out, "${baseDir}", baseDir, -1)
expectedNormalized := strings.Replace(expectedOut, "\\", "/", -1)
// normalize path format for windows
actualNormalized := strings.Replace(
strings.Replace(out.String(), "\\", "/", -1),
"//", "/", -1)
if !assert.Contains(t, actualNormalized, expectedNormalized) {
t.FailNow()
}
@@ -815,7 +828,7 @@ spec:
t.FailNow()
}
actualOpenAPI, err := ioutil.ReadFile(f.Name())
actualOpenAPI, err := ioutil.ReadFile(f)
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -827,3 +840,92 @@ spec:
})
}
}
func TestCreateSetterSubPackages(t *testing.T) {
var tests = []struct {
name string
dataset string
packagePath string
args []string
expected string
}{
{
name: "create-setter-recurse-subpackages",
dataset: "dataset-without-setters",
args: []string{"namespace", "myspace", "-R"},
expected: `${baseDir}/mysql/
created setter "namespace"
${baseDir}/mysql/storage/
created setter "namespace"
`,
},
{
name: "create-setter-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql",
args: []string{"namespace", "myspace"},
expected: `${baseDir}/mysql/
created setter "namespace"
`,
},
{
name: "create-setter-nested-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql/storage",
args: []string{"namespace", "myspace"},
expected: `${baseDir}/mysql/storage/
created setter "namespace"
`,
},
{
name: "create-setter-already-exists",
dataset: "dataset-with-setters",
packagePath: "mysql",
args: []string{"namespace", "myspace", "-R"},
expected: `${baseDir}/mysql/
setter with name "namespace" already exists, if you want to modify it, please delete the existing setter and recreate it
${baseDir}/mysql/nosetters/
created setter "namespace"
${baseDir}/mysql/storage/
setter with name "namespace" already exists, if you want to modify it, please delete the existing setter and recreate it
`,
},
}
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
// reset the openAPI afterward
openapi.ResetOpenAPI()
defer openapi.ResetOpenAPI()
sourceDir := filepath.Join("test", "testdata", test.dataset)
baseDir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
copyutil.CopyDir(sourceDir, baseDir)
defer os.RemoveAll(baseDir)
runner := commands.NewCreateSetterRunner("")
actual := &bytes.Buffer{}
runner.Command.SetOut(actual)
runner.Command.SetArgs(append([]string{filepath.Join(baseDir, test.packagePath)}, test.args...))
err = runner.Command.Execute()
if !assert.NoError(t, err) {
t.FailNow()
}
// normalize path format for windows
actualNormalized := strings.Replace(
strings.Replace(actual.String(), "\\", "/", -1),
"//", "/", -1)
expected := strings.Replace(test.expected, "${baseDir}", baseDir, -1)
expectedNormalized := strings.Replace(expected, "\\", "/", -1)
if !assert.Equal(t, expectedNormalized, actualNormalized) {
t.FailNow()
}
})
}
}

View File

@@ -5,13 +5,11 @@ package commands
import (
"fmt"
"io"
"path/filepath"
"github.com/go-openapi/spec"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
)
@@ -19,10 +17,10 @@ import (
func NewCreateSubstitutionRunner(parent string) *CreateSubstitutionRunner {
r := &CreateSubstitutionRunner{}
cs := &cobra.Command{
Use: "create-subst DIR NAME",
Args: cobra.ExactArgs(2),
PreRunE: r.preRunE,
RunE: r.runE,
Use: "create-subst DIR NAME",
Args: cobra.ExactArgs(2),
PreRun: r.preRun,
RunE: r.runE,
}
cs.Flags().StringVar(&r.CreateSubstitution.FieldName, "field", "",
"name of the field to set -- e.g. --field image")
@@ -30,6 +28,8 @@ func NewCreateSubstitutionRunner(parent string) *CreateSubstitutionRunner {
"value of the field to create substitution for -- e.g. --field-value nginx:0.1.0")
cs.Flags().StringVar(&r.CreateSubstitution.Pattern, "pattern", "",
`substitution pattern -- e.g. --pattern \${my-image-setter}:\${my-tag-setter}`)
cs.Flags().BoolVarP(&r.CreateSubstitution.RecurseSubPackages, "recurse-subpackages", "R", false,
"creates substitution recursively in all the nested subpackages")
_ = cs.MarkFlagRequired("pattern")
_ = cs.MarkFlagRequired("field-value")
fixDocs(parent, cs)
@@ -49,49 +49,52 @@ type CreateSubstitutionRunner struct {
}
func (r *CreateSubstitutionRunner) runE(c *cobra.Command, args []string) error {
return handleError(c, r.CreateSubstitution.Create(r.OpenAPIFile, args[0]))
}
func (r *CreateSubstitutionRunner) preRunE(c *cobra.Command, args []string) error {
var err error
r.CreateSubstitution.Name = args[1]
e := executeCmdOnPkgs{
needOpenAPI: true,
writer: c.OutOrStdout(),
rootPkgPath: args[0],
recurseSubPackages: r.CreateSubstitution.RecurseSubPackages,
cmdRunner: r,
}
err := e.execute()
if err != nil {
return err
}
r.OpenAPIFile, err = ext.GetOpenAPIFile(args)
if err != nil {
return err
}
if err := openapi.AddSchemaFromFile(r.OpenAPIFile); err != nil {
return err
}
// check if substitution with same name exists and throw error
ref, err := spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SubstitutionDefinitionPrefix + r.CreateSubstitution.Name)
if err != nil {
return err
}
subst, _ := openapi.Resolve(&ref)
// if substitution already exists with the input substitution name, throw error
if subst != nil {
return errors.Errorf("substitution with name %s already exists", r.CreateSubstitution.Name)
}
// check if setter with same name exists and throw error
ref, err = spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SetterDefinitionPrefix + r.CreateSubstitution.Name)
if err != nil {
return err
}
setter, _ := openapi.Resolve(&ref)
// if setter already exists with input substitution name, throw error
if setter != nil {
return errors.Errorf(fmt.Sprintf("setter with name %s already exists, "+
"substitution and setter can't have same name", r.CreateSubstitution.Name))
return handleError(c, err)
}
return nil
}
func (r *CreateSubstitutionRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
r.CreateSubstitution = settersutil.SubstitutionCreator{
Name: r.CreateSubstitution.Name,
FieldName: r.CreateSubstitution.FieldName,
FieldValue: r.CreateSubstitution.FieldValue,
RecurseSubPackages: r.CreateSubstitution.RecurseSubPackages,
Pattern: r.CreateSubstitution.Pattern,
OpenAPIFileName: openAPIFileName,
OpenAPIPath: filepath.Join(pkgPath, openAPIFileName),
ResourcesPath: pkgPath,
}
err = r.CreateSubstitution.Create()
if err != nil {
// return err if RecurseSubPackages is false
if !r.CreateSubstitution.RecurseSubPackages {
return err
} else {
// print error message and continue if RecurseSubPackages is true
fmt.Fprintf(w, "%s\n", err.Error())
}
} else {
fmt.Fprintf(w, "created substitution %q\n", r.CreateSubstitution.Name)
}
return nil
}
func (r *CreateSubstitutionRunner) preRun(c *cobra.Command, args []string) {
r.CreateSubstitution.Name = args[1]
}

View File

@@ -7,12 +7,13 @@ import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/kyaml/copyutil"
"sigs.k8s.io/kustomize/kyaml/openapi"
)
@@ -62,6 +63,7 @@ openAPI:
name: my-tag-setter
value: "1.7.9"
`,
out: `created substitution "my-image-subst"`,
expectedOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -123,7 +125,7 @@ openAPI:
- marker: ${my-tag-setter}
ref: '#/definitions/io.k8s.cli.setters.my-tag-setter'
`,
err: "substitution with name my-image already exists",
err: `substitution with name "my-image" already exists`,
},
{
name: "error if setter with same name exists",
@@ -140,7 +142,7 @@ openAPI:
name: my-image
value: "nginx"
`,
err: "setter with name my-image already exists, substitution and setter can't have same name",
err: `setter with name "my-image" already exists, substitution and setter can't have same name`,
},
{
name: "substitution and create setters 1",
@@ -165,6 +167,7 @@ spec:
apiVersion: v1alpha1
kind: Example
`,
out: `created substitution "my-image-subst"`,
expectedOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -253,6 +256,7 @@ openAPI:
- marker: ${my-tag-setter}
ref: '#/definitions/io.k8s.cli.setters.my-tag-setter'
`,
out: `created substitution "my-nested-subst"`,
expectedOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -341,7 +345,7 @@ spec:
substVal: prefix-1234
`,
err: "setters must have different name than the substitution: foo",
err: `setters must have different name than the substitution: foo`,
},
}
for i := range tests {
@@ -351,22 +355,18 @@ spec:
openapi.ResetOpenAPI()
defer openapi.ResetOpenAPI()
f, err := ioutil.TempFile("", "k8s-cli-")
baseDir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
defer os.Remove(f.Name())
err = ioutil.WriteFile(f.Name(), []byte(test.inputOpenAPI), 0600)
defer os.RemoveAll(baseDir)
f := filepath.Join(baseDir, "Krmfile")
err = ioutil.WriteFile(f, []byte(test.inputOpenAPI), 0600)
if !assert.NoError(t, err) {
t.FailNow()
}
old := ext.GetOpenAPIFile
defer func() { ext.GetOpenAPIFile = old }()
ext.GetOpenAPIFile = func(args []string) (s string, err error) {
return f.Name(), nil
}
r, err := ioutil.TempFile("", "k8s-cli-*.yaml")
r, err := ioutil.TempFile(baseDir, "k8s-cli-*.yaml")
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -379,7 +379,7 @@ spec:
runner := commands.NewCreateSubstitutionRunner("")
out := &bytes.Buffer{}
runner.Command.SetOut(out)
runner.Command.SetArgs(append([]string{r.Name()}, test.args...))
runner.Command.SetArgs(append([]string{baseDir}, test.args...))
err = runner.Command.Execute()
if test.err != "" {
@@ -393,7 +393,14 @@ spec:
t.FailNow()
}
if !assert.Equal(t, test.out, out.String()) {
expectedOut := strings.Replace(test.out, "${baseDir}", baseDir, -1)
expectedNormalized := strings.Replace(expectedOut, "\\", "/", -1)
// normalize path format for windows
actualNormalized := strings.Replace(
strings.Replace(out.String(), "\\", "/", -1),
"//", "/", -1)
if !assert.Contains(t, actualNormalized, expectedNormalized) {
t.FailNow()
}
@@ -407,7 +414,7 @@ spec:
t.FailNow()
}
actualOpenAPI, err := ioutil.ReadFile(f.Name())
actualOpenAPI, err := ioutil.ReadFile(f)
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -419,3 +426,89 @@ spec:
})
}
}
func TestCreateSubstSubPackages(t *testing.T) {
var tests = []struct {
name string
dataset string
packagePath string
args []string
expected string
}{
{
name: "create-subst-recurse-subpackages",
dataset: "dataset-without-setters",
args: []string{"image-tag", "--field-value", "mysql:1.7.9", "--pattern", "${image}:${tag}", "-R"},
expected: `${baseDir}/mysql/
created substitution "image-tag"
${baseDir}/mysql/storage/
created substitution "image-tag"
`,
},
{
name: "create-subst-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql",
args: []string{"image-tag", "--field-value", "mysql:1.7.9", "--pattern", "${image}:${tag}"},
expected: `${baseDir}/mysql/
created substitution "image-tag"`,
},
{
name: "create-subst-nested-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql/storage",
args: []string{"image-tag", "--field-value", "storage:1.7.9", "--pattern", "${image}:${tag}"},
expected: `${baseDir}/mysql/storage/
created substitution "image-tag"`,
},
{
name: "create-subst-already-exists",
dataset: "dataset-with-setters",
packagePath: "mysql",
args: []string{"image-tag", "--field-value", "mysql:1.7.9", "--pattern", "${image}:${tag}", "-R"},
expected: `${baseDir}/mysql/
substitution with name "image-tag" already exists
${baseDir}/mysql/nosetters/
created substitution "image-tag"
${baseDir}/mysql/storage/
created substitution "image-tag"`,
},
}
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
// reset the openAPI afterward
openapi.ResetOpenAPI()
defer openapi.ResetOpenAPI()
sourceDir := filepath.Join("test", "testdata", test.dataset)
baseDir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
copyutil.CopyDir(sourceDir, baseDir)
defer os.RemoveAll(baseDir)
runner := commands.NewCreateSubstitutionRunner("")
actual := &bytes.Buffer{}
runner.Command.SetOut(actual)
runner.Command.SetArgs(append([]string{filepath.Join(baseDir, test.packagePath)}, test.args...))
err = runner.Command.Execute()
if !assert.NoError(t, err) {
t.FailNow()
}
// normalize path format for windows
actualNormalized := strings.Replace(
strings.Replace(actual.String(), "\\", "/", -1),
"//", "/", -1)
expected := strings.Replace(test.expected, "${baseDir}", baseDir, -1)
expectedNormalized := strings.Replace(expected, "\\", "/", -1)
if !assert.Equal(t, strings.TrimSpace(expectedNormalized), strings.TrimSpace(actualNormalized)) {
t.FailNow()
}
})
}
}

View File

@@ -4,11 +4,14 @@
package commands
import (
"fmt"
"io"
"path/filepath"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
)
@@ -24,6 +27,8 @@ func NewDeleteSetterRunner(parent string) *DeleteSetterRunner {
PreRunE: r.preRunE,
RunE: r.runE,
}
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", false,
"deletes setter recursively in all the nested subpackages")
fixDocs(parent, c)
r.Command = c
@@ -35,9 +40,10 @@ func DeleteSetterCommand(parent string) *cobra.Command {
}
type DeleteSetterRunner struct {
Command *cobra.Command
DeleteSetter settersutil.DeleterCreator
OpenAPIFile string
Command *cobra.Command
DeleteSetter settersutil.DeleterCreator
OpenAPIFile string
RecurseSubPackages bool
}
func (r *DeleteSetterRunner) preRunE(c *cobra.Command, args []string) error {
@@ -50,17 +56,49 @@ func (r *DeleteSetterRunner) preRunE(c *cobra.Command, args []string) error {
return err
}
if err := openapi.AddSchemaFromFile(r.OpenAPIFile); err != nil {
return err
}
return nil
}
func (r *DeleteSetterRunner) runE(c *cobra.Command, args []string) error {
return handleError(c, r.delete(c, args))
e := executeCmdOnPkgs{
needOpenAPI: true,
writer: c.OutOrStdout(),
rootPkgPath: args[0],
recurseSubPackages: r.RecurseSubPackages,
cmdRunner: r,
}
err := e.execute()
if err != nil {
return handleError(c, err)
}
return nil
}
func (r *DeleteSetterRunner) delete(c *cobra.Command, args []string) error {
return r.DeleteSetter.Delete(r.OpenAPIFile, args[0])
func (r *DeleteSetterRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
r.DeleteSetter = settersutil.DeleterCreator{
Name: r.DeleteSetter.Name,
DefinitionPrefix: fieldmeta.SetterDefinitionPrefix,
RecurseSubPackages: r.RecurseSubPackages,
OpenAPIFileName: openAPIFileName,
OpenAPIPath: filepath.Join(pkgPath, openAPIFileName),
ResourcesPath: pkgPath,
}
err = r.DeleteSetter.Delete()
if err != nil {
// return err if RecurseSubPackages is false
if !r.DeleteSetter.RecurseSubPackages {
return err
} else {
// print error message and continue if RecurseSubPackages is true
fmt.Fprintf(w, "%s\n", err.Error())
}
} else {
fmt.Fprintf(w, "deleted setter %q\n", r.DeleteSetter.Name)
}
return nil
}

View File

@@ -7,12 +7,13 @@ import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/kyaml/copyutil"
"sigs.k8s.io/kustomize/kyaml/openapi"
)
@@ -52,6 +53,7 @@ openAPI:
value: "3"
setBy: me
`,
out: `deleted setter "replicas-setter"`,
expectedOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -95,6 +97,7 @@ openAPI:
name: image
value: nginx
`,
out: `deleted setter "replicas-setter"`,
expectedOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -158,6 +161,7 @@ spec:
- "b"
- "c"
`,
out: `deleted setter "list"`,
expectedResources: `
apiVersion: example.com/v1beta1
kind: Example1
@@ -226,7 +230,7 @@ metadata:
spec:
replicas: 3 # {"$openapi" : "replicas-setter"}
`,
err: `setter with name image does not exist`,
err: `setter "image" does not exist`,
},
{
name: "delete setter used in substitution error",
@@ -287,7 +291,7 @@ openAPI:
apiVersion: apps/v1
kind: Deployment
`,
err: `setter is used in substitution image, please delete the parent substitution first`,
err: `setter "image-name" is used in substitution "image", please delete the parent substitution first`,
},
}
for i := range tests {
@@ -297,24 +301,18 @@ kind: Deployment
openapi.ResetOpenAPI()
defer openapi.ResetOpenAPI()
f, err := ioutil.TempFile("", "k8s-cli-")
baseDir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
defer os.Remove(f.Name())
err = ioutil.WriteFile(f.Name(), []byte(test.inputOpenAPI), 0600)
defer os.RemoveAll(baseDir)
f := filepath.Join(baseDir, "Krmfile")
err = ioutil.WriteFile(f, []byte(test.inputOpenAPI), 0600)
if !assert.NoError(t, err) {
t.FailNow()
}
old := ext.GetOpenAPIFile
defer func() { ext.GetOpenAPIFile = old }()
ext.GetOpenAPIFile = func(args []string) (s string, err error) {
return f.Name(), nil
}
r, err := ioutil.TempFile("", "k8s-cli-*.yaml")
r, err := ioutil.TempFile(baseDir, "k8s-cli-*.yaml")
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -327,21 +325,29 @@ kind: Deployment
runner := commands.NewDeleteSetterRunner("")
out := &bytes.Buffer{}
runner.Command.SetOut(out)
runner.Command.SetArgs(append([]string{r.Name()}, test.args...))
runner.Command.SetArgs(append([]string{baseDir}, test.args...))
err = runner.Command.Execute()
if test.err != "" {
if !assert.NotNil(t, err) {
t.FailNow()
} else {
assert.Equal(t, err.Error(), test.err)
return
}
assert.Equal(t, test.err, err.Error())
return
}
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Equal(t, test.out, out.String()) {
// normalize path format for windows
actualNorm := strings.Replace(
strings.Replace(out.String(), "\\", "/", -1),
"//", "/", -1)
expectedOut := strings.Replace(test.out, "${baseDir}", baseDir, -1)
expectedNormalized := strings.Replace(expectedOut, "\\", "/", -1)
if !assert.Contains(t, strings.TrimSpace(actualNorm), expectedNormalized) {
t.FailNow()
}
@@ -355,7 +361,7 @@ kind: Deployment
t.FailNow()
}
actualOpenAPI, err := ioutil.ReadFile(f.Name())
actualOpenAPI, err := ioutil.ReadFile(f)
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -367,3 +373,80 @@ kind: Deployment
})
}
}
func TestDeleteSetterSubPackages(t *testing.T) {
var tests = []struct {
name string
dataset string
packagePath string
args []string
expected string
}{
{
name: "delete-setter-recurse-subpackages",
dataset: "dataset-with-setters",
args: []string{"namespace", "-R"},
expected: `${baseDir}/mysql/
deleted setter "namespace"
${baseDir}/mysql/nosetters/
setter "namespace" does not exist
${baseDir}/mysql/storage/
deleted setter "namespace"
`,
},
{
name: "delete-setter-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-with-setters",
packagePath: "mysql",
args: []string{"namespace"},
expected: `${baseDir}/mysql/
deleted setter "namespace"
`,
},
{
name: "delete-setter-nested-pkg-no-recurse-subpackages",
dataset: "dataset-with-setters",
packagePath: "mysql/storage",
args: []string{"namespace"},
expected: `${baseDir}/mysql/storage/
deleted setter "namespace"
`,
},
}
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
// reset the openAPI afterward
openapi.ResetOpenAPI()
defer openapi.ResetOpenAPI()
sourceDir := filepath.Join("test", "testdata", test.dataset)
baseDir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
copyutil.CopyDir(sourceDir, baseDir)
//defer os.RemoveAll(baseDir)
runner := commands.NewDeleteSetterRunner("")
actual := &bytes.Buffer{}
runner.Command.SetOut(actual)
runner.Command.SetArgs(append([]string{filepath.Join(baseDir, test.packagePath)}, test.args...))
err = runner.Command.Execute()
if !assert.NoError(t, err) {
t.FailNow()
}
// normalize path format for windows
actualNormalized := strings.Replace(
strings.Replace(actual.String(), "\\", "/", -1),
"//", "/", -1)
expected := strings.Replace(test.expected, "${baseDir}", baseDir, -1)
expectedNormalized := strings.Replace(expected, "\\", "/", -1)
if !assert.Equal(t, expectedNormalized, actualNormalized) {
t.FailNow()
}
})
}
}

View File

@@ -4,10 +4,13 @@
package commands
import (
"fmt"
"io"
"path/filepath"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
)
@@ -20,6 +23,8 @@ func NewDeleteSubstitutionRunner(parent string) *DeleteSubstitutionRunner {
PreRunE: r.preRunE,
RunE: r.runE,
}
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", false,
"deletes substitution recursively in all the nested subpackages")
fixDocs(parent, c)
r.Command = c
@@ -34,6 +39,7 @@ type DeleteSubstitutionRunner struct {
Command *cobra.Command
DeleteSubstitution settersutil.DeleterCreator
OpenAPIFile string
RecurseSubPackages bool
}
func (r *DeleteSubstitutionRunner) preRunE(c *cobra.Command, args []string) error {
@@ -46,17 +52,49 @@ func (r *DeleteSubstitutionRunner) preRunE(c *cobra.Command, args []string) erro
return err
}
if err := openapi.AddSchemaFromFile(r.OpenAPIFile); err != nil {
return err
}
return nil
}
func (r *DeleteSubstitutionRunner) runE(c *cobra.Command, args []string) error {
return handleError(c, r.delete(c, args))
e := executeCmdOnPkgs{
needOpenAPI: true,
writer: c.OutOrStdout(),
rootPkgPath: args[0],
recurseSubPackages: r.RecurseSubPackages,
cmdRunner: r,
}
err := e.execute()
if err != nil {
return handleError(c, err)
}
return nil
}
func (r *DeleteSubstitutionRunner) delete(c *cobra.Command, args []string) error {
return r.DeleteSubstitution.Delete(r.OpenAPIFile, args[0])
func (r *DeleteSubstitutionRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
r.DeleteSubstitution = settersutil.DeleterCreator{
Name: r.DeleteSubstitution.Name,
DefinitionPrefix: fieldmeta.SubstitutionDefinitionPrefix,
RecurseSubPackages: r.RecurseSubPackages,
OpenAPIFileName: openAPIFileName,
OpenAPIPath: filepath.Join(pkgPath, openAPIFileName),
ResourcesPath: pkgPath,
}
err = r.DeleteSubstitution.Delete()
if err != nil {
// return err if RecurseSubPackages is false
if !r.DeleteSubstitution.RecurseSubPackages {
return err
} else {
// print error message and continue if RecurseSubPackages is true
fmt.Fprintf(w, "%s\n", err.Error())
}
} else {
fmt.Fprintf(w, "deleted substitution %q\n", r.DeleteSubstitution.Name)
}
return nil
}

View File

@@ -7,12 +7,13 @@ import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/kyaml/copyutil"
"sigs.k8s.io/kustomize/kyaml/openapi"
)
@@ -79,6 +80,7 @@ spec:
- name: sidecar
image: nginx:1.7.9 # {"$ref":"#/definitions/io.k8s.cli.substitutions.my.image"}
`,
out: `deleted substitution "my.image"`,
expectedResources: `
apiVersion: apps/v1
kind: Deployment
@@ -169,6 +171,7 @@ spec:
- name: sidecar
image: nginx:1.7.9 # {"$openapi":"my-image-sub"}
`,
out: `deleted substitution "my-image-sub"`,
expectedResources: `
apiVersion: apps/v1
kind: Deployment
@@ -297,7 +300,7 @@ openAPI:
value: "3"
setBy: me
`,
err: "substitution with name my-image-sub-not-present does not exist",
err: `substitution "my-image-sub-not-present" does not exist`,
},
{
@@ -415,7 +418,7 @@ spec:
- name: sidecar
image: nginx::1.7.9 # {"$openapi":"my-image-subst"}
`,
err: "substitution is used in substitution my-nested-subst, please delete the parent substitution first",
err: `substitution "my-image-subst" is used in substitution "my-nested-subst", please delete the parent substitution first`,
},
}
for i := range tests {
@@ -425,24 +428,18 @@ spec:
openapi.ResetOpenAPI()
defer openapi.ResetOpenAPI()
f, err := ioutil.TempFile("", "k8s-cli-")
baseDir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
defer os.Remove(f.Name())
err = ioutil.WriteFile(f.Name(), []byte(test.inputOpenAPI), 0600)
defer os.RemoveAll(baseDir)
f := filepath.Join(baseDir, "Krmfile")
err = ioutil.WriteFile(f, []byte(test.inputOpenAPI), 0600)
if !assert.NoError(t, err) {
t.FailNow()
}
old := ext.GetOpenAPIFile
defer func() { ext.GetOpenAPIFile = old }()
ext.GetOpenAPIFile = func(args []string) (s string, err error) {
return f.Name(), nil
}
r, err := ioutil.TempFile("", "k8s-cli-*.yaml")
r, err := ioutil.TempFile(baseDir, "k8s-cli-*.yaml")
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -455,21 +452,38 @@ spec:
runner := commands.NewDeleteSubstitutionRunner("")
out := &bytes.Buffer{}
runner.Command.SetOut(out)
runner.Command.SetArgs(append([]string{r.Name()}, test.args...))
runner.Command.SetArgs(append([]string{baseDir}, test.args...))
err = runner.Command.Execute()
if test.err != "" {
if !assert.NotNil(t, err) {
t.FailNow()
} else {
assert.Equal(t, err.Error(), test.err)
return
}
assert.Equal(t, test.err, err.Error())
return
}
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Equal(t, test.out, out.String()) {
// normalize path format for windows
actualNorm := strings.Replace(
strings.Replace(out.String(), "\\", "/", -1),
"//", "/", -1)
expectedOut := strings.Replace(test.out, "${baseDir}", baseDir, -1)
expectedNorm := strings.Replace(expectedOut, "\\", "/", -1)
if !assert.Contains(t, strings.TrimSpace(actualNorm), expectedNorm) {
t.FailNow()
}
actualOpenAPI, err := ioutil.ReadFile(f)
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Equal(t,
strings.TrimSpace(test.expectedOpenAPI),
strings.TrimSpace(string(actualOpenAPI))) {
t.FailNow()
}
@@ -480,16 +494,74 @@ spec:
if !assert.Equal(t,
strings.TrimSpace(test.expectedResources),
strings.TrimSpace(string(actualResources))) {
return
}
actualOpenAPI, err := ioutil.ReadFile(f.Name())
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Equal(t,
strings.TrimSpace(test.expectedOpenAPI),
strings.TrimSpace(string(actualOpenAPI))) {
t.FailNow()
}
})
}
}
func TestDeleteSubstitutionSubPackages(t *testing.T) {
var tests = []struct {
name string
dataset string
packagePath string
args []string
expected string
}{
{
name: "delete-substitution-recurse-subpackages",
dataset: "dataset-with-setters",
args: []string{"image-tag", "-R"},
expected: `${baseDir}/mysql/
deleted substitution "image-tag"
${baseDir}/mysql/nosetters/
substitution "image-tag" does not exist
${baseDir}/mysql/storage/
substitution "image-tag" does not exist
`,
},
{
name: "delete-setter-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-with-setters",
packagePath: "mysql",
args: []string{"image-tag"},
expected: `${baseDir}/mysql/
deleted substitution "image-tag"
`,
},
}
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
// reset the openAPI afterward
openapi.ResetOpenAPI()
defer openapi.ResetOpenAPI()
sourceDir := filepath.Join("test", "testdata", test.dataset)
baseDir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
copyutil.CopyDir(sourceDir, baseDir)
//defer os.RemoveAll(baseDir)
runner := commands.NewDeleteSubstitutionRunner("")
actual := &bytes.Buffer{}
runner.Command.SetOut(actual)
runner.Command.SetArgs(append([]string{filepath.Join(baseDir, test.packagePath)}, test.args...))
err = runner.Command.Execute()
if !assert.NoError(t, err) {
t.FailNow()
}
// normalize path format for windows
actualNormalized := strings.Replace(
strings.Replace(actual.String(), "\\", "/", -1),
"//", "/", -1)
expected := strings.Replace(test.expected, "${baseDir}", baseDir, -1)
expectedNormalized := strings.Replace(expected, "\\", "/", -1)
if !assert.Equal(t, expectedNormalized, actualNormalized) {
t.FailNow()
}
})

View File

@@ -7,15 +7,14 @@ import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/olekukonko/tablewriter"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/pathutil"
"sigs.k8s.io/kustomize/kyaml/setters"
"sigs.k8s.io/kustomize/kyaml/setters2"
)
@@ -36,6 +35,8 @@ func NewListSettersRunner(parent string) *ListSettersRunner {
"output as github markdown")
c.Flags().BoolVar(&r.IncludeSubst, "include-subst", false,
"include substitutions in the output")
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", true,
"list setters recursively in all the nested subpackages")
fixDocs(parent, c)
r.Command = c
return r
@@ -46,11 +47,12 @@ func ListSettersCommand(parent string) *cobra.Command {
}
type ListSettersRunner struct {
Command *cobra.Command
Lookup setters.LookupSetters
List setters2.List
Markdown bool
IncludeSubst bool
Command *cobra.Command
Lookup setters.LookupSetters
List setters2.List
Markdown bool
IncludeSubst bool
RecurseSubPackages bool
}
func (r *ListSettersRunner) preRunE(c *cobra.Command, args []string) error {
@@ -65,48 +67,50 @@ func (r *ListSettersRunner) preRunE(c *cobra.Command, args []string) error {
func (r *ListSettersRunner) runE(c *cobra.Command, args []string) error {
if setterVersion == "v2" {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
e := executeCmdOnPkgs{
needOpenAPI: true,
writer: c.OutOrStdout(),
rootPkgPath: args[0],
recurseSubPackages: r.RecurseSubPackages,
cmdRunner: r,
}
openAPIPaths, err := pathutil.SubDirsWithFile(args[0], openAPIFileName)
err := e.execute()
if err != nil {
return err
}
if len(openAPIPaths) == 0 {
return errors.Errorf("unable to find %s in %s", openAPIFileName, args[0])
}
// list setters for all the subpackages with openAPI file paths
for _, openAPIPath := range openAPIPaths {
r.List = setters2.List{
Name: r.List.Name,
OpenAPIFileName: openAPIFileName,
}
resourcePath := strings.TrimSuffix(openAPIPath, openAPIFileName)
fmt.Fprintf(c.OutOrStdout(), "%s\n", resourcePath)
if err := r.ListSetters(c, openAPIPath, resourcePath); err != nil {
return err
}
if r.IncludeSubst {
if err := r.ListSubstitutions(c, openAPIPath); err != nil {
return err
}
}
return handleError(c, err)
}
return nil
}
return handleError(c, lookup(r.Lookup, c, args))
}
func (r *ListSettersRunner) ListSetters(c *cobra.Command, openAPIPath, resourcePath string) error {
func (r *ListSettersRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
r.List = setters2.List{
Name: r.List.Name,
OpenAPIFileName: openAPIFileName,
}
openAPIPath := filepath.Join(pkgPath, openAPIFileName)
if err := r.ListSetters(w, openAPIPath, pkgPath); err != nil {
return err
}
if r.IncludeSubst {
if err := r.ListSubstitutions(w, openAPIPath); err != nil {
return err
}
}
return nil
}
func (r *ListSettersRunner) ListSetters(w io.Writer, openAPIPath, resourcePath string) error {
// use setters v2
if err := r.List.ListSetters(openAPIPath, resourcePath); err != nil {
return err
}
table := newTable(c.OutOrStdout(), r.Markdown)
table := newTable(w, r.Markdown)
table.SetHeader([]string{"NAME", "VALUE", "SET BY", "DESCRIPTION", "COUNT", "REQUIRED"})
for i := range r.List.Setters {
s := r.List.Setters[i]
@@ -137,12 +141,12 @@ func (r *ListSettersRunner) ListSetters(c *cobra.Command, openAPIPath, resourceP
return nil
}
func (r *ListSettersRunner) ListSubstitutions(c *cobra.Command, openAPIPath string) error {
func (r *ListSettersRunner) ListSubstitutions(w io.Writer, openAPIPath string) error {
// use setters v2
if err := r.List.ListSubst(openAPIPath); err != nil {
return err
}
table := newTable(c.OutOrStdout(), r.Markdown)
table := newTable(w, r.Markdown)
b := tablewriter.Border{Top: true}
table.SetBorders(b)

View File

@@ -471,9 +471,11 @@ func TestListSettersSubPackages(t *testing.T) {
}{
{
name: "list-replicas",
dataset: "dataset1",
dataset: "dataset-with-setters",
args: []string{"--include-subst"},
expected: `test/testdata/dataset1/mysql/
expected: `
test/testdata/dataset-with-setters/mysql/
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
image mysql 1 No
namespace myspace 1 No
@@ -481,11 +483,26 @@ func TestListSettersSubPackages(t *testing.T) {
--------------- ----------------- --------------
SUBSTITUTION PATTERN REFERENCES
image-tag ${image}:${tag} [image,tag]
test/testdata/dataset1/mysql/nosetters/
test/testdata/dataset-with-setters/mysql/nosetters/
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
test/testdata/dataset1/mysql/storage/
test/testdata/dataset-with-setters/mysql/storage/
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
namespace myspace 1 No
`,
},
{
name: "list-replicas",
dataset: "dataset-with-setters/mysql",
args: []string{"--recurse-subpackages=false"},
expected: `
test/testdata/dataset-with-setters/mysql/
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
image mysql 1 No
namespace myspace 1 No
tag 1.7.9 1 No
`,
},
}
@@ -509,7 +526,7 @@ test/testdata/dataset1/mysql/storage/
// normalize path format for windows
actualNormalized := strings.Replace(actual.String(), "\\", "/", -1)
if !assert.Equal(t, test.expected, actualNormalized) {
if !assert.Equal(t, strings.TrimSpace(test.expected), strings.TrimSpace(actualNormalized)) {
t.FailNow()
}
})

View File

@@ -5,7 +5,9 @@ package commands
import (
"fmt"
"io"
"os"
"path/filepath"
"github.com/olekukonko/tablewriter"
"github.com/spf13/cobra"
@@ -39,6 +41,8 @@ func NewSetRunner(parent string) *SetRunner {
"annotate the field with a description of its value")
c.Flags().StringVar(&setterVersion, "version", "",
"use this version of the setter format")
c.Flags().BoolVarP(&r.Set.RecurseSubPackages, "recurse-subpackages", "R", false,
"sets recursively in all the nested subpackages")
c.Flags().MarkHidden("version")
return r
@@ -126,15 +130,23 @@ func (r *SetRunner) preRunE(c *cobra.Command, args []string) error {
return err
}
}
return nil
}
func (r *SetRunner) runE(c *cobra.Command, args []string) error {
if setterVersion == "v2" {
count, err := r.Set.Set(r.OpenAPIFile, args[0])
fmt.Fprintf(c.OutOrStdout(), "set %d fields\n", count)
return handleError(c, err)
e := executeCmdOnPkgs{
needOpenAPI: true,
writer: c.OutOrStdout(),
rootPkgPath: args[0],
recurseSubPackages: r.Set.RecurseSubPackages,
cmdRunner: r,
}
err := e.execute()
if err != nil {
return handleError(c, err)
}
return nil
}
if len(args) > 2 || c.Flag("values").Changed {
return handleError(c, r.perform(c, args))
@@ -142,6 +154,38 @@ func (r *SetRunner) runE(c *cobra.Command, args []string) error {
return handleError(c, lookup(r.Lookup, c, args))
}
func (r *SetRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
r.Set = settersutil.FieldSetter{
Name: r.Set.Name,
Value: r.Set.Value,
ListValues: r.Set.ListValues,
Description: r.Set.Description,
SetBy: r.Set.SetBy,
Count: 0,
OpenAPIPath: filepath.Join(pkgPath, openAPIFileName),
OpenAPIFileName: openAPIFileName,
ResourcesPath: pkgPath,
RecurseSubPackages: r.Set.RecurseSubPackages,
}
count, err := r.Set.Set()
if err != nil {
// return err if RecurseSubPackages is false
if !r.Set.RecurseSubPackages {
return err
} else {
// print error message and continue if RecurseSubPackages is true
fmt.Fprintf(w, "%s\n", err.Error())
}
} else {
fmt.Fprintf(w, "set %d field(s)\n", count)
}
return nil
}
func lookup(l setters.LookupSetters, c *cobra.Command, args []string) error {
// lookup the setters
err := kio.Pipeline{

View File

@@ -7,12 +7,13 @@ import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/kyaml/copyutil"
"sigs.k8s.io/kustomize/kyaml/openapi"
)
@@ -30,7 +31,7 @@ func TestSetCommand(t *testing.T) {
{
name: "set replicas",
args: []string{"replicas", "4", "--description", "hi there", "--set-by", "pw"},
out: "set 1 fields\n",
out: "set 1 field(s)\n",
inputOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -126,7 +127,7 @@ spec:
{
name: "set replicas no description",
args: []string{"replicas", "4"},
out: "set 1 fields\n",
out: "set 1 field(s)\n",
inputOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -174,7 +175,7 @@ spec:
{
name: "set image with value",
args: []string{"tag", "1.8.1"},
out: "set 1 fields\n",
out: "set 1 field(s)\n",
inputOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -509,7 +510,7 @@ list in body should have at most 2 items`,
{
name: "set replicas with value set by flag",
args: []string{"replicas", "--values", "4", "--description", "hi there"},
out: "set 1 fields\n",
out: "set 1 field(s)\n",
inputOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -605,7 +606,7 @@ spec:
{
name: "openAPI list values set by flag success",
args: []string{"list", "--values", "10", "--values", "11"},
out: "set 1 fields\n",
out: "set 1 field(s)\n",
inputOpenAPI: `
kind: Kptfile
openAPI:
@@ -709,7 +710,7 @@ list in body should have at most 2 items`,
{
name: "nested substitution",
args: []string{"my-image-setter", "ubuntu"},
out: "set 2 fields\n",
out: "set 2 field(s)\n",
inputOpenAPI: `
apiVersion: v1alpha1
kind: Example
@@ -1013,22 +1014,19 @@ spec:
openapi.ResetOpenAPI()
defer openapi.ResetOpenAPI()
f, err := ioutil.TempFile("", "k8s-cli-")
baseDir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
defer os.Remove(f.Name())
err = ioutil.WriteFile(f.Name(), []byte(test.inputOpenAPI), 0600)
defer os.RemoveAll(baseDir)
f := filepath.Join(baseDir, "Krmfile")
err = ioutil.WriteFile(f, []byte(test.inputOpenAPI), 0600)
if !assert.NoError(t, err) {
t.FailNow()
}
old := ext.GetOpenAPIFile
defer func() { ext.GetOpenAPIFile = old }()
ext.GetOpenAPIFile = func(args []string) (s string, err error) {
return f.Name(), nil
}
r, err := ioutil.TempFile("", "k8s-cli-*.yaml")
r, err := ioutil.TempFile(baseDir, "k8s-cli-*.yaml")
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -1041,7 +1039,7 @@ spec:
runner := commands.NewSetRunner("")
out := &bytes.Buffer{}
runner.Command.SetOut(out)
runner.Command.SetArgs(append([]string{r.Name()}, test.args...))
runner.Command.SetArgs(append([]string{baseDir}, test.args...))
err = runner.Command.Execute()
if test.errMsg != "" {
if !assert.NotNil(t, err) {
@@ -1056,7 +1054,7 @@ spec:
t.FailNow()
}
if test.errMsg == "" && !assert.Equal(t, test.out, out.String()) {
if test.errMsg == "" && !assert.Contains(t, out.String(), strings.TrimSpace(test.out)) {
t.FailNow()
}
@@ -1070,7 +1068,7 @@ spec:
t.FailNow()
}
actualOpenAPI, err := ioutil.ReadFile(f.Name())
actualOpenAPI, err := ioutil.ReadFile(f)
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -1082,3 +1080,82 @@ spec:
})
}
}
func TestSetSubPackages(t *testing.T) {
var tests = []struct {
name string
dataset string
packagePath string
args []string
expected string
}{
{
name: "set-recurse-subpackages",
dataset: "dataset-with-setters",
args: []string{"namespace", "otherspace", "-R"},
expected: `${baseDir}/mysql/
set 1 field(s)
${baseDir}/mysql/nosetters/
setter "namespace" is not found
${baseDir}/mysql/storage/
set 1 field(s)
`,
},
{
name: "set-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-with-setters",
packagePath: "mysql",
args: []string{"namespace", "otherspace"},
expected: `${baseDir}/mysql/
set 1 field(s)
`,
},
{
name: "set-nested-pkg-no-recurse-subpackages",
dataset: "dataset-with-setters",
packagePath: "mysql/storage",
args: []string{"namespace", "otherspace"},
expected: `${baseDir}/mysql/storage/
set 1 field(s)
`,
},
}
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
// reset the openAPI afterward
openapi.ResetOpenAPI()
defer openapi.ResetOpenAPI()
sourceDir := filepath.Join("test", "testdata", test.dataset)
baseDir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
copyutil.CopyDir(sourceDir, baseDir)
defer os.RemoveAll(baseDir)
runner := commands.NewSetRunner("")
actual := &bytes.Buffer{}
runner.Command.SetOut(actual)
runner.Command.SetArgs(append([]string{filepath.Join(baseDir, test.packagePath)}, test.args...))
err = runner.Command.Execute()
if !assert.NoError(t, err) {
t.FailNow()
}
// normalize path format for windows
actualNormalized := strings.Replace(
strings.Replace(actual.String(), "\\", "/", -1),
"//", "/", -1)
expected := strings.Replace(test.expected, "${baseDir}", baseDir, -1)
expectedNormalized := strings.Replace(
strings.Replace(expected, "\\", "/", -1),
"//", "/", -1)
if !assert.Equal(t, strings.TrimSpace(expectedNormalized), strings.TrimSpace(actualNormalized)) {
t.FailNow()
}
})
}
}

View File

@@ -182,7 +182,7 @@ items:
kind: Deployment
metadata:
name: mysql-deployment
namespace: myspace # {"$openapi":"namespace"}
namespace: myspace
annotations:
config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'config/mysql-deployment_deployment.yaml'
@@ -192,7 +192,7 @@ items:
spec:
containers:
- name: mysql
image: mysql:1.7.9 # {"$openapi":"image-tag"}
image: mysql:1.7.9
- apiVersion: apps/v1
kind: Deployment
metadata:
@@ -212,7 +212,7 @@ items:
kind: Deployment
metadata:
name: storage-deployment
namespace: myspace # {"$openapi":"namespace"}
namespace: myspace
annotations:
config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'config/storage-deployment_deployment.yaml'

View File

@@ -5,9 +5,11 @@ package commands
import (
"fmt"
"io"
"sort"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/sets"
@@ -17,18 +19,18 @@ import (
func GetCountRunner(name string) *CountRunner {
r := &CountRunner{}
c := &cobra.Command{
Use: "count DIR...",
Use: "count [DIR]",
Args: cobra.MaximumNArgs(1),
Short: commands.CountShort,
Long: commands.CountLong,
Example: commands.CountExamples,
RunE: r.runE,
}
fixDocs(name, c)
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
"also print resources from subpackages.")
c.Flags().BoolVar(&r.Kind, "kind", true,
"count resources by kind.")
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", true,
"prints count of resources recursively in all the nested subpackages")
r.Command = c
return r
}
@@ -42,20 +44,56 @@ type CountRunner struct {
IncludeSubpackages bool
Kind bool
Command *cobra.Command
RecurseSubPackages bool
}
func (r *CountRunner) runE(c *cobra.Command, args []string) error {
var inputs []kio.Reader
for _, a := range args {
inputs = append(inputs, kio.LocalPackageReader{
PackagePath: a,
IncludeSubpackages: r.IncludeSubpackages,
})
}
if len(inputs) == 0 {
inputs = append(inputs, &kio.ByteReader{Reader: c.InOrStdin()})
if len(args) == 0 {
input := &kio.ByteReader{Reader: c.InOrStdin()}
return handleError(c, kio.Pipeline{
Inputs: []kio.Reader{input},
Outputs: r.out(c.OutOrStdout()),
}.Execute())
}
e := executeCmdOnPkgs{
writer: c.OutOrStdout(),
needOpenAPI: false,
recurseSubPackages: r.RecurseSubPackages,
cmdRunner: r,
rootPkgPath: args[0],
}
return e.execute()
}
func (r *CountRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: openAPIFileName}
err = kio.Pipeline{
Inputs: []kio.Reader{input},
Outputs: r.out(w),
}.Execute()
if err != nil {
// return err if there is only package
if !r.RecurseSubPackages {
return err
} else {
// print error message and continue if there are multiple packages to annotate
fmt.Fprintf(w, "%s\n", err.Error())
}
}
return nil
}
func (r *CountRunner) out(w io.Writer) []kio.Writer {
var out []kio.Writer
if r.Kind {
out = append(out, kio.WriterFunc(func(nodes []*yaml.RNode) error {
@@ -69,20 +107,15 @@ func (r *CountRunner) runE(c *cobra.Command, args []string) error {
order := k.List()
sort.Strings(order)
for _, k := range order {
fmt.Fprintf(c.OutOrStdout(), "%s: %d\n", k, count[k])
fmt.Fprintf(w, "%s: %d\n", k, count[k])
}
return nil
}))
} else {
out = append(out, kio.WriterFunc(func(nodes []*yaml.RNode) error {
fmt.Fprintf(c.OutOrStdout(), "%d\n", len(nodes))
fmt.Fprintf(w, "%d\n", len(nodes))
return nil
}))
}
return handleError(c, kio.Pipeline{
Inputs: inputs,
Outputs: out,
}.Execute())
return out
}

View File

@@ -8,10 +8,13 @@ import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/kyaml/copyutil"
"sigs.k8s.io/kustomize/kyaml/openapi"
)
func TestCountCommand_files(t *testing.T) {
@@ -67,7 +70,80 @@ spec:
return
}
if !assert.Equal(t, "Deployment: 2\nService: 1\n", b.String()) {
if !assert.Contains(t, b.String(), "Deployment: 2\nService: 1\n") {
return
}
}
func TestCountSubPackages(t *testing.T) {
var tests = []struct {
name string
dataset string
packagePath string
args []string
expected string
}{
{
name: "count-recurse-subpackages",
dataset: "dataset-without-setters",
expected: `${baseDir}/mysql/
Deployment: 1
${baseDir}/mysql/storage/
Deployment: 1
`,
},
{
name: "count-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
args: []string{"-R=false"},
packagePath: "mysql",
expected: `${baseDir}/mysql/
Deployment: 1
`,
},
{
name: "count-nested-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql/storage",
args: []string{"-R=false"},
expected: `${baseDir}/mysql/storage/
Deployment: 1
`,
},
}
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
// reset the openAPI afterward
openapi.ResetOpenAPI()
defer openapi.ResetOpenAPI()
sourceDir := filepath.Join("test", "testdata", test.dataset)
baseDir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
copyutil.CopyDir(sourceDir, baseDir)
defer os.RemoveAll(baseDir)
runner := commands.GetCountRunner("")
actual := &bytes.Buffer{}
runner.Command.SetOut(actual)
runner.Command.SetArgs(append([]string{filepath.Join(baseDir, test.packagePath)}, test.args...))
err = runner.Command.Execute()
if !assert.NoError(t, err) {
t.FailNow()
}
// normalize path format for windows
actualNormalized := strings.Replace(
strings.Replace(actual.String(), "\\", "/", -1),
"//", "/", -1)
expected := strings.Replace(test.expected, "${baseDir}", baseDir, -1)
expectedNormalized := strings.Replace(expected, "\\", "/", -1)
if !assert.Equal(t, expectedNormalized, actualNormalized) {
t.FailNow()
}
})
}
}

View File

@@ -4,7 +4,11 @@
package commands
import (
"fmt"
"io"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/kio/filters"
@@ -33,6 +37,8 @@ formatting substitution verbs {'%n': 'metadata.name', '%s': 'metadata.namespace'
`if true, override existing filepath annotations.`)
c.Flags().BoolVar(&r.UseSchema, "use-schema", false,
`if true, uses openapi resource schema to format resources.`)
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", false,
"formats resource files recursively in all the nested subpackages")
r.Command = c
return r
}
@@ -43,12 +49,13 @@ func FmtCommand(name string) *cobra.Command {
// FmtRunner contains the run function
type FmtRunner struct {
Command *cobra.Command
FilenamePattern string
SetFilenames bool
KeepAnnotations bool
Override bool
UseSchema bool
Command *cobra.Command
FilenamePattern string
SetFilenames bool
KeepAnnotations bool
Override bool
UseSchema bool
RecurseSubPackages bool
}
func (r *FmtRunner) preRunE(c *cobra.Command, args []string) error {
@@ -59,17 +66,6 @@ func (r *FmtRunner) preRunE(c *cobra.Command, args []string) error {
}
func (r *FmtRunner) runE(c *cobra.Command, args []string) error {
f := []kio.Filter{filters.FormatFilter{
UseSchema: r.UseSchema,
}}
// format with file names
if r.SetFilenames {
f = append(f, &filters.FileSetter{
FilenamePattern: r.FilenamePattern,
Override: r.Override,
})
}
// format stdin if there are no args
if len(args) == 0 {
@@ -79,20 +75,64 @@ func (r *FmtRunner) runE(c *cobra.Command, args []string) error {
KeepReaderAnnotations: r.KeepAnnotations,
}
return handleError(c, kio.Pipeline{
Inputs: []kio.Reader{rw}, Filters: f, Outputs: []kio.Writer{rw}}.Execute())
Inputs: []kio.Reader{rw}, Filters: r.fmtFilters(), Outputs: []kio.Writer{rw}}.Execute())
}
for i := range args {
path := args[i]
rw := &kio.LocalPackageReadWriter{
NoDeleteFiles: true,
PackagePath: path,
KeepReaderAnnotations: r.KeepAnnotations}
err := kio.Pipeline{
Inputs: []kio.Reader{rw}, Filters: f, Outputs: []kio.Writer{rw}}.Execute()
for _, rootPkgPath := range args {
e := executeCmdOnPkgs{
writer: c.OutOrStdout(),
needOpenAPI: false,
recurseSubPackages: r.RecurseSubPackages,
cmdRunner: r,
rootPkgPath: rootPkgPath,
}
err := e.execute()
if err != nil {
return handleError(c, err)
return err
}
}
return nil
}
func (r *FmtRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
rw := &kio.LocalPackageReadWriter{
NoDeleteFiles: true,
PackagePath: pkgPath,
KeepReaderAnnotations: r.KeepAnnotations, PackageFileName: openAPIFileName}
err = kio.Pipeline{
Inputs: []kio.Reader{rw}, Filters: r.fmtFilters(), Outputs: []kio.Writer{rw}}.Execute()
if err != nil {
// return err if RecurseSubPackages is false
if !r.RecurseSubPackages {
return err
} else {
// print error message and continue if RecurseSubPackages is true
fmt.Fprintf(w, "%s\n", err.Error())
}
} else {
fmt.Fprint(w, "formatted resource files in the package\n")
}
return nil
}
func (r *FmtRunner) fmtFilters() []kio.Filter {
fmtFilters := []kio.Filter{filters.FormatFilter{
UseSchema: r.UseSchema,
}}
// format with file names
if r.SetFilenames {
fmtFilters = append(fmtFilters, &filters.FileSetter{
FilenamePattern: r.FilenamePattern,
Override: r.Override,
})
}
return fmtFilters
}

View File

@@ -7,12 +7,15 @@ import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/kyaml/copyutil"
"sigs.k8s.io/kustomize/kyaml/kio/filters/testyaml"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/testutil"
)
@@ -163,3 +166,78 @@ func TestCmd_failFileContents(t *testing.T) {
// expect an error
assert.EqualError(t, err, "yaml: line 1: did not find expected node content")
}
func TestFmtSubPackages(t *testing.T) {
var tests = []struct {
name string
dataset string
packagePath string
args []string
expected string
}{
{
name: "fmt-recurse-subpackages",
dataset: "dataset-with-setters",
args: []string{"-R"},
expected: `${baseDir}/mysql/
formatted resource files in the package
${baseDir}/mysql/nosetters/
formatted resource files in the package
${baseDir}/mysql/storage/
formatted resource files in the package
`,
},
{
name: "fmt-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql",
expected: `${baseDir}/mysql/
formatted resource files in the package
`,
},
{
name: "fmt-nested-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql/storage",
expected: `${baseDir}/mysql/storage/
formatted resource files in the package
`,
},
}
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
// reset the openAPI afterward
openapi.ResetOpenAPI()
defer openapi.ResetOpenAPI()
sourceDir := filepath.Join("test", "testdata", test.dataset)
baseDir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
copyutil.CopyDir(sourceDir, baseDir)
defer os.RemoveAll(baseDir)
runner := commands.GetFmtRunner("")
actual := &bytes.Buffer{}
runner.Command.SetOut(actual)
runner.Command.SetArgs(append([]string{filepath.Join(baseDir, test.packagePath)}, test.args...))
err = runner.Command.Execute()
if !assert.NoError(t, err) {
t.FailNow()
}
// normalize path format for windows
actualNormalized := strings.Replace(
strings.Replace(actual.String(), "\\", "/", -1),
"//", "/", -1)
expected := strings.Replace(test.expected, "${baseDir}", baseDir, -1)
expectedNormalized := strings.Replace(expected, "\\", "/", -1)
if !assert.Equal(t, strings.TrimSpace(expectedNormalized), strings.TrimSpace(actualNormalized)) {
t.FailNow()
}
})
}
}

View File

@@ -5,10 +5,12 @@ package commands
import (
"fmt"
"io"
"strings"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/resource"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/kio/filters"
@@ -18,22 +20,21 @@ import (
func GetGrepRunner(name string) *GrepRunner {
r := &GrepRunner{}
c := &cobra.Command{
Use: "grep QUERY [DIR]...",
Use: "grep QUERY [DIR]",
Short: commands.GrepShort,
Long: commands.GrepLong,
Example: commands.GrepExamples,
PreRunE: r.preRunE,
RunE: r.runE,
Args: cobra.MinimumNArgs(1),
Args: cobra.MaximumNArgs(2),
}
fixDocs(name, c)
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
"also print resources from subpackages.")
c.Flags().BoolVar(&r.KeepAnnotations, "annotate", true,
"annotate resources with their file origins.")
c.Flags().BoolVarP(&r.InvertMatch, "invert-match", "", false,
"Selected Resources are those not matching any of the specified patterns..")
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", true,
"also print resources recursively in all the nested subpackages")
r.Command = c
return r
}
@@ -44,11 +45,11 @@ func GrepCommand(name string) *cobra.Command {
// GrepRunner contains the run function
type GrepRunner struct {
IncludeSubpackages bool
KeepAnnotations bool
Command *cobra.Command
KeepAnnotations bool
Command *cobra.Command
filters.GrepFilter
Format bool
Format bool
RecurseSubPackages bool
}
func (r *GrepRunner) preRunE(c *cobra.Command, args []string) error {
@@ -101,25 +102,57 @@ func (r *GrepRunner) preRunE(c *cobra.Command, args []string) error {
}
func (r *GrepRunner) runE(c *cobra.Command, args []string) error {
var filters = []kio.Filter{r.GrepFilter}
var inputs []kio.Reader
for _, a := range args[1:] {
inputs = append(inputs, kio.LocalPackageReader{
PackagePath: a,
IncludeSubpackages: r.IncludeSubpackages,
})
}
if len(inputs) == 0 {
inputs = append(inputs, &kio.ByteReader{Reader: c.InOrStdin()})
if len(args) == 1 {
input := &kio.ByteReader{Reader: c.InOrStdin()}
return handleError(c, kio.Pipeline{
Inputs: []kio.Reader{input},
Filters: []kio.Filter{r.GrepFilter},
Outputs: []kio.Writer{kio.ByteWriter{
Writer: c.OutOrStdout(),
KeepReaderAnnotations: r.KeepAnnotations,
}},
}.Execute())
}
return handleError(c, kio.Pipeline{
Inputs: inputs,
Filters: filters,
e := executeCmdOnPkgs{
writer: c.OutOrStdout(),
needOpenAPI: false,
recurseSubPackages: r.RecurseSubPackages,
cmdRunner: r,
rootPkgPath: args[1],
skipPkgPathPrint: true,
}
return e.execute()
}
func (r *GrepRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: openAPIFileName}
err = kio.Pipeline{
Inputs: []kio.Reader{input},
Filters: []kio.Filter{r.GrepFilter},
Outputs: []kio.Writer{kio.ByteWriter{
Writer: c.OutOrStdout(),
Writer: w,
KeepReaderAnnotations: r.KeepAnnotations,
}},
}.Execute())
}.Execute()
if err != nil {
// return err if there is only package
if !r.RecurseSubPackages {
return err
} else {
// print error message and continue if there are multiple packages to annotate
fmt.Fprintf(w, "%s\n", err.Error())
}
}
fmt.Fprintf(w, "---")
return nil
}

View File

@@ -8,10 +8,12 @@ import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
"sigs.k8s.io/kustomize/kyaml/copyutil"
)
// TestGrepCommand_files verifies grep reads the files and filters them
@@ -68,7 +70,7 @@ spec:
return
}
if !assert.Equal(t, `kind: Deployment
if !assert.Contains(t, b.String(), `kind: Deployment
metadata:
labels:
app: nginx2
@@ -90,7 +92,7 @@ metadata:
spec:
selector:
app: nginx
`, b.String()) {
`) {
return
}
}
@@ -136,7 +138,7 @@ spec:
return
}
if !assert.Equal(t, `kind: Deployment
if !assert.Contains(t, b.String(), `kind: Deployment
metadata:
labels:
app: nginx2
@@ -156,7 +158,7 @@ metadata:
spec:
selector:
app: nginx
`, b.String()) {
`) {
return
}
}
@@ -250,7 +252,7 @@ spec:
if !assert.NoError(t, err) {
return
}
if !assert.Equal(t, `kind: Deployment
if !assert.Contains(t, b.String(), `kind: Deployment
metadata:
labels:
app: nginx1.7
@@ -264,7 +266,142 @@ spec:
containers:
- name: nginx
image: nginx:1.7.9
`, b.String()) {
`) {
return
}
}
func TestGrepSubPackages(t *testing.T) {
var tests = []struct {
name string
dataset string
packagePath string
args []string
expected string
}{
{
name: "grep-recurse-subpackages",
dataset: "dataset-without-setters",
args: []string{"kind=Deployment"},
expected: `# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: myspace
name: mysql-deployment
annotations:
config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'deployment.yaml'
spec:
replicas: 3
template:
spec:
containers:
- name: mysql
image: mysql:1.7.9
---
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: myspace
name: storage-deployment
annotations:
config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'deployment.yaml'
spec:
replicas: 4
template:
spec:
containers:
- name: storage
image: storage:1.7.7
---`,
},
{
name: "grep-top-level-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
args: []string{"kind=Deployment", "-R=false"},
packagePath: "mysql",
expected: `# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: myspace
name: mysql-deployment
annotations:
config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'deployment.yaml'
spec:
replicas: 3
template:
spec:
containers:
- name: mysql
image: mysql:1.7.9
---`,
},
{
name: "grep-nested-pkg-no-recurse-subpackages",
dataset: "dataset-without-setters",
packagePath: "mysql/storage",
args: []string{"kind=Deployment", "-R=false"},
expected: `# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: myspace
name: storage-deployment
annotations:
config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'deployment.yaml'
spec:
replicas: 4
template:
spec:
containers:
- name: storage
image: storage:1.7.7
---`,
},
}
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
sourceDir := filepath.Join("test", "testdata", test.dataset)
baseDir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
copyutil.CopyDir(sourceDir, baseDir)
defer os.RemoveAll(baseDir)
runner := commands.GetGrepRunner("")
actual := &bytes.Buffer{}
runner.Command.SetOut(actual)
runner.Command.SetArgs(append(test.args, filepath.Join(baseDir, test.packagePath)))
err = runner.Command.Execute()
if !assert.NoError(t, err) {
t.FailNow()
}
// normalize path format for windows
actualNormalized := strings.Replace(
strings.Replace(actual.String(), "\\", "/", -1),
"//", "/", -1)
expected := strings.Replace(test.expected, "${baseDir}", baseDir, -1)
expectedNormalized := strings.Replace(expected, "\\", "/", -1)
if !assert.Equal(t, expectedNormalized, actualNormalized) {
t.FailNow()
}
})
}
}

View File

@@ -9,11 +9,13 @@ import (
"strings"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
"sigs.k8s.io/kustomize/kyaml/runfn"
"sigs.k8s.io/kustomize/kyaml/yaml"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
)
// GetCatRunner returns a RunFnRunner.
@@ -65,6 +67,11 @@ func GetRunFnRunner(name string) *RunFnRunner {
r.Command.Flags().StringArrayVar(
&r.Mounts, "mount", []string{},
"a list of storage options read from the filesystem")
r.Command.Flags().BoolVar(
&r.LogSteps, "log-steps", false, "log steps to stderr")
r.Command.Flags().StringArrayVarP(
&r.Env, "env", "e", []string{},
"a list of environment variables to be used by functions")
return r
}
@@ -91,6 +98,8 @@ type RunFnRunner struct {
Network bool
NetworkName string
Mounts []string
LogSteps bool
Env []string
}
func (r *RunFnRunner) runE(c *cobra.Command, args []string) error {
@@ -99,7 +108,7 @@ func (r *RunFnRunner) runE(c *cobra.Command, args []string) error {
// getContainerFunctions parses the commandline flags and arguments into explicit
// Functions to run.
func (r *RunFnRunner) getContainerFunctions(c *cobra.Command, args, dataItems []string) (
func (r *RunFnRunner) getContainerFunctions(c *cobra.Command, dataItems []string) (
[]*yaml.RNode, error) {
if r.Image == "" && r.StarPath == "" && r.ExecPath == "" && r.StarURL == "" {
@@ -193,7 +202,7 @@ data: {}
}
err = rc.PipeE(
yaml.LookupCreate(yaml.MappingNode, "metadata", "annotations"),
yaml.SetField("config.kubernetes.io/function", yaml.NewScalarRNode(value)))
yaml.SetField(runtimeutil.FunctionAnnotationKey, yaml.NewScalarRNode(value)))
if err != nil {
return nil, err
}
@@ -267,7 +276,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.getContainerFunctions(c, args, dataItems)
fns, err := r.getContainerFunctions(c, dataItems)
if err != nil {
return err
}
@@ -305,6 +314,8 @@ func (r *RunFnRunner) preRunE(c *cobra.Command, args []string) error {
EnableExec: r.EnableExec,
StorageMounts: storageMounts,
ResultsDir: r.ResultsDir,
LogSteps: r.LogSteps,
Env: r.Env,
}
// don't consider args for the function

View File

@@ -11,6 +11,7 @@ import (
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/kyaml/runfn"
)
@@ -203,6 +204,7 @@ apiVersion: v1
Path: "dir",
NetworkName: "bridge",
EnableStarlark: true,
Env: []string{},
},
},
{
@@ -256,6 +258,7 @@ apiVersion: v1
Path: "dir",
NetworkName: "bridge",
ResultsDir: "foo/",
Env: []string{},
},
expected: `
metadata:
@@ -283,6 +286,27 @@ apiVersion: v1
args: []string{"run", "dir", "--image", "foo:bar", "--", "a=b", "c", "e=f"},
err: "must have keys and values separated by",
},
{
name: "log steps",
args: []string{"run", "dir", "--log-steps"},
path: "dir",
expectedStruct: &runfn.RunFns{
Path: "dir",
NetworkName: "bridge",
LogSteps: true,
Env: []string{},
},
},
{
name: "envs",
args: []string{"run", "dir", "--env", "FOO=BAR", "-e", "BAR"},
path: "dir",
expectedStruct: &runfn.RunFns{
Path: "dir",
NetworkName: "bridge",
Env: []string{"FOO=BAR", "BAR"},
},
},
}
for i := range tests {
@@ -385,5 +409,4 @@ apiVersion: v1
})
}
}

View File

@@ -0,0 +1,6 @@
apiVersion: krm.dev/v1alpha1
kind: Krmfile
metadata:
name: mysql
packageMetadata:
shortDescription: sample description

View File

@@ -0,0 +1,15 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: myspace
name: mysql-deployment
spec:
replicas: 3
template:
spec:
containers:
- name: mysql
image: mysql:1.7.9

View File

@@ -0,0 +1,6 @@
apiVersion: krm.dev/v1alpha1
kind: Krmfile
metadata:
name: storage
packageMetadata:
shortDescription: sample description

View File

@@ -0,0 +1,15 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: myspace
name: storage-deployment
spec:
replicas: 4
template:
spec:
containers:
- name: storage
image: storage:1.7.7

View File

@@ -7,6 +7,7 @@ import (
"path/filepath"
"strings"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/kio/filters"
@@ -26,8 +27,6 @@ func GetTreeRunner(name string) *TreeRunner {
Args: cobra.MaximumNArgs(1),
}
fixDocs(name, c)
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
"also print resources from subpackages.")
// TODO(pwittrock): Figure out if these are the right things to expose, and consider making it
// a list of options instead of individual flags
@@ -59,29 +58,33 @@ func TreeCommand(name string) *cobra.Command {
// TreeRunner contains the run function
type TreeRunner struct {
IncludeSubpackages bool
Command *cobra.Command
name bool
resources bool
ports bool
images bool
replicas bool
all bool
env bool
args bool
cmd bool
fields []string
includeLocal bool
excludeNonLocal bool
structure string
Command *cobra.Command
name bool
resources bool
ports bool
images bool
replicas bool
all bool
env bool
args bool
cmd bool
fields []string
includeLocal bool
excludeNonLocal bool
structure string
}
func (r *TreeRunner) runE(c *cobra.Command, args []string) error {
var input kio.Reader
var root = "."
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
matchFilesGlob := append([]string{openAPIFileName}, kio.DefaultMatch...)
if len(args) == 1 {
root = filepath.Clean(args[0])
input = kio.LocalPackageReader{PackagePath: args[0]}
input = kio.LocalPackageReader{PackagePath: args[0], MatchFilesGlob: matchFilesGlob}
} else {
input = &kio.ByteReader{Reader: c.InOrStdin()}
}
@@ -156,10 +159,12 @@ func (r *TreeRunner) runE(c *cobra.Command, args []string) error {
Inputs: []kio.Reader{input},
Filters: fltrs,
Outputs: []kio.Writer{kio.TreeWriter{
Root: root,
Writer: c.OutOrStdout(),
Fields: fields,
Structure: kio.TreeStructure(r.structure)}},
Root: root,
Writer: c.OutOrStdout(),
Fields: fields,
Structure: kio.TreeStructure(r.structure),
OpenAPIFileName: openAPIFileName,
}},
}.Execute())
}

View File

@@ -90,6 +90,109 @@ spec:
}
}
func TestTreeCommand_subpkgs(t *testing.T) {
d, err := ioutil.TempDir("", "kustomize-tree-test")
defer os.RemoveAll(d)
if !assert.NoError(t, err) {
t.FailNow()
}
err = os.MkdirAll(filepath.Join(d, "subpkg"), 0700)
if !assert.NoError(t, err) {
t.FailNow()
}
err = ioutil.WriteFile(filepath.Join(d, "f1.yaml"), []byte(`
apiVersion: v1
kind: Abstraction
metadata:
name: foo
configFn:
container:
image: gcr.io/example/reconciler:v1
annotations:
config.kubernetes.io/local-config: "true"
spec:
replicas: 1
---
kind: Deployment
metadata:
labels:
app: nginx2
name: foo
annotations:
app: nginx2
spec:
replicas: 1
---
kind: Service
metadata:
name: foo
annotations:
app: nginx
spec:
selector:
app: nginx
`), 0600)
if !assert.NoError(t, err) {
return
}
err = ioutil.WriteFile(filepath.Join(d, "subpkg", "f2.yaml"), []byte(`kind: Deployment
metadata:
labels:
app: nginx
name: bar
annotations:
app: nginx
spec:
replicas: 3
`), 0600)
if !assert.NoError(t, err) {
return
}
err = ioutil.WriteFile(filepath.Join(d, "Krmfile"), []byte(`apiVersion: kpt.dev/v1alpha1
kind: Krmfile
metadata:
name: mainpkg
openAPI:
definitions:
`), 0600)
if !assert.NoError(t, err) {
return
}
err = ioutil.WriteFile(filepath.Join(d, "subpkg", "Krmfile"), []byte(`apiVersion: kpt.dev/v1alpha1
kind: Krmfile
metadata:
name: subpkg
openAPI:
definitions:
`), 0600)
if !assert.NoError(t, err) {
return
}
// fmt the files
b := &bytes.Buffer{}
r := commands.GetTreeRunner("")
r.Command.SetArgs([]string{d})
r.Command.SetOut(b)
if !assert.NoError(t, r.Command.Execute()) {
return
}
if !assert.Equal(t, fmt.Sprintf(`%s
├── [Krmfile] Krmfile mainpkg
├── [f1.yaml] Deployment foo
├── [f1.yaml] Service foo
└── Pkg: subpkg
├── [Krmfile] Krmfile subpkg
└── [f2.yaml] Deployment bar
`, d), b.String()) {
return
}
}
func TestTreeCommand_stdin(t *testing.T) {
// fmt the files
b := &bytes.Buffer{}

View File

@@ -5,13 +5,91 @@ package commands
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/go-errors/errors"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/pathutil"
)
// cmdRunner interface holds executeCmd definition which executes respective command's
// implementation on single package
type cmdRunner interface {
executeCmd(w io.Writer, pkgPath string) error
}
// executeCmdOnPkgs struct holds the parameters necessary to
// execute the filter command on packages in rootPkgPath
type executeCmdOnPkgs struct {
rootPkgPath string
recurseSubPackages bool
needOpenAPI bool
cmdRunner cmdRunner
writer io.Writer
skipPkgPathPrint bool
}
// executeCmdOnPkgs takes the function definition for a command to be executed on single package, applies that definition
// recursively on all the subpackages present in rootPkgPath if recurseSubPackages is true, else applies the command on rootPkgPath only
func (e executeCmdOnPkgs) execute() error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
pkgsPaths, err := pathutil.DirsWithFile(e.rootPkgPath, openAPIFileName, e.recurseSubPackages)
if err != nil {
return err
}
if len(pkgsPaths) == 0 {
// at this point, there are no openAPI files in the rootPkgPath
if e.needOpenAPI {
// few executions need openAPI file to be present(ex: setters commands), if true throw an error
return errors.Errorf("unable to find %q in package %q", openAPIFileName, e.rootPkgPath)
}
// add root path for commands which doesn't need openAPI(ex: annotate, fmt)
pkgsPaths = []string{e.rootPkgPath}
}
for i := range pkgsPaths {
pkgPath := pkgsPaths[i]
// Add schema present in openAPI file for current package
if e.needOpenAPI {
if err := openapi.AddSchemaFromFile(filepath.Join(pkgPath, openAPIFileName)); err != nil {
return err
}
}
if !e.skipPkgPathPrint {
fmt.Fprintf(e.writer, "%s/\n", pkgPath)
}
err := e.cmdRunner.executeCmd(e.writer, pkgPath)
if err != nil {
return err
}
if i != len(pkgsPaths)-1 {
fmt.Fprint(e.writer, "\n")
}
// Delete schema present in openAPI file for current package
if e.needOpenAPI {
if err := openapi.DeleteSchemaInFile(filepath.Join(pkgPath, openAPIFileName)); err != nil {
return err
}
}
}
return nil
}
// parseFieldPath parse a flag value into a field path
func parseFieldPath(path string) ([]string, error) {
// fixup '\.' so we don't split on it

View File

@@ -0,0 +1,184 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package commands
import (
"bytes"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/kyaml/errors"
)
func TestExecuteCmdOnPkgs(t *testing.T) {
var tests = []struct {
name string
recurse bool
pkgPath string
needOpenAPI bool
errMsg string
expectedOut string
}{
{
name: "need_Krmfile_error",
recurse: true,
needOpenAPI: true,
pkgPath: "subpkg1/subdir1",
errMsg: `unable to find "Krmfile" in package`,
},
{
name: "Krmfile_not_needed_no_err",
recurse: true,
needOpenAPI: false,
pkgPath: "subpkg1/subdir1",
expectedOut: `${baseDir}/subpkg1/subdir1/
`,
},
{
name: "executeCmd_returns_error",
recurse: true,
needOpenAPI: false,
pkgPath: "subpkg4",
expectedOut: `${baseDir}/subpkg4/
`,
errMsg: `this command returns an error if package has error.txt file`,
},
{
name: "executeCmd_prints_pkgpaths",
recurse: true,
needOpenAPI: false,
pkgPath: "subpkg2",
expectedOut: `${baseDir}/subpkg2/
${baseDir}/subpkg2/subpkg3/
`,
},
}
dir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
defer os.RemoveAll(dir)
err = createTestDirStructure(dir)
if !assert.NoError(t, err) {
t.FailNow()
}
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
actual := &bytes.Buffer{}
r := &TestRunner{}
e := executeCmdOnPkgs{
needOpenAPI: test.needOpenAPI,
writer: actual,
rootPkgPath: filepath.Join(dir, test.pkgPath),
recurseSubPackages: test.recurse,
cmdRunner: r,
}
err := e.execute()
if test.errMsg == "" {
if !assert.NoError(t, err) {
t.FailNow()
}
} else {
if !assert.Error(t, err) {
t.FailNow()
}
if !assert.Contains(t, err.Error(), test.errMsg) {
t.FailNow()
}
}
// normalize path format for windows
actualNormalized := strings.Replace(
strings.Replace(actual.String(), "\\", "/", -1),
"//", "/", -1)
expected := strings.Replace(test.expectedOut, "${baseDir}", dir+"/", -1)
expectedNormalized := strings.Replace(
strings.Replace(expected, "\\", "/", -1),
"//", "/", -1)
if !assert.Equal(t, expectedNormalized, actualNormalized) {
t.FailNow()
}
})
}
}
func createTestDirStructure(dir string) error {
/*
Adds the folders to the input dir with following structure
dir
├── subpkg1
│   ├── Krmfile
│   └── subdir1
├── subpkg4
│   ├── Krmfile
│   └── error.txt
└── subpkg2
├── subpkg3
│ ├── Krmfile
│ └── subdir2
└── Krmfile
*/
err := os.MkdirAll(filepath.Join(dir, "subpkg1/subdir1"), 0777|os.ModeDir)
if err != nil {
return err
}
err = os.MkdirAll(filepath.Join(dir, "subpkg2/subpkg3/subdir2"), 0777|os.ModeDir)
if err != nil {
return err
}
err = os.MkdirAll(filepath.Join(dir, "subpkg4"), 0777|os.ModeDir)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "subpkg1", "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "subpkg2", "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "subpkg2/subpkg3", "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "subpkg4", "error.txt"), []byte(""), 0777)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "subpkg4", "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
return nil
}
type TestRunner struct{}
func (r *TestRunner) executeCmd(w io.Writer, pkgPath string) error {
children, err := ioutil.ReadDir(pkgPath)
if err != nil {
return err
}
for _, child := range children {
if child.Name() == "error.txt" {
return errors.Errorf("this command returns an error if package has error.txt file")
}
}
return nil
}

View File

@@ -1,4 +1,4 @@
# 使用 kustomize 对 helm chart s进行修改
# 使用 kustomize 对 helm charts 进行修改
[last mile]: https://testingclouds.wordpress.com/2018/07/20/844/
[stable chart]: https://github.com/helm/charts/tree/master/stable

View File

@@ -8,19 +8,19 @@ require (
github.com/spf13/cobra v1.0.0
github.com/spf13/pflag v1.0.5
k8s.io/client-go v0.17.3
sigs.k8s.io/kustomize/api v0.5.1
sigs.k8s.io/kustomize/cmd/config v0.5.0
sigs.k8s.io/kustomize/api v0.6.0
sigs.k8s.io/kustomize/cmd/config v0.6.0
sigs.k8s.io/yaml v1.2.0
)
replace (
sigs.k8s.io/kustomize/api v0.5.1 => ../api
sigs.k8s.io/kustomize/cmd/config v0.5.0 => ../cmd/config
sigs.k8s.io/kustomize/kyaml => ../kyaml
)
exclude (
github.com/russross/blackfriday v2.0.0+incompatible
sigs.k8s.io/kustomize/api v0.2.0
sigs.k8s.io/kustomize/cmd/config v0.2.0
)
replace sigs.k8s.io/kustomize/api v0.6.0 => ../api
replace sigs.k8s.io/kustomize/cmd/config v0.6.0 => ../cmd/config
replace sigs.k8s.io/kustomize/kyaml v0.7.1 => ../kyaml

View File

@@ -629,6 +629,7 @@ golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -744,12 +745,14 @@ modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
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/cli-utils v0.19.2 h1:BwidWPZ3Qop4RBOl27MU8uN/BSEZPQ8rw1mwsNofXfw=
sigs.k8s.io/cli-utils v0.19.2/go.mod h1:ulIQPERYwkYksNriRknJRbGECDR/ZZROpkiThlXBtB4=
sigs.k8s.io/cli-utils v0.20.1 h1:S3IM4Rmely9oWNAeytx46PhngTwdRxsJ4ixtoGWPc3o=
sigs.k8s.io/cli-utils v0.20.1/go.mod h1:fQkEMmLXduMNmUf1+dgQ5GRJa4OrrLMw3qzAN8YXAU8=
sigs.k8s.io/controller-runtime v0.4.0 h1:wATM6/m+3w8lj8FXNaO6Fs/rq/vqoOjO1Q116Z9NPsg=
sigs.k8s.io/controller-runtime v0.4.0/go.mod h1:ApC79lpY3PHW9xj/w9pj+lYkLgwAAUZwfXkME1Lajns=
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
sigs.k8s.io/kustomize/kyaml v0.8.0 h1:/MqPML99XAm2pbrD/eTpePh5rnU5bpnuTPqb29LpSz4=
sigs.k8s.io/kustomize/kyaml v0.8.0/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
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/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18=

View File

@@ -81,6 +81,11 @@ func newCmdAddConfigMap(
"from-env-file",
"",
"Specify the path to a file to read lines of key=val pairs to create a configmap (i.e. a Docker .env file).")
cmd.Flags().BoolVar(
&flags.DisableNameSuffixHash,
"disableNameSuffixHash",
false,
"Disable the name suffix for the configmap")
return cmd
}
@@ -126,4 +131,9 @@ func mergeFlagsIntoCmArgs(args *types.ConfigMapArgs, flags flagsAndArgs) {
args.EnvSources = append(
args.EnvSources, flags.EnvFileSource)
}
if flags.DisableNameSuffixHash {
args.Options = &types.GeneratorOptions{
DisableNameSuffixHash: true,
}
}
}

View File

@@ -26,6 +26,8 @@ type flagsAndArgs struct {
Type string
// Namespace of secret
Namespace string
// Disable name suffix
DisableNameSuffixHash bool
}
// Validate validates required fields are set to support structured generation.

View File

@@ -91,6 +91,11 @@ func newCmdAddSecret(
"namespace",
"",
"Specify the namespace of the secret")
cmd.Flags().BoolVar(
&flags.DisableNameSuffixHash,
"disableNameSuffixHash",
false,
"Disable the name suffix for the secret")
return cmd
}
@@ -139,4 +144,9 @@ func mergeFlagsIntoGeneratorArgs(args *types.GeneratorArgs, flags flagsAndArgs)
args.EnvSources = append(
args.EnvSources, flags.EnvFileSource)
}
if flags.DisableNameSuffixHash {
args.Options = &types.GeneratorOptions{
DisableNameSuffixHash: true,
}
}
}

View File

@@ -114,3 +114,14 @@ func TestMergeFlagsIntoSecretArgs_EnvSource(t *testing.T) {
t.Fatalf("expected env2")
}
}
func TestMergeFlagsIntoSecretArgs_DisableNameSuffixHash(t *testing.T) {
k := &types.Kustomization{}
args := findOrMakeSecretArgs(k, "foo", "bar", "forbidden")
mergeFlagsIntoGeneratorArgs(
&args.GeneratorArgs,
flagsAndArgs{DisableNameSuffixHash: true})
if k.SecretGenerator[0].Options.DisableNameSuffixHash != true {
t.Fatalf("expected true")
}
}

View File

@@ -39,5 +39,6 @@ func RunFix(fSys filesys.FileSystem) error {
return err
}
m.FixKustomizationPreMarshalling()
return mf.Write(m)
}

View File

@@ -7,6 +7,7 @@ import (
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"sigs.k8s.io/kustomize/api/filesys"
testutils_test "sigs.k8s.io/kustomize/kustomize/v3/internal/commands/testutils"
)
@@ -31,3 +32,104 @@ func TestFix(t *testing.T) {
t.Errorf("expected kind in kustomization")
}
}
func TestFixOutdatedPatchesFieldTitle(t *testing.T) {
kustomizationContentWithOutdatedPatchesFieldTitle := []byte(`
patchesJson6902:
- path: patch1.yaml
target:
kind: Service
- path: patch2.yaml
target:
group: apps
kind: Deployment
version: v1
`)
expected := []byte(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patches:
- path: patch1.yaml
target:
kind: Service
- path: patch2.yaml
target:
group: apps
kind: Deployment
version: v1
`)
fSys := filesys.MakeFsInMemory()
testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedPatchesFieldTitle)
cmd := NewCmdFix(fSys)
err := cmd.RunE(cmd, nil)
if err != nil {
t.Errorf("unexpected cmd error: %v", err)
}
content, err := testutils_test.ReadTestKustomization(fSys)
if err != nil {
t.Errorf("unexpected read error: %v", err)
}
if !strings.Contains(string(content), "apiVersion: ") {
t.Errorf("expected apiVersion in kustomization")
}
if !strings.Contains(string(content), "kind: Kustomization") {
t.Errorf("expected kind in kustomization")
}
if diff := cmp.Diff(expected, content); diff != "" {
t.Errorf("Mismatch (-expected, +actual):\n%s", diff)
}
}
func TestRenameAndKeepOutdatedPatchesField(t *testing.T) {
kustomizationContentWithOutdatedPatchesFieldTitle := []byte(`
patchesJson6902:
- path: patch1.yaml
target:
kind: Deployment
patches:
- path: patch2.yaml
target:
kind: Deployment
- path: patch3.yaml
target:
kind: Service
`)
expected := []byte(`
patches:
- path: patch2.yaml
target:
kind: Deployment
- path: patch3.yaml
target:
kind: Service
- path: patch1.yaml
target:
kind: Deployment
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
`)
fSys := filesys.MakeFsInMemory()
testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedPatchesFieldTitle)
cmd := NewCmdFix(fSys)
err := cmd.RunE(cmd, nil)
if err != nil {
t.Errorf("unexpected cmd error: %v", err)
}
content, err := testutils_test.ReadTestKustomization(fSys)
if err != nil {
t.Errorf("unexpected read error: %v", err)
}
if !strings.Contains(string(content), "apiVersion: ") {
t.Errorf("expected apiVersion in kustomization")
}
if !strings.Contains(string(content), "kind: Kustomization") {
t.Errorf("expected kind in kustomization")
}
if diff := cmp.Diff(expected, content); diff != "" {
t.Errorf("Mismatch (-expected, +actual):\n%s", diff)
}
}

View File

@@ -145,6 +145,47 @@ func TestSetImage(t *testing.T) {
" newTag: my-tag2",
}},
},
{
description: "override file with patch",
given: given{
args: []string{"image1=foo.bar.foo:8800/foo/image1:foo-bar"},
infileImages: []string{
"images:",
"- name: image1",
" newName: my-image1",
" newTag: my-tag",
"- name: image2",
" newName: my-image2",
" newTag: my-tag2",
"patchesJson6902:",
"- patch: |-",
" - op: remove",
" path: /spec/selector",
" target:",
" kind: Service",
" name: foo",
" version: v1",
},
},
expected: expected{
fileOutput: []string{
"images:",
"- name: image1",
" newName: foo.bar.foo:8800/foo/image1",
" newTag: foo-bar",
"- name: image2",
" newName: my-image2",
" newTag: my-tag2",
"patchesJson6902:",
"- patch: |-",
" - op: remove",
" path: /spec/selector",
" target:",
" kind: Service",
" name: foo",
" version: v1",
}},
},
{
description: "override new tag and new name with just a new tag",
given: given{

View File

@@ -170,7 +170,6 @@ func (mf *kustomizationFile) Write(kustomization *types.Kustomization) error {
if kustomization == nil {
return errors.New("util: kustomization file arg is nil")
}
kustomization.FixKustomizationPreMarshalling()
data, err := mf.marshal(kustomization)
if err != nil {
return err

View File

@@ -338,103 +338,6 @@ kind: Kustomization
}
}
func TestRenameAndKeepOutdatedPatchesField(t *testing.T) {
kustomizationContentWithOutdatedPatchesFieldTitle := []byte(`
patchesJson6902:
- path: patch1.yaml
target:
kind: Deployment
patches:
- path: patch2.yaml
target:
kind: Deployment
- path: patch3.yaml
target:
kind: Service
`)
expected := []byte(`
patches:
- path: patch2.yaml
target:
kind: Deployment
- path: patch3.yaml
target:
kind: Service
- path: patch1.yaml
target:
kind: Deployment
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
`)
fSys := filesys.MakeFsInMemory()
testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedPatchesFieldTitle)
mf, err := NewKustomizationFile(fSys)
if err != nil {
t.Fatalf("Unexpected Error: %v", err)
}
kustomization, err := mf.Read()
if err != nil {
t.Fatalf("Unexpected Error: %v", err)
}
if err = mf.Write(kustomization); err != nil {
t.Fatalf("Unexpected Error: %v", err)
}
bytes, _ := fSys.ReadFile(mf.path)
if diff := cmp.Diff(expected, bytes); diff != "" {
t.Errorf("Mismatch (-expected, +actual):\n%s", diff)
}
}
func TestFixOutdatedPatchesFieldTitle(t *testing.T) {
kustomizationContentWithOutdatedPatchesFieldTitle := []byte(`
patchesJson6902:
- path: patch1.yaml
target:
kind: Service
- path: patch2.yaml
target:
group: apps
kind: Deployment
version: v1
`)
expected := []byte(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patches:
- path: patch1.yaml
target:
kind: Service
- path: patch2.yaml
target:
group: apps
kind: Deployment
version: v1
`)
fSys := filesys.MakeFsInMemory()
testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedPatchesFieldTitle)
mf, err := NewKustomizationFile(fSys)
if err != nil {
t.Fatalf("Unexpected Error: %v", err)
}
kustomization, err := mf.Read()
if err != nil {
t.Fatalf("Unexpected Error: %v", err)
}
if err = mf.Write(kustomization); err != nil {
t.Fatalf("Unexpected Error: %v", err)
}
bytes, _ := fSys.ReadFile(mf.path)
if diff := cmp.Diff(expected, bytes); diff != "" {
t.Errorf("Mismatch (-expected, +actual):\n%s", diff)
}
}
func TestUnknownFieldInKustomization(t *testing.T) {
kContent := []byte(`
foo:

View File

@@ -38,6 +38,7 @@ type ignoreFilesMatcher struct {
// if it is, reads it in and turns it into a matcher. If we can't find a file,
// we just add a matcher that match nothing.
func (i *ignoreFilesMatcher) readIgnoreFile(path string) error {
i.verifyPath(path)
m, err := gitignore.NewGitIgnore(filepath.Join(path, ext.GetIgnoreFileName()))
if err != nil {
if os.IsNotExist(err) {
@@ -63,8 +64,8 @@ func (i *ignoreFilesMatcher) readIgnoreFile(path string) error {
func (i *ignoreFilesMatcher) verifyPath(path string) {
for j := len(i.matchers) - 1; j >= 0; j-- {
matcher := i.matchers[j]
if !strings.HasPrefix(path, matcher.basePath) {
i.matchers = i.matchers[:j]
if strings.HasPrefix(path, matcher.basePath) || path == matcher.basePath {
i.matchers = i.matchers[:j+1]
return
}
}
@@ -76,7 +77,7 @@ func (i *ignoreFilesMatcher) matchFile(path string) bool {
if len(i.matchers) == 0 {
return false
}
i.verifyPath(path)
i.verifyPath(filepath.Dir(path))
return i.matchers[len(i.matchers)-1].matcher.Match(path, false)
}

View File

@@ -165,6 +165,52 @@ a_test.yaml
`b: b`,
},
},
{
name: "handles a combination of packages and directories",
directories: []string{
filepath.Join("a"),
filepath.Join("d", "e"),
filepath.Join("f"),
},
files: map[string][]byte{
filepath.Join("pkgFile"): {},
filepath.Join("d", "pkgFile"): {},
filepath.Join("d", "e", "pkgFile"): {},
filepath.Join("f", "pkgFile"): {},
filepath.Join("manifest.yaml"): []byte(`root: root`),
filepath.Join("a", "manifest.yaml"): []byte(`a: a`),
filepath.Join("d", "manifest.yaml"): []byte(`d: d`),
filepath.Join("d", "e", "manifest.yaml"): []byte(`e: e`),
filepath.Join("f", "manifest.yaml"): []byte(`f: f`),
filepath.Join("d", ".krmignore"): []byte(`
manifest.yaml
`),
},
expected: []string{
`a: a`,
`e: e`,
`f: f`,
`root: root`,
},
},
{
name: "ignore file can exclude subpackages",
directories: []string{
filepath.Join("a"),
},
files: map[string][]byte{
filepath.Join("pkgFile"): {},
filepath.Join("a", "pkgFile"): {},
filepath.Join("manifest.yaml"): []byte(`root: root`),
filepath.Join("a", "manifest.yaml"): []byte(`a: a`),
filepath.Join(".krmignore"): []byte(`
a
`),
},
expected: []string{
`root: root`,
},
},
}
for i := range testCases {

View File

@@ -80,6 +80,7 @@ func (r *LocalPackageReadWriter) Read() ([]*yaml.RNode, error) {
IncludeSubpackages: r.IncludeSubpackages,
ErrorIfNonResources: r.ErrorIfNonResources,
SetAnnotations: r.SetAnnotations,
PackageFileName: r.PackageFileName,
}.Read()
if err != nil {
return nil, errors.Wrap(err)
@@ -212,9 +213,9 @@ func (r LocalPackageReader) Read() ([]*yaml.RNode, error) {
// check if we should skip the directory or file
if info.IsDir() {
return r.ShouldSkipDir(path, ignoreFilesMatcher)
return r.shouldSkipDir(path, ignoreFilesMatcher)
}
if match, err := r.ShouldSkipFile(path, ignoreFilesMatcher); err != nil {
if match, err := r.shouldSkipFile(path, ignoreFilesMatcher); err != nil {
return err
} else if !match {
// skip this file
@@ -256,8 +257,8 @@ func (r *LocalPackageReader) readFile(path string, _ os.FileInfo) ([]*yaml.RNode
return rr.Read()
}
// ShouldSkipFile returns true if the file should be skipped
func (r *LocalPackageReader) ShouldSkipFile(path string, matcher *ignoreFilesMatcher) (bool, error) {
// shouldSkipFile returns true if the file should be skipped
func (r *LocalPackageReader) shouldSkipFile(path string, matcher *ignoreFilesMatcher) (bool, error) {
// check if the file is covered by a .krmignore file.
if matcher.matchFile(path) {
return false, nil
@@ -284,23 +285,18 @@ func (r *LocalPackageReader) initReaderAnnotations(path string, _ os.FileInfo) {
}
}
// ShouldSkipDir returns a filepath.SkipDir if the directory should be skipped
func (r *LocalPackageReader) ShouldSkipDir(path string, matcher *ignoreFilesMatcher) error {
// shouldSkipDir returns a filepath.SkipDir if the directory should be skipped
func (r *LocalPackageReader) shouldSkipDir(path string, matcher *ignoreFilesMatcher) error {
if matcher.matchDir(path) {
return filepath.SkipDir
}
if r.PackageFileName == "" {
// If the folder is not a package, but covered by the .krmignore file,
// we skip it.
if matcher.matchDir(path) {
return filepath.SkipDir
}
return nil
}
// check if this is a subpackage
_, err := os.Stat(filepath.Join(path, r.PackageFileName))
if os.IsNotExist(err) {
// Skip the folder if it is covered by the .krmignore file.
if matcher.matchDir(path) {
return filepath.SkipDir
}
return nil
} else if err != nil {
return errors.Wrap(err)
@@ -308,9 +304,5 @@ func (r *LocalPackageReader) ShouldSkipDir(path string, matcher *ignoreFilesMatc
if !r.IncludeSubpackages {
return filepath.SkipDir
}
// We don't allow the .krmignore file in a package cause us to skip
// a subpackage. So if we have found a package file in the folder and
// we should include subpackages, we don't check the .krmignore file. We
// do however check whether the package contains a .krmignore file.
return matcher.readIgnoreFile(path)
}

View File

@@ -6,6 +6,7 @@ package kio
import (
"fmt"
"io"
"os"
"path/filepath"
"sort"
"strings"
@@ -33,10 +34,11 @@ var GraphStructures = []string{string(TreeStructureGraph), string(TreeStructureP
// TODO(pwittrock): test this package better. it is lower-risk since it is only
// used for printing rather than updating or editing.
type TreeWriter struct {
Writer io.Writer
Root string
Fields []TreeWriterField
Structure TreeStructure
Writer io.Writer
Root string
Fields []TreeWriterField
Structure TreeStructure
OpenAPIFileName string
}
// TreeWriterField configures a Resource field to be included in the tree
@@ -72,7 +74,7 @@ func (p TreeWriter) packageStructure(nodes []*yaml.RNode) error {
// create a new branch for the package
createOk := pkg != "." // special edge case logic for tree on current working dir
if createOk {
branch = branch.AddBranch(pkg)
branch = branch.AddBranch(branchName(p.Root, pkg, p.OpenAPIFileName))
}
// cache the branch for this package
@@ -91,6 +93,19 @@ func (p TreeWriter) packageStructure(nodes []*yaml.RNode) error {
return err
}
// branchName takes the root directory and relative path to the directory
// and returns the branch name
func branchName(root, dirRelPath, openAPIFileName string) string {
name := filepath.Base(dirRelPath)
_, err := os.Stat(filepath.Join(root, dirRelPath, openAPIFileName))
if !os.IsNotExist(err) {
// add Pkg: prefix indicating that it is a separate package as it has
// openAPIFile
return fmt.Sprintf("Pkg: %s", name)
}
return name
}
// Write writes the ascii tree to p.Writer
func (p TreeWriter) Write(nodes []*yaml.RNode) error {
switch p.Structure {

View File

@@ -6,7 +6,6 @@ package kio_test
import (
"bytes"
"fmt"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
@@ -76,9 +75,9 @@ spec:
└── foo-package
├── [f1.yaml] Deployment default/foo
├── [f1.yaml] Service default/foo
└── foo-package%s3
└── 3
└── [f3.yaml] Deployment default/foo
`, string(filepath.Separator)), out.String()) {
`), out.String()) {
t.FailNow()
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -95,7 +95,7 @@ func openapiKustomizationapiSwaggerJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "openapi/kustomizationapi/swagger.json", size: 3127, mode: os.FileMode(420), modTime: time.Unix(1586844916, 0)}
info := bindataFileInfo{name: "openapi/kustomizationapi/swagger.json", size: 3127, mode: os.FileMode(420), modTime: time.Unix(1586909905, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}

View File

@@ -8,6 +8,7 @@ import (
"fmt"
"io/ioutil"
"reflect"
"strings"
"sync"
"github.com/go-openapi/spec"
@@ -23,10 +24,11 @@ var globalSchema openapiData
// openapiData contains the parsed openapi state. this is in a struct rather than
// a list of vars so that it can be reset from tests.
type openapiData struct {
setup sync.Once
schema spec.Schema
schemaByResourceType map[yaml.TypeMeta]*spec.Schema
noUseBuiltInSchema bool
setup sync.Once
schema spec.Schema
schemaByResourceType map[yaml.TypeMeta]*spec.Schema
namespaceabilityByResourceType map[yaml.TypeMeta]bool
noUseBuiltInSchema bool
}
// ResourceSchema wraps the OpenAPI Schema.
@@ -66,6 +68,41 @@ func AddSchemaFromFile(path string) error {
return AddSchemaFromFileUsingField(path, SupplementaryOpenAPIFieldName)
}
// DeleteSchemaInFile reads the file at path and removes all the openAPI definitions
// present in file from global schema
func DeleteSchemaInFile(path string) error {
b, err := ioutil.ReadFile(path)
if err != nil {
return err
}
object, err := yaml.Parse(string(b))
if err != nil {
return err
}
definitions, err := object.Pipe(yaml.Lookup(SupplementaryOpenAPIFieldName, "definitions"))
if definitions == nil {
return nil
}
if err != nil {
return err
}
fields, err := definitions.Fields()
if err != nil {
return err
}
for _, field := range fields {
_, ok := globalSchema.schema.Definitions[field]
if ok {
delete(globalSchema.schema.Definitions, field)
}
}
return nil
}
// AddSchemaFromFileUsingField reads the file at path and parses the OpenAPI definitions
// from the specified field. If field is the empty string, use the whole document as
// OpenAPI.
@@ -109,7 +146,7 @@ func AddSchemaFromFileUsingField(path, field string) error {
}
// add the json schema to the global schema
_, err = AddSchema(j)
err = AddSchema(j)
if err != nil {
return err
}
@@ -117,7 +154,7 @@ func AddSchemaFromFileUsingField(path, field string) error {
}
// AddSchema parses s, and adds definitions from s to the global schema.
func AddSchema(s []byte) (*spec.Schema, error) {
func AddSchema(s []byte) error {
return parse(s)
}
@@ -153,21 +190,29 @@ func AddDefinitions(definitions spec.Definitions) {
if !ok || len(exts) != 1 {
continue
}
m, ok := exts[0].(map[string]interface{})
typeMeta, ok := toTypeMeta(exts[0])
if !ok {
continue
}
// build the index key and save it
g := m[groupKey].(string)
apiVersion := m[versionKey].(string)
if g != "" {
apiVersion = g + "/" + apiVersion
}
globalSchema.schemaByResourceType[yaml.TypeMeta{Kind: m[kindKey].(string), APIVersion: apiVersion}] = &d
globalSchema.schemaByResourceType[typeMeta] = &d
}
}
func toTypeMeta(ext interface{}) (yaml.TypeMeta, bool) {
m, ok := ext.(map[string]interface{})
if !ok {
return yaml.TypeMeta{}, false
}
g := m[groupKey].(string)
apiVersion := m[versionKey].(string)
if g != "" {
apiVersion = g + "/" + apiVersion
}
return yaml.TypeMeta{Kind: m[kindKey].(string), APIVersion: apiVersion}, true
}
// Resolve resolves the reference against the global schema
func Resolve(ref *spec.Ref) (*spec.Schema, error) {
return resolve(Schema(), ref)
@@ -196,6 +241,19 @@ func GetSchema(s string) (*ResourceSchema, error) {
return &ResourceSchema{Schema: &sc}, nil
}
// IsNamespaceScoped determines whether a resource is namespace or
// cluster-scoped by looking at the information in the openapi schema.
// The second return value tells whether the provided type could be found
// in the openapi schema. If the value is false here, the scope of the
// resource is not known. If the type if found, the first return value will
// be true if the resource is namespace-scoped, and false if the type is
// cluster-scoped.
func IsNamespaceScoped(typeMeta yaml.TypeMeta) (bool, bool) {
initSchema()
isNamespaceScoped, found := globalSchema.namespaceabilityByResourceType[typeMeta]
return isNamespaceScoped, found
}
// SuppressBuiltInSchemaUse can be called to prevent using the built-in Kubernetes
// schema as part of the global schema.
// Must be called before the schema is used.
@@ -333,12 +391,12 @@ func initSchema() {
}
// parse the swagger, this should never fail
if _, err := parse(kubernetesapi.MustAsset(kubernetesAPIAssetName)); err != nil {
if err := parse(kubernetesapi.MustAsset(kubernetesAPIAssetName)); err != nil {
// this should never happen
panic(err)
}
if _, err := parse(kustomizationapi.MustAsset(kustomizationAPIAssetName)); err != nil {
if err := parse(kustomizationapi.MustAsset(kustomizationAPIAssetName)); err != nil {
// this should never happen
panic(err)
}
@@ -346,14 +404,55 @@ func initSchema() {
}
// parse parses and indexes a single json schema
func parse(b []byte) (*spec.Schema, error) {
var sc spec.Schema
func parse(b []byte) error {
var swagger spec.Swagger
if err := sc.UnmarshalJSON(b); err != nil {
return nil, errors.Wrap(err)
if err := swagger.UnmarshalJSON(b); err != nil {
return errors.Wrap(err)
}
AddDefinitions(swagger.Definitions)
findNamespaceability(swagger.Paths)
return nil
}
// findNamespaceability looks at the api paths for the resource to determine
// if it is cluster-scoped or namespace-scoped. The gvk of the resource
// for each path is found by looking at the x-kubernetes-group-version-kind
// extension. If a path exists for the resource that contains a namespace path
// parameter, the resource is namespace-scoped.
func findNamespaceability(paths *spec.Paths) {
if globalSchema.namespaceabilityByResourceType == nil {
globalSchema.namespaceabilityByResourceType = make(map[yaml.TypeMeta]bool)
}
if paths == nil {
return
}
for path, pathInfo := range paths.Paths {
if pathInfo.Get == nil {
continue
}
gvk, found := pathInfo.Get.VendorExtensible.Extensions[kubernetesGVKExtensionKey]
if !found {
continue
}
typeMeta, found := toTypeMeta(gvk)
if !found {
continue
}
if strings.Contains(path, "namespaces/{namespace}") {
// if we find a namespace path parameter, we just update the map
// directly
globalSchema.namespaceabilityByResourceType[typeMeta] = true
} else if _, found := globalSchema.namespaceabilityByResourceType[typeMeta]; !found {
// if the resource doesn't have the namespace path parameter, we
// only add it to the map if it doesn't already exist.
globalSchema.namespaceabilityByResourceType[typeMeta] = false
}
}
AddDefinitions(sc.Definitions)
return &sc, nil
}
func resolve(root interface{}, ref *spec.Ref) (*spec.Schema, error) {

View File

@@ -16,7 +16,7 @@ func TestAddSchema(t *testing.T) {
// reset package vars
globalSchema = openapiData{}
_, err := AddSchema(additionalSchema)
err := AddSchema(additionalSchema)
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -36,7 +36,7 @@ func TestNoUseBuiltInSchema_AddSchema(t *testing.T) {
globalSchema = openapiData{}
SuppressBuiltInSchemaUse()
_, err := AddSchema(additionalSchema)
err := AddSchema(additionalSchema)
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -160,6 +160,82 @@ openAPI:
fmt.Sprintf("%v", s.Schema.Extensions))
}
func TestDeleteSchemaInFile(t *testing.T) {
ResetOpenAPI()
inputyaml := `
openAPI:
definitions:
io.k8s.cli.setters.image-name:
x-k8s-cli:
setter:
name: image-name
value: "nginx"
`
f, err := ioutil.TempFile("", "openapi-")
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.NoError(t, ioutil.WriteFile(f.Name(), []byte(inputyaml), 0600)) {
t.FailNow()
}
err = AddSchemaFromFile(f.Name())
if !assert.NoError(t, err) {
t.FailNow()
}
s, err := GetSchema(`{"$ref": "#/definitions/io.k8s.cli.setters.image-name"}`)
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Greater(t, len(globalSchema.schema.Definitions), 200) {
t.FailNow()
}
assert.Equal(t, `map[x-k8s-cli:map[setter:map[name:image-name value:nginx]]]`,
fmt.Sprintf("%v", s.Schema.Extensions))
err = DeleteSchemaInFile(f.Name())
if !assert.NoError(t, err) {
t.FailNow()
}
_, err = GetSchema(`{"$ref": "#/definitions/io.k8s.cli.setters.image-name"}`)
if !assert.Error(t, err) {
t.FailNow()
}
if !assert.Equal(t, `object has no key "io.k8s.cli.setters.image-name"`, err.Error()) {
t.FailNow()
}
}
func TestDeleteSchemaInFileNoDefs(t *testing.T) {
ResetOpenAPI()
inputyaml := `
openAPI:
definitions:
`
f, err := ioutil.TempFile("", "openapi-")
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.NoError(t, ioutil.WriteFile(f.Name(), []byte(inputyaml), 0600)) {
t.FailNow()
}
err = AddSchemaFromFile(f.Name())
if !assert.NoError(t, err) {
t.FailNow()
}
err = DeleteSchemaInFile(f.Name())
if !assert.NoError(t, err) {
t.FailNow()
}
}
func TestPopulateDefsInOpenAPI_Substitution(t *testing.T) {
ResetOpenAPI()
inputyaml := `
@@ -237,3 +313,100 @@ kind: Example
t.FailNow()
}
}
func TestIsNamespaceScoped_builtin(t *testing.T) {
testCases := []struct {
name string
typeMeta yaml.TypeMeta
expectIsFound bool
expectIsNamespaced bool
}{
{
name: "namespacescoped resource",
typeMeta: yaml.TypeMeta{
APIVersion: "apps/v1",
Kind: "Deployment",
},
expectIsFound: true,
expectIsNamespaced: true,
},
{
name: "clusterscoped resource",
typeMeta: yaml.TypeMeta{
APIVersion: "v1",
Kind: "Namespace",
},
expectIsFound: true,
expectIsNamespaced: false,
},
{
name: "unknown resource",
typeMeta: yaml.TypeMeta{
APIVersion: "custom.io/v1",
Kind: "Custom",
},
expectIsFound: false,
},
}
for i := range testCases {
test := testCases[i]
t.Run(test.name, func(t *testing.T) {
ResetOpenAPI()
isNamespaceable, isFound := IsNamespaceScoped(test.typeMeta)
if !test.expectIsFound {
assert.False(t, isFound)
return
}
assert.True(t, isFound)
assert.Equal(t, test.expectIsNamespaced, isNamespaceable)
})
}
}
func TestIsNamespaceScoped_custom(t *testing.T) {
SuppressBuiltInSchemaUse()
err := AddSchema([]byte(`
{
"definitions": {},
"paths": {
"/apis/custom.io/v1/namespaces/{namespace}/customs/{name}": {
"get": {
"x-kubernetes-action": "get",
"x-kubernetes-group-version-kind": {
"group": "custom.io",
"kind": "Custom",
"version": "v1"
}
}
},
"/apis/custom.io/v1/clustercustoms": {
"get": {
"x-kubernetes-action": "get",
"x-kubernetes-group-version-kind": {
"group": "custom.io",
"kind": "ClusterCustom",
"version": "v1"
}
}
}
}
}
`))
assert.NoError(t, err)
isNamespaceable, isFound := IsNamespaceScoped(yaml.TypeMeta{
APIVersion: "custom.io/v1",
Kind: "ClusterCustom",
})
assert.True(t, isFound)
assert.False(t, isNamespaceable)
isNamespaceable, isFound = IsNamespaceScoped(yaml.TypeMeta{
APIVersion: "custom.io/v1",
Kind: "Custom",
})
assert.True(t, isFound)
assert.True(t, isNamespaceable)
}

View File

@@ -6,23 +6,29 @@ package pathutil
import (
"os"
"path/filepath"
"strings"
)
// SubDirsWithFile takes the root directory path and returns all the paths of
// sub-directories which contain file with input fileName including itself
func SubDirsWithFile(root, fileName string) ([]string, error) {
// DirsWithFile takes the root directory path and returns all the paths of
// sub-directories(including itself) which contain file with input fileName
// at top level if recurse is true
func DirsWithFile(root, fileName string, recurse bool) ([]string, error) {
var res []string
if !recurse {
// check if the file with fileName is present in root and return it
// else return empty list
_, err := os.Stat(filepath.Join(root, fileName))
if !os.IsNotExist(err) {
res = append(res, filepath.Clean(root))
}
return res, nil
}
err := filepath.Walk(root,
func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if strings.HasSuffix(path, fileName) {
if root == "." {
path = root + "/" + path
}
res = append(res, path)
if filepath.Base(path) == fileName {
res = append(res, filepath.Dir(path))
}
return nil
})

View File

@@ -13,6 +13,32 @@ import (
)
func TestSubDirsWithFile(t *testing.T) {
var tests = []struct {
name string
fileName string
recurse bool
outFilesCount int
}{
{
name: "dirs-with-file-recurse",
fileName: "Krmfile",
outFilesCount: 3,
recurse: true,
},
{
name: "dirs-with-non-existent-file-recurse",
fileName: "non-existent-file.txt",
outFilesCount: 0,
recurse: true,
},
{
name: "dir-with-file-no-recurse",
fileName: "Krmfile",
outFilesCount: 1,
recurse: false,
},
}
dir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
@@ -23,28 +49,17 @@ func TestSubDirsWithFile(t *testing.T) {
t.FailNow()
}
res, err := SubDirsWithFile(dir, "Krmfile")
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Equal(t, 3, len(res)) {
t.FailNow()
}
}
func TestSubDirsWithFileNoMatch(t *testing.T) {
dir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
defer os.RemoveAll(dir)
res, err := SubDirsWithFile(dir, "non-existent-file.txt")
if !assert.NoError(t, err) {
t.FailNow()
}
var expected []string
if !assert.Equal(t, expected, res) {
t.FailNow()
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
res, err := DirsWithFile(dir, test.fileName, test.recurse)
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Equal(t, test.outFilesCount, len(res)) {
t.FailNow()
}
})
}
}

View File

@@ -135,18 +135,18 @@ func (dd DeleterDefinition) Filter(object *yaml.RNode) (*yaml.RNode, error) {
}
definitions, err := object.Pipe(yaml.Lookup(openapi.SupplementaryOpenAPIFieldName, "definitions"))
if err != nil || definitions == nil {
if err != nil {
return nil, err
}
// return error if the setter to be deleted doesn't exist
if definitions.Field(key) == nil {
return nil, errors.Errorf("%s with name %s does not exist", defType, dd.Name)
if definitions == nil || definitions.Field(key) == nil {
return nil, errors.Errorf("%s %q does not exist", defType, dd.Name)
}
subst := SubstReferringDefinition(definitions, key)
if subst != "" {
return nil, errors.Errorf("%s is used in substitution %s, please delete the parent substitution first", defType, subst)
return nil, errors.Errorf("%s %q is used in substitution %q, please delete the parent substitution first", defType, dd.Name, subst)
}
_, err = definitions.Pipe(yaml.FieldClearer{Name: key})

View File

@@ -38,7 +38,7 @@ metadata:
spec:
replicas: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"}
`
_, err := openapi.AddSchema([]byte(schema)) // add the schema definitions
err := openapi.AddSchema([]byte(schema)) // add the schema definitions
if err != nil {
panic(err)
}
@@ -103,7 +103,7 @@ spec:
image: nginx:1.7.9 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`
_, err := openapi.AddSchema([]byte(schema)) // add the schema definitions
err := openapi.AddSchema([]byte(schema)) // add the schema definitions
if err != nil {
panic(err)
}

View File

@@ -367,14 +367,14 @@ func (s SetOpenAPI) Filter(object *yaml.RNode) (*yaml.RNode, error) {
return nil, err
}
if oa == nil {
return nil, errors.Errorf("no setter %s found", s.Name)
return nil, errors.Errorf("setter %q is not found", s.Name)
}
def, err := oa.Pipe(yaml.Lookup("x-k8s-cli", "setter"))
if err != nil {
return nil, err
}
if def == nil {
return nil, errors.Errorf("no setter %s found", s.Name)
return nil, errors.Errorf("setter %q is not found", s.Name)
}
// record the OpenAPI type for the setter

View File

@@ -954,7 +954,7 @@ func initSchema(t *testing.T, s string) {
openapi.ResetOpenAPI()
// add the json schema to the global schema
_, err = openapi.AddSchema(j)
err = openapi.AddSchema(j)
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -1271,7 +1271,7 @@ openAPI:
{
name: "error",
setter: "replicas",
err: "no setter replicas found",
err: `setter "replicas" is not found`,
input: `
openAPI:
definitions:

View File

@@ -75,8 +75,10 @@ func TestDeleterCreator_Delete(t *testing.T) {
if !assert.NoError(t, err) {
t.FailNow()
}
dc.OpenAPIPath = openAPI.Name()
dc.ResourcesPath = resource.Name()
err = dc.Delete(openAPI.Name(), resource.Name())
err = dc.Delete()
if !assert.NoError(t, err) {
t.FailNow()
}

View File

@@ -17,24 +17,34 @@ type DeleterCreator struct {
// DefinitionPrefix is the prefix of the OpenAPI definition type
DefinitionPrefix string
RecurseSubPackages bool
OpenAPIFileName string
// Path to openAPI file
OpenAPIPath string
// Path to resources folder
ResourcesPath string
}
func (d DeleterCreator) Delete(openAPIPath, resourcesPath string) error {
func (d DeleterCreator) Delete() error {
dd := setters2.DeleterDefinition{
Name: d.Name,
DefinitionPrefix: d.DefinitionPrefix,
}
if err := dd.DeleteFromFile(openAPIPath); err != nil {
if err := dd.DeleteFromFile(d.OpenAPIPath); err != nil {
return err
}
// Load the updated definitions
if err := openapi.AddSchemaFromFile(openAPIPath); err != nil {
if err := openapi.AddSchemaFromFile(d.OpenAPIPath); err != nil {
return err
}
// Update the resources with the deleter reference
inout := &kio.LocalPackageReadWriter{PackagePath: resourcesPath}
inout := &kio.LocalPackageReadWriter{PackagePath: d.ResourcesPath, PackageFileName: d.OpenAPIFileName}
return kio.Pipeline{
Inputs: []kio.Reader{inout},
Filters: []kio.Filter{kio.FilterAll(

View File

@@ -32,16 +32,20 @@ type FieldSetter struct {
OpenAPIPath string
OpenAPIFileName string
ResourcesPath string
RecurseSubPackages bool
}
func (fs *FieldSetter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
fs.Count, _ = fs.Set(fs.OpenAPIPath, fs.ResourcesPath)
fs.Count, _ = fs.Set()
return nil, nil
}
// Set updates the OpenAPI definitions and resources with the new setter value
func (fs FieldSetter) Set(openAPIPath, resourcesPath string) (int, error) {
func (fs FieldSetter) Set() (int, error) {
// Update the OpenAPI definitions
soa := setters2.SetOpenAPI{
Name: fs.Name,
@@ -55,30 +59,30 @@ func (fs FieldSetter) Set(openAPIPath, resourcesPath string) (int, error) {
// at to get the value and set it to resource files, but if there is error
// after updating openAPI file and while updating resources, the openAPI
// file should be reverted, as set operation failed
stat, err := os.Stat(openAPIPath)
stat, err := os.Stat(fs.OpenAPIPath)
if err != nil {
return 0, err
}
curOpenAPI, err := ioutil.ReadFile(openAPIPath)
curOpenAPI, err := ioutil.ReadFile(fs.OpenAPIPath)
if err != nil {
return 0, err
}
// write the new input value to openAPI file
if err := soa.UpdateFile(openAPIPath); err != nil {
if err := soa.UpdateFile(fs.OpenAPIPath); err != nil {
return 0, err
}
// Load the updated definitions
if err := openapi.AddSchemaFromFile(openAPIPath); err != nil {
if err := openapi.AddSchemaFromFile(fs.OpenAPIPath); err != nil {
return 0, err
}
// Update the resources with the new value
// Set NoDeleteFiles to true as SetAll will return only the nodes of files which should be updated and
// hence, rest of the files should not be deleted
inout := &kio.LocalPackageReadWriter{PackagePath: resourcesPath, NoDeleteFiles: true}
inout := &kio.LocalPackageReadWriter{PackagePath: fs.ResourcesPath, NoDeleteFiles: true, PackageFileName: fs.OpenAPIFileName}
s := &setters2.Set{Name: fs.Name}
err = kio.Pipeline{
Inputs: []kio.Reader{inout},
@@ -88,7 +92,7 @@ func (fs FieldSetter) Set(openAPIPath, resourcesPath string) (int, error) {
// revert openAPI file if set operation fails
if err != nil {
if writeErr := ioutil.WriteFile(openAPIPath, curOpenAPI, stat.Mode().Perm()); writeErr != nil {
if writeErr := ioutil.WriteFile(fs.OpenAPIPath, curOpenAPI, stat.Mode().Perm()); writeErr != nil {
return 0, writeErr
}
}

View File

@@ -47,6 +47,10 @@ type SetterCreator struct {
// the package publisher's intent to make the setter required to be set.
Required bool
RecurseSubPackages bool
OpenAPIFileName string
// Path to openAPI file
OpenAPIPath string
@@ -55,17 +59,21 @@ type SetterCreator struct {
}
func (c *SetterCreator) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
return nil, c.Create(c.OpenAPIPath, c.ResourcesPath)
return nil, c.Create()
}
func (c SetterCreator) Create(openAPIPath, resourcesPath string) error {
err := validateSchema(c.Schema)
func (c SetterCreator) Create() error {
err := c.validateSetterInfo()
if err != nil {
return err
}
err = validateSchema(c.Schema)
if err != nil {
return errors.Errorf("invalid schema: %v", err)
}
// Update the resources with the setter reference
inout := &kio.LocalPackageReadWriter{PackagePath: resourcesPath}
inout := &kio.LocalPackageReadWriter{PackagePath: c.ResourcesPath}
a := &setters2.Add{
FieldName: c.FieldName,
FieldValue: c.FieldValue,
@@ -78,7 +86,7 @@ func (c SetterCreator) Create(openAPIPath, resourcesPath string) error {
Outputs: []kio.Writer{inout},
}.Execute()
if a.Count == 0 {
fmt.Printf("setter %s doesn't match any field in resource configs, "+
fmt.Printf("setter %q doesn't match any field in resource configs, "+
"but creating setter definition\n", c.Name)
}
if err != nil {
@@ -90,12 +98,12 @@ func (c SetterCreator) Create(openAPIPath, resourcesPath string) error {
Name: c.Name, Value: c.FieldValue, SetBy: c.SetBy, Description: c.Description,
Type: c.Type, Schema: c.Schema, Required: c.Required,
}
if err := sd.AddToFile(openAPIPath); err != nil {
if err := sd.AddToFile(c.OpenAPIPath); err != nil {
return err
}
// Load the updated definitions
if err := openapi.AddSchemaFromFile(openAPIPath); err != nil {
if err := openapi.AddSchemaFromFile(c.OpenAPIPath); err != nil {
return err
}
// if the setter is of array type write the derived list values back to
@@ -103,7 +111,7 @@ func (c SetterCreator) Create(openAPIPath, resourcesPath string) error {
if len(a.ListValues) > 0 {
sd.ListValues = a.ListValues
sd.Value = ""
if err := sd.AddToFile(openAPIPath); err != nil {
if err := sd.AddToFile(c.OpenAPIPath); err != nil {
return err
}
}
@@ -165,3 +173,32 @@ func validateSchemaTypes(sc *spec.Schema) error {
}
return nil
}
func (c SetterCreator) validateSetterInfo() error {
// check if substitution with same name exists and throw error
ref, err := spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SubstitutionDefinitionPrefix + c.Name)
if err != nil {
return err
}
subst, _ := openapi.Resolve(&ref)
// if substitution already exists with the input setter name, throw error
if subst != nil {
return errors.Errorf("substitution with name %q already exists, "+
"substitution and setter can't have same name", c.Name)
}
// check if setter with same name exists and throw error
ref, err = spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SetterDefinitionPrefix + c.Name)
if err != nil {
return err
}
setter, _ := openapi.Resolve(&ref)
// if setter already exists with the input setter name, throw error
if setter != nil {
return errors.Errorf("setter with name %q already exists, "+
"if you want to modify it, please delete the existing setter and recreate it", c.Name)
}
return nil
}

View File

@@ -47,15 +47,23 @@ type SubstitutionCreator struct {
// Path to openAPI file
OpenAPIPath string
OpenAPIFileName string
RecurseSubPackages bool
// Path to resources folder
ResourcesPath string
}
func (c *SubstitutionCreator) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
return nil, c.Create(c.OpenAPIPath, c.ResourcesPath)
return nil, c.Create()
}
func (c SubstitutionCreator) Create(openAPIPath, resourcesPath string) error {
func (c SubstitutionCreator) Create() error {
err := c.validateSubstitutionInfo()
if err != nil {
return err
}
values, err := markersAndRefs(c.Name, c.Pattern)
if err != nil {
return err
@@ -70,22 +78,22 @@ func (c SubstitutionCreator) Create(openAPIPath, resourcesPath string) error {
// the input substitution definition is updated in the openAPI file and then parsed
// to check if there are any cycles in nested substitutions, if there are
// any, the openAPI file will be reverted to current state and error is thrown
stat, err := os.Stat(openAPIPath)
stat, err := os.Stat(c.OpenAPIPath)
if err != nil {
return err
}
curOpenAPI, err := ioutil.ReadFile(openAPIPath)
curOpenAPI, err := ioutil.ReadFile(c.OpenAPIPath)
if err != nil {
return err
}
if err := d.AddToFile(openAPIPath); err != nil {
if err := d.AddToFile(c.OpenAPIPath); err != nil {
return err
}
// Load the updated definitions
if err := openapi.AddSchemaFromFile(openAPIPath); err != nil {
if err := openapi.AddSchemaFromFile(c.OpenAPIPath); err != nil {
return err
}
@@ -105,19 +113,19 @@ func (c SubstitutionCreator) Create(openAPIPath, resourcesPath string) error {
return err
}
err = c.CreateSettersForSubstitution(openAPIPath)
err = c.CreateSettersForSubstitution(c.OpenAPIPath)
if err != nil {
return err
}
// Load the updated definitions after setters are created
if err := openapi.AddSchemaFromFile(openAPIPath); err != nil {
if err := openapi.AddSchemaFromFile(c.OpenAPIPath); err != nil {
return err
}
// revert openAPI file if there are cycles detected in created input substitution
if err := checkForCycles(ext, visited); err != nil {
if writeErr := ioutil.WriteFile(openAPIPath, curOpenAPI, stat.Mode().Perm()); writeErr != nil {
if writeErr := ioutil.WriteFile(c.OpenAPIPath, curOpenAPI, stat.Mode().Perm()); writeErr != nil {
return writeErr
}
return err
@@ -130,7 +138,7 @@ func (c SubstitutionCreator) Create(openAPIPath, resourcesPath string) error {
}
// Update the resources with the substitution reference
inout := &kio.LocalPackageReadWriter{PackagePath: resourcesPath}
inout := &kio.LocalPackageReadWriter{PackagePath: c.ResourcesPath, PackageFileName: c.OpenAPIFileName}
err = kio.Pipeline{
Inputs: []kio.Reader{inout},
Filters: []kio.Filter{kio.FilterAll(a)},
@@ -203,7 +211,7 @@ func (c SubstitutionCreator) CreateSettersForSubstitution(openAPIPath string) er
// continue if ref is a substitution, as it has already been checked if it exists
// as part of preRunE
if strings.Contains(value.Ref, fieldmeta.SubstitutionDefinitionPrefix) {
fmt.Printf("found a substitution with name %s\n", value.Marker)
fmt.Printf("found a substitution with name %q\n", value.Marker)
continue
}
setterObj, err := y.Pipe(yaml.Lookup(
@@ -420,3 +428,32 @@ func min(a int, b int) int {
}
return b
}
func (c SubstitutionCreator) validateSubstitutionInfo() error {
// check if substitution with same name exists and throw error
ref, err := spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SubstitutionDefinitionPrefix + c.Name)
if err != nil {
return err
}
subst, _ := openapi.Resolve(&ref)
// if substitution already exists with the input substitution name, throw error
if subst != nil {
return errors.Errorf("substitution with name %q already exists", c.Name)
}
// check if setter with same name exists and throw error
ref, err = spec.NewRef(fieldmeta.DefinitionsPrefix + fieldmeta.SetterDefinitionPrefix + c.Name)
if err != nil {
return err
}
setter, _ := openapi.Resolve(&ref)
// if setter already exists with input substitution name, throw error
if setter != nil {
return errors.Errorf(fmt.Sprintf("setter with name %q already exists, "+
"substitution and setter can't have same name", c.Name))
}
return nil
}

View File

@@ -31,7 +31,7 @@ var Filters = map[string]func() Filter{
"TeePiper": func() Filter { return &TeePiper{} },
}
// YFilter wraps the GrepFilter interface so the filter can be represented as
// YFilter wraps the Filter interface so the filter can be represented as
// data and can be unmarshalled into a struct from a yaml config file.
// This allows Pipelines to be expressed as data rather than code.
type YFilter struct {
@@ -54,7 +54,7 @@ func (y *YFilter) UnmarshalYAML(unmarshal func(interface{}) error) error {
knownFilters = append(knownFilters, k)
}
sort.Strings(knownFilters)
return fmt.Errorf("unsupported GrepFilter Kind %s: may be one of: [%s]",
return fmt.Errorf("unsupported Filter Kind %s: may be one of: [%s]",
meta.Kind, strings.Join(knownFilters, ","))
}
y.Filter = filter()

View File

@@ -605,7 +605,7 @@ func IsListIndex(p string) bool {
// SplitIndexNameValue splits a lookup part Val index into the field name
// and field value to match.
// e.g. splits [name=nginx] into (name, nginx)
// e.g. splits [=-jar] into ("", jar)
// e.g. splits [=-jar] into ("", -jar)
func SplitIndexNameValue(p string) (string, string, error) {
elem := strings.TrimSuffix(p, "]")
elem = strings.TrimPrefix(elem, "[")

View File

@@ -518,6 +518,11 @@ func TestSplitIndexNameValue(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "a", k)
assert.Equal(t, "b=c", v)
k, v, err = SplitIndexNameValue("=-jar")
assert.NoError(t, err)
assert.Equal(t, "", k)
assert.Equal(t, "-jar", v)
}
type filter struct {

View File

@@ -277,14 +277,14 @@ func (rn *RNode) GetMeta() (ResourceMeta, error) {
return m, nil
}
// Pipe sequentially invokes each GrepFilter, and passes the result to the next
// GrepFilter.
// Pipe sequentially invokes each Filter, and passes the result to the next
// Filter.
//
// Analogous to http://www.linfo.org/pipes.html
//
// * rn is provided as input to the first GrepFilter.
// * if any GrepFilter returns an error, immediately return the error
// * if any GrepFilter returns a nil RNode, immediately return nil, nil
// * rn is provided as input to the first Filter.
// * if any Filter returns an error, immediately return the error
// * if any Filter returns a nil RNode, immediately return nil, nil
// * if all Filters succeed with non-empty results, return the final result
func (rn *RNode) Pipe(functions ...Filter) (*RNode, error) {
// check if rn is nil to make chaining Pipe calls easier

View File

@@ -3,11 +3,9 @@ module sigs.k8s.io/kustomize/plugin/builtin/annotationstransformer
go 1.14
require (
sigs.k8s.io/kustomize/api v0.5.1
sigs.k8s.io/kustomize/kyaml v0.7.1
sigs.k8s.io/kustomize/api v0.6.0
sigs.k8s.io/kustomize/kyaml v0.8.0
sigs.k8s.io/yaml v1.2.0
)
replace sigs.k8s.io/kustomize/api v0.5.1 => ../../../api
replace sigs.k8s.io/kustomize/kyaml v0.7.1 => ../../../kyaml
replace sigs.k8s.io/kustomize/api v0.6.0 => ../../../api

View File

@@ -470,6 +470,7 @@ golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDq
golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@@ -524,6 +525,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/kyaml v0.8.0 h1:/MqPML99XAm2pbrD/eTpePh5rnU5bpnuTPqb29LpSz4=
sigs.k8s.io/kustomize/kyaml v0.8.0/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw=
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=

View File

@@ -3,8 +3,8 @@ module sigs.k8s.io/kustomize/plugin/builtin/configmapgenerator
go 1.14
require (
sigs.k8s.io/kustomize/api v0.5.1
sigs.k8s.io/kustomize/api v0.6.0
sigs.k8s.io/yaml v1.2.0
)
replace sigs.k8s.io/kustomize/api v0.5.1 => ../../../api
replace sigs.k8s.io/kustomize/api v0.6.0 => ../../../api

Some files were not shown because too many files have changed in this diff Show More