Compare commits

...

445 Commits

Author SHA1 Message Date
Jeff Regan
9d992aae68 Merge pull request #3015 from monopole/pinToCmdConfigV0.8.1
Pin to cmd/config/v0.8.1
2020-09-19 07:42:05 -07:00
Jeffrey Regan
8c906b804f Pin to cmd/config/v0.8.1 2020-09-19 07:12:13 -07:00
Jeff Regan
4ff4940fa7 Update README.md 2020-09-18 18:28:42 -07:00
Jeff Regan
09aec5694a Merge pull request #3013 from monopole/generated
Generated pin to cli-utils v0.20.2 hash
2020-09-18 18:26:25 -07:00
Jeffrey Regan
1f917c0499 Generated pin to cli-utils v0.20.2 hash 2020-09-18 17:52:33 -07:00
Kubernetes Prow Robot
225ffc7cd8 Merge pull request #3012 from Shell32-Natsu/remove-network-name
remove --network-name flag from kpt fn run
2020-09-18 16:48:27 -07:00
Kubernetes Prow Robot
eb638cc312 Merge pull request #3009 from Shell32-Natsu/endpoint-service
put endpoints before service
2020-09-18 14:20:28 -07:00
Jeff Regan
7dfb96425e Merge pull request #3010 from monopole/pinToCliUtils_v0.20.2
Pin to cli-utils/v0.20.2
2020-09-18 13:35:02 -07:00
Jeff Regan
6d4c6127c8 Update README.md 2020-09-18 13:18:54 -07:00
Jeff Regan
6aa72b66ef Update README.md 2020-09-18 13:15:52 -07:00
Jeff Regan
f03fdc09cb Update README.md 2020-09-18 13:10:19 -07:00
Jeffrey Regan
30b6eeb460 Pin to cli-utils/v0.20.2 2020-09-18 13:08:53 -07:00
Jeff Regan
bf67fcb6d6 Update README.md 2020-09-18 12:55:59 -07:00
Jeff Regan
4ae420cce1 Merge pull request #3008 from monopole/pinToKyamlv_0_8_1
Pin to kyaml v0.8.1
2020-09-18 12:40:02 -07:00
Donny Xia
87d2187436 remove --network-name flag from kpt fn run 2020-09-18 12:39:49 -07:00
Donny Xia
f1dabbd4fc put endpoints before service 2020-09-18 12:21:03 -07:00
Jeffrey Regan
747e05f2a4 Pin to kyaml v0.8.1 2020-09-18 12:11:03 -07:00
Jeff Regan
3514317b3d Merge pull request #3007 from monopole/unpin
Unpin the dependencies post release.
2020-09-18 11:19:42 -07:00
Jeff Regan
9299821571 Merge pull request #2998 from Shell32-Natsu/network
Change network to a boolean in kpt fn run
2020-09-18 11:12:26 -07:00
Jeffrey Regan
d91f313137 Unpin the dependencies post release. 2020-09-18 09:51:05 -07:00
Jeff Regan
161af9d99c Merge pull request #3002 from monopole/pinToApiV0_6_1
Pin to api/v0.6.1
2020-09-17 17:18:11 -07:00
jregan
b115c95ea1 Pin to api/v0.6.1 2020-09-17 16:27:08 -07:00
Jeff Regan
20cd4bfef9 Merge pull request #2997 from kubernetes-sigs/removeReplaceDir
Update go.mod
2020-09-17 11:02:08 -07:00
Donny Xia
f6c06b58ef Change network to a boolean 2020-09-16 16:20:50 -07:00
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
Jeff Regan
ff55856c63 Merge pull request #2913 from monopole/pinApiToKyamlV_0_7_1
Pin api to kyaml/v0.7.1
2020-08-28 19:23:36 -07:00
jregan
ceef219eec Pin api to kyaml/v0.7.1 2020-08-28 18:54:41 -07:00
Jeff Regan
b21699a277 Merge pull request #2912 from monopole/pinCmdConfigToKyamlv0_7_1
Pin to cmd/config to kyaml/v0.7.1 and cli-utils/v0.19.2
2020-08-28 18:47:00 -07:00
jregan
2ab85d2f63 Pin to cmd/config to kyaml/v0.7.1 and cli-utils/v0.19.2 2020-08-28 18:25:14 -07:00
Kubernetes Prow Robot
320545884c Merge pull request #2898 from mortent/AddKrmignoreFile
Add support for .krmignore file
2020-08-28 18:17:19 -07:00
Morten Torkildsen
16bbc2d67e Add support for .krmignore file 2020-08-28 17:28:02 -07:00
Jeff Regan
6d860e8ace Merge pull request #2910 from monopole/updateReleaseInstructions
Add recommended sequence to release instructions.
2020-08-28 11:45:58 -07:00
Jeffrey Regan
80c8a6df61 Add recommended sequence to release instructions. 2020-08-28 11:43:34 -07:00
Jeff Regan
90bc96d9d8 Merge pull request #2892 from SyamSundarKirubakaran/Docs-Patch
Docs Update - patches
2020-08-28 11:32:33 -07:00
Jeff Regan
2be59aefec Merge pull request #2909 from Shell32-Natsu/remove-flags
remove --fn-user and --fn-env flags
2020-08-28 11:22:17 -07:00
Donny Xia
91b779269f remove --fn-user and --fn-env flags 2020-08-28 10:42:30 -07:00
Jeff Regan
e6ea4ad260 Merge pull request #2902 from monopole/fixcomments
Fix some generated comments.
2020-08-27 14:49:58 -07:00
jregan
f5cab0f6e1 Fix some generated comments. 2020-08-27 14:49:23 -07:00
Jeff Regan
e39afc9f68 Merge pull request #2900 from Shell32-Natsu/add-fn-env
add --fn-env flag to fn run
2020-08-27 14:38:51 -07:00
Donny Xia
3801a29d9b add --fn-env flag to fn run 2020-08-27 13:46:36 -07:00
Kubernetes Prow Robot
39cf4af638 Merge pull request #2891 from phanimarupaka/ListSettersWithSubPackages
List setters in subpackages
2020-08-27 13:43:24 -07:00
Phani Teja Marupaka
9d65dd0786 List setters in subpackages 2020-08-27 12:32:22 -07:00
Jeff Regan
3dced70850 Merge pull request #2888 from Shell32-Natsu/envs
explicitly specify envs to be exported in function
2020-08-26 15:47:43 -07:00
Jeff Regan
4356043582 Merge pull request #2847 from Shell32-Natsu/prefix-suffix-name-reference
fix name reference with prefixsuffix
2020-08-26 13:13:59 -07:00
Donny Xia
c202be0338 Remove redundant env field 2020-08-26 12:49:42 -07:00
Jeff Regan
9359155418 Update nameref.go 2020-08-26 12:00:37 -07:00
Jeff Regan
ba22bbe19e Merge pull request #2890 from Shell32-Natsu/fn-user
add --fn-user flag to function run
2020-08-26 10:44:49 -07:00
Syam Sundar K
3e5989ae18 docs/ build 2020-08-26 18:11:27 +05:30
Syam Sundar K
fbebd990a4 Docs update - Patch Examples 2020-08-26 17:46:29 +05:30
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
Donny Xia
646e0b4f61 add --fn-user flag to function run 2020-08-25 15:29:59 -07:00
Donny Xia
0f67692265 Add more tests 2020-08-25 14:51:01 -07:00
Donny Xia
6a7afd8694 fix name reference with prefixsuffix 2020-08-25 12:25:37 -07:00
Donny Xia
46194b3385 code review 2020-08-25 12:15:37 -07:00
Donny Xia
904a9dea08 explicitly specify envs to be exported in function 2020-08-25 12:14:46 -07:00
Jeff Regan
30b58e90a3 Merge pull request #2887 from Shell32-Natsu/network-name
refactor network name in kyaml container
2020-08-25 11:47:13 -07:00
Jeff Regan
5bdd8657a5 Merge pull request #2889 from etefera/release-note-generator
Add logging for module release notes.
2020-08-24 16:58:42 -07:00
Donny Xia
893c99da1c code review 2020-08-24 16:27:55 -07:00
Eyob Tefera
43980f8586 Remove changelog directive in yaml. 2020-08-24 21:39:51 +00:00
Eyob Tefera
0c8e033c96 Add logging for module release notes. 2020-08-24 21:21:30 +00:00
Donny Xia
fa15242719 refactor network name in kyaml container 2020-08-24 11:40:57 -07:00
Kubernetes Prow Robot
a2e080bf6c Merge pull request #2886 from monopole/deprecateOrDrown
Add types and proposal for k8s to kyaml migration.
2020-08-24 10:42:17 -07:00
jregan
e91cdb5eba Checkpoint 2020-08-23 19:46:08 -07:00
Jeff Regan
ef54f9be5a Merge pull request #2885 from monopole/cleanupOpts
Clean up option construction.
2020-08-23 12:20:52 -07:00
jregan
f051acb83c Clean up option construction. 2020-08-23 12:06:48 -07:00
Jeff Regan
bbb046081b Merge pull request #2884 from monopole/splitPreservingLineHistory
Split out rewrangler preserving line history
2020-08-23 09:18:23 -07:00
jregan
77b28a986f Split reswrangler.go and test from resmap.go 2020-08-23 08:23:13 -07:00
jregan
97bc34eb37 Delete non-api/resmap/reswrangler stuff from api/resmap/reswrangler. 2020-08-23 08:18:23 -07:00
jregan
719380f523 Copy api/resmap/resmap to api/resmap/reswrangler. 2020-08-23 08:18:23 -07:00
Jeff Regan
640ae9521b Merge pull request #2882 from monopole/unpin
Unpin transformers from kyaml.
2020-08-22 18:57:46 -07:00
jregan
1dffc7577b Unpin transformers from kyaml. 2020-08-22 18:38:48 -07:00
Jeff Regan
a0b7288329 Merge pull request #2883 from monopole/tweakCloudBuild
Tweak cloudbuild.sh release note handling
2020-08-22 18:11:26 -07:00
Jeffrey Regan
cc5617c048 Tweak cloudbuild.sh release note handling 2020-08-22 18:07:36 -07:00
Jeff Regan
a77d7e5164 Merge pull request #2875 from etefera/bundled-release-notes
Generate release notes per module.
2020-08-22 17:45:41 -07:00
Jeff Regan
40dc90b3b1 Update cloudbuild.sh 2020-08-22 17:45:16 -07:00
Jeff Regan
16229095b3 Merge pull request #2880 from monopole/merginator
Simplify use of the Merginator.
2020-08-22 08:36:22 -07:00
jregan
1d91401772 Simplify use of the Merginator. 2020-08-22 08:07:57 -07:00
Jeff Regan
007a5327d7 Merge pull request #2877 from monopole/rnodeCopy
RNode copier
2020-08-21 18:33:17 -07:00
jregan
24beeb429d RNode copier 2020-08-21 18:04:58 -07:00
Jeff Regan
9b4d4c9d46 Merge pull request #2876 from monopole/parseGv
Gvk.ParseGroupVersion function.
2020-08-21 16:16:02 -07:00
jregan
d5f868c5c7 Gvk.ParseGroupVersion function. 2020-08-21 15:40:37 -07:00
Jeff Regan
ff3f39d84b Merge pull request #2871 from Shell32-Natsu/container-user
Update kyaml to specify user for function
2020-08-21 14:19:55 -07:00
Donny Xia
451c5c32c9 code review 2020-08-21 12:05:11 -07:00
Eyob Tefera
faef5714bf Feed generated changelog as input to goreleaser. 2020-08-21 18:11:47 +00:00
Jeff Regan
7833c6edcf Merge pull request #2873 from mortent/BumpCliUtilsVersion
Bump cli-utils version to 0.19.0
2020-08-21 08:14:26 -07:00
Morten Torkildsen
a1cd23c91d Bump cli-utils version to v0.19.0 2020-08-20 20:35:46 -07:00
Jeff Regan
e39a5adc00 Merge pull request #2864 from Shell32-Natsu/fn-source-empty-dir
add option to continue pipeline when the input is empty
2020-08-20 18:09:11 -07:00
Donny Xia
b6900ead22 update TODO with issue number 2020-08-20 17:01:03 -07:00
Donny Xia
d03cf061e8 Update kyaml to specify user for function 2020-08-20 15:24:59 -07:00
Jeff Regan
8293f3002d Merge pull request #2870 from monopole/deleteNewlyUnused
Delete newly orphaned code.
2020-08-20 14:55:01 -07:00
jregan
edced4b3f6 Delete newly orphaned code. 2020-08-20 13:12:06 -07:00
Donny Xia
501684a9c6 remove break after input in pipeline 2020-08-20 11:54:56 -07:00
Jeff Regan
4e42e1a058 Merge pull request #2866 from yankeexe/patch-1
Update dead URL to base in glossary.
2020-08-20 09:33:02 -07:00
Yankee
b450b624e8 Update dead URL to base in glossary.
The term `central concept` referring to `base` was a dead link. Updated the link to go to proper definition of base.
2020-08-20 08:18:47 +05:45
Jeff Regan
0be4a61f64 Merge pull request #2794 from etefera/replace-patches-name
Replace patchesJson6902 field with patches.
2020-08-19 14:02:59 -07:00
Kubernetes Prow Robot
596c39b7bc Merge pull request #2855 from phanimarupaka/DeleteSubst
Delete substitution and fix delete setters
2020-08-19 12:27:23 -07:00
Donny Xia
037ac3b134 add option to continue pipeline when the input is empty 2020-08-19 11:21:35 -07:00
Jeff Regan
0ff4e53046 Update comment in types.go 2020-08-19 10:36:28 -07:00
Kubernetes Prow Robot
660f7f9435 Merge pull request #2859 from monopole/namespaceable
Add TypeMeta.IsNamespaceable
2020-08-19 09:31:14 -07:00
jregan
e6ee03e3e3 Add TypeMeta.IsNamespaceable 2020-08-19 06:50:12 -07:00
Phani Teja Marupaka
ca04c874f2 Delete substitution and fix delete setters 2020-08-18 22:24:50 -07:00
Kubernetes Prow Robot
cbfef858a0 Merge pull request #2854 from monopole/inlineTypeMeta
Inline repeated types.
2020-08-18 10:39:11 -07:00
Kubernetes Prow Robot
62fbfdfa21 Merge pull request #2826 from ZhuGongpu/master
Add an option to log which function is running
2020-08-17 13:25:31 -07:00
Kubernetes Prow Robot
5d72fbc6c9 Merge pull request #2848 from phanimarupaka/UpdateArraySetterComments
Update setter comments correctly on updates
2020-08-17 10:29:31 -07:00
Kubernetes Prow Robot
bc37ec9d88 Merge pull request #2853 from phanimarupaka/WarnIfNoSubstMatch
Print message if subst doesn't match any field value
2020-08-17 10:00:19 -07:00
jregan
8619c9aa13 Inline TypeMeta. 2020-08-16 17:20:30 -07:00
Phani Teja Marupaka
5d8722a786 Print message if subst doesn't match any field value 2020-08-16 15:54:34 -07:00
Jeff Regan
0d5552fca6 Merge pull request #2852 from monopole/splitPreservingLineHistory
Make mapnode.go, preserving line history.
2020-08-16 14:33:33 -07:00
jregan
8a8e35f3bb Split mapnode.go and test from types.go 2020-08-16 13:25:19 -07:00
jregan
25dbe1eaa8 Delete non-kyaml/yaml/mapnode stuff from kyaml/yaml/mapnode. 2020-08-16 13:25:19 -07:00
jregan
2289e7d2e9 Copy kyaml/yaml/types to kyaml/yaml/mapnode. 2020-08-16 13:25:19 -07:00
Jeff Regan
eb0f484e3d Merge pull request #2851 from monopole/blamePreservingSplit
Split rnode.go from types.go, preserving line history
2020-08-16 08:03:06 -07:00
jregan
d438271263 Split rnode.go and test from types.go 2020-08-16 07:36:15 -07:00
jregan
c4c8decb74 Delete non-rnode stuff from rnode.go. 2020-08-16 07:35:11 -07:00
jregan
0590b225c7 Copy types.go to rnode.go. 2020-08-16 07:35:11 -07:00
Jeff Regan
45131a6d62 Merge pull request #2850 from monopole/autoMod
Automated go.sum/format updates.
2020-08-15 19:31:40 -07:00
jregan
4dfe3c6296 Automated go.sum updates. 2020-08-15 19:18:08 -07:00
Jeff Regan
881f358228 Merge pull request #2835 from james-callahan/transformer-APIService-support
Transform namespace inside of APIService
2020-08-15 18:03:25 -07:00
Jeff Regan
86c93b9fb7 Merge pull request #2829 from msk-/master
Bug: name prefix or suffix in base results in incorrect references
2020-08-15 18:02:59 -07:00
Phani Teja Marupaka
25e30de2d6 Update setter comments correctly on updates 2020-08-15 03:46:33 -07:00
Jeff Regan
a8160356bd Merge pull request #2839 from mortent/SetterNestedPath
Add test for adding setter with path inside a sequence
2020-08-14 09:48:25 -07:00
Jeff Regan
32de6de313 Merge pull request #2840 from mortent/ImproveFieldPathDescription
Improve the description of the --field flag for create-setter
2020-08-14 09:47:42 -07:00
Jeff Regan
501ec38777 Merge pull request #2831 from Shell32-Natsu/line-break-test
Add test for long quoted string with blanks
2020-08-13 17:25:18 -07:00
Morten Torkildsen
1b2a966c62 Improve the description of the --field flag for create-setter 2020-08-12 20:21:12 -07:00
Morten Torkildsen
bcdbb1a282 Add test for adding setter with path inside a sequence 2020-08-12 20:04:39 -07:00
Jeff Regan
01f28e6779 Merge pull request #2838 from phanimarupaka/UnpinCmdConfigv0.6.0
Unpin kyaml v0.6.0 from cmd/comnfig
2020-08-12 15:43:33 -07:00
Phani Teja Marupaka
3f8e3686e2 Unpin kyaml v0.6.0 from cmd/comnfig 2020-08-12 14:45:27 -07:00
Kubernetes Prow Robot
b47e34ea5e Merge pull request #2836 from phanimarupaka/BumpKyamlAndCliUtils
Bump kyaml and cli-utils in cmd/config
2020-08-12 13:05:15 -07:00
Phani Teja Marupaka
762e587471 Bump kyaml and cli-utils in cmd/config 2020-08-12 12:49:31 -07:00
Donny Xia
6f782ac8c3 fix linter issue 2020-08-12 12:25:49 -07:00
Donny Xia
e5bc644653 change the test for blanks in string 2020-08-12 12:17:56 -07:00
Eyob Tefera
1bc9225302 Move patches fix to before Write step. 2020-08-12 18:14:03 +00:00
msk-
99d7ad6dc9 Made test pass- whoops 2020-08-12 11:53:47 +01:00
msk-
345dbc83e3 Implemented PR feedback 2020-08-12 11:49:24 +01:00
James Callahan
8ddf2297e8 Transform namespace inside of APIService 2020-08-12 17:19:25 +10:00
Gongpu Zhu
b407675fc0 Enable logging in runfn 2020-08-11 18:02:22 -07:00
Jeff Regan
fd5eeb1645 Merge pull request #2832 from Shell32-Natsu/fix-cmdxargs
Fix IsFieldEmpty in cmdxargs
2020-08-11 16:39:46 -07:00
Donny Xia
ff5051711f fix test failure 2020-08-11 16:21:50 -07:00
Donny Xia
51268a5f06 Fix IsFieldEmpty in cmdxargs 2020-08-11 16:11:23 -07:00
Donny Xia
1366e0344a Add test for long line break 2020-08-11 13:43:18 -07:00
Jeff Regan
9be38e815e Merge pull request #2830 from kubernetes-sigs/drop-link-from-readme
Drop link to github release page from main readme
2020-08-11 12:59:26 -07:00
Jeff Regan
88c318bf46 Drop link to github release page from main readme
Fix #2823
2020-08-11 12:52:59 -07:00
msk-
b71b36a213 Added test for name suffix in base not generating expected reference name 2020-08-11 10:02:25 +01:00
Gongpu Zhu
e5a78710aa Add callback to kio pipeline execution 2020-08-10 17:14:56 -07:00
Jeff Regan
7ee75c33a9 Merge pull request #2824 from monopole/deleteIsFieldEmpty
Remove unused IsFieldEmpty function, add more godoc.
2020-08-10 12:54:41 -07:00
jregan
2b328eeb36 Remove unused IsFieldEmpty, add more godoc. 2020-08-10 12:37:13 -07:00
Eyob Tefera
4da40461d3 Merge branch 'master' into replace-patches-name 2020-08-10 18:31:33 +00:00
Eyob Tefera
c96a4f3d73 Merge branch 'master' of https://github.com/kubernetes-sigs/kustomize 2020-08-10 18:26:16 +00:00
Eyob Tefera
45893b2588 Iteratively convert PatchesJson6902 to Patches. 2020-08-10 17:57:39 +00:00
Eyob Tefera
2f3c89e73f Add diffing to tests. 2020-08-10 17:57:03 +00:00
Eyob Tefera
eee581462c Undo wholesale replacement of PatchesJson6902. 2020-08-10 17:53:30 +00:00
Jeff Regan
616363ee73 Merge pull request #2822 from monopole/punchDrunk
IsFieldEmpty renamed to MapNode.IsNilOrEmpty
2020-08-10 10:46:39 -07:00
jregan
0e13eadd7a IsFieldEmpty renamed to MapNode.IsNilOrEmpty 2020-08-10 10:24:02 -07:00
Jeff Regan
0c37388135 Merge pull request #2821 from monopole/moveIsNilToMethod
Testing for nilness, nullness and emptyness.
2020-08-10 10:23:16 -07:00
Jeff Regan
5d1352882b Merge pull request #2815 from fknipp/patch-1
Add full github link to varreference.go
2020-08-09 17:30:23 -07:00
jregan
c469e80cad Add RNode.IsNilOrEmpty and test. 2020-08-09 12:37:12 -07:00
jregan
5559601ecb Add tests for IsTaggedNull, IsYNodeEmptySeq and IsYNodeEmptyMap. 2020-08-09 12:29:35 -07:00
jregan
01b34c8ea0 Add tests for IsNil 2020-08-09 11:55:28 -07:00
Jeff Regan
eba0ffdde2 Merge pull request #2820 from monopole/dropIsEmptyCalls
Replace all calls to yaml.IsEmpty with IsMissingOrNull
2020-08-09 11:09:57 -07:00
jregan
31c59bd7f2 Drop all calls to IsEmpty. 2020-08-09 10:47:06 -07:00
Eyob Tefera
bd7d0f864b Revert "Remove unused utility function StringInSplice."
This reverts commit 43b0f2d925.
2020-08-09 07:30:40 +00:00
Jeff Regan
2da8959198 Merge pull request #2818 from monopole/hoserFace
Use yaml.IsYNodeString
2020-08-07 18:21:23 -07:00
Jeff Regan
dc591f0a10 Merge pull request #2817 from monopole/pinToCmdConfigv_0_5_0
Switch to cmd/config v0.5.0
2020-08-07 15:57:19 -07:00
jregan
c94f164e66 Use new 2020-08-07 15:57:00 -07:00
jregan
fb216d8af8 Switch to cmd/config v0.5.0 2020-08-07 15:31:54 -07:00
Jeff Regan
72207bfa04 Merge pull request #2816 from monopole/moveToKyamlv0_5_0
Move to kyaml v0.5.0
2020-08-07 15:13:41 -07:00
jregan
fe3321d710 Move to kyaml v0.5.0 2020-08-07 14:45:56 -07:00
Jeff Regan
35b5890e46 Merge pull request #2814 from monopole/moofloaves
Fix more constants.
2020-08-07 13:35:13 -07:00
Franz Knipp
ca807019f0 Add full github link to varreference.go
Otherwise, the link is broken on github.io: https://kubernetes-sigs.github.io/kustomize/api-reference/kustomization/vars/
2020-08-07 22:23:18 +02:00
jregan
6420fc4911 Fix more constants. 2020-08-07 13:21:35 -07:00
Jeff Regan
bd8262630e Merge pull request #2813 from monopole/apiCleanup
Kyaml api cleanup
2020-08-07 13:15:56 -07:00
jregan
cf5b26db8a Kyaml api cleanup 2020-08-07 12:44:31 -07:00
Jeff Regan
4b4049e646 Merge pull request #2812 from monopole/baseApiCleanup
Remove old constants from kyaml
2020-08-07 12:36:08 -07:00
Jeff Regan
f211841035 Merge pull request #2811 from monopole/moveToNewConstants
Move to new constants.
2020-08-07 12:32:41 -07:00
Jeff Regan
efa4587f92 Merge pull request #2811 from monopole/moveToNewConstants
Move to new constants.
2020-08-07 12:21:02 -07:00
jregan
873c8c1d17 Move to new constants. 2020-08-07 12:18:24 -07:00
Jeff Regan
686e97f2fe Merge pull request #2810 from Shell32-Natsu/fieldspec-empty
fix panic when fieldspec refers an empty value
2020-08-07 11:50:14 -07:00
Donny Xia
669ae59982 code review 2020-08-07 11:12:40 -07:00
Donny Xia
868a226e4e fix typo 2020-08-07 11:11:08 -07:00
Donny Xia
a2693d0249 fix panic when fieldspec refers an empty value 2020-08-07 10:47:25 -07:00
Jeff Regan
b7d913b58c Merge pull request #2805 from Shell32-Natsu/keep-empty-map
Keep empty map in kustomize output
2020-08-07 10:40:34 -07:00
Jeff Regan
f199b747e9 Merge pull request #2807 from wingyplus/fix-typo
Fix typo in build sub-command example
2020-08-07 10:35:03 -07:00
Kubernetes Prow Robot
5a9fbf7da3 Merge pull request #2804 from phanimarupaka/SubstWithSameName
Error on creation if setter/subst exists
2020-08-07 09:47:56 -07:00
Thanabodee Charoenpiriyakij
c18c803d3f Fix typo in build sub-command example 2020-08-07 14:16:35 +07:00
Donny Xia
d59d0401f4 Keep empty map in kustomize output 2020-08-06 13:21:38 -07:00
Phani Teja Marupaka
83a70f7830 Error on creation if setter/subst exists 2020-08-06 11:02:20 -07:00
Jeff Regan
6afabf26ae Merge pull request #2802 from monopole/goHash
Auto module hash update.
2020-08-05 17:14:12 -07:00
jregan
2bcece5f1e Auto module hash update. 2020-08-05 16:54:49 -07:00
Jeff Regan
e605391895 Merge pull request #2800 from Shell32-Natsu/ignore-tempdir-env
Ignore TMPDIR when run container
2020-08-05 16:41:22 -07:00
Jeff Regan
9de2c6b58e Merge pull request #2787 from Shell32-Natsu/hasher
Refactor hasher with kyaml
2020-08-05 16:25:06 -07:00
Eyob Tefera
b3f147d012 Add group and verison to fix test. 2020-08-05 22:03:12 +00:00
Donny Xia
fc70e3181f code review 2020-08-05 13:31:05 -07:00
Donny Xia
8cd7c13fad fix linter issue 2020-08-05 12:04:46 -07:00
Donny Xia
740ec39dd8 Temporarily disable hash result check in configGeneration.md to pass test 2020-08-05 11:59:13 -07:00
Donny Xia
e6927a2fdf Add test for legacy hasher 2020-08-05 11:59:13 -07:00
Donny Xia
083dccfe91 Update hash result in tests 2020-08-05 11:59:13 -07:00
Donny Xia
b61553e584 refactor hasher 2020-08-05 11:59:12 -07:00
Donny Xia
8cdc97a0dd code review 2020-08-05 11:56:19 -07:00
Jeff Regan
f205641498 Merge pull request #2780 from Shell32-Natsu/namereferencetransformer
Refactor namereferencetransformer with kyaml
2020-08-05 10:38:47 -07:00
Jeff Regan
bfaca2122a Merge pull request #2801 from monopole/updateGoMods
Update module hashes
2020-08-05 09:22:18 -07:00
jregan
9482c571f0 Update module hashes 2020-08-05 09:00:12 -07:00
Jeff Regan
1ad49de087 Merge pull request #2796 from betterclever/patch-1
Order PersistentVolume before Deployment
2020-08-05 08:55:08 -07:00
Jeff Regan
5e89565930 Merge pull request #2792 from mortent/FixSetterWalk
Fix issue where the schema was not propagated correctly when walking yaml doc
2020-08-05 08:38:51 -07:00
Jeff Regan
ef713e33ce Merge pull request #2777 from hornpolish/tftest
adds test for issue#2767
2020-08-04 19:11:50 -07:00
Donny Xia
2f7241f4c3 code review 2020-08-04 17:11:18 -07:00
Paul Kent
34e0ade3e7 respond to PR feedback 2020-08-04 17:25:38 -04:00
Kubernetes Prow Robot
436c688bd0 Merge pull request #2797 from phanimarupaka/SuffixSubstInFix
Infix/Suffix subst creation for fix
2020-08-04 14:11:40 -07:00
Kubernetes Prow Robot
9d8fbd9f04 Merge pull request #2795 from phanimarupaka/CommentOnUpdate
Update setter comments during 3-way merge
2020-08-04 14:11:32 -07:00
Kubernetes Prow Robot
bb6fb703a0 Merge pull request #2799 from phanimarupaka/ErrorForSettersInsufficientArgs
Throw insufficient arguments error for create-setter
2020-08-04 13:24:22 -07:00
Donny Xia
c99bc47c8d fix test on macos 2020-08-04 11:01:06 -07:00
Donny Xia
60422c8090 Ignore TMPDIR when run container 2020-08-04 10:48:59 -07:00
Phani Teja Marupaka
fc83477ec8 Throw insufficient arguments error for create-setter 2020-08-04 00:41:52 -07:00
Jeff Regan
c9e8631399 Merge pull request #2776 from hornpolish/psmtest
add test for issues raised in #2734
2020-08-03 15:35:07 -07:00
Phani Teja Marupaka
974e3847dd Infix/Suffix subst creation for fix 2020-08-03 14:46:29 -07:00
Pranjal Paliwal
8f4e7e8072 Order PersistentVolume before Deployment
Solves issue https://github.com/kubernetes-sigs/kustomize/issues/202

