Compare commits

...

688 Commits

Author SHA1 Message Date
Jeff Regan
c45e05b7bd Update go.mod 2020-09-16 12:53:39 -07:00
Kubernetes Prow Robot
76bae738a0 Merge pull request #2932 from mstrYoda/master
add DisableNameSuffixHash parameter to edit Secret & ConfigMap
2020-09-16 10:29:20 -07:00
Jeff Regan
0770661b2a Merge pull request #2991 from monopole/goSumUpdates
Go sum updates
2020-09-15 17:34:23 -07:00
jregan
67d5871e87 Go sum updates 2020-09-15 17:02:40 -07:00
Jeff Regan
f98c683915 Merge pull request #2983 from Shell32-Natsu/allow-null
ignore null value in fieldspec
2020-09-15 17:02:20 -07:00
Jeff Regan
ffe9c9d947 Merge pull request #2990 from monopole/pinToKyamlv0_8_0
Pin to kyaml v0.8.0
2020-09-15 15:51:08 -07:00
jregan
4d42ffc7f8 Pin to kyaml v0.8.0 2020-09-15 15:26:29 -07:00
Jeff Regan
d7dc7d911e Merge pull request #2989 from monopole/minorFix
Generated changes.
2020-09-15 14:56:16 -07:00
jregan
04404ff61b Generated changes. 2020-09-15 14:55:08 -07:00
Jeff Regan
f864e15c68 Merge pull request #2974 from Shell32-Natsu/function-definition
remove not used args & use const string instead of literal
2020-09-15 14:34:25 -07:00
Jeff Regan
29a444fffc Merge pull request #2988 from Shell32-Natsu/env-flag
Add --env/-e flag to fn run
2020-09-15 14:31:40 -07:00
Donny Xia
327035a43a Add --env/-e flag 2020-09-15 11:49:26 -07:00
Kubernetes Prow Robot
ad7fed061e Merge pull request #2984 from phanimarupaka/FixCmdCfgIssues
Do not print package info in grep
2020-09-15 09:40:07 -07:00
Phani Teja Marupaka
cea2986574 Don not pring package info in grep 2020-09-15 00:15:52 -07:00
Kubernetes Prow Robot
00f0fd7109 Merge pull request #2978 from mortent/NamespaceabilityFromSchema
Determine namespaceability of resources from openapi schema
2020-09-14 21:10:06 -07:00
Kubernetes Prow Robot
1c6481d011 Merge pull request #2982 from mortent/UpdateCliUtils
Update cmd/config to use latest version of cli-utils
2020-09-14 13:27:24 -07:00
Donny Xia
f0bc926640 ignore null value in fieldspec 2020-09-14 13:20:20 -07:00
Morten Torkildsen
11d9ff5690 Update cmd/config to use latest version of cli-utils 2020-09-14 12:08:48 -07:00
Jeff Regan
6a0a909e73 Merge pull request #2976 from monopole/deferLive
Remove live; done testing.  Bring to sig-cli for discussion.
2020-09-14 11:00:48 -07:00
Kubernetes Prow Robot
bd8f0c88e5 Merge pull request #2967 from phanimarupaka/CfgTreeWithSubpackages
Print Krmfile data for cfg tree
2020-09-14 10:42:59 -07:00
Donny Xia
e5809e49cb remove not used args 2020-09-14 10:10:20 -07:00
Phani Teja Marupaka
880009b648 Print Krmfile data for cfg tree 2020-09-14 09:57:18 -07:00
Morten Torkildsen
d083c7f1d0 Determine namespaceability of resources from openapi schema 2020-09-12 15:01:42 -07:00
Jeffrey Regan
684ce141de Defer live testing. 2020-09-11 17:25:25 -07:00
Kubernetes Prow Robot
5c8c7a043a Merge pull request #2973 from phanimarupaka/CfgCommandsStdoutFixes
Format the output of cfg commands
2020-09-11 16:44:57 -07:00
Kubernetes Prow Robot
0fe7f65ef2 Merge pull request #2975 from monopole/addTest
Add test representing 2960
2020-09-11 16:10:57 -07:00
Jeffrey Regan
950c1de46d Add test representing 2960 2020-09-11 15:22:41 -07:00
Phani Teja Marupaka
fc690f14a8 Format the output of cfg commands 2020-09-11 14:49:18 -07:00
Jeff Regan
a6e03e4d11 Merge pull request #2920 from wyyxd2017/hato4
Technical details structure picture
2020-09-11 14:32:19 -07:00
Jeff Regan
60428be5fb Merge pull request #2944 from justinsb/alas_poor_grepfilter
Remove some obsolete references to GrepFilter
2020-09-11 14:16:30 -07:00
Jeff Regan
4d402d4875 Merge pull request #2969 from justinsb/fix_split_docs
Fix comment on SplitIndexNameValue
2020-09-11 14:13:43 -07:00
Jeff Regan
fbddd264be Merge pull request #2971 from etefera/fix-broken-patches-change
Fix unintended patches change in all Kustomization writes.
2020-09-11 13:33:09 -07:00
Eyob Tefera
d3c46d3f7c Move offending Write() tests to tests for fix. 2020-09-11 19:19:54 +00:00
Eyob Tefera
dda3984a8f Move kustomization fixing to before Write step. 2020-09-11 18:57:14 +00:00
Eyob Tefera
f889ca8885 Add set image test with patchesJson6902. 2020-09-11 18:48:48 +00:00
Justin SB
341bacb9a2 Fix comment on SplitIndexNameValue
It was incorrect and suggested some behaviour which isn't present.
Added test to verify the documented behaviour.
2020-09-11 11:39:49 -04:00
Kubernetes Prow Robot
badc1177d9 Merge pull request #2939 from ZhuGongpu/master
Add --log-steps flag
2020-09-09 19:05:44 -07:00
Kubernetes Prow Robot
1680cc72c0 Merge pull request #2953 from easimon/add_namespace_to_namespace_transformer
Add namespace name to namespace transformer defaults
2020-09-09 14:57:44 -07:00
Jeff Regan
2f89de86f8 Merge pull request #2956 from justinsb/fix_language
Replace language with more inclusive & accurate "hard-coded"
2020-09-09 11:33:53 -07:00
Jeff Regan
ab4e9c718b Merge pull request #2943 from Shell32-Natsu/clean-up-temp-dir
remove all temp dir
2020-09-09 11:20:17 -07:00
Kubernetes Prow Robot
288c03ddca Merge pull request #2959 from phanimarupaka/CatWithSubpkgs
Cat with subpackages
2020-09-09 10:49:08 -07:00
Justin SB
5c60285f25 Replace language with more inclusive & accurate "hard-coded"
hard-coded is probably more helpful to understanding the limitations
of the current approach.
2020-09-09 08:41:33 -04:00
Kubernetes Prow Robot
6df0a45368 Merge pull request #2958 from phanimarupaka/GrepWithSubpkgs
Grep with subpackages
2020-09-08 21:09:52 -07:00
Kubernetes Prow Robot
8206987580 Merge pull request #2957 from phanimarupaka/CountWithSubpkgs
Count with Subpackages
2020-09-08 20:53:52 -07:00
Kubernetes Prow Robot
6189ca9798 Merge pull request #2955 from phanimarupaka/FmtWithSubpkgs
Fmt with subpackages
2020-09-08 20:33:52 -07:00
Phani Teja Marupaka
b8c1601a93 Cat with subpackages 2020-09-08 18:42:31 -07:00
Phani Teja Marupaka
34d610a38d Fmt with subpackages 2020-09-08 17:07:55 -07:00
Phani Teja Marupaka
8e4c8464e7 Grep with subpackages 2020-09-08 16:59:23 -07:00
Phani Teja Marupaka
43ab7a8e71 Count with Subpackages 2020-09-08 16:33:00 -07:00
Kubernetes Prow Robot
d2f23a4b8b Merge pull request #2938 from phanimarupaka/OtherCfgCommandsWithSubPkgs
annotate, delete-setter, delete-subst With Subpackages
2020-09-08 16:25:52 -07:00
Phani Teja Marupaka
0dc36a4f7c Annotate With Subpackages
Delete Setters And Subst With Subpkgs
2020-09-08 15:52:57 -07:00
Kubernetes Prow Robot
678ae12115 Merge pull request #2946 from phanimarupaka/RefactorSubPkgsIteration
Refactor subpackages logic
2020-09-08 11:47:52 -07:00
Phani Teja Marupaka
c4d937322f Refactor subpackages logic 2020-09-08 11:23:54 -07:00
Kubernetes Prow Robot
a2adb835b6 Merge pull request #2941 from mortent/FixIgnoreFilesMatcher
Fix issue where ignoreFilesMatcher doesn't work correctly
2020-09-08 10:33:44 -07:00
Markus Dobel
01b5c4e9da Add namespace name to namespace transformer defaults 2020-09-08 11:24:58 +02:00
Justin SB
eb4c5dc035 Remove some obsolete references to GrepFilter
Looks like GrepFilter was generalized to Filter.
2020-09-04 13:41:16 -04:00
Morten Torkildsen
e976386931 Fix issue where ignoreFilesMatcher doesn't work correctly 2020-09-03 20:14:07 -07:00
Donny Xia
bae9986422 remove all temp dir 2020-09-03 12:03:12 -07:00
Jeff Regan
e7970d82a8 Merge pull request #2942 from Shell32-Natsu/addDonny
add Donny to maintainer
2020-09-03 11:52:14 -07:00
Donny Xia
9bdd489c96 add Donny to maintainer 2020-09-03 10:57:50 -07:00
Kubernetes Prow Robot
0f49fef5ed Merge pull request #2940 from phanimarupaka/FixSettersSubPkgsFriction
Fix setters subpkgs friction
2020-09-03 08:59:41 -07:00
Phani Teja Marupaka
8d74b8c3b5 Fix setters subpkgs friction 2020-09-02 23:06:26 -07:00
Gongpu Zhu
39a8798a87 Add --log-steps flag 2020-09-02 20:47:21 -07:00
Jeff Regan
980f407552 Merge pull request #2931 from Shell32-Natsu/image-tag-legacy
add legacy filter to image tag transformer
2020-09-02 13:02:53 -07:00
Donny Xia
9ca8f4602d add legacy filter to image tag transformer 2020-09-01 13:06:14 -07:00
Kubernetes Prow Robot
ba0f583ee5 Merge pull request #2911 from phanimarupaka/SetWithSubPackages
Setters/substitutions with subpackages
2020-09-01 11:23:51 -07:00
Phani Teja Marupaka
f432f4d75e Setters with subpackages 2020-09-01 10:54:08 -07:00
Jeff Regan
17793abacd Merge pull request #2930 from daniel-hutao/patch-1
fix “chart s” to “charts ”
2020-09-01 10:12:58 -07:00
Jeff Regan
64cd4ec1d5 Merge pull request #2929 from monopole/testExamplesAgainst_v3.8.2
Test examples against v3.8.2
2020-09-01 10:12:18 -07:00
Daniel (ht)
fb822984e3 fix “chart s” to “charts ”
fix “chart s” to “charts ”
2020-09-01 16:24:49 +08:00
jregan
6d2a737c29 Test examples against v3.8.2 2020-08-31 16:48:19 -07:00
Jeff Regan
6e7713281e Merge pull request #2928 from monopole/addGorepomod
Add more release instructions
2020-08-31 13:50:48 -07:00
jregan
6a7bb9e33e Add gorepomod tool to install list 2020-08-31 13:28:19 -07:00
Jeff Regan
0e9428c8b0 Merge pull request #2927 from monopole/unpinning
Unpinning after release releases
2020-08-31 12:47:28 -07:00
jregan
c838962432 fix module hashes 2020-08-31 12:08:16 -07:00
jregan
548d10ef08 unpin kyaml 2020-08-31 12:08:16 -07:00
jregan
2db8487f02 unpin cmd/config 2020-08-31 12:08:16 -07:00
jregan
b42f71a20f unpin api 2020-08-31 12:08:16 -07:00
Jeff Regan
e9824aa749 Merge pull request #2926 from monopole/fixAGoMod
Repair a go module spec.
2020-08-31 12:08:06 -07:00
jregan
92cc9fc5e1 Repair a go module spec. 2020-08-31 11:35:32 -07:00
wangyeyu
e53b4c9884 Technical details structure picture 2020-08-31 10:01:19 +08:00
Jeff Regan
e2973f6ecc Merge pull request #2915 from monopole/pinToKustomizeApiv_0_6_0
Pin to kustomize api v0.6.0
2020-08-29 09:42:26 -07:00
jregan
2bf9fc816d Pin to kustomize api v0.6.0 2020-08-29 08:55:29 -07:00
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
Jeff Regan
42d1f7b792 Update cloudbuild.sh 2020-07-04 09:35:52 -07:00
Jeff Regan
8912c454ff Merge pull request #2692 from monopole/independence
New cloud build scripts.
2020-07-04 09:13:18 -07:00
jregan
d4eb2c9426 New cloud build scripts. 2020-07-04 08:58:17 -07:00
Jeff Regan
d2b95fb09a Merge pull request #2691 from phanimarupaka/IncludeSubstFlag
Hide list-subst behind a flag
2020-07-04 08:44:42 -07:00
Jeff Regan
298b3c8622 Merge pull request #2688 from prachirp/grep-shorthand
Drop grep invert-match shorthand flag
2020-07-04 08:44:29 -07:00
Phani Teja Marupaka
c12e95fe06 Hide list-subst behind a flag 2020-07-03 23:55:29 -07:00
Prachi Pendse
87c7a32ffe Drop grep invert-match shorthand flag to resolve conflict with log level verbosity 2020-07-03 11:43:17 -04:00
Jeff Regan
a7545bdad3 Merge pull request #2686 from monopole/updateBuildStrategy
Update build strategy.
2020-07-02 18:09:31 -07:00
Jeffrey Regan
622a121042 Update build strategy. 2020-07-02 18:08:13 -07: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
Kubernetes Prow Robot
c7bc9d2066 Merge pull request #2676 from phanimarupaka/RemoveCountField
Remove count field, convert error to warning
2020-07-01 11:30:17 -07:00
Phani Teja Marupaka
9567d7ef16 Remove count field, convert error to warning 2020-07-01 10:55:30 -07:00
Jeff Regan
e5b0ceb4e3 Merge pull request #2682 from monopole/release_kustomize_v3_7_0_based_on_api_v0_4_2
Prep to release kustomize 3.7.0 on api v0.4.2
2020-07-01 07:23:15 -07:00
jregan
5fb238a581 Prep to release kustomize 3.7.0 on api v0.4.2 2020-07-01 06:51:53 -07:00
Jeff Regan
3ddc9af6c5 Merge pull request #2680 from monopole/syncEverythingTo_gopkg_in_yaml_v2_v2_3_0
Sync everything to gopkg.in/yaml.v2 v2.3.0 via kyaml v0.3.4
2020-06-30 19:07:33 -07:00
jregan
128e171c20 Sync everything to gopkg.in/yaml.v2 v2.3.0 via kyaml v0.3.4 2020-06-30 18:53:11 -07:00
Jeff Regan
c2681b6fae Merge pull request #2679 from monopole/upgradeKyaml_gopkgyaml_deps
Upgrade to gopkg.in/yaml.v2 v2.3.0
2020-06-30 18:31:21 -07:00
Jeff Regan
ae5c392319 Merge pull request #2678 from monopole/gopkg_in_yaml_v2_v2_3_0
Upgrade to gopkg.in/yaml.v2 v2.3.0
2020-06-30 18:14:18 -07:00
jregan
66bcf84682 Upgrade to gopkg.in/yaml.v2 v2.3.0 2020-06-30 18:06:06 -07:00
jregan
436dada184 Upgrade to gopkg.in/yaml.v2 v2.3.0 2020-06-30 17:45:43 -07:00
Jeff Regan
a689e0c2b4 Merge pull request #2675 from monopole/kyaml_v0_3_3
Switch kustomize to kyaml v0.3.3
2020-06-30 17:45:30 -07:00
jregan
30ae7183a4 Switch kustomize to kyaml v0.3.3 2020-06-30 15:46:26 -07:00
Jeff Regan
279a9b673f Merge pull request #2674 from mortent/RemoveKstatus
Remove the kstatus module
2020-06-30 15:10:23 -07:00
Jeff Regan
0ac45c65c9 Merge pull request #2652 from omninonsense/add-sopsgenerator-example
Add link to another Go plugin
2020-06-30 15:09:47 -07:00
Jeff Regan
d7fb813c16 Merge pull request #2666 from viggys/master
configMapGenerator docs content addition for `envs` option
2020-06-30 15:09:12 -07:00
Jeff Regan
83c5c4d1f1 Merge pull request #2661 from trodge/field-not-found-error
Error message for creating setter that matches no fields
2020-06-30 15:08:28 -07:00
Kubernetes Prow Robot
7259d3eb48 Merge pull request #2670 from phanimarupaka/CheckRequiredSetters
Check if required setters are set
2020-06-30 13:34:07 -07:00
Morten Torkildsen
0e44202c20 Remove the kstatus module 2020-06-30 13:27:02 -07:00
Phani Teja Marupaka
0d90b769f1 Check if required setters are set 2020-06-30 13:21:17 -07:00
Jeff Regan
7ad2791072 Merge pull request #2667 from Shell32-Natsu/kpt-function
Improvements for KRM function implementation
2020-06-30 10:47:17 -07:00
Kubernetes Prow Robot
6de94548ba Merge pull request #2669 from monopole/notZero
Fix an index.
2020-06-30 10:34:06 -07:00
Jeff Regan
b1b190227e Merge pull request #2672 from wyyxd2017/hato2
fix k8s api doc
2020-06-30 09:46:15 -07:00
wangyeyu
4ceddaa8f4 kubernetes api 2020-06-30 14:19:27 +08:00
wangyeyu
9e64ac5315 help doc 2020-06-30 14:12:20 +08:00
jregan
f24ec14956 Fix an index. 2020-06-29 17:48:30 -07:00
Donny Xia
98a92a6443 Remove comment from fnexectest.sh 2020-06-29 16:57:49 -07:00
Donny Xia
8bb612889c Improve function invocation 2020-06-29 16:51:56 -07:00
Donny Xia
e3ec184e92 Add unit test for fnplugin 2020-06-29 14:07:48 -07:00
Donny Xia
3019230283 Move functionConfig from items to upper level 2020-06-29 13:35:14 -07:00
Vignesh Subramanian
69adcf9aaf configMapGenerator docs content addition 2020-06-30 00:44:14 +05:30
Donny Xia
8d543d8483 Refactor 2020-06-29 11:12:20 -07:00
Donny Xia
94a55210e1 skeleton for kustomize function 2020-06-29 10:45:37 -07:00
Jeff Regan
441581b745 Merge pull request #2597 from aodinokov/fnplugins
PoC to use kpt functions as kustomize plugins
2020-06-29 10:38:32 -07:00
Thomas Rodgers
a066ba9628 added count to expected output 2020-06-29 10:16:36 -07:00
Thomas Rodgers
3a0dd72c88 added count for list setters 2020-06-29 09:52:18 -07:00
Thomas Rodgers
d4ed285fd1 added count for creating setters 2020-06-29 09:37:18 -07:00
Thomas Rodgers
4cae8cfe9b added error message 2020-06-29 09:37:18 -07:00
Jeff Regan
b044a52a84 Merge pull request #2664 from monopole/upgradeTo_Kyaml_v0_3_2
Upgrade kustomize to kyaml v0.3.2
2020-06-28 12:54:15 -07:00
jregan
5607478d8e Upgrade kustomize to kyaml v0.3.2 2020-06-28 12:36:21 -07:00
Jeff Regan
d60cf8ebc5 Merge pull request #2663 from monopole/smpAttempt
Start supporting strategic merge patch in kyaml/yaml/merge2.
2020-06-28 12:28:03 -07:00
jregan
ef04983392 Start supporting strategic merge patch in kyaml merge2. 2020-06-28 12:12:09 -07:00
Jeff Regan
2153863355 Merge pull request #2660 from monopole/kyaml_0_3_1
Switch to kyaml v0.3.1
2020-06-26 15:58:10 -07:00
jregan
4afab168c5 Switch to kyaml v0.3.1 2020-06-26 15:28:12 -07:00
Jeff Regan
2c52e3a851 Merge pull request #2659 from monopole/schemaTest
Allow multiple patch strategies.
2020-06-26 15:04:12 -07:00
jregan
781e396122 Allow multiple patch strategies. 2020-06-26 14:46:29 -07:00
Jeff Regan
cebb1b31ab Merge pull request #2658 from monopole/volMergeTests
Deployment volume merge tests.
2020-06-26 14:33:49 -07:00
jregan
9137d2a39a Deployment volume merge tests. 2020-06-26 14:19:15 -07:00
Kubernetes Prow Robot
95f4ecd261 Merge pull request #2657 from phanimarupaka/FixCommentsInFunctions
Fix copy comments for Folded style scalar nodes
2020-06-26 12:41:31 -07:00
Phani Teja Marupaka
600d4f2c0b Fix copy comments for Folded style scalar nodes 2020-06-26 12:22:08 -07:00
Jeff Regan
6c4c5cf9ad Merge pull request #2655 from monopole/updatePSMT
Update SMP transformer for kyaml
2020-06-26 11:35:56 -07:00
jregan
5f5b23af58 Update SMP transformer for kyaml 2020-06-26 11:14:02 -07:00
Jeff Regan
ae5a690146 Merge pull request #2654 from monopole/moreKyamlTests
More kyaml list merge tests
2020-06-26 11:03:15 -07:00
jregan
625e011e2b More kyaml list merge tests 2020-06-26 10:58:27 -07:00
Jeff Regan
01ce33b926 Merge pull request #2653 from monopole/apiversionv1
Convert all deployments to v1 to use openapi schema.
2020-06-26 10:58:02 -07:00
jregan
a323d78bbc Convert all deployments to v1 to use openapi schema. 2020-06-26 10:30:02 -07:00
Nino Miletich
69dc34500a docs: add link to another Go plugin 2020-06-26 17:02:00 +01:00
Alexey Odinokov
919bdb84c9 Refactoring to get rid of duplicated code 2020-06-26 04:28:38 +00:00
Alexey Odinokov
178f4e21f0 Added test for exec-based function generator 2020-06-26 04:22:33 +00:00
Alexey Odinokov
d732a6faab Gave up to install docker in pod. Just skipping tests that require docker if there is no binary 2020-06-26 04:22:33 +00:00
Alexey Odinokov
f053ca6a5f little fix 2020-06-26 04:22:33 +00:00
Alexey Odinokov
dfc5c32af5 Added manual start of rootless docker 2020-06-26 04:22:33 +00:00
Alexey Odinokov
80b3f4e00a Added info about user to subgid 2020-06-26 04:22:33 +00:00
Alexey Odinokov
4646bca230 Added info about user to subuid 2020-06-26 04:22:32 +00:00
Alexey Odinokov
57ca8fa321 Do update of repos 2020-06-26 04:22:32 +00:00
Alexey Odinokov
de7fa4bf3a Check what is os release 2020-06-26 04:22:32 +00:00
Alexey Odinokov
af1280ea43 Install uidmap before docker 2020-06-26 04:22:32 +00:00
Alexey Odinokov
0dd191c0f6 Added flag to skip iptables 2020-06-26 04:22:32 +00:00
Alexey Odinokov
e20e126d65 Switched back to rootless docker 2020-06-26 04:22:32 +00:00
Alexey Odinokov
abf862fff1 Added more post-install check for docker 2020-06-26 04:22:32 +00:00
Alexey Odinokov
27cf3981ca Added post-install check for docker 2020-06-26 04:22:32 +00:00
Alexey Odinokov
2c39ff0fa0 Changed to std docker to run fn tests 2020-06-26 04:22:32 +00:00
Alexey Odinokov
afc14afe45 Trying to install rootless docker to run fn tests 2020-06-26 04:22:31 +00:00
Alexey Odinokov
6e91e0667d Disabled tests because we don't have docker installed 2020-06-26 04:22:31 +00:00
Alexey Odinokov
1aca8b8b9e Corrected literal to make lint happy 2020-06-26 04:22:31 +00:00
Alexey Odinokov
448c060084 Added tests for fn-based generators and transformers 2020-06-26 04:22:31 +00:00
Alexey Odinokov
b3951942e3 removed commented import to make linter happy 2020-06-26 04:22:31 +00:00
Alexey Odinokov
b78464c8b1 Made generators work in addition to transformers
Made go fmt to make linter happy
2020-06-26 04:22:31 +00:00
Alexey Odinokov
9bd4f78288 PoC to use kpt functions as kustomize plugins
Closes [1]
In addition removes accidentally committed binary [2]

[1]
https://github.com/GoogleContainerTools/kpt/issues/646

[2]
1644fdd076 (diff-78873bc1f515e5cb644e68f0bcbaba23)
2020-06-26 04:22:31 +00:00
Jeff Regan
85e9fa94b0 Merge pull request #2648 from monopole/moreTests
Add more SMP tests.
2020-06-25 12:27:53 -07:00
jregan
c754927112 Add more SMP tests. 2020-06-25 12:09:53 -07:00
Jeff Regan
8049c57b72 Merge pull request #2623 from Shell32-Natsu/releasing-doc
Releasing doc
2020-06-25 11:04:51 -07:00
Jeff Regan
695ec44bf7 Merge pull request #2636 from jijiew/fmt-test
add test case showing that kustomize/kpt fmt works on yaml file with top-level lists
2020-06-25 11:04:21 -07:00
Jeff Regan
5b394b2079 Merge pull request #2638 from haiyanmeng/mem
Avoid reprocess queries whose range size is 0 and improve memory usage
2020-06-25 10:58:20 -07:00
Jeff Regan
97c2ac77cd Merge pull request #2639 from Shell32-Natsu/knative-back-ref
Add back reference for secret in knative service
2020-06-25 10:57:44 -07:00
Jijie Wei
3183fcc926 simplify the test case 2020-06-25 10:01:15 -07:00
Jijie Wei
0af9ca1266 simplify the test case 2020-06-25 09:59:17 -07:00
Kubernetes Prow Robot
a6111b5c3c Merge pull request #2642 from mortent/FixListSettersErr
Fix failing list setters test
2020-06-24 10:01:18 -07:00
Morten Torkildsen
fdbd1bdbbb Fix failing list setters test 2020-06-23 17:32:21 -07:00
Morten Torkildsen
16baf7a955 Merge pull request #2629 from phanimarupaka/ListSettersNoSet
Tests for List setters should not alter resources
2020-06-23 17:17:30 -07:00
Kubernetes Prow Robot
69aea07c4e Merge pull request #2637 from pwittrock/merge-primitize
Support merging primitive lists
2020-06-23 16:55:18 -07:00
Kubernetes Prow Robot
2250ad3e18 Merge pull request #2635 from phanimarupaka/RequiredSettersForApply
Required setters for apply
2020-06-23 15:19:17 -07:00
Phani Teja Marupaka
c107d1ddff List setters should not alter resources
Remove Dryrun flag
2020-06-23 14:39:03 -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
Jijie Wei
f17b893dd2 fmt 2020-06-23 13:16:18 -07:00
Phillip Wittrock
09894d3022 Support merging primitive lists 2020-06-23 12:39:51 -07:00
Donny Xia
fd3e84f701 Add knative API version 2020-06-23 11:58:14 -07:00
Donny Xia
22d5d4d2c1 Add back reference for secret in knative service 2020-06-23 11:48:26 -07:00
Haiyan Meng
145ba0c7ff Avoid reprocess queries whose range size is 0 2020-06-23 11:36:29 -07:00
Haiyan Meng
a83433d5cf Optimize memory usage by avoiding accumulating all the referred
documents into a single stack.
2020-06-23 11:36:29 -07:00
Haiyan Meng
2d496e0efe Update golang to 1.14 2020-06-23 11:25:37 -07:00
Haiyan Meng
171412cc98 Use RWMutex to control the map access
Without RWMutex, we may run into fatal error: concurrent map read and map write.
2020-06-23 11:25:37 -07:00
Phani Teja Marupaka
68ab3b87d9 Required setters for apply 2020-06-22 22:33:21 -07:00
Jijie Wei
e9bd11caaa add test for fmt on yaml file of a list 2020-06-22 22:32:08 -07:00
Kubernetes Prow Robot
a895220743 Merge pull request #2553 from jijiew/deletesetter
Delete setters
2020-06-22 12:15:40 -07:00
Kubernetes Prow Robot
ab2dc7fcb9 Merge pull request #2546 from phanimarupaka/FnSourceJson
Include json files for fn source and sink
2020-06-22 11:00:40 -07:00
Kubernetes Prow Robot
afde29601a Merge pull request #2633 from syed-awais-ali/patch-1
fix typo
2020-06-22 10:34:40 -07:00
Jijie Wei
be0f1a7fcb remove the uncessary conversion 2020-06-22 10:00:22 -07:00
Jijie Wei
99d2994b98 remove empty definition 2020-06-22 09:54:10 -07:00
Syed Awais Ali
94101fb7cc fix typo 2020-06-22 15:59:38 +05:00
Kubernetes Prow Robot
346071897e Merge pull request #2630 from ash2k/ash2k/drop-ghodss-yaml
Drop ghodss/yaml dependency
2020-06-21 10:32:38 -07:00
Mikhail Mazurskiy
0772540214 Drop github.com/ghodss/yaml dependency 2020-06-21 20:35:50 +10:00
Donny Xia
6791688f5f Code review 2020-06-19 19:24:41 -07:00
Phani Teja Marupaka
28307bc435 Simplify parsing 2020-06-19 17:21:13 -07:00
Jijie Wei
29cadfe8b0 modify the doc to simple string, will update the doc later 2020-06-19 16:35:57 -07:00
Kubernetes Prow Robot
68f4f330f5 Merge pull request #2601 from sunny0826/master
zh docs for docsy site
2020-06-19 15:54:40 -07:00
Jeff Regan
507779c9dc force branch fetches in gitrunner 2020-06-19 15:34:55 -07:00
Jeff Regan
062d0f7b75 Merge pull request #2626 from monopole/delegateKunstructured
Delegate to Kunstructured.
2020-06-19 15:29:20 -07:00
jregan
e783af2881 Delegate to Kunstructured. 2020-06-19 15:06:13 -07:00
Jeff Regan
f2da1f621f Merge pull request #2624 from monopole/sortIfc
Sort ifc.go for easier change monitoring during refactor.
2020-06-19 15:06:05 -07:00
jregan
294312f2fc Sort ifc.go for easier change monitoring during refactor. 2020-06-19 14:49:57 -07:00
Jeff Regan
ff79bd0b31 Merge pull request #2613 from Shell32-Natsu/validator
Introduce `validators` field in kustomization file
2020-06-19 14:49:44 -07:00
Jeff Regan
410e300243 Merge pull request #2622 from arrikto/feature-update-components-example
Revamp components example
2020-06-19 14:45:44 -07:00
Phani Teja Marupaka
e994b3b566 E2e test for run with json 2020-06-19 12:33:08 -07:00
Phani Teja Marupaka
b39c522cc1 Suggested changes 2020-06-19 12:33:08 -07:00
Phani Teja Marupaka
dc4bf03da2 Write json files in sink 2020-06-19 12:33:07 -07:00
Phani Teja Marupaka
a158eeaaff Suggested changes 2020-06-19 12:33:07 -07:00
Phani Teja Marupaka
4cd3944860 Include json files for fn source 2020-06-19 12:33:06 -07:00
Donny Xia
79a48a8802 Remove files 2020-06-19 10:52:56 -07:00
Donny Xia
5a33e90f18 Update releasing readme 2020-06-19 10:50:17 -07:00
Ioannis Androulidakis
e77d1a881f Revamp the components example
Standardize on `patchesStrategicMerge` and `patchesJSON6902` instead of
`patches` in kustomization files.