Ordering is not being maintained for "PersistentVolume" and "PersistentVolumeClaim" which leads to the creation of "Deployment" before persistent volume leading to container crashes.
2020-08-04 01:09:35 +05:30
Phani Teja Marupaka
4e74947731 Update setter comments during 3-way merge 2020-08-03 11:55:34 -07:00
Eyob Tefera
43b0f2d925 Remove unused utility function StringInSplice. 2020-08-01 18:45:44 +00:00
Eyob Tefera
efd5f414a8 Remove unused field from field order list. 2020-08-01 18:44:30 +00:00
Eyob Tefera
9b8232533f Add test. 2020-08-01 08:55:18 +00:00
Eyob Tefera
bc5859d44b Replace patchesJson6902 field with patches. 2020-08-01 08:55:00 +00:00
Morten Torkildsen
5c433ead5e Use k8s schema to determine formatting if no type on setter 2020-07-31 13:44:47 -07:00
Morten Torkildsen
feeaa994b7 Fix issue where the schema was not propagated correctly when walking yaml doc 2020-07-31 10:56:00 -07:00
Kubernetes Prow Robot
17f935452f Merge pull request #2778 from phanimarupaka/FixSetters
Fix command: Migrate v1 Setters to latest
2020-07-30 13:09:07 -07:00
Phani Teja Marupaka
6faff2d031 Fix V1 Setters and migrate to latest 2020-07-30 12:51:57 -07:00
Kubernetes Prow Robot
18a86bd7d6 Merge pull request #2784 from mortent/HandleIncorrectTypes
Handle some incorrect type values like 'int' and 'bool' in setters
2020-07-30 12:19:06 -07:00
Kubernetes Prow Robot
7eac250cf4 Merge pull request #2783 from mortent/ValidateSchema
Validate provided schema when creating setter
2020-07-29 15:16:03 -07:00
Morten Torkildsen
52083c6e49 Validate schema when creating setter 2020-07-29 13:54:47 -07:00
Morten Torkildsen
6f63cf7238 SetterCreator accepts schema as a string rather than file path and validates schema 2020-07-28 22:53:21 -07:00
Morten Torkildsen
de0c8dedc4 Handle some incorrect type values like 'int' and 'bool' in setters 2020-07-28 13:49:07 -07:00
Paul Kent
c23004df79 Merge branch 'psmtest' of github.com:hornpolish/kustomize into psmtest 2020-07-28 13:38:16 -04:00
Paul Kent
1a44c3c543 add test for issues raised in #2734 2020-07-28 13:22:05 -04:00
Donny Xia
a9d1182322 Add test for name ref 2020-07-27 12:45:45 -07:00
Donny Xia
a3d5628133 Add methods for namref filter test 2020-07-27 12:17:27 -07:00
Donny Xia
a563169461 refactor namereftransformer with kyaml 2020-07-27 10:56:13 -07:00
Paul Kent
729544b9f4 adds test for issue 2767 2020-07-25 15:37:07 -04:00
Paul Kent
69d497ccdd add test for issue #2767 2020-07-25 13:17:23 -04:00
Paul Kent
c58c142849 add test for issues raised in #2734 2020-07-25 12:44:49 -04:00
Jeff Regan
9ba04e3f7d Merge pull request #2769 from kzwang/add-component
add kustomize edit add component command
2020-07-24 19:35:47 -07:00
Kevin Wang
3f842e5e92 add kustomize edit add component command 2020-07-24 18:17:20 -07:00
Jeff Regan
9fdb3e1e9e Merge pull request #2768 from kzwang/remote-resource
Support remote resources for kustomize edit add
2020-07-24 17:58:55 -07:00
Jeff Regan
462dbcb999 Merge pull request #2771 from Shell32-Natsu/slash-in-path
support slash in path in fieldspec
2020-07-24 17:58:35 -07:00
Jeff Regan
3e0448f1b7 Merge pull request #2759 from Shell32-Natsu/refvartransformer
Refactor refvartransformer with kyaml
2020-07-24 17:01:48 -07:00
Jeff Regan
3c3f9a26f6 Merge pull request #2772 from mortent/AddBackReplaceCmdConfig
Add back replace directive for kyaml in cmd/config
2020-07-24 16:58:00 -07:00
Jeff Regan
7d7c889285 Update README.md 2020-07-24 16:04:29 -07:00
Morten Torkildsen
4fe2f9dd5b Add back replace directive for kyaml in cmd/config 2020-07-24 15:38:29 -07:00
Donny Xia
0cb852b98a support slash in path 2020-07-24 15:22:36 -07:00
Kubernetes Prow Robot
7f5ce3e6f0 Merge pull request #2770 from mortent/BumpDepsForCmdConfig
Bump cli-utils version in cmd/config for relase
2020-07-24 13:54:17 -07:00
Donny Xia
bf5656b02b remove kyaml replace in kustomize 2020-07-24 13:34:15 -07:00
Morten Torkildsen
0ec901a9a9 Bump cli-utils version in cmd/config for relase 2020-07-24 13:30:45 -07:00
Donny Xia
af057a95c5 Refactor refvartransformer with kyaml 2020-07-24 13:23:35 -07:00
Jeff Regan
c48e584d1a Merge pull request #2766 from monopole/swicthToKyamlV0_4_2
Switch to kyaml v0.4.2
2020-07-24 12:48:46 -07:00
Kevin Wang
2ee4eec791 Support remote resources for kustomize edit add 2020-07-24 12:26:58 -07:00
jregan
f06a64e9cc Switch to kyaml v0.4.2 2020-07-24 11:59:01 -07:00
Jeff Regan
51f9a84358 Update cloudbuild.sh 2020-07-24 11:54:39 -07:00
Jeff Regan
07c25eb458 Update cloudbuild.sh 2020-07-24 11:46:53 -07:00
Jeff Regan
ba57cdbd99 Merge pull request #2765 from monopole/updateCloudbuild
Try goreleaser's skip to deal with no-binary releases
2020-07-24 11:35:50 -07:00
jregan
8a9dc011f4 Try goreleaser skip to deal with no-binary releases 2020-07-24 11:34:57 -07:00
Jeff Regan
fd196f5d70 Merge pull request #2762 from kzwang/components-field
Retain components field in edit
2020-07-24 11:31:19 -07:00
Jeff Regan
4c577f6667 Merge pull request #2764 from Shell32-Natsu/seqtag
Add seq tag in kyaml
2020-07-24 11:30:59 -07:00
Donny Xia
65fd7c3e6e Add seq tag in kyaml 2020-07-24 11:17:31 -07:00
Jeff Regan
1dff481883 Merge pull request #2763 from monopole/updateReleaseInstructions
Update release instructions.
2020-07-24 10:28:55 -07:00
jregan
d437f67035 Update release instructions. 2020-07-24 10:27:31 -07:00
Kevin Wang
ee57e9db12 Retain components field in edit 2020-07-23 21:39:55 -07:00
Jeff Regan
a0fdcfe2e3 Merge pull request #2757 from phanimarupaka/revert-2738-ListSettersRecursively
Revert "List and set setters in folders recursively"
2020-07-22 14:56:26 -07:00
phani
d9fe98a289 Revert "List and set setters in folders recursively" 2020-07-22 13:51:42 -07:00
Jeff Regan
8b9829f222 Merge pull request #2738 from phanimarupaka/ListSettersRecursively
List and set setters in folders recursively
2020-07-22 13:14:13 -07:00
Jeff Regan
2114b97969 Merge pull request #2737 from tinselspoon/hash-arbitrary-objects
Allow hash suffixing of arbitrary types
2020-07-22 13:12:44 -07:00
Kubernetes Prow Robot
508d193e7a Merge pull request #2753 from phanimarupaka/AddV1CreateSetterTest
Add v1 create setter tests
2020-07-22 12:51:39 -07:00
Phani Teja Marupaka
e0eb79adcc Add v1 create setter tests 2020-07-22 12:11:19 -07:00
Jeff Regan
dcab3cbb5f Merge pull request #2739 from Shell32-Natsu/rolebinding
Role binding for serviceaccount across namesapce.
2020-07-22 11:45:05 -07:00
Jeff Regan
8225ca45a8 Merge pull request #2752 from monopole/convertImageTagTransformer
Convert image transformer to kyaml.
2020-07-22 11:37:04 -07:00
jregan
ef924a5c9c Convert image transformer to kyaml. 2020-07-22 11:10:52 -07:00
Jeff Regan
33b03fce89 remove a blank 2020-07-22 11:06:26 -07:00
Donny Xia
3907643880 Add function to check role binding namespace 2020-07-22 11:01:23 -07:00
Donny Xia
b7f7536cfa Update comment 2020-07-22 11:01:23 -07:00
Donny Xia
15bc399d5a Support RoleBinding for ServiceAccount across namespace 2020-07-22 11:01:23 -07:00
Jeff Regan
46a6bf0bb4 Merge pull request #2751 from monopole/moreImageTagTests
Add more tests to imagetag filter
2020-07-22 10:59:27 -07:00
Jeff Regan
6717bbd36b Merge pull request #2750 from Shell32-Natsu/rolebinding-test
Add test for role binding across namespace.
2020-07-22 10:54:17 -07:00
Kubernetes Prow Robot
6fccb7fd48 Merge pull request #2743 from phanimarupaka/FixV1Setters
Fix V1 setters
2020-07-22 10:52:06 -07:00
jregan
370a3d2e74 Add more imagetag tests to support refactor. 2020-07-22 10:46:20 -07:00
Phani Teja Marupaka
eb7beba8ad Fix V1 setters 2020-07-22 10:17:10 -07:00
Jeff Regan
1e3bc51645 Merge pull request #2748 from monopole/tweakSequenceTreatment
Tweak sequence treatment in fieldspecs
2020-07-22 10:01:21 -07:00
Donny Xia
92e1d452b7 Add test for role binding across namespace. 2020-07-22 10:00:34 -07:00
Kubernetes Prow Robot
7abedcf87b Merge pull request #2749 from pwittrock/default
Update kustomize FAQ with kubectl explanation
2020-07-22 09:52:05 -07:00
Phillip Wittrock
aa991956ef Docs: build site 2020-07-22 09:27:32 -07:00
Phillip Wittrock
c6524f984c Docs: Update FAQ with why kubectl has kustomize 2 2020-07-22 09:27:07 -07:00
Jeff Regan
a70c6b3496 Tweak sequence treatment in fieldspecs 2020-07-22 09:23:47 -07:00
Jeff Regan
166c7f3167 Merge pull request #2742 from techniumlabs/master
Avoiding Prefix Transformer for Namespace resource
2020-07-21 17:21:29 -07:00
Kubernetes Prow Robot
10371aa1b5 Merge pull request #2595 from phanimarupaka/FixAnnotations
Error for null files while reading
2020-07-21 17:16:05 -07:00
Jeff Regan
95fb639fa8 Merge pull request #2728 from prachirp/markdownlint
Docs: Auto-fix markdownlint issues
2020-07-21 16:56:45 -07:00
Jeff Regan
0f7aae38e3 Merge pull request #2735 from monopole/moreBadness
Switch replica count transformer to kyaml.
2020-07-21 16:55:55 -07:00
ageekymonk
c660fd33ae Avoiding Prefix Transformer for Namespace resource 2020-07-21 18:33:42 +10:00
Phani Teja Marupaka
108195185f List and set setters in folders recursively 2020-07-20 00:50:04 -07:00
Nick
4fbe565b36 Allow hash suffixing of arbitrary types 2020-07-19 23:29:24 +01:00
jregan
e9bc2c00c1 Switch prefix transformer to kyaml. 2020-07-17 19:48:13 -07:00
Jeff Regan
45eed23b26 Merge pull request #2733 from kubernetes-sigs/ctFormatting
Update formatting of component_test.go
2020-07-17 19:48:06 -07:00
Jeff Regan
27b2c7f294 Update formatting of component_test.go 2020-07-17 18:31:54 -07:00
Jeff Regan
03d6229c0b Merge pull request #2732 from monopole/beanPole
Switch prefix transformer to kyaml.
2020-07-17 18:09:19 -07:00
jregan
71b7b00bd8 Switch prefix transformer to kyaml. 2020-07-17 16:08:41 -07:00
Jeff Regan
e9396dca2c Merge pull request #2731 from prachirp/go-plugins
Fix go plugins caveats link
2020-07-17 15:49:36 -07:00
Prachi Pendse
bc581b70bf Fix go plugins caveats link 2020-07-17 12:03:19 -07:00
Jeff Regan
ac1c31c82b Merge pull request #2730 from monopole/addTest
Add a test and temporarily disable some plugin tests.
2020-07-17 10:25:07 -07:00
jregan
c878957d0b Add a test and temporarily disable some plugin tests. 2020-07-17 08:23:11 -07:00
Prachi Pendse
f9ee578aed Docs: Auto-fix markdownlint issues 2020-07-16 12:57:18 -07:00
Jeff Regan
0b359d0ef0 Merge pull request #2727 from monopole/addE2eTests
Pre v3.8.1; Add e2e tests pinned at v3.8.0
2020-07-15 17:54:54 -07:00
jregan
22ee7cbd49 Pre v3.8.1; Add e2e tests pinned at v3.8.0 2020-07-15 17:33:43 -07:00
Jeff Regan
7bf9c7002f Merge pull request #2726 from monopole/pinToKustomizeApiV_0_5_1
Pin to kustomize/api v0.5.1
2020-07-15 17:26:12 -07:00
jregan
155411f229 Pin to kustomize/api v0.5.1 2020-07-15 17:00:33 -07:00
Jeff Regan
699cc70a7c Merge pull request #2725 from monopole/pinToKyamlv0_4_1
Pin To Kyaml/v0.4.1
2020-07-15 16:44:17 -07:00
jregan
a63a472024 Pin To Kyaml/v0.4.1 2020-07-15 16:17:12 -07:00
Phani Teja Marupaka
e894756003 Error for null files while reading 2020-07-15 16:05:52 -07:00
Jeff Regan
55f55a5091 Merge pull request #2718 from Shell32-Natsu/unknown-fields
Uniform unmarshal function
2020-07-15 14:36:06 -07:00
Donny Xia
8401196ef9 fix typo 2020-07-15 11:47:47 -07:00
Donny Xia
14edc3890c Add tests for kustomization.go 2020-07-15 11:42:50 -07:00
Donny Xia
897698fb29 Uniform unmarshal function 2020-07-14 17:01:43 -07:00
Jeff Regan
ec9ae3d7b0 Merge pull request #2713 from Shell32-Natsu/empty-list-in-patch
Keep empty array in output
2020-07-14 13:50:37 -07:00
Donny Xia
3a828941fa Improve tests 2020-07-14 11:38:29 -07:00
Jeff Regan
b63b5ce7cc Merge pull request #2683 from Shell32-Natsu/function-benchmark
KRM Function benchmark
2020-07-14 09:05:31 -07:00
Donny Xia
23bd4390d3 code review 2020-07-13 16:40:34 -07:00
Kubernetes Prow Robot
21a0fd33a2 Merge pull request #2696 from arrikto/feature-site-components-guide
docs: Add guide for components
2020-07-13 14:29:20 -07:00
Donny Xia
c6b6dec91f Add tests for IsEmpty and IsMissingorNull 2020-07-13 14:15:55 -07:00
Kubernetes Prow Robot
9cf4367db7 Merge pull request #2709 from aodinokov/fixmount
Fixed incorrect docker mount arguments generation
2020-07-13 12:35:22 -07:00
Jeff Regan
e9c118fd55 Update readme.md 2020-07-13 12:24:34 -07:00
Kubernetes Prow Robot
bfbb1971d4 Merge pull request #2695 from sunny0826/master
add favicons for doc site
2020-07-13 12:09:20 -07:00
Donny Xia
6fabfe963e code review 2020-07-13 12:05:03 -07:00
Donny Xia
67cdd2e27e Add test for keeping empty array 2020-07-13 11:50:01 -07:00
Jeff Regan
6c6b5f744d Merge pull request #2641 from jijiew/doc
doc for kustomize config delete setter
2020-07-13 11:38:43 -07:00
Jeff Regan
7775666c50 Merge pull request #2702 from kubernetes-sigs/dependabot/npm_and_yarn/api/internal/crawl/ui/npm-registry-fetch-4.0.5
Bump npm-registry-fetch from 4.0.2 to 4.0.5 in /api/internal/crawl/ui
2020-07-13 11:36:55 -07:00
Kubernetes Prow Robot
bdd7ae085e Merge pull request #2708 from monopole/byeByeFlag
Removing YAMLSupport==false code path.
2020-07-13 11:11:20 -07:00
Alexey Odinokov
ba3e09849a Made mountString params more similar to docker params
see [1]
kept support for the previous field names similarly to
docker behavior.

[1]
https://docs.docker.com/storage/bind-mounts/#use-a-read-only-bind-mount
2020-07-13 17:21:37 +00:00
Donny Xia
236ae29e9a Don't consider empty array as "empty" 2020-07-13 10:03:24 -07:00
Kubernetes Prow Robot
5c3bd83252 Merge pull request #2707 from mortent/FixDotInSetterName
Allow setters/substitutions with . in the name
2020-07-13 10:03:20 -07:00
Kubernetes Prow Robot
3674e0a91d Merge pull request #2711 from mortent/SubstitutionWithSameNameSetter
Don't allow creating setter with same name as substitution
2020-07-12 23:02:32 -07:00
Morten Torkildsen
f9631e4bb2 Don't allow creating setter with same name as substitution 2020-07-12 11:28:09 -07:00
Morten Torkildsen
c419c1efc3 Allow setters/substitutions with . in the name 2020-07-11 10:41:27 -07:00
Alexey Odinokov
63f9f79fc0 Fixed incorrect docker mount arguments generation
The previous implementation combined --mount and -v notation
of argument [1] adding :ro to make the read-only mount point.
E.g. the command [2] called docker with the following
params: [3]. As a result instead of the read-only
folder /tmp/source, the read-write folder /tmp/source/:ro/'
is created.

This PR:
1. substitutes ':ro' with correct ',readonly'.
2. changes 'src=' and 'dst=' with 'source=' and 'target=' as
   it is stated in the documentation [1]
3. introduces the ability to EXPLICITLY create a mountpoint
   with read-write access. To do so it's necessary to add
   ',rw=true' to the --mount argument
4. corrects UTs adds some additional coverage for added
   functionality

[1]
https://docs.docker.com/storage/bind-mounts/#use-a-read-only-bind-mount

[2]
kustomize fn run ./d --mount type=bind,src=$(pwd)/test/,dst=/tmp/source/