Also, add example commands to create local input files for existing
SecretGenerators.

Signed-off-by: Ioannis Androulidakis <ioannis@arrikto.com>
2020-06-19 14:37:39 +03:00
Ioannis Androulidakis
343b938c73 Remove WIP from components example
Signed-off-by: Ioannis Androulidakis <ioannis@arrikto.com>
2020-06-19 14:37:39 +03:00
Jijie Wei
25186e94af implement new visitor method 2020-06-18 13:49:54 -07:00
Jijie Wei
e4ba898e20 return subst name inerror message 2020-06-18 13:49:53 -07:00
Jijie Wei
22a6017870 update the pr to handle the case when the setter to be deleted is used in substitution 2020-06-18 13:49:52 -07:00
Donny Xia
e62f1adabf Force update local tags 2020-06-18 12:20:08 -07:00
Donny Xia
7e2d3ff5ab Reuse tansformer codes 2020-06-18 12:18:37 -07:00
Kubernetes Prow Robot
fb6830c98a Merge pull request #2617 from phanimarupaka/FixArraySetters
Fix validation for array setters
2020-06-18 12:03:11 -07:00
Phani Teja Marupaka
52e8a701ac Fix validation for array setters 2020-06-18 11:50:02 -07:00
Donny Xia
160485ef19 Add examples to validators 2020-06-17 14:44:59 -07:00
Donny Xia
cea1154cd9 Add exception for "validated-by" label 2020-06-17 14:35:12 -07:00
Donny Xia
4843718a2b Check modification 2020-06-17 14:35:12 -07:00
Donny Xia
a0c1979798 Add validator to kustomization 2020-06-17 14:35:12 -07:00
Kubernetes Prow Robot
8576acf1aa Merge pull request #2612 from mortent/UpdateVersionsForKyamlAndCmdConfig
Update VERSIONS file with latest versions of kyaml and cmd/config
2020-06-17 14:08:05 -07:00
Morten Torkildsen
1e7a764900 Update VERSIONS file with latest versions of kyaml and cmd/config 2020-06-17 13:22:11 -07:00
Kubernetes Prow Robot
9b5ce5002a Merge pull request #2608 from mortent/AllValuesAcceptedAsStringType
Accept all values as string type in validation
2020-06-16 16:10:05 -07:00
Morten Torkildsen
0952421800 Accept all values as string type in validation 2020-06-16 15:54:28 -07:00
Kubernetes Prow Robot
df9af1869f Merge pull request #2605 from phanimarupaka/ArraySettersUX
Avoid manual step for creating array setters
2020-06-16 15:30:05 -07:00
Phani Teja Marupaka
dbb16dcb6d Suggested changes 2020-06-16 15:11:25 -07:00
Jeff Regan
cc8fc99999 Merge pull request #2603 from Shell32-Natsu/doc
Update GO plugin doc
2020-06-16 10:22:36 -07:00
Phani Teja Marupaka
0f0efe2a4c Avoid manual step for creating array setters 2020-06-15 22:34:05 -07:00
Donny Xia
36165d2843 Update GO plugin doc 2020-06-15 14:22:31 -07:00
Kubernetes Prow Robot
3e9276271a Merge pull request #2599 from mortent/FixValidation
Fix validation logic to use yaml parsing instead of json
2020-06-15 11:31:57 -07:00
guoxudong
af7df1448d fix 2020-06-15 14:21:15 +08:00
guoxudong
518147c129 add zh docsy 2020-06-15 13:39:13 +08:00
Kubernetes Prow Robot
a0072a2cf9 Merge pull request #2600 from pwittrock/master
Add more Kustomize contributing docs
2020-06-14 14:17:55 -07:00
Phillip Wittrock
c4518e964f Add more Kustomize contributing docs 2020-06-14 08:26:51 -07:00
Kubernetes Prow Robot
c2eb09cd8f Merge pull request #2593 from pwittrock/master
kustomize docs tweaks
2020-06-13 17:43:55 -07:00
Kubernetes Prow Robot
89b4e7ae02 Merge pull request #2596 from Liujingfang1/master
cleanup binary file
2020-06-13 17:29:55 -07:00
Morten Torkildsen
714ff85806 Fix validation logic to use yaml parsing instead of json 2020-06-13 14:07:05 -07:00
Phillip Wittrock
589ddcb4fa kustomize docs tweaks 2020-06-12 11:22:26 -07:00
Jingfang Liu
3d09b0cb83 cleanup binary file 2020-06-12 11:06:49 -07:00
Kubernetes Prow Robot
3012dd67ac Merge pull request #2592 from pwittrock/master
Fix kustomize docs "move to" links
2020-06-11 21:07:56 -07:00
Phillip Wittrock
60f826fb2d Generate kustomize docs -- update last modified 2020-06-11 20:54:46 -07:00
Phillip Wittrock
5d24062d42 Fix kustomize docs "move to" links 2020-06-11 20:46:25 -07:00
Jeff Regan
d553919dfb Merge pull request #2589 from pierreozoux/patch-1
Fixes markdown.
2020-06-11 16:52:32 -07:00
Jeff Regan
661743c7e5 Merge pull request #2576 from pwittrock/master
Use docsy site for kustomize docs
2020-06-11 11:54:02 -07:00
Jeff Regan
1dc22e3f0d Merge pull request #2579 from pietervincken/re-introduce-shallow-git-clones
Re-introduce shallow git clones for git based remote resources
2020-06-11 11:01:04 -07:00
Pierre Ozoux
808843457a Fixes markdown. 2020-06-11 10:46:29 +02:00
Phillip Wittrock
42497c664f Convert docs to docsy 2020-06-10 14:59:19 -07:00
Kubernetes Prow Robot
88cc78d5b7 Merge pull request #2578 from Liujingfang1/master
Add kustomize build flag --enable_managedby_label
2020-06-09 14:38:04 -07:00
Jeff Regan
9ac9a28db7 Merge pull request #2580 from haiyanmeng/remove-external-ip
Avoid exposing ElasticSearch DB over public IPs
2020-06-09 14:22:53 -07:00
Haiyan Meng
5cf0d887b1 Avoid exposing ElasticSearch DB over public IPs 2020-06-09 13:03:37 -07:00
Pieter Vincken
58c2df2dec fix: add the fetch head in the correct location 2020-06-09 20:22:28 +02:00
Jingfang Liu
1644fdd076 Add kustomize build flag --enable_managedby_label 2020-06-09 11:10:19 -07:00
Pieter Vincken
cd25740b61 fix: solve issues with tags not being loaded 2020-06-09 19:56:04 +02:00
Pieter Vincken
28045399f3 fix: add missing assignment 2020-06-09 16:57:01 +02:00
Pieter Vincken
e630334837 fix: re-add log outputs 2020-06-09 16:56:20 +02:00
Pieter Vincken
b97df057c1 feat: re-introduce shallow git clones
Making full git clones slows down the kustomize build significantly for big repositories.
2020-06-09 16:35:09 +02:00
Kubernetes Prow Robot
546a7386ff Merge pull request #2481 from Liujingfang1/master
support option for adding managed-by label
2020-06-08 13:47:47 -07:00
Jingfang Liu
4b117c4736 support option for adding managed-by label 2020-06-08 13:08:10 -07:00
Kubernetes Prow Robot
bc968d17e3 Merge pull request #2571 from pwittrock/release
Update kustomize to use latest version of cmd/config and cli-utils
2020-06-08 13:03:47 -07:00
Phillip Wittrock
51c2fe9742 Update kustomize to use latest version of cmd/config and cli-utils 2020-06-08 12:46:18 -07:00
Kubernetes Prow Robot
25a38ad2b6 Merge pull request #2573 from pankona/update-go-mod-to-use-go-1-14
Update go.mod to go 1.14
2020-06-08 10:09:49 -07:00
Kubernetes Prow Robot
8046efd261 Merge pull request #2575 from pwittrock/json
Add tests for reading json
2020-06-08 09:37:48 -07:00
Phillip Wittrock
9a4acba118 Add tests for reading json 2020-06-08 08:48:14 -07:00
pankona
d9d67e33e7 Run travis/check-go-mod.sh and make all 2020-06-08 16:25:52 +09:00
pankona
18d6a96f80 Update go.mod to use go 1.14 2020-06-08 16:25:35 +09:00
Kubernetes Prow Robot
458a7c532c Merge pull request #2567 from pwittrock/kubectl-krm
Refactor kustomize config command structure
2020-06-06 09:03:45 -07:00
Phillip Wittrock
701c217791 Refactor kustomize config command structure
- Create cfg, fn, live parent commands
2020-06-06 08:50:41 -07:00
Kubernetes Prow Robot
e042a22d0f Merge pull request #2570 from mortent/FixEmptyStringHandling
Treat empty strings as string type instead of null type
2020-06-05 15:23:46 -07:00
Morten Torkildsen
4fca00014c Treat empty strings as string type instead of null type 2020-06-05 15:04:18 -07:00
Jeff Regan
1c2eaa9d29 Merge pull request #2554 from quiye/ResMap
Fix length checking for ResMap resources
2020-06-05 14:06:37 -07:00
Kubernetes Prow Robot
1f32e89d95 Merge pull request #2560 from yutachaos/feature/added_numberonlytag_test_editset_image
Add test case when image tag is a number
2020-06-05 13:57:46 -07:00
Jeff Regan
b7a379604c Merge pull request #2568 from monopole/addTests
Add kustomize v3.6.1 e2e testing to prow tests
2020-06-05 13:46:14 -07:00
jregan
cea461e8f2 addTests 2020-06-05 13:24:56 -07:00
Kubernetes Prow Robot
73157c7141 Merge pull request #2562 from sunny0826/plugin-guided
add zh doc exec/go plugin
2020-06-05 10:23:44 -07:00
Kubernetes Prow Robot
72dc895c52 Merge pull request #2552 from pwittrock/krm
Write setter definitions to `Krmfile` instead of `kustomization`
2020-06-05 10:01:46 -07:00
Kubernetes Prow Robot
2aca65a126 Merge pull request #2565 from MadVikingGod/fix-windows
Fix windows builds.
2020-06-05 08:57:44 -07:00
Aaron Clawson
ac2e6990c3 Fix windows builds.
This updates golang.org/x/crypto to a version that has reverted the changes made because of a breaking api change in golang.org/x/sys.
2020-06-05 08:55:15 -05:00
guoxudong
8f0900f95e fix 2020-06-05 09:42:05 +08:00
Kubernetes Prow Robot
2549a8c6be Merge pull request #2558 from Shell32-Natsu/statefulset-name-in-hpa
Update StatefulSet ref name in HPA
2020-06-04 11:35:14 -07:00
yutachaos
88ebe1c73e Add test case when image tag is a number 2020-06-04 11:39:44 +09:00
quiye
08922cfe29 Fix length checking for ResMap resources 2020-06-04 08:37:44 +09:00
Kubernetes Prow Robot
952a2ebbf4 Merge pull request #2547 from dan-slinky-ckpd/patch-1
Update set.md examples to use correct field name
2020-06-03 14:08:43 -07:00
Phillip Wittrock
075846c731 Support initializing a directory with a Krmfile 2020-06-03 11:56:59 -07:00
Kubernetes Prow Robot
d531de6774 Merge pull request #2551 from phanimarupaka/NestedSubst
Nested substitutions
2020-06-03 10:56:11 -07:00
Kubernetes Prow Robot
cedcf3ac04 Merge pull request #2168 from pgpx/feature-kustomizationpatch
Implement "kind: Component" to support composition
2020-06-03 10:32:11 -07:00
guoxudong
8ce637a004 add zh doc exec/go plugin 2020-06-03 17:12:47 +08:00
Phani Teja Marupaka
10250286c7 Check for cycles during create-subst 2020-06-01 20:27:13 -07:00
Phani Teja Marupaka
a43d43f2c4 Nested substitutions 2020-06-01 20:27:02 -07:00
Donny Xia
8356979e1f Update StatefulSet ref name in HPA 2020-06-01 16:52:13 -07:00
Morten Torkildsen
46d9a8dc46 Merge pull request #2556 from mortent/releasecmdconf
release cmd/config
2020-06-01 12:52:53 -07:00
Morten Torkildsen
cb3854edaa release cmd/config 2020-06-01 12:33:34 -07:00
Kubernetes Prow Robot
083a266b0b Merge pull request #2555 from mortent/ReleaseKyaml
Release v0.1.13 of kyaml
2020-06-01 11:57:56 -07:00
Morten Torkildsen
d6fdf1c01a Release v0.1.13 of kyaml 2020-06-01 11:42:47 -07:00
Kubernetes Prow Robot
b679e33d47 Merge pull request #2545 from jijiew/addingFlags
Accept `set` value as flag or argument
2020-05-30 08:31:53 -07:00
Jijie Wei
e63b9ef825 update on util and comments 2020-05-29 16:23:10 -07:00
Jijie Wei
4b5b0dfdce rebase 2020-05-29 12:50:03 -07:00
Jijie Wei
572260c0f0 change args to use flags instead, so that values starting with hyphen can be correctly parsed. 2020-05-29 12:45:31 -07:00
Phillip Wittrock
0e5e2648b3 write krm metadata to Krmfile instead of Kustomization 2020-05-29 12:01:01 -07:00
Jeff Regan
144471ce78 Merge pull request #2550 from Shell32-Natsu/releasing-replace
Check replace in go.mod before releasing
2020-05-28 15:52:11 -07:00
Paul Martin
98cb7fc8cd Additional tests around reusing the same bases and components 2020-05-28 23:02:32 +01:00
Paul Martin
ca8e00fc15 Replace 'patch' with 'comp' in test data. 2020-05-28 23:02:32 +01:00
Paul Martin
93b0b1b0b1 Refactored Compontent tests to be table-driven 2020-05-28 23:02:32 +01:00
Paul Martin
34a442bbef Additional tests around reusing the same bases and components 2020-05-28 23:02:31 +01:00
Donny Xia
37918ae745 Check error from ioutil.TempDir in test 2020-05-28 13:02:46 -07:00
Donny Xia
dca164e967 More tests 2020-05-28 12:53:26 -07:00
Donny Xia
8ac2365406 Check replace in go.mod before releasing 2020-05-28 12:34:58 -07:00
Jeff Regan
c1a2bf14da Merge pull request #2548 from Shell32-Natsu/go-getter-doc
Add a note for go-getter
2020-05-28 11:38:24 -07:00
Donny Xia
a7af7df9cb Add a note for go-getter 2020-05-28 10:15:19 -07:00
Dan Slinky @ Cookpad
8d148c7ee4 Update set.md examples to use correct field name 2020-05-28 13:36:12 +01:00
Kubernetes Prow Robot
0b94a1405d Merge pull request #2544 from Shell32-Natsu/add-stringdata-to-encodesecret
Consider stringData when calculate secret hash
2020-05-27 17:22:02 -07:00
Kubernetes Prow Robot
b083187e6a Merge pull request #2509 from phanimarupaka/RefChange
Short hand notation for setters/subst
2020-05-27 14:36:02 -07:00
Donny Xia
4dcf81050e Consider stringData when calculate secret hash 2020-05-27 13:58:28 -07:00
Jeff Regan
c97fa946d5 Merge pull request #2543 from monopole/pinToApiv041
pin CLI to API v0.4.1
2020-05-27 13:44:51 -07:00
jregan
c35f5b0189 pin CLI to API v0.4.1 2020-05-27 13:32:22 -07:00
Jeff Regan
dd4aafe148 Merge pull request #2537 from Shell32-Natsu/fix-clone-hash
Fix git commit hash ignored
2020-05-27 13:22:08 -07:00
Jeff Regan
adb56abd99 Merge pull request #2542 from monopole/pinKustomizeToCmdKubectl_v0_1_0
pin kustomize to cmd/kubectl_v0_1_0
2020-05-27 12:36:44 -07:00
jregan
def978b334 pin kustomize to cmd/kubectl_v0_1_0 2020-05-27 12:20:39 -07:00
Phani Teja Marupaka
f7ca4fa106 Suggested Changes 2020-05-27 11:47:31 -07:00
Jeff Regan
ff7a7937c5 Merge pull request #2541 from monopole/pinToKStatus_v0_0_2
Pin to kstatus/v0.0.2
2020-05-27 11:13:15 -07:00
jregan
90c23026c2 Pin to kstatus/v0.0.2 2020-05-27 10:56:01 -07:00
Donny Xia
e5e4f33ac7 Fix go-getter 2020-05-26 17:42:31 -07:00
Donny Xia
5449dbc775 Fix git commit hash ignored 2020-05-26 14:44:37 -07:00
Kubernetes Prow Robot
52c5a9d380 Merge pull request #2490 from sunny0826/zh-docs
add zh docs plugins-builtions.md
2020-05-26 14:06:42 -07:00
Kubernetes Prow Robot
74d59f87c2 Merge pull request #2536 from Shell32-Natsu/merge-error-message
Improve error message for merge error
2020-05-26 13:54:41 -07:00
Phani Teja Marupaka
98ba8b7491 Change to create setter 2020-05-26 13:39:23 -07:00
Donny Xia
e05404f89c Improve error message for merge error 2020-05-26 10:12:33 -07:00
Jeff Regan
9e40cc177a Merge pull request #2532 from monopole/upgradeToV040
Upgrade CLI to API v0.4.0
2020-05-24 10:41:56 -07:00
jregan
315f7c6e7f Upgrade CLI to API v0.4.0 2020-05-24 10:28:30 -07:00
Phani Teja Marupaka
b3f5874978 Short hand notation for set 2020-05-21 11:15:16 -07:00
guoxudong
59f8f4ae14 fix 2020-05-20 09:25:31 +08:00
Paul Martin
ab9d4c7e7b Added test to ensure that individusal files cannot be added to the components list. 2020-05-19 19:26:18 +01:00
guoxudong
7bae481252 fix 2020-05-19 10:19:59 +08:00
Paul Martin
c5c53011da PoC to add Components to a separate components list (instead of resources)
If this idea is preferred, the code could really do with a refactor (probably using closures to control the behaviour of accumulate directory)
2020-05-18 19:25:29 +01:00
Paul Martin
fdfb58cc3e Require version kustomize.config.k8s.io/v1alpha1 for Component 2020-05-18 19:25:29 +01:00
Paul Martin
1079d8604c Renamed KustomizationPatch to Component 2020-05-18 19:25:29 +01:00
Paul Martin
4454edc14c Implement "kind: KustomizationPatch" to support composition of Kustomize files 2020-05-18 19:25:29 +01:00
guoxudong
bf71dce60c add zh docs plugins-builtions.md 2020-05-15 14:44:27 +08:00
12176 changed files with 971759 additions and 27523 deletions

2
.gitignore vendored
View File

@@ -19,3 +19,5 @@
# macOS
*.DS_store
.bin

View File

@@ -14,11 +14,9 @@ all: verify-kustomize
verify-kustomize: \
lint-kustomize \
test-unit-kustomize-all \
test-examples-kustomize-against-HEAD
# TODO: restore test-examples-kustomize-against-3.5.5 \
# once it works. Likely have to fix and release 3.6
# test-examples-kustomize-against-3.5.4 no longer works because
# the examples tests features not in 3.5.4
test-examples-kustomize-against-HEAD \
test-examples-kustomize-against-3.8.0 \
test-examples-kustomize-against-3.8.2
# The following target referenced by a file in
# https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/kustomize
@@ -26,9 +24,11 @@ verify-kustomize: \
prow-presubmit-check: \
lint-kustomize \
test-unit-kustomize-all \
test-examples-kustomize-against-HEAD \
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
@@ -47,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
@@ -83,6 +84,7 @@ $(MYGOBIN)/kustomize:
install-tools: \
$(MYGOBIN)/goimports \
$(MYGOBIN)/golangci-lint-kustomize \
$(MYGOBIN)/gorepomod \
$(MYGOBIN)/mdrip \
$(MYGOBIN)/pluginator \
$(MYGOBIN)/stringer
@@ -198,7 +200,7 @@ build-kustomize-api: $(builtinplugins)
.PHONY: test-unit-kustomize-api
test-unit-kustomize-api: build-kustomize-api
cd api; go test ./...
cd api; go test ./... -ldflags "-X sigs.k8s.io/kustomize/api/provenance.version=v444.333.222"
.PHONY: test-unit-kustomize-plugins
test-unit-kustomize-plugins:
@@ -235,10 +237,10 @@ test-examples-kustomize-against-HEAD: $(MYGOBIN)/kustomize $(MYGOBIN)/mdrip
./hack/testExamplesAgainstKustomize.sh HEAD
.PHONY:
test-examples-kustomize-against-3.5.4: $(MYGOBIN)/mdrip
test-examples-kustomize-against-3.8.0: $(MYGOBIN)/mdrip
( \
set -e; \
tag=v3.5.4; \
tag=v3.8.0; \
/bin/rm -f $(MYGOBIN)/kustomize; \
echo "Installing kustomize $$tag."; \
GO111MODULE=on go get sigs.k8s.io/kustomize/kustomize/v3@$${tag}; \
@@ -248,10 +250,10 @@ test-examples-kustomize-against-3.5.4: $(MYGOBIN)/mdrip
)
.PHONY:
test-examples-kustomize-against-3.5.5: $(MYGOBIN)/mdrip
test-examples-kustomize-against-3.8.2: $(MYGOBIN)/mdrip
( \
set -e; \
tag=v3.5.5; \
tag=v3.8.2; \
/bin/rm -f $(MYGOBIN)/kustomize; \
echo "Installing kustomize $$tag."; \
GO111MODULE=on go get sigs.k8s.io/kustomize/kustomize/v3@$${tag}; \
@@ -260,7 +262,6 @@ test-examples-kustomize-against-3.5.5: $(MYGOBIN)/mdrip
cd kustomize; go install .; \
)
# linux only.
# This is for testing an example plugin that
# uses kubeval for validation.

View File

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

View File

@@ -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](docs/INSTALL.md).
Browse the [docs](docs) or jump right into the
tested [examples](examples).
## kubectl integration
Since [v1.14][kubectl announcement] the kustomize build system has been included in kubectl.
@@ -132,20 +129,8 @@ The YAML can be directly [applied] to a cluster:
## Community
To file bugs please read [this](docs/bugs.md).
Before working on an implementation, please
* Read the [eschewed feature list].
* File an issue describing
how the new feature would behave
and label it [kind/feature].
### Other communication channels
- [Slack]
- [Mailing List]
- General kubernetes [community page]
- [file a bug](https://kubernetes-sigs.github.io/kustomize/contributing/bugs/) instructions
- [contribute a feature](https://kubernetes-sigs.github.io/kustomize/contributing/features/) instructions
### Code of conduct
@@ -154,32 +139,27 @@ is governed by the [Kubernetes Code of Conduct].
[`make`]: https://www.gnu.org/software/make
[`sed`]: https://www.gnu.org/software/sed
[DAM]: docs/glossary.md#declarative-application-management
[DAM]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#declarative-application-management
[KEP]: https://github.com/kubernetes/enhancements/blob/master/keps/sig-cli/0008-kustomize.md
[Kubernetes Code of Conduct]: code-of-conduct.md
[Mailing List]: https://groups.google.com/forum/#!forum/kubernetes-sig-cli
[Slack]: https://kubernetes.slack.com/messages/sig-cli
[applied]: docs/glossary.md#apply
[base]: docs/glossary.md#base
[community page]: http://kubernetes.io/community/
[declarative configuration]: docs/glossary.md#declarative-application-management
[eschewed feature list]: docs/eschewedFeatures.md
[applied]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#apply
[base]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#base
[declarative configuration]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#declarative-application-management
[imageBase]: docs/images/base.jpg
[imageOverlay]: docs/images/overlay.jpg
[kind/feature]: /../../labels/kind%2Ffeature
[kubectl announcement]: https://kubernetes.io/blog/2019/03/25/kubernetes-1-14-release-announcement
[kubectl book]: https://kubectl.docs.kubernetes.io/pages/app_customization/introduction.html
[kubernetes documentation]: https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/
[kubernetes style]: docs/glossary.md#kubernetes-style-object
[kustomization]: docs/glossary.md#kustomization
[overlay]: docs/glossary.md#overlay
[overlays]: docs/glossary.md#overlay
[release page]: /../../releases
[resource]: docs/glossary.md#resource
[resources]: docs/glossary.md#resource
[kubernetes style]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#kubernetes-style-object
[kustomization]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#kustomization
[overlay]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#overlay
[overlays]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#overlay
[release page]: https://github.com/kubernetes-sigs/kustomize/releases
[resource]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#resource
[resources]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#resource
[sig-cli]: https://github.com/kubernetes/community/blob/master/sig-cli/README.md
[variant]: docs/glossary.md#variant
[variants]: docs/glossary.md#variant
[v2.0.3]: /../../releases/tag/v2.0.3
[v2.1.0]: /../../releases/tag/v2.1.0
[workflows]: docs/workflows.md
[variant]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#variant
[variants]: https://kubernetes-sigs.github.io/kustomize/api-reference/glossary#variant
[v2.0.3]: https://github.com/kubernetes-sigs/kustomize/releases/tag/v2.0.3
[v2.1.0]: https://github.com/kubernetes-sigs/kustomize/releases/tag/v2.1.0
[workflows]: https://kubernetes-sigs.github.io/kustomize/guides

View File

@@ -29,7 +29,7 @@ func (p *AnnotationsTransformerPlugin) Transform(m resmap.ResMap) error {
err := filtersutil.ApplyToJSON(annotations.Filter{
Annotations: p.Annotations,
FsSlice: p.FieldSpecs,
}, r.Kunstructured)
}, r)
if err != nil {
return err
}

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

@@ -29,7 +29,7 @@ func (p *LabelTransformerPlugin) Transform(m resmap.ResMap) error {
err := filtersutil.ApplyToJSON(labels.Filter{
Labels: p.Labels,
FsSlice: p.FieldSpecs,
}, r.Kunstructured)
}, 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.Kunstructured)
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.Kunstructured)
}
return filtersutil.ApplyToJSON(patchjson6902.Filter{
Patch: p.JsonOp,
}, obj)
}
func NewPatchJson6902TransformerPlugin() resmap.TransformerPlugin {

View File

@@ -4,11 +4,10 @@
package builtins
import (
"encoding/json"
"fmt"
"strings"
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/filters/patchstrategicmerge"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
@@ -22,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(
@@ -67,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
}
@@ -76,42 +73,48 @@ func (p *PatchStrategicMergeTransformerPlugin) Transform(m resmap.ResMap) error
if err != nil {
return err
}
if !p.YAMLSupport {
err = target.Patch(patch.Kunstructured)
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 {
node, err := getRNode(patch)
if err != nil {
return err
}
err = filtersutil.ApplyToJSON(patchstrategicmerge.Filter{
Patch: node,
}, target.Kunstructured)
}
}
return nil
}
//TODO: Remove this once the next version of kyaml is released which
// exposes GetRNode from the filutersutil package.
func getRNode(k json.Marshaler) (*kyaml.RNode, error) {
j, err := k.MarshalJSON()
if err != nil {
return nil, err
}
return kyaml.Parse(string(j))
}
func NewPatchStrategicMergeTransformerPlugin() resmap.TransformerPlugin {
return &PatchStrategicMergeTransformerPlugin{}
}

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.Kunstructured)
} else {
node, err := filtersutil.GetRNode(patch)
if err != nil {
return err
}
return filtersutil.ApplyToJSON(patchstrategicmerge.Filter{
Patch: node,
}, resource.Kunstructured)
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.Kunstructured)
}
}
// 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