[3]
--mount type=bind,src=/home/ubuntu/kpt-functions-catalog/functions/ts/test/,dst=/tmp/source/:ro
2020-07-11 17:03:44 +00:00
jregan
33e68c0f97 Removing YAMLSupport==false code path.
This continues work on the master and v3.8.* branches
to eliminate apimachinery dependence.
2020-07-10 19:06:26 -07:00
Kubernetes Prow Robot
556eb48651 Merge pull request #2706 from mortent/FixCmdConfigGoMod
Fix go.mod file in cmd/config
2020-07-10 18:53:22 -07:00
Morten Torkildsen
5b26c3b4cc Fix go.mod file in cmd/config 2020-07-10 17:14:49 -07:00
Donny Xia
42e19d610a Improve cleanup 2020-07-08 11:08:19 -07:00
dependabot[bot]
950b1c895f Bump npm-registry-fetch from 4.0.2 to 4.0.5 in /api/internal/crawl/ui
Bumps [npm-registry-fetch](https://github.com/npm/registry-fetch) from 4.0.2 to 4.0.5.
- [Release notes](https://github.com/npm/registry-fetch/releases)
- [Changelog](https://github.com/npm/npm-registry-fetch/blob/latest/CHANGELOG.md)
- [Commits](https://github.com/npm/registry-fetch/commits)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-08 00:49:07 +00:00
Kubernetes Prow Robot
ca5feb7751 Merge pull request #2700 from jijiew/win-seperator
modify the byteioreader to handler windows line ending.
2020-07-07 10:13:58 -07:00
Jijie Wei
488a88ec6e modify the bytereader to handler windows line ending. 2020-07-07 09:49:17 -07:00
Morten Torkildsen
fd3a4a88be Merge pull request #2699 from mortent/ReturnCmdConfigRedirects
Return go.mod replace directives
2020-07-06 21:28:37 -07:00
Morten Torkildsen
e6147347a8 Return go.mod replace directives 2020-07-06 21:12:32 -07:00
Morten Torkildsen
0b756877e1 Merge pull request #2698 from mortent/PrepCmdConfigForRelease
Prep cmd/config for release
2020-07-06 21:03:40 -07:00
Morten Torkildsen
0f4b5e6787 Prep cmd/config for release 2020-07-06 20:50:18 -07:00
Ioannis Androulidakis
1b531c6ac7 docs: Add guide for components
Extend the list of Kustomize guides available in the official website
with one about components, so that users can familiarize with this use
case and feature.

Signed-off-by: Ioannis Androulidakis <ioannis@arrikto.com>
2020-07-06 23:15:49 +03:00
Donny Xia
f6cac7e7e8 Add newline to the end of file 2020-07-06 09:38:31 -07:00
guoxudong
fe0577a15f add favicons 2020-07-06 09:42:23 +08:00
guoxudong
f68740be66 add favicons 2020-07-06 09:42:09 +08:00
Kubernetes Prow Robot
855ce1a8db Merge pull request #2693 from t0rr3sp3dr0/master
Update function annotation on docs
2020-07-05 18:06:50 -07:00
Jeff Regan
6a50372dd5 Merge pull request #2694 from monopole/switchToApiV0_5_0
Switch to kustomize/api v0.5.0
2020-07-04 21:22:19 -07:00
jregan
5a0228629f Switch kustomize to api/v0.5.0 2020-07-04 19:45:45 -07:00
Jeff Regan
def00220ce Merge pull request #2668 from monopole/doesItWork
Switch namespace and patch transformers to kyaml.
2020-07-04 17:11:56 -07:00
jregan
d3a7335bbc Switch namespace and patch transformers to kyaml. 2020-07-04 16:21:01 -07:00
Pedro Tôrres
94095a63ff Update function annotation on docs
Signed-off-by: Pedro Tôrres <t0rr3sp3dr0@gmail.com>
2020-07-04 18:19:28 -03:00
Donny Xia
c2ccfd72ad Update readme 2020-07-01 12:55:38 -07:00
Donny Xia
6d324d70c4 Add benchmark for containerized KRM function in kustomize 2020-07-01 12:47:16 -07:00
Jijie Wei
e32aa8ddb2 revert generated doc change 2020-06-23 14:22:09 -07:00
Jijie Wei
b92de5cb80 revert change in generated doc 2020-06-23 14:17:39 -07:00
Jijie Wei
ecfa732a04 doc for kustomize config delete setter 2020-06-23 13:47:19 -07:00
600 changed files with 96801 additions and 12076 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.6.1
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
@@ -23,10 +24,11 @@ verify-kustomize: \
prow-presubmit-check: \
lint-kustomize \
test-unit-kustomize-all \
test-examples-kustomize-against-HEAD \
test-examples-kustomize-against-3.6.1 \
test-unit-cmd-all \
test-go-mod
test-go-mod \
test-examples-kustomize-against-HEAD \
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
@@ -233,10 +237,23 @@ test-examples-kustomize-against-HEAD: $(MYGOBIN)/kustomize $(MYGOBIN)/mdrip
./hack/testExamplesAgainstKustomize.sh HEAD
.PHONY:
test-examples-kustomize-against-3.6.1: $(MYGOBIN)/mdrip
test-examples-kustomize-against-3.8.0: $(MYGOBIN)/mdrip
( \
set -e; \
tag=v3.6.1; \
tag=v3.8.0; \
/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 .; \
)
.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}; \

View File

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

View File

@@ -9,18 +9,15 @@ patch [kubernetes style] API objects. It's like
[`make`], in that what it does is declared in a file,
and it's like [`sed`], in that it emits edited text.
This tool is sponsored by [sig-cli] ([KEP]), and
inspired by [DAM].
This tool is sponsored by [sig-cli] ([KEP]).
- [Installation instructions](https://kubernetes-sigs.github.io/kustomize/installation)
- [General documentation](https://kubernetes-sigs.github.io/kustomize)
- [Examples](examples)
[![Build Status](https://prow.k8s.io/badge.svg?jobs=kustomize-presubmit-master)](https://prow.k8s.io/job-history/kubernetes-jenkins/pr-logs/directory/kustomize-presubmit-master)
[![Go Report Card](https://goreportcard.com/badge/github.com/kubernetes-sigs/kustomize)](https://goreportcard.com/report/github.com/kubernetes-sigs/kustomize)
Download a binary from the [release page], or see
these [instructions](https://kubernetes-sigs.github.io/kustomize/installation/).
Browse the [docs](https://kubernetes-sigs.github.io/kustomize/) or jump right into the
tested [examples](examples).
## kubectl integration
Since [v1.14][kubectl announcement] the kustomize build system has been included in kubectl.

View File

@@ -8,10 +8,10 @@ import (
"regexp"
"strings"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/api/filters/imagetag"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
"sigs.k8s.io/yaml"
)
@@ -31,18 +31,19 @@ func (p *ImageTagTransformerPlugin) Config(
func (p *ImageTagTransformerPlugin) Transform(m resmap.ResMap) error {
for _, r := range m.Resources() {
for _, path := range p.FieldSpecs {
if !r.OrgId().IsSelected(&path.Gvk) {
continue
}
err := transform.MutateField(
r.Map(), path.PathSlice(), false, p.mutateImage)
if err != nil {
return err
}
// traverse all fields at first
err := filtersutil.ApplyToJSON(imagetag.LegacyFilter{
ImageTag: p.ImageTag,
}, r)
if err != nil {
return err
}
// Kept for backward compatibility
if err := p.findAndReplaceImage(r.Map()); err != nil && r.OrgId().Kind != `CustomResourceDefinition` {
// then use user specified field specs
err = filtersutil.ApplyToJSON(imagetag.Filter{
ImageTag: p.ImageTag,
FsSlice: p.FieldSpecs,
}, r)
if err != nil {
return err
}
}

View File

@@ -10,7 +10,6 @@ import (
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
"sigs.k8s.io/yaml"
@@ -20,11 +19,6 @@ import (
type NamespaceTransformerPlugin struct {
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
// YAMLSupport can be set to true to use the kyaml filter instead of the
// kunstruct transformer.
// TODO: change the default to use kyaml when it is stable
YAMLSupport bool `json:"yamlSupport,omitempty" yaml:"yamlSupport,omitempty"`
}
func (p *NamespaceTransformerPlugin) Config(
@@ -43,31 +37,13 @@ func (p *NamespaceTransformerPlugin) Transform(m resmap.ResMap) error {
// Don't mutate empty objects?
continue
}
id := r.OrgId()
if p.YAMLSupport {
// use the new style transform
err := filtersutil.ApplyToJSON(namespace.Filter{
Namespace: p.Namespace,
FsSlice: p.FieldSpecs,
}, r)
if err != nil {
return err
}
} else {
// use the old style transform
applicableFs := p.applicableFieldSpecs(id)
for _, fs := range applicableFs {
err := transform.MutateField(
r.Map(), fs.PathSlice(), fs.CreateIfNotPresent,
p.changeNamespace(r))
if err != nil {
return err
}
}
err := filtersutil.ApplyToJSON(namespace.Filter{
Namespace: p.Namespace,
FsSlice: p.FieldSpecs,
}, r)
if err != nil {
return err
}
matches := m.GetMatchingResourcesByCurrentId(r.CurId().Equals)
if len(matches) != 1 {
return fmt.Errorf(

View File

@@ -23,8 +23,6 @@ type PatchJson6902TransformerPlugin struct {
Target types.PatchTarget `json:"target,omitempty" yaml:"target,omitempty"`
Path string `json:"path,omitempty" yaml:"path,omitempty"`
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
YAMLSupport bool `json:"yamlSupport,omitempty" yaml:"yamlSupport,omitempty"`
}
func (p *PatchJson6902TransformerPlugin) Config(
@@ -87,22 +85,9 @@ func (p *PatchJson6902TransformerPlugin) Transform(m resmap.ResMap) error {
if err != nil {
return err
}
if !p.YAMLSupport {
rawObj, err := obj.MarshalJSON()
if err != nil {
return err
}
modifiedObj, err := p.decodedPatch.Apply(rawObj)
if err != nil {
return errors.Wrapf(
err, "failed to apply json patch '%s'", p.JsonOp)
}
return obj.UnmarshalJSON(modifiedObj)
} else {
return filtersutil.ApplyToJSON(patchjson6902.Filter{
Patch: p.JsonOp,
}, obj)
}
return filtersutil.ApplyToJSON(patchjson6902.Filter{
Patch: p.JsonOp,
}, obj)
}
func NewPatchJson6902TransformerPlugin() resmap.TransformerPlugin {

View File

@@ -5,7 +5,9 @@ package builtins
import (
"fmt"
"strings"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/filters/patchstrategicmerge"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
@@ -19,8 +21,6 @@ type PatchStrategicMergeTransformerPlugin struct {
loadedPatches []*resource.Resource
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
YAMLSupport bool `json:"yamlSupport,omitempty" yaml:"yamlSupport,omitempty"`
}
func (p *PatchStrategicMergeTransformerPlugin) Config(
@@ -64,7 +64,7 @@ func (p *PatchStrategicMergeTransformerPlugin) Config(
}
func (p *PatchStrategicMergeTransformerPlugin) Transform(m resmap.ResMap) error {
patches, err := p.h.ResmapFactory().MergePatches(p.loadedPatches)
patches, err := p.h.ResmapFactory().Merge(p.loadedPatches)
if err != nil {
return err
}
@@ -73,31 +73,43 @@ func (p *PatchStrategicMergeTransformerPlugin) Transform(m resmap.ResMap) error
if err != nil {
return err
}
if !p.YAMLSupport {
err = target.Patch(patch.Copy())
patchCopy := patch.DeepCopy()
patchCopy.SetName(target.GetName())
patchCopy.SetNamespace(target.GetNamespace())
patchCopy.SetGvk(target.GetGvk())
node, err := filtersutil.GetRNode(patchCopy)
if err != nil {
return err
}
err = filtersutil.ApplyToJSON(patchstrategicmerge.Filter{
Patch: node,
}, target)
if err != nil {
// Check for an error string from UnmarshalJSON that's indicative
// of an object that's missing basic KRM fields, and thus may have been
// entirely deleted (an acceptable outcome). This error handling should
// be deleted along with use of ResMap and apimachinery functions like
// UnmarshalJSON.
if !strings.Contains(err.Error(), "Object 'Kind' is missing") {
// Some unknown error, let it through.
return err
}
if len(target.Map()) != 0 {
return errors.Wrapf(
err, "with unexpectedly non-empty object map of size %d",
len(target.Map()))
}
// Fall through to handle deleted object.
}
if len(target.Map()) == 0 {
// This means all fields have been removed from the object.
// This can happen if a patch required deletion of the
// entire resource (not just a part of it). This means
// the overall resmap must shrink by one.
err = m.Remove(target.CurId())
if err != nil {
return err
}
// remove the resource from resmap
// when the patch is to $patch: delete that target
if len(target.Map()) == 0 {
err = m.Remove(target.CurId())
if err != nil {
return err
}
}
} else {
patchCopy := patch.DeepCopy()
patchCopy.SetName(target.GetName())
patchCopy.SetNamespace(target.GetNamespace())
patchCopy.SetGvk(target.GetGvk())
node, err := filtersutil.GetRNode(patchCopy)
if err != nil {
return err
}
err = filtersutil.ApplyToJSON(patchstrategicmerge.Filter{
Patch: node,
}, target)
}
}
return nil

View File

@@ -8,7 +8,6 @@ import (
"strings"
jsonpatch "github.com/evanphx/json-patch"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/filters/patchjson6902"
"sigs.k8s.io/kustomize/api/filters/patchstrategicmerge"
"sigs.k8s.io/kustomize/api/resmap"
@@ -24,8 +23,6 @@ type PatchTransformerPlugin struct {
Path string `json:"path,omitempty" yaml:"path,omitempty"`
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
YAMLSupport bool `json:"yamlSupport,omitempty" yaml:"yamlSupport,omitempty"`
}
func (p *PatchTransformerPlugin) Config(
@@ -73,11 +70,11 @@ func (p *PatchTransformerPlugin) Config(
}
func (p *PatchTransformerPlugin) Transform(m resmap.ResMap) error {
if p.loadedPatch != nil {
if p.loadedPatch == nil {
return p.transformJson6902(m, p.decodedPatch)
} else {
// The patch was a strategic merge patch
return p.transformStrategicMerge(m, p.loadedPatch)
} else {
return p.transformJson6902(m, p.decodedPatch)
}
}
@@ -111,20 +108,15 @@ func (p *PatchTransformerPlugin) transformStrategicMerge(m resmap.ResMap, patch
}
// applySMPatch applies the provided strategic merge patch to the
// given resource. Depending on the value of YAMLSupport, it will either
// use the legacy implementation or the kyaml-based solution.
// given resource.
func (p *PatchTransformerPlugin) applySMPatch(resource, patch *resource.Resource) error {
if !p.YAMLSupport {
return resource.Patch(patch.Copy())
} else {
node, err := filtersutil.GetRNode(patch)
if err != nil {
return err
}
return filtersutil.ApplyToJSON(patchstrategicmerge.Filter{
Patch: node,
}, resource)
node, err := filtersutil.GetRNode(patch)
if err != nil {
return err
}
return filtersutil.ApplyToJSON(patchstrategicmerge.Filter{
Patch: node,
}, resource)
}
// transformJson6902 applies the provided json6902 patch
@@ -133,13 +125,14 @@ func (p *PatchTransformerPlugin) transformJson6902(m resmap.ResMap, patch jsonpa
if p.Target == nil {
return fmt.Errorf("must specify a target for patch %s", p.Patch)
}
resources, err := m.Select(*p.Target)
if err != nil {
return err
}
for _, res := range resources {
err = p.applyJson6902Patch(res, patch)
err = filtersutil.ApplyToJSON(patchjson6902.Filter{
Patch: p.Patch,
}, res)
if err != nil {
return err
}
@@ -147,28 +140,6 @@ func (p *PatchTransformerPlugin) transformJson6902(m resmap.ResMap, patch jsonpa
return nil
}
// applyJson6902Patch applies the provided patch to the given resource.
// Depending on the value of YAMLSupport, it will either
// use the legacy implementation or the kyaml-based solution.
func (p *PatchTransformerPlugin) applyJson6902Patch(resource *resource.Resource, patch jsonpatch.Patch) error {
if !p.YAMLSupport {
rawObj, err := resource.MarshalJSON()
if err != nil {
return err
}
modifiedObj, err := patch.Apply(rawObj)
if err != nil {
return errors.Wrapf(
err, "failed to apply json patch '%s'", p.Patch)
}
return resource.UnmarshalJSON(modifiedObj)
} else {
return filtersutil.ApplyToJSON(patchjson6902.Filter{
Patch: p.Patch,
}, resource)
}
}
// jsonPatchFromBytes loads a Json 6902 patch from
// a bytes input
func jsonPatchFromBytes(

View File

@@ -5,31 +5,28 @@ package builtins
import (
"errors"
"fmt"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/api/filters/prefixsuffix"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
"sigs.k8s.io/yaml"
)
// Add the given prefix and suffix to the field.
type PrefixSuffixTransformerPlugin struct {
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
FieldSpecs types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
// Not placed in a file yet due to lack of demand.
var prefixSuffixFieldSpecsToSkip = []types.FieldSpec{
{
Gvk: resid.Gvk{Kind: "CustomResourceDefinition"},
},
{
Gvk: resid.Gvk{Group: "apiregistration.k8s.io", Kind: "APIService"},
},
// A Gvk skip list for prefix/suffix modification.
// hard coded for now - eventually should be part of config.
var prefixSuffixFieldSpecsToSkip = types.FsSlice{
{Gvk: resid.Gvk{Kind: "CustomResourceDefinition"}},
{Gvk: resid.Gvk{Group: "apiregistration.k8s.io", Kind: "APIService"}},
{Gvk: resid.Gvk{Kind: "Namespace"}},
}
func (p *PrefixSuffixTransformerPlugin) Config(
@@ -48,29 +45,24 @@ func (p *PrefixSuffixTransformerPlugin) Config(
}
func (p *PrefixSuffixTransformerPlugin) Transform(m resmap.ResMap) error {
// Even if both the Prefix and Suffix are empty we want
// to proceed with the transformation. This allows to add contextual
// information to the resources (AddNamePrefix and AddNameSuffix).
for _, r := range m.Resources() {
// TODO: move this test into the filter (i.e. make a better filter)
if p.shouldSkip(r.OrgId()) {
// Don't change the actual definition
// of a CRD.
continue
}
id := r.OrgId()
// current default configuration contains
// only one entry: "metadata/name" with no GVK
for _, path := range p.FieldSpecs {
if !id.IsSelected(&path.Gvk) {
// With the currrent default configuration,
// because no Gvk is specified, so a wild
// card
for _, fs := range p.FieldSpecs {
// TODO: this is redundant to filter (but needed for now)
if !id.IsSelected(&fs.Gvk) {
continue
}
if smellsLikeANameChange(&path) {
// TODO: move this test into the filter.
if smellsLikeANameChange(&fs) {
// "metadata/name" is the only field.
// this will add a prefix and a suffix
// to the resource even if those are
@@ -78,15 +70,11 @@ func (p *PrefixSuffixTransformerPlugin) Transform(m resmap.ResMap) error {
r.AddNamePrefix(p.Prefix)
r.AddNameSuffix(p.Suffix)
}
// the addPrefixSuffix method will not
// change the name if both the prefix and suffix
// are empty.
err := transform.MutateField(
r.Map(),
path.PathSlice(),
path.CreateIfNotPresent,
p.addPrefixSuffix)
err := filtersutil.ApplyToJSON(prefixsuffix.Filter{
Prefix: p.Prefix,
Suffix: p.Suffix,
FieldSpec: fs,
}, r)
if err != nil {
return err
}
@@ -99,8 +87,7 @@ func smellsLikeANameChange(fs *types.FieldSpec) bool {
return fs.Path == "metadata/name"
}
func (p *PrefixSuffixTransformerPlugin) shouldSkip(
id resid.ResId) bool {
func (p *PrefixSuffixTransformerPlugin) shouldSkip(id resid.ResId) bool {
for _, path := range prefixSuffixFieldSpecsToSkip {
if id.IsSelected(&path.Gvk) {
return true
@@ -109,15 +96,6 @@ func (p *PrefixSuffixTransformerPlugin) shouldSkip(
return false
}
func (p *PrefixSuffixTransformerPlugin) addPrefixSuffix(
in interface{}) (interface{}, error) {
s, ok := in.(string)
if !ok {
return nil, fmt.Errorf("%#v is expected to be %T", in, s)
}
return fmt.Sprintf("%s%s%s", p.Prefix, s, p.Suffix), nil
}
func NewPrefixSuffixTransformerPlugin() resmap.TransformerPlugin {
return &PrefixSuffixTransformerPlugin{}
}

View File

@@ -6,7 +6,8 @@ package builtins
import (
"fmt"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/filters/replicacount"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
@@ -30,18 +31,24 @@ func (p *ReplicaCountTransformerPlugin) Config(
func (p *ReplicaCountTransformerPlugin) Transform(m resmap.ResMap) error {
found := false
for i, replicaSpec := range p.FieldSpecs {
matcher := p.createMatcher(i)
for _, fs := range p.FieldSpecs {
matcher := p.createMatcher(fs)
matchOriginal := m.GetMatchingResourcesByOriginalId(matcher)
matchCurrent := m.GetMatchingResourcesByCurrentId(matcher)
for _, res := range append(matchOriginal, matchCurrent...) {
resList := append(
matchOriginal, m.GetMatchingResourcesByCurrentId(matcher)...)
if len(resList) > 0 {
found = true
err := transform.MutateField(
res.Map(), replicaSpec.PathSlice(),
replicaSpec.CreateIfNotPresent, p.addReplicas)
if err != nil {
return err
for _, r := range resList {
// There are redundant checks in the filter
// that we'll live with until resolution of
// https://github.com/kubernetes-sigs/kustomize/issues/2506
err := filtersutil.ApplyToJSON(replicacount.Filter{
Replica: p.Replica,
FieldSpec: fs,
}, r)
if err != nil {
return err
}
}
}
}
@@ -59,30 +66,12 @@ func (p *ReplicaCountTransformerPlugin) Transform(m resmap.ResMap) error {
}
// Match Replica.Name and FieldSpec
func (p *ReplicaCountTransformerPlugin) createMatcher(i int) resmap.IdMatcher {
func (p *ReplicaCountTransformerPlugin) createMatcher(fs types.FieldSpec) resmap.IdMatcher {
return func(r resid.ResId) bool {
return r.Name == p.Replica.Name &&
r.Gvk.IsSelected(&p.FieldSpecs[i].Gvk)
return r.Name == p.Replica.Name && r.Gvk.IsSelected(&fs.Gvk)
}
}
func (p *ReplicaCountTransformerPlugin) addReplicas(in interface{}) (interface{}, error) {
switch m := in.(type) {
case int64:
// Was already in the field.
case map[string]interface{}:
if len(m) != 0 {
// A map was already in the replicas field, don't want to
// discard this data silently.
return nil, fmt.Errorf("%#v is expected to be %T", in, m)
}
// Just got added, default type is map, but we can return anything.
default:
return nil, fmt.Errorf("%#v is expected to be %T", in, m)
}
return p.Replica.Count, nil
}
func NewReplicaCountTransformerPlugin() resmap.TransformerPlugin {
return &ReplicaCountTransformerPlugin{}
}

View File

@@ -29,10 +29,11 @@ func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
func(node *yaml.RNode) (*yaml.RNode, error) {
for _, k := range keys {
if err := node.PipeE(fsslice.Filter{
FsSlice: f.FsSlice,
SetValue: fsslice.SetEntry(k, f.Annotations[k], yaml.StringTag),
FsSlice: f.FsSlice,
SetValue: filtersutil.SetEntry(
k, f.Annotations[k], yaml.NodeTagString),
CreateKind: yaml.MappingNode, // Annotations are MappingNodes.
CreateTag: "!!map",
CreateTag: yaml.NodeTagMap,
}); err != nil {
return nil, err
}

View File

@@ -0,0 +1,6 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package fieldspec contains a yaml.Filter to modify a resource
// that matches the FieldSpec.
package fieldspec

View File

@@ -0,0 +1,61 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package fieldspec_test
import (
"bytes"
"log"
"os"
. "sigs.k8s.io/kustomize/api/filters/fieldspec"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
func ExampleFilter() {
in := &kio.ByteReader{
Reader: bytes.NewBufferString(`
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
---
apiVersion: example.com/v1
kind: Bar
metadata:
name: instance
`),
}
fltr := Filter{
CreateKind: yaml.ScalarNode,
SetValue: filtersutil.SetScalar("green"),
FieldSpec: types.FieldSpec{Path: "a/b", CreateIfNotPresent: true},
}
err := kio.Pipeline{
Inputs: []kio.Reader{in},
Filters: []kio.Filter{kio.FilterAll(fltr)},
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
}.Execute()
if err != nil {
log.Fatal(err)
}
// Output:
// apiVersion: example.com/v1
// kind: Foo
// metadata:
// name: instance
// a:
// b: green
// ---
// apiVersion: example.com/v1
// kind: Bar
// metadata:
// name: instance
// a:
// b: green
}

View File

@@ -1,24 +1,27 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package fsslice
package fieldspec
import (
"strings"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// fieldSpecFilter applies a single fieldSpec to a single object
// fieldSpecFilter stores internal state and should not be reused
type fieldSpecFilter struct {
var _ yaml.Filter = Filter{}
// Filter applies a single fieldSpec to a single object
// Filter stores internal state and should not be reused
type Filter struct {
// FieldSpec contains the path to the value to set.
FieldSpec types.FieldSpec `yaml:"fieldSpec"`
// Set the field using this function
SetValue SetFn
SetValue filtersutil.SetFn
// CreateKind defines the type of node to create if the field is not found
CreateKind yaml.Kind
@@ -29,48 +32,54 @@ type fieldSpecFilter struct {
path []string
}
func (fltr fieldSpecFilter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
func (fltr Filter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
// check if the FieldSpec applies to the object
if match, err := isMatchGVK(fltr.FieldSpec, obj); !match || err != nil {
return obj, errors.Wrap(err)
}
fltr.path = strings.Split(fltr.FieldSpec.Path, "/")
fltr.path = splitPath(fltr.FieldSpec.Path)
if err := fltr.filter(obj); err != nil {
s, _ := obj.String()
return nil, errors.WrapPrefixf(err,
"obj %v at path %v", s, fltr.FieldSpec.Path)
"obj '%s' at path '%v'", s, fltr.FieldSpec.Path)
}
return obj, nil
}
func (fltr fieldSpecFilter) filter(obj *yaml.RNode) error {
func (fltr Filter) filter(obj *yaml.RNode) error {
if len(fltr.path) == 0 {
// 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)
case yaml.MappingNode:
return fltr.field(obj)
default:
return errors.Errorf("expected sequence or mapping node")
}
// not found -- this might be an error since the type doesn't match
return errors.Errorf("unsupported yaml node")
}
// field calls filter on the field matching the next path element
func (fltr fieldSpecFilter) field(obj *yaml.RNode) error {
func (fltr Filter) field(obj *yaml.RNode) error {
fieldName, isSeq := isSequenceField(fltr.path[0])
// lookup the field matching the next path element
var lookupField yaml.Filter
var kind yaml.Kind
var tag string
tag := yaml.NodeTagEmpty
switch {
case !fltr.FieldSpec.CreateIfNotPresent || fltr.CreateKind == 0 || isSeq:
// dont' create the field if we don't find it
lookupField = yaml.Lookup(fieldName)
if isSeq {
// The query path thinks this field should be a sequence;
// accept this hint for use later if the tag is NodeTagNull.
kind = yaml.SequenceNode
}
case len(fltr.path) <= 1:
// create the field if it is missing: use the provided node kind
lookupField = yaml.LookupCreate(fltr.CreateKind, fieldName)
@@ -80,7 +89,7 @@ func (fltr fieldSpecFilter) field(obj *yaml.RNode) error {
// create the field if it is missing: must be a mapping node
lookupField = yaml.LookupCreate(yaml.MappingNode, fieldName)
kind = yaml.MappingNode
tag = "!!map"
tag = yaml.NodeTagMap
}
// locate (or maybe create) the field
@@ -89,9 +98,10 @@ func (fltr fieldSpecFilter) 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 == "!!null" {
if field.YNode().Tag == yaml.NodeTagNull && yaml.IsCreate(kind) {
field.YNode().Kind = kind
field.YNode().Tag = tag
}
@@ -104,9 +114,9 @@ func (fltr fieldSpecFilter) field(obj *yaml.RNode) error {
}
// seq calls filter on all sequence elements
func (fltr fieldSpecFilter) seq(obj *yaml.RNode) error {
func (fltr Filter) seq(obj *yaml.RNode) error {
if err := obj.VisitElements(func(node *yaml.RNode) error {
// recurse on each element -- re-allocating a fieldSpecFilter is
// recurse on each element -- re-allocating a Filter is
// not strictly required, but is more consistent with field
// and less likely to have side effects
// keep the entire path -- it does not contain parts for sequences
@@ -153,3 +163,18 @@ func isMatchGVK(fs types.FieldSpec, obj *yaml.RNode) (bool, error) {
return true, nil
}
func splitPath(path string) []string {
ps := strings.Split(path, "/")
var res []string
res = append(res, ps[0])
for i := 1; i < len(ps); i++ {
lastIndex := len(res) - 1
if strings.HasSuffix(res[lastIndex], "\\") {
res[lastIndex] = strings.TrimSuffix(res[lastIndex], "\\") + "/" + ps[i]
} else {
res = append(res, ps[i])
}
}
return res
}

View File

@@ -0,0 +1,535 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package fieldspec_test
import (
"bytes"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/filters/fieldspec"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
type TestCase struct {
name string
input string
expected string
filter fieldspec.Filter
fieldSpec string
error string
}
var tests = []TestCase{
{
name: "update",
fieldSpec: `
path: a/b
group: foo
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a:
b: c
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a:
b: e
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
},
},
{
name: "update-kind-not-match",
fieldSpec: `
path: a/b
group: foo
kind: Bar1
`,
input: `
apiVersion: foo/v1beta1
kind: Bar2
a:
b: c
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar2
a:
b: c
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
},
},
{
name: "update-group-not-match",
fieldSpec: `
path: a/b
group: foo1
kind: Bar
`,
input: `
apiVersion: foo2/v1beta1
kind: Bar
a:
b: c
`,
expected: `
apiVersion: foo2/v1beta1
kind: Bar
a:
b: c
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
},
},
{
name: "update-version-not-match",
fieldSpec: `
path: a/b
group: foo
version: v1beta1
kind: Bar
`,
input: `
apiVersion: foo/v1beta2
kind: Bar
a:
b: c
`,
expected: `
apiVersion: foo/v1beta2
kind: Bar
a:
b: c
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
},
},
{
name: "bad-version",
fieldSpec: `
path: a/b
group: foo
version: v1beta1
kind: Bar
`,
input: `
apiVersion: foo/v1beta2/something
kind: Bar
a:
b: c
`,
expected: `
apiVersion: foo/v1beta2/something
kind: Bar
a:
b: c
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
},
},
{
name: "bad-meta",
fieldSpec: `
path: a/b
group: foo
version: v1beta1
kind: Bar
`,
input: `
a:
b: c
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
},
error: "missing Resource metadata",
},
{
name: "miss-match-type",
fieldSpec: `
path: a/b/c
kind: Bar
`,
input: `
kind: Bar
a:
b: a
`,
error: "obj 'kind: Bar\na:\n b: a\n' at path 'a/b/c': " +
"expected sequence or mapping node",
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
},
},
{
name: "add",
fieldSpec: `
path: a/b/c/d
group: foo
create: true
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a: {}
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a: {b: {c: {d: e}}}
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
{
name: "update-in-sequence",
fieldSpec: `
path: a/b[]/c/d
group: foo
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a:
b:
- c:
d: a
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a:
b:
- c:
d: e
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
},
},
// Don't create a sequence
{
name: "empty-sequence-no-create",
fieldSpec: `
path: a/b[]/c/d
group: foo
create: true
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a: {}
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a: {}
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
// Create a new field for an element in a sequence
{
name: "empty-sequence-create",
fieldSpec: `
path: a/b[]/c/d
group: foo
create: true
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a:
b:
- c: {}
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a:
b:
- c: {d: e}
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
{
name: "group v1",
fieldSpec: `
path: a/b
group: v1
create: true
kind: Bar
`,
input: `
apiVersion: v1
kind: Bar
`,
expected: `
apiVersion: v1
kind: Bar
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
{
name: "version v1",
fieldSpec: `
path: a/b
version: v1
create: true
kind: Bar
`,
input: `
apiVersion: v1
kind: Bar
`,
expected: `
apiVersion: v1
kind: Bar
a:
b: e
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
{
name: "successfully set field on array entry no sequence hint",
fieldSpec: `
path: spec/containers/image
version: v1
kind: Bar
`,
input: `
apiVersion: v1
kind: Bar
spec:
containers:
- image: foo
`,
expected: `
apiVersion: v1
kind: Bar
spec:
containers:
- image: bar
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("bar"),
CreateKind: yaml.ScalarNode,
},
},
{
name: "successfully set field on array entry with sequence hint",
fieldSpec: `
path: spec/containers[]/image
version: v1
kind: Bar
`,
input: `
apiVersion: v1
kind: Bar
spec:
containers:
- image: foo
`,
expected: `
apiVersion: v1
kind: Bar
spec:
containers:
- image: bar
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("bar"),
CreateKind: yaml.ScalarNode,
},
},
{
name: "failure to set field on array entry with sequence hint in path",
fieldSpec: `
path: spec/containers[]/image
version: v1
kind: Bar
`,
input: `
apiVersion: v1
kind: Bar
spec:
containers:
`,
expected: `
apiVersion: v1
kind: Bar
spec:
containers: []
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("bar"),
CreateKind: yaml.ScalarNode,
},
},
{
name: "failure to set field on array entry, no sequence hint in path",
fieldSpec: `
path: spec/containers/image
version: v1
kind: Bar
`,
input: `
apiVersion: v1
kind: Bar
spec:
containers:
`,
expected: `
apiVersion: v1
kind: Bar
spec:
containers:
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("bar"),
CreateKind: yaml.ScalarNode,
},
},
{
name: "filedname with slash '/'",
fieldSpec: `
path: a/b\/c/d
version: v1
kind: Bar
`,
input: `
apiVersion: v1
kind: Bar
a:
b/c:
d: foo
`,
expected: `
apiVersion: v1
kind: Bar
a:
b/c:
d: bar
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("bar"),
CreateKind: yaml.ScalarNode,
},
},
{
name: "filedname with multiple '/'",
fieldSpec: `
path: a/b\/c/d\/e/f
version: v1
kind: Bar
`,
input: `
apiVersion: v1
kind: Bar
a:
b/c:
d/e:
f: foo
`,
expected: `
apiVersion: v1
kind: Bar
a:
b/c:
d/e:
f: bar
`,
filter: fieldspec.Filter{
SetValue: filtersutil.SetScalar("bar"),
CreateKind: yaml.ScalarNode,
},
},
}
func TestFilter_Filter(t *testing.T) {
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
err := yaml.Unmarshal([]byte(test.fieldSpec), &test.filter.FieldSpec)
if !assert.NoError(t, err) {
t.FailNow()
}
out := &bytes.Buffer{}
rw := &kio.ByteReadWriter{
Reader: bytes.NewBufferString(test.input),
Writer: out,
OmitReaderAnnotations: true,
}
// run the filter
err = kio.Pipeline{
Inputs: []kio.Reader{rw},
Filters: []kio.Filter{kio.FilterAll(test.filter)},
Outputs: []kio.Writer{rw},
}.Execute()
if test.error != "" {
if !assert.EqualError(t, err, test.error) {
t.FailNow()
}
// stop rest of test
return
}
if !assert.NoError(t, err) {
t.FailNow()
}
// check results
if !assert.Equal(t,
strings.TrimSpace(test.expected),
strings.TrimSpace(out.String())) {
t.FailNow()
}
})
}
}

View File

@@ -1,6 +1,6 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package fsslice
package fieldspec
import (
"strings"

View File

@@ -1,6 +1,6 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package fsslice
package fieldspec
import (
"strings"

View File

@@ -0,0 +1,33 @@
package filtersutil
import (
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// SetFn is a function that accepts an RNode to possibly modify.
type SetFn func(*yaml.RNode) error
// SetScalar returns a SetFn to set a scalar value
func SetScalar(value string) SetFn {
return func(node *yaml.RNode) error {
return node.PipeE(yaml.FieldSetter{StringValue: value})
}
}
// SetEntry returns a SetFn to set an entry in a map
func SetEntry(key, value, tag string) SetFn {
n := &yaml.Node{
Kind: yaml.ScalarNode,
Value: value,
Tag: tag,
}
if tag == yaml.NodeTagString && yaml.IsYaml1_1NonString(n) {
n.Style = yaml.DoubleQuotedStyle
}
return func(node *yaml.RNode) error {
return node.PipeE(yaml.FieldSetter{
Name: key,
Value: yaml.NewRNode(n),
})
}
}

View File

@@ -1,6 +1,6 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package fsslice contains a yaml.Filter to modify a resource using an
// FsSlice to identify fields to be updated within the resource.
// Package fsslice contains a yaml.Filter to modify a resource if
// it matches one or more FieldSpec entries.
package fsslice

View File

@@ -8,6 +8,7 @@ import (
"log"
"os"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/filters/fsslice"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
@@ -30,7 +31,7 @@ metadata:
}
fltr := fsslice.Filter{
CreateKind: yaml.ScalarNode,
SetValue: fsslice.SetScalar("green"),
SetValue: filtersutil.SetScalar("green"),
FsSlice: []types.FieldSpec{
{Path: "a/b", CreateIfNotPresent: true},
},

View File

@@ -4,48 +4,22 @@
package fsslice
import (
"sigs.k8s.io/kustomize/api/filters/fieldspec"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// SetFn sets a value
type SetFn func(*yaml.RNode) error
// SetScalar returns a SetFn to set a scalar value
func SetScalar(value string) SetFn {
return func(node *yaml.RNode) error {
return node.PipeE(yaml.FieldSetter{StringValue: value})
}
}
// SetEntry returns a SetFn to set an entry in a map
func SetEntry(key, value, tag string) SetFn {
n := &yaml.Node{
Kind: yaml.ScalarNode,
Value: value,
Tag: tag,
}
if tag == yaml.StringTag && yaml.IsYaml1_1NonString(n) {
n.Style = yaml.DoubleQuotedStyle
}
return func(node *yaml.RNode) error {
return node.PipeE(yaml.FieldSetter{
Name: key,
Value: yaml.NewRNode(n),
})
}
}
var _ yaml.Filter = Filter{}
// Filter uses an FsSlice to modify fields on a single object
// Filter ranges over an FsSlice to modify fields on a single object.
// An FsSlice is a range of FieldSpecs. A FieldSpec is a GVK plus a path.
type Filter struct {
// FieldSpecList list of FieldSpecs to set
FsSlice types.FsSlice `yaml:"fsSlice"`
// SetValue is called on each field that matches one of the FieldSpecs
SetValue SetFn
SetValue filtersutil.SetFn
// CreateKind is used to create fields that do not exist
CreateKind yaml.Kind
@@ -59,7 +33,7 @@ func (fltr Filter) Filter(obj *yaml.RNode) (*yaml.RNode, error) {
// apply this FieldSpec
// create a new filter for each iteration because they
// store internal state about the field paths
_, err := (&fieldSpecFilter{
_, err := (&fieldspec.Filter{
FieldSpec: fltr.FsSlice[i],
SetValue: fltr.SetValue,
CreateKind: fltr.CreateKind,

View File

@@ -9,335 +9,77 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/filters/fsslice"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
. "sigs.k8s.io/kustomize/api/filters/fsslice"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
type TestCase struct {
name string
input string
expected string
filter fsslice.Filter
filter Filter
fsSlice string
error string
}
var tests = []TestCase{
{
name: "update",
var tests = map[string]TestCase{
"empty": {
fsSlice: `
- path: a/b
group: foo
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
apiVersion: foo/v1
kind: Bar
a:
b: c
`,
expected: `
apiVersion: foo/v1beta1
apiVersion: foo/v1
kind: Bar
a:
b: e
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
},
},
{
name: "update-kind-not-match",
fsSlice: `
- path: a/b
group: foo
kind: Bar1
`,
input: `
apiVersion: foo/v1beta1
kind: Bar2
a:
b: c
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar2
a:
b: c
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
},
},
{
name: "update-group-not-match",
fsSlice: `
- path: a/b
group: foo1
kind: Bar
`,
input: `
apiVersion: foo2/v1beta1
kind: Bar
a:
b: c
`,
expected: `
apiVersion: foo2/v1beta1
kind: Bar
a:
b: c
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
},
},
{
name: "update-version-not-match",
fsSlice: `
- path: a/b
group: foo
version: v1beta1
kind: Bar
`,
input: `
apiVersion: foo/v1beta2
kind: Bar
a:
b: c
`,
expected: `
apiVersion: foo/v1beta2
kind: Bar
a:
b: c
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
},
},
{
name: "bad-version",
fsSlice: `
- path: a/b
group: foo
version: v1beta1
kind: Bar
`,
input: `
apiVersion: foo/v1beta2/something
kind: Bar
a:
b: c
`,
expected: `
apiVersion: foo/v1beta2/something
kind: Bar
a:
b: c
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
},
},
{
name: "bad-meta",
fsSlice: `
- path: a/b
group: foo
version: v1beta1
kind: Bar
`,
input: `
a:
b: c
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
},
error: "missing Resource metadata",
},
{
name: "miss-match-type",
fsSlice: `
- path: a/b/c
kind: Bar
`,
input: `
kind: Bar
a:
b: a
`,
error: "obj kind: Bar\na:\n b: a\n at path a/b/c: unsupported yaml node",
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
},
},
{
name: "add",
fsSlice: `
- path: a/b/c/d
group: foo
create: true
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a: {}
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a: {b: {c: {d: e}}}
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
filter: Filter{
SetValue: filtersutil.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
{
name: "update-in-sequence",
fsSlice: `
- path: a/b[]/c/d
group: foo
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a:
b:
- c:
d: a
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a:
b:
- c:
d: e
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
},
},
// Don't create a sequence
{
name: "empty-sequence-no-create",
fsSlice: `
- path: a/b[]/c/d
group: foo
create: true
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a: {}
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a: {}
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
// Create a new field for an element in a sequence
{
name: "empty-sequence-create",
fsSlice: `
- path: a/b[]/c/d
group: foo
create: true
kind: Bar
`,
input: `
apiVersion: foo/v1beta1
kind: Bar
a:
b:
- c: {}
`,
expected: `
apiVersion: foo/v1beta1
kind: Bar
a:
b:
- c: {d: e}
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
{
name: "group v1",
"two": {
fsSlice: `
- path: a/b
group: v1
group: foo
version: v1
create: true
kind: Bar
`,
input: `
apiVersion: v1
kind: Bar
`,
expected: `
apiVersion: v1
kind: Bar
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
{
name: "version v1",
fsSlice: `
- path: a/b
- path: q/r[]/s/t
group: foo
version: v1
create: true
kind: Bar
`,
input: `
apiVersion: v1
apiVersion: foo/v1
kind: Bar
q:
r:
- s: {}
`,
expected: `
apiVersion: v1
apiVersion: foo/v1
kind: Bar
q:
r:
- s: {t: e}
a:
b: e
`,
filter: fsslice.Filter{
SetValue: fsslice.SetScalar("e"),
filter: Filter{
SetValue: filtersutil.SetScalar("e"),
CreateKind: yaml.ScalarNode,
},
},
}
func TestFilter_Filter(t *testing.T) {
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
func TestFilter(t *testing.T) {
for name := range tests {
test := tests[name]
t.Run(name, func(t *testing.T) {
err := yaml.Unmarshal([]byte(test.fsSlice), &test.filter.FsSlice)
if !assert.NoError(t, err) {
t.FailNow()

View File

@@ -4,17 +4,24 @@
package imagetag
import (
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/filters/fsslice"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// Filter modifies an "image tag", the value used to specify the
// name, tag, version digest etc. of (docker) container images
// used by a pod template.
type Filter struct {
// imageTag is the tag we want to apply to the inputs
// The name of the image is used as a key, and other fields
// can specify a new name, tag, etc.
ImageTag types.Image `json:"imageTag,omitempty" yaml:"imageTag,omitempty"`
// FsSlice contains the FieldSpecs to locate the namespace field
// FsSlice contains the FieldSpecs to locate an image field,
// e.g. Path: "spec/myContainers[]/image"
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
@@ -26,6 +33,12 @@ func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
}
func (f Filter) filter(node *yaml.RNode) (*yaml.RNode, error) {
// FsSlice is an allowlist, not a denyList, so to deny
// something via configuration a new config mechanism is
// needed. Until then, hardcode it.
if f.isOnDenyList(node) {
return node, nil
}
if err := node.PipeE(fsslice.Filter{
FsSlice: f.FsSlice,
SetValue: updateImageTagFn(f.ImageTag),
@@ -35,7 +48,19 @@ func (f Filter) filter(node *yaml.RNode) (*yaml.RNode, error) {
return node, nil
}
func updateImageTagFn(imageTag types.Image) fsslice.SetFn {
func (f Filter) isOnDenyList(node *yaml.RNode) bool {
meta, err := node.GetMeta()
if err != nil {
// A missing 'meta' field will cause problems elsewhere;
// ignore it here to keep the signature simple.
return false
}
// Ignore CRDs
// https://github.com/kubernetes-sigs/kustomize/issues/890
return meta.Kind == `CustomResourceDefinition`
}
func updateImageTagFn(imageTag types.Image) filtersutil.SetFn {
return func(node *yaml.RNode) error {
return node.PipeE(imageTagUpdater{
ImageTag: imageTag,

View File

@@ -19,6 +19,162 @@ func TestImageTagUpdater_Filter(t *testing.T) {
filter Filter
fsSlice types.FsSlice
}{
"ignore CustomResourceDefinition": {
input: `
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: whatever
spec:
containers:
- image: whatever
`,
expectedOutput: `
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: whatever
spec:
containers:
- image: whatever
`,
filter: Filter{
ImageTag: types.Image{
Name: "whatever",
NewName: "theImageShouldNotChangeInACrd",
},
},
fsSlice: []types.FieldSpec{
{
Path: "spec/containers/image",
},
},
},
"legacy multiple images in containers": {
input: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
containers:
- image: nginx:1.2.1
- image: nginx:2.1.2
`,
expectedOutput: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
containers:
- image: apache@12345
- image: apache@12345
`,
filter: Filter{
ImageTag: types.Image{
Name: "nginx",
NewName: "apache",
Digest: "12345",
},
},
fsSlice: []types.FieldSpec{
{
Path: "spec/containers/image",
},
},
},
"legacy both containers and initContainers": {
input: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
containers:
- image: nginx:1.2.1
- image: tomcat:1.2.3
initContainers:
- image: nginx:1.2.1
- image: apache:1.2.3
`,
expectedOutput: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
containers:
- image: apache:3.2.1
- image: tomcat:1.2.3
initContainers:
- image: apache:3.2.1
- image: apache:1.2.3
`,
filter: Filter{
ImageTag: types.Image{
Name: "nginx",
NewName: "apache",
NewTag: "3.2.1",
},
},
fsSlice: []types.FieldSpec{
{
Path: "spec/containers/image",
},
{
Path: "spec/initContainers/image",
},
},
},
"legacy updates at multiple depths": {
input: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
containers:
- image: nginx:1.2.1
- image: tomcat:1.2.3
template:
spec:
initContainers:
- image: nginx:1.2.1
- image: apache:1.2.3
`,
expectedOutput: `
apiVersion: example.com/v1
kind: Foo
metadata:
name: instance
spec:
containers:
- image: apache:3.2.1
- image: tomcat:1.2.3
template:
spec:
initContainers:
- image: apache:3.2.1
- image: apache:1.2.3
`,
filter: Filter{
ImageTag: types.Image{
Name: "nginx",
NewName: "apache",
NewTag: "3.2.1",
},
},
fsSlice: []types.FieldSpec{
{
Path: "spec/containers/image",
},
{
Path: "spec/template/spec/initContainers/image",
},
},
},
"update with digest": {
input: `
apiVersion: example.com/v1
@@ -49,6 +205,7 @@ spec:
},
},
},
"multiple matches in sequence": {
input: `
apiVersion: example.com/v1
@@ -85,6 +242,422 @@ spec:
},
},
},
"new Tag": {
input: `
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
spec:
containers:
- image: nginx:1.7.9
name: nginx-tagged
- image: nginx:latest
name: nginx-latest
- image: foobar:1
name: replaced-with-digest
- image: postgres:1.8.0
name: postgresdb
initContainers:
- image: nginx
name: nginx-notag
- image: nginx@sha256:111111111111111111
name: nginx-sha256
- image: alpine:1.8.0
name: init-alpine`,
expectedOutput: `
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
spec:
containers:
- image: nginx:v2
name: nginx-tagged
- image: nginx:v2
name: nginx-latest
- image: foobar:1
name: replaced-with-digest
- image: postgres:1.8.0
name: postgresdb
initContainers:
- image: nginx:v2
name: nginx-notag
- image: nginx:v2
name: nginx-sha256
- image: alpine:1.8.0
name: init-alpine
`,
filter: Filter{
ImageTag: types.Image{
Name: "nginx",
NewTag: "v2",
},
},
fsSlice: []types.FieldSpec{
{
Path: "spec/template/spec/containers[]/image",
},
{
Path: "spec/template/spec/initContainers[]/image",
},
},
},
"newImage": {
input: `
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
spec:
containers:
- image: nginx:1.7.9
name: nginx-tagged
- image: nginx:latest
name: nginx-latest
- image: foobar:1
name: replaced-with-digest
- image: postgres:1.8.0
name: postgresdb
initContainers:
- image: nginx
name: nginx-notag
- image: nginx@sha256:111111111111111111
name: nginx-sha256
- image: alpine:1.8.0
name: init-alpine
`,
expectedOutput: `
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
spec:
containers:
- image: busybox:1.7.9
name: nginx-tagged
- image: busybox:latest
name: nginx-latest
- image: foobar:1
name: replaced-with-digest
- image: postgres:1.8.0
name: postgresdb
initContainers:
- image: busybox
name: nginx-notag
- image: busybox@sha256:111111111111111111
name: nginx-sha256
- image: alpine:1.8.0
name: init-alpine
`,
filter: Filter{
ImageTag: types.Image{
Name: "nginx",
NewName: "busybox",
},
},
fsSlice: []types.FieldSpec{
{
Path: "spec/template/spec/containers[]/image",
},
{
Path: "spec/template/spec/initContainers[]/image",
},
},
},
"newImageAndTag": {
input: `
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
spec:
containers:
- image: nginx:1.7.9
name: nginx-tagged
- image: nginx:latest
name: nginx-latest
- image: foobar:1
name: replaced-with-digest
- image: postgres:1.8.0
name: postgresdb
initContainers:
- image: nginx
name: nginx-notag
- image: nginx@sha256:111111111111111111
name: nginx-sha256
- image: alpine:1.8.0
name: init-alpine
`,
expectedOutput: `
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
spec:
containers:
- image: busybox:v3
name: nginx-tagged
- image: busybox:v3
name: nginx-latest
- image: foobar:1
name: replaced-with-digest
- image: postgres:1.8.0
name: postgresdb
initContainers:
- image: busybox:v3
name: nginx-notag
- image: busybox:v3
name: nginx-sha256
- image: alpine:1.8.0
name: init-alpine
`,
filter: Filter{
ImageTag: types.Image{
Name: "nginx",
NewName: "busybox",
NewTag: "v3",
},
},
fsSlice: []types.FieldSpec{
{
Path: "spec/template/spec/containers[]/image",
},
{
Path: "spec/template/spec/initContainers[]/image",
},
},
},
"newDigest": {
input: `
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
spec:
containers:
- image: nginx:1.7.9
name: nginx-tagged
- image: nginx:latest
name: nginx-latest
- image: foobar:1
name: replaced-with-digest
- image: postgres:1.8.0
name: postgresdb
initContainers:
- image: nginx
name: nginx-notag
- image: nginx@sha256:111111111111111111
name: nginx-sha256
- image: alpine:1.8.0
name: init-alpine
`,
expectedOutput: `
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
spec:
containers:
- image: nginx@sha256:222222222222222222
name: nginx-tagged
- image: nginx@sha256:222222222222222222
name: nginx-latest
- image: foobar:1
name: replaced-with-digest
- image: postgres:1.8.0
name: postgresdb
initContainers:
- image: nginx@sha256:222222222222222222
name: nginx-notag
- image: nginx@sha256:222222222222222222
name: nginx-sha256
- image: alpine:1.8.0
name: init-alpine
`,
filter: Filter{
ImageTag: types.Image{
Name: "nginx",
Digest: "sha256:222222222222222222",
},
},
fsSlice: []types.FieldSpec{
{
Path: "spec/template/spec/containers/image",
},
{
Path: "spec/template/spec/initContainers/image",
},
},
},
"newImageAndDigest": {
input: `
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
spec:
containers:
- image: nginx:1.7.9
name: nginx-tagged
- image: nginx:latest
name: nginx-latest
- image: foobar:1
name: replaced-with-digest
- image: postgres:1.8.0
name: postgresdb
initContainers:
- image: nginx
name: nginx-notag
- image: nginx@sha256:111111111111111111
name: nginx-sha256
- image: alpine:1.8.0
name: init-alpine
`,
expectedOutput: `
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
spec:
containers:
- image: busybox@sha256:222222222222222222
name: nginx-tagged
- image: busybox@sha256:222222222222222222
name: nginx-latest
- image: foobar:1
name: replaced-with-digest
- image: postgres:1.8.0
name: postgresdb
initContainers:
- image: busybox@sha256:222222222222222222
name: nginx-notag
- image: busybox@sha256:222222222222222222
name: nginx-sha256
- image: alpine:1.8.0
name: init-alpine
`,
filter: Filter{
ImageTag: types.Image{
Name: "nginx",
NewName: "busybox",
Digest: "sha256:222222222222222222",
},
},
fsSlice: []types.FieldSpec{
{
Path: "spec/template/spec/containers[]/image",
},
{
Path: "spec/template/spec/initContainers[]/image",
},
},
},
"emptyContainers": {
input: `
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
containers:
`,
expectedOutput: `
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
containers: []
`,
filter: Filter{
ImageTag: types.Image{
Name: "nginx",
NewTag: "v2",
},
},
fsSlice: []types.FieldSpec{
{
Path: "spec/containers[]/image",
// CreateIfNotPresent: true,
},
},
},
"tagWithBraces": {
input: `
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
spec:
containers:
- image: some.registry.io/my-image:{GENERATED_TAG}
name: my-image
`,
expectedOutput: `
group: apps
apiVersion: v1
kind: Deployment
metadata:
name: deploy1
spec:
template:
spec:
containers:
- image: some.registry.io/my-image:my-fixed-tag
name: my-image
`,
filter: Filter{
ImageTag: types.Image{
Name: "some.registry.io/my-image",
NewTag: "my-fixed-tag",
},
},
fsSlice: []types.FieldSpec{
{
Path: "spec/template/spec/containers[]/image",
},
{
Path: "spec/template/spec/initContainers[]/image",
},
},
},
}
for tn, tc := range testCases {

View File

@@ -30,10 +30,11 @@ func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
func(node *yaml.RNode) (*yaml.RNode, error) {
for _, k := range keys {
if err := node.PipeE(fsslice.Filter{
FsSlice: f.FsSlice,
SetValue: fsslice.SetEntry(k, f.Labels[k], yaml.StringTag),
FsSlice: f.FsSlice,
SetValue: filtersutil.SetEntry(
k, f.Labels[k], yaml.NodeTagString),
CreateKind: yaml.MappingNode, // Labels are MappingNodes.
CreateTag: "!!map",
CreateTag: yaml.NodeTagMap,
}); err != nil {
return nil, err
}

View File

@@ -0,0 +1,3 @@
// Package nameref contains a kio.Filter implementation of the kustomize
// name reference transformer.
package nameref

View File

@@ -0,0 +1,233 @@
package nameref
import (
"fmt"
"sigs.k8s.io/kustomize/api/filters/fieldspec"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// Filter will update the name reference
type Filter struct {
FieldSpec types.FieldSpec `json:"fieldSpec,omitempty" yaml:"fieldSpec,omitempty"`
Referrer *resource.Resource
Target resid.Gvk
ReferralCandidates resmap.ResMap
}
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
return kio.FilterAll(yaml.FilterFunc(f.run)).Filter(nodes)
}
func (f Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
err := node.PipeE(fieldspec.Filter{
FieldSpec: f.FieldSpec,
SetValue: f.set,
})
return node, err
}
func (f Filter) set(node *yaml.RNode) error {
if yaml.IsMissingOrNull(node) {
return nil
}
switch node.YNode().Kind {
case yaml.ScalarNode:
return f.setScalar(node)
case yaml.MappingNode:
// Kind: ValidatingWebhookConfiguration
// FieldSpec is webhooks/clientConfig/service
return f.setMapping(node)
case yaml.SequenceNode:
return f.setSequence(node)
default:
return fmt.Errorf(
"node is expected to be either a string or a slice of string or a map of string")
}
}
func (f Filter) setSequence(node *yaml.RNode) error {
return applyFilterToSeq(seqFilter{
setScalarFn: f.setScalar,
setMappingFn: f.setMapping,
}, node)
}
func (f Filter) setMapping(node *yaml.RNode) error {
return setNameAndNs(
node,
f.Referrer,
f.Target,
f.ReferralCandidates,
)
}
func (f Filter) setScalar(node *yaml.RNode) error {
newValue, err := getSimpleNameField(
node.YNode().Value,
f.Referrer,
f.Target,
f.ReferralCandidates,
f.ReferralCandidates.Resources(),
)
if err != nil {
return err
}
err = filtersutil.SetScalar(newValue)(node)
if err != nil {
return err
}
return nil
}
func filterReferralCandidates(
referrer *resource.Resource,
matches []*resource.Resource) []*resource.Resource {
var ret []*resource.Resource
for _, m := range matches {
if referrer.PrefixesSuffixesEquals(m) {
ret = append(ret, m)
}
}
return ret
}
// selectReferral picks the referral among a subset of candidates.
// It returns the current name and namespace of the selected candidate.
// Note that the content of the referricalCandidateSubset slice is most of the time
// identical to the referralCandidates resmap. Still in some cases, such
// as ClusterRoleBinding, the subset only contains the resources of a specific
// namespace.
func selectReferral(
oldName string,
referrer *resource.Resource,
target resid.Gvk,
referralCandidates resmap.ResMap,
referralCandidateSubset []*resource.Resource) (string, string, error) {
for _, res := range referralCandidateSubset {
id := res.OrgId()
if id.IsSelected(&target) && res.GetOriginalName() == oldName {
matches := referralCandidates.GetMatchingResourcesByOriginalId(id.Equals)
// If there's more than one match,
// filter the matches by prefix and suffix
if len(matches) > 1 {
filteredMatches := filterReferralCandidates(referrer, matches)
if len(filteredMatches) > 1 {
return "", "", fmt.Errorf(
"multiple matches for %s:\n %v",
id, getIds(filteredMatches))
}
// Check is the match the resource we are working on
if len(filteredMatches) == 0 || res != filteredMatches[0] {
continue
}
}
// In the resource, note that it is referenced
// by the referrer.
res.AppendRefBy(referrer.CurId())
// Return transformed name of the object,
// complete with prefixes, hashes, etc.
return res.GetName(), res.GetNamespace(), nil
}
}
return oldName, "", nil
}
// utility function to replace a simple string by the new name
func getSimpleNameField(
oldName string,
referrer *resource.Resource,
target resid.Gvk,
referralCandidates resmap.ResMap,
referralCandidateSubset []*resource.Resource) (string, error) {
newName, _, err := selectReferral(oldName, referrer, target,
referralCandidates, referralCandidateSubset)
return newName, err
}
func getIds(rs []*resource.Resource) []string {
var result []string
for _, r := range rs {
result = append(result, r.CurId().String()+"\n")
}
return result
}
// utility function to replace name field within a map RNode
// and leverage the namespace field.
func setNameAndNs(
in *yaml.RNode,
referrer *resource.Resource,
target resid.Gvk,
referralCandidates resmap.ResMap) error {
if in.YNode().Kind != yaml.MappingNode {
return fmt.Errorf("expect a mapping node")
}
// Get name field
nameNode, err := in.Pipe(yaml.FieldMatcher{
Name: "name",
})
if err != nil || nameNode == nil {
return fmt.Errorf("cannot find field 'name' in node")
}
// Get namespace field
namespaceNode, err := in.Pipe(yaml.FieldMatcher{
Name: "namespace",
})
if err != nil {
return fmt.Errorf("error when find field 'namespace'")
}
// check is namespace matched
// name will bot be updated if the namespace doesn't match
subset := referralCandidates.Resources()
if namespaceNode != nil {
namespace := namespaceNode.YNode().Value
bynamespace := referralCandidates.GroupedByOriginalNamespace()
if _, ok := bynamespace[namespace]; !ok {
return nil
}
subset = bynamespace[namespace]
}
oldName := nameNode.YNode().Value
newname, newnamespace, err := selectReferral(oldName, referrer, target,
referralCandidates, subset)
if err != nil {
return err
}
if (newname == oldName) && (newnamespace == "") {
// no candidate found.
return nil
}
// set name
in.Pipe(yaml.FieldSetter{
Name: "name",
StringValue: newname,
})
if newnamespace != "" {
// We don't want value "" to replace value "default" since
// the empty string is handled as a wild card here not default namespace
// by kubernetes.
in.Pipe(yaml.FieldSetter{
Name: "namespace",
StringValue: newnamespace,
})
}
return nil
}

View File

@@ -0,0 +1,781 @@
package nameref
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
"sigs.k8s.io/kustomize/api/types"
)
func TestNamerefFilter(t *testing.T) {
testCases := map[string]struct {
input string
candidates string
expected string
filter Filter
originalNames []string
}{
"simple scalar": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: oldName
`,
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
ref:
name: newName
`,
filter: Filter{
FieldSpec: types.FieldSpec{Path: "ref/name"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
},
"sequence": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
seq:
- oldName1
- oldName2
`,
candidates: `
apiVersion: apps/v1
kind: Secret
metadata:
name: newName
---
apiVersion: apps/v1
kind: NotSecret
metadata:
name: newName2
`,
originalNames: []string{"oldName1", ""},
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
seq:
- newName
- oldName2
`,
filter: Filter{
FieldSpec: types.FieldSpec{Path: "seq"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
},
"mapping": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
map:
name: oldName
`,
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: newName
`,
filter: Filter{
FieldSpec: types.FieldSpec{Path: "map"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
},
"mapping with namespace": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
map:
name: oldName
namespace: oldNs
`,
candidates: `
apiVersion: apps/v1
kind: Secret
metadata:
name: newName
namespace: oldNs
---
apiVersion: apps/v1
kind: NotSecret
metadata:
name: newName2
`,
originalNames: []string{"oldName", ""},
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
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"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
factory := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
referrer, err := factory.FromBytes([]byte(tc.input))
if err != nil {
t.Fatal(err)
}
tc.filter.Referrer = referrer
resMapFactory := resmap.NewFactory(factory, nil)
candidatesRes, err := factory.SliceFromBytesWithNames(
tc.originalNames, []byte(tc.candidates))
if err != nil {
t.Fatal(err)
}
candidates := resMapFactory.FromResourceSlice(candidatesRes)
tc.filter.ReferralCandidates = candidates
if !assert.Equal(t,
strings.TrimSpace(tc.expected),
strings.TrimSpace(
filtertest_test.RunFilter(t, tc.input, tc.filter))) {
t.FailNow()
}
})
}
}
func TestNamerefFilterUnhappy(t *testing.T) {
testCases := map[string]struct {
input string
candidates string
expected string
filter Filter
originalNames []string
}{
"multiple match": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: oldName
`,
candidates: `
apiVersion: apps/v1
kind: Secret
metadata:
name: newName
---
apiVersion: apps/v1
kind: Secret
metadata:
name: newName2
`,
originalNames: []string{"oldName", "oldName"},
expected: "",
filter: Filter{
FieldSpec: types.FieldSpec{Path: "ref/name"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
},
"no name": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
notName: oldName
`,
candidates: `
apiVersion: apps/v1
kind: Secret
metadata:
name: newName
---
apiVersion: apps/v1
kind: Secret
metadata:
name: newName2
`,
originalNames: []string{"oldName", "oldName"},
expected: "",
filter: Filter{
FieldSpec: types.FieldSpec{Path: "ref"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
factory := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
referrer, err := factory.FromBytes([]byte(tc.input))
if err != nil {
t.Fatal(err)
}
tc.filter.Referrer = referrer
resMapFactory := resmap.NewFactory(factory, nil)
candidatesRes, err := factory.SliceFromBytesWithNames(
tc.originalNames, []byte(tc.candidates))
if err != nil {
t.Fatal(err)
}
candidates := resMapFactory.FromResourceSlice(candidatesRes)
tc.filter.ReferralCandidates = candidates
_, err = filtertest_test.RunFilterE(t, tc.input, tc.filter)
if err == nil {
t.Fatalf("expect an error")
}
if tc.expected != "" && !assert.EqualError(t, err, tc.expected) {
t.FailNow()
}
})
}
}
func TestCandidatesWithDifferentPrefixSuffix(t *testing.T) {
testCases := map[string]struct {
input string
candidates string
expected string
filter Filter
originalNames []string
prefix []string
suffix []string
inputPrefix string
inputSuffix string
err bool
}{
"prefix match": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: oldName
`,
candidates: `
apiVersion: apps/v1
kind: Secret
metadata:
name: newName
---
apiVersion: apps/v1
kind: Secret
metadata:
name: newName2
`,
originalNames: []string{"oldName", "oldName"},
prefix: []string{"prefix1", "prefix2"},
suffix: []string{"", "suffix2"},
inputPrefix: "prefix1",
inputSuffix: "",
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: newName
`,
filter: Filter{
FieldSpec: types.FieldSpec{Path: "ref/name"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
err: false,
},
"suffix match": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: oldName
`,
candidates: `
apiVersion: apps/v1
kind: Secret
metadata:
name: newName
---
apiVersion: apps/v1
kind: Secret
metadata:
name: newName2
`,
originalNames: []string{"oldName", "oldName"},
prefix: []string{"", "prefix2"},
suffix: []string{"suffix1", "suffix2"},
inputPrefix: "",
inputSuffix: "suffix1",
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: newName
`,
filter: Filter{
FieldSpec: types.FieldSpec{Path: "ref/name"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
err: false,
},
"prefix suffix both match": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: oldName
`,
candidates: `
apiVersion: apps/v1
kind: Secret
metadata:
name: newName
---
apiVersion: apps/v1
kind: Secret
metadata:
name: newName2
`,
originalNames: []string{"oldName", "oldName"},
prefix: []string{"prefix1", "prefix2"},
suffix: []string{"suffix1", "suffix2"},
inputPrefix: "prefix1",
inputSuffix: "suffix1",
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: newName
`,
filter: Filter{
FieldSpec: types.FieldSpec{Path: "ref/name"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
err: false,
},
"multiple match: both": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: oldName
`,
candidates: `
apiVersion: apps/v1
kind: Secret
metadata:
name: newName
---
apiVersion: apps/v1
kind: Secret
metadata:
name: newName2
`,
originalNames: []string{"oldName", "oldName"},
prefix: []string{"prefix", "prefix"},
suffix: []string{"suffix", "suffix"},
inputPrefix: "prefix",
inputSuffix: "suffix",
expected: "",
filter: Filter{
FieldSpec: types.FieldSpec{Path: "ref/name"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
err: true,
},
"multiple match: only prefix": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: oldName
`,
candidates: `
apiVersion: apps/v1
kind: Secret
metadata:
name: newName
---
apiVersion: apps/v1
kind: Secret
metadata:
name: newName2
`,
originalNames: []string{"oldName", "oldName"},
prefix: []string{"prefix", "prefix"},
suffix: []string{"", ""},
inputPrefix: "prefix",
inputSuffix: "",
expected: "",
filter: Filter{
FieldSpec: types.FieldSpec{Path: "ref/name"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
err: true,
},
"multiple match: only suffix": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: oldName
`,
candidates: `
apiVersion: apps/v1
kind: Secret
metadata:
name: newName
---
apiVersion: apps/v1
kind: Secret
metadata:
name: newName2
`,
originalNames: []string{"oldName", "oldName"},
prefix: []string{"", ""},
suffix: []string{"suffix", "suffix"},
inputPrefix: "",
inputSuffix: "suffix",
expected: "",
filter: Filter{
FieldSpec: types.FieldSpec{Path: "ref/name"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
err: true,
},
"no match: neither match": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: oldName
`,
candidates: `
apiVersion: apps/v1
kind: Secret
metadata:
name: newName
---
apiVersion: apps/v1
kind: Secret
metadata:
name: newName2
`,
originalNames: []string{"oldName", "oldName"},
prefix: []string{"prefix1", "prefix2"},
suffix: []string{"suffix1", "suffix2"},
inputPrefix: "prefix",
inputSuffix: "suffix",
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: oldName
`,
filter: Filter{
FieldSpec: types.FieldSpec{Path: "ref/name"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
err: false,
},
"no match: prefix doesn't match": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: oldName
`,
candidates: `
apiVersion: apps/v1
kind: Secret
metadata:
name: newName
---
apiVersion: apps/v1
kind: Secret
metadata:
name: newName2
`,
originalNames: []string{"oldName", "oldName"},
prefix: []string{"prefix1", "prefix2"},
suffix: []string{"suffix", "suffix"},
inputPrefix: "prefix",
inputSuffix: "suffix",
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: oldName
`,
filter: Filter{
FieldSpec: types.FieldSpec{Path: "ref/name"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
err: false,
},
"no match: suffix doesn't match": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: oldName
`,
candidates: `
apiVersion: apps/v1
kind: Secret
metadata:
name: newName
---
apiVersion: apps/v1
kind: Secret
metadata:
name: newName2
`,
originalNames: []string{"oldName", "oldName"},
prefix: []string{"prefix", "prefix"},
suffix: []string{"suffix1", "suffix2"},
inputPrefix: "prefix",
inputSuffix: "suffix",
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
ref:
name: oldName
`,
filter: Filter{
FieldSpec: types.FieldSpec{Path: "ref/name"},
Target: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Secret",
},
},
err: false,
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
factory := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
referrer, err := factory.FromBytes([]byte(tc.input))
if err != nil {
t.Fatal(err)
}
if tc.inputPrefix != "" {
referrer.AddNamePrefix(tc.inputPrefix)
}
if tc.inputSuffix != "" {
referrer.AddNameSuffix(tc.inputSuffix)
}
tc.filter.Referrer = referrer
resMapFactory := resmap.NewFactory(factory, nil)
candidatesRes, err := factory.SliceFromBytesWithNames(
tc.originalNames, []byte(tc.candidates))
if err != nil {
t.Fatal(err)
}
for i := range candidatesRes {
if tc.prefix[i] != "" {
candidatesRes[i].AddNamePrefix(tc.prefix[i])
}
if tc.suffix[i] != "" {
candidatesRes[i].AddNameSuffix(tc.suffix[i])
}
}
candidates := resMapFactory.FromResourceSlice(candidatesRes)
tc.filter.ReferralCandidates = candidates
if !tc.err {
if !assert.Equal(t,
strings.TrimSpace(tc.expected),
strings.TrimSpace(
filtertest_test.RunFilter(t, tc.input, tc.filter))) {
t.FailNow()
}
} else {
_, err := filtertest_test.RunFilterE(t, tc.input, tc.filter)
if err == nil {
t.Fatalf("an error is expected")
}
}
})
}
}

View File

@@ -0,0 +1,57 @@
package nameref
import (
"fmt"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
type setFn func(*yaml.RNode) error
type seqFilter struct {
setScalarFn setFn
setMappingFn setFn
}
func (sf seqFilter) Filter(node *yaml.RNode) (*yaml.RNode, error) {
if yaml.IsMissingOrNull(node) {
return node, nil
}
switch node.YNode().Kind {
case yaml.ScalarNode:
// Kind: Role/ClusterRole
// FieldSpec is rules.resourceNames
err := sf.setScalarFn(node)
return node, err
case yaml.MappingNode:
// Kind: RoleBinding/ClusterRoleBinding
// FieldSpec is subjects
// Note: The corresponding fieldSpec had been changed from
// from path: subjects/name to just path: subjects. This is
// what get mutatefield to request the mapping of the whole
// map containing namespace and name instead of just a simple
// string field containing the name
err := sf.setMappingFn(node)
return node, err
default:
return node, fmt.Errorf(
"%#v is expected to be either a string or a map of string", node)
}
}
// applyFilterToSeq will apply the filter to each element in the sequence node
func applyFilterToSeq(filter yaml.Filter, node *yaml.RNode) error {
if node.YNode().Kind != yaml.SequenceNode {
return fmt.Errorf("expect a sequence node but got %v", node.YNode().Kind)
}
for _, elem := range node.Content() {
rnode := yaml.NewRNode(elem)
err := rnode.PipeE(filter)
if err != nil {
return err
}
}
return nil
}

View File

@@ -0,0 +1,80 @@
package nameref
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
func SeqFilter(node *yaml.RNode) (*yaml.RNode, error) {
if node.YNode().Value == "aaa" {
node.YNode().SetString("ccc")
}
return node, nil
}
func TestApplyFilterToSeq(t *testing.T) {
fltr := yaml.FilterFunc(SeqFilter)
testCases := map[string]struct {
input string
expect string
}{
"replace in seq": {
input: `
- aaa
- bbb`,
expect: `
- ccc
- bbb`,
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
node, err := yaml.Parse(tc.input)
if err != nil {
t.Fatal(err)
}
err = applyFilterToSeq(fltr, node)
if err != nil {
t.Fatal(err)
}
if !assert.Equal(t,
strings.TrimSpace(tc.expect),
strings.TrimSpace(node.MustString())) {
t.Fatalf("expect:\n%s\nactual:\n%s",
strings.TrimSpace(tc.expect),
strings.TrimSpace(node.MustString()))
}
})
}
}
func TestApplyFilterToSeqUnhappy(t *testing.T) {
fltr := yaml.FilterFunc(SeqFilter)
testCases := map[string]struct {
input string
}{
"replace in seq": {
input: `
aaa`,
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
node, err := yaml.Parse(tc.input)
if err != nil {
t.Fatal(err)
}
err = applyFilterToSeq(fltr, node)
if err == nil {
t.Fatalf("expect an error")
}
})
}
}

View File

@@ -4,6 +4,8 @@
package namespace
import (
"sigs.k8s.io/kustomize/api/filters/fieldspec"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/filters/fsslice"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
@@ -42,9 +44,9 @@ func (ns Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
// transformations based on data -- :)
err := node.PipeE(fsslice.Filter{
FsSlice: ns.FsSlice,
SetValue: fsslice.SetScalar(ns.Namespace),
SetValue: filtersutil.SetScalar(ns.Namespace),
CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode
CreateTag: yaml.StringTag,
CreateTag: yaml.NodeTagString,
})
return node, err
}
@@ -67,13 +69,13 @@ 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,
// or through inlined OpenAPI on the resource as a YAML comment.
func (ns Filter) metaNamespaceHack(obj *yaml.RNode, meta yaml.ResourceMeta) error {
gvk := fsslice.GetGVK(meta)
gvk := fieldspec.GetGVK(meta)
if !gvk.IsNamespaceableKind() {
return nil
}
@@ -81,7 +83,7 @@ func (ns Filter) metaNamespaceHack(obj *yaml.RNode, meta yaml.ResourceMeta) erro
FsSlice: []types.FieldSpec{
{Path: types.MetadataNamespacePath, CreateIfNotPresent: true},
},
SetValue: fsslice.SetScalar(ns.Namespace),
SetValue: filtersutil.SetScalar(ns.Namespace),
CreateKind: yaml.ScalarNode, // Namespace is a ScalarNode
}
_, err := f.Filter(obj)
@@ -110,7 +112,7 @@ func (ns Filter) roleBindingHack(obj *yaml.RNode, meta yaml.ResourceMeta) error
// Lookup the namespace field on all elements.
// We should change the fieldspec so this isn't necessary.
obj, err := obj.Pipe(yaml.Lookup(subjectsField))
if err != nil || yaml.IsEmpty(obj) {
if err != nil || yaml.IsMissingOrNull(obj) {
return err
}
@@ -123,7 +125,7 @@ func (ns Filter) roleBindingHack(obj *yaml.RNode, meta yaml.ResourceMeta) error
name, err := o.Pipe(
yaml.Lookup("name"), yaml.Match("default"),
)
if err != nil || yaml.IsEmpty(name) {
if err != nil || yaml.IsMissingOrNull(name) {
return err
}

View File

@@ -1,3 +1,6 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package patchstrategicmerge
import (
@@ -13,9 +16,13 @@ type Filter struct {
var _ kio.Filter = Filter{}
func (pf Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
return kio.FilterAll(yaml.FilterFunc(pf.run)).Filter(nodes)
}
func (pf Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
return merge2.Merge(pf.Patch, node)
var result []*yaml.RNode
for i := range nodes {
r, err := merge2.Merge(pf.Patch, nodes[i])
if err != nil {
return nil, err
}
result = append(result, r)
}
return result, nil
}

View File

@@ -9,12 +9,11 @@ import (
"os"
"sigs.k8s.io/kustomize/api/filters/prefixsuffix"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
)
func ExampleFilter() {
fss := builtinconfig.MakeDefaultConfig().NamePrefix
err := kio.Pipeline{
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
apiVersion: example.com/v1
@@ -27,7 +26,8 @@ kind: Bar
metadata:
name: instance
`)}},
Filters: []kio.Filter{prefixsuffix.Filter{Prefix: "baz-", FsSlice: fss}},
Filters: []kio.Filter{prefixsuffix.Filter{
Prefix: "baz-", FieldSpec: types.FieldSpec{Path: "metadata/name"}}},
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
}.Execute()
if err != nil {

View File

@@ -6,7 +6,8 @@ package prefixsuffix
import (
"fmt"
"sigs.k8s.io/kustomize/api/filters/fsslice"
"sigs.k8s.io/kustomize/api/filters/fieldspec"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
@@ -17,28 +18,26 @@ type Filter struct {
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
FieldSpec types.FieldSpec `json:"fieldSpec,omitempty" yaml:"fieldSpec,omitempty"`
}
var _ kio.Filter = Filter{}
func (ns Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
return kio.FilterAll(yaml.FilterFunc(ns.run)).Filter(nodes)
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
return kio.FilterAll(yaml.FilterFunc(f.run)).Filter(nodes)
}
// Run runs the filter on a single node rather than a slice
func (ns Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
// transformations based on data -- :)
err := node.PipeE(fsslice.Filter{
FsSlice: ns.FsSlice,
SetValue: ns.set,
func (f Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
err := node.PipeE(fieldspec.Filter{
FieldSpec: f.FieldSpec,
SetValue: f.evaluateField,
CreateKind: yaml.ScalarNode, // Name is a ScalarNode
CreateTag: yaml.StringTag,
CreateTag: yaml.NodeTagString,
})
return node, err
}
func (ns Filter) set(node *yaml.RNode) error {
return fsslice.SetScalar(fmt.Sprintf(
"%s%s%s", ns.Prefix, node.YNode().Value, ns.Suffix))(node)
func (f Filter) evaluateField(node *yaml.RNode) error {
return filtersutil.SetScalar(fmt.Sprintf(
"%s%s%s", f.Prefix, node.YNode().Value, f.Suffix))(node)
}

View File

@@ -9,14 +9,12 @@ import (
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/filters/prefixsuffix"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
"sigs.k8s.io/kustomize/api/types"
)
var tests = []TestCase{
{
name: "prefix",
var tests = map[string]TestCase{
"prefix": {
input: `
apiVersion: example.com/v1
kind: Foo
@@ -40,10 +38,10 @@ metadata:
name: foo-instance
`,
filter: prefixsuffix.Filter{Prefix: "foo-"},
fs: types.FieldSpec{Path: "metadata/name"},
},
{
name: "suffix",
"suffix": {
input: `
apiVersion: example.com/v1
kind: Foo
@@ -67,10 +65,10 @@ metadata:
name: instance-foo
`,
filter: prefixsuffix.Filter{Suffix: "-foo"},
fs: types.FieldSpec{Path: "metadata/name"},
},
{
name: "prefix-suffix",
"prefix-suffix": {
input: `
apiVersion: example.com/v1
kind: Foo
@@ -94,10 +92,10 @@ metadata:
name: bar-instance-foo
`,
filter: prefixsuffix.Filter{Prefix: "bar-", Suffix: "-foo"},
fs: types.FieldSpec{Path: "metadata/name"},
},
{
name: "data-fieldspecs",
"data-fieldspecs": {
input: `
apiVersion: example.com/v1
kind: Foo
@@ -119,7 +117,7 @@ a:
apiVersion: example.com/v1
kind: Foo
metadata:
name: foo-instance
name: instance
a:
b:
c: foo-d
@@ -127,35 +125,28 @@ a:
apiVersion: example.com/v1
kind: Bar
metadata:
name: foo-instance
name: instance
a:
b:
c: foo-d
`,
filter: prefixsuffix.Filter{Prefix: "foo-"},
fsslice: []types.FieldSpec{
{
Path: "a/b/c",
},
},
fs: types.FieldSpec{Path: "a/b/c"},
},
}
type TestCase struct {
name string
input string
expected string
filter prefixsuffix.Filter
fsslice types.FsSlice
fs types.FieldSpec
}
var config = builtinconfig.MakeDefaultConfig()
func TestFilter(t *testing.T) {
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
test.filter.FsSlice = append(config.NamePrefix, test.fsslice...)
for name := range tests {
test := tests[name]
t.Run(name, func(t *testing.T) {
test.filter.FieldSpec = test.fs
if !assert.Equal(t,
strings.TrimSpace(test.expected),
strings.TrimSpace(

View File

@@ -0,0 +1,3 @@
// Package refvar contains a kio.Filter implementation of the kustomize
// refvar transformer.
package refvar

View File

@@ -0,0 +1,101 @@
package refvar
import (
"fmt"
"strconv"
"sigs.k8s.io/kustomize/api/filters/fieldspec"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
expansion2 "sigs.k8s.io/kustomize/api/internal/accumulator/expansion"
)
// Filter updates $(VAR) style variables with values.
// The fieldSpecs are the places to look for occurrences of $(VAR).
type Filter struct {
MappingFunc func(string) interface{} `json:"mappingFunc,omitempty" yaml:"mappingFunc,omitempty"`
FieldSpec types.FieldSpec `json:"fieldSpec,omitempty" yaml:"fieldSpec,omitempty"`
}
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
return kio.FilterAll(yaml.FilterFunc(f.run)).Filter(nodes)
}
func (f Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
err := node.PipeE(fieldspec.Filter{
FieldSpec: f.FieldSpec,
SetValue: f.set,
})
return node, err
}
func (f Filter) set(node *yaml.RNode) error {
if yaml.IsMissingOrNull(node) {
return nil
}
switch node.YNode().Kind {
case yaml.ScalarNode:
return f.setScalar(node)
case yaml.MappingNode:
return f.setMap(node)
case yaml.SequenceNode:
return f.setSeq(node)
default:
return fmt.Errorf("invalid type encountered %v", node.YNode().Kind)
}
}
func updateNodeValue(node *yaml.Node, newValue interface{}) {
switch newValue := newValue.(type) {
case int64:
node.Value = strconv.FormatInt(newValue, 10)
node.Tag = yaml.NodeTagInt
case bool:
node.SetString(strconv.FormatBool(newValue))
node.Tag = yaml.NodeTagBool
case float64:
node.SetString(strconv.FormatFloat(newValue, 'f', -1, 64))
node.Tag = yaml.NodeTagFloat
default:
node.SetString(newValue.(string))
node.Tag = yaml.NodeTagString
}
node.Style = 0
}
func (f Filter) setScalar(node *yaml.RNode) error {
if !yaml.IsYNodeString(node.YNode()) {
return nil
}
v := expansion2.Expand(node.YNode().Value, f.MappingFunc)
updateNodeValue(node.YNode(), v)
return nil
}
func (f Filter) setMap(node *yaml.RNode) error {
contents := node.YNode().Content
for i := 0; i < len(contents); i += 2 {
if !yaml.IsYNodeString(contents[i]) {
return fmt.Errorf("invalid map key: %s, type: %s", contents[i].Value, contents[i].Tag)
}
if !yaml.IsYNodeString(contents[i+1]) {
continue
}
newValue := expansion2.Expand(contents[i+1].Value, f.MappingFunc)
updateNodeValue(contents[i+1], newValue)
}
return nil
}
func (f Filter) setSeq(node *yaml.RNode) error {
for _, item := range node.YNode().Content {
if !yaml.IsYNodeString(item) {
return fmt.Errorf("invalid value type expect a string")
}
newValue := expansion2.Expand(item.Value, f.MappingFunc)
updateNodeValue(item, newValue)
}
return nil
}

View File

@@ -0,0 +1,293 @@
package refvar
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
expansion2 "sigs.k8s.io/kustomize/api/internal/accumulator/expansion"
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
func TestFilter(t *testing.T) {
replacementCounts := make(map[string]int)
testCases := map[string]struct {
input string
expected string
filter Filter
}{
"simple scalar": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
spec:
replicas: $(VAR)`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
spec:
replicas: 5`,
filter: Filter{
MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{
"VAR": int64(5),
}),
FieldSpec: types.FieldSpec{Path: "spec/replicas"},
},
},
"non-string scalar": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
spec:
replicas: 1`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
spec:
replicas: 1`,
filter: Filter{
MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{
"VAR": int64(5),
}),
FieldSpec: types.FieldSpec{Path: "spec/replicas"},
},
},
"wrong path": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
spec:
replicas: 1`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
spec:
replicas: 1`,
filter: Filter{
MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{
"VAR": int64(5),
}),
FieldSpec: types.FieldSpec{Path: "a/b/c"},
},
},
"sequence": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
data:
- $(FOO)
- $(BAR)
- $(BAZ)
- $(FOO)+$(BAR)
- $(BOOL)
- $(FLOAT)`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
data:
- foo
- bar
- $(BAZ)
- foo+bar
- false
- 1.23`,
filter: Filter{
MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{
"FOO": "foo",
"BAR": "bar",
"BOOL": false,
"FLOAT": 1.23,
}),
FieldSpec: types.FieldSpec{Path: "data"},
},
},
"maps": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
data:
FOO: $(FOO)
BAR: $(BAR)
BAZ: $(BAZ)
PLUS: $(FOO)+$(BAR)`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
data:
FOO: foo
BAR: bar
BAZ: $(BAZ)
PLUS: foo+bar`,
filter: Filter{
MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{
"FOO": "foo",
"BAR": "bar",
}),
FieldSpec: types.FieldSpec{Path: "data"},
},
},
"complicated case": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
data:
slice1:
- $(FOO)
slice2:
FOO: $(FOO)
BAR: $(BAR)
BOOL: false
INT: 0
SLICE:
- $(FOO)`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
data:
slice1:
- $(FOO)
slice2:
FOO: foo
BAR: bar
BOOL: false
INT: 0
SLICE:
- $(FOO)`,
filter: Filter{
MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{
"FOO": "foo",
"BAR": "bar",
}),
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 {
t.Run(tn, func(t *testing.T) {
if !assert.Equal(t,
strings.TrimSpace(tc.expected),
strings.TrimSpace(
filtertest_test.RunFilter(t, tc.input, tc.filter))) {
t.FailNow()
}
})
}
}
func TestFilterUnhappy(t *testing.T) {
replacementCounts := make(map[string]int)
testCases := map[string]struct {
input string
expectedError string
filter Filter
}{
"non-string in sequence": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
data:
slice:
- false`,
expectedError: `obj 'apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
annotations:
config.kubernetes.io/index: '0'
data:
slice:
- false
' at path 'data/slice': invalid value type expect a string`,
filter: Filter{
MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{
"VAR": int64(5),
}),
FieldSpec: types.FieldSpec{Path: "data/slice"},
},
},
"invalid key in map": {
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
data:
1: str`,
expectedError: `obj 'apiVersion: apps/v1
kind: Deployment
metadata:
name: dep
annotations:
config.kubernetes.io/index: '0'
data:
1: str
' at path 'data': invalid map key: 1, type: ` + yaml.NodeTagInt,
filter: Filter{
MappingFunc: expansion2.MappingFuncFor(replacementCounts, map[string]interface{}{
"VAR": int64(5),
}),
FieldSpec: types.FieldSpec{Path: "data"},
},
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
_, err := filtertest_test.RunFilterE(t, tc.input, tc.filter)
if !assert.EqualError(t, err, tc.expectedError) {
t.FailNow()
}
})
}
}

View File

@@ -33,10 +33,8 @@ spec:
Count: 42,
Name: "instance",
},
FsSlice: types.FsSlice{
{
Path: "spec/template/replicas",
},
FieldSpec: types.FieldSpec{
Path: "spec/template/replicas",
},
}},
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},

View File

@@ -3,7 +3,8 @@ package replicacount
import (
"strconv"
"sigs.k8s.io/kustomize/api/filters/fsslice"
"sigs.k8s.io/kustomize/api/filters/fieldspec"
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
@@ -11,10 +12,8 @@ import (
// Filter updates/sets replicas fields using the fieldSpecs
type Filter struct {
Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"`
// FsSlice contains the FieldSpecs to locate the namespace field
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"`
FieldSpec types.FieldSpec `json:"fieldSpec,omitempty" yaml:"fieldSpec,omitempty"`
}
var _ kio.Filter = Filter{}
@@ -23,27 +22,16 @@ func (rc Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
return kio.FilterAll(yaml.FilterFunc(rc.run)).Filter(nodes)
}
// run processes each node individually.
func (rc Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
meta, err := node.GetMeta()
if err != nil {
return nil, err
}
// only update resources where the name matches the Replica name.
if meta.Name != rc.Replica.Name {
return node, nil
}
err = node.PipeE(fsslice.Filter{
FsSlice: rc.FsSlice,
err := node.PipeE(fieldspec.Filter{
FieldSpec: rc.FieldSpec,
SetValue: rc.set,
CreateKind: yaml.ScalarNode, // replicas is a ScalarNode
CreateTag: yaml.IntTag,
CreateTag: yaml.NodeTagInt,
})
return node, err
}
func (rc Filter) set(node *yaml.RNode) error {
return fsslice.SetScalar(strconv.FormatInt(rc.Replica.Count, 10))(node)
return filtersutil.SetScalar(strconv.FormatInt(rc.Replica.Count, 10))(node)
}

View File

@@ -5,19 +5,16 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
"sigs.k8s.io/kustomize/api/types"
)
func TestFilter(t *testing.T) {
var config = builtinconfig.MakeDefaultConfig()
testCases := map[string]struct {
input string
expected string
filter Filter
fsslice types.FsSlice
}{
"update field": {
input: `
@@ -41,11 +38,7 @@ spec:
Name: "dep",
Count: 42,
},
},
fsslice: types.FsSlice{
{
Path: "spec/replicas",
},
FieldSpec: types.FieldSpec{Path: "spec/replicas"},
},
},
"add field": {
@@ -73,9 +66,7 @@ spec:
Name: "cus",
Count: 42,
},
},
fsslice: types.FsSlice{
{
FieldSpec: types.FieldSpec{
Path: "spec/template/replicas",
CreateIfNotPresent: true,
},
@@ -108,9 +99,7 @@ spec:
Name: "cus",
Count: 42,
},
},
fsslice: types.FsSlice{
{
FieldSpec: types.FieldSpec{
Path: "spec/template/replicas",
CreateIfNotPresent: true,
},
@@ -140,9 +129,7 @@ spec:
Name: "cus",
Count: 42,
},
},
fsslice: types.FsSlice{
{
FieldSpec: types.FieldSpec{
Path: "spec/template/replicas",
},
},
@@ -154,7 +141,6 @@ kind: Custom
metadata:
name: cus
spec:
replicas: 5
template:
replicas: 5
`,
@@ -164,7 +150,6 @@ kind: Custom
metadata:
name: cus
spec:
replicas: 42
template:
replicas: 42
`,
@@ -173,21 +158,13 @@ spec:
Name: "cus",
Count: 42,
},
},
fsslice: types.FsSlice{
{
Path: "spec/template/replicas",
},
{
Path: "spec/replicas",
},
FieldSpec: types.FieldSpec{Path: "spec/template/replicas"},
},
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
tc.filter.FsSlice = append(config.Replicas, tc.fsslice...)
if !assert.Equal(t,
strings.TrimSpace(tc.expected),
strings.TrimSpace(

View File

@@ -10,12 +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.3.4
sigs.k8s.io/kustomize/kyaml v0.8.1
sigs.k8s.io/yaml v1.2.0
)

View File

@@ -239,6 +239,7 @@ github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoD
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
@@ -306,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=
@@ -438,6 +441,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392 h1:ACG4HJsFiNMf47Y4PeRoebLNy/2lXT9EtprMuTFWt1M=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -464,11 +468,11 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -499,6 +503,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -523,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=
@@ -554,8 +561,8 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 h1:Xe2gvTZUJpsvOWUnvmL/tmhVBZUmHSvLbMjRj6NUUKo=
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
@@ -573,6 +580,7 @@ k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU=
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo=
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I=
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
@@ -580,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.3.4 h1:RhxnabYltv4mdD5+I7pIaJtae+eaTn4TiZqPT7K+C7A=
sigs.k8s.io/kustomize/kyaml v0.3.4/go.mod h1:XJL84E6sOFeNrQ7CADiemc1B0EjIxHo3OhW4o1aJYNw=
sigs.k8s.io/kustomize/kyaml v0.8.1 h1:5GRanVGU6+iq3ERTiQD9VIfyGByFVB4z4GthP8NkRYE=
sigs.k8s.io/kustomize/kyaml v0.8.1/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

@@ -8,6 +8,8 @@ import (
"encoding/json"
"fmt"
"sort"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// SortArrayAndComputeHash sorts a string array and
@@ -50,3 +52,105 @@ func Encode(hex string) (string, error) {
func Hash(data string) string {
return fmt.Sprintf("%x", sha256.Sum256([]byte(data)))
}
// HashRNode returns the hash value of input RNode
func HashRNode(node *yaml.RNode) (string, error) {
// get node kind
kindNode, err := node.Pipe(yaml.FieldMatcher{Name: "kind"})
if err != nil {
return "", err
}
kind := kindNode.YNode().Value
// calculate hash for different kinds
encoded := ""
switch kind {
case "ConfigMap":
encoded, err = encodeConfigMap(node)
case "Secret":
encoded, err = encodeSecret(node)
default:
var encodedBytes []byte
encodedBytes, err = json.Marshal(node.YNode())
encoded = string(encodedBytes)
}
if err != nil {
return "", err
}
return Encode(Hash(encoded))
}
func getNodeValues(node *yaml.RNode, paths []string) (map[string]interface{}, error) {
values := make(map[string]interface{})
for _, p := range paths {
vn, err := node.Pipe(yaml.Lookup(p))
if err != nil {
return map[string]interface{}{}, err
}
if vn == nil {
values[p] = ""
continue
}
if vn.YNode().Kind != yaml.ScalarNode {
vs, err := vn.MarshalJSON()
if err != nil {
return map[string]interface{}{}, err
}
// data, binaryData and stringData are all maps
var v map[string]interface{}
json.Unmarshal(vs, &v)
values[p] = v
} else {
values[p] = vn.YNode().Value
}
}
return values, nil
}
// encodeConfigMap encodes a ConfigMap.
// Data, Kind, and Name are taken into account.
// BinaryData is included if it's not empty to avoid useless key in output.
func encodeConfigMap(node *yaml.RNode) (string, error) {
// get fields
paths := []string{"metadata/name", "data", "binaryData"}
values, err := getNodeValues(node, paths)
if err != nil {
return "", err
}
m := map[string]interface{}{"kind": "ConfigMap", "name": values["metadata/name"],
"data": values["data"]}
if _, ok := values["binaryData"].(map[string]interface{}); ok {
m["binaryData"] = values["binaryData"]
}
// json.Marshal sorts the keys in a stable order in the encoding
data, err := json.Marshal(m)
if err != nil {
return "", err
}
return string(data), nil
}
// encodeSecret encodes a Secret.
// Data, Kind, Name, and Type are taken into account.
// StringData is included if it's not empty to avoid useless key in output.
func encodeSecret(node *yaml.RNode) (string, error) {
// get fields
paths := []string{"type", "metadata/name", "data", "stringData"}
values, err := getNodeValues(node, paths)
if err != nil {
return "", err
}
m := map[string]interface{}{"kind": "Secret", "type": values["type"],
"name": values["metadata/name"], "data": values["data"]}
if _, ok := values["stringData"].(map[string]interface{}); ok {
m["stringData"] = values["stringData"]
}
// json.Marshal sorts the keys in a stable order in the encoding
data, err := json.Marshal(m)
if err != nil {
return "", err
}
return string(data), nil
}

View File

@@ -1,12 +1,13 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package hasher_test
package hasher
import (
"strings"
"testing"
. "sigs.k8s.io/kustomize/api/hasher"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
func TestSortArrayAndComputeHash(t *testing.T) {
@@ -39,3 +40,314 @@ func TestHash(t *testing.T) {
t.Errorf("expected hash %q but got %q", expect, sum)
}
}
func TestConfigMapHash(t *testing.T) {
cases := []struct {
desc string
cmYaml string
hash string
err string
}{
// empty map
{"empty data", `
apiVersion: v1
kind: ConfigMap`, "6ct58987ht", ""},
// one key
{"one key", `
apiVersion: v1
kind: ConfigMap
data:
one: ""`, "9g67k2htb6", ""},
// three keys (tests sorting order)
{"three keys", `
apiVersion: v1
kind: ConfigMap
data:
two: 2
one: ""
three: 3`, "7757f9kkct", ""},
// empty binary data map
{"empty binary data", `
apiVersion: v1
kind: ConfigMap`, "6ct58987ht", ""},
// one key with binary data
{"one key with binary data", `
apiVersion: v1
kind: ConfigMap
binaryData:
one: ""`, "6mtk2m274t", ""},
// three keys with binary data (tests sorting order)
{"three keys with binary data", `
apiVersion: v1
kind: ConfigMap
binaryData:
two: 2
one: ""
three: 3`, "9th7kc28dg", ""},
// two keys, one with string and another with binary data
{"two keys with one each", `
apiVersion: v1
kind: ConfigMap
data:
one: ""
binaryData:
two: ""`, "698h7c7t9m", ""},
}
for _, c := range cases {
node, err := yaml.Parse(c.cmYaml)
if err != nil {
t.Fatal(err)
}
h, err := HashRNode(node)
if SkipRest(t, c.desc, err, c.err) {
continue
}
if c.hash != h {
t.Errorf("case %q, expect hash %q but got %q", c.desc, c.hash, h)
}
}
}
func TestSecretHash(t *testing.T) {
cases := []struct {
desc string
secretYaml string
hash string
err string
}{
// empty map
{"empty data", `
apiVersion: v1
kind: Secret
type: my-type`, "5gmgkf8578", ""},
// one key
{"one key", `
apiVersion: v1
kind: Secret
type: my-type
data:
one: ""`, "74bd68bm66", ""},
// three keys (tests sorting order)
{"three keys", `
apiVersion: v1
kind: Secret
type: my-type
data:
two: 2
one: ""
three: 3`, "4gf75c7476", ""},
// with stringdata
{"stringdata", `
apiVersion: v1
kind: Secret
type: my-type
data:
one: ""
stringData:
two: 2`, "c4h4264gdb", ""},
// empty stringdata
{"empty stringdata", `
apiVersion: v1
kind: Secret
type: my-type
data:
one: ""`, "74bd68bm66", ""},
}
for _, c := range cases {
node, err := yaml.Parse(c.secretYaml)
if err != nil {
t.Fatal(err)
}
h, err := HashRNode(node)
if SkipRest(t, c.desc, err, c.err) {
continue
}
if c.hash != h {
t.Errorf("case %q, expect hash %q but got %q", c.desc, c.hash, h)
}
}
}
func TestUnstructuredHash(t *testing.T) {
cases := []struct {
desc string
unstructured string
hash string
err string
}{
{"minimal", `
apiVersion: test/v1
kind: TestResource
metadata:
name: my-resource`, "244782mkb7", ""},
{"with spec", `
apiVersion: test/v1
kind: TestResource
metadata:
name: my-resource
spec:
foo: 1
bar: abc`, "59m2mdccg4", ""},
}
for _, c := range cases {
node, err := yaml.Parse(c.unstructured)
if err != nil {
t.Fatal(err)
}
h, err := HashRNode(node)
if SkipRest(t, c.desc, err, c.err) {
continue
}
if c.hash != h {
t.Errorf("case %q, expect hash %q but got %q", c.desc, c.hash, h)
}
}
}
func TestEncodeConfigMap(t *testing.T) {
cases := []struct {
desc string
cmYaml string
expect string
err string
}{
// empty map
{"empty data", `
apiVersion: v1
kind: ConfigMap`, `{"data":"","kind":"ConfigMap","name":""}`, ""},
// one key
{"one key", `
apiVersion: v1
kind: ConfigMap
data:
one: ""`, `{"data":{"one":""},"kind":"ConfigMap","name":""}`, ""},
// three keys (tests sorting order)
{"three keys", `
apiVersion: v1
kind: ConfigMap
data:
two: 2
one: ""
three: 3`, `{"data":{"one":"","three":3,"two":2},"kind":"ConfigMap","name":""}`, ""},
// empty binary map
{"empty data", `
apiVersion: v1
kind: ConfigMap`, `{"data":"","kind":"ConfigMap","name":""}`, ""},
// one key with binary data
{"one key", `
apiVersion: v1
kind: ConfigMap
binaryData:
one: ""`, `{"binaryData":{"one":""},"data":"","kind":"ConfigMap","name":""}`, ""},
// three keys with binary data (tests sorting order)
{"three keys", `
apiVersion: v1
kind: ConfigMap
binaryData:
two: 2
one: ""
three: 3`, `{"binaryData":{"one":"","three":3,"two":2},"data":"","kind":"ConfigMap","name":""}`, ""},
// two keys, one string and one binary values
{"two keys with one each", `
apiVersion: v1
kind: ConfigMap
data:
one: ""
binaryData:
two: ""`, `{"binaryData":{"two":""},"data":{"one":""},"kind":"ConfigMap","name":""}`, ""},
}
for _, c := range cases {
node, err := yaml.Parse(c.cmYaml)
if err != nil {
t.Fatal(err)
}
s, err := encodeConfigMap(node)
if SkipRest(t, c.desc, err, c.err) {
continue
}
if s != c.expect {
t.Errorf("case %q, expect %q but got %q from encode %#v", c.desc, c.expect, s, c.cmYaml)
}
}
}
func TestEncodeSecret(t *testing.T) {
cases := []struct {
desc string
secretYaml string
expect string
err string
}{
// empty map
{"empty data", `
apiVersion: v1
kind: Secret
type: my-type`, `{"data":"","kind":"Secret","name":"","type":"my-type"}`, ""},
// one key
{"one key", `
apiVersion: v1
kind: Secret
type: my-type
data:
one: ""`, `{"data":{"one":""},"kind":"Secret","name":"","type":"my-type"}`, ""},
// three keys (tests sorting order) - note json.Marshal base64 encodes the values because they come in as []byte
{"three keys", `
apiVersion: v1
kind: Secret
type: my-type
data:
two: 2
one: ""
three: 3`, `{"data":{"one":"","three":3,"two":2},"kind":"Secret","name":"","type":"my-type"}`, ""},
// with stringdata
{"stringdata", `
apiVersion: v1
kind: Secret
type: my-type
data:
one: ""
stringData:
two: 2`, `{"data":{"one":""},"kind":"Secret","name":"","stringData":{"two":2},"type":"my-type"}`, ""},
// empty stringdata
{"empty stringdata", `
apiVersion: v1
kind: Secret
type: my-type
data:
one: ""`, `{"data":{"one":""},"kind":"Secret","name":"","type":"my-type"}`, ""},
}
for _, c := range cases {
node, err := yaml.Parse(c.secretYaml)
if err != nil {
t.Fatal(err)
}
s, err := encodeSecret(node)
if SkipRest(t, c.desc, err, c.err) {
continue
}
if s != c.expect {
t.Errorf("case %q, expect %q but got %q from encode %#v", c.desc, c.expect, s, c.secretYaml)
}
}
}
// SkipRest returns true if there was a non-nil error or if we expected an error that didn't happen,
// and logs the appropriate error on the test object.
// The return value indicates whether we should skip the rest of the test case due to the error result.
func SkipRest(t *testing.T, desc string, err error, contains string) bool {
if err != nil {
if len(contains) == 0 {
t.Errorf("case %q, expect nil error but got %q", desc, err.Error())
} else if !strings.Contains(err.Error(), contains) {
t.Errorf("case %q, expect error to contain %q but got %q", desc, contains, err.Error())
}
return true
} else if len(contains) > 0 {
t.Errorf("case %q, expect error to contain %q but got nil error", desc, contains)
return true
}
return false
}

View File

@@ -38,35 +38,68 @@ type Loader interface {
Cleanup() error
}
// Kunstructured allows manipulation of k8s objects
// that do not have Golang structs.
// Kunstructured represents a Kubernetes Resource Model object.
type Kunstructured interface {
// Several uses.
Copy() Kunstructured
// Used by Resource.Replace, which in turn is used in many places, e.g.
// - resource.Resource.Merge
// - resWrangler.appendReplaceOrMerge (AbsorbAll)
// - api.internal.k8sdeps.transformer.patch.conflictdetector
GetAnnotations() map[string]string
GetBool(path string) (bool, error)
// Used by ResAccumulator and ReplacementTransformer.
GetFieldValue(string) (interface{}, error)
GetFloat64(path string) (float64, error)
// Used by Resource.OrgId
GetGvk() resid.Gvk
GetInt64(path string) (int64, error)
// Used by resource.Factory.SliceFromBytes
GetKind() string
// Used by Resource.Replace
GetLabels() map[string]string
GetMap(path string) (map[string]interface{}, error)
// Used by Resource.CurId and resource factory.
GetName() string
// Used by special case code in
// ResMap.SubsetThatCouldBeReferencedByResource
GetSlice(path string) ([]interface{}, error)
// GetString returns the value of a string field.
// Used by Resource.GetNamespace
GetString(string) (string, error)
GetStringMap(path string) (map[string]string, error)
GetStringSlice(string) ([]string, error)
// Several uses.
Map() map[string]interface{}
// Used by Resource.AsYAML and Resource.String
MarshalJSON() ([]byte, error)
// Used by resWrangler.Select
MatchesAnnotationSelector(selector string) (bool, error)
// Used by resWrangler.Select
MatchesLabelSelector(selector string) (bool, error)
Patch(Kunstructured) error
// Used by Resource.Replace.
SetAnnotations(map[string]string)
// Used by PatchStrategicMergeTransformer.
SetGvk(resid.Gvk)
// Used by Resource.Replace and used to remove "validated by" labels.
SetLabels(map[string]string)
SetMap(map[string]interface{})
// Used by Resource.Replace.
SetName(string)
// Used by Resource.Replace.
SetNamespace(string)
// Needed, for now, by kyaml/filtersutil.ApplyToJSON.
UnmarshalJSON([]byte) error
}

View File

@@ -4,14 +4,12 @@
package accumulator
import (
"fmt"
"log"
"sigs.k8s.io/kustomize/api/filters/nameref"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
)
type nameReferenceTransformer struct {
@@ -86,16 +84,12 @@ func (o *nameReferenceTransformer) Transform(m resmap.ResMap) error {
if candidates == nil {
candidates = m.SubsetThatCouldBeReferencedByResource(referrer)
}
err := transform.MutateField(
referrer.Map(),
fSpec.PathSlice(),
fSpec.CreateIfNotPresent,
o.getNewNameFunc(
// referrer could be an HPA instance,
// target could be Gvk for Deployment,
// candidate a list of resources "reachable"
// from the HPA.
referrer, target.Gvk, candidates))
err := filtersutil.ApplyToJSON(nameref.Filter{
FieldSpec: fSpec,
Referrer: referrer,
Target: target.Gvk,
ReferralCandidates: candidates,
}, referrer)
if err != nil {
return err
}
@@ -105,165 +99,3 @@ func (o *nameReferenceTransformer) Transform(m resmap.ResMap) error {
}
return nil
}
// selectReferral picks the referral among a subset of candidates.
// It returns the current name and namespace of the selected candidate.
// Note that the content of the referricalCandidateSubset slice is most of the time
// identical to the referralCandidates resmap. Still in some cases, such
// as ClusterRoleBinding, the subset only contains the resources of a specific
// namespace.
func (o *nameReferenceTransformer) selectReferral(
oldName string,
referrer *resource.Resource,
target resid.Gvk,
referralCandidates resmap.ResMap,
referralCandidateSubset []*resource.Resource) (interface{}, interface{}, error) {
for _, res := range referralCandidateSubset {
id := res.OrgId()
if id.IsSelected(&target) && res.GetOriginalName() == oldName {
matches := referralCandidates.GetMatchingResourcesByOriginalId(id.Equals)
// If there's more than one match, there's no way
// to know which one to pick, so emit error.
if len(matches) > 1 {
return nil, nil, fmt.Errorf(
"multiple matches for %s:\n %v",
id, getIds(matches))
}
// In the resource, note that it is referenced
// by the referrer.
res.AppendRefBy(referrer.CurId())
// Return transformed name of the object,
// complete with prefixes, hashes, etc.
return res.GetName(), res.GetNamespace(), nil
}
}
return oldName, nil, nil
}
// utility function to replace a simple string by the new name
func (o *nameReferenceTransformer) getSimpleNameField(
oldName string,
referrer *resource.Resource,
target resid.Gvk,
referralCandidates resmap.ResMap,
referralCandidateSubset []*resource.Resource) (interface{}, error) {
newName, _, err := o.selectReferral(oldName, referrer, target,
referralCandidates, referralCandidateSubset)
return newName, err
}
// utility function to replace name field within a map[string]interface{}
// and leverage the namespace field.
func (o *nameReferenceTransformer) getNameAndNsStruct(
inMap map[string]interface{},
referrer *resource.Resource,
target resid.Gvk,
referralCandidates resmap.ResMap) (interface{}, error) {
// Example:
if _, ok := inMap["name"]; !ok {
return nil, fmt.Errorf(
"%#v is expected to contain a name field", inMap)
}
oldName, ok := inMap["name"].(string)
if !ok {
return nil, fmt.Errorf(
"%#v is expected to contain a name field of type string", oldName)
}
subset := referralCandidates.Resources()
if namespacevalue, ok := inMap["namespace"]; ok {
namespace := namespacevalue.(string)
bynamespace := referralCandidates.GroupedByOriginalNamespace()
if _, ok := bynamespace[namespace]; !ok {
return inMap, nil
}
subset = bynamespace[namespace]
}
newname, newnamespace, err := o.selectReferral(oldName, referrer, target,
referralCandidates, subset)
if err != nil {
return nil, err
}
if (newname == oldName) && (newnamespace == nil) {
// no candidate found.
return inMap, nil
}
inMap["name"] = newname
if newnamespace != "" {
// We don't want value "" to replace value "default" since
// the empty string is handled as a wild card here not default namespace
// by kubernetes.
inMap["namespace"] = newnamespace
}
return inMap, nil
}
func (o *nameReferenceTransformer) getNewNameFunc(
referrer *resource.Resource,
target resid.Gvk,
referralCandidates resmap.ResMap) func(in interface{}) (interface{}, error) {
return func(in interface{}) (interface{}, error) {
switch thing := in.(type) {
case string:
return o.getSimpleNameField(thing, referrer, target,
referralCandidates, referralCandidates.Resources())
case map[string]interface{}:
// Kind: ValidatingWebhookConfiguration
// FieldSpec is webhooks/clientConfig/service
return o.getNameAndNsStruct(thing, referrer, target,
referralCandidates)
case []interface{}:
for idx, item := range thing {
switch value := item.(type) {
case string:
// Kind: Role/ClusterRole
// FieldSpec is rules.resourceNames
newName, err := o.getSimpleNameField(value, referrer, target,
referralCandidates, referralCandidates.Resources())
if err != nil {
return nil, err
}
thing[idx] = newName
case map[string]interface{}:
// Kind: RoleBinding/ClusterRoleBinding
// FieldSpec is subjects
// Note: The corresponding fieldSpec had been changed from
// from path: subjects/name to just path: subjects. This is
// what get mutatefield to request the mapping of the whole
// map containing namespace and name instead of just a simple
// string field containing the name
newMap, err := o.getNameAndNsStruct(value, referrer, target,
referralCandidates)
if err != nil {
return nil, err
}
thing[idx] = newMap
default:
return nil, fmt.Errorf(
"%#v is expected to be either a []string or a []map[string]interface{}", in)
}
}
return in, nil
default:
return nil, fmt.Errorf(
"%#v is expected to be either a string or a []interface{}", in)
}
}
}
func getIds(rs []*resource.Resource) []string {
var result []string
for _, r := range rs {
result = append(result, r.CurId().String()+"\n")
}
return result
}

View File

@@ -520,7 +520,7 @@ func TestNameReferenceUnhappyRun(t *testing.T) {
},
},
}).ResMap(),
expectedErr: "is expected to contain a name field"},
expectedErr: "cannot find field 'name' in node"},
}
nrt := newNameReferenceTransformer(builtinconfig.MakeDefaultConfig().NameReference)

View File

@@ -4,13 +4,12 @@
package accumulator
import (
"fmt"
expansion2 "sigs.k8s.io/kustomize/api/internal/accumulator/expansion"
"sigs.k8s.io/kustomize/api/filters/refvar"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
)
type refVarTransformer struct {
@@ -31,59 +30,6 @@ func newRefVarTransformer(
}
}
// replaceVars accepts as 'in' a string, or string array, which can have
// embedded instances of $VAR style variables, e.g. a container command string.
// The function returns the string with the variables expanded to their final
// values.
func (rv *refVarTransformer) replaceVars(in interface{}) (interface{}, error) {
switch vt := in.(type) {
case []interface{}:
var xs []interface{}
for _, a := range in.([]interface{}) {
x, ok := a.(string)
if !ok {
return nil, fmt.Errorf("expected array of strings, found %v", in)
}
xs = append(xs, expansion2.Expand(x, rv.mappingFunc))
}
return xs, nil
case map[string]interface{}:
inMap := in.(map[string]interface{})
xs := make(map[string]interface{}, len(inMap))
for k, v := range inMap {
s, ok := v.(string)
if !ok {
// This field can not contain a $(VAR) since it is not
// of string type. For instance .spec.replicas: 3 in
// a Deployment object
xs[k] = v
} else {
// This field can potentially contains a $(VAR) since it is
// of string type. For instance .spec.replicas: $(REPLICAS)
// in a Deployment object
xs[k] = expansion2.Expand(s, rv.mappingFunc)
}
}
return xs, nil
case interface{}:
s, ok := in.(string)
if !ok {
// This field can not contain a $(VAR) since it is not of string type.
return in, nil
}
// This field can potentially contain a $(VAR) since it is
// of string type.
return expansion2.Expand(s, rv.mappingFunc), nil
// staticcheck erroneously claims that `case nil`
// is unreachable here, so suppressing it.
//nolint:staticcheck
case nil:
return nil, nil
default:
return "", fmt.Errorf("invalid type encountered %T", vt)
}
}
// UnusedVars returns slice of Var names that were unused
// after a Transform run.
func (rv *refVarTransformer) UnusedVars() []string {
@@ -104,12 +50,12 @@ func (rv *refVarTransformer) Transform(m resmap.ResMap) error {
rv.replacementCounts, rv.varMap)
for _, res := range m.Resources() {
for _, fieldSpec := range rv.fieldSpecs {
if res.OrgId().IsSelected(&fieldSpec.Gvk) {
if err := transform.MutateField(
res.Map(), fieldSpec.PathSlice(),
false, rv.replaceVars); err != nil {
return err
}
err := filtersutil.ApplyToJSON(refvar.Filter{
MappingFunc: rv.mappingFunc,
FieldSpec: fieldSpec,
}, res)
if err != nil {
return err
}
}
}

View File

@@ -44,7 +44,6 @@ func TestRefVarTransformer(t *testing.T) {
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/map"},
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/slice"},
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/interface"},
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/nil"},
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/num"},
},
res: resmaptest_test.NewRmBuilder(
@@ -63,7 +62,7 @@ func TestRefVarTransformer(t *testing.T) {
"item4": "$(BAZ)+$(BAZ)",
"item5": "$(BOO)",
"item6": "if $(BOO)",
"item7": 2019,
"item7": int64(2019),
},
"slice": []interface{}{
"$(FOO)",
@@ -74,8 +73,7 @@ func TestRefVarTransformer(t *testing.T) {
"if $(BOO)",
},
"interface": "$(FOO)",
"nil": nil,
"num": 2019,
"num": int64(2019),
}}).ResMap(),
},
expected: expected{
@@ -95,7 +93,7 @@ func TestRefVarTransformer(t *testing.T) {
"item4": "5+5",
"item5": true,
"item6": "if true",
"item7": 2019,
"item7": int64(2019),
},
"slice": []interface{}{
"replacementForFoo",
@@ -106,8 +104,7 @@ func TestRefVarTransformer(t *testing.T) {
"if true",
},
"interface": "replacementForFoo",
"nil": nil,
"num": 2019,
"num": int64(2019),
}}).ResMap(),
unused: []string{"BAR"},
},
@@ -131,7 +128,41 @@ func TestRefVarTransformer(t *testing.T) {
"slice": []interface{}{5}, // noticeably *not* a []string
}}).ResMap(),
},
errMessage: "expected array of strings, found [5]",
errMessage: `obj '{"apiVersion": "v1", "data": {"slice": [5]}, "kind": "ConfigMap", "metadata": {"name": "cm1"}}
' at path 'data/slice': invalid value type expect a string`,
},
{
description: "var replacement in nil",
given: given{
varMap: map[string]interface{}{},
fs: []types.FieldSpec{
{Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data/nil"},
},
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(),
},
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

@@ -16,8 +16,10 @@ github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmU
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
@@ -72,6 +74,7 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM=
@@ -91,11 +94,13 @@ github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
@@ -110,6 +115,7 @@ github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsd
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw=
github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk=
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
@@ -120,6 +126,7 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
@@ -242,6 +249,7 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -263,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=
@@ -330,6 +340,7 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@@ -353,6 +364,7 @@ github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOV
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yujunz/go-getter v1.4.1-lite h1:FhvNc94AXMZkfqUwfMKhnQEC9phkphSGdPTL7tIdhOM=
@@ -404,8 +416,6 @@ golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -462,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=
@@ -494,7 +505,8 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 h1:Xe2gvTZUJpsvOWUnvmL/tmhVBZUmHSvLbMjRj6NUUKo=
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
@@ -515,7 +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.3.4/go.mod h1:XJL84E6sOFeNrQ7CADiemc1B0EjIxHo3OhW4o1aJYNw=
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=

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package patch
package merge
import (
"encoding/json"
@@ -20,18 +20,20 @@ import (
type conflictDetector interface {
hasConflict(patch1, patch2 *resource.Resource) (bool, error)
findConflict(conflictingPatchIdx int, patches []*resource.Resource) (*resource.Resource, error)
findConflict(
conflictingPatchIdx int,
patches []*resource.Resource) (*resource.Resource, error)
mergePatches(patch1, patch2 *resource.Resource) (*resource.Resource, error)
}
type jsonMergePatch struct {
rf *resource.Factory
resourceFactory *resource.Factory
}
var _ conflictDetector = &jsonMergePatch{}
func newJMPConflictDetector(rf *resource.Factory) conflictDetector {
return &jsonMergePatch{rf: rf}
return &jsonMergePatch{resourceFactory: rf}
}
func (jmp *jsonMergePatch) hasConflict(
@@ -40,7 +42,8 @@ func (jmp *jsonMergePatch) hasConflict(
}
func (jmp *jsonMergePatch) findConflict(
conflictingPatchIdx int, patches []*resource.Resource) (*resource.Resource, error) {
conflictingPatchIdx int,
patches []*resource.Resource) (*resource.Resource, error) {
for i, patch := range patches {
if i == conflictingPatchIdx {
continue
@@ -77,7 +80,7 @@ func (jmp *jsonMergePatch) mergePatches(
}
mergedMap := make(map[string]interface{})
err = json.Unmarshal(mergedBytes, &mergedMap)
return jmp.rf.FromMap(mergedMap), err
return jmp.resourceFactory.FromMap(mergedMap), err
}
type strategicMergePatch struct {
@@ -94,13 +97,15 @@ func newSMPConflictDetector(
return &strategicMergePatch{lookupPatchMeta: lookupPatchMeta, rf: rf}, err
}
func (smp *strategicMergePatch) hasConflict(p1, p2 *resource.Resource) (bool, error) {
func (smp *strategicMergePatch) hasConflict(
p1, p2 *resource.Resource) (bool, error) {
return strategicpatch.MergingMapsHaveConflicts(
p1.Map(), p2.Map(), smp.lookupPatchMeta)
}
func (smp *strategicMergePatch) findConflict(
conflictingPatchIdx int, patches []*resource.Resource) (*resource.Resource, error) {
conflictingPatchIdx int,
patches []*resource.Resource) (*resource.Resource, error) {
for i, patch := range patches {
if i == conflictingPatchIdx {
continue
@@ -122,10 +127,12 @@ func (smp *strategicMergePatch) findConflict(
return nil, nil
}
func (smp *strategicMergePatch) mergePatches(patch1, patch2 *resource.Resource) (*resource.Resource, error) {
func (smp *strategicMergePatch) mergePatches(
patch1, patch2 *resource.Resource) (*resource.Resource, error) {
if hasDeleteDirectiveMarker(patch2.Map()) {
if hasDeleteDirectiveMarker(patch1.Map()) {
return nil, fmt.Errorf("cannot merge patches both containing '$patch: delete' directives")
return nil, fmt.Errorf(
"cannot merge patches both containing '$patch: delete' directives")
}
patch1, patch2 = patch2, patch1
}
@@ -134,10 +141,21 @@ func (smp *strategicMergePatch) mergePatches(patch1, patch2 *resource.Resource)
return smp.rf.FromMap(mergeJSONMap), err
}
// MergePatches merge and index patches by OrgId.
// It errors out if there is conflict between patches.
func MergePatches(patches []*resource.Resource,
rf *resource.Factory) (resmap.ResMap, error) {
type merginatorImpl struct {
rf *resource.Factory
}
// NewMerginator returns a new implementation of resmap.Merginator.
func NewMerginator(rf *resource.Factory) resmap.Merginator {
return &merginatorImpl{rf: rf}
}
var _ resmap.Merginator = (*merginatorImpl)(nil)
// Merge merges the incoming resources into a new resmap.ResMap.
// Returns an error on conflict.
func (m *merginatorImpl) Merge(
patches []*resource.Resource) (resmap.ResMap, error) {
rc := resmap.New()
for ix, patch := range patches {
id := patch.OrgId()
@@ -156,9 +174,9 @@ func MergePatches(patches []*resource.Resource,
}
var cd conflictDetector
if err != nil {
cd = newJMPConflictDetector(rf)
cd = newJMPConflictDetector(m.rf)
} else {
cd, err = newSMPConflictDetector(versionedObj, rf)
cd, err = newSMPConflictDetector(versionedObj, m.rf)
if err != nil {
return nil, err
}

View File

@@ -1,25 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package transformer provides transformer factory
package transformer
import (
"sigs.k8s.io/kustomize/api/internal/k8sdeps/transformer/patch"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
)
// FactoryImpl makes patch transformer and name hash transformer
type FactoryImpl struct{}
// NewFactoryImpl makes a new factoryImpl instance
func NewFactoryImpl() *FactoryImpl {
return &FactoryImpl{}
}
func (p *FactoryImpl) MergePatches(patches []*resource.Resource,
rf *resource.Factory) (
resmap.ResMap, error) {
return patch.MergePatches(patches, rf)
}

View File

@@ -0,0 +1,25 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package merge
import (
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
)
// Merginator implements resmap.Merginator using kyaml libs.
type Merginator struct {
}
var _ resmap.Merginator = (*Merginator)(nil)
func NewMerginator(_ *resource.Factory) *Merginator {
return &Merginator{}
}
// Merge implements resmap.Merginator
func (m Merginator) Merge(
resources []*resource.Resource) (resmap.ResMap, error) {
panic("TODO(#Merginator): implement Merge")
}

View File

@@ -0,0 +1,4 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package merge_test

View File

@@ -173,11 +173,11 @@ func (p *FnPlugin) invokePlugin(input []byte) ([]byte, error) {
// TODO(donnyxia): This is actually not used by generator and only used to bypass a kio limitation.
// Need better solution.
if input == nil {
yaml, err := functionConfig.String()
yml, err := functionConfig.String()
if err != nil {
return nil, err
}
input = []byte(yaml)
input = []byte(yml)
}
// Configure and Execute Fn. We don't need to convert resources to ResourceList here

View File

@@ -65,8 +65,8 @@ func TestLoader(t *testing.T) {
t.Fatal(err)
}
for _, behavior := range []types.BuiltinPluginLoadingOptions{
types.BploUseStaticallyLinked,
types.BploLoadFromFileSys} {
/* types.BploUseStaticallyLinked,
types.BploLoadFromFileSys */} {
c, err := konfig.EnabledPluginConfig(behavior)
if err != nil {
t.Fatal(err)

View File

@@ -4,7 +4,6 @@
package target
import (
"bytes"
"encoding/json"
"fmt"
"strings"
@@ -18,7 +17,6 @@ import (
"sigs.k8s.io/kustomize/api/internal/plugins/loader"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
@@ -29,7 +27,6 @@ type KustTarget struct {
ldr ifc.Loader
validator ifc.Validator
rFactory *resmap.Factory
tFactory resmap.PatchFactory
pLdr *loader.Loader
}
@@ -38,13 +35,11 @@ func NewKustTarget(
ldr ifc.Loader,
validator ifc.Validator,
rFactory *resmap.Factory,
tFactory resmap.PatchFactory,
pLdr *loader.Loader) *KustTarget {
return &KustTarget{
ldr: ldr,
validator: validator,
rFactory: rFactory,
tFactory: tFactory,
pLdr: pLdr,
}
}
@@ -60,7 +55,7 @@ func (kt *KustTarget) Load() error {
return err
}
var k types.Kustomization
err = unmarshal(content, &k)
err = k.Unmarshal(content)
if err != nil {
return err
}
@@ -104,18 +99,8 @@ func loadKustFile(ldr ifc.Loader) ([]byte, error) {
}
}
func unmarshal(y []byte, o interface{}) error {
j, err := yaml.YAMLToJSON(y)
if err != nil {
return err
}
dec := json.NewDecoder(bytes.NewReader(j))
dec.DisallowUnknownFields()
return dec.Decode(o)
}
// MakeCustomizedResMap creates a fully customized ResMap
// per the instructions contained in its kustomiztion instance.
// per the instructions contained in its kustomization instance.
func (kt *KustTarget) MakeCustomizedResMap() (resmap.ResMap, error) {
return kt.makeCustomizedResMap()
}
@@ -269,8 +254,7 @@ func (kt *KustTarget) runTransformers(ra *accumulator.ResAccumulator) error {
return err
}
r = append(r, lts...)
t := transform.NewMultiTransformer(r)
return ra.Transform(t)
return ra.Transform(newMultiTransformer(r))
}
func (kt *KustTarget) configureExternalTransformers(transformers []string) ([]resmap.Transformer, error) {
@@ -305,7 +289,6 @@ func (kt *KustTarget) runValidators(ra *accumulator.ResAccumulator) error {
}
func (kt *KustTarget) removeValidatedByLabel(rm resmap.ResMap) {
resources := rm.Resources()
for _, r := range resources {
labels := r.GetLabels()
@@ -364,8 +347,7 @@ func (kt *KustTarget) accumulateComponents(
func (kt *KustTarget) accumulateDirectory(
ra *accumulator.ResAccumulator, ldr ifc.Loader, isComponent bool) (*accumulator.ResAccumulator, error) {
defer ldr.Cleanup()
subKt := NewKustTarget(
ldr, kt.validator, kt.rFactory, kt.tFactory, kt.pLdr)
subKt := NewKustTarget(ldr, kt.validator, kt.rFactory, kt.pLdr)
err := subKt.Load()
if err != nil {
return nil, errors.Wrapf(

View File

@@ -187,7 +187,7 @@ metadata:
"apiVersion": "v1",
"kind": "Namespace",
"metadata": map[string]interface{}{
"name": "foo-ns1-bar",
"name": "ns1",
"labels": map[string]interface{}{
"app": "nginx",
},
@@ -201,7 +201,7 @@ metadata:
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "foo-literalConfigMap-bar-8d2dkb8k24",
"name": "foo-literalConfigMap-bar-g5f6t456f5",
"namespace": "ns1",
"labels": map[string]interface{}{
"app": "nginx",
@@ -220,7 +220,7 @@ metadata:
"apiVersion": "v1",
"kind": "Secret",
"metadata": map[string]interface{}{
"name": "foo-secret-bar-9btc7bt4kb",
"name": "foo-secret-bar-82c2g5f8f6",
"namespace": "ns1",
"labels": map[string]interface{}{
"app": "nginx",

View File

@@ -7,7 +7,7 @@ import (
"testing"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/internal/k8sdeps/transformer"
"sigs.k8s.io/kustomize/api/internal/k8sdeps/merge"
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
"sigs.k8s.io/kustomize/api/internal/target"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
@@ -35,17 +35,17 @@ func makeKustTargetWithRf(
t *testing.T,
fSys filesys.FileSystem,
root string,
resFact *resource.Factory) *target.KustTarget {
rf := resmap.NewFactory(resFact, transformer.NewFactoryImpl())
pc := konfig.DisabledPluginConfig()
resourceFactory *resource.Factory) *target.KustTarget {
ldr, err := fLdr.NewLoader(fLdr.RestrictionRootOnly, root, fSys)
if err != nil {
t.Fatal(err)
}
rf := resmap.NewFactory(
resourceFactory, merge.NewMerginator(resourceFactory))
pc := konfig.DisabledPluginConfig()
return target.NewKustTarget(
ldr,
valtest_test.MakeFakeValidator(),
rf,
transformer.NewFactoryImpl(),
pLdr.NewLoader(pc, rf))
}

View File

@@ -1,7 +1,7 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package transform
package target
import (
"fmt"
@@ -17,8 +17,8 @@ type multiTransformer struct {
var _ resmap.Transformer = &multiTransformer{}
// NewMultiTransformer constructs a multiTransformer.
func NewMultiTransformer(t []resmap.Transformer) resmap.Transformer {
// newMultiTransformer constructs a multiTransformer.
func newMultiTransformer(t []resmap.Transformer) resmap.Transformer {
r := &multiTransformer{
transformers: make([]resmap.Transformer, len(t)),
checkConflictEnabled: false}

View File

@@ -0,0 +1,64 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package validate
import (
"sigs.k8s.io/kustomize/api/ifc"
)
// FieldValidator implements ifc.Validator to check
// the values of various KRM string fields,
// e.g. labels, annotations, names, namespaces.
type FieldValidator struct {
}
var _ ifc.Validator = (*FieldValidator)(nil)
func NewFieldValidator() *FieldValidator {
return &FieldValidator{}
}
// TODO(#FieldValidator): implement MakeAnnotationValidator
func (f FieldValidator) MakeAnnotationValidator() func(map[string]string) error {
return func(x map[string]string) error {
return nil
}
}
// TODO(#FieldValidator): implement MakeAnnotationNameValidator
func (f FieldValidator) MakeAnnotationNameValidator() func([]string) error {
return func(x []string) error {
return nil
}
}
// TODO(#FieldValidator): implement MakeLabelValidator
func (f FieldValidator) MakeLabelValidator() func(map[string]string) error {
return func(x map[string]string) error {
return nil
}
}
// TODO(#FieldValidator): implement MakeLabelNameValidator
func (f FieldValidator) MakeLabelNameValidator() func([]string) error {
return func(x []string) error {
return nil
}
}
// TODO(#FieldValidator): implement ValidateNamespace
func (f FieldValidator) ValidateNamespace(s string) []string {
var errs []string
return errs
}
// TODO(#FieldValidator): implement ErrIfInvalidKey
func (f FieldValidator) ErrIfInvalidKey(s string) error {
return nil
}
// TODO(#FieldValidator): implement IsEnvVarName
func (f FieldValidator) IsEnvVarName(k string) error {
return nil
}

View File

@@ -0,0 +1,4 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package validate_test

View File

@@ -0,0 +1,41 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package wrappy
import (
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/types"
)
// WNodeFactory makes instances of WNode.
// These instances in turn adapt
// sigs.k8s.io/kustomize/kyaml/yaml.RNode
// to implement ifc.Unstructured.
// This factory is meant to implement ifc.KunstructuredFactory.
type WNodeFactory struct {
}
var _ ifc.KunstructuredFactory = (*WNodeFactory)(nil)
func (k *WNodeFactory) SliceFromBytes(bs []byte) ([]ifc.Kunstructured, error) {
panic("TODO(#WNodeFactory): implement SliceFromBytes")
}
func (k *WNodeFactory) FromMap(m map[string]interface{}) ifc.Kunstructured {
panic("TODO(#WNodeFactory): implement FromMap")
}
func (k *WNodeFactory) Hasher() ifc.KunstructuredHasher {
panic("TODO(#WNodeFactory): implement Hasher")
}
func (k *WNodeFactory) MakeConfigMap(
kvLdr ifc.KvLoader, args *types.ConfigMapArgs) (ifc.Kunstructured, error) {
panic("TODO(#WNodeFactory): implement MakeConfigMap")
}
func (k *WNodeFactory) MakeSecret(
kvLdr ifc.KvLoader, args *types.SecretArgs) (ifc.Kunstructured, error) {
panic("TODO(#WNodeFactory): implement MakeSecret")
}

View File

@@ -0,0 +1,4 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package wrappy_test

View File

@@ -0,0 +1,143 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package wrappy
import (
"log"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// WNode implements ifc.Kunstructured using yaml.RNode.
//
// It exists only to help manage a switch from
// kunstruct.UnstructAdapter to yaml.RNode as the core
// representation of KRM objects in kustomize.
//
// It's got a silly name because we don't want it around for long,
// and want its use to be obvious.
type WNode struct {
node *yaml.RNode
}
var _ ifc.Kunstructured = (*WNode)(nil)
func NewWNode() *WNode {
return FromRNode(yaml.NewRNode(nil))
}
func FromRNode(node *yaml.RNode) *WNode {
return &WNode{node: node}
}
func (wn *WNode) demandMetaData(label string) yaml.ResourceMeta {
meta, err := wn.node.GetMeta()
if err != nil {
// Log and die since interface doesn't allow error.
log.Fatalf("for %s', expected valid resource: %v", label, err)
}
return meta
}
// Copy implements ifc.Kunstructured.
func (wn *WNode) Copy() ifc.Kunstructured {
return &WNode{node: wn.node.Copy()}
}
// GetAnnotations implements ifc.Kunstructured.
func (wn *WNode) GetAnnotations() map[string]string {
return wn.demandMetaData("GetAnnotations").Annotations
}
// GetFieldValue implements ifc.Kunstructured.
func (wn *WNode) GetFieldValue(path string) (interface{}, error) {
// The argument is a json path, e.g. "metadata.name"
// fields := strings.Split(path, ".")
// return wn.node.Pipe(yaml.Lookup(fields...))
panic("TODO(#WNode): GetFieldValue; implement or drop from API")
}
// GetGvk implements ifc.Kunstructured.
func (wn *WNode) GetGvk() resid.Gvk {
meta := wn.demandMetaData("GetGvk")
g, v := resid.ParseGroupVersion(meta.APIVersion)
return resid.Gvk{Group: g, Version: v, Kind: meta.Kind}
}
// GetKind implements ifc.Kunstructured.
func (wn *WNode) GetKind() string {
return wn.demandMetaData("GetKind").Kind
}
// GetLabels implements ifc.Kunstructured.
func (wn *WNode) GetLabels() map[string]string {
return wn.demandMetaData("GetLabels").Labels
}
// GetName implements ifc.Kunstructured.
func (wn *WNode) GetName() string {
return wn.demandMetaData("GetName").Name
}
// GetSlice implements ifc.Kunstructured.
func (wn *WNode) GetSlice(string) ([]interface{}, error) {
panic("TODO(#WNode) GetSlice; implement or drop from API")
}
// GetSlice implements ifc.Kunstructured.
func (wn *WNode) GetString(string) (string, error) {
panic("TODO(#WNode) GetString; implement or drop from API")
}
// Map implements ifc.Kunstructured.
func (wn *WNode) Map() map[string]interface{} {
panic("TODO(#WNode) Map; implement or drop from API")
}
// MarshalJSON implements ifc.Kunstructured.
func (wn *WNode) MarshalJSON() ([]byte, error) {
return wn.node.MarshalJSON()
}
// MatchesAnnotationSelector implements ifc.Kunstructured.
func (wn *WNode) MatchesAnnotationSelector(string) (bool, error) {
panic("TODO(#WNode) MatchesAnnotationSelector; implement or drop from API")
}
// MatchesLabelSelector implements ifc.Kunstructured.
func (wn *WNode) MatchesLabelSelector(string) (bool, error) {
panic("TODO(#WNode) MatchesLabelSelector; implement or drop from API")
}
// SetAnnotations implements ifc.Kunstructured.
func (wn *WNode) SetAnnotations(map[string]string) {
panic("TODO(#WNode) SetAnnotations; implement or drop from API")
}
// SetGvk implements ifc.Kunstructured.
func (wn *WNode) SetGvk(resid.Gvk) {
panic("TODO(#WNode) SetGvk; implement or drop from API")
}
// SetLabels implements ifc.Kunstructured.
func (wn *WNode) SetLabels(map[string]string) {
panic("TODO(#WNode) SetLabels; implement or drop from API")
}
// SetName implements ifc.Kunstructured.
func (wn *WNode) SetName(string) {
panic("TODO(#WNode) SetName; implement or drop from API")
}
// SetNamespace implements ifc.Kunstructured.
func (wn *WNode) SetNamespace(string) {
panic("TODO(#WNode) SetNamespace; implement or drop from API")
}
// UnmarshalJSON implements ifc.Kunstructured.
func (wn *WNode) UnmarshalJSON(data []byte) error {
return wn.node.UnmarshalJSON(data)
}

View File

@@ -0,0 +1,339 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package wrappy_test
import (
"strings"
"testing"
"gopkg.in/yaml.v3"
. "sigs.k8s.io/kustomize/api/internal/wrappy"
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
)
const (
deploymentLittleJson = `{"apiVersion":"apps/v1","kind":"Deployment",` +
`"metadata":{"name":"homer","namespace":"simpsons"}}`
deploymentBiggerJson = `
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "homer",
"namespace": "simpsons",
"labels": {
"fruit": "apple",
"veggie": "carrot"
},
"annotations": {
"area": "51",
"greeting": "Take me to your leader."
}
}
}
`
bigMapYaml = `Kind: Service
complextree:
- field1:
- boolfield: true
floatsubfield: 1.01
intsubfield: 1010
stringsubfield: idx1010
- boolfield: false
floatsubfield: 1.011
intsubfield: 1011
stringsubfield: idx1011
field2:
- boolfield: true
floatsubfield: 1.02
intsubfield: 1020
stringsubfield: idx1020
- boolfield: false
floatsubfield: 1.021
intsubfield: 1021
stringsubfield: idx1021
- field1:
- boolfield: true
floatsubfield: 1.11
intsubfield: 1110
stringsubfield: idx1110
- boolfield: false
floatsubfield: 1.111
intsubfield: 1111
stringsubfield: idx1111
field2:
- boolfield: true
floatsubfield: 1.112
intsubfield: 1120
stringsubfield: idx1120
- boolfield: false
floatsubfield: 1.1121
intsubfield: 1121
stringsubfield: idx1121
metadata:
labels:
app: application-name
name: service-name
spec:
ports:
port: 80
that:
- idx0
- idx1
- idx2
- idx3
these:
- field1:
- idx010
- idx011
field2:
- idx020
- idx021
- field1:
- idx110
- idx111
field2:
- idx120
- idx121
- field1:
- idx210
- idx211
field2:
- idx220
- idx221
this:
is:
aBool: true
aFloat: 1.001
aNilValue: null
aNumber: 1000
anEmptyMap: {}
anEmptySlice: []
those:
- field1: idx0foo
field2: idx0bar
- field1: idx1foo
field2: idx1bar
- field1: idx2foo
field2: idx2bar
`
)
func makeBigMap() map[string]interface{} {
return map[string]interface{}{
"Kind": "Service",
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"app": "application-name",
},
"name": "service-name",
},
"spec": map[string]interface{}{
"ports": map[string]interface{}{
"port": int64(80),
},
},
"this": map[string]interface{}{
"is": map[string]interface{}{
"aNumber": int64(1000),
"aFloat": float64(1.001),
"aNilValue": nil,
"aBool": true,
"anEmptyMap": map[string]interface{}{},
"anEmptySlice": []interface{}{},
/*
TODO: test for unrecognizable (e.g. a function)
"unrecognizable": testing.InternalExample{
Name: "fooBar",
},
*/
},
},
"that": []interface{}{
"idx0",
"idx1",
"idx2",
"idx3",
},
"those": []interface{}{
map[string]interface{}{
"field1": "idx0foo",
"field2": "idx0bar",
},
map[string]interface{}{
"field1": "idx1foo",
"field2": "idx1bar",
},
map[string]interface{}{
"field1": "idx2foo",
"field2": "idx2bar",
},
},
"these": []interface{}{
map[string]interface{}{
"field1": []interface{}{"idx010", "idx011"},
"field2": []interface{}{"idx020", "idx021"},
},
map[string]interface{}{
"field1": []interface{}{"idx110", "idx111"},
"field2": []interface{}{"idx120", "idx121"},
},
map[string]interface{}{
"field1": []interface{}{"idx210", "idx211"},
"field2": []interface{}{"idx220", "idx221"},
},
},
"complextree": []interface{}{
map[string]interface{}{
"field1": []interface{}{
map[string]interface{}{
"stringsubfield": "idx1010",
"intsubfield": int64(1010),
"floatsubfield": float64(1.010),
"boolfield": true,
},
map[string]interface{}{
"stringsubfield": "idx1011",
"intsubfield": int64(1011),
"floatsubfield": float64(1.011),
"boolfield": false,
},
},
"field2": []interface{}{
map[string]interface{}{
"stringsubfield": "idx1020",
"intsubfield": int64(1020),
"floatsubfield": float64(1.020),
"boolfield": true,
},
map[string]interface{}{
"stringsubfield": "idx1021",
"intsubfield": int64(1021),
"floatsubfield": float64(1.021),
"boolfield": false,
},
},
},
map[string]interface{}{
"field1": []interface{}{
map[string]interface{}{
"stringsubfield": "idx1110",
"intsubfield": int64(1110),
"floatsubfield": float64(1.110),
"boolfield": true,
},
map[string]interface{}{
"stringsubfield": "idx1111",
"intsubfield": int64(1111),
"floatsubfield": float64(1.111),
"boolfield": false,
},
},
"field2": []interface{}{
map[string]interface{}{
"stringsubfield": "idx1120",
"intsubfield": int64(1120),
"floatsubfield": float64(1.1120),
"boolfield": true,
},
map[string]interface{}{
"stringsubfield": "idx1121",
"intsubfield": int64(1121),
"floatsubfield": float64(1.1121),
"boolfield": false,
},
},
},
},
}
}
func TestBasicYamlOperationFromMap(t *testing.T) {
bytes, err := yaml.Marshal(makeBigMap())
if err != nil {
t.Fatalf("unexpected yaml.Marshal err: %v", err)
}
if string(bytes) != bigMapYaml {
t.Fatalf("unexpected string equality")
}
rNode, err := kyaml.Parse(string(bytes))
if err != nil {
t.Fatalf("unexpected yaml.Marshal err: %v", err)
}
rNodeString := rNode.MustString()
// The result from MustString has more indentation
// than bigMapYaml.
rNodeStrings := strings.Split(rNodeString, "\n")
bigMapStrings := strings.Split(bigMapYaml, "\n")
if len(rNodeStrings) != len(bigMapStrings) {
t.Fatalf("line count mismatch")
}
for i := range rNodeStrings {
s1 := strings.TrimSpace(rNodeStrings[i])
s2 := strings.TrimSpace(bigMapStrings[i])
if s1 != s2 {
t.Fatalf("expected '%s'=='%s'", s1, s2)
}
}
}
func TestRoundTripJSON(t *testing.T) {
wn := NewWNode()
err := wn.UnmarshalJSON([]byte(deploymentLittleJson))
if err != nil {
t.Fatalf("unexpected UnmarshalJSON err: %v", err)
}
data, err := wn.MarshalJSON()
if err != nil {
t.Fatalf("unexpected MarshalJSON err: %v", err)
}
actual := string(data)
if actual != deploymentLittleJson {
t.Fatalf("expected %s, got %s", deploymentLittleJson, actual)
}
}
func TestGettingFields(t *testing.T) {
wn := NewWNode()
err := wn.UnmarshalJSON([]byte(deploymentBiggerJson))
if err != nil {
t.Fatalf("unexpected unmarshaljson err: %v", err)
}
gvk := wn.GetGvk()
expected := "apps"
actual := gvk.Group
if expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
expected = "v1"
actual = gvk.Version
if expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
expected = "Deployment"
actual = gvk.Kind
if expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
actual = wn.GetKind()
if expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
expected = "homer"
actual = wn.GetName()
if expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
actualMap := wn.GetLabels()
v, ok := actualMap["fruit"]
if !ok || v != "apple" {
t.Fatalf("unexpected labels '%v'", actualMap)
}
actualMap = wn.GetAnnotations()
v, ok = actualMap["greeting"]
if !ok || v != "Take me to your leader." {
t.Fatalf("unexpected annotations '%v'", actualMap)
}
}

View File

@@ -17,7 +17,11 @@ import (
"sigs.k8s.io/kustomize/api/types"
)
// KunstructuredFactoryImpl hides construction using apimachinery types.
// KunstructuredFactoryImpl makes instances of UnstructAdapter.
// These instances in turn adapt structs in
// k8s.io/apimachinery/pkg/apis/meta/v1/unstructured
// to implement ifc.Kunstructured.
// This factory is meant to implement ifc.KunstructuredFactory.
type KunstructuredFactoryImpl struct {
hasher *kustHash
}

View File

@@ -4,13 +4,9 @@
package kunstruct
import (
"encoding/json"
"fmt"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/kustomize/api/hasher"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
)
// kustHash computes a hash of an unstructured object.
@@ -21,109 +17,11 @@ func NewKustHash() *kustHash {
return &kustHash{}
}
// Hash returns a hash of either a ConfigMap or a Secret
// Hash returns a hash of the given object
func (h *kustHash) Hash(m ifc.Kunstructured) (string, error) {
u := unstructured.Unstructured{
Object: m.Map(),
}
kind := u.GetKind()
switch kind {
case "ConfigMap":
cm, err := unstructuredToConfigmap(u)
if err != nil {
return "", err
}
return configMapHash(cm)
case "Secret":
sec, err := unstructuredToSecret(u)
if err != nil {
return "", err
}
return secretHash(sec)
default:
return "", fmt.Errorf(
"type %s is not supported for hashing in %v",
kind, m.Map())
}
}
// configMapHash returns a hash of the ConfigMap.
// The Data, Kind, and Name are taken into account.
func configMapHash(cm *corev1.ConfigMap) (string, error) {
encoded, err := encodeConfigMap(cm)
node, err := filtersutil.GetRNode(m)
if err != nil {
return "", err
}
h, err := hasher.Encode(hasher.Hash(encoded))
if err != nil {
return "", err
}
return h, nil
}
// SecretHash returns a hash of the Secret.
// The Data, Kind, Name, and Type are taken into account.
func secretHash(sec *corev1.Secret) (string, error) {
encoded, err := encodeSecret(sec)
if err != nil {
return "", err
}
h, err := hasher.Encode(hasher.Hash(encoded))
if err != nil {
return "", err
}
return h, nil
}
// encodeConfigMap encodes a ConfigMap.
// Data, Kind, and Name are taken into account.
// BinaryData is included if it's not empty to avoid useless key in output.
func encodeConfigMap(cm *corev1.ConfigMap) (string, error) {
// json.Marshal sorts the keys in a stable order in the encoding
m := map[string]interface{}{"kind": "ConfigMap", "name": cm.Name, "data": cm.Data}
if len(cm.BinaryData) > 0 {
m["binaryData"] = cm.BinaryData
}
data, err := json.Marshal(m)
if err != nil {
return "", err
}
return string(data), nil
}
// encodeSecret encodes a Secret.
// Data, Kind, Name, and Type are taken into account.
// StringData is included if it's not empty to avoid useless key in output.
func encodeSecret(sec *corev1.Secret) (string, error) {
// json.Marshal sorts the keys in a stable order in the encoding
m := map[string]interface{}{"kind": "Secret", "type": sec.Type, "name": sec.Name, "data": sec.Data}
if len(sec.StringData) > 0 {
m["stringData"] = sec.StringData
}
data, err := json.Marshal(m)
if err != nil {
return "", err
}
return string(data), nil
}
func unstructuredToConfigmap(u unstructured.Unstructured) (*corev1.ConfigMap, error) {
marshaled, err := json.Marshal(u.Object)
if err != nil {
return nil, err
}
var out corev1.ConfigMap
err = json.Unmarshal(marshaled, &out)
return &out, err
}
func unstructuredToSecret(u unstructured.Unstructured) (*corev1.Secret, error) {
marshaled, err := json.Marshal(u.Object)
if err != nil {
return nil, err
}
var out corev1.Secret
err = json.Unmarshal(marshaled, &out)
return &out, err
return hasher.HashRNode(node)
}

View File

@@ -1,190 +1,34 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package kunstruct
import (
"reflect"
"strings"
"testing"
corev1 "k8s.io/api/core/v1"
)
func TestConfigMapHash(t *testing.T) {
cases := []struct {
desc string
cm *corev1.ConfigMap
hash string
err string
}{
// empty map
{"empty data", &corev1.ConfigMap{Data: map[string]string{}, BinaryData: map[string][]byte{}}, "42745tchd9", ""},
// one key
{"one key", &corev1.ConfigMap{Data: map[string]string{"one": ""}}, "9g67k2htb6", ""},
// three keys (tests sorting order)
{"three keys", &corev1.ConfigMap{Data: map[string]string{"two": "2", "one": "", "three": "3"}}, "f5h7t85m9b", ""},
// empty binary data map
{"empty binary data", &corev1.ConfigMap{BinaryData: map[string][]byte{}}, "dk855m5d49", ""},
// one key with binary data
{"one key with binary data", &corev1.ConfigMap{BinaryData: map[string][]byte{"one": []byte("")}}, "mk79584b8c", ""},
// three keys with binary data (tests sorting order)
{"three keys with binary data", &corev1.ConfigMap{BinaryData: map[string][]byte{"two": []byte("2"), "one": []byte(""), "three": []byte("3")}}, "t458mc6db2", ""},
// two keys, one with string and another with binary data
{"two keys with one each", &corev1.ConfigMap{Data: map[string]string{"one": ""}, BinaryData: map[string][]byte{"two": []byte("")}}, "698h7c7t9m", ""},
}
for _, c := range cases {
h, err := configMapHash(c.cm)
if SkipRest(t, c.desc, err, c.err) {
continue
}
if c.hash != h {
t.Errorf("case %q, expect hash %q but got %q", c.desc, c.hash, h)
}
}
}
func TestSecretHash(t *testing.T) {
cases := []struct {
desc string
secret *corev1.Secret
hash string
err string
}{
// empty map
{"empty data", &corev1.Secret{Type: "my-type", Data: map[string][]byte{}}, "t75bgf6ctb", ""},
// one key
{"one key", &corev1.Secret{Type: "my-type", Data: map[string][]byte{"one": []byte("")}}, "74bd68bm66", ""},
// three keys (tests sorting order)
{"three keys", &corev1.Secret{Type: "my-type", Data: map[string][]byte{"two": []byte("2"), "one": []byte(""), "three": []byte("3")}}, "dgcb6h9tmk", ""},
// with stringdata
{"stringdata", &corev1.Secret{Type: "my-type", Data: map[string][]byte{"one": []byte("")}, StringData: map[string]string{"two": "2"}}, "ckm7f798g2", ""},
// empty stringdata
{"empty stringdata", &corev1.Secret{Type: "my-type", Data: map[string][]byte{"one": []byte("")}, StringData: map[string]string{}}, "74bd68bm66", ""},
}
for _, c := range cases {
h, err := secretHash(c.secret)
if SkipRest(t, c.desc, err, c.err) {
continue
}
if c.hash != h {
t.Errorf("case %q, expect hash %q but got %q", c.desc, c.hash, h)
}
}
}
func TestEncodeConfigMap(t *testing.T) {
cases := []struct {
desc string
cm *corev1.ConfigMap
expect string
err string
}{
// empty map
{"empty data", &corev1.ConfigMap{Data: map[string]string{}}, `{"data":{},"kind":"ConfigMap","name":""}`, ""},
// one key
{"one key", &corev1.ConfigMap{Data: map[string]string{"one": ""}}, `{"data":{"one":""},"kind":"ConfigMap","name":""}`, ""},
// three keys (tests sorting order)
{"three keys", &corev1.ConfigMap{Data: map[string]string{"two": "2", "one": "", "three": "3"}},
`{"data":{"one":"","three":"3","two":"2"},"kind":"ConfigMap","name":""}`, ""},
// empty binary map
{"empty data", &corev1.ConfigMap{BinaryData: map[string][]byte{}}, `{"data":null,"kind":"ConfigMap","name":""}`, ""},
// one key with binary data
{"one key", &corev1.ConfigMap{BinaryData: map[string][]byte{"one": []byte("")}},
`{"binaryData":{"one":""},"data":null,"kind":"ConfigMap","name":""}`, ""},
// three keys with binary data (tests sorting order)
{"three keys", &corev1.ConfigMap{BinaryData: map[string][]byte{"two": []byte("2"), "one": []byte(""), "three": []byte("3")}},
`{"binaryData":{"one":"","three":"Mw==","two":"Mg=="},"data":null,"kind":"ConfigMap","name":""}`, ""},
// two keys, one string and one binary values
{"two keys with one each", &corev1.ConfigMap{Data: map[string]string{"one": ""}, BinaryData: map[string][]byte{"two": []byte("")}},
`{"binaryData":{"two":""},"data":{"one":""},"kind":"ConfigMap","name":""}`, ""},
}
for _, c := range cases {
s, err := encodeConfigMap(c.cm)
if SkipRest(t, c.desc, err, c.err) {
continue
}
if s != c.expect {
t.Errorf("case %q, expect %q but got %q from encode %#v", c.desc, c.expect, s, c.cm)
}
}
}
func TestEncodeSecret(t *testing.T) {
cases := []struct {
desc string
secret *corev1.Secret
expect string
err string
}{
// empty map
{"empty data", &corev1.Secret{Type: "my-type", Data: map[string][]byte{}}, `{"data":{},"kind":"Secret","name":"","type":"my-type"}`, ""},
// one key
{"one key", &corev1.Secret{Type: "my-type", Data: map[string][]byte{"one": []byte("")}}, `{"data":{"one":""},"kind":"Secret","name":"","type":"my-type"}`, ""},
// three keys (tests sorting order) - note json.Marshal base64 encodes the values because they come in as []byte
{"three keys", &corev1.Secret{
Type: "my-type",
Data: map[string][]byte{"two": []byte("2"), "one": []byte(""), "three": []byte("3")},
},
`{"data":{"one":"","three":"Mw==","two":"Mg=="},"kind":"Secret","name":"","type":"my-type"}`, ""},
// with stringdata
{"stringdata", &corev1.Secret{Type: "my-type", Data: map[string][]byte{"one": []byte("")}, StringData: map[string]string{"two": "2"}},
`{"data":{"one":""},"kind":"Secret","name":"","stringData":{"two":"2"},"type":"my-type"}`, ""},
// empty stringdata
{"empty stringdata", &corev1.Secret{Type: "my-type", Data: map[string][]byte{"one": []byte("")}, StringData: map[string]string{}},
`{"data":{"one":""},"kind":"Secret","name":"","type":"my-type"}`, ""},
}
for _, c := range cases {
s, err := encodeSecret(c.secret)
if SkipRest(t, c.desc, err, c.err) {
continue
}
if s != c.expect {
t.Errorf("case %q, expect %q but got %q from encode %#v", c.desc, c.expect, s, c.secret)
}
}
}
// warn devs who change types that they might have to update a hash function
// not perfect, as it only checks the number of top-level fields
func TestTypeStability(t *testing.T) {
errfmt := `case %q, expected %d fields but got %d
Depending on the field(s) you added, you may need to modify the hash function for this type.
To guide you: the hash function targets fields that comprise the contents of objects,
not their metadata (e.g. the Data of a ConfigMap, but nothing in ObjectMeta).
func TestHasher(t *testing.T) {
input := `
apiVersion: v1
kind: ConfigMap
metadata:
name: foo
data:
one: ""
binaryData:
two: ""
`
cases := []struct {
typeName string
obj interface{}
expect int
}{
{"ConfigMap", corev1.ConfigMap{}, 4},
{"Secret", corev1.Secret{}, 5},
}
for _, c := range cases {
val := reflect.ValueOf(c.obj)
if num := val.NumField(); c.expect != num {
t.Errorf(errfmt, c.typeName, c.expect, num)
}
}
}
expect := "698h7c7t9m"
// SkipRest returns true if there was a non-nil error or if we expected an error that didn't happen,
// and logs the appropriate error on the test object.
// The return value indicates whether we should skip the rest of the test case due to the error result.
func SkipRest(t *testing.T, desc string, err error, contains string) bool {
factory := NewKunstructuredFactoryImpl()
k, err := factory.SliceFromBytes([]byte(input))
if err != nil {
if len(contains) == 0 {
t.Errorf("case %q, expect nil error but got %q", desc, err.Error())
} else if !strings.Contains(err.Error(), contains) {
t.Errorf("case %q, expect error to contain %q but got %q", desc, contains, err.Error())
}
return true
} else if len(contains) > 0 {
t.Errorf("case %q, expect error to contain %q but got nil error", desc, contains)
return true
t.Fatal(err)
}
hasher := NewKustHash()
result, err := hasher.Hash(k[0])
if err != nil {
t.Fatal(err)
}
if result != expect {
t.Fatalf("expect %s but got %s", expect, result)
}
return false
}

View File

@@ -466,278 +466,6 @@ func TestGetString(t *testing.T) {
}
}
func TestGetInt64(t *testing.T) {
tests := []struct {
name string
pathToField string
expectedValue int64
errorExpected bool
errorMsg string
}{
{
name: "numberAsValue",
pathToField: "this.is.aNumber",
errorExpected: false,
expectedValue: int64(1000),
},
{
name: "validStructSubFieldIndexSubfield",
pathToField: "complextree[1].field2[1].intsubfield",
errorExpected: false,
expectedValue: int64(1121),
},
{
name: "twoFieldsOneMissing",
pathToField: "metadata.banana",
errorExpected: true,
errorMsg: "no field named 'metadata.banana'",
},
{
name: "validStructSubFieldOutOfBoundIndex",
pathToField: "these[1].field2[99]",
errorExpected: true,
errorMsg: "no field named 'these[1].field2[99]'",
},
{
name: "validDownwardAPISpecs",
pathToField: `spec.ports['port']`,
errorExpected: false,
expectedValue: int64(80),
},
}
for _, test := range tests {
s, err := kunstructured.GetInt64(test.pathToField)
if test.errorExpected {
compareExpectedError(t, test.name, test.pathToField, err, test.errorMsg)
continue
}
if err != nil {
unExpectedError(t, test.name, test.pathToField, err)
}
compareValues(t, test.name, test.pathToField, test.expectedValue, s)
}
}
func TestGetFloat64(t *testing.T) {
tests := []struct {
name string
pathToField string
expectedValue float64
errorExpected bool
errorMsg string
}{
{
name: "floatAsValue",
pathToField: "this.is.aFloat",
errorExpected: false,
expectedValue: float64(1.001),
},
{
name: "validStructSubFieldIndexSubfield",
pathToField: "complextree[1].field2[1].floatsubfield",
errorExpected: false,
expectedValue: float64(1.1121),
},
{
name: "validDownwardAPIThis",
pathToField: `this.is[aFloat]`,
errorExpected: false,
expectedValue: float64(1.001),
},
{
name: "twoFieldsOneMissing",
pathToField: "metadata.banana",
errorExpected: true,
errorMsg: "no field named 'metadata.banana'",
},
{
name: "validStructSubFieldOutOfBoundIndex",
pathToField: "these[1].field2[99]",
errorExpected: true,
errorMsg: "index 99 is out of bounds",
},
}
for _, test := range tests {
s, err := kunstructured.GetFloat64(test.pathToField)
if test.errorExpected {
compareExpectedError(t, test.name, test.pathToField, err, test.errorMsg)
continue
}
if err != nil {
unExpectedError(t, test.name, test.pathToField, err)
}
compareValues(t, test.name, test.pathToField, test.expectedValue, s)
}
}
func TestGetBool(t *testing.T) {
tests := []struct {
name string
pathToField string
expectedValue bool
errorExpected bool
errorMsg string
}{
{
name: "boolAsValue",
pathToField: "this.is.aBool",
errorExpected: false,
expectedValue: true,
},
{
name: "validStructSubFieldIndexSubfield",
pathToField: "complextree[1].field2[1].boolfield",
errorExpected: false,
expectedValue: false,
},
{
name: "twoFieldsOneMissing",
pathToField: "metadata.banana",
errorExpected: true,
errorMsg: "no field named 'metadata.banana'",
},
{
name: "validStructSubFieldOutOfBoundIndex",
pathToField: "these[1].field2[99]",
errorExpected: true,
errorMsg: "no field named 'these[1].field2[99]'",
},
}
for _, test := range tests {
s, err := kunstructured.GetBool(test.pathToField)
if test.errorExpected {
compareExpectedError(t, test.name, test.pathToField, err, test.errorMsg)
continue
}
if err != nil {
unExpectedError(t, test.name, test.pathToField, err)
}
compareValues(t, test.name, test.pathToField, test.expectedValue, s)
}
}
func TestGetStringMap(t *testing.T) {
tests := []struct {
name string
pathToField string
errorExpected bool
errorMsg string
}{
{
name: "validStringMap",
pathToField: "those[2]",
errorExpected: false,
},
{
name: "twoFieldsOneMissing",
pathToField: "metadata.banana",
errorExpected: true,
errorMsg: "no field named 'metadata.banana'",
},
{
name: "validStructSubFieldOutOfBoundIndex",
pathToField: "these[1].field2[99]",
errorExpected: true,
errorMsg: "no field named 'these[1].field2[99]'",
},
}
for _, test := range tests {
_, err := kunstructured.GetStringMap(test.pathToField)
if test.errorExpected {
compareExpectedError(t, test.name, test.pathToField, err, test.errorMsg)
continue
}
if err != nil {
unExpectedError(t, test.name, test.pathToField, err)
}
}
}
func TestGetMap(t *testing.T) {
tests := []struct {
name string
pathToField string
errorExpected bool
errorMsg string
}{
{
name: "validMap",
pathToField: "those[2]",
errorExpected: false,
},
{
name: "validStructSubFieldIndexSubfield",
pathToField: "complextree[1].field2[1]",
errorExpected: false,
},
{
name: "twoFieldsOneMissing",
pathToField: "metadata.banana",
errorExpected: true,
errorMsg: "no field named 'metadata.banana'",
},
{
name: "validStructSubFieldOutOfBoundIndex",
pathToField: "these[1].field2[99]",
errorExpected: true,
errorMsg: "no field named 'these[1].field2[99]'",
},
}
for _, test := range tests {
_, err := kunstructured.GetMap(test.pathToField)
if test.errorExpected {
compareExpectedError(t, test.name, test.pathToField, err, test.errorMsg)
continue
}
if err != nil {
unExpectedError(t, test.name, test.pathToField, err)
}
}
}
func TestGetStringSlice(t *testing.T) {
tests := []struct {
name string
pathToField string
errorExpected bool
errorMsg string
}{
{
name: "validStringSlice",
pathToField: "that",
errorExpected: false,
},
{
name: "twoFieldsOneMissing",
pathToField: "metadata.banana",
errorExpected: true,
errorMsg: "no field named 'metadata.banana'",
},
{
name: "validStructSubFieldOutOfBoundIndex",
pathToField: "these[1].field2[99]",
errorExpected: true,
errorMsg: "no field named 'these[1].field2[99]'",
},
}
for _, test := range tests {
_, err := kunstructured.GetStringSlice(test.pathToField)
if test.errorExpected {
compareExpectedError(t, test.name, test.pathToField, err, test.errorMsg)
continue
}
if err != nil {
unExpectedError(t, test.name, test.pathToField, err)
}
}
}
func TestGetSlice(t *testing.T) {
tests := []struct {
name string

View File

@@ -14,11 +14,14 @@ import (
v1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
"sigs.k8s.io/kustomize/api/ifc"
)
// KustValidator validates Labels and annotations by apimachinery
type KustValidator struct{}
var _ ifc.Validator = (*KustValidator)(nil)
// NewKustValidator returns a KustValidator object
func NewKustValidator() *KustValidator {
return &KustValidator{}

View File

@@ -4,7 +4,15 @@
package builtinpluginconsts
const (
// imageFieldSpecs is left empty since `containers` and `initContainers`
// of *ANY* kind in *ANY* path are builtin supported in code
imagesFieldSpecs = ``
imagesFieldSpecs = `
images:
- path: spec/containers[]/image
create: true
- path: spec/initContainers[]/image
create: true
- path: spec/template/spec/containers[]/image
create: true
- path: spec/template/spec/initContainers[]/image
create: true
`
)

View File

@@ -8,9 +8,16 @@ const (
namespace:
- path: metadata/namespace
create: true
- path: metadata/name
kind: Namespace
create: true
- path: subjects
kind: RoleBinding
- path: subjects
kind: ClusterRoleBinding
- path: spec/service/namespace
group: apiregistration.k8s.io
kind: APIService
create: true
`
)

View File

@@ -225,13 +225,13 @@ spec:
spec:
containers:
- env:
- name: foo
value: bar
- name: FOO
valueFrom:
configMapKeyRef:
key: somekey
name: test-infra-app-env-ffmd9b969m
- name: foo
value: bar
name: test-infra-app-env-8h5mh7f7ch
image: nginx:1.8.0
name: nginx
ports:
@@ -240,7 +240,7 @@ spec:
- configMapRef:
name: someConfigMap
- configMapRef:
name: test-infra-app-env-ffmd9b969m
name: test-infra-app-env-8h5mh7f7ch
image: busybox
name: busybox
volumeMounts:
@@ -248,7 +248,7 @@ spec:
name: app-env
volumes:
- configMap:
name: test-infra-app-env-ffmd9b969m
name: test-infra-app-env-8h5mh7f7ch
name: app-env
---
apiVersion: v1
@@ -288,7 +288,7 @@ metadata:
app: mungebot
org: kubernetes
repo: test-infra
name: test-infra-app-env-ffmd9b969m
name: test-infra-app-env-8h5mh7f7ch
---
apiVersion: v1
data:
@@ -301,6 +301,6 @@ metadata:
app: mungebot
org: kubernetes
repo: test-infra
name: test-infra-app-config-f462h769f9
name: test-infra-app-config-49d6f5h7b5
`)
}

View File

@@ -70,7 +70,7 @@ metadata:
apiVersion: v1
kind: Namespace
metadata:
name: p-b-myNs
name: myNs
---
apiVersion: v1
kind: Role
@@ -95,7 +95,7 @@ metadata:
apiVersion: v1
kind: Namespace
metadata:
name: p-myNs2
name: myNs2
`)
}

View File

@@ -39,8 +39,8 @@ resources:
configMapGenerator:
- name: my-configmap
literals:
- testValue=1
- otherValue=10
- testValue=1
- otherValue=10
`)
th.WriteF("/app/base/deploy.yaml", `
apiVersion: v1
@@ -59,13 +59,13 @@ replicas:
- name: storefront
count: 3
resources:
- stub.yaml
- stub.yaml
configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- testValue=2
- compValue=5
- testValue=2
- compValue=5
`)
th.WriteF("/app/comp/stub.yaml", `
apiVersion: v1
@@ -132,7 +132,7 @@ kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: comp-my-configmap-ct5bgtbccd
name: comp-my-configmap-kc6k2kmkh9
---
apiVersion: v1
kind: Deployment
@@ -156,7 +156,7 @@ configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- otherValue=9
- otherValue=9
`),
writeK("/app/prod", `
resources:
@@ -186,7 +186,7 @@ kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: comp-my-configmap-dgf97tmg6h
name: comp-my-configmap-55249mf5kb
---
apiVersion: v1
kind: Deployment
@@ -211,8 +211,8 @@ components:
configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- otherValue=9
literals:
- otherValue=9
`),
writeK("/app/prod", `
resources:
@@ -241,7 +241,7 @@ kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: comp-my-configmap-dgf97tmg6h
name: comp-my-configmap-55249mf5kb
---
apiVersion: v1
kind: Deployment
@@ -283,7 +283,7 @@ data:
testValue: "1"
kind: ConfigMap
metadata:
name: my-configmap-7k9t4h74f8
name: my-configmap-2g9c94mhb8
---
apiVersion: v1
kind: Deployment
@@ -301,7 +301,7 @@ kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: comp-my-configmap-ct5bgtbccd
name: comp-my-configmap-kc6k2kmkh9
---
apiVersion: v1
kind: Deployment
@@ -327,8 +327,8 @@ configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- compValue=5
- testValue=2
- compValue=5
- testValue=2
`),
},
runPath: "/app/direct-component",
@@ -349,7 +349,7 @@ kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: my-configmap-96dt22k28h
name: my-configmap-kc6k2kmkh9
`,
},
"missing-optional-component-api-version": {
@@ -360,7 +360,7 @@ configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- otherValue=9
- otherValue=9
`),
},
runPath: "/app/prod",
@@ -380,7 +380,7 @@ kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: my-configmap-72cfg2mg5d
name: my-configmap-5g7gh5mgt5
---
apiVersion: v1
kind: Deployment
@@ -427,7 +427,7 @@ data:
testValue: "1"
kind: ConfigMap
metadata:
name: my-configmap-a-b-tfb7c5t69m
name: my-configmap-a-b-2g9c94mhb8
---
apiVersion: v1
kind: Deployment
@@ -442,7 +442,7 @@ data:
testValue: "1"
kind: ConfigMap
metadata:
name: my-configmap-b-8h7b8862bb
name: my-configmap-b-2g9c94mhb8
`,
},
@@ -574,7 +574,7 @@ configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- otherValue=9
- otherValue=9
`),
},
runPath: "/app/prod",

View File

@@ -81,7 +81,7 @@ data:
vegetable: broccoli
kind: ConfigMap
metadata:
name: blah-bob-k772g5db55
name: blah-bob-d87t8m8tgm
---
apiVersion: v1
data:
@@ -89,7 +89,7 @@ data:
v2: '[{"path": "var/druid/segment-cache"}]'
kind: ConfigMap
metadata:
name: blah-json-9gtcc2fgb4
name: blah-json-5298bc8g99
---
apiVersion: v1
data:
@@ -101,7 +101,7 @@ data:
vegetable: YnJvY2NvbGk=
kind: Secret
metadata:
name: blah-bob-gmc2824f4b
name: blah-bob-ftht6hfgmb
type: Opaque
`)
}
@@ -155,7 +155,7 @@ data:
vegetable: broccoli
kind: ConfigMap
metadata:
name: blah-bob-gfkcbk5ckf
name: blah-bob-db529cg5bk
`)
}
@@ -217,7 +217,7 @@ kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: p1-com1-dhbbm922gd
name: p1-com1-8tc62428t2
---
apiVersion: v1
data:
@@ -226,7 +226,7 @@ kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: p2-com2-c4b8md75k9
name: p2-com2-87mcggf7d7
`)
}
@@ -274,7 +274,7 @@ kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: o1-cm-28g596k77k
name: o1-cm-ft9mmdc8c6
---
apiVersion: v1
data:
@@ -284,6 +284,6 @@ kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: cm-o2-gfcc59fg5m
name: cm-o2-5k95kd76ft
`)
}

View File

@@ -59,6 +59,7 @@ spec:
location: SW
`)
th.WriteF("/app/base/animalPark.yaml", `
apiVersion: foo
kind: AnimalPark
metadata:
name: sandiego
@@ -93,6 +94,7 @@ varReference:
`)
m := th.Run("/app/base", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: foo
kind: AnimalPark
metadata:
labels:
@@ -161,6 +163,7 @@ varReference:
`)
m := th.Run("/app/base", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: foo
kind: AnimalPark
metadata:
labels:
@@ -212,14 +215,17 @@ func TestFixedBug605_BaseCustomizationAvailableInOverlay(t *testing.T) {
nameReference:
- kind: Gorilla
fieldSpecs:
- kind: AnimalPark
- apiVersion: foo
kind: AnimalPark
path: spec/gorillaRef/name
- kind: Giraffe
fieldSpecs:
- kind: AnimalPark
- apiVersion: foo
kind: AnimalPark
path: spec/giraffeRef/name
varReference:
- path: spec/food
apiVersion: foo
kind: AnimalPark
`)
th.WriteK("/app/overlay", `
@@ -242,6 +248,7 @@ spec:
`)
// The following replaces the gorillaRef in the AnimalPark.
th.WriteF("/app/overlay/animalPark.yaml", `
apiVersion: foo
kind: AnimalPark
metadata:
name: sandiego
@@ -251,6 +258,7 @@ spec:
`)
m := th.Run("/app/overlay", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: foo
kind: AnimalPark
metadata:
labels:

View File

@@ -83,7 +83,7 @@ metadata:
if secret == nil {
t.Errorf("Expected to find a Secret")
}
if secret.GetName() != "foo-secret-bar-9btc7bt4kb" {
if secret.GetName() != "foo-secret-bar-82c2g5f8f6" {
t.Errorf("unexpected secret resource name: %s", secret.GetName())
}
@@ -140,7 +140,7 @@ secretGenerator:
if secret == nil {
t.Errorf("Expected to find a Secret")
}
if secret.GetName() != "yeshash-mcgcmdcm69" {
if secret.GetName() != "yeshash-82c2g5f8f6" {
t.Errorf("unexpected secret resource name: %s", secret.GetName())
}
}

View File

@@ -150,8 +150,6 @@ spec:
func makeBaseWithGenerators(th kusttest_test.Harness) {
th.WriteK("/app", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: team-foo-
commonLabels:
app: mynginx
@@ -253,7 +251,7 @@ spec:
- emptyDir: {}
name: nginx-persistent-storage
- configMap:
name: team-foo-configmap-in-base-bbdmdh7m8t
name: team-foo-configmap-in-base-798k5k7g9f
name: configmap-in-base
---
apiVersion: v1
@@ -285,7 +283,7 @@ metadata:
app: mynginx
org: example.com
team: foo
name: team-foo-configmap-in-base-bbdmdh7m8t
name: team-foo-configmap-in-base-798k5k7g9f
---
apiVersion: v1
data:
@@ -299,7 +297,7 @@ metadata:
app: mynginx
org: example.com
team: foo
name: team-foo-secret-in-base-tkm7hhtf8d
name: team-foo-secret-in-base-bgd6bkgdm2
type: Opaque
`)
}
@@ -325,8 +323,6 @@ spec:
name: configmap-in-overlay
`)
th.WriteK("/overlay", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: staging-
commonLabels:
env: staging
@@ -390,11 +386,11 @@ spec:
pdName: nginx-persistent-storage
name: nginx-persistent-storage
- configMap:
name: staging-configmap-in-overlay-k7cbc75tg8
name: configmap-in-overlay
- configMap:
name: staging-team-foo-configmap-in-base-gh9d7t85gb
name: staging-team-foo-configmap-in-base-hc6g9dk6g9
name: configmap-in-base
- configMap:
name: staging-configmap-in-overlay-dc6fm46dhm
name: configmap-in-overlay
---
apiVersion: v1
kind: Service
@@ -428,7 +424,7 @@ metadata:
env: staging
org: example.com
team: override-foo
name: staging-team-foo-configmap-in-base-gh9d7t85gb
name: staging-team-foo-configmap-in-base-hc6g9dk6g9
---
apiVersion: v1
data:
@@ -444,7 +440,7 @@ metadata:
env: staging
org: example.com
team: override-foo
name: staging-team-foo-secret-in-base-c8db7gk2m2
name: staging-team-foo-secret-in-base-k2k4692t9g
type: Opaque
---
apiVersion: v1
@@ -455,7 +451,7 @@ metadata:
labels:
env: staging
team: override-foo
name: staging-configmap-in-overlay-k7cbc75tg8
name: staging-configmap-in-overlay-dc6fm46dhm
`)
}
@@ -490,7 +486,7 @@ data:
key: value
kind: ConfigMap
metadata:
name: test-t5t4md8fdm
name: test-t757gk2bmf
namespace: default
---
apiVersion: v1
@@ -498,7 +494,7 @@ data:
key: value
kind: ConfigMap
metadata:
name: test-t5t4md8fdm
name: test-t757gk2bmf
namespace: kube-system
---
apiVersion: v1
@@ -507,7 +503,7 @@ data:
username: YWRtaW4=
kind: Secret
metadata:
name: test-h65t9hg6kc
name: test-bgd6bkgdm2
namespace: default
type: Opaque
---
@@ -517,7 +513,7 @@ data:
username: YWRtaW4=
kind: Secret
metadata:
name: test-h65t9hg6kc
name: test-bgd6bkgdm2
namespace: kube-system
type: Opaque
`)

View File

@@ -40,7 +40,7 @@ data:
passphrase: ZGF0IHBocmFzZQ==
kind: Secret
metadata:
name: bob-kf5c9fccbt
name: bob-bh645k7tmg
type: Opaque
`)
}
@@ -91,6 +91,6 @@ kind: ConfigMap
metadata:
labels:
fruit: apple
name: shouldHaveHash-2k9hc848ff
name: shouldHaveHash-c9867f8446
`)
}

View File

@@ -0,0 +1,183 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package provider
import (
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/internal/k8sdeps/merge"
kmerge "sigs.k8s.io/kustomize/api/internal/merge"
"sigs.k8s.io/kustomize/api/internal/validate"
"sigs.k8s.io/kustomize/api/internal/wrappy"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/k8sdeps/validator"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
)
// DepProvider is a dependency provider.
//
// The instances it returns are either
// - old implementations backed by k8sdeps code,
// - new implementations backed by kyaml code.
//
// History:
//
// kubectl depends on k8s.io code, and at the time of writing, so
// does kustomize. Code that imports k8s.io/api* cannot be imported
// back into k8s.io/*, yet kustomize appears inside k8s.io/kubectl.
//
// To allow kustomize to appear inside kubectl, yet still be developed
// outside kubectl, the kustomize code was divided into the following
// packages
//
// api/
// k8sdeps/ (and internal/ks8deps/)
// ifc/
// krusty/
// everythingElse/
//
// with the following rules:
//
// - Only k8sdeps/ may import k8s.io/api*.
//
// - Only krusty/ (and its internals) may import k8sdeps/.
// I.e., ifc/ and everythingElse/ must not
// import k8sdeps/ or k8s.io/api*.
//
// - Code in krusty/ may use code in k8sdeps/ to create
// objects then inject said objects into
// everythingElse/ behind dependency neutral interfaces.
//
// The idea was to periodically copy, not import, the large k8sdeps/
// tree (plus a snippet from krusty/kustomizer.go) into the kubectl
// codebase via a large PR, and have kubectl depend on the rest via
// normal importing.
//
// Over 2019, however, kubectl underwent large changes including
// a switch to Go modules, and a concerted attempt to extract kubectl
// from the k8s repo. This made large kustomize integration PRs too
// intrusive to review.
//
// In 2020, kubectl is based on Go modules, and almost entirely
// extracted from the k8s.io repositories, and further the kyaml
// library has a appeared as a viable replacement to k8s.io/api*
// KRM manipulation code.
//
// The new plan is to eliminate k8sdeps/ entirely, along with its
// k8s.io/api* dependence, allowing kustomize code to be imported
// into kubectl via normal Go module imports. Then the kustomize API
// code can then move into the github.com/kubernetes-sigs/cli-utils
// repo. The kustomize CLI in github.com/kubernetes-sigs/kustomize
// and the kubectl CLI can then both depend on the kustomize API.
//
// So, all code that depends on k8sdeps must go behind interfaces,
// and kustomize must be factored to choose the implementation.
//
// That problem has been reduced to three interfaces, each having
// two implementations. (1) is k8sdeps-based, (2) is kyaml-based.
//
// - ifc.Kunstructured
//
// 1) api/k8sdeps/kunstruct.UnstructAdapter
//
// This adapts structs in
// k8s.io/apimachinery/pkg/apis/meta/v1/unstructured
// to ifc.Kunstructured.
//
// 2) api/wrappy.WNode
//
// This adapts sigs.k8s.io/kustomize/kyaml/yaml.RNode
// to ifc.Unstructured.
//
// At time of writing, implementation started.
// Further reducing the size of ifc.Kunstructed
// would really reduce the work
// (e.g. drop Vars, drop ReplacementTranformer).
//
// - resmap.Merginator
//
// 1) api/internal/k8sdeps/merge.Merginator
//
// Uses k8s.io/apimachinery/pkg/util/strategicpatch,
// apimachinery/pkg/util/mergepatch, etc. to merge
// resource.Resource instances.
//
// 2) api/internal/merge.Merginator
//
// At time of writing, this is unimplemented.
//
// - ifc.Validator
//
// 1) api/k8sdeps/validator.KustValidator
//
// Uses k8s.io/apimachinery/pkg/api/validation and
// friends to validate strings.
//
// 2) api/internal/validate.FieldValidator
//
// At time of writing, this is a do-nothing
// validator as it's not critical to kustomize function.
//
// Proposed plan:
// [ ] Ship kustomize with the ability to switch from 1 to 2 via
// an --enable_kyaml flag.
// [ ] Make --enable_kyaml true by default.
// [ ] When 2 is not noticeably more buggy than 1, delete 1.
// I.e. delete k8sdeps/, transitively deleting all k8s.io/api* deps.
// This DepProvider should be left in place to retain these
// comments, but it will have only one choice.
// [ ] The way is now clear to reintegrate into kubectl.
// This should be done ASAP; the last step is cleanup.
// [ ] With only one impl of Kunstructure remaining, that interface
// and WNode can be deleted, along with this DepProvider.
// The other two interfaces could be dropped too.
//
// When the above is done, kustomize will use yaml.RNode and/or
// KRM Config Functions directly and exclusively.
// If you're reading this, plan not done.
//
type DepProvider struct {
resourceFactory *resource.Factory
merginator resmap.Merginator
fieldValidator ifc.Validator
}
func makeK8sdepBasedInstances() *DepProvider {
kf := kunstruct.NewKunstructuredFactoryImpl()
rf := resource.NewFactory(kf)
return &DepProvider{
resourceFactory: rf,
merginator: merge.NewMerginator(rf),
fieldValidator: validator.NewKustValidator(),
}
}
func makeKyamlBasedInstances() *DepProvider {
kf := &wrappy.WNodeFactory{}
rf := resource.NewFactory(kf)
return &DepProvider{
resourceFactory: rf,
merginator: kmerge.NewMerginator(rf),
fieldValidator: validate.NewFieldValidator(),
}
}
func NewDepProvider(useKyaml bool) *DepProvider {
if useKyaml {
return makeKyamlBasedInstances()
}
return makeK8sdepBasedInstances()
}
func (dp *DepProvider) GetResourceFactory() *resource.Factory {
return dp.resourceFactory
}
func (dp *DepProvider) GetMerginator() resmap.Merginator {
return dp.merginator
}
func (dp *DepProvider) GetFieldValidator() ifc.Validator {
return dp.fieldValidator
}

View File

@@ -0,0 +1,48 @@
package krusty_test
import (
"testing"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func TestKeepEmptyArray(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("/app/resources.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: testing123
spec:
replicas: 1
selector: null
template:
spec:
containers:
- name: event
image: testing123
imagePullPolicy: IfNotPresent
imagePullSecrets: []`)
th.WriteK("/app", `
resources:
- resources.yaml`)
m := th.Run("/app", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: testing123
spec:
replicas: 1
selector: null
template:
spec:
containers:
- image: testing123
imagePullPolicy: IfNotPresent
name: event
imagePullSecrets: []
`)
}

View File

@@ -8,16 +8,13 @@ import (
"sigs.k8s.io/kustomize/api/builtins"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/internal/k8sdeps/transformer"
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
"sigs.k8s.io/kustomize/api/internal/target"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/k8sdeps/validator"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/krusty/internal/provider"
fLdr "sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/provenance"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
)
@@ -28,13 +25,18 @@ import (
// number of overlays and bases), then make a Kustomizer
// injected with the given fileystem, then call Run.
type Kustomizer struct {
fSys filesys.FileSystem
options *Options
fSys filesys.FileSystem
options *Options
depProvider *provider.DepProvider
}
// MakeKustomizer returns an instance of Kustomizer.
func MakeKustomizer(fSys filesys.FileSystem, o *Options) *Kustomizer {
return &Kustomizer{fSys: fSys, options: o}
return &Kustomizer{
fSys: fSys,
options: o,
depProvider: provider.NewDepProvider(o.UseKyaml),
}
}
// Run performs a kustomization.
@@ -49,11 +51,9 @@ func MakeKustomizer(fSys filesys.FileSystem, o *Options) *Kustomizer {
// on any number of internal paths (e.g. the filesystem may contain
// multiple overlays, and Run can be called on each of them).
func (b *Kustomizer) Run(path string) (resmap.ResMap, error) {
pf := transformer.NewFactoryImpl()
rf := resmap.NewFactory(
resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl()),
pf)
resmapFactory := resmap.NewFactory(
b.depProvider.GetResourceFactory(),
b.depProvider.GetMerginator())
lr := fLdr.RestrictionNone
if b.options.LoadRestrictions == types.LoadRestrictionsRootOnly {
lr = fLdr.RestrictionRootOnly
@@ -65,10 +65,9 @@ func (b *Kustomizer) Run(path string) (resmap.ResMap, error) {
defer ldr.Cleanup()
kt := target.NewKustTarget(
ldr,
validator.NewKustValidator(),
rf,
pf,
pLdr.NewLoader(b.options.PluginConfig, rf),
b.depProvider.GetFieldValidator(),
resmapFactory,
pLdr.NewLoader(b.options.PluginConfig, resmapFactory),
)
err = kt.Load()
if err != nil {
@@ -84,7 +83,9 @@ func (b *Kustomizer) Run(path string) (resmap.ResMap, error) {
}
if b.options.AddManagedbyLabel {
t := builtins.LabelTransformerPlugin{
Labels: map[string]string{konfig.ManagedbyLabelKey: fmt.Sprintf("kustomize-%s", provenance.GetProvenance().Version)},
Labels: map[string]string{
konfig.ManagedbyLabelKey: fmt.Sprintf(
"kustomize-%s", provenance.GetProvenance().Version)},
FieldSpecs: []types.FieldSpec{{
Path: "metadata/labels",
CreateIfNotPresent: true,

View File

@@ -147,11 +147,11 @@ spec:
pdName: nginx-persistent-storage
name: nginx-persistent-storage
- configMap:
name: a-configmap-in-overlay-ffm9hf78mc
name: configmap-in-overlay
- configMap:
name: a-b-configmap-in-base-fm96mhk4dt
name: a-b-configmap-in-base-798k5k7g9f
name: configmap-in-base
- configMap:
name: a-configmap-in-overlay-dc6fm46dhm
name: configmap-in-overlay
---
apiVersion: v1
kind: Service
@@ -175,7 +175,7 @@ metadata:
labels:
env: staging
team: foo
name: a-b-configmap-in-base-fm96mhk4dt
name: a-b-configmap-in-base-798k5k7g9f
---
apiVersion: v1
data:
@@ -184,14 +184,12 @@ kind: ConfigMap
metadata:
labels:
env: staging
name: a-configmap-in-overlay-ffm9hf78mc
name: a-configmap-in-overlay-dc6fm46dhm
`)
}
func makeCommonFileForMultiplePatchTest(th kusttest_test.Harness) {
th.WriteK("/app/base", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: team-foo-
commonLabels:
app: mynginx
@@ -249,8 +247,6 @@ spec:
app: nginx
`)
th.WriteK("/app/overlay/staging", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: staging-
commonLabels:
env: staging
@@ -356,11 +352,11 @@ spec:
pdName: nginx-persistent-storage
name: nginx-persistent-storage
- configMap:
name: staging-configmap-in-overlay-k7cbc75tg8
name: configmap-in-overlay
- configMap:
name: staging-team-foo-configmap-in-base-g7k6gt2889
name: staging-team-foo-configmap-in-base-798k5k7g9f
name: configmap-in-base
- configMap:
name: staging-configmap-in-overlay-dc6fm46dhm
name: configmap-in-overlay
---
apiVersion: v1
kind: Service
@@ -394,7 +390,7 @@ metadata:
env: staging
org: example.com
team: foo
name: staging-team-foo-configmap-in-base-g7k6gt2889
name: staging-team-foo-configmap-in-base-798k5k7g9f
---
apiVersion: v1
data:
@@ -403,7 +399,7 @@ kind: ConfigMap
metadata:
labels:
env: staging
name: staging-configmap-in-overlay-k7cbc75tg8
name: staging-configmap-in-overlay-dc6fm46dhm
`)
}
@@ -547,7 +543,7 @@ spec:
- emptyDir: {}
name: nginx-persistent-storage
- configMap:
name: staging-team-foo-configmap-in-base-g7k6gt2889
name: staging-team-foo-configmap-in-base-798k5k7g9f
name: configmap-in-base
---
apiVersion: v1
@@ -582,7 +578,7 @@ metadata:
env: staging
org: example.com
team: foo
name: staging-team-foo-configmap-in-base-g7k6gt2889
name: staging-team-foo-configmap-in-base-798k5k7g9f
---
apiVersion: v1
data:
@@ -591,7 +587,7 @@ kind: ConfigMap
metadata:
labels:
env: staging
name: staging-configmap-in-overlay-k7cbc75tg8
name: staging-configmap-in-overlay-dc6fm46dhm
`)
})
}

View File

@@ -0,0 +1,113 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package krusty_test
import (
"testing"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
// Coverage for issue #2609
func TestNamePrefixSuffixPatch(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("handlers/kustomization.yaml", `
nameSuffix: -suffix
resources:
- deployment.yaml
`)
th.WriteF("handlers/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: short
spec:
template:
spec:
containers:
- name: handler
`)
th.WriteF("mysql/kustomization.yaml", `
configMapGenerator:
- name: mysql
literals:
- MYSQL_USER=default
- MYSQL_DATABASE=default
- PORT=3306
`)
th.WriteK(".", `
resources:
- mysql
- handlers
configMapGenerator:
- name: mysql
behavior: merge
literals:
- MYSQL_DATABASE=db
- MYSQL_USER=my-user
- MYSQL_PASSWORD='correct horse battery staple'
patches:
- target:
kind: Deployment
name: s.*
patch: |-
kind: Deployment
metadata:
name: ignored
spec:
template:
spec:
containers:
- name: handler
envFrom:
- configMapRef:
name: mysql
env:
- valueFrom:
configMapKeyRef:
name: mysql
key: MYSQL_DATABASE
`)
m := th.Run(".", th.MakeDefaultOptions())
// Per #2609, the desired behavior is for configMapRef.name and configMapKeyRef.name to be "mysql-9792mdchtg" not "mysql"
th.AssertActualEqualsExpected(m, `
apiVersion: v1
data:
MYSQL_DATABASE: db
MYSQL_PASSWORD: correct horse battery staple
MYSQL_USER: my-user
PORT: "3306"
kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: mysql-9792mdchtg
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: short-suffix
spec:
template:
spec:
containers:
- env:
- valueFrom:
configMapKeyRef:
key: MYSQL_DATABASE
name: mysql-9792mdchtg
envFrom:
- configMapRef:
name: mysql-9792mdchtg
name: handler
`)
}

View File

@@ -0,0 +1,44 @@
package krusty_test
import (
"testing"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func TestEmptyFieldSpecValue(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK("/app", `
generators:
- generators.yaml
configurations:
- kustomizeconfig.yaml
`)
th.WriteF("/app/generators.yaml", `
apiVersion: builtin
kind: ConfigMapGenerator
metadata:
name: secret-example
labels:
app.kubernetes.io/name: secret-example
literals:
- this_is_a_secret_name=
`)
th.WriteF("/app/kustomizeconfig.yaml", `
nameReference:
- kind: Secret
version: v1
fieldSpecs:
- path: data/this_is_a_secret_name
kind: ConfigMap
`)
m := th.Run("/app", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: v1
data:
this_is_a_secret_name: ""
kind: ConfigMap
metadata:
name: secret-example-7hf4fh868h
`)
}

View File

@@ -42,7 +42,7 @@ data:
enableRisky: "false"
kind: ConfigMap
metadata:
name: the-non-default-namespace-map-b6h49k7mt8
name: the-non-default-namespace-map-64b2md8tth
namespace: non-default
---
apiVersion: v1
@@ -51,14 +51,14 @@ data:
enableRisky: "false"
kind: ConfigMap
metadata:
name: the-map-4959m5tm6c
name: the-map-tg7t5hk8bk
---
apiVersion: v1
data:
password.txt: dmVyeVNlY3JldA==
kind: Secret
metadata:
name: the-non-default-namespace-secret-h8d9hkgtb9
name: the-non-default-namespace-secret-8tc9gdd76t
namespace: non-default
type: Opaque
---
@@ -67,7 +67,7 @@ data:
password.txt: YW5vdGhlclNlY3JldA==
kind: Secret
metadata:
name: the-secret-fgb45h45bh
name: the-secret-6557m7fcg8
type: Opaque
`)
}
@@ -104,7 +104,7 @@ kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: testCase-4g75kbk6gm
name: testCase-bcbmmg48hd
namespace: overlay
`)
}

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

@@ -32,14 +32,20 @@ type Options struct {
// Options related to kustomize plugins.
PluginConfig *types.PluginConfig
// When true, use kyaml/ packages to manipulate KRM yaml.
// When false, use k8sdeps/ instead (uses k8s.io/api* packages).
UseKyaml bool
}
// MakeDefaultOptions returns a default instance of Options.
func MakeDefaultOptions() *Options {
return &Options{
DoLegacyResourceSort: true,
DoLegacyResourceSort: false,
AddManagedbyLabel: false,
LoadRestrictions: types.LoadRestrictionsRootOnly,
DoPrune: false,
PluginConfig: konfig.DisabledPluginConfig(),
UseKyaml: false,
}
}

View File

@@ -0,0 +1,215 @@
package krusty_test
import (
"testing"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func TestRoleBindingAcrossNamespace(t *testing.T) {
th := kusttest_test.MakeEnhancedHarness(t)
defer th.Reset()
th.WriteK("/app", `
resources:
- resource.yaml
nameSuffix: -ns2
`)
th.WriteF("/app/resource.yaml", `
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-sa1
namespace: ns1
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-sa2
namespace: ns2
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-sa3
namespace: ns3
---
apiVersion: v1
kind: NotServiceAccount
metadata:
name: my-nsa
namespace: ns1
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: my-role
namespace: ns2
rules:
- apiGroups:
- '*'
resources:
- '*'
verbs:
- '*'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-role-binding
namespace: ns2
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: my-role
subjects:
- kind: ServiceAccount
name: my-sa1
namespace: ns1
- kind: ServiceAccount
name: my-sa2
namespace: ns2
- kind: ServiceAccount
name: my-sa3
namespace: ns3
- kind: NotServiceAccount
name: my-nsa
namespace: ns1
`)
m := th.Run("/app", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-sa1-ns2
namespace: ns1
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-sa2-ns2
namespace: ns2
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-sa3-ns2
namespace: ns3
---
apiVersion: v1
kind: NotServiceAccount
metadata:
name: my-nsa-ns2
namespace: ns1
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: my-role-ns2
namespace: ns2
rules:
- apiGroups:
- '*'
resources:
- '*'
verbs:
- '*'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-role-binding-ns2
namespace: ns2
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: my-role-ns2
subjects:
- kind: ServiceAccount
name: my-sa1-ns2
namespace: ns1
- kind: ServiceAccount
name: my-sa2-ns2
namespace: ns2
- kind: ServiceAccount
name: my-sa3-ns2
namespace: ns3
- kind: NotServiceAccount
name: my-nsa
namespace: ns1
`)
}
func TestRoleBindingAcrossNamespaceWoSubjects(t *testing.T) {
th := kusttest_test.MakeEnhancedHarness(t)
defer th.Reset()
th.WriteK("/app", `
resources:
- resource.yaml
nameSuffix: -ns2
`)
th.WriteF("/app/resource.yaml", `
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-sa1
namespace: ns1
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: my-role
namespace: ns2
rules:
- apiGroups:
- '*'
resources:
- '*'
verbs:
- '*'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-role-binding
namespace: ns2
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: my-role
`)
m := th.Run("/app", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-sa1-ns2
namespace: ns1
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: my-role-ns2
namespace: ns2
rules:
- apiGroups:
- '*'
resources:
- '*'
verbs:
- '*'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-role-binding-ns2
namespace: ns2
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: my-role-ns2
`)
}

View File

@@ -0,0 +1,79 @@
package krusty_test
import (
"testing"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
// This test is for output string style.
// Currently all quotes will be removed if the string is valid as plain (unquoted) style.
// If a string cannot be unquoted, it will be put into a pair of single quotes.
// See https://yaml.org/spec/1.2/spec.html#id2788859 for more details about what kind of string
// is invalid as plain style.
func TestLongLineBreaks(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("/app/deployment.yaml", `
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: test
spec:
template:
spec:
containers:
- name: mariadb
image: test
env:
- name: SHORT_STRING
value: short_string
- name: SHORT_STRING_WITH_SINGLE_QUOTE
value: 'short_string'
- name: SHORT_STRING_WITH_DOUBLE_QUOTE
value: "short_string"
- name: SHORT_STRING_BLANK
value: short string
- name: LONG_STRING_BLANK
value: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas suscipit ex non molestie varius.
- name: LONG_STRING_BLANK_WITH_SINGLE_QUOTE
value: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas suscipit ex non molestie varius.'
- name: LONG_STRING_BLANK_WITH_DOUBLE_QUOTE
value: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas suscipit ex non molestie varius."
- name: INVALID_PLAIN_STYLE_STRING
value: ': test'
`)
th.WriteK("/app", `
resources:
- deployment.yaml
`)
m := th.Run("/app", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: test
spec:
template:
spec:
containers:
- env:
- name: SHORT_STRING
value: short_string
- name: SHORT_STRING_WITH_SINGLE_QUOTE
value: short_string
- name: SHORT_STRING_WITH_DOUBLE_QUOTE
value: short_string
- name: SHORT_STRING_BLANK
value: short string
- name: LONG_STRING_BLANK
value: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas suscipit ex non molestie varius.
- name: LONG_STRING_BLANK_WITH_SINGLE_QUOTE
value: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas suscipit ex non molestie varius.
- name: LONG_STRING_BLANK_WITH_DOUBLE_QUOTE
value: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas suscipit ex non molestie varius.
- name: INVALID_PLAIN_STYLE_STRING
value: ': test'
image: test
name: mariadb
`)
}

View File

@@ -10,24 +10,6 @@ import (
"sigs.k8s.io/kustomize/api/types"
)
func writeDeployment(th *kusttest_test.HarnessEnhanced, path string) {
th.WriteF(path, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeployment
spec:
template:
metadata:
labels:
backend: awesome
spec:
containers:
- name: whatever
image: whatever
`)
}
func writeStringPrefixer(th *kusttest_test.HarnessEnhanced, path, name string) {
th.WriteF(path, `
apiVersion: someteam.example.com/v1
@@ -37,53 +19,6 @@ metadata:
`)
}
func writeDatePrefixer(th *kusttest_test.HarnessEnhanced, path, name string) {
th.WriteF(path, `
apiVersion: someteam.example.com/v1
kind: DatePrefixer
metadata:
name: `+name+`
`)
}
func TestOrderedTransformers(t *testing.T) {
th := kusttest_test.MakeEnhancedHarness(t).
BuildGoPlugin("someteam.example.com", "v1", "StringPrefixer").
BuildGoPlugin("someteam.example.com", "v1", "DatePrefixer")
defer th.Reset()
th.WriteK("/app", `
resources:
- deployment.yaml
transformers:
- peachPrefixer.yaml
- date1Prefixer.yaml
- applePrefixer.yaml
- date2Prefixer.yaml
`)
writeDeployment(th, "/app/deployment.yaml")
writeStringPrefixer(th, "/app/applePrefixer.yaml", "apple")
writeStringPrefixer(th, "/app/peachPrefixer.yaml", "peach")
writeDatePrefixer(th, "/app/date1Prefixer.yaml", "date1")
writeDatePrefixer(th, "/app/date2Prefixer.yaml", "date2")
m := th.Run("/app", th.MakeOptionsPluginsEnabled())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: 2018-05-11-apple-2018-05-11-peach-myDeployment
spec:
template:
metadata:
labels:
backend: awesome
spec:
containers:
- image: whatever
name: whatever
`)
}
func TestPluginsNotEnabled(t *testing.T) {
th := kusttest_test.MakeEnhancedHarness(t).
BuildGoPlugin("someteam.example.com", "v1", "StringPrefixer")
@@ -161,7 +96,79 @@ data:
FOO: foo
kind: ConfigMap
metadata:
name: test-k4bkhftttd
name: test-6bc28fff49
`)
}
/*
The tests below are disabled until the StringPrefixer and DatePrefixer
can be rewritten using kyaml, instead of depending on the
PrefixSuffixTransformerPlugin. That dependency is causing
failures in the test loader.
func writeDeployment(th *kusttest_test.HarnessEnhanced, path string) {
th.WriteF(path, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeployment
spec:
template:
metadata:
labels:
backend: awesome
spec:
containers:
- name: whatever
image: whatever
`)
}
func writeDatePrefixer(th *kusttest_test.HarnessEnhanced, path, name string) {
th.WriteF(path, `
apiVersion: someteam.example.com/v1
kind: DatePrefixer
metadata:
name: `+name+`
`)
}
func TestOrderedTransformers(t *testing.T) {
th := kusttest_test.MakeEnhancedHarness(t).
BuildGoPlugin("someteam.example.com", "v1", "StringPrefixer").
BuildGoPlugin("someteam.example.com", "v1", "DatePrefixer")
defer th.Reset()
th.WriteK("/app", `
resources:
- deployment.yaml
transformers:
- peachPrefixer.yaml
- date1Prefixer.yaml
- applePrefixer.yaml
- date2Prefixer.yaml
`)
writeDeployment(th, "/app/deployment.yaml")
writeStringPrefixer(th, "/app/applePrefixer.yaml", "apple")
writeStringPrefixer(th, "/app/peachPrefixer.yaml", "peach")
writeDatePrefixer(th, "/app/date1Prefixer.yaml", "date1")
writeDatePrefixer(th, "/app/date2Prefixer.yaml", "date2")
m := th.Run("/app", th.MakeOptionsPluginsEnabled())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: 2018-05-11-apple-2018-05-11-peach-myDeployment
spec:
template:
metadata:
labels:
backend: awesome
spec:
containers:
- image: whatever
name: whatever
`)
}
@@ -205,3 +212,4 @@ spec:
name: whatever
`)
}
*/

View File

@@ -173,6 +173,9 @@ spec:
`)
}
// The default configuration recognizes image paths starting
// with "spec", not spec2 or spec3, so the latter two specs won't
// have their image entries changed.
func TestTransfomersImageDefaultConfig(t *testing.T) {
th := kusttest_test.MakeHarness(t)
makeTransfomersImageBase(th)
@@ -299,11 +302,11 @@ spec3:
th.WriteF("/app/base/config/custom.yaml", `
images:
- kind: Custom
path: spec/template/spec/myContainers/image
path: spec/template/spec/myContainers[]/image
- kind: Custom
path: spec2/template/spec/myContainers/image
path: spec2/template/spec/myContainers[]/image
- kind: Custom
path: spec3/template/spec/myInitContainers/image
path: spec3/template/spec/myInitContainers[]/image
`)
}

View File

@@ -895,7 +895,7 @@ spec:
- command:
- echo
- dev-base-cockroachdb
- dev-base-test-config-map-b2g2dmd64b
- dev-base-test-config-map-6b85g79g7g
env:
- name: CDB_PUBLIC_SVC
value: dev-base-cockroachdb-public
@@ -921,7 +921,7 @@ data:
foo: bar
kind: ConfigMap
metadata:
name: dev-base-test-config-map-b2g2dmd64b
name: dev-base-test-config-map-6b85g79g7g
`)
}

View File

@@ -199,7 +199,9 @@ func (fl *fileLoader) New(path string) (ifc.Loader, error) {
}
root, errDir := demandDirectoryRoot(fl.fSys, fl.root.Join(path))
if errDir != nil {
return nil, fmt.Errorf("Error loading %s with git: %v, dir: %v, get: %v", path, errGit, errDir, errGet)
return nil, fmt.Errorf(
"error loading %s with git: %v, dir: %v, get: %v",
path, errGit, errDir, errGet)
}
if errDir := fl.errIfGitContainmentViolation(root); errDir != nil {
return nil, errDir

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()

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