@@ -121,13 +121,13 @@ func (p *ValueAddTransformerPlugin) Transform(m resmap.ResMap) (err error) {
if t.FieldPath == types.MetadataNamespacePath {
err = filtersutil.ApplyToJSON(namespace.Filter{
Namespace: p.Value,
}, res.Kunstructured)
}, res)
} else {
err = filtersutil.ApplyToJSON(valueadd.Filter{
Value: p.Value,
FieldPath: t.FieldPath,
FilePathPosition: t.FilePathPosition,
}, res.Kunstructured)
}, res)
}
if err != nil {
return err

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

@@ -31,6 +31,86 @@ apiVersion: apps/v1
metadata:
name: yourDeploy
kind: Deployment
`,
},
"container patch": {
input: `
apiVersion: apps/v1
metadata:
name: myDeploy
kind: Deployment
spec:
template:
spec:
containers:
- name: foo1
- name: foo2
- name: foo3
`,
patch: yaml.MustParse(`
apiVersion: apps/v1
metadata:
name: myDeploy
kind: Deployment
spec:
template:
spec:
containers:
- name: foo0
`),
expected: `
apiVersion: apps/v1
metadata:
name: myDeploy
kind: Deployment
spec:
template:
spec:
containers:
- name: foo1
- name: foo2
- name: foo3
- name: foo0
`,
},
"volumes patch": {
input: `
apiVersion: apps/v1
metadata:
name: myDeploy
kind: Deployment
spec:
template:
spec:
volumes:
- name: foo1
- name: foo2
- name: foo3
`,
patch: yaml.MustParse(`
apiVersion: apps/v1
metadata:
name: myDeploy
kind: Deployment
spec:
template:
spec:
volumes:
- name: foo0
`),
expected: `
apiVersion: apps/v1
metadata:
name: myDeploy
kind: Deployment
spec:
template:
spec:
volumes:
- name: foo1
- name: foo2
- name: foo3
- name: foo0
`,
},
"nested patch": {

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

@@ -1,6 +1,6 @@
module sigs.k8s.io/kustomize/api
go 1.13
go 1.14
require (
github.com/evanphx/json-patch v4.5.0+incompatible
@@ -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
gopkg.in/yaml.v2 v2.2.8
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.1.11
sigs.k8s.io/kustomize/kyaml v0.8.0
sigs.k8s.io/yaml v1.2.0
)

View File

@@ -104,7 +104,6 @@ github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34
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 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
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=
@@ -167,7 +166,6 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -241,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=
@@ -281,7 +280,6 @@ github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
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 h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
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=
@@ -309,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=
@@ -343,6 +343,7 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d h1:K6eOUihrFLdZjZnA4XlRp864fmWXv9YTIk7VPLhRacA=
github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d/go.mod h1:7DPO4domFU579Ga6E61sB9VFNaniPVwJP5C4bBCu3wA=
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
@@ -373,7 +374,6 @@ github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
@@ -427,6 +427,7 @@ go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qL
go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.starlark.net v0.0.0-20190528202925-30ae18b8564f/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg=
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc=
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
@@ -440,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=
@@ -468,10 +470,9 @@ 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 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=
@@ -493,7 +494,6 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69 h1:rOhMmluY6kLMhdnrivzec6lLgaVbMHMn2ISQXJeJ5EM=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c h1:Vco5b+cuG5NNfORVxZy6bYZQ7rsigisU1WQFkvQ0L5E=
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -503,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=
@@ -527,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=
@@ -553,14 +556,13 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/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.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-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=
@@ -578,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=
@@ -585,10 +588,9 @@ 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.1.11 h1:/VvWxVIgH5gG1K4A7trgbyLgO3tRBiAWNhLFVU1HEmo=
sigs.k8s.io/kustomize/kyaml v0.1.11/go.mod h1:72/rLkSi+L/pHM1oCjwrf3ClU+tH5kZQvvdLSqIHwWU=
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=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

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,36 +38,69 @@ 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 {
Map() map[string]interface{}
SetMap(map[string]interface{})
// Several uses.
Copy() Kunstructured
GetFieldValue(string) (interface{}, error)
GetString(string) (string, error)
GetStringSlice(string) ([]string, error)
GetBool(path string) (bool, error)
GetFloat64(path string) (float64, error)
GetInt64(path string) (int64, error)
GetSlice(path string) ([]interface{}, error)
GetStringMap(path string) (map[string]string, error)
GetMap(path string) (map[string]interface{}, error)
MarshalJSON() ([]byte, error)
UnmarshalJSON([]byte) error
GetGvk() resid.Gvk
SetGvk(resid.Gvk)
GetKind() string
GetName() string
SetName(string)
SetNamespace(string)
GetLabels() map[string]string
SetLabels(map[string]string)
// 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
SetAnnotations(map[string]string)
MatchesLabelSelector(selector string) (bool, error)
// Used by ResAccumulator and ReplacementTransformer.
GetFieldValue(string) (interface{}, error)
// Used by Resource.OrgId
GetGvk() resid.Gvk
// Used by resource.Factory.SliceFromBytes
GetKind() string
// Used by Resource.Replace
GetLabels() map[string]string
// 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)
// 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)
Patch(Kunstructured) error
// Used by resWrangler.Select
MatchesLabelSelector(selector string) (bool, 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)
// Used by Resource.Replace.
SetName(string)
// Used by Resource.Replace.
SetNamespace(string)
// Needed, for now, by kyaml/filtersutil.ApplyToJSON.
UnmarshalJSON([]byte) error
}
// KunstructuredFactory makes instances of Kunstructured.

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

@@ -1,4 +1,4 @@
FROM golang:1.11 AS build
FROM golang:1.14 AS build
ARG GO111MODULE=on

View File

@@ -159,40 +159,31 @@ func main() {
}
}
seedDocs := make(crawler.CrawlSeed, 0)
// get all the documents in the index
getSeedDocsFunc := func() {
query := []byte(`{ "query":{ "match_all":{} } }`)
it := idx.IterateQuery(query, 10000, 60*time.Second)
for it.Next() {
for _, hit := range it.Value().Hits.Hits {
seedDocs = append(seedDocs, hit.Document.Document.Copy())
}
}
if err := it.Err(); err != nil {
log.Fatalf("getSeedDocsFunc Error iterating: %v\n", err)
}
}
query := []byte(`{ "query":{ "match_all":{} } }`)
it := idx.IterateQuery(query, 10000, 60*time.Second)
switch mode {
case CrawlIndexAndGithub:
getSeedDocsFunc()
crawlers := []crawler.Crawler{ghCrawlerConstructor("", "")}
crawler.CrawlFromSeed(ctx, seedDocs, crawlers, docConverter, indexFunc, seen)
crawler.CrawlFromSeedIterator(ctx, it, crawlers, docConverter, indexFunc, seen)
crawler.CrawlGithub(ctx, crawlers, docConverter, indexFunc, seen)
case CrawlIndex:
getSeedDocsFunc()
crawlers := []crawler.Crawler{ghCrawlerConstructor("", "")}
crawler.CrawlFromSeed(ctx, seedDocs, crawlers, docConverter, indexFunc, seen)
crawler.CrawlFromSeedIterator(ctx, it, crawlers, docConverter, indexFunc, seen)
case CrawlGithub:
crawlers := []crawler.Crawler{ghCrawlerConstructor("", "")}
// add all the documents in the index into seen.
// this greatly reduces the time overhead of CrawlGithub.
getSeedDocsFunc()
for _, d := range seedDocs {
seen[d.ID()] = d.FileType
for it.Next() {
for _, hit := range it.Value().Hits.Hits {
d := hit.Document.Document
seen.Set(d.ID(), d.FileType)
}
}
if err := it.Err(); err != nil {
log.Fatalf("Error iterating the index: %v\n", err)
}
crawler.CrawlGithub(ctx, crawlers, docConverter, indexFunc, seen)
case CrawlUser:
if *githubUserPtr == "" {

View File

@@ -1,16 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
spec:
selector:
custom-resource: v1alpha1.ESCluster
custom-resource-name: esbasic
custom-resource-namespace: default
es/data: "true"
using: escluster.Cluster
ports:
- protocol: "TCP"
port: 9200
type: LoadBalancer
loadBalancerIP: ""

View File

@@ -213,21 +213,36 @@ func doCrawl(ctx context.Context, docsPtr *CrawlSeed, crawlers []Crawler, conv C
logger.Printf("\t%d documents cannot be converted but still were inserted or updated in the index\n", convErrCount)
}
// CrawlFromSeedIterator iterates all the documents in the index and call CrawlFromSeed for each document.
func CrawlFromSeedIterator(ctx context.Context, it *index.KustomizeIterator, crawlers []Crawler,
conv Converter, indx IndexFunc, seen utils.SeenMap) {
docCount := 0
for it.Next() {
for _, hit := range it.Value().Hits.Hits {
docCount++
logger.Printf("updating document %d from seed\n", docCount)
singleSeed := CrawlSeed{&(hit.Document.Document)}
CrawlFromSeed(ctx, singleSeed, crawlers, conv, indx, seen)
}
}
if err := it.Err(); err != nil {
log.Fatalf("Error iterating the index: %v\n", err)
}
}
// CrawlFromSeed updates all the documents in seed, and crawls all the new
// documents referred in the seed.
func CrawlFromSeed(ctx context.Context, seed CrawlSeed, crawlers []Crawler,
conv Converter, indx IndexFunc, seen utils.SeenMap) {
// stack tracks the documents directly referred in other documents.
// stack tracks the documents directly referred in the seed.
stack := make(CrawlSeed, 0)
// Exploit seed to update bulk of corpus.
logger.Printf("updating %d documents from seed\n", len(seed))
// each unique document in seed will be crawled once.
doCrawl(ctx, &seed, crawlers, conv, indx, seen, &stack, true, false)
// Traverse any new documents added while updating corpus.
logger.Printf("crawling %d new documents found in the seed\n", len(stack))
logger.Printf("crawling %d new documents referred by doc\n", len(stack))
// While crawling each document in stack, the documents directly referred in the document
// will be added into stack.
// After this statement is done, stack will become empty.
@@ -297,8 +312,6 @@ func CrawlGithubRunner(ctx context.Context, output chan<- CrawledDocument,
// CrawlGithub crawls all the kustomization files on Github.
func CrawlGithub(ctx context.Context, crawlers []Crawler, conv Converter,
indx IndexFunc, seen utils.SeenMap) {
// stack tracks the documents directly referred in other documents.
stack := make(CrawlSeed, 0)
// ch is channel where all the crawlers sends the crawled documents to.
ch := make(chan CrawledDocument, 1<<10)
@@ -324,7 +337,20 @@ func CrawlGithub(ctx context.Context, crawlers []Crawler, conv Converter,
"%v could not match any crawler", cdoc))
continue
}
// stack tracks the documents directly referred in the document.
stack := make(CrawlSeed, 0)
addBranches(cdoc, match, indx, seen, &stack)
if len(stack) > 0 {
// here the documents referred in a kustomization file are crawled separately,
// to avoid accumulating all the referred documents into a single gigantic
// mem-inentive stack.
logger.Printf("crawling the %d new documents referred in doc %d",
len(stack), docCount)
doCrawl(ctx, &stack, crawlers, conv, indx, seen, &stack, false, true)
}
}
}()
@@ -336,9 +362,4 @@ func CrawlGithub(ctx context.Context, crawlers []Crawler, conv Converter,
}
close(ch)
wg.Wait()
// Handle deps of newly discovered documents.
logger.Printf("crawling the %d new documents referred by other documents",
len(stack))
doCrawl(ctx, &stack, crawlers, conv, indx, seen, &stack, false, true)
}

View File

@@ -82,14 +82,15 @@ func (gc githubCrawler) Crawl(ctx context.Context,
ranges := []RangeWithin{
RangeWithin{
start: uint64(0),
end: githubMaxFileSize,
},
start: uint64(0),
end: githubMaxFileSize,
},
}
errs := make(multiError, 0)
for len(ranges) > 0 {
tailRange := ranges[len(ranges) - 1]
logger.Printf("Current ranges: %v (len: %d)\n", ranges, len(ranges))
tailRange := ranges[len(ranges)-1]
ranges = ranges[:(len(ranges) - 1)]
reProcessQueryRanges, err := gc.CrawlSingleRange(ctx, output, seen, tailRange.start, tailRange.end)
if err != nil {
@@ -151,7 +152,15 @@ func (gc githubCrawler) CrawlSingleRange(ctx context.Context,
}
queryResult.Add(rangeResult)
if reProcessQuery {
reProcessQueryRanges = append(reProcessQueryRanges, RangeSizes(query))
// if the size of a range is 0, such as [245, 245], and reProcessQuery is true,
// it means that there are more than 1000 results for the query range.
// Reprocessing the query range will not help because the GitHub Search API
// only provides up to 1,000 results for each search.
if RangeSizes(query).Size() == 0 {
logger.Printf("range size is 0 includes more than 1000 results: %s", query)
} else {
reProcessQueryRanges = append(reProcessQueryRanges, RangeSizes(query))
}
}
}

View File

@@ -225,3 +225,7 @@ type RangeWithin struct {
func (r RangeWithin) RangeString() string {
return fmt.Sprintf("%d..%d", r.start, r.end)
}
func (r RangeWithin) Size() uint64 {
return r.end - r.start
}

View File

@@ -1,6 +1,6 @@
module sigs.k8s.io/kustomize/api/internal/crawl
go 1.13
go 1.14
require (
github.com/elastic/go-elasticsearch/v6 v6.8.5

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=
@@ -490,10 +501,12 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
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-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=
@@ -514,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.1.11/go.mod h1:72/rLkSi+L/pHM1oCjwrf3ClU+tH5kZQvvdLSqIHwWU=
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,21 +1,37 @@
package utils
type SeenMap map[string]string
import "sync"
type SeenMap struct {
data map[string]string
lock sync.RWMutex
}
// TODO: add lock to avoid race condition
func (seen SeenMap) Seen(item string) bool {
_, ok := seen[item]
seen.lock.RLock()
_, ok := seen.data[item]
seen.lock.RUnlock()
return ok
}
func (seen SeenMap) Set(k, v string) {
seen[k] = v
seen.lock.Lock()
seen.data[k] = v
seen.lock.Unlock()
}
// The caller should make sure that key is in the map.
func (seen SeenMap) Value(k string) string {
return seen[k]
seen.lock.RLock()
v := seen.data[k]
seen.lock.RUnlock()
return v
}
func NewSeenMap() SeenMap {
return make(map[string]string)
return SeenMap{
data: make(map[string]string),
lock: sync.RWMutex{},
}
}

View File

@@ -4,7 +4,6 @@
package git
import (
"bytes"
"log"
"os/exec"
@@ -36,32 +35,50 @@ func ClonerUsingGitExec(repoSpec *RepoSpec) error {
"clone",
"--depth=1",
repoSpec.CloneSpec(),
"-b",
repoSpec.Ref,
repoSpec.Dir.String())
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &out
err = cmd.Run()
out, err := cmd.CombinedOutput()
if err != nil {
log.Printf("Error cloning git repo: %s", out.String())
log.Printf("Error cloning git repo: %s", out)
return errors.Wrapf(
err,
"trouble cloning git repo %v in %s",
repoSpec.CloneSpec(), repoSpec.Dir.String())
}
cmd = exec.Command(
gitProgram,
"fetch",
"--depth=1",
"origin",
repoSpec.Ref)
cmd.Dir = repoSpec.Dir.String()
out, err = cmd.CombinedOutput()
if err != nil {
log.Printf("Error fetching ref: %s", out)
return errors.Wrapf(err, "trouble fetching %s", repoSpec.Ref)
}
cmd = exec.Command(
gitProgram,
"checkout",
"FETCH_HEAD")
cmd.Dir = repoSpec.Dir.String()
out, err = cmd.CombinedOutput()
if err != nil {
log.Printf("Error checking out ref: %s", out)
return errors.Wrapf(err, "trouble checking out %s", repoSpec.Ref)
}
cmd = exec.Command(
gitProgram,
"submodule",
"update",
"--init",
"--recursive")
cmd.Stdout = &out
cmd.Stderr = &out
cmd.Dir = repoSpec.Dir.String()
err = cmd.Run()
out, err = cmd.CombinedOutput()
if err != nil {
log.Printf("Error fetching submodules: %s", out)
return errors.Wrapf(err, "trouble fetching submodules for %s", repoSpec.CloneSpec())
}

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

@@ -9,22 +9,17 @@ import (
"io/ioutil"
"os"
"os/exec"
"strconv"
"strings"
"github.com/google/shlex"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/internal/plugins/utils"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
const (
idAnnotation = "kustomize.config.k8s.io/id"
HashAnnotation = "kustomize.config.k8s.io/needs-hash"
BehaviorAnnotation = "kustomize.config.k8s.io/behavior"
tmpConfigFilePrefix = "kust-plugin-config-"
)
@@ -114,12 +109,12 @@ func (p *ExecPlugin) Generate() (resmap.ResMap, error) {
if err != nil {
return nil, err
}
return p.UpdateResourceOptions(rm)
return utils.UpdateResourceOptions(rm)
}
func (p *ExecPlugin) Transform(rm resmap.ResMap) error {
// add ResIds as annotations to all objects so that we can add them back
inputRM, err := p.getResMapWithIdAnnotation(rm)
inputRM, err := utils.GetResMapWithIDAnnotation(rm)
if err != nil {
return err
}
@@ -137,7 +132,7 @@ func (p *ExecPlugin) Transform(rm resmap.ResMap) error {
}
// update the original ResMap based on the output
return p.updateResMapValues(output, rm)
return utils.UpdateResMapValues(p.path, p.h, output, rm)
}
// invokePlugin writes plugin config to a temp file, then
@@ -184,91 +179,3 @@ func (p *ExecPlugin) getEnv() []string {
"KUSTOMIZE_PLUGIN_CONFIG_ROOT="+p.h.Loader().Root())
return env
}
// Returns a new copy of the given ResMap with the ResIds annotated in each Resource
func (p *ExecPlugin) getResMapWithIdAnnotation(rm resmap.ResMap) (resmap.ResMap, error) {
inputRM := rm.DeepCopy()
for _, r := range inputRM.Resources() {
idString, err := yaml.Marshal(r.CurId())
if err != nil {
return nil, err
}
annotations := r.GetAnnotations()
if annotations == nil {
annotations = make(map[string]string)
}
annotations[idAnnotation] = string(idString)
r.SetAnnotations(annotations)
}
return inputRM, nil
}
// updateResMapValues updates the Resource value in the given ResMap
// with the emitted Resource values in output.
func (p *ExecPlugin) updateResMapValues(output []byte, rm resmap.ResMap) error {
outputRM, err := p.h.ResmapFactory().NewResMapFromBytes(output)
if err != nil {
return err
}
for _, r := range outputRM.Resources() {
// for each emitted Resource, find the matching Resource in the original ResMap
// using its id
annotations := r.GetAnnotations()
idString, ok := annotations[idAnnotation]
if !ok {
return fmt.Errorf("the transformer %s should not remove annotation %s",
p.path, idAnnotation)
}
id := resid.ResId{}
err := yaml.Unmarshal([]byte(idString), &id)
if err != nil {
return err
}
res, err := rm.GetByCurrentId(id)
if err != nil {
return fmt.Errorf("unable to find unique match to %s", id.String())
}
// remove the annotation set by Kustomize to track the resource
delete(annotations, idAnnotation)
if len(annotations) == 0 {
annotations = nil
}
r.SetAnnotations(annotations)
// update the ResMap resource value with the transformed object
res.Kunstructured = r.Kunstructured
}
return nil
}
// updateResourceOptions updates the generator options for each resource in the
// given ResMap based on plugin provided annotations.
func (p *ExecPlugin) UpdateResourceOptions(rm resmap.ResMap) (resmap.ResMap, error) {
for _, r := range rm.Resources() {
// Disable name hashing by default and require plugin to explicitly
// request it for each resource.
annotations := r.GetAnnotations()
behavior := annotations[BehaviorAnnotation]
var needsHash bool
if val, ok := annotations[HashAnnotation]; ok {
b, err := strconv.ParseBool(val)
if err != nil {
return nil, fmt.Errorf(
"the annotation %q contains an invalid value (%q)",
HashAnnotation, val)
}
needsHash = b
}
delete(annotations, HashAnnotation)
delete(annotations, BehaviorAnnotation)
if len(annotations) == 0 {
annotations = nil
}
r.SetAnnotations(annotations)
r.SetOptions(types.NewGenArgs(
&types.GeneratorArgs{
Behavior: behavior,
Options: &types.GeneratorOptions{DisableNameSuffixHash: !needsHash}}))
}
return rm, nil
}

View File

@@ -4,7 +4,6 @@
package execplugin_test
import (
"fmt"
"strings"
"testing"
@@ -17,7 +16,6 @@ import (
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/api/types"
)
func TestExecPluginConfig(t *testing.T) {
@@ -91,107 +89,3 @@ metadata:
t.Fatalf("unexpected arg array: %#v", p.Args())
}
}
func makeConfigMap(rf *resource.Factory, name, behavior string, hashValue *string) *resource.Resource {
r := rf.FromMap(map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{"name": name},
})
annotations := map[string]string{}
if behavior != "" {
annotations[BehaviorAnnotation] = behavior
}
if hashValue != nil {
annotations[HashAnnotation] = *hashValue
}
if len(annotations) > 0 {
r.SetAnnotations(annotations)
}
return r
}
func makeConfigMapOptions(rf *resource.Factory, name, behavior string, disableHash bool) *resource.Resource {
return rf.FromMapAndOption(map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{"name": name},
}, &types.GeneratorArgs{
Behavior: behavior,
Options: &types.GeneratorOptions{DisableNameSuffixHash: disableHash}})
}
func strptr(s string) *string {
return &s
}
func TestUpdateResourceOptions(t *testing.T) {
p := NewExecPlugin("")
if err := p.ErrIfNotExecutable(); err == nil {
t.Fatalf("expected unexecutable error")
}
rf := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
in := resmap.New()
expected := resmap.New()
cases := []struct {
behavior string
needsHash bool
hashValue *string
}{
{hashValue: strptr("false")},
{hashValue: strptr("true"), needsHash: true},
{behavior: "replace"},
{behavior: "merge"},
{behavior: "create"},
{behavior: "nonsense"},
{behavior: "merge", hashValue: strptr("false")},
{behavior: "merge", hashValue: strptr("true"), needsHash: true},
}
for i, c := range cases {
name := fmt.Sprintf("test%d", i)
in.Append(makeConfigMap(rf, name, c.behavior, c.hashValue))
expected.Append(makeConfigMapOptions(rf, name, c.behavior, !c.needsHash))
}
actual, err := p.UpdateResourceOptions(in)
if err != nil {
t.Fatalf("unexpected error: %v", err.Error())
}
for i, a := range expected.Resources() {
b := actual.GetByIndex(i)
if b == nil {
t.Fatalf("resource %d missing from processed map", i)
}
if !a.Equals(b) {
t.Errorf("expected %v got %v", a, b)
}
if a.NeedHashSuffix() != b.NeedHashSuffix() {
t.Errorf("")
}
if a.Behavior() != b.Behavior() {
t.Errorf("expected %v got %v", a.Behavior(), b.Behavior())
}
}
}
func TestUpdateResourceOptionsWithInvalidHashAnnotationValues(t *testing.T) {
p := NewExecPlugin("")
if err := p.ErrIfNotExecutable(); err == nil {
t.Fatalf("expected unexecutable error")
}
rf := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
cases := []string{
"",
"FaLsE",
"TrUe",
"potato",
}
for i, c := range cases {
name := fmt.Sprintf("test%d", i)
in := resmap.New()
in.Append(makeConfigMap(rf, name, "", &c))
_, err := p.UpdateResourceOptions(in)
if err == nil {
t.Errorf("expected error from value %q", c)
}
}
}

View File

@@ -0,0 +1,197 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package fnplugin
import (
"bytes"
"fmt"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/internal/plugins/utils"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
"sigs.k8s.io/kustomize/kyaml/runfn"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// FnPlugin is the struct to hold function information
type FnPlugin struct {
// Function runner
runFns runfn.RunFns
// Plugin configuration data.
cfg []byte
// Plugin name cache for error output
pluginName string
// PluginHelpers
h *resmap.PluginHelpers
}
func bytesToRNode(yml []byte) (*yaml.RNode, error) {
rnode, err := yaml.Parse(string(yml))
if err != nil {
return nil, err
}
return rnode, nil
}
func resourceToRNode(res *resource.Resource) (*yaml.RNode, error) {
yml, err := res.AsYAML()
if err != nil {
return nil, err
}
return bytesToRNode(yml)
}
// GetFunctionSpec return function spec is there is. Otherwise return nil
func GetFunctionSpec(res *resource.Resource) *runtimeutil.FunctionSpec {
rnode, err := resourceToRNode(res)
if err != nil {
return nil
}
return runtimeutil.GetFunctionSpec(rnode)
}
func toStorageMounts(mounts []string) []runtimeutil.StorageMount {
var sms []runtimeutil.StorageMount
for _, mount := range mounts {
sms = append(sms, runtimeutil.StringToStorageMount(mount))
}
return sms
}
// NewFnPlugin creates a FnPlugin struct
func NewFnPlugin(o *types.FnPluginLoadingOptions) *FnPlugin {
return &FnPlugin{
runFns: runfn.RunFns{
Functions: []*yaml.RNode{},
Network: o.Network,
NetworkName: o.NetworkName,
EnableStarlark: o.EnableStar,
EnableExec: o.EnableExec,
StorageMounts: toStorageMounts(o.Mounts),
},
}
}
// Cfg returns function config
func (p *FnPlugin) Cfg() []byte {
return p.cfg
}
// Config is called by kustomize to pass-in config information
func (p *FnPlugin) Config(h *resmap.PluginHelpers, config []byte) error {
p.h = h
p.cfg = config
fn, err := bytesToRNode(p.cfg)
if err != nil {
return err
}
meta, err := fn.GetMeta()
if err != nil {
return err
}
p.pluginName = fmt.Sprintf("api: %s, kind: %s, name: %s",
meta.APIVersion, meta.Kind, meta.Name)
return nil
}
// Generate is called when run as generator
func (p *FnPlugin) Generate() (resmap.ResMap, error) {
output, err := p.invokePlugin(nil)
if err != nil {
return nil, err
}
rm, err := p.h.ResmapFactory().NewResMapFromBytes(output)
if err != nil {
return nil, err
}
return utils.UpdateResourceOptions(rm)
}
// Transform is called when run as transformer
func (p *FnPlugin) Transform(rm resmap.ResMap) error {
// add ResIds as annotations to all objects so that we can add them back
inputRM, err := utils.GetResMapWithIDAnnotation(rm)
if err != nil {
return err
}
// encode the ResMap so it can be fed to the plugin
resources, err := inputRM.AsYaml()
if err != nil {
return err
}
// invoke the plugin with resources as the input
output, err := p.invokePlugin(resources)
if err != nil {
return fmt.Errorf("%v %s", err, string(output))
}
// update the original ResMap based on the output
return utils.UpdateResMapValues(p.pluginName, p.h, output, rm)
}
func injectAnnotation(input *yaml.RNode, k, v string) error {
err := input.PipeE(yaml.SetAnnotation(k, v))
if err != nil {
return err
}
return nil
}
// invokePlugin uses Function runner to run function as plugin
func (p *FnPlugin) invokePlugin(input []byte) ([]byte, error) {
// get function config rnode
functionConfig, err := bytesToRNode(p.cfg)
if err != nil {
return nil, err
}
// This annotation will let kustomize ingnore this item in output
err = injectAnnotation(functionConfig, "config.kubernetes.io/local-config", "true")
if err != nil {
return nil, err
}
// we need to add config as input for generators. Some of them don't work with FunctionConfig
// and in addition kio.Pipeline won't create anything if there are no objects
// see https://github.com/kubernetes-sigs/kustomize/blob/master/kyaml/kio/kio.go#L93
// Since we added `local-config` annotation so it will be ignored in generator output
// TODO(donnyxia): This is actually not used by generator and only used to bypass a kio limitation.
// Need better solution.
if input == nil {
yml, err := functionConfig.String()
if err != nil {
return nil, err
}
input = []byte(yml)
}
// Configure and Execute Fn. We don't need to convert resources to ResourceList here
// because function runtime will do that. See kyaml/fn/runtime/runtimeutil/runtimeutil.go
var ouputBuffer bytes.Buffer
p.runFns.Input = bytes.NewReader(input)
p.runFns.Functions = append(p.runFns.Functions, functionConfig)
p.runFns.Output = &ouputBuffer
err = p.runFns.Execute()
if err != nil {
return nil, errors.Wrap(
err, "couldn't execute function")
}
return ouputBuffer.Bytes(), nil
}

View File

@@ -16,6 +16,7 @@ import (
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers"
"sigs.k8s.io/kustomize/api/internal/plugins/execplugin"
"sigs.k8s.io/kustomize/api/internal/plugins/fnplugin"
"sigs.k8s.io/kustomize/api/internal/plugins/utils"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/resid"
@@ -116,7 +117,7 @@ func (l *Loader) loadAndConfigurePlugin(
if isBuiltinPlugin(res) {
switch l.pc.BpLoadingOptions {
case types.BploLoadFromFileSys:
c, err = l.loadPlugin(res.OrgId())
c, err = l.loadPlugin(res)
case types.BploUseStaticallyLinked:
// Instead of looking for and loading a .so file,
// instantiate the plugin from a generated factory
@@ -131,7 +132,7 @@ func (l *Loader) loadAndConfigurePlugin(
} else {
switch l.pc.PluginRestrictions {
case types.PluginRestrictionsNone:
c, err = l.loadPlugin(res.OrgId())
c, err = l.loadPlugin(res)
case types.PluginRestrictionsBuiltinsOnly:
err = types.NewErrOnlyBuiltinPluginsAllowed(res.OrgId().Kind)
default:
@@ -166,7 +167,15 @@ func (l *Loader) makeBuiltinPlugin(r resid.Gvk) (resmap.Configurable, error) {
return nil, errors.Errorf("unable to load builtin %s", r)
}
func (l *Loader) loadPlugin(resId resid.ResId) (resmap.Configurable, error) {
func (l *Loader) loadPlugin(res *resource.Resource) (resmap.Configurable, error) {
spec := fnplugin.GetFunctionSpec(res)
if spec != nil {
return fnplugin.NewFnPlugin(&l.pc.FnpLoadingOptions), nil
}
return l.loadExecOrGoPlugin(res.OrgId())
}
func (l *Loader) loadExecOrGoPlugin(resId resid.ResId) (resmap.Configurable, error) {
// First try to load the plugin as an executable.
p := execplugin.NewExecPlugin(l.absolutePluginPath(resId))
err := p.ErrIfNotExecutable()

View File

@@ -4,13 +4,25 @@
package utils
import (
"fmt"
"os"
"path/filepath"
"runtime"
"strconv"
"time"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
const (
idAnnotation = "kustomize.config.k8s.io/id"
HashAnnotation = "kustomize.config.k8s.io/needs-hash"
BehaviorAnnotation = "kustomize.config.k8s.io/behavior"
)
func GoBin() string {
@@ -113,3 +125,91 @@ func FileExists(path string) bool {
}
return true
}
// GetResMapWithIDAnnotation returns a new copy of the given ResMap with the ResIds annotated in each Resource
func GetResMapWithIDAnnotation(rm resmap.ResMap) (resmap.ResMap, error) {
inputRM := rm.DeepCopy()
for _, r := range inputRM.Resources() {
idString, err := yaml.Marshal(r.CurId())
if err != nil {
return nil, err
}
annotations := r.GetAnnotations()
if annotations == nil {
annotations = make(map[string]string)
}
annotations[idAnnotation] = string(idString)
r.SetAnnotations(annotations)
}
return inputRM, nil
}
// UpdateResMapValues updates the Resource value in the given ResMap
// with the emitted Resource values in output.
func UpdateResMapValues(pluginName string, h *resmap.PluginHelpers, output []byte, rm resmap.ResMap) error {
outputRM, err := h.ResmapFactory().NewResMapFromBytes(output)
if err != nil {
return err
}
for _, r := range outputRM.Resources() {
// for each emitted Resource, find the matching Resource in the original ResMap
// using its id
annotations := r.GetAnnotations()
idString, ok := annotations[idAnnotation]
if !ok {
return fmt.Errorf("the transformer %s should not remove annotation %s",
pluginName, idAnnotation)
}
id := resid.ResId{}
err := yaml.Unmarshal([]byte(idString), &id)
if err != nil {
return err
}
res, err := rm.GetByCurrentId(id)
if err != nil {
return fmt.Errorf("unable to find unique match to %s", id.String())
}
// remove the annotation set by Kustomize to track the resource
delete(annotations, idAnnotation)
if len(annotations) == 0 {
annotations = nil
}
r.SetAnnotations(annotations)
// update the resource value with the transformed object
res.ResetPrimaryData(r)
}
return nil
}
// UpdateResourceOptions updates the generator options for each resource in the
// given ResMap based on plugin provided annotations.
func UpdateResourceOptions(rm resmap.ResMap) (resmap.ResMap, error) {
for _, r := range rm.Resources() {
// Disable name hashing by default and require plugin to explicitly
// request it for each resource.
annotations := r.GetAnnotations()
behavior := annotations[BehaviorAnnotation]
var needsHash bool
if val, ok := annotations[HashAnnotation]; ok {
b, err := strconv.ParseBool(val)
if err != nil {
return nil, fmt.Errorf(
"the annotation %q contains an invalid value (%q)",
HashAnnotation, val)
}
needsHash = b
}
delete(annotations, HashAnnotation)
delete(annotations, BehaviorAnnotation)
if len(annotations) == 0 {
annotations = nil
}
r.SetAnnotations(annotations)
r.SetOptions(types.NewGenArgs(
&types.GeneratorArgs{
Behavior: behavior,
Options: &types.GeneratorOptions{DisableNameSuffixHash: !needsHash}}))
}
return rm, nil
}

View File

@@ -4,12 +4,17 @@
package utils
import (
"fmt"
"path/filepath"
"strings"
"testing"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
)
func TestDeterminePluginSrcRoot(t *testing.T) {
@@ -24,3 +29,99 @@ func TestDeterminePluginSrcRoot(t *testing.T) {
t.Errorf("expected suffix '%s' in '%s'", konfig.RelPluginHome, actual)
}
}
func makeConfigMap(rf *resource.Factory, name, behavior string, hashValue *string) *resource.Resource {
r := rf.FromMap(map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{"name": name},
})
annotations := map[string]string{}
if behavior != "" {
annotations[BehaviorAnnotation] = behavior
}
if hashValue != nil {
annotations[HashAnnotation] = *hashValue
}
if len(annotations) > 0 {
r.SetAnnotations(annotations)
}
return r
}
func makeConfigMapOptions(rf *resource.Factory, name, behavior string, disableHash bool) *resource.Resource {
return rf.FromMapAndOption(map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{"name": name},
}, &types.GeneratorArgs{
Behavior: behavior,
Options: &types.GeneratorOptions{DisableNameSuffixHash: disableHash}})
}
func strptr(s string) *string {
return &s
}
func TestUpdateResourceOptions(t *testing.T) {
rf := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
in := resmap.New()
expected := resmap.New()
cases := []struct {
behavior string
needsHash bool
hashValue *string
}{
{hashValue: strptr("false")},
{hashValue: strptr("true"), needsHash: true},
{behavior: "replace"},
{behavior: "merge"},
{behavior: "create"},
{behavior: "nonsense"},
{behavior: "merge", hashValue: strptr("false")},
{behavior: "merge", hashValue: strptr("true"), needsHash: true},
}
for i, c := range cases {
name := fmt.Sprintf("test%d", i)
in.Append(makeConfigMap(rf, name, c.behavior, c.hashValue))
expected.Append(makeConfigMapOptions(rf, name, c.behavior, !c.needsHash))
}
actual, err := UpdateResourceOptions(in)
if err != nil {
t.Fatalf("unexpected error: %v", err.Error())
}
for i, a := range expected.Resources() {
b := actual.GetByIndex(i)
if b == nil {
t.Fatalf("resource %d missing from processed map", i)
}
if !a.Equals(b) {
t.Errorf("expected %v got %v", a, b)
}
if a.NeedHashSuffix() != b.NeedHashSuffix() {
t.Errorf("")
}
if a.Behavior() != b.Behavior() {
t.Errorf("expected %v got %v", a.Behavior(), b.Behavior())
}
}
}
func TestUpdateResourceOptionsWithInvalidHashAnnotationValues(t *testing.T) {
rf := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
cases := []string{
"",
"FaLsE",
"TrUe",
"potato",
}
for i, c := range cases {
name := fmt.Sprintf("test%d", i)
in := resmap.New()
in.Append(makeConfigMap(rf, name, "", &c))
_, err := UpdateResourceOptions(in)
if err == nil {
t.Errorf("expected error from value %q", c)
}
}
}

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()
}
@@ -166,11 +151,21 @@ func (kt *KustTarget) addHashesToNames(
// not yet fixed.
func (kt *KustTarget) AccumulateTarget() (
ra *accumulator.ResAccumulator, err error) {
ra = accumulator.MakeEmptyAccumulator()
err = kt.accumulateResources(ra, kt.kustomization.Resources)
return kt.accumulateTarget(accumulator.MakeEmptyAccumulator())
}
// ra should be empty when this KustTarget is a Kustomization, or the ra of the parent if this KustTarget is a Component
// (or empty if the Component does not have a parent).
func (kt *KustTarget) accumulateTarget(ra *accumulator.ResAccumulator) (
resRa *accumulator.ResAccumulator, err error) {
ra, err = kt.accumulateResources(ra, kt.kustomization.Resources)
if err != nil {
return nil, errors.Wrap(err, "accumulating resources")
}
ra, err = kt.accumulateComponents(ra, kt.kustomization.Components)
if err != nil {
return nil, errors.Wrap(err, "accumulating components")
}
tConfig, err := builtinconfig.MakeTransformerConfig(
kt.ldr, kt.kustomization.Configurations)
if err != nil {
@@ -199,6 +194,10 @@ func (kt *KustTarget) AccumulateTarget() (
if err != nil {
return nil, err
}
err = kt.runValidators(ra)
if err != nil {
return nil, err
}
err = ra.MergeVars(kt.kustomization.Vars)
if err != nil {
return nil, errors.Wrapf(
@@ -235,7 +234,7 @@ func (kt *KustTarget) runGenerators(
func (kt *KustTarget) configureExternalGenerators() ([]resmap.Generator, error) {
ra := accumulator.MakeEmptyAccumulator()
err := kt.accumulateResources(ra, kt.kustomization.Generators)
ra, err := kt.accumulateResources(ra, kt.kustomization.Generators)
if err != nil {
return nil, err
}
@@ -250,65 +249,138 @@ func (kt *KustTarget) runTransformers(ra *accumulator.ResAccumulator) error {
return err
}
r = append(r, lts...)
lts, err = kt.configureExternalTransformers()
lts, err = kt.configureExternalTransformers(kt.kustomization.Transformers)
if err != nil {
return err
}
r = append(r, lts...)
t := transform.NewMultiTransformer(r)
return ra.Transform(t)
return ra.Transform(newMultiTransformer(r))
}
func (kt *KustTarget) configureExternalTransformers() ([]resmap.Transformer, error) {
func (kt *KustTarget) configureExternalTransformers(transformers []string) ([]resmap.Transformer, error) {
ra := accumulator.MakeEmptyAccumulator()
err := kt.accumulateResources(ra, kt.kustomization.Transformers)
ra, err := kt.accumulateResources(ra, transformers)
if err != nil {
return nil, err
}
return kt.pLdr.LoadTransformers(kt.ldr, kt.validator, ra.ResMap())
}
// accumulateResources fills the given resourceAccumulator
// with resources read from the given list of paths.
func (kt *KustTarget) accumulateResources(
ra *accumulator.ResAccumulator, paths []string) error {
for _, path := range paths {
// try loading resource as file then as base (directory or git repository)
if errF := kt.accumulateFile(ra, path); errF != nil {
ldr, errL := kt.ldr.New(path)
if errL != nil {
return fmt.Errorf("accumulateFile %q, loader.New %q", errF, errL)
}
errD := kt.accumulateDirectory(ra, ldr)
if errD != nil {
return fmt.Errorf("accumulateFile %q, accumulateDirector: %q", errF, errD)
}
func (kt *KustTarget) runValidators(ra *accumulator.ResAccumulator) error {
validators, err := kt.configureExternalTransformers(kt.kustomization.Validators)
if err != nil {
return err
}
for _, v := range validators {
// Validators shouldn't modify the resource map
orignal := ra.ResMap().DeepCopy()
err = v.Transform(ra.ResMap())
if err != nil {
return err
}
new := ra.ResMap().DeepCopy()
kt.removeValidatedByLabel(new)
if err = orignal.ErrorIfNotEqualSets(new); err != nil {
return fmt.Errorf("validator shouldn't modify the resource map: %v", err)
}
}
return nil
}
func (kt *KustTarget) removeValidatedByLabel(rm resmap.ResMap) {
resources := rm.Resources()
for _, r := range resources {
labels := r.GetLabels()
if _, found := labels[konfig.ValidatedByLabelKey]; !found {
continue
}
delete(labels, konfig.ValidatedByLabelKey)
if len(labels) == 0 {
r.SetLabels(nil)
} else {
r.SetLabels(labels)
}
}
}
// accumulateResources fills the given resourceAccumulator
// with resources read from the given list of paths.
func (kt *KustTarget) accumulateResources(
ra *accumulator.ResAccumulator, paths []string) (*accumulator.ResAccumulator, error) {
for _, path := range paths {
// try loading resource as file then as base (directory or git repository)
if errF := kt.accumulateFile(ra, path); errF != nil {
ldr, errL := kt.ldr.New(path)
if errL != nil {
return nil, fmt.Errorf("accumulateFile %q, loader.New %q", errF, errL)
}
var errD error
ra, errD = kt.accumulateDirectory(ra, ldr, false)
if errD != nil {
return nil, fmt.Errorf("accumulateFile %q, accumulateDirector: %q", errF, errD)
}
}
}
return ra, nil
}
// accumulateResources fills the given resourceAccumulator
// with resources read from the given list of paths.
func (kt *KustTarget) accumulateComponents(
ra *accumulator.ResAccumulator, paths []string) (*accumulator.ResAccumulator, error) {
for _, path := range paths {
// Components always refer to directories
ldr, errL := kt.ldr.New(path)
if errL != nil {
return nil, fmt.Errorf("loader.New %q", errL)
}
var errD error
ra, errD = kt.accumulateDirectory(ra, ldr, true)
if errD != nil {
return nil, fmt.Errorf("accumulateDirectory: %q", errD)
}
}
return ra, nil
}
func (kt *KustTarget) accumulateDirectory(
ra *accumulator.ResAccumulator, ldr ifc.Loader) error {
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 errors.Wrapf(
return nil, errors.Wrapf(
err, "couldn't make target for path '%s'", ldr.Root())
}
subRa, err := subKt.AccumulateTarget()
if isComponent && subKt.kustomization.Kind != types.ComponentKind {
return nil, fmt.Errorf(
"expected kind '%s' for path '%s' but got '%s'", types.ComponentKind, ldr.Root(), subKt.kustomization.Kind)
} else if !isComponent && subKt.kustomization.Kind == types.ComponentKind {
return nil, fmt.Errorf(
"expected kind != '%s' for path '%s'", types.ComponentKind, ldr.Root())
}
var subRa *accumulator.ResAccumulator
if isComponent {
// Components don't create a new accumulator: the kustomization directives are added to the current accumulator
subRa, err = subKt.accumulateTarget(ra)
ra = accumulator.MakeEmptyAccumulator()
} else {
// Child Kustomizations create a new accumulator which resolves their kustomization directives, which will later
// be merged into the current accumulator.
subRa, err = subKt.AccumulateTarget()
}
if err != nil {
return errors.Wrapf(
return nil, errors.Wrapf(
err, "recursed accumulation of path '%s'", ldr.Root())
}
err = ra.MergeAccumulator(subRa)
if err != nil {
return errors.Wrapf(
return nil, errors.Wrapf(
err, "recursed merging from path '%s'", ldr.Root())
}
return nil
return ra, nil
}
func (kt *KustTarget) accumulateFile(

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,103 +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.
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.
func encodeSecret(sec *corev1.Secret) (string, error) {
// json.Marshal sorts the keys in a stable order in the encoding
data, err := json.Marshal(map[string]interface{}{"kind": "Secret", "type": sec.Type, "name": sec.Name, "data": sec.Data})
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,180 +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", ""},
}
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"}`, ""},
}
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

@@ -21,6 +21,11 @@ nameReference:
- path: spec/scaleTargetRef/name
kind: HorizontalPodAutoscaler
- kind: StatefulSet
fieldSpecs:
- path: spec/scaleTargetRef/name
kind: HorizontalPodAutoscaler
- kind: ConfigMap
version: v1
fieldSpecs:
@@ -247,6 +252,10 @@ nameReference:
kind: Role
- path: rules/resourceNames
kind: ClusterRole
- path: spec/template/spec/containers/env/valueFrom/secretKeyRef/name
kind: Service
group: serving.knative.dev
version: v1
- kind: Service
version: v1

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

@@ -30,4 +30,13 @@ const (
// A program name, for use in help, finding the XDG_CONFIG_DIR, etc.
ProgramName = "kustomize"
// Label key that indicates the resources are built from Kustomize
ManagedbyLabelKey = "app.kubernetes.io/managed-by"
// An environment variable to turn on/off adding the ManagedByLabelKey
EnableManagedbyLabelEnv = "KUSTOMIZE_ENABLE_MANAGEDBY_LABEL"
// Label key that indicates the resources are validated by a validator
ValidatedByLabelKey = "validated-by"
)

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,12 +288,11 @@ metadata:
app: mungebot
org: kubernetes
repo: test-infra
name: test-infra-app-env-ffmd9b969m
name: test-infra-app-env-8h5mh7f7ch
---
apiVersion: v1
data:
nonsense: "Lorem ipsum dolor sit amet, consectetur\nadipiscing elit, sed do eiusmod
tempor\nincididunt ut labore et dolore magna aliqua. \n"
nonsense: "Lorem ipsum dolor sit amet, consectetur\nadipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. \n"
kind: ConfigMap
metadata:
annotations:
@@ -302,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
`)
}
@@ -132,6 +132,54 @@ spec:
`)
}
func TestTinyOverlay(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK("base", `
namePrefix: a-
resources:
- deployment.yaml
`)
th.WriteF("base/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeployment
spec:
template:
spec:
containers:
- image: whatever
`)
th.WriteK("overlay", `
namePrefix: b-
resources:
- ../base
patchesStrategicMerge:
- depPatch.yaml
`)
th.WriteF("overlay/depPatch.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeployment
spec:
replicas: 999
`)
m := th.Run("overlay", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: b-a-myDeployment
spec:
replicas: 999
template:
spec:
containers:
- image: whatever
`)
}
func writeSmallBase(th kusttest_test.Harness) {
th.WriteK("/app/base", `
namePrefix: a-

View File

@@ -0,0 +1,670 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package krusty_test
import (
"fmt"
"strings"
"testing"
"sigs.k8s.io/kustomize/api/konfig"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
type FileGen func(kusttest_test.Harness)
func writeC(path string, content string) FileGen {
return func(th kusttest_test.Harness) {
th.WriteC(path, content)
}
}
func writeF(path string, content string) FileGen {
return func(th kusttest_test.Harness) {
th.WriteF(path, content)
}
}
func writeK(path string, content string) FileGen {
return func(th kusttest_test.Harness) {
th.WriteK(path, content)
}
}
func writeTestBase(th kusttest_test.Harness) {
th.WriteK("/app/base", `
resources:
- deploy.yaml
configMapGenerator:
- name: my-configmap
literals:
- testValue=1
- otherValue=10
`)
th.WriteF("/app/base/deploy.yaml", `
apiVersion: v1
kind: Deployment
metadata:
name: storefront
spec:
replicas: 1
`)
}
func writeTestComponent(th kusttest_test.Harness) {
th.WriteC("/app/comp", `
namePrefix: comp-
replicas:
- name: storefront
count: 3
resources:
- stub.yaml
configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- testValue=2
- compValue=5
`)
th.WriteF("/app/comp/stub.yaml", `
apiVersion: v1
kind: Deployment
metadata:
name: stub
spec:
replicas: 1
`)
}
func writeOverlayProd(th kusttest_test.Harness) {
th.WriteK("/app/prod", `
resources:
- ../base
- db
components:
- ../comp
`)
writeDB(th)
}
func writeDB(th kusttest_test.Harness) {
deployment("db", "/app/prod/db")(th)
}
func deployment(name string, path string) FileGen {
return writeF(path, fmt.Sprintf(`
apiVersion: v1
kind: Deployment
metadata:
name: %s
spec:
type: Logical
`, name))
}
func TestComponent(t *testing.T) {
testCases := map[string]struct {
input []FileGen
runPath string
expectedOutput string
}{
// Components are inserted into the resource hierarchy as the parent of those
// resources that come before it in the resources list of the parent Kustomization.
"basic-component": {
input: []FileGen{writeTestBase, writeTestComponent, writeOverlayProd},
runPath: "/app/prod",
expectedOutput: `
apiVersion: v1
kind: Deployment
metadata:
name: comp-storefront
spec:
replicas: 3
---
apiVersion: v1
data:
compValue: "5"
otherValue: "10"
testValue: "2"
kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: comp-my-configmap-kc6k2kmkh9
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-db
spec:
type: Logical
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-stub
spec:
replicas: 1
`,
},
"multiple-components": {
input: []FileGen{writeTestBase, writeTestComponent, writeDB,
writeC("/app/additionalcomp", `
configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- otherValue=9
`),
writeK("/app/prod", `
resources:
- ../base
- db
components:
- ../comp
- ../additionalcomp
`),
},
runPath: "/app/prod",
expectedOutput: `
apiVersion: v1
kind: Deployment
metadata:
name: comp-storefront
spec:
replicas: 3
---
apiVersion: v1
data:
compValue: "5"
otherValue: "9"
testValue: "2"
kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: comp-my-configmap-55249mf5kb
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-db
spec:
type: Logical
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-stub
spec:
replicas: 1
`,
},
"nested-components": {
input: []FileGen{writeTestBase, writeTestComponent, writeDB,
writeC("/app/additionalcomp", `
components:
- ../comp
configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- otherValue=9
`),
writeK("/app/prod", `
resources:
- ../base
- db
components:
- ../additionalcomp
`),
},
runPath: "/app/prod",
expectedOutput: `
apiVersion: v1
kind: Deployment
metadata:
name: comp-storefront
spec:
replicas: 3
---
apiVersion: v1
data:
compValue: "5"
otherValue: "9"
testValue: "2"
kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: comp-my-configmap-55249mf5kb
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-db
spec:
type: Logical
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-stub
spec:
replicas: 1
`,
},
// If a component sets a name prefix on a base, then that base can also be separately included
// without being affected by the component in another branch of the resource tree
"basic-component-with-repeated-base": {
input: []FileGen{writeTestBase, writeTestComponent, writeOverlayProd,
writeK("/app/repeated", `
resources:
- ../base
- ../prod
`),
},
runPath: "/app/repeated",
expectedOutput: `
apiVersion: v1
kind: Deployment
metadata:
name: storefront
spec:
replicas: 1
---
apiVersion: v1
data:
otherValue: "10"
testValue: "1"
kind: ConfigMap
metadata:
name: my-configmap-2g9c94mhb8
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-storefront
spec:
replicas: 3
---
apiVersion: v1
data:
compValue: "5"
otherValue: "10"
testValue: "2"
kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: comp-my-configmap-kc6k2kmkh9
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-db
spec:
type: Logical
---
apiVersion: v1
kind: Deployment
metadata:
name: comp-stub
spec:
replicas: 1
`,
},
"applying-component-directly-should-be-same-as-kustomization": {
input: []FileGen{writeTestBase, writeTestComponent,
writeC("/app/direct-component", `
resources:
- ../base
configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- compValue=5
- testValue=2
`),
},
runPath: "/app/direct-component",
expectedOutput: `
apiVersion: v1
kind: Deployment
metadata:
name: storefront
spec:
replicas: 1
---
apiVersion: v1
data:
compValue: "5"
otherValue: "10"
testValue: "2"
kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: my-configmap-kc6k2kmkh9
`,
},
"missing-optional-component-api-version": {
input: []FileGen{writeTestBase, writeOverlayProd,
writeF("/app/comp/"+konfig.DefaultKustomizationFileName(), `
kind: Component
configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- otherValue=9
`),
},
runPath: "/app/prod",
expectedOutput: `
apiVersion: v1
kind: Deployment
metadata:
name: storefront
spec:
replicas: 1
---
apiVersion: v1
data:
otherValue: "9"
testValue: "1"
kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: my-configmap-5g7gh5mgt5
---
apiVersion: v1
kind: Deployment
metadata:
name: db
spec:
type: Logical
`,
},
// See how nameSuffix "-b" is also added to the resources included by "comp-a" because they are in the
// accumulator when "comp-b" is accumulated. In practice we could use simple Kustomizations for this example.
"components-can-add-the-same-base-if-the-first-renames-resources": {
input: []FileGen{writeTestBase,
deployment("proxy", "/app/comp-a/proxy.yaml"),
writeC("/app/comp-a", `
resources:
- ../base
nameSuffix: "-a"
`),
writeC("/app/comp-b", `
resources:
- ../base
nameSuffix: "-b"
`),
writeK("/app/prod", `
components:
- ../comp-a
- ../comp-b`),
},
runPath: "/app/prod",
expectedOutput: `
apiVersion: v1
kind: Deployment
metadata:
name: storefront-a-b
spec:
replicas: 1
---
apiVersion: v1
data:
otherValue: "10"
testValue: "1"
kind: ConfigMap
metadata:
name: my-configmap-a-b-2g9c94mhb8
---
apiVersion: v1
kind: Deployment
metadata:
name: storefront-b
spec:
replicas: 1
---
apiVersion: v1
data:
otherValue: "10"
testValue: "1"
kind: ConfigMap
metadata:
name: my-configmap-b-2g9c94mhb8
`,
},
"multiple-bases-can-add-the-same-component-if-it-doesn-not-define-named-entities": {
input: []FileGen{
writeC("/app/comp", `
namespace: prod
`),
writeK("/app/base-a", `
resources:
- proxy.yaml
components:
- ../comp
`),
deployment("proxy-a", "/app/base-a/proxy.yaml"),
writeK("/app/base-b", `
resources:
- proxy.yaml
components:
- ../comp
`),
deployment("proxy-b", "/app/base-b/proxy.yaml"),
writeK("/app/prod", `
resources:
- proxy.yaml
- ../base-a
- ../base-b
`),
deployment("proxy-prod", "/app/prod/proxy.yaml"),
},
runPath: "/app/prod",
// Note that the namepsace has not been applied to proxy-prod because it was not in scope when the
// component was applied
expectedOutput: `
apiVersion: v1
kind: Deployment
metadata:
name: proxy-prod
spec:
type: Logical
---
apiVersion: v1
kind: Deployment
metadata:
name: proxy-a
namespace: prod
spec:
type: Logical
---
apiVersion: v1
kind: Deployment
metadata:
name: proxy-b
namespace: prod
spec:
type: Logical
`,
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
th := kusttest_test.MakeHarness(t)
for _, f := range tc.input {
f(th)
}
m := th.Run(tc.runPath, th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, tc.expectedOutput)
})
}
}
func TestComponentErrors(t *testing.T) {
testCases := map[string]struct {
input []FileGen
runPath string
expectedError string
}{
"components-cannot-be-added-to-resources": {
input: []FileGen{writeTestBase, writeTestComponent,
writeK("/app/compinres", `
resources:
- ../base
- ../comp
`),
},
runPath: "app/compinres",
expectedError: "expected kind != 'Component' for path '/app/comp'",
},
"kustomizations-cannot-be-added-to-components": {
input: []FileGen{writeTestBase, writeTestComponent,
writeK("/app/kustincomponents", `
components:
- ../base
- ../comp
`),
},
runPath: "/app/kustincomponents",
expectedError: "accumulating components: accumulateDirectory: \"expected kind 'Component' for path " +
"'/app/base' but got 'Kustomization'",
},
"files-cannot-be-added-to-components-list": {
input: []FileGen{writeTestBase,
writeF("/app/filesincomponents/stub.yaml", `
apiVersion: v1
kind: Deployment
metadata:
name: stub
spec:
replicas: 1
`),
writeK("/app/filesincomponents", `
components:
- stub.yaml
- ../comp
`),
},
runPath: "/app/filesincomponents",
expectedError: "'/app/filesincomponents/stub.yaml' must be a directory to be a root",
},
"invalid-component-api-version": {
input: []FileGen{writeTestBase, writeOverlayProd,
writeF("/app/comp/"+konfig.DefaultKustomizationFileName(), `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Component
configMapGenerator:
- name: my-configmap
behavior: merge
literals:
- otherValue=9
`),
},
runPath: "/app/prod",
expectedError: "apiVersion for Component should be kustomize.config.k8s.io/v1alpha1",
},
"components-cannot-add-the-same-resource": {
input: []FileGen{writeTestBase,
writeC("/app/comp-a", `
resources:
- proxy.yaml
`),
deployment("proxy", "/app/comp-a/proxy.yaml"),
writeC("/app/comp-b", `
resources:
- proxy.yaml
`),
deployment("proxy", "/app/comp-b/proxy.yaml"),
writeK("/app/prod", `
resources:
- ../base
components:
- ../comp-a
- ../comp-b`),
},
runPath: "/app/prod",
expectedError: "may not add resource with an already registered id: ~G_v1_Deployment|~X|proxy",
},
"components-cannot-add-the-same-base": {
input: []FileGen{writeTestBase,
deployment("proxy", "/app/comp-a/proxy.yaml"),
writeC("/app/comp-a", `
resources:
- ../base
`),
writeC("/app/comp-b", `
resources:
- ../base
`),
writeK("/app/prod", `
components:
- ../comp-a
- ../comp-b`),
},
runPath: "/app/prod",
expectedError: "may not add resource with an already registered id: ~G_v1_Deployment|~X|storefront",
},
"components-cannot-add-bases-containing-the-same-resource": {
input: []FileGen{writeTestBase,
writeC("/app/comp-a", `
resources:
- ../base-a
`),
writeK("/app/base-a", `
resources:
- proxy.yaml
`),
deployment("proxy", "/app/base-a/proxy.yaml"),
writeC("/app/comp-b", `
resources:
- ../base-b
`),
writeK("/app/base-b", `
resources:
- proxy.yaml
`),
deployment("proxy", "/app/base-b/proxy.yaml"),
writeK("/app/prod", `
resources:
- ../base
components:
- ../comp-a
- ../comp-b`),
},
runPath: "/app/prod",
expectedError: "may not add resource with an already registered id: ~G_v1_Deployment|~X|proxy",
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
th := kusttest_test.MakeHarness(t)
for _, f := range tc.input {
f(th)
}
err := th.RunWithErr(tc.runPath, th.MakeDefaultOptions())
if err == nil || !strings.Contains(err.Error(), tc.expectedError) {
t.Fatalf("unexpected error: %s", err)
}
})
}
}

View File

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

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