Compare commits

...

1111 Commits

Author SHA1 Message Date
Jeff Regan
bae6418ca2 Merge pull request #1777 from monopole/pinKustomizeApiToPseudo
Pin kustomize API to pseudok8s v0.1.0
2019-11-11 18:17:35 -08:00
Jeffrey Regan
1db0248748 Pin kustomize API to pseudok8s v0.1.0 2019-11-11 17:45:19 -08:00
Jeff Regan
387afef19b Merge pull request #1776 from monopole/moarTweaksDarnPseudo
Tweaks to accomodate pseudo/k8s.
2019-11-11 17:11:31 -08:00
Jeffrey Regan
9e47e585d4 Tweaks to accomodate pseudo/k8s. 2019-11-11 17:09:17 -08:00
Jeff Regan
1f8696865f Merge pull request #1775 from monopole/addPseudoReleaseOption
Set up for pseudok8s release.
2019-11-11 15:38:59 -08:00
Jeff Regan
87b6a4d6bc Set up for pseudok8s release. 2019-11-11 15:37:53 -08:00
Kubernetes Prow Robot
5fe0b9e1b2 Merge pull request #1774 from kubernetes-sigs/pseudoK8sReleaseStuff
Set up for pseudok8s release.
2019-11-11 15:06:06 -08:00
Jeffrey Regan
9a25cb96b7 Set up for pseudok8s release. 2019-11-11 12:37:12 -08:00
Jeff Regan
0f81cf52e7 Update README.md 2019-11-11 11:10:01 -08:00
Jeff Regan
eb75c039e5 Merge pull request #1773 from monopole/pseudoMain
A pseudo main to make goreleaser happier.
2019-11-11 10:59:46 -08:00
jregan
0f0c6618a0 A pseudo main to make goreleaser happier. 2019-11-11 10:57:35 -08:00
Jeff Regan
97f2f33460 Merge pull request #1769 from monopole/removeOpsysCommentFromGeneratedCode
Remove opsys comment from generated code
2019-11-11 08:47:38 -08:00
jregan
382981fb43 Remove opsys comment from generated code. 2019-11-11 08:32:35 -08:00
Jeff Regan
519dacc10f Merge pull request #1768 from monopole/makeRepoMoreRelocatable
Add a relative path option for finding plugin source.
2019-11-11 08:08:30 -08:00
jregan
02c0c2692f Make repo more relocatable on developer's workstation. 2019-11-11 08:03:58 -08:00
Jeff Regan
6df4efd145 Merge pull request #1766 from monopole/lessGopath
Simplify pre-submit.sh
2019-11-09 16:19:02 -08:00
jregan
4dab6268da Less GOPATH dependence. 2019-11-09 15:01:26 -08:00
Jeff Regan
4150026ec7 Merge pull request #1767 from monopole/updateGeneratedCodeAndGoSums
Update plugin go.sums
2019-11-09 14:43:46 -08:00
jregan
10cd82ce31 Update go.sums 2019-11-09 14:42:29 -08:00
Jeff Regan
d0ce4fcf15 Merge pull request #1765 from monopole/makaMaka
Move code generation to makefile.
2019-11-09 08:54:15 -08:00
Jeffrey Regan
d54ff23560 Move code generation to makefile. 2019-11-09 08:32:09 -08:00
Phillip Wittrock
8e4609a850 Merge pull request #1764 from pwittrock/cmd
Switch cmd/kyaml to pseudo/k8s
2019-11-08 17:51:24 -08:00
Phillip Wittrock
eabb476461 Switch cmd/kyaml to pseudo/k8s 2019-11-08 17:23:04 -08:00
Kubernetes Prow Robot
74255f6bad Merge pull request #1763 from pwittrock/deps-fresh1
Switch kustomize to depend on pseudo/k8s
2019-11-08 17:05:59 -08:00
Phillip Wittrock
3dfe62fe55 switch to pseudo/k8s deps 2019-11-08 16:48:42 -08:00
Phillip Wittrock
ad9b869ddb Use local kustomize api for pluginator and hack/crawl 2019-11-08 16:38:01 -08:00
Phillip Wittrock
5c4c19bf19 Script to update pseudo references 2019-11-08 16:38:01 -08:00
Jeff Regan
1f86a0ca5d Merge pull request #1749 from pwittrock/cmd
Create kyaml command to expose running kyaml filters on the cli
2019-11-08 13:24:13 -08:00
Kubernetes Prow Robot
db630a9d07 Merge pull request #1762 from pwittrock/deps-fresh1
Fetch pseudo modules
2019-11-08 13:21:25 -08:00
Jeff Regan
388dd13a5f Merge pull request #1753 from oke-py/gnu-sed
brew install gnu-sed
2019-11-08 12:53:02 -08:00
Phillip Wittrock
67c9d469c4 Enable pseudo dependency checking in travis 2019-11-08 12:52:00 -08:00
Jeff Regan
28a55bbd9c Merge pull request #1761 from monopole/rmScript
Remove hack/fork_k8s_and_fix_deps.sh to avoid confusion.
2019-11-08 12:50:54 -08:00
Jeffrey Regan
bdacb941ab Remove hack/fork_k8s_and_fix_deps.sh to avoid confusion. 2019-11-08 12:49:58 -08:00
Phillip Wittrock
d87ad523de Fix pseudo/README.md script name 2019-11-08 12:49:20 -08:00
Phillip Wittrock
ec36993d42 Run pseudo/init-pseudo-module.sh to fetch packages 2019-11-08 12:48:06 -08:00
Kubernetes Prow Robot
6b5aebac22 Merge pull request #1760 from pwittrock/deps-fresh1
pseudo: script for creating psuedo modules
2019-11-08 12:44:52 -08:00
Phillip Wittrock
883714e2e5 Scripts for adding psuedo modules
psuedo modules will contain modules copied from k8s where we cannot depend directly on the k8s modules
2019-11-08 12:25:13 -08:00
Phillip Wittrock
8b0f4bf714 kyaml: Add kyaml filters as cli commands 2019-11-08 09:26:02 -08:00
Kubernetes Prow Robot
e83b97ea1f Merge pull request #1748 from pwittrock/commands
kyaml: rename annotations and fix linting
2019-11-07 20:00:20 -08:00
Jeff Regan
48dfcf5a3e Merge pull request #1750 from monopole/invokePluginUnitTests
Invoke plugin unit tests in presubmit.
2019-11-07 17:29:15 -08:00
Jeff Regan
cb4498594b Merge pull request #1758 from monopole/scriptToForkAndFixDeps
Script to fork and fix k8s deps.
2019-11-07 17:28:33 -08:00
Jeffrey Regan
b0bd4b5410 Script to fork and fix k8s deps. 2019-11-07 17:20:15 -08:00
Jeffrey Regan
dbf8a0fde4 Invoke plugin unit tests in presubmit. 2019-11-07 15:54:20 -08:00
Phillip Wittrock
3db1111f8e kyaml: rename annotations and fix linting 2019-11-07 15:46:30 -08:00
Kubernetes Prow Robot
e482ffa3f9 Merge pull request #1755 from monopole/unpinThePlugins
Repin the plugins on head for release testing.
2019-11-07 15:44:19 -08:00
Jeffrey Regan
2b1749778f Unpin all the plugins, so we can test against head b4 release. 2019-11-07 15:28:04 -08:00
Naoki Oketani
6af51a1bfe brew install gnu-sed 2019-11-08 08:17:48 +09:00
Phillip Wittrock
e0b46acf2f Merge pull request #1746 from pwittrock/kyaml
Kyaml documentation improvements
2019-11-07 09:42:42 -08:00
Phillip Wittrock
2e33a69388 Update documentation for kyaml package 2019-11-07 09:16:27 -08:00
Phillip Wittrock
018698ec85 Update .gitignore to ignore Intellij metadata files 2019-11-07 08:02:52 -08:00
Phillip Wittrock
0029a8ce32 Update Makefile with licenseadder and golangci-lint 2019-11-07 07:57:37 -08:00
Jeff Regan
04d5494246 Merge pull request #1745 from monopole/likelyLastMove
Remove more k8sdeps from external API.
2019-11-06 21:00:57 -08:00
jregan
41a8bd208d Remove more k8sdeps from external API. 2019-11-06 20:43:26 -08:00
Kubernetes Prow Robot
6bb470dbd0 Merge pull request #1744 from monopole/removePluginsPackagesFromExternalApi
Remove remaining plugins packages from external API.
2019-11-06 19:48:43 -08:00
jregan
9fa0391ce9 Remove remaining plugins packages from external API. 2019-11-06 19:32:53 -08:00
Kubernetes Prow Robot
bda22d08cc Merge pull request #1743 from monopole/lowercaseBuiltins
Lowercase the generated filenames per Go style.
2019-11-06 19:30:43 -08:00
jregan
09faaa1b2c Lowercase the generated filenames per Go style. 2019-11-06 19:12:12 -08:00
Jeff Regan
9a65634df6 Merge pull request #1742 from monopole/moveBuiltinsToTop
Move the builtins to the top level as part of API
2019-11-06 18:50:49 -08:00
Jeffrey Regan
300383959d Remove plugins packages from external API. 2019-11-06 18:31:33 -08:00
Kubernetes Prow Robot
ab17d8dd74 Merge pull request #1741 from monopole/RemoveCMandSecretPackageFromApi
Remove CMSecret package from API.
2019-11-06 16:00:43 -08:00
Jeffrey Regan
c5ba2ced3b Remove CMSecret package from API. 2019-11-06 15:35:18 -08:00
Kubernetes Prow Robot
4103580834 Merge pull request #1740 from monopole/removeTargetFromExposedApi
Remove target package from exposed API.
2019-11-06 15:25:50 -08:00
Jeffrey Regan
d36e3f015d Remove target package from exposed API. 2019-11-06 15:10:11 -08:00
Jeff Regan
975e071394 Merge pull request #1739 from monopole/removeGitFromExposedApi
Remove git package from exposed API.
2019-11-06 13:16:08 -08:00
Jeffrey Regan
6542af600d Remove 'git' package from exposed API. 2019-11-06 13:08:47 -08:00
Kubernetes Prow Robot
9e6e928725 Merge pull request #1732 from monopole/moarMakefile
Migrate some presubmit functionality to Makefile.
2019-11-05 15:44:59 -08:00
Jeffrey Regan
ad24ba2234 Migrate some presubmit functionality to Makefile. 2019-11-05 12:37:08 -08:00
Jeff Regan
c7fd1dee8b Merge pull request #1716 from bzub/node_cm_namereference
Support node configmap namereference.
2019-11-04 14:38:22 -08:00
Jeff Regan
606eb8a74c Merge pull request #1731 from monopole/noKubevalOnTravis2
No kubeval dependent test on travis.
2019-11-04 14:37:27 -08:00
Jeffrey Regan
2340c98f6a No kubeval dependent test on travis. 2019-11-04 14:20:39 -08:00
Kubernetes Prow Robot
a7607c20e3 Merge pull request #1730 from monopole/noKubevalOnTravis
No kubeval dependent test on travis.
2019-11-04 14:08:12 -08:00
Phillip Wittrock
0b5cf74945 Merge pull request #1728 from pwittrock/kyaml
kyaml: initial support for yaml and resource manipulation
2019-11-04 14:04:01 -08:00
Jeffrey Regan
0687699d27 No kubeval dependent test on travis. 2019-11-04 13:01:37 -08:00
Kubernetes Prow Robot
357126fc4e Merge pull request #1729 from gliptak/patch-1
Correct typo
2019-11-04 12:56:12 -08:00
Gábor Lipták
0aeb53a2b3 Correct typo 2019-11-04 15:36:13 -05:00
Phillip Wittrock
efd7c8e3f7 kyaml: initial support for yaml and resource manipulation 2019-11-04 11:36:35 -08:00
bzub
152ee44b92 Support node configmap namereference. 2019-11-04 12:38:28 -06:00
Jeff Regan
588297f1f9 Update whatApi.sh 2019-11-04 09:50:43 -08:00
Jeff Regan
6b81ae9a93 Merge pull request #1726 from monopole/konfigPalooza
Improve config package names and reduce API exposure.
2019-11-04 09:24:28 -08:00
jregan
077c7b2d20 Improve config package names and reduce API exposure. 2019-11-03 16:39:44 -08:00
Jeff Regan
1a4330a7cb Merge pull request #1725 from monopole/tryThisOne
Improve plugin home defaulting.
2019-11-03 15:58:33 -08:00
jregan
d08690a6aa Improve plugin home defaulting. 2019-11-03 15:47:43 -08:00
Jeff Regan
ba925e833d Merge pull request #1724 from monopole/removeErrorFromConstructor
Improve error messaging around plugin loading problems.
2019-11-03 06:46:31 -08:00
jregan
4c15c42447 Remove error return from constructor. 2019-11-03 06:37:04 -08:00
Jeff Regan
690e01c2ba Update whatApi.sh 2019-11-02 14:12:15 -07:00
Jeff Regan
133d8bff5e Merge pull request #1723 from monopole/renaming
Improved plugin loading docs.
2019-11-02 13:56:55 -07:00
jregan
079c3307c1 Improved plugin loading docs. 2019-11-02 13:47:47 -07:00
Jeff Regan
e0070f7ec5 Merge pull request #1722 from monopole/moveLoadRestrictions
push flag code from api module to kustomize internal
2019-11-02 11:07:36 -07:00
Jeffrey Regan
a45eca7e22 move load restrictions 2019-11-02 10:34:33 -07:00
Jeff Regan
79c5f8a977 Merge pull request #1719 from monopole/mvPluginConfig
Move plugin config to main config package.
2019-11-01 16:32:42 -07:00
Jeffrey Regan
69d1699963 Move plugin config to main config package. 2019-11-01 16:31:00 -07:00
Jeff Regan
b6b8f4396f Merge pull request #1717 from liztio/patch-1
strategic-merge-patch documentation has moved
2019-11-01 16:11:32 -07:00
Liz
9ca5284e4f strategic-merge-patch documentation has moved 2019-10-31 14:31:19 -04:00
Kubernetes Prow Robot
335292fe8a Merge pull request #1714 from monopole/addTests
Add some kustomization tests.
2019-10-31 09:19:37 -07:00
Jeff Regan
cf9edbfb3c Merge pull request #1712 from pwittrock/mac-docs
Add Mac development guide
2019-10-30 16:36:17 -07:00
Jeffrey Regan
364a2342df Add some kustomization tests. 2019-10-30 16:20:23 -07:00
Phillip Wittrock
3301913178 Add Mac development guide 2019-10-30 09:11:25 -07:00
Jeff Regan
ac3c53557e Merge pull request #1709 from pwittrock/skip
Support for ignoring specific Resources via annotation.
2019-10-29 17:19:59 -07:00
Phillip Wittrock
8bf98dd255 Support for ignoring specific Resources via annotation.
Resources annotated with `config.kubernetes.io/local-config` will be ignored by Kustomize
2019-10-29 16:51:38 -07:00
Jeff Regan
f2368201d9 Merge pull request #1704 from monopole/whatApi
Script to report on api usage.
2019-10-28 14:41:07 -07:00
Jeffrey Regan
f44574cf43 Script to report on api usage. 2019-10-28 14:40:24 -07:00
Jeff Regan
3054d69dd9 Merge pull request #1702 from monopole/buryBuildCode
Reduce the size of the API used by the build command
2019-10-28 14:36:07 -07:00
Jeff Regan
739c2a5bac Merge pull request #1703 from monopole/timApple
Update travis.yaml for osx
2019-10-28 14:14:40 -07:00
Jeffrey Regan
a780bd6465 Update travis.yaml for osx 2019-10-28 13:51:24 -07:00
Jeffrey Regan
4716cb026f Simplify building api. 2019-10-28 13:36:14 -07:00
Jeff Regan
a186144a78 Reinstate simplified makefile
Partially undo
2ea4762d0f

The original makefile was annoying people who naturally expected it to work.
2019-10-28 13:35:49 -07:00
Jeff Regan
2ea4762d0f Delete makefile
This isn't maintained because it's not used by ./travis/pre-commit.sh or any other automated process.
It's just causing confusion.
2019-10-28 11:54:44 -07:00
Jeff Regan
eb268fa722 Merge pull request #1701 from monopole/replaceApiWithLocalApi
Point kustomize to local API for development.
2019-10-28 11:29:57 -07:00
Jeffrey Regan
3b3a1309e4 Point kustomize to local API for development. 2019-10-28 11:17:34 -07:00
Jeff Regan
72db6dde9e Merge pull request #1699 from monopole/makeKrusty
Make krusty package - high-level CLI-like package.
2019-10-27 08:28:33 -07:00
jregan
6d30bc5c35 Make krusty package - high-level CLI-like package. 2019-10-27 08:19:56 -07:00
Jeff Regan
773629e544 Merge pull request #1698 from monopole/mvHacksToHack
mv hacks dir to hack (match pattern in k/k repo).
2019-10-27 05:13:30 -07:00
jregan
cd50bf4e1e Move hacks to hack (match k8s pattern). 2019-10-27 05:05:23 -07:00
Jeff Regan
ff59e9b52f Merge pull request #1681 from rcmorano/feature/add-releaseName-and-releaseNamespace-support
Add support to render charts using '.Release.Name' and .Release.Namespace'
2019-10-25 10:33:59 -07:00
Jeff Regan
9a954d4f0b Merge pull request #1693 from monopole/fixSomeNits
Fix some nits.
2019-10-25 10:30:28 -07:00
jregan
5c63c20390 Fix some nits. 2019-10-25 10:29:48 -07:00
Kubernetes Prow Robot
a84f8d65db Merge pull request #1692 from monopole/movePluginsToApiV011
Pin the plugins to api/v0.1.1
2019-10-24 16:59:38 -07:00
Jeffrey Regan
6e2335ec3d Move plugins to api/v0.1.1 2019-10-24 16:32:12 -07:00
Jeff Regan
4cf6630fc0 Merge pull request #1671 from beautytiger/dev-191022-dup
delete duplicated entry in slice
2019-10-24 15:34:23 -07:00
Jeff Regan
d239d52217 Merge pull request #1690 from monopole/tuneUpCrawl
Tune up hack/crawl.
2019-10-24 13:29:59 -07:00
Jeffrey Regan
c260105212 Tune up hack/crawl. 2019-10-24 13:29:14 -07:00
Jeff Regan
44cdf98a47 Filter out pluginator in install curl script. 2019-10-24 12:40:06 -07:00
Kubernetes Prow Robot
92390eabe4 Merge pull request #1663 from chaosteil/pluginloadfail
Refactor exec plugin load to error if plugin isn't executable
2019-10-24 11:55:41 -07:00
Jeff Regan
7b8fa51ec5 More fixes to releasing instructions. 2019-10-24 11:50:34 -07:00
Jeff Regan
af8e17a1ed Fix curl command in INSTALL.md 2019-10-24 11:34:09 -07:00
Jeff Regan
e2eeb90639 Update INSTALL.md 2019-10-24 11:23:21 -07:00
Jeff Regan
1704977a4b Explain using go to install kustomize. 2019-10-24 11:08:21 -07:00
Kubernetes Prow Robot
7050c6a7b6 Merge pull request #1688 from monopole/moveKustBackToV3
Move kustomize back to v3
2019-10-24 10:45:13 -07:00
Jeffrey Regan
02f9b98b5a Move kustomize back to v3 2019-10-24 10:32:11 -07:00
Jeff Regan
ce7ebe3299 Make all releases draft by default 2019-10-23 17:03:01 -07:00
Roberto C. Morano
3928ada0e5 Add support to inflate charts including '.Release.Name' and .Release.Namespace' references in templates 2019-10-23 10:15:54 +02:00
Jeff Regan
0a8faced8f Merge pull request #1679 from monopole/updateCloudbuildAgain
Improve the release process instructions
2019-10-22 16:16:36 -07:00
Jeff Regan
3c06debf98 Merge pull request #1678 from monopole/fixCliInternalDeps
Fix internal kustomize CLI deps
2019-10-22 16:14:39 -07:00
Jeff Regan
fcee91eafd Merge pull request #1678 from monopole/fixCliInternalDeps
Fix internal kustomize CLI deps
2019-10-22 15:37:37 -07:00
Jeffrey Regan
b0b3a705f4 Fix internal kustomize CLI deps 2019-10-22 15:27:57 -07:00
Jeff Regan
67c8fbcc3c Merge pull request #1676 from monopole/useLatestCloudbuilderSigh
Use latest cloudbuilder image.
2019-10-22 12:50:33 -07:00
Jeffrey Regan
9b50b78ec8 Use latest cloudbuilder image. 2019-10-22 12:49:38 -07:00
Jeff Regan
943a1b0195 Merge pull request #1675 from monopole/pinKustomizeToApiV011
Pin kustomize CLI to API v0.1.1
2019-10-22 12:40:12 -07:00
Jeffrey Regan
f77143cd34 Pin kustomize CLI to API v0.1.1 2019-10-22 12:32:05 -07:00
Jeff Regan
b7d2ba2376 Merge pull request #1674 from monopole/dealWithDeprecationsInGoReleaser
Deal with goreleaser field deprecations.
2019-10-22 12:12:34 -07:00
Jeffrey Regan
c28a0eb83d Deal with goreleaser field deprecations. 2019-10-22 12:11:13 -07:00
Jeff Regan
f7e5b5138b Merge pull request #1673 from monopole/moreTweaks
Add tag check to release script
2019-10-22 11:52:55 -07:00
Jeffrey Regan
61149cbf21 Add tag check to release script 2019-10-22 11:51:26 -07:00
Jeff Regan
310d516030 Update README.md 2019-10-22 10:16:51 -07:00
Jeff Regan
a9e3fe155b Merge pull request #1672 from monopole/moreReleasingTweaks
Pin the cloudbuild step container tags.
2019-10-22 10:13:32 -07:00
Jeffrey Regan
24837bad40 More releasing tweaks. 2019-10-22 10:10:47 -07:00
Guangming Wang
9686cc9861 delete duplicated entry in slice 2019-10-22 21:45:55 +08:00
Dominykas Djacenko
a4784ee5ec Refactor exec plugin load to error if plugin isn't executable 2019-10-21 19:49:27 -07:00
Jeff Regan
3063560e77 Merge pull request #1670 from monopole/installKubevalNotes
Add kubeval install notes.
2019-10-21 19:34:41 -07:00
jregan
bff0604bee Add kubeval install notes. 2019-10-21 19:33:45 -07:00
Jeff Regan
9f8faa7d7e Merge pull request #1669 from monopole/cloudBuildTake9834
Cloud build adjustments.
2019-10-21 19:03:03 -07:00
jregan
335077eade Cloud build adjustments. 2019-10-21 19:00:52 -07:00
Jeff Regan
491baa74cb Merge pull request #1668 from monopole/tweakReleaseProcess
Experimenting with cloud build and goreleaser
2019-10-21 17:33:52 -07:00
Jeff Regan
2f2d078669 Update README.md 2019-10-21 17:31:40 -07:00
Jeff Regan
b7bcb90057 Update README.md 2019-10-21 16:43:35 -07:00
Jeff Regan
35dc15b16b Merge pull request #1667 from monopole/setupApiRelease
Define the API release process.
2019-10-21 16:37:41 -07:00
Jeffrey Regan
83f70877c8 Define the API release process. 2019-10-21 16:24:16 -07:00
Jeff Regan
98cd31b820 Merge pull request #1666 from monopole/modulesForAll
Each plugin gets its own module.
2019-10-21 16:16:25 -07:00
Jeffrey Regan
5416ae7365 Introduce API module. 2019-10-21 15:21:04 -07:00
Kubernetes Prow Robot
644f2ddcdc Merge pull request #1665 from monopole/introduceApiModule
Introduce API module.
2019-10-21 15:13:22 -07:00
Jeffrey Regan
46524d3b6a Introduce API module. 2019-10-21 13:30:31 -07:00
Jeff Regan
4f014d0262 Merge pull request #1664 from monopole/moveGeneratedCode
Move generated code
2019-10-21 13:21:19 -07:00
Jeffrey Regan
0cf2057fc5 Install generated plugin code into the API module. 2019-10-21 11:15:51 -07:00
Jeffrey Regan
3f08e1546c Move generated plugin code. 2019-10-21 09:48:11 -07:00
Jeff Regan
10619fb0f7 Merge pull request #1662 from monopole/builtinNestingPlace
Make new nesting place for generated builtin code.
2019-10-20 17:53:02 -07:00
jregan
c88e8cc057 Make new nesting place for generated builtin code. 2019-10-20 17:41:09 -07:00
Jeff Regan
327a3f5300 Merge pull request #1661 from monopole/moveK8sdeps
Move ks8deps to api for now.
2019-10-20 16:51:47 -07:00
jregan
fddde81f9c Move ks8deps to api for now. 2019-10-20 16:49:53 -07:00
Jeff Regan
22d07ed37d Merge pull request #1660 from monopole/drainTopInternal
Drain top internal folder
2019-10-20 16:14:08 -07:00
jregan
dee1c425da Drain the top level internal. 2019-10-20 15:51:04 -07:00
jregan
951d15bf17 Make api/plugins 2019-10-20 15:12:13 -07:00
Jeff Regan
0f82d2932c Merge pull request #1658 from monopole/makeInventoryPublic
Make inventory public.
2019-10-20 11:46:09 -07:00
jregan
e2d7a06e9f Make inventory public. 2019-10-20 11:43:36 -07:00
Jeff Regan
286b9c1aed Merge pull request #1657 from monopole/makeGitPrivate
Make git package private
2019-10-20 11:43:25 -07:00
jregan
f54d4a5837 Make git package private 2019-10-20 11:36:10 -07:00
Jeff Regan
d9031fb2c9 Merge pull request #1656 from monopole/makeResourcePublic
Make resource, resmap and ifc public.
2019-10-20 11:14:22 -07:00
jregan
3af5a8afea Make resource, resmap public. 2019-10-20 10:51:20 -07:00
Jeff Regan
e2fd33c54a Merge pull request #1655 from monopole/drainPkgTransformers
Drain pkg transformers
2019-10-20 09:50:59 -07:00
jregan
c90e0a4080 Drain pkg/transformers. 2019-10-20 09:19:07 -07:00
jregan
5de000ee3d Move FieldSpec to API. 2019-10-20 06:52:13 -07:00
Jeff Regan
c28b82510c Merge pull request #1654 from monopole/makeSmpPrivate
Make SMP code private to CLI.
2019-10-18 17:16:10 -07:00
jregan
fda3ba8af9 Make SMP code private to CLI. 2019-10-18 17:14:43 -07:00
Kubernetes Prow Robot
fd1356e5d8 Merge pull request #1653 from monopole/docsUpdate
Update docs
2019-10-18 13:13:37 -07:00
jregan
a62f1364fe Update docs 2019-10-18 12:46:36 -07:00
Jeff Regan
d1240bcc63 Update INSTALL.md 2019-10-18 10:48:54 -07:00
Jeff Regan
1c24fe7d16 Merge pull request #1651 from monopole/startApi
Start api directory, which will become the api module.
2019-10-17 15:03:57 -07:00
Jeffrey Regan
e5c8b5ec8f Start api directory, which will become a module. 2019-10-17 14:01:20 -07:00
Jeff Regan
180429774a Merge pull request #1649 from monopole/fixNits
fixNits
2019-10-17 11:16:46 -07:00
Jeffrey Regan
586bba0b31 fixNits 2019-10-17 11:15:10 -07:00
Jeff Regan
2ce138ab3a Update awker.sh 2019-10-16 20:40:21 -07:00
Jeff Regan
5e99ad000e Merge pull request #1645 from monopole/docTypes
Document the types package.
2019-10-16 17:25:05 -07:00
jregan
0f0e740c21 Document the types package. 2019-10-16 17:24:21 -07:00
Kubernetes Prow Robot
33600189bc Merge pull request #1644 from monopole/makeTypesPublic
Make types package public.
2019-10-16 16:58:38 -07:00
jregan
07d2500ee3 Make types package public. 2019-10-16 16:41:43 -07:00
Jeff Regan
de6eb14867 Merge pull request #1643 from monopole/cleanupTypes
Cleanup types package before going public.
2019-10-16 16:24:40 -07:00
jregan
85b71a31e3 Cleanup types package before going public. 2019-10-16 16:02:01 -07:00
Jeff Regan
16e7638220 Merge pull request #1642 from monopole/makeHasherPublic
Maker hasher public for now.
2019-10-16 14:21:44 -07:00
jregan
04c23b2085 Maker hasher public for now. 2019-10-16 12:25:09 -07:00
Kubernetes Prow Robot
24db94dd0d Merge pull request #1638 from dbachrach/f-edit-set-replicas
Add support for kustomize edit set replicas
2019-10-15 19:44:07 -07:00
Kubernetes Prow Robot
5f862ba17c Merge pull request #1639 from dbachrach/b-zero-replica-formatting
Fix yaml formatting of replicas count when count is 0
2019-10-15 17:00:13 -07:00
Jeff Regan
18ba3ee91b Merge pull request #1640 from monopole/moveKvStuff
Extract kv loader from file loader, and place in public package.
2019-10-15 16:59:21 -07:00
Jeffrey Regan
4e9d42fae7 Move kv loader code to public package. 2019-10-15 16:52:03 -07:00
Dustin Bachrach
52e57dab7f FIx yaml formatting of replicas count when count is 0
Previously, a count of 0 would cause the count field to be omitted from the yaml
2019-10-15 15:47:53 -07:00
Dustin Bachrach
ba464a5e11 Add support for kustomize edit set replicas
New command line tool for editing replica counts for resources.
Example:
  kustomize edit set replicas app=3 other-app=1
2019-10-15 15:43:10 -07:00
Jeff Regan
2734085fb0 Merge pull request #1634 from tkellen/gh-1600-failing
make failing test showing spurious variable conflicts
2019-10-15 14:24:28 -07:00
Tyler
d21ff7cfe6 make test pass with reference to bug 2019-10-15 16:59:32 -04:00
Jeff Regan
3a15f450a9 Merge pull request #1637 from monopole/renameDataSources
Rename DataSources to KvPairSources and remove deprecated env field.
2019-10-15 13:47:44 -07:00
Jeffrey Regan
bb77e7491a Rename DataSources to KvPairSources and remove deprecated env field. 2019-10-15 13:39:42 -07:00
Tyler
aa82240b4c use namespace value when making Var 2019-10-15 14:47:05 -04:00
Kubernetes Prow Robot
cac7b46ebd Merge pull request #1635 from beautytiger/dev-191015-trimfix
fix string trim in normalizeGitHostSpec func
2019-10-15 09:27:53 -07:00
Guangming Wang
367d0e042c fix string trim in normalizeGitHostSpec func
Signed-off-by: Guangming Wang <guangming.wang@daocloud.io>
2019-10-16 00:06:02 +08:00
Tyler
d851305c33 make failing test showing spurious variable conflicts 2019-10-15 00:33:33 -04:00
Jeff Regan
0c52bd71ba Merge pull request #1633 from monopole/startPlugLib
Start pluglib, a set of public, plugin specific functions.
2019-10-14 20:25:15 -07:00
Jeffrey Regan
41a008e9a3 Start pluglib, a set of public, plugin specific functions. 2019-10-14 19:43:55 -07:00
Jeff Regan
2fadb4dd59 Merge pull request #1630 from monopole/moveFilesysUp
Move filesys package up to make public.
2019-10-14 12:50:15 -07:00
Jeffrey Regan
a88ee3f93c Move filesys package up to make public. 2019-10-14 12:40:09 -07:00
Jeff Regan
237848a80b Merge pull request #1629 from monopole/renamePackageFsToFileSys
Rename fs package to filesys
2019-10-14 11:01:43 -07:00
Jeffrey Regan
9e3b837093 Rename fs package to filesys 2019-10-14 10:50:27 -07:00
Jeff Regan
c4eca908ac Merge pull request #1623 from monopole/removeVersionCheckFromMinecraft
Remove minecraft version check from chart plugin tests.
2019-10-12 13:03:22 -07:00
jregan
72d9b4cbca Remove minecraft version check from chart plugin tests. 2019-10-12 12:52:36 -07:00
Jeff Regan
19d94110b1 Merge pull request #1621 from scottnuma/patch-1
Update broken URL in Exec Plugin Tutorial
2019-10-12 10:10:41 -07:00
Jeff Regan
1756765dbc Merge pull request #1622 from monopole/fixNits
Fix some nits
2019-10-12 07:43:03 -07:00
jregan
b306f8511c Fix some nits 2019-10-12 07:42:04 -07:00
Scott Numamoto
9778f867b5 Update broken URL in Exec Plugin Tutorial
- link created in the scripts of Exec plugin on linux in 60 seconds to download the kustomize executable does not work
- used the [releases page](https://github.com/kubernetes-sigs/kustomize/releases/tag/v3.0.0) to fix
2019-10-12 01:02:16 -07:00
Jeff Regan
a69ebf2b11 Merge pull request #1576 from chenrui333/go-1.13
Upgrade golang to v1.13
2019-10-11 11:04:23 -07:00
Jeff Regan
cf9c81f908 Merge pull request #1615 from monopole/moreCodeToDiscussIn1297
More composition testing
2019-10-11 11:01:02 -07:00
Jeffrey Regan
b95164b9a8 More code to discuss in 1297 2019-10-11 10:37:29 -07:00
Rui Chen
0551338958 Merge branch 'master' of github.com:kubernetes-sigs/kustomize into go-1.13
* 'master' of github.com:kubernetes-sigs/kustomize: (27 commits)
  Update complexcomposition_test.go
  doc: add configmap generator key example
  tweakNamesInTest
  cleanup on errors in git loader
  refactor complexcomposition_test in prep for addition
  Update INSTALL.md
  Update INSTALL.md
  Introduce dummy program to help with API releases.
  fix zh-doc
  v3.3.0 release notes
  Move pluginator to kustomize Go API v3.3.0
  Three builders.
  Update README.md
  update release process doc
  improve tests for alternative kustomization file names
  Reduce size of pgmconfig package
  Break the dep between fs and pgmconfig.
  Improve fs package and doc in prep to officially go public
  Update versioning notes.
  Fix: documentation link for plugins
  ...
2019-10-11 11:18:20 -04:00
Kubernetes Prow Robot
40b7ad23ea Merge pull request #1618 from seriousben/add-configmap-key-example
doc: add configmap generator key example
2019-10-10 15:19:21 -07:00
Kubernetes Prow Robot
ce66ceeed6 Merge pull request #1616 from jeffmhastings/cleanup-git-clone-errors
cleanup on errors in git loader
2019-10-10 15:17:21 -07:00
Jeff Regan
4e45af6265 Update complexcomposition_test.go 2019-10-10 13:16:45 -07:00
Benjamin Boudreau
07a9454215 doc: add configmap generator key example 2019-10-10 16:11:37 -04:00
Jeff Regan
9f5a936236 Merge pull request #1617 from monopole/tweakNamesInTest
tweakNamesInTest
2019-10-10 13:04:25 -07:00
Jeffrey Regan
e6770e5f1e tweakNamesInTest 2019-10-10 13:03:55 -07:00
Jeff Hastings
705b4ab212 cleanup on errors in git loader 2019-10-10 15:54:56 -04:00
Jeff Regan
2cb964ab8e Merge pull request #1614 from monopole/refactorComplexTest
refactor complexcomposition_test in prep for addition
2019-10-10 11:28:27 -07:00
Jeffrey Regan
949b10bf93 refactor complexcomposition_test in prep for addition 2019-10-10 11:25:38 -07:00
Jeff Regan
cc4341c546 Update INSTALL.md 2019-10-09 11:16:19 -07:00
Jeff Regan
d0caea0ce1 Update INSTALL.md
fix #1604
2019-10-09 11:15:48 -07:00
Jeff Regan
f2ac5a2d0d Merge pull request #1603 from monopole/kustapiversion
Introduce dummy program to help with API releases.
2019-10-08 15:39:44 -07:00
jregan
78d14d0d75 Introduce dummy program to help with API releases. 2019-10-08 15:15:24 -07:00
Kubernetes Prow Robot
d5034af5ca Merge pull request #1519 from sunny0826/zh
zh example:chart,secret generator plugin
2019-10-08 11:25:50 -07:00
guoxudong
40ed9e6a44 fix zh-doc 2019-10-08 09:49:55 +08:00
Jeff Regan
c1d20546ec Merge pull request #1597 from monopole/v330releaseNotes
v3.3.0 release notes
2019-10-07 17:35:02 -07:00
Jeffrey Regan
3cf6b8ec4d v3.3.0 release notes 2019-10-07 17:34:21 -07:00
Jeff Regan
3aee7a9081 Merge pull request #1596 from monopole/updatePluginator
Move pluginator to kustomize Go API v3.3.0
2019-10-07 16:47:28 -07:00
Jeffrey Regan
abefa2b155 Move pluginator to kustomize Go API v3.3.0 2019-10-07 16:46:16 -07:00
Jeff Regan
5d800f0b0a Merge pull request #1595 from monopole/threeReleases
Differentiate the cloud builders.
2019-10-07 15:45:01 -07:00
Jeffrey Regan
4eb2d5bcc2 Three builders. 2019-10-07 15:40:36 -07:00
Jeff Regan
988af1ff61 Update README.md 2019-10-07 12:38:21 -07:00
Kubernetes Prow Robot
1617183ea4 Merge pull request #1590 from monopole/releaseProcessUpdate
update release process doc
2019-10-07 11:39:11 -07:00
jregan
ee72746481 update release process doc 2019-10-07 10:21:29 -07:00
Jeff Regan
c9e7dc3bfa Merge pull request #1589 from monopole/moreTestsAroundKustFileName
improve tests for alternative kustomization file names
2019-10-04 10:22:04 -07:00
Jeffrey Regan
07e0e46ac7 improve tests for alternative kustomization file names 2019-10-04 10:17:49 -07:00
Jeff Regan
404d2d631a Merge pull request #1587 from monopole/reducePgmconfig
Reduce size of pgmconfig package
2019-10-03 18:37:27 -07:00
Jeffrey Regan
baa0296a12 Reduce size of pgmconfig package 2019-10-03 18:22:05 -07:00
Jeff Regan
0f665ac153 Merge pull request #1544 from ptux/add-transformer-href
add transformer href
2019-10-03 16:38:47 -07:00
Jeff Regan
14b0a65091 Merge pull request #1581 from monopole/refactorFs
Break the dep between fs and pgmconfig.
2019-10-02 12:39:02 -07:00
Jeffrey Regan
2d58f8b81c Break the dep between fs and pgmconfig. 2019-10-02 12:01:45 -07:00
Jeff Regan
9a43ca53cc Merge pull request #1578 from nlamirault/fix/build-plugins-doc
Fix: documentation link for plugins
2019-10-02 11:15:41 -07:00
Jeff Regan
5372fc6f6c Merge pull request #1579 from monopole/fsPackageCleanup
Improve fs package and doc in prep to officially go public
2019-10-01 12:16:38 -07:00
Kubernetes Prow Robot
86bc344057 Merge pull request #1513 from nimohunter/fix_empty_list_item
empty list or map item return error
2019-10-01 12:13:34 -07:00
Jeff Regan
a014f7d414 Merge pull request #1561 from beautytiger/dev-190925
improve test code coverage in transformers
2019-10-01 12:13:00 -07:00
Jeffrey Regan
9a94bcb854 Improve fs package and doc in prep to officially go public 2019-10-01 11:12:27 -07:00
Jeff Regan
07634ef098 Merge pull request #1575 from monopole/versioning
Update versioning notes.
2019-09-30 18:42:14 -07:00
jregan
995f88d60c Update versioning notes. 2019-09-30 18:41:09 -07:00
Rui Chen
5caba59073 Upgrade golang to v1.13 2019-09-29 16:34:18 -04:00
Nicolas Lamirault
334a64676f Fix: documentation link for plugins
Signed-off-by: Nicolas Lamirault <nicolas.lamirault@gmail.com>
2019-09-27 09:22:35 +02:00
Guangming Wang
08963ba503 improve test code coverage in transformers
Signed-off-by: Guangming Wang <guangming.wang@daocloud.io>
2019-09-27 14:53:58 +08:00
Jeff Regan
326fb689be Merge pull request #1570 from bzub/1234-go_plugin_doc
Fix compile kustomize example.
2019-09-26 17:40:11 -07:00
Jeff Regan
970ce67c34 Update goPluginCaveats.md 2019-09-26 17:38:50 -07:00
Jeff Regan
98d1893057 Update INSTALL.md 2019-09-26 17:34:53 -07:00
Jeff Regan
d89b448c74 Fix git tag recovery in cloud build.
Deleted in previous PR.  Hard to test locally.
2019-09-26 17:08:58 -07:00
Jeff Regan
17bf9d325b Update releasing README. 2019-09-26 16:58:22 -07:00
Kubernetes Prow Robot
a99aff1d1c Merge pull request #1571 from monopole/updateCloudBuildProcess
Update cloud build process for kustomize.
2019-09-26 16:39:34 -07:00
Jeffrey Regan
a694ac7b63 Update cloud build process for kustomize. 2019-09-26 16:05:35 -07:00
bzub
b5b11ef6e9 Fix compile kustomize example. 2019-09-26 17:37:53 -05:00
Jeff Regan
fa1af6f51e Merge pull request #1473 from richardmarshall/execpluginhash
Support resource generator options in exec plugins
2019-09-26 10:12:52 -07:00
Jeff Regan
9288dec02a Fix failing BashedConfigMapTest 2019-09-26 09:56:04 -07:00
Kubernetes Prow Robot
1a45dd0b4f Merge pull request #1566 from monopole/releaseNotes3.2.1
v3.2.1 release notes
2019-09-26 09:09:08 -07:00
Richard Marshall
592c5acf5a docs: Exec plugin generator options 2019-09-26 08:41:41 -07:00
Richard Marshall
ac9424fa3e tests: Add unit tests for update resource options 2019-09-26 08:41:41 -07:00
Richard Marshall
79fbe7c4cc Support resource generator options in exec plugins 2019-09-26 08:41:41 -07:00
Jeff Regan
f69d526fa3 v3.2.1 release notes 2019-09-25 19:48:37 -07:00
Jeff Regan
07a95a60f6 Merge pull request #1565 from monopole/tweakBinaryDepsBeforeTagging
Pin the kustomize binary's dependence on kustomize libs.
2019-09-25 18:29:38 -07:00
jregan
032b385711 Pin the kustomize binary's dependence on kustomize libs. 2019-09-25 18:09:45 -07:00
Kubernetes Prow Robot
810629596a Merge pull request #1564 from monopole/moveKustomizeBinaryToOwnModule
Move the kustomize binary to its own module.
2019-09-25 16:53:06 -07:00
Jeffrey Regan
b82a8fd316 Move the kustomize binary to its own module. 2019-09-25 15:37:48 -07:00
Kubernetes Prow Robot
2d0c22d6a4 Merge pull request #1562 from keleustes/tools
Pin tool versions using go modules
2019-09-25 13:50:06 -07:00
Ian Howell
aa342deff7 Pin tool versions using go modules
This pins down the versions of various tools used in the building,
testing, and linting of kustomize. This will provide more consistency
across contributors' and travis' environments.
2019-09-25 15:27:47 -05:00
Kubernetes Prow Robot
10786ec0a7 Merge pull request #1554 from keleustes/readme
Update README.md to include Kubernetes 1.16
2019-09-25 09:12:02 -07:00
Jerome Brette
7c7056877b Update README.md to include Kubernetes 1.16 2019-09-25 12:51:51 +00:00
Jeff Regan
e8933d9789 Merge pull request #1560 from monopole/precommitTuneup
Make pre-commit more portable and less tricky.
2019-09-24 21:42:35 -07:00
jregan
9d7b65446f Make pre-commit more portable and less tricky. 2019-09-24 21:10:58 -07:00
Jeff Regan
7a0946a922 Merge pull request #1558 from monopole/dependOnNewPluginatorModule
Depend on new pluginator location.
2019-09-24 18:18:18 -07:00
Jeffrey Regan
def4f04572 Depend on new pluginator location. 2019-09-24 16:43:53 -07:00
Jeff Regan
2f2408f1cd Merge pull request #1559 from monopole/compressCopyright
Compress copyright in the commands package.
2019-09-24 16:43:26 -07:00
Jeffrey Regan
3b9bcc48a0 Compress copyright in the commands package. 2019-09-24 16:40:32 -07:00
Jeff Regan
d0429ff43b Merge pull request #1557 from monopole/pluginatorModule
Copy pluginator to its own module.
2019-09-24 14:38:38 -07:00
Jeffrey Regan
33deefc307 Copy pluginator to its own module. 2019-09-24 11:24:13 -07:00
Jeff Regan
9b3de82b45 Merge pull request #1506 from Liujingfang1/release
add release note for v3.2.0
2019-09-23 10:14:17 -07:00
Kubernetes Prow Robot
d217074fbf Merge pull request #1550 from keleustes/apiversion
Fix typo yaml declaration of APIVersion field of Kustomization type
2019-09-23 09:25:24 -07:00
Jerome Brette
1d90ba7c7b Fix typo in apiVersion yaml declaration 2019-09-22 05:24:58 +00:00
Kubernetes Prow Robot
eeeb4c36a1 Merge pull request #1547 from keleustes/extensions
Update Ingress apiVersion to networking.k8s.io/v1beta1
2019-09-20 13:17:26 -07:00
Jerome Brette
b1faa989f4 Update Ingress apiVersion to networking.k8s.io/v1beta1 2019-09-20 19:37:05 +00:00
nimohunter
d8250c9ee2 move test case 2019-09-19 15:45:31 +08:00
Wang(わん)
c950046659 add transformer href 2019-09-19 11:34:01 +09:00
Kubernetes Prow Robot
0c32691e9e Merge pull request #1537 from jaypipes/gomod-install-note
add note about GO111MODULE for source install
2019-09-18 11:43:31 -07:00
Jeff Regan
88b1d62740 Merge pull request #1541 from rtnpro/patch-1
Fix typo in transformerconfigs README
2019-09-18 11:34:18 -07:00
Jeff Regan
aec8206695 Update INSTALL.md 2019-09-18 11:33:18 -07:00
Jeff Regan
20c2b53a46 Merge pull request #1542 from monopole/tweakFilePathsInTest
Tweak file path handling and logging in test.
2019-09-18 11:19:08 -07:00
Jeffrey Regan
274b5c3b4e Tweak file path handling and logging in test. 2019-09-18 11:17:21 -07:00
Ratnadeep Debnath
b1fdaa2311 Fix typo in transformerconfigs README 2019-09-18 19:01:02 +05:30
Kubernetes Prow Robot
a3103f1e62 Merge pull request #1534 from monopole/configExample
Example of configuring builtin plugin.
2019-09-17 16:43:15 -07:00
Jeffrey Regan
74ed0b30e5 Example of configuring builtin plugin. 2019-09-17 16:29:08 -07:00
nimohunter
b5d5e70bdc empty list or map item return error 2019-09-16 09:42:49 +08:00
nimohunter
2e82985380 empty list or map item return error 2019-09-16 09:30:01 +08:00
Jay Pipes
55941f5769 add note about GO111MODULE for source install
It's not immediately obvious that in order to
get the `go install sigs.k8s.io/kustomize/v3/cmd/kustomize` instructions
to work successfully, you need to have `GO111MODULE=on` set, so I added
a note about that.

Issues #1536, #1314
2019-09-14 18:59:07 -04:00
Kubernetes Prow Robot
32be1cf4c2 Merge pull request #1532 from monopole/runBuiltinSansFlag
Ease configuring and running the builtin plugins.
2019-09-13 15:28:00 -07:00
jregan
2050afdeb4 Ease doing custom configuration of builtin plugins. 2019-09-13 14:45:36 -07:00
Kubernetes Prow Robot
7e71009283 Merge pull request #1526 from jimmidyson/ignore-prefix-suffix-apiservice
Do not prefix/suffix APIService resources
2019-09-13 11:28:29 -07:00
Kubernetes Prow Robot
72d26c6ad5 Merge pull request #1522 from jcassee/basereusenameprefix-test
Add test for name conflict with base reuse
2019-09-13 11:02:29 -07:00
Jeff Regan
e011f3be4f change "bases:" to "resources:"
per https://github.com/monopole/kustomize/blob/master/docs/fields.md#bases

no big deal
2019-09-13 10:47:35 -07:00
Kubernetes Prow Robot
f725bfc165 Merge pull request #1520 from jcpetruzza/cm-merge-nameprefix
Consider also currentId when replacing/merging resources
2019-09-13 10:40:30 -07:00
Jeff Regan
94ac55f17b Merge pull request #1505 from Liujingfang1/master
add inline patch document
2019-09-13 10:16:40 -07:00
Jimmi Dyson
dd5b3c1e2e Do not prefix/suffix APIService resources 2019-09-12 09:53:33 +01:00
Joost Cassee
e898c5221b Add test for name conflict with base reuse 2019-09-10 23:57:15 +02:00
Daniel Gorin
1237ae43b4 Consider currentId when replacing/merging resources
When merging resources such as the output of a `configMapGenerator`,
we need to consider the `CurrentId`, otherwise, we cannot extend
a common base definition twice by adding different prefixes, and
then further kustomize them.

See #1442.
2019-09-10 11:14:08 +01:00
guoxudong
281f932814 zh example:chart,secret generator plugin 2019-09-10 10:19:18 +08:00
Kubernetes Prow Robot
cd0187e948 Merge pull request #1515 from yujunz/plugin/go-getter
plugin/go-getter: support urls including `:`
2019-09-09 09:05:22 -07:00
jingfangliu
9516880042 add inline patch document 2019-09-09 09:02:48 -07:00
Yujun Zhang
4cb883863f plugin/go-getter: support urls including : 2019-09-09 15:39:45 +08:00
nimohunter
9e226001e3 empty list or map item return error 2019-09-09 13:42:18 +08:00
Kubernetes Prow Robot
9ee35c9afb Merge pull request #1484 from sunny0826/master
update zh doc
2019-09-06 08:44:58 -07:00
guoxudong
e455acc14b fix 2019-09-06 09:20:21 +08:00
Jeff Regan
6a3c2b2893 Merge pull request #1507 from monopole/anotherTest
Add an example of reusable builtin plugins with custom config.
2019-09-05 16:11:53 -07:00
Jeffrey Regan
f59d7998d2 Add an example of reusable builtin plugins with custom config. 2019-09-05 15:53:03 -07:00
jingfangliu
77b63f96d1 add release note for v3.2.0 2019-09-05 13:42:43 -07:00
Michael
6fcb78403f use kubectl apply -k # (#1495)
`kubectl apply -f ` is executed failed.  ref: #1494
2019-09-05 09:27:39 -07:00
Kubernetes Prow Robot
f87edc8c67 Merge pull request #1488 from yujunz/plugin/go-getter
Add example plugin for go-getter
2019-09-05 08:57:10 -07:00
Yujun Zhang
6a4150d199 Amend go-getter plugin document according to comments 2019-09-05 13:57:20 +08:00
Jeff Regan
143c5dd21d Merge pull request #1489 from damienr74/generic-crawler
tooling performance improvements, better structure
2019-09-03 11:35:43 -07:00
Yujun Zhang
ed920afb2e Support setting command in go-getter plugin
This allows one to use non-kustomization remote source
2019-09-02 14:53:18 +08:00
Jeff Regan
2677f4c4e7 Merge pull request #1492 from monopole/anotherTest
Test custom configuration of a builtin plugin.
2019-08-30 16:54:21 -07:00
jregan
a081534938 Test custom configuration of a builtin plugin. 2019-08-30 16:37:29 -07:00
Kubernetes Prow Robot
4ebad27d7a Merge pull request #1490 from mr-karan/docfix
feat: Add instructions for setting key in configmap
2019-08-30 11:08:57 -07:00
Karan Sharma
716a7307b2 feat: Add instructions for setting key in configmap 2019-08-30 16:21:11 +05:30
Yujun Zhang
ed91bce275 Add example plugin for go-getter 2019-08-30 11:14:46 +08:00
Damien Robichaud
c2d6f09ef3 Crawler performance improvements, better structure
Refactored the crawler implementation to make the whole thing more
testable. Added a document interface to make the crawler generic.
This will be useful for collecting plugins, and other documents.
2019-08-29 22:25:45 -03:00
Kubernetes Prow Robot
119ff5af73 Merge pull request #1487 from laverya/properly-omitempty-kustomization-inventory
properly omitempty for 'inventory' in 'kustomize'
2019-08-29 15:17:00 -07:00
Andrew Lavery
2e7ad48b44 properly omitempty for 'inventory' in 'kustomize'
with the current 'yaml:"inventory:omitempty"', 'inventory:omitempty' is used as the literal name for the yaml field
2019-08-29 14:41:03 -07:00
Kubernetes Prow Robot
6ead3b7b1f Merge pull request #1446 from keleustes/ending
IsInKustomizeCtx should use end of nameprefix array instead of beginning
2019-08-29 12:12:59 -07:00
Jerome Brette
31262cccbe IsInKustomizeCtx should use end of nameprefix array (code review) 2019-08-29 13:59:01 -05:00
Jerome Brette
93cedbaa51 IsInKustomizeCtx should use end of nameprefix array (3/3)
Improve multi level kustomization ctx during candidate selection
testing.
2019-08-29 13:58:03 -05:00
Jerome Brette
6e13acfac3 IsInKustomizeCtx should use end of nameprefix array (2/3)
Update unit tests associated with in IsSameKustomizeCtx
2019-08-29 13:58:03 -05:00
Jerome Brette
2e6dd481e0 IsInKustomizeCtx should use end of nameprefix array (1/3)
Need to use ending prefix and suffix subarray instead of beginning
2019-08-29 13:58:03 -05:00
Kubernetes Prow Robot
a66808a10d Merge pull request #1483 from bianpengyuan/fix-typo
Fix environment variable typo in plugin doc
2019-08-28 13:17:55 -07:00
guoxudong
a4e1ba0593 update zh doc 2019-08-27 13:57:17 +08:00
Pengyuan Bian
73660af10c fix environment variable typo. 2019-08-26 16:24:44 -07:00
Kubernetes Prow Robot
84519c236b Merge pull request #1434 from sunny0826/master
update examples-zh
2019-08-26 09:00:27 -07:00
guoxudong
aedb362565 fix doc 2019-08-24 16:18:34 +08:00
Jeff Regan
6918931728 Merge pull request #1481 from damienr74/modify-crawler
Add configs
2019-08-23 12:59:08 -07:00
Damien Robichaud
3f1b2bb744 Add configs 2019-08-23 12:57:59 -07:00
Kubernetes Prow Robot
33ad02a6b4 Merge pull request #1383 from richardmarshall/smp_patch_directive
Handle ordering patch with SMP delete directives
2019-08-23 11:15:18 -07:00
Kubernetes Prow Robot
bfd6e086de Merge pull request #1474 from keleustes/coverage
Add cover target to Makefile
2019-08-23 10:55:18 -07:00
Jeff Regan
a9f58383d8 Merge pull request #1460 from richardmarshall/namespace_conflicts
Detect ID conflicts in namespace transformer
2019-08-23 10:54:36 -07:00
Ian Howell
aabbbf05ef Add cover target to Makefile 2019-08-23 08:22:00 -05:00
Jeff Regan
40c613d0cd Merge pull request #1476 from damienr74/add-ui
Adds frontend + configs to interal/tools
2019-08-22 16:59:44 -07:00
Jeff Regan
eca5b8796f Merge pull request #1470 from damienr74/index
First draft of documentation for internal/tools
2019-08-22 16:08:44 -07:00
Damien Robichaud
aa2bf7ed08 Adds frontend + configs to interal/tools/ui 2019-08-22 15:39:00 -07:00
Damien Robichaud
351df67e39 First draft of documentation for internal/tools 2019-08-21 17:01:59 -07:00
Kubernetes Prow Robot
8a8698ccdd Merge pull request #1469 from damienr74/index
Add simple service/configs to internal tooling.
2019-08-21 14:58:31 -07:00
Damien Robichaud
66fa2de073 Add main backend service and configurations 2019-08-21 14:29:41 -07:00
Kubernetes Prow Robot
3ace96d7a4 Merge pull request #1467 from richardmarshall/create_fixes
Fixes to create sub-command
2019-08-21 11:38:33 -07:00
Jeff Regan
2b44ba200f Merge pull request #1455 from lcostea/master
Add short version flag
2019-08-21 11:35:23 -07:00
Jeff Regan
4b67a6de12 Merge pull request #1456 from matti/patch-2
fix latest version
2019-08-21 10:57:18 -07:00
Jeff Regan
33bd221a98 Update README.md
removed it rather than keeping it and having it get out of date again
2019-08-21 10:56:43 -07:00
Richard Marshall
594a06d35b Fixes to create sub-command 2019-08-21 08:59:21 -07:00
Kubernetes Prow Robot
e541ff3999 Merge pull request #1414 from richardmarshall/create_subcommand
Create subcommand
2019-08-20 16:47:20 -07:00
Jeff Regan
9ea184c04a Merge pull request #1449 from richardmarshall/git_cycle_detection
Fix indirect cycle detection for git resources
2019-08-20 16:17:36 -07:00
Jeff Regan
993993c6cd Merge pull request #1464 from damienr74/index
Add internal tooling library for index managment.
2019-08-20 15:22:58 -07:00
Jeff Regan
35b39763dd Merge pull request #1445 from liggitt/patch-path
Fix patch path example
2019-08-20 15:15:03 -07:00
Jeff Regan
2c1dda5436 Merge pull request #1437 from fentas/fentas-patch-1
add PriorityClass to the order list
2019-08-20 15:09:57 -07:00
Jeff Regan
653123975c Merge pull request #1435 from lukatera/go-get-submodules
Download submodules when using base from git
2019-08-20 15:08:08 -07:00
Jeff Regan
fb8b314a29 Merge pull request #1426 from fleeto/translate-zh-glossary
translate-zh: glossary.md
2019-08-20 15:04:22 -07:00
Jeff Regan
5cf3f4e275 Merge pull request #1419 from richardmarshall/git_url_handling
Handle git:: prefix in urls containing _git
2019-08-20 15:01:14 -07:00
Jeff Regan
766500508c Merge pull request #1465 from monopole/testHeadAgainstExamples
Test examples against HEAD as well as against latest release.
2019-08-20 14:24:09 -07:00
Jeffrey Regan
423a8a6e0d Test examples against HEAD as well as against latest release. 2019-08-20 14:10:01 -07:00
Damien Robichaud
7783a76b8f Add internal tooling library for index queries. 2019-08-20 11:25:20 -07:00
Jeff Regan
2b6a406dc7 Merge pull request #1462 from monopole/errormessages
in plugin executor remove unnecessary code and improve error messages
2019-08-19 20:35:51 -07:00
jregan
bc303c4629 in plugin executor remove unnecessary code and improve error messages 2019-08-19 20:23:07 -07:00
Jeff Regan
00360f381c Merge pull request #1461 from monopole/fixNonTravisTests
Fix non-travis tests.
2019-08-19 16:29:44 -07:00
jregan
fa834f9541 Fix non-travis tests. 2019-08-19 16:29:00 -07:00
Jeff Regan
a2767cab2a Merge pull request #1374 from alexeldeib/ace/windows
fix: windows builds
2019-08-19 15:03:51 -07:00
Richard Marshall
24c173a49b Detect ID conflicts in namespace transformer 2019-08-19 08:55:54 -07:00
Matti Paksula
d3d4908f95 fix latest version
I don't think it makes sense to have version in README, though
2019-08-18 13:18:22 +03:00
Jeff Regan
be1d5478dc Merge pull request #1450 from damienr74/master
Add internal tooling for kustomize
2019-08-16 14:49:37 -07:00
Damien Robichaud
d3022ccd65 rename to tools directory 2019-08-16 11:25:20 -07:00
Damien Robichaud
fe45157b26 Update crawler to cache web request form github.
- Increase logging signal to noise ratio.
- Allow to specify the `http.Client` for github requests. (This allows
 the use of caching http.Clients).
- Clean up implementation.
2019-08-16 09:48:23 -07:00
Damien Robichaud
df779fd720 Modify document for elasticsearch migration. 2019-08-16 09:48:23 -07:00
Damien Robichaud
e0d388c6f7 Implements search query partitioning by filesize.
Binary searches through different ranges of file sizes to create search
queries with fewer than 1000 results. This is required since github will
only return the first 1000 result of any search query.

The implementation handles the case where some files may be deleted
while the search is running, and (possibly artificially) assures that the
number of files increases monotonically as the filesize range grows.

The implementation also caches queries and is expected to make fewer
than O((#files/1000) * lg(max file size)) API calls to retrieve the
range queries that can be used to index all of the files.

In practice running the search splitting takes a few minutes, while
retrieving all of the data takes a few hours.
2019-08-16 09:48:23 -07:00
Damien Robichaud
62edcae233 Implementation of configurable github crawler.
Currently I've left the search splitting by file size out of this commit
since it's ~200 lines of logic, and I think it's best to get it reviewed
separately.

In it's current state the crawler would only be able to get the last
1000 indexed files by Github, but it does show the general structure of
how the crawler is implemented.
2019-08-16 09:48:23 -07:00
Damien Robichaud
ac6918d70f Implementation of github query helper library.
To make this easier to read, use, and modify, I've abstracted the
important parts of the github query api into crawler/github/query.go
which allows to describe at a high level what is to be searched without
knowing the API syntax.
2019-08-16 09:48:23 -07:00
Damien Robichaud
ca41674df3 Implementation of basic crawler organisation.
`crawler.Crawler` interface is defined, where a crawler has to implement
a `Crawl` method that forwards document found by the crawler to a channel.

A helper function that launches a list of crawlers concurrently and
merges their channels into one main output channel, forwarding errors is
also implemented.

Finally, a test that verifies the correctness and concurrency of the
helper method is provided.
2019-08-16 09:48:23 -07:00
Damien Robichaud
c02b4f3a11 Initial (temporary) implementation of search doc.
Document describing how to convert a kustomization file into a
searchable document on appengine (will be changed to elasticsearch)
soon.
2019-08-16 09:48:23 -07:00
Liviu Costea
64341a81fa Add short version flag 2019-08-16 09:46:37 +03:00
Richard Marshall
fe8ba8e44b Log loader errors during resource accumulation 2019-08-15 07:59:55 -07:00
Richard Marshall
54f1952195 Log output from git on errors 2019-08-15 07:34:38 -07:00
Richard Marshall
44b62a8ebc Fix indirect git resource cycle detection 2019-08-15 07:25:20 -07:00
Jordan Liggitt
8e9c08ea61 Fix patch path example 2019-08-14 15:55:55 -04:00
Kubernetes Prow Robot
c464fb0a81 Merge pull request #1436 from richardmarshall/kubectl_clarity
docs: Additional details for kubectl integration
2019-08-13 15:18:23 -07:00
Richard Marshall
9481e3fba6 docs: Update patchesStrategicMerge documentation 2019-08-13 13:38:42 -07:00
Richard Marshall
0e5206a251 test: Update target tests for SMP directives 2019-08-13 13:38:42 -07:00
Richard Marshall
96c5b4aa3e Handle ordering patches with SMP delete directives
This change enables the SMP patch merging process to support delete
directives in patches regardless of input order.
2019-08-13 13:38:41 -07:00
Jan Guth
6c44da52a2 add PriorityClass to the order list 2019-08-10 07:31:54 +02:00
Kubernetes Prow Robot
694cf23df8 Merge pull request #1432 from richardmarshall/lostreplicas
Retain replicas field in edit marshal path
2019-08-09 14:29:14 -07:00
Richard Marshall
e66656aa7f docs: Additional details for kubectl integration 2019-08-08 17:06:19 -07:00
Richard Marshall
eaae7af5fe Retain replicas field in edit marshal path 2019-08-08 15:45:56 -07:00
Luka Skugor
2de052ecd8 Download submodules when using base from git 2019-08-08 15:49:56 +02:00
guoxudong
6cf8b9e2b8 update examples-zh 2019-08-08 10:16:13 +08:00
Kubernetes Prow Robot
f9fe138114 Merge pull request #1416 from anthonyho007/makefile
add Makefile for local development
2019-08-07 11:04:09 -07:00
Vincent C
78c9729252 translate-zh: glossary.md 2019-08-03 20:40:58 +08:00
Kubernetes Prow Robot
2a2a889c37 Merge pull request #1423 from sunny0826/master
Update zh-README.md & zh-example-README.md
2019-08-02 12:37:55 -07:00
郭旭东
34287e511f fix example-zh-README.md 2019-08-02 09:09:32 +08:00
Anthony Ho
e6fffc8ba4 add makefile 2019-08-01 11:23:38 -04:00
郭旭东
86f221611e Update zh-example-README.md 2019-08-01 15:30:11 +08:00
郭旭东
b4d6e89fa2 Update zh-README.md 2019-08-01 15:19:14 +08:00
Richard Marshall
adbb6228a5 Handle git:: prefix in urls containing _git 2019-07-31 10:23:05 -07:00
Kubernetes Prow Robot
5937bd0259 Merge pull request #1394 from richardmarshall/namerefperformance
Simplify name reference candidate resmap building
2019-07-31 10:18:14 -07:00
Richard Marshall
eeafd43513 Remove import of k8sdeps from create command 2019-07-30 20:52:06 -07:00
Richard Marshall
a68f95b65f Rename commands utility function file 2019-07-30 20:50:52 -07:00
Richard Marshall
ed3c29be12 Simplify name reference candidate resmap building
This patch removes a layer of looping in the name reference candiate
resmap building process by not checking if the resources already exist
in the new resmap.
2019-07-30 17:15:15 -07:00
Kubernetes Prow Robot
3d2e956b19 Merge pull request #1412 from richardmarshall/anchor_resmap_select
Automatically anchor resource selector patterns
2019-07-30 15:47:11 -07:00
Kubernetes Prow Robot
dd9d1f95e9 Merge pull request #1389 from Liujingfang1/repospec
make repospec memebers public
2019-07-30 15:27:51 -07:00
jingfangliu
a279c08f7d make repospec memebers public 2019-07-30 13:56:20 -07:00
Kubernetes Prow Robot
a798109161 Merge pull request #1413 from bai/fix-typo
Fix typo in patches definition
2019-07-30 10:14:51 -07:00
Richard Marshall
5dfa929906 Add create subcommand 2019-07-30 09:17:29 -07:00
Richard Marshall
e904f612f3 Move commands/edit utils package up to commands 2019-07-30 08:45:06 -07:00
Vlad Gorodetsky
bafd6b5423 Fix typo in patches definition 2019-07-30 14:52:02 +03:00
Richard Marshall
963913f9ef Automatically anchor resource selector patterns 2019-07-29 17:57:33 -07:00
Jingfang Liu
46905588ac add document for inline patch (#1411) 2019-07-29 15:15:06 -07:00
Kubernetes Prow Robot
5426888df4 Merge pull request #1405 from Liujingfang1/inlinepatch
add inline patch support for Strategic Merge Patch and JSON patch
2019-07-29 14:28:49 -07:00
jingfangliu
35481ec6d9 add inline patch support for Strategic Merge Patch and JSON patch 2019-07-29 14:10:57 -07:00
Kubernetes Prow Robot
6c92c30e94 Merge pull request #1402 from damienr74/currentid-replicas
Allow replicas to find modified names.
2019-07-29 12:54:47 -07:00
Damien Robichaud
02f6b3ec98 Allow replicas to find modified names.
Also allows to test for modified resmaps instead of directly loading
them.
2019-07-26 18:00:59 -07:00
Kubernetes Prow Robot
a9848f2738 Merge pull request #1403 from Liujingfang1/inlinepatch
add testing for patch transformers
2019-07-26 15:05:57 -07:00
jingfangliu
b4038a6cd2 add testting for patch transformers 2019-07-26 14:02:52 -07:00
Kubernetes Prow Robot
95f3303493 Merge pull request #1400 from keleustes/defaultsa
Force the namespace value for the "default" service object.
2019-07-26 10:51:21 -07:00
Jerome Brette
2faf4a491b Force the namespace value for the "default" service object.
The clusterrolebinding and rolebinding is pointing at a resource
which is not listed in the kustomize
2019-07-25 22:43:59 +00:00
Kubernetes Prow Robot
e646bba1ff Merge pull request #1396 from Liujingfang1/delete
support strategic merge patch with $patch: delete
2019-07-25 12:24:45 -07:00
Kubernetes Prow Robot
99a21b0a3c Merge pull request #1308 from keleustes/varequal
Demonstrate need for Var.DeepEqual method equivalent
2019-07-25 11:26:06 -07:00
Kubernetes Prow Robot
e7a22b6bc5 Merge pull request #1398 from keleustes/doc
Update v3.1.0 release notes.
2019-07-25 10:43:28 -07:00
Jerome Brette
d783bbc0bc DeepEqual method seems cleaner than adding Defaulting before every
reflect.DeepEqual call
2019-07-25 03:52:25 +00:00
Jerome Brette
b7405f3872 Test new types.Var.DeepEqual method. 2019-07-25 03:50:28 +00:00
Jerome Brette
abc419b5f9 Add Absorb method to VarSet and DeepEqual to Var 2019-07-25 03:42:40 +00:00
Jerome Brette
336378b114 Update release notes 2019-07-25 00:12:51 +00:00
jingfangliu
29959551da release note for v3.1.0 2019-07-24 14:16:09 -07:00
jingfangliu
fc78917191 support strategic merge patch with $patch: delete 2019-07-24 12:46:33 -07:00
Kubernetes Prow Robot
ffd95ef5a9 Merge pull request #1378 from keleustes/nameprefix
Name Prefix and Suffix Transformation for multi level level kustomize context
2019-07-24 11:33:21 -07:00
Jerome Brette
230090d790 Fix namereference and stacked kustomization contexts (3/3)
- Update unit and integration tests.
2019-07-24 18:02:29 +00:00
Jerome Brette
8fa3861ba3 Fix namereference and stacked kustomization contexts (2/3)
- Leverage nameprefix and namesuffix contextual data
2019-07-24 18:02:23 +00:00
Jerome Brette
69c90e3427 Fix namereference and stacked kustomization contexts (1/3)
- Update PrefixSuffixTransfomer to add empty prefix and suffix
2019-07-24 10:59:07 -05:00
Kubernetes Prow Robot
5a73f345fd Merge pull request #1388 from Liujingfang1/patch
add example for extended patches
2019-07-23 17:04:16 -07:00
jingfangliu
0e62d759f0 address comments 2019-07-23 16:55:58 -07:00
jingfangliu
b2967d2f77 add example for extended patches 2019-07-23 15:54:25 -07:00
Kubernetes Prow Robot
c23039c07a Merge pull request #1379 from keleustes/namespace
Update Namespace and Name simultaneously
2019-07-23 14:10:14 -07:00
Kubernetes Prow Robot
5747c417c4 Merge pull request #1363 from Liujingfang1/patch
update edit fix to convert the old patches to patchesStrategicMerge
2019-07-23 13:16:14 -07:00
jingfangliu
8c53d77111 update edit fix to convert the old patches to patchesStrategicMerge 2019-07-23 10:38:48 -07:00
Jerome Brette
01667cabde Update Namespace and Name simultaneously (2/2)
Add tests combining prefixsuffix and namespace transformers.
2019-07-23 11:04:59 -05:00
Jerome Brette
f649b62629 Update Namespace and Name simultaneously (1/2)
- Removed RoleBinding and Webhook specific code in the namespacetransformer.
  That code was attempting to perform the task of the namereference
- Updated namereference transformer configuration to suppport the
  Webhooks.
- Prevent the namereference from wiping out the namespace value if
  no referral candidate was selected
- Added unit tests.
2019-07-23 11:04:52 -05:00
Kubernetes Prow Robot
3a4d025b5c Merge pull request #1371 from keleustes/nsvar
Add namespace to variable definition
2019-07-22 11:04:53 -07:00
Ace Eldeib
c2cc93a009 fix: tempfile(?) 2019-07-19 17:38:24 -07:00
Ace Eldeib
af29855802 fix: windows builds 2019-07-19 12:58:06 -07:00
Jerome Brette
99eb08eb1e Add Namespace to var definition to allow disambiguation 2019-07-19 12:08:38 -05:00
Kubernetes Prow Robot
d3f8c0d87f Merge pull request #1327 from keleustes/residrequals-variables
ResId.Equals usable for VariableRef.
2019-07-19 09:41:12 -07:00
Jerome Brette
0bec7b996b Code review implementation for namespace needed in vars 2019-07-18 19:20:10 -05:00
Jerome Brette
dd5674fe6b ResId.Equals usable for VariableRef.
- Namespace need objRef field in variable declaration
- Add namespace conflict test for variables

The replacement of ResId.GkvnEquals reference by ResId.Equals
highligthed the fact it is no possible yet when looking for
variable targets because the namespace field is not allowed yet.
This commit adds two tests to the namespaces_test.go regarding
that use case.
2019-07-18 19:20:10 -05:00
Kubernetes Prow Robot
33159c26df Merge pull request #1369 from Liujingfang1/order
add ResourceQuota to the order list
2019-07-18 16:35:51 -07:00
Kubernetes Prow Robot
afc7dbebe5 Merge pull request #1326 from keleustes/residequals-patchtransformer
Residequals patchtransformer
2019-07-18 13:14:19 -07:00
Jerome Brette
f363acf839 Implement code review changes for ResId.Equals instead of ResId.GkvnEquals 2019-07-18 14:13:51 -05:00
Kubernetes Prow Robot
96d5a7401d Merge pull request #1365 from richardmarshall/fix_integration_test
Fix kustomize install in integration test
2019-07-18 11:56:26 -07:00
jingfangliu
403fa20546 add ResourceQuota and LimitRange to the order list 2019-07-18 11:44:46 -07:00
Richard Marshall
ba4d7ddca8 test: Fix kustomize install in integration test 2019-07-17 20:28:47 -07:00
Jerome Brette
5116e2f210 Improve Transformer with Namespace tests.
- Reorganize test into test tables.
- Ensure that every test case, convers SMP and JSONPatch by
  using Deployment as kind first and then "MyCRD" as kind.
- Add tests involving namespaces.
- Add tests involving reordering of patches.
2019-07-17 15:44:44 -05:00
Jerome Brette
9e0f198227 Start to phase out usage ResId.GvknEquals where possible 2019-07-17 15:44:44 -05:00
Kubernetes Prow Robot
30b378a924 Merge pull request #1325 from keleustes/residequals-namereference
NameReference Transformer needs to account for namespace and cluster wide objects.
2019-07-17 13:20:13 -07:00
Kubernetes Prow Robot
3a843f1eca Merge pull request #1362 from Liujingfang1/doc
update the latest version in readme
2019-07-17 13:04:14 -07:00
Jerome Brette
9b40f8ab47 Implement code review comments to NameReferenceTransformer changes.
- Add comments where code with potentially misleading.
- Rename functions according to comments
2019-07-17 14:10:01 -05:00
jingfangliu
dc6dcd8150 update the latest version in readme 2019-07-17 12:05:12 -07:00
Kubernetes Prow Robot
3cb6c7f1f4 Merge pull request #1349 from yujunz/faq
Add FAQ about how to customize configuration
2019-07-17 11:26:11 -07:00
Kubernetes Prow Robot
7632839bc8 Merge pull request #1350 from yujunz/docs/plugins
Convert go plugin example to GPG based
2019-07-17 10:40:37 -07:00
Yujun Zhang
c3ea109b59 Update goPluginGuidedExample.md 2019-07-17 08:19:50 +08:00
Jerome Brette
579995dc8a Address simultaneous transformation of name and namespace
Namereference handler needs to address simulatenous change of
name and namespace in ClusterRoleBinding for instance.
2019-07-16 18:17:33 -05:00
Jerome Brette
b43bd5440d Update Issue 1264 Reproduction Test 2019-07-16 18:17:33 -05:00
Jerome Brette
c4d899f7f3 Improve NameReference Test cases
- Add more NameReference Namespace tests
- Address issue when mixing empty/no namespace and default namespace.
- Address ClusterRoleBinding subjects field pointing at multiple namespaces.
2019-07-16 18:17:33 -05:00
Jerome Brette
7998ee7036 Addresses slice case with notNamespaceable objects 2019-07-16 18:17:33 -05:00
Kubernetes Prow Robot
878960d7b1 Merge pull request #1355 from Liujingfang1/patch
enable extended patch transformer and add tests
2019-07-16 15:58:34 -07:00
jingfangliu
ed0cfc685b add test for extended patch with overlapping patches 2019-07-16 15:16:00 -07:00
Kubernetes Prow Robot
b0a7345123 Merge pull request #1359 from keleustes/imagetag
Address replacement of digest by ImageTransformer
2019-07-16 13:10:49 -07:00
Jerome Brette
580963ea76 Address replacement of digest by ImageTransformer
- See [Issue 1357](https://github.com/kubernetes-sigs/kustomize/issues/1357)
- Add more plugin tests.
2019-07-16 14:03:56 -05:00
Kubernetes Prow Robot
0707deae95 Merge pull request #1356 from keleustes/droppatch
Test tracking issue patchesStrategicMerge elements can be dropped
2019-07-16 10:50:18 -07:00
Yujun Zhang
fb44880b8c Add back GCP KMS example 2019-07-16 20:10:16 +08:00
Jerome Brette
e5ebca6604 Test tracking issue "patchesStrategicMerge elements can be dropped"
- Issue 1354
- $patch: delete is ignored or not depending of the include order
  in the kustomization.yaml
2019-07-15 19:02:52 -05:00
jingfangliu
f5fc9acb84 fix local test failures 2019-07-15 18:59:16 -05:00
jingfangliu
28d1bad3cb fix the ci failure 2019-07-15 18:58:52 -05:00
jingfangliu
6f74419628 fix local test failures 2019-07-15 16:34:13 -07:00
jingfangliu
8121467c1e fix the ci failure 2019-07-15 16:01:23 -07:00
jingfangliu
a85f297f31 enable extended patch transformer and add tests 2019-07-15 15:45:08 -07:00
Kubernetes Prow Robot
76a7816aeb Merge pull request #1348 from yujunz/nameref
Add storage class name ref
2019-07-15 13:17:25 -07:00
Kubernetes Prow Robot
7872405379 Merge pull request #1336 from richardmarshall/fix_test_flags
Remove go testing flags from kustomize help
2019-07-15 13:13:24 -07:00
Kubernetes Prow Robot
6c17a3409f Merge pull request #1346 from Liujingfang1/patchallkinds
add extended patch transformer
2019-07-15 11:45:24 -07:00
Yujun Zhang
f1dbab9dee Convert go plugin example to GPG based 2019-07-14 11:33:37 +08:00
Yujun Zhang
bfafbbf47f Add FAQ about how to customize configuration 2019-07-14 10:39:45 +08:00
Yujun Zhang
08d7c35da7 Add storage class name ref 2019-07-14 10:05:19 +08:00
Kubernetes Prow Robot
f12704f6c1 Merge pull request #1331 from Rjerk/fix-vp-doc
docs/versioningPolicy.md: fix expired urls
2019-07-12 14:41:05 -07:00
Tony Hsu
0edab60b30 Fix typo: kubectl v1.15 -> kubectl v1.14 (#1333)
* Fix typo: kubectl v1.15 -> kubectl v1.14

Match version number to the version in the link.

* Add both kubectl v1.14 and v1.15

* Add both kubectl v1.14 and v1.15
2019-07-12 14:38:10 -07:00
jingfangliu
3c05e2d664 add extended patch transformer 2019-07-12 14:34:08 -07:00
Kubernetes Prow Robot
aa2313c282 Merge pull request #1344 from Liujingfang1/fix
include nameprefix and namesuffix to find matched reference for cluster level kinds
2019-07-12 11:55:06 -07:00
jingfangliu
eeed1954fb include nameprefix and namesuffix to find matched reference for cluster level kinds 2019-07-12 10:27:02 -07:00
Kubernetes Prow Robot
cd00ce7ab1 Merge pull request #1341 from Liujingfang1/refactor
move strategic merge patch transformer to a builtin transformer
2019-07-12 09:25:05 -07:00
jingfangliu
145d07363f add labels in test patch files 2019-07-12 08:56:34 -07:00
jingfangliu
33fff655db move strategic merge patch transformer to a builtin transformer 2019-07-11 13:39:30 -07:00
Jingfang Liu
31ab347da2 refactor the strategic merge patch transformer toward moving it to a plugin (#1340) 2019-07-11 10:22:56 -07:00
Kubernetes Prow Robot
7a48b2ba8e Merge pull request #1338 from yujunz/transformer/config
Fix missing nameReference in default config
2019-07-11 09:32:55 -07:00
Yujun Zhang
876f2a8236 Fix missing nameReference in default config
Related to #1322
2019-07-11 19:46:29 +08:00
Richard Marshall
095333ffb1 Update references to NewEnvForTest 2019-07-10 20:43:50 -07:00
Richard Marshall
0d8d9e2f2b Move plugin EnvForTest manager into new package
Move the EnvForTest manager into an independent package that is not
imported by any non-test code. Previously this code was directly
embedded in the plugins package resulting in testing flags being exposed
in the main kustomize binary.
2019-07-10 17:16:05 -07:00
Kubernetes Prow Robot
9bff2e8883 Merge pull request #1330 from qiujian16/generate-ns-transformer
Generate updated ns transformer
2019-07-10 08:22:28 -07:00
Liu Lan
120ba6b870 docs/versioningPolicy.md: fix expired urls
Signed-off-by: Liu Lan <liulan@umcloud.com>
2019-07-10 11:41:54 +08:00
Jian Qiu
483188ba89 Generate updated ns transformer 2019-07-10 11:07:31 +08:00
Kubernetes Prow Robot
672bda0c9c Merge pull request #1328 from Liujingfang1/cmgenerator
fix the regression on merging configmap with different namespace
2019-07-09 14:22:24 -07:00
jingfangliu
49b32473ca fix the regression on merging configmap with different namespace 2019-07-09 13:39:19 -07:00
Kubernetes Prow Robot
08400d77a6 Merge pull request #1321 from qiujian16/webhook-ns-transform
Enable ns transformer for webhook
2019-07-09 10:08:03 -07:00
Jian Qiu
c912baeb3a Enable ns transformer for webhook
Add namespace transformer for ValidatingWebhookConfiguration
and MutatingWebhookConfiguration
2019-07-09 13:32:33 +08:00
Kubernetes Prow Robot
433733eb0e Merge pull request #1309 from richardmarshall/go_plugin_guide
Fix typo in the go plugin guide
2019-07-08 09:18:35 -07:00
Richard Marshall
f996ac82c7 Fix typo in the go plugin guide 2019-07-03 20:48:07 -07:00
Jeff Regan
efcb7cc5a5 Update README.md 2019-07-03 12:43:17 -07:00
Jeff Regan
bf7b57537b Merge pull request #1306 from monopole/updateV3Notes
Update v3 notes
2019-07-03 12:40:53 -07:00
Jeffrey Regan
6b597f8711 Update v3 notes 2019-07-03 12:40:30 -07:00
Jeff Regan
088739900f Merge pull request #1305 from monopole/tweakDocs
Update goPluginGuidedExample.md
2019-07-03 12:25:21 -07:00
Jeff Regan
3bf13f83d3 Update goPluginGuidedExample.md 2019-07-03 12:24:23 -07:00
Jeff Regan
c64a72f1f9 Update goPluginGuidedExample.md 2019-07-03 11:34:16 -07:00
Jeff Regan
8b60b456ac Update README.md 2019-07-03 11:22:27 -07:00
Jeff Regan
e0bac6ad19 Merge pull request #1302 from mmb/nginx-auth-tls-secret
Add support for nginx.ingress.kubernetes.io/auth-tls-secret
2019-07-03 11:01:14 -07:00
Kubernetes Prow Robot
d841d1bb36 Merge pull request #1270 from sunny0826/master
Chinese localization & fix fields.md
2019-07-03 09:00:35 -07:00
Matthew M. Boedicker
0d87cd6ba1 Add support for nginx.ingress.kubernetes.io/auth-tls-secret 2019-07-02 20:17:16 -07:00
郭旭东
28ad36b02c Merge remote-tracking branch 'upstream/master' 2019-07-03 09:38:44 +08:00
郭旭东
cad8a7bd3f fix zh/fields.md 2019-07-03 09:21:33 +08:00
Jeff Regan
60a990d660 Merge pull request #1297 from arrikto/feature-complex-overlay-composition
Add complex overlay composition test
2019-07-02 13:41:52 -07:00
Kubernetes Prow Robot
cb3751cea6 Merge pull request #1293 from monopole/fix1281
Fix 1281
2019-07-02 09:45:09 -07:00
Ioannis Androulidakis
5ad012e6d9 Add complex overlay composition test
Signed-off-by: Ioannis Androulidakis <ioannis@arrikto.com>
Signed-off-by: Alex Pyrgiotis <apyrgio@arrikto.com>
2019-07-02 19:26:04 +03:00
Jeffrey Regan
8a454de8f9 Fix 1281 2019-07-01 18:09:48 -07:00
Jeff Regan
57b18b7caa Merge pull request #1294 from monopole/repo1281
Add a test combining imagetag and jsonpatch
2019-07-01 18:05:47 -07:00
Jeffrey Regan
701d2c9597 Add a test combining imagetag and jsonpatch 2019-07-01 17:58:46 -07:00
Kubernetes Prow Robot
e7e844bc95 Merge pull request #1291 from monopole/addTest
Add another resmap test.
2019-07-01 11:55:22 -07:00
Jeffrey Regan
0fe95a2f74 Add another resmap test. 2019-07-01 11:17:46 -07:00
Jeff Regan
eb93d8c389 Merge pull request #1289 from monopole/moreTests
Add more json transformer examples.
2019-07-01 09:14:43 -07:00
jregan
8b373ab587 Add more json transformer examples. 2019-07-01 08:52:55 -07:00
Jeff Regan
c352003f3e Merge pull request #1290 from arrikto/feature-diamond-test-harden
Update the diamond composition test case
2019-07-01 08:34:23 -07:00
Alex Pyrgiotis
79d0de7000 Update the diamond composition test case
Refactor the existing base, so that one of the overlays patches an
already present field of the base resource. Previously, all overlays
added a new field in the base deployment, which made this case easier to
solve, with a merge of the produced YAMLs from each overlay.

Also, fix a typo in the comments.

Signed-off-by: Alex Pyrgiotis <apyrgio@arrikto.com>
Signed-off-by: Ioannis Androulidakis <ioannis@arrikto.com>
2019-07-01 14:57:59 +00:00
Jeff Regan
a32d5ce7ab Merge pull request #1288 from monopole/inlineJson
Push json transform code down to plugin.
2019-06-30 17:49:24 -07:00
jregan
5de0673db1 Push json transform code down to plugin. 2019-06-30 17:30:52 -07:00
Jeff Regan
c2b0b6f781 Merge pull request #1286 from monopole/anotherTest
Stacked patching example
2019-06-30 08:58:08 -07:00
jregan
116b37813a stackedOverlays 2019-06-30 08:45:37 -07:00
Jeff Regan
27f0d29734 Merge pull request #1287 from monopole/defineConstants
Define some constants in a test for later reuse.
2019-06-30 08:44:16 -07:00
jregan
f62af4ebf3 Define some constants in a test for later reuse. 2019-06-30 08:42:15 -07:00
Jeff Regan
faa6d0fd0a Merge pull request #1285 from monopole/v1App
Switch Deployment apiVersion to apps/v1 in a couple of tests.
2019-06-30 07:51:53 -07:00
jregan
0554da9d6e Switch to apps/v1 in various tests. 2019-06-30 07:45:29 -07:00
Jeff Regan
fa1fd9fbd7 Merge pull request #1283 from arrikto/feature-diamond-composition-test
Add diamond composition test with multiple patches
2019-06-30 06:56:56 -07:00
Jeff Regan
3dffc30e83 Merge pull request #1280 from sethpollack/generator_metadata
use ObjectMeta
2019-06-30 06:55:52 -07:00
Seth Pollack
2126b6cf23 use ObjectMeta instead of name and namespace fields 2019-06-29 23:30:50 -04:00
Ioannis Androulidakis
2b052fdd55 Add diamond composition test with multiple patches
The purpose of this commit is to demonstrate a composition use case,
that combines multiple overlays that patch the same base resource.

Signed-off-by: Ioannis Androulidakis <ioannis@arrikto.com>
Signed-off-by: Alex Pyrgiotis <apyrgio@arrikto.com>
2019-06-29 22:05:30 +03:00
Jeff Regan
58faa762cb Merge pull request #1275 from Liujingfang1/patches
add function to find all matched patch targets
2019-06-29 09:36:53 -07:00
jingfangliu
349cfff1cb add function to find all matched patch targets 2019-06-28 17:12:02 -07:00
Jeff Regan
558be8b923 Merge pull request #1284 from monopole/objectmeta
Add ObjectMeta type.
2019-06-28 14:56:45 -07:00
Jeffrey Regan
233b3613ae Add ObjectMeta type. 2019-06-28 14:39:56 -07:00
Jeff Regan
615a41d6be Merge pull request #1282 from monopole/repoBug1044
Repo bug 1044
2019-06-28 13:08:39 -07:00
Jeffrey Regan
0ceefcf39d Repo bug 1044 2019-06-28 11:29:48 -07:00
Jeff Regan
16ae64a722 Merge pull request #1279 from monopole/fix972
Fix JSON patch targetting issue.
2019-06-27 17:43:54 -07:00
Jeff Regan
3f239fb4a5 Update bugs.md 2019-06-27 17:40:34 -07:00
Jeffrey Regan
a60d99fdc9 Fix 972 2019-06-27 17:37:12 -07:00
Kubernetes Prow Robot
dd0334536b Merge pull request #1278 from monopole/addDiamondTest
Add diamond base test, improve patching error messages.
2019-06-27 16:53:21 -07:00
Jeffrey Regan
3cef37bdb2 Add diamond base test. 2019-06-27 16:10:58 -07:00
Jeff Regan
ac27e94dff Update README.md 2019-06-27 16:04:15 -07:00
Jeff Regan
0877aa7e0b Merge pull request #1277 from monopole/deleteGetById
Delete deprecated GetById
2019-06-27 15:28:34 -07:00
Jeffrey Regan
07e5a544fe Delete deprecated GetById 2019-06-27 15:26:03 -07:00
Kubernetes Prow Robot
60c04a5f33 Merge pull request #1271 from etiennecoutaud/support_azure_tfs_url
Add suport for _git in git  url
2019-06-27 11:51:22 -07:00
Jeff Regan
b9b9fb1dd2 Merge pull request #1274 from monopole/plainerPluginSecurityDiscussion
Plainer plugin security discussion.
2019-06-27 11:09:08 -07:00
Jeffrey Regan
e1233a0fbc Plainer plugin security discussion. 2019-06-27 11:08:26 -07:00
Etienne Coutaud
cc8203032c Add suport for _git in git url 2019-06-27 11:54:37 +02:00
郭旭东
7117961234 Chinese localization & fix fields.md 2019-06-27 16:52:00 +08:00
Jeff Regan
d410252cf8 Update goPluginCaveats.md 2019-06-26 16:56:46 -07:00
Jeff Regan
4235c57657 Update goPluginCaveats.md 2019-06-26 16:55:33 -07:00
Jeff Regan
e34c1ce192 Merge pull request #1263 from monopole/pluginsDocs
More plugin docs.
2019-06-26 16:38:53 -07:00
Jeffrey Regan
4d399ad89c More plugin docs. 2019-06-26 16:37:26 -07:00
Jeff Regan
9d6ab24388 Merge pull request #1260 from monopole/gomodtidy
A round of go mod tidy.
2019-06-26 13:27:20 -07:00
Jeffrey Regan
ee9f35d451 A round of go mod tidy. 2019-06-26 13:24:40 -07:00
Jeff Regan
45c11ec733 Update README.md 2019-06-26 13:22:22 -07:00
Jeff Regan
0519df4ad5 Merge pull request #1259 from monopole/releasing
Update notes for releasing.
2019-06-26 13:19:03 -07:00
Jeffrey Regan
55585d8da5 Update notes for releasing. 2019-06-26 13:10:41 -07:00
Jeff Regan
b8b49c3124 Merge pull request #1244 from Liujingfang1/patches
add type for extended patches
2019-06-26 11:21:22 -07:00
Jeff Regan
a41471d895 Merge pull request #1254 from monopole/nonnamespace
Fix some minor nits around namespace code.
2019-06-26 10:25:16 -07:00
Jeffrey Regan
877e9ecf64 Fix some minor nits around namespace code. 2019-06-26 10:02:22 -07:00
Kubernetes Prow Robot
150985bb9c Merge pull request #1200 from sunny0826/master
Chinese configGeneration.md dosc
2019-06-26 09:11:16 -07:00
jingfangliu
039f7669df add type for extended patches 2019-06-26 09:01:17 -07:00
Jeff Regan
6caa042b05 Merge pull request #1255 from monopole/fixNits
Fix some random Go nits.
2019-06-25 21:03:38 -07:00
jregan
cc0fffc67b Fix some random Go nits. 2019-06-25 20:46:56 -07:00
郭旭东
50d40ef941 fix zh/configGeneration.md 2019-06-26 09:57:46 +08:00
Jeff Regan
69d40bd740 Merge pull request #1221 from keleustes/mergens
ConfigMap Generators with identical name in different namespaces
2019-06-25 16:31:18 -07:00
Jerome Brette
4272611593 Change key used sort "not namespaceable objects.
- Use "%no_namespace% instead of "cluster-wide"
- Ensure will be no conflict with a kubernetes valid namespace name.
2019-06-25 17:04:55 -05:00
Jerome Brette
74f5e74b89 Consolidate IsClusterKind and IsNamespaceableKind method to avoid duplication 2019-06-25 13:46:49 -05:00
Jerome Brette
2bba0a6aa3 Support for ConfigMap generator with identical names in different namespaces.
- Attempt to account, at build time, for subsequent kubectl apply behavior.
  (empty or no namespace means default).
- Account for the fact that not all objects have a namespace.
- Add new Equal method to ResId address merge name conflict
- Add GroupByName to resources by namespaces to resolve filenames conflict
- Added corresponding unit tests.
- Change the fail test for issue #1155
2019-06-25 13:39:32 -05:00
Jeff Regan
762d3143eb Merge pull request #1242 from taxpon/add-patch-remover
Add patch remover
2019-06-25 09:51:44 -07:00
Jeff Regan
7f22e25dfe Merge pull request #1239 from sethpollack/fix_plugins
allow reuse of plugins
2019-06-25 09:10:05 -07:00
Kubernetes Prow Robot
41c162a65f Merge pull request #1204 from zeusro/master
Chinese translation:jsonpatch.md
2019-06-25 09:02:40 -07:00
Zeusro
ca521946a5 add missing text 2019-06-25 16:50:27 +08:00
Zeusro
b0e53d2b39 Chinese translation:jsonpatch.md 2019-06-25 16:49:41 +08:00
Takuro Wada
5c93722db8 Update pkg structure to avoid circular import 2019-06-25 11:46:01 +09:00
Takuro Wada
d34c82c905 move globPatterns to edit pkg and make it public 2019-06-25 11:21:29 +09:00
Takuro Wada
f11d083b0a Apply goimports 2019-06-25 11:05:56 +09:00
Takuro Wada
f1a5a7703c Update Copyright to shorter one 2019-06-25 11:05:43 +09:00
Seth Pollack
9cc2c90a4b allow reuse of plugins 2019-06-24 21:09:13 -04:00
Jeff Regan
bc31fa9120 Merge pull request #1247 from monopole/updateReleaseNotes
Update versioning policy.
2019-06-24 17:27:44 -07:00
Jeffrey Regan
7a67645558 Update versioning policy. 2019-06-24 17:26:42 -07:00
Jeff Regan
b0f59358d9 Update v3.0.0.md 2019-06-24 16:17:36 -07:00
Jeff Regan
0e6c7d8af7 Update v3.0.0.md 2019-06-24 16:15:54 -07:00
Jeff Regan
9c20085ca9 Update goPluginGuidedExample.md 2019-06-24 15:27:14 -07:00
Jeff Regan
d48a52055a Update goPluginGuidedExample.md 2019-06-24 15:25:03 -07:00
Jeff Regan
dc433e12fb Merge pull request #1246 from monopole/pluginDocGetsOwnDir
Add another detailed plugin example.
2019-06-24 15:21:04 -07:00
Jeffrey Regan
1740ca6a16 Add another detailed plugin example. 2019-06-24 15:19:49 -07:00
Takuro Wada
2ae8ca1d63 Fix help message to align other cmd 2019-06-24 21:28:44 +09:00
Takuro Wada
674cd89ac9 Add patch remover 2019-06-24 21:25:01 +09:00
Takuro Wada
6ed70add4a Add Delete function to patch pkg 2019-06-24 21:14:26 +09:00
Jeff Regan
ae5ebccec7 Merge pull request #1241 from monopole/hackPluginTesting
Hack for local testing of isolated plugins.
2019-06-23 18:05:23 -07:00
jregan
19c8e23425 Hack for local testing of isolated plugins. 2019-06-23 18:04:20 -07:00
Jeff Regan
b878cd050d Merge pull request #1240 from monopole/v3
Starting v3 release for plugin developers.
2019-06-23 15:18:18 -07:00
jregan
a7df00c07a Starting v3 release for plugin developers.
[doc]: https://github.com/golang/go/wiki/Modules#releasing-modules-v2-or-higher

Per this Go modules [doc] a repo or branch that's
already tagged v2 or higher should increment the major
version (e.g. go to v3) when releasing their first Go
module-based packages.

At the moment, the kustomize repo has these top level
packages in the sigs.k8s.io/kustomize module:

 - `cmd` - holds main program for kustomize

	 Conceivably someone can depend on this
	 package for integration tests.

 - `internal` - intentionally unreleased subpackages

 - `k8sdeps` - an adapter wrapping k8s dependencies

	 This exists only for use in pre-Go-modules kustomize-into-kubectl
	 integration and won't live much longer (as everything involved is
	 switching to Go modules).

 - `pkg` - kustomize packages for export

	 This should shrink in later versions, since
	 the surface area is too large, containing
	 sub-packages that should be in 'internal'.

 - `plugin` - holds main programs for plugins

This PR changes the top level go.mod file from

```
module sigs.k8s.io/kustomize
```

to

```
module sigs.k8s.io/kustomize/v3
```

and adjusts all import statements to
reflect the change.
2019-06-23 15:05:59 -07:00
Jeff Regan
3127f1adc6 Merge pull request #1238 from monopole/removeSopsEncodedSecretsPlugin
Remove SopsEncodedSecretsPlugin
2019-06-23 10:02:15 -07:00
jregan
a722cca80a Remove SopsEncodedSecretsPlugin 2019-06-23 09:46:45 -07:00
Jeff Regan
0ffd78eab6 Merge pull request #1224 from keleustes/varset
Change the backing data structure of VarSet from slice to map
2019-06-23 09:03:48 -07:00
Jeff Regan
694c868048 Merge pull request #1231 from arnodel/fix-1228
Iterate over fieldspecs for name tranformations (fixes #1228)
2019-06-23 09:02:54 -07:00
Jeff Regan
2da2006e2a Merge pull request #1237 from taxpon/add-metadata-remover
Add metadata remover
2019-06-23 08:56:03 -07:00
Jeff Regan
0bc83ca065 Merge pull request #1227 from leoxiongdev/patch-1
Fix typo
2019-06-23 08:36:08 -07:00
Takuro Wada
ab2643ef14 Fix FakeValidator 2019-06-23 19:59:01 +09:00
Takuro Wada
297812ec11 Fix lint 2019-06-23 19:43:49 +09:00
Takuro Wada
158f754f18 Add remove annotation command 2019-06-23 18:43:52 +09:00
Takuro Wada
da3504105e Add remove label command 2019-06-23 18:43:52 +09:00
Arnaud Delobelle
d3f50695b4 Fix configmap name in test 2019-06-22 08:46:22 +01:00
Arnaud Delobelle
5a9a6ab0f6 Fix typo in test 2019-06-22 08:27:23 +01:00
Arnaud Delobelle
b86e78b7a9 Add test for regression 2019-06-22 08:09:39 +01:00
Ian Howell
b1cdf581d0 Change the backing data structure of VarSet from slice to map
This will speed up most operations performed on a large set of Vars
2019-06-21 17:28:57 -05:00
Jeff Regan
8bf20527be Merge pull request #1232 from monopole/moreVarTestCoverage
More var test coverage.
2019-06-21 14:14:53 -07:00
Jeffrey Regan
3eedc40595 More var test coverage. 2019-06-21 13:53:58 -07:00
Arnaud Delobelle
93db0ef3e9 Iterate over fieldspecs for name tranformations 2019-06-21 21:08:59 +01:00
Jeff Regan
6922dbbc70 Merge pull request #1225 from keleustes/fix/compiler
Fixed unit test failures when GOROOT was unset
2019-06-21 09:52:39 -07:00
Jeff Regan
f1b9b27a15 Merge pull request #1220 from keleustes/downwardapi
FieldPath syntax backward compatibility
2019-06-21 09:36:52 -07:00
Leo Xiong
a755558beb Fix typo 2019-06-21 12:29:31 +12:00
Ian Howell
b8423d0f5f Fixed unit test failures when GOROOT was unset 2019-06-20 16:37:20 -05:00
Jeff Regan
42ef4fbcc1 Merge pull request #1222 from monopole/linuxIn30
Another plugin demo.
2019-06-20 11:47:34 -07:00
Jeffrey Regan
69c11780eb Another plugin demo. 2019-06-20 11:45:26 -07:00
Jerome Brette
c925b43090 FieldSpec Backward Compatibility with K8s Downward API 2019-06-20 09:22:47 -05:00
Kubernetes Prow Robot
a5b97cbd9b Merge pull request #1214 from monopole/sops
A secret generator using sops.
2019-06-19 19:50:48 -07:00
Jeffrey Regan
bcb844663f A secret generator using sops. 2019-06-19 18:55:50 -07:00
Jeff Regan
0905ee293c Merge pull request #1213 from monopole/commitGenerated
Commit generated code for image and namespace transformers.
2019-06-19 18:53:02 -07:00
Jeffrey Regan
3325852aab Commit generated code for image and namespace transformers. 2019-06-19 18:52:24 -07:00
Jeff Regan
c437d99c5f Merge pull request #1210 from monopole/pushTagTransformCodeToPlugin
Push image tag transform code to plugin.
2019-06-19 18:26:31 -07:00
Jeff Regan
cacafc63e8 Merge pull request #1211 from monopole/pushNamespaceTransformerCodeToPlugin
Push namespace transformer code to plugin.
2019-06-19 18:26:05 -07:00
Jeff Regan
b08f3383b8 Merge pull request #1206 from jbrette/namespace
Addresses issue discovered in attempting to patch K8s objects across different namespaces.
2019-06-19 13:07:50 -07:00
Jeffrey Regan
2eccf67b1c Push namespace transformer code to plugin. 2019-06-19 12:57:02 -07:00
Kubernetes Prow Robot
293c8bef54 Merge pull request #1202 from mamoit/patch-1
Typo correction in 2.1.0 release notes
2019-06-19 12:38:19 -07:00
Kubernetes Prow Robot
00c7ae0542 Merge pull request #1199 from ramnar/master
Corrected spelling mistake
2019-06-19 12:36:21 -07:00
Jeffrey Regan
cd656faadf Push image tag transform code to plugin. 2019-06-19 12:24:00 -07:00
Kubernetes Prow Robot
056b95ffa9 Merge pull request #1201 from yujunz/fix-typo
Fix typo in docs
2019-06-19 11:28:34 -07:00
Kubernetes Prow Robot
d211df1e73 Merge pull request #1205 from pyaillet/fix-typo
Fix typo in comment
2019-06-19 08:56:36 -07:00
Jerome Brette
934e036b99 Attempting to patch K8s objects across different namespaces.
- Return an error when findTarget fails.
- Add unit test testing the change.
2019-06-19 08:42:12 -05:00
Zeusro
9fc86f92fa Chinese translation:jsonpatch.md 2019-06-19 21:16:40 +08:00
Pierre-Yves Aillet
49c6bd4141 Fix typo in comment 2019-06-19 14:53:29 +02:00
Miguel Almeida
24011cf2a5 Simple flag typo correction
The flag is load_restrictor and not load_restrictions.
2019-06-19 11:35:33 +01:00
郭旭东
83b284dfde fix configGeneration.md 2019-06-19 17:21:07 +08:00
Yujun Zhang
7c9181317f Fix typo in docs 2019-06-19 15:09:31 +08:00
郭旭东
01b410fe9c Chinese configGeneration.md dosc 2019-06-19 14:36:21 +08:00
ramnar
56ac98468d Corrected spelling mistake
Corrected spelling mistake
2019-06-19 08:22:55 +05:30
Jeff Regan
658ebeaa21 Merge pull request #1197 from keleustes/showcasevariables
Demonstrate new capabilities in pkg/target testing
2019-06-18 19:22:27 -07:00
Jeff Regan
59aa898533 Merge pull request #1198 from sunny0826/master
update docs/zh/README.md
2019-06-18 19:21:37 -07:00
Jeff Regan
c88f87cee2 Merge pull request #1196 from keleustes/helperimprovment
Improve robutness of helper code
2019-06-18 18:59:15 -07:00
郭旭东
cc663bb08c update docs/zh/README.md 2019-06-19 09:26:44 +08:00
Jeff Regan
63d647df18 Update secretGeneratorPlugin.md 2019-06-18 16:50:48 -07:00
Jerome Brette
e3a46cb6ce Leverage new variables during testing
Extract the HTTP port (int) from the container section end
use it in the service definition.

Also enable variable replacement for Service object.
2019-06-18 18:37:20 -05:00
Jerome Brette
4556eb3a0c Improve robutness of helper code
As per request, changed usage of pointer to int into plain int.
Use -1 value where nil use to be used.
2019-06-18 18:06:38 -05:00
Jeff Regan
26ed9b7c58 Fix date of release v2.1.0 2019-06-18 15:30:37 -07:00
Jeff Regan
8ff0b5423d Update v2.1.0.md 2019-06-18 15:27:27 -07:00
Jeff Regan
0fbced95a8 Merge pull request #1195 from monopole/updateReleaseLinks
Update release note links.
2019-06-18 15:25:09 -07:00
Jeffrey Regan
66b816aabc Update release note links. 2019-06-18 15:24:10 -07:00
Jeff Regan
af67c893d8 Merge pull request #1194 from monopole/moveKustomizeToCmd
Move kustomize main to cmd directory.
2019-06-18 14:40:09 -07:00
Jeff Regan
71f44d646f Update v_2.1.0.md 2019-06-18 14:39:46 -07:00
Jeff Regan
9edecffcc8 Update v_2.1.0.md 2019-06-18 14:25:47 -07:00
Jeffrey Regan
d2c93065d5 Move kustomize main to cmd directory. 2019-06-18 14:17:51 -07:00
Jeff Regan
7dd02c1766 Merge pull request #1111 from keleustes/master
Improvment var and varRefs handling
2019-06-18 14:17:27 -07:00
Jeff Regan
93a97950e7 Merge pull request #1193 from monopole/moarMods
More release note tweaks.
2019-06-18 13:34:34 -07:00
Jeffrey Regan
f17698a8ea More release note tweaks. 2019-06-18 13:33:56 -07:00
Kubernetes Prow Robot
2cb9f81bab Merge pull request #1189 from monopole/deprecateBasesField
Deprecate 'bases:' field.
2019-06-18 13:23:51 -07:00
Ian Howell
ed03818e20 This commit enhances the UnstructAdapter
* Added support for arbitrary data types rather than just strings
* Added support for integer index-able arrays
* Improve code coverage for kunstruct
  - kunstruct around 90%
  - helper at 100%
* Update expansion.Expand method to preserve the original type of the variable
* Ensure the int field such .spec.replicas can be used
  as a source in a first Deployment or as destination of a variable (in the
  second Deployment variable).
2019-06-18 13:43:01 -05:00
Jeffrey Regan
cc531af665 Deprecate 'bases:' field. 2019-06-18 10:36:58 -07:00
Jeff Regan
0dbe78149d Merge pull request #1192 from monopole/movePluginator
Move pluginator main.go from plugin to cmd directory.
2019-06-18 10:36:25 -07:00
Jeffrey Regan
4bc31f4b2a Move pluginator to cmd directory. 2019-06-18 10:16:46 -07:00
Jeff Regan
a5253adb9c Merge pull request #1187 from rvodden/master
Added test to verify usage of multiline strip chomp in configMapGener…
2019-06-18 09:54:47 -07:00
Jeff Regan
ae3700a193 Merge pull request #1191 from monopole/homebrewUpdate
Tell homebrew to update.
2019-06-18 09:53:15 -07:00
Jeffrey Regan
a56604154d Tell homebrew to update. 2019-06-18 09:39:40 -07:00
Richard Vodden
000f81b21c Added test to verify usage of multiline strip chomp in configMapGenerator 2019-06-18 17:19:11 +01:00
Jeff Regan
a9583fc6ec Merge pull request #1188 from monopole/fixTest
Fix test broken by the change in ordering.
2019-06-18 07:49:26 -07:00
Jeffrey Regan
57eecd7497 Fix test broken by the change in ordering. 2019-06-18 07:30:29 -07:00
Jeff Regan
6803cc4788 Merge pull request #1186 from monopole/moveWindowsPrecommit
Put windows test script next to pre-commit.sh
2019-06-17 16:30:11 -07:00
Jeffrey Regan
2796e54540 Put windows test script next to pre-commit.sh 2019-06-17 16:29:40 -07:00
Jeff Regan
06c23b7742 Merge pull request #852 from kenmaglio/windows-precommit
Windows Tests - Precommit Script
2019-06-17 16:26:28 -07:00
Jeff Regan
7ce6181bce Merge pull request #610 from twz123/transformer-no-create-arrays
Proposal: Make transformer configs array-aware
2019-06-17 16:22:09 -07:00
Jeff Regan
ec31bcbe62 Merge pull request #1185 from monopole/unsort
Expected raw kustomize ordering in tests.
2019-06-17 16:15:28 -07:00
Jeffrey Regan
0b555e1b2c Modify tests to present expected data in unsorted order.
Modify all `build` tests to use the raw,
non-sorted output of build.  This makes every test
provide coverage for how kustomize re-orders (or
doesn't reorder) resources during processing.

Going forward, the ordering of resources in
_expected_ output should match the depth-first
ordering specified in the `resources:` field used
in the test's kustomization file.

The only exception to this rule would be tests
that actually confirmed some other output
ordering, e.g. the test of the
`LegacyOrderTransformer` plugin.

Fixes #756
Related #821
2019-06-17 16:02:23 -07:00
Jeff Regan
ed21e77fb1 Merge pull request #1181 from damienr74/fix-replica-transformer
Make the replica transformer `kind` aware.
2019-06-17 12:37:39 -07:00
Damien Robichaud
3f8b1fe05b Make the replica transformer kind aware.
The previous implementation had a bug and poorly handled
types that should not have a `spec: replica:` field.

Documentation is updated to reflect the change in behavior,
and better highlights the cases where a patch should be
used instead of this shorthand.
2019-06-17 11:41:43 -07:00
Damien Robichaud
8d4b6452d4 Make the replica transformer kind aware.
The previous implementation had a bug and poorly handled
types that should not have a `spec: replica:` field.

Documentation is updated to reflect the change in behavior,
and better highlights the cases where a patch should be
used instead of this shorthand.
2019-06-17 11:33:31 -07:00
Jeff Regan
05e3dead7b Merge pull request #1183 from monopole/maintainOrder
Simplify code base.
2019-06-17 10:59:44 -07:00
Jeffrey Regan
3a01a63a01 Simplify code base.
- In ResMap, drop concept of internal Id to Resource
   map.  The ResMap is now (just) a list, allowing only
   very particular edits.

 - Resources should now be maintained in the order
   loaded.  A later PR can adjust tests to remove the
   internal legacy sorting, and confirm order-out is
   predictable from order-in.  The PR would suppress
   the sort in tests, and reorder the output to make
   all tests pass again, and confirm that the new order
   matched depth-first input traversal.  The FromMap
   fixture function was removed from all test inputs to
   establish a predictable input order.

 - Resources now have two 'Ids', OriginalId and
   CurrentId.  The former is fixed as
   GVK-name-namespace at load time, the latter changes
   during transformations.  The latter can be used to
   narrow name references when the former maps to
   multiple resources.  We allow bases to be loaded
   more than once in a build (a diamond pattern), so
   the OriginalId is not unique across the resources
   set.  The CurrentId is (and must be) unique, but is
   constantly mutating.  Failing to make this
   distinction clear, and attempting to maintain a
   mapping from a single mutating Id to a resource was
   making the code too complex.

 - Drop prefix/suffix from ResId - the ResId is now
   immutable.  A later PR can remove the distinction
   with ItemId.

 - This PR increases coverage of ResMap is since this
   is a large refactor.  Higher level tests didn't need
   much change outside reordering of results at the
   resource level.
2019-06-17 10:50:45 -07:00
Jeff Regan
624aa5290e Merge pull request #1180 from monopole/justTheTestRefactor
Move the rmBuilder test helper to a test package.
2019-06-13 16:23:49 -07:00
Jeffrey Regan
8d9897d5a5 Add the rmBuilder test helper. 2019-06-13 16:15:43 -07:00
Jeff Regan
16a9975e84 Merge pull request #1175 from monopole/errorIfNotEqualLists
Add some utilities.
2019-06-12 20:51:01 -07:00
jregan
755dd3d024 Add some utilities. 2019-06-12 20:43:39 -07:00
Jeff Regan
ba49fd4c18 Merge pull request #1178 from monopole/goLinterUpdate
Update golinter to 1.17.1
2019-06-12 20:40:41 -07:00
jregan
08b6f6f4e4 Update golinter to 1.17.1 2019-06-12 20:33:07 -07:00
Jeff Regan
3128b25236 Merge pull request #1174 from monopole/addOriginalNameToResource
Add originalName field to resource.
2019-06-12 16:43:28 -07:00
Jeffrey Regan
5e054c9d31 Add originalName field to resource. 2019-06-12 16:30:03 -07:00
Jeff Regan
4bb4a85037 Merge pull request #1149 from qiujian16/var-reference
Keep var refernce in resources
2019-06-12 09:50:06 -07:00
Jeff Regan
b24d813f0f Merge pull request #1173 from monopole/prefixSuffixPlugin
Push suffix/prefix code to plugin.
2019-06-11 20:46:28 -07:00
Jian Qiu
7e12918f75 Keep var refernce in resources 2019-06-12 10:51:19 +08:00
jregan
11bb176a3f Push suffix/prefix code to plugin. 2019-06-11 19:37:06 -07:00
Jeff Regan
fcc3082231 Merge pull request #1172 from monopole/renamePrefixSuffixTransformer
Rename the prefix/suffix transformer.
2019-06-11 17:57:15 -07:00
jregan
49d94f5318 Rename the prefix/suffix transformer. 2019-06-11 17:47:23 -07:00
Kubernetes Prow Robot
fa23026b80 Merge pull request #1171 from monopole/addReorderFlag
Add --reorder flag.
2019-06-11 13:26:19 -07:00
Jeffrey Regan
0fa2d9c32c Add --reorder flag. 2019-06-11 12:52:53 -07:00
Kubernetes Prow Robot
15a77fd2bb Merge pull request #1169 from monopole/improveNameTransformComments
Improve performance in name transform code.
2019-06-10 17:10:15 -07:00
Jeffrey Regan
9c36ac28fa Improve comments in name transform code. 2019-06-10 16:58:16 -07:00
Kubernetes Prow Robot
e1e622d985 Merge pull request #1165 from monopole/hoser
Add test for ordered transformers.
2019-06-07 18:09:06 -07:00
Jeff Regan
3e86ebc3cf Merge pull request #1166 from monopole/cover1155WithTest
Cover #1155 with a test.
2019-06-07 16:28:42 -07:00
Jeffrey Regan
6d309b52a5 Introduce stacked transformers. 2019-06-07 16:16:58 -07:00
Jeffrey Regan
52faa01ecf Cover #1155 with a test. 2019-06-07 16:11:54 -07:00
Kubernetes Prow Robot
a79c888e0c Merge pull request #1163 from monopole/sortingPlugin
Add a sorting plugin, as an example.
2019-06-07 15:42:00 -07:00
Jeffrey Regan
449175e3a6 Add a sorting plugin. 2019-06-07 15:06:12 -07:00
Jeff Regan
2fce1a6d25 Merge pull request #1162 from monopole/addMergeMethodToVarSet
Add Merge (one Var) method to VarSet
2019-06-07 13:55:34 -07:00
Jeffrey Regan
798b61c8ef Add copy method to VarSet 2019-06-07 13:22:07 -07:00
Kubernetes Prow Robot
84efd367d2 Merge pull request #1161 from monopole/addCopyToVarSet
Add copy method to VarSet
2019-06-07 13:13:59 -07:00
Jeffrey Regan
d9b0c4c84c Add copy method to VarSet 2019-06-07 13:01:34 -07:00
Kubernetes Prow Robot
c9300edead Merge pull request #1160 from matti/patch-1
Update inventory_object.md
2019-06-07 07:36:04 -07:00
Matti Paksula
4502e8fffb Update inventory_object.md 2019-06-07 17:00:43 +03:00
Jeff Regan
51d82bece3 Merge pull request #1159 from monopole/minorRenames
Rename ErrorIfNotEqual to ErrorIfNotEqualSets
2019-06-06 20:29:52 -07:00
jregan
0e4f9acb6e Rename ErrorIfNotEqual to ErrorIfNotEqualSets 2019-06-06 20:20:48 -07:00
Jeff Regan
aa2d8b20cd Merge pull request #1158 from monopole/hoohah
Preserve order when merging.
2019-06-06 20:14:54 -07:00
Jeffrey Regan
c63ebbdfc4 Preserve order when merging. 2019-06-06 20:01:39 -07:00
Kubernetes Prow Robot
c094780aae Merge pull request #1154 from monopole/maintainResourcesInLoadOrder
Maintain resources in a list.
2019-06-06 16:19:59 -07:00
Jeffrey Regan
4162dbc2d8 Maintain resources in order loaded. 2019-06-06 15:55:57 -07:00
Jingfang Liu
c250f75d1d enable go module in the integration test (#1153) 2019-06-06 09:35:25 -07:00
Kubernetes Prow Robot
af57fc3ece Merge pull request #1152 from Liujingfang1/patchfix
fix the bug for patching CRDs
2019-06-04 11:53:54 -07:00
Kubernetes Prow Robot
985abd1456 Merge pull request #1148 from Liujingfang1/examples
update examples/README.md
2019-06-04 11:27:54 -07:00
jingfangliu
0375137296 fix the bug for patching CRDs 2019-06-04 10:20:24 -07:00
jingfangliu
e4956c5500 update examples/README.md 2019-06-03 16:09:18 -07:00
Jeff Regan
53377cdddc Merge pull request #1145 from monopole/invTransformerPlugin
Convert inventory transformer to plugin, reduce k8sdeps.
2019-06-02 11:01:05 -07:00
Jeffrey Regan
81c98c855f Convert inventory transformer to plugin, reduce k8sdeps. 2019-06-02 10:49:01 -07:00
Jeff Regan
115a0bc560 Merge pull request #1144 from monopole/invField
Add entry for inventory in fields.md
2019-05-31 13:56:46 -07:00
Jeffrey Regan
2744e058b6 Add entry for inventory in fields.md 2019-05-31 13:55:23 -07:00
Jeff Regan
b6139f74de Merge pull request #1139 from damienr74/implement-replica-transform
Implement replica transformer as patch alternative
2019-05-31 13:43:59 -07:00
Damien Robichaud
d925939795 Add documentation for the replicas transform 2019-05-31 13:29:04 -07:00
Damien Robichaud
d4842ebd90 Cleanup the replica plugin implementation. 2019-05-31 13:28:51 -07:00
Damien Robichaud
5000a2e503 Implement replica transformer as patch alternative 2019-05-31 13:10:34 -07:00
Jeff Regan
109988d105 Merge pull request #797 from cartyc/update-docs
Translated kustomization.yaml into markdown in fields.md.
2019-05-31 12:17:30 -07:00
Chris Carty
b07bea40f7 added field tables 2019-05-31 12:14:58 -07:00
Chris Carty
e287f615f4 readded kustomization.yaml 2019-05-31 11:11:34 -07:00
Chris Carty
d2103dbf39 updated grouping and added brief descriptions of sections 2019-05-31 11:11:01 -07:00
Chris Carty
7a54d998d4 added links to section headings 2019-05-31 11:11:01 -07:00
Chris Carty
3168b2a1ed added link to examples 2019-05-31 11:09:54 -07:00
Chris Carty
e0d2fa5701 Translated kustomization.yaml into markdown in fields.md. Updated links to point to fields.md 2019-05-31 11:09:54 -07:00
Kubernetes Prow Robot
4b4c799129 Merge pull request #1143 from Liujingfang1/plugindoc
update validation transformer example text
2019-05-31 10:42:30 -07:00
jingfangliu
b2c8752211 update validation transformer example text 2019-05-31 09:58:48 -07:00
Kubernetes Prow Robot
4e9436eb80 Merge pull request #1116 from Liujingfang1/plugindoc
add example for transformer plugin
2019-05-31 09:32:30 -07:00
Ken Maglio
8c133ef048 Removes mdrip testing for Windows 2019-05-30 23:30:19 -05:00
jingfangliu
142879ec30 add example for transformer plugin 2019-05-30 17:08:12 -07:00
Kubernetes Prow Robot
c4f79eff51 Merge pull request #1141 from monopole/releaseNotes
Update 2.1 release notes.
2019-05-30 17:02:23 -07:00
jregan
1dd448e65c Update 2.1 release notes before release. 2019-05-30 15:33:30 -07:00
Jeff Regan
ab3fed06c7 Merge pull request #1112 from Liujingfang1/validator
add validation transformer
2019-05-30 13:38:18 -07:00
Jingfang Liu
b4dbac1b84 add validation transformer 2019-05-30 10:10:16 -07:00
Jeffrey Regan
e1b59c93de 2.1 release notes 2019-05-29 16:58:34 -07:00
Kubernetes Prow Robot
0adfd2751e Merge pull request #1137 from monopole/hashTransformerOutOfk8sdeps
Move hashing transformer out of k8sdeps.
2019-05-29 14:08:20 -07:00
Jeffrey Regan
fd2248e7c2 Move hashing transformer out of k8sdeps. 2019-05-29 13:51:41 -07:00
Jeff Regan
dd75392d98 Merge pull request #1136 from monopole/updateReleaseForGoModules
Use go modules in cloud builder.
2019-05-29 11:31:33 -07:00
Jeffrey Regan
af2b101fe2 Use go modules in cloud builder. 2019-05-29 11:21:40 -07:00
Kubernetes Prow Robot
62cef3de98 Merge pull request #1117 from sunny0826/master
chinese helloworld doc
2019-05-29 10:52:27 -07:00
Tom Wieczorek
03e518f0ea Merge branch 'master' into transformer-no-create-arrays 2019-05-29 12:18:59 +02:00
郭旭东
7765bdd967 fix some doc 2019-05-29 15:22:41 +08:00
郭旭东
cd19d4262b Merge remote-tracking branch 'upstream/master' 2019-05-29 14:08:40 +08:00
Jeff Regan
4812ddff9f Merge pull request #1134 from monopole/renameBinToTravis
Rename ./bin dir to ./travis.
2019-05-28 22:05:26 -07:00
Jeff Regan
df52b51f67 Merge pull request #1133 from monopole/hasher
Move basic hashing code out of k8sdeps.
2019-05-28 21:57:43 -07:00
jregan
a2e4f6cf68 Rename ./bin dir to ./travis. 2019-05-28 21:56:59 -07:00
jregan
ee728d58f5 Move hashing code out of k8sdeps. 2019-05-28 21:46:46 -07:00
Jeff Regan
6be6ade6d7 Merge pull request #1131 from monopole/updateMinecraft
Update minecraft version in example.
2019-05-28 18:40:13 -07:00
Jeff Regan
d4305ab9da Merge pull request #1130 from monopole/envToEnvs
Fix yaml in generator examples.
2019-05-28 18:34:14 -07:00
Jeffrey Regan
ca478016c9 Update minecraft version in example. 2019-05-28 18:32:23 -07:00
Jeffrey Regan
a7a2589e81 Fix yaml in generator examples. 2019-05-28 18:21:07 -07:00
Jeff Regan
02e4f7305d Merge pull request #1120 from wlezzar/fix-commonLabels-spec
Fix commonLabels spec for volumeClaimTemplates
2019-05-28 17:53:18 -07:00
Jeff Regan
f777ba8aa9 Merge pull request #1129 from monopole/idiomFixes
Idiom fixes.
2019-05-28 17:48:55 -07:00
Jeff Regan
7e9eaf41c9 Merge pull request #1128 from monopole/localBuild
Add script to run cloud build 'locally'.
2019-05-28 17:26:22 -07:00
Jeff Regan
bb9b3163ee Add script to run cloud build 'locally'. 2019-05-28 17:09:06 -07:00
wlezzar
e6d1de0d72 fix commonLabels spec for volumeClaimTemplates 2019-05-28 22:27:28 +02:00
Jeff Regan
e2a660c787 Merge pull request #1123 from qiujian16/webhook-reference
Add Webhookconfiguration in default name references
2019-05-28 09:53:17 -07:00
Tom Wieczorek
c9a5c03eaa Convert legacy file based test to in-memory 2019-05-28 11:27:21 +02:00
Tom Wieczorek
c2eda0a172 Merge branch 'master' into transformer-no-create-arrays 2019-05-28 11:27:04 +02:00
Tom Wieczorek
c470982ce5 Make transformer configs array-aware
If path segments end with the special marker `[]` in transformer configs, this
indicates that the respective path segment is supposed to be an array. That
information may be used to suppress the meaningless creation of non-existent
paths that should be arrays, not objects.
2019-05-28 11:26:33 +02:00
Jian Qiu
68f6b0be6e Add Webhookconfiguration in default name references 2019-05-28 14:02:32 +08:00
jregan
02f379536c Idiom fixes.
- func/struct names prefixed with package name
- public funcs/structs that should be private
2019-05-27 17:54:44 -07:00
Jeff Regan
e239d5f909 Merge pull request #1121 from monopole/lessK8sdeps
Move 400loc from k8sdeps to loader
2019-05-27 15:56:27 -07:00
jregan
47c965481f Reduce k8ds deps 2019-05-27 15:37:03 -07:00
Jeff Regan
3af0f9776f Merge pull request #1118 from monopole/deleteKvPluginCode
Delete the KV plugin code.
2019-05-25 19:29:55 -07:00
Jeff Regan
c116a28e67 Merge pull request #1109 from nzoueidi/907
Add support for escaping characters in Doc
2019-05-24 18:55:20 -07:00
Jeffrey Regan
6a10654618 Delete the KV plugin code. 2019-05-24 16:49:16 -07:00
Kubernetes Prow Robot
a42b0bd574 Merge pull request #1115 from Liujingfang1/examples
reorganize the examples layout
2019-05-24 10:47:28 -07:00
郭旭东
404884e295 chinese helloworld doc 2019-05-24 13:31:11 +08:00
Jingfang Liu
e17d303392 reorganize the examples layout 2019-05-23 13:50:30 -07:00
Jeff Regan
e4205c125c Merge pull request #1104 from mgoltzsche/master
Order ValidatingWebhookConfig last.
2019-05-23 09:43:22 -07:00
Kubernetes Prow Robot
fdee15e523 Merge pull request #1093 from sunny0826/master
translate example list
2019-05-23 07:28:30 -07:00
Naeil ZOUEIDI
c9d903cc36 Add support for escaping characters in Doc 2019-05-23 04:56:03 -04:00
Jeff Regan
e5a0a12ffd Merge pull request #1105 from monopole/updatePluginDocs
Rewrite plugin docs.
2019-05-22 21:27:10 -07:00
jregan
78cdff6d09 Remove kv plugins from docs. 2019-05-22 21:13:45 -07:00
郭旭东
a64baed428 fix link 2019-05-23 09:38:16 +08:00
Kubernetes Prow Robot
d8f3bffe63 Merge pull request #1103 from monopole/testAllThePlugins
Test all the plugins.
2019-05-22 16:38:24 -07:00
Max Goltzsche
a09b42b364 Order ValidatingWebhookConfig last.
Fixes the cert-manager example of #821.
2019-05-23 00:48:01 +02:00
jregan
fe67bcdb8b Cut more ties to k8sdeps
Add tests for all the plugins.
2019-05-22 14:17:36 -07:00
Jeff Regan
7dc1eae40f Merge pull request #1102 from monopole/refactorFactory
bye bye baseFactory
2019-05-22 14:10:44 -07:00
jregan
e13896496e Cut more ties to k8sdeps 2019-05-22 14:03:30 -07:00
Jeff Regan
f864c912ad Merge pull request #1101 from monopole/breakDeps
Break a bad dep.
2019-05-22 07:48:51 -07:00
Jeffrey Regan
b28aaae66b Break a bad dep. 2019-05-22 07:39:36 -07:00
Jeff Regan
fb872be04a Merge pull request #1099 from qiujian16/add-storageclass-nameref
Add name reference of storageClass
2019-05-22 07:34:59 -07:00
Jian Qiu
8f413f523c Add name reference of storageClass 2019-05-22 14:43:15 +08:00
郭旭东
89243aed37 add zh dir 2019-05-22 09:40:41 +08:00
Kubernetes Prow Robot
f212deab4d Merge pull request #1097 from monopole/namespaceTransformer
Add builtin namespace transformer plugin
2019-05-21 15:56:05 -07:00
Jeffrey Regan
79906d73d0 Add builtin namespace transformer plugin 2019-05-21 13:56:36 -07:00
Jeff Regan
d4e3cd31a4 Merge pull request #1096 from monopole/kusttargetCleanup
Cleanup kusttarget.
2019-05-21 11:41:40 -07:00
Jeffrey Regan
f621543d9c Cleanup kusttarget. 2019-05-21 11:40:23 -07:00
Kubernetes Prow Robot
e801b3a75d Merge pull request #1090 from monopole/prune
replace ambiguous parameters regarding prune
2019-05-21 11:40:08 -07:00
Jeff Regan
5f93266e2c Merge pull request #1095 from monopole/formatGeneratedCode
Format generated code.
2019-05-21 11:37:38 -07:00
Jeffrey Regan
9b6f8f0c74 Format generated code. 2019-05-21 11:35:41 -07:00
jregan
a352ff3923 True and false are mysterious. 2019-05-21 10:58:43 -07:00
Kubernetes Prow Robot
812ae77257 Merge pull request #1091 from qiujian16/fix-1017
Allow nil label and annotaion
2019-05-21 09:02:52 -07:00
郭旭东
b4efc833c7 translate example list 2019-05-21 15:26:49 +08:00
Jian Qiu
5e33ac4a09 Allow nil label and annotaion
This fix is to allow value of lable or annoation to be nil
2019-05-21 13:55:19 +08:00
Jeff Regan
72f565d55d Merge pull request #1089 from monopole/tinyFixNits
Fix some nits.
2019-05-20 20:17:29 -07:00
jregan
b92ee25696 Fix some nits. 2019-05-20 19:56:07 -07:00
Jeff Regan
a2d4423630 Merge pull request #1037 from jnewland/patch-2
Apply LimitRange resources before workloads
2019-05-20 18:27:15 -07:00
Kubernetes Prow Robot
897d434673 Merge pull request #1088 from monopole/jsonPatchTransformer
Add builtin JSON patch transformer
2019-05-20 16:18:39 -07:00
Jeffrey Regan
0df5883853 Add builtin JSON patch transformer 2019-05-20 15:38:46 -07:00
Kubernetes Prow Robot
84c5e44345 Merge pull request #1087 from monopole/addAnnotationTransformer
Add builtin annotation transformer.
2019-05-20 09:27:16 -07:00
jregan
aafc23a615 Add annotation transformer. 2019-05-19 19:04:29 -07:00
Jeff Regan
49bd56d012 Merge pull request #1086 from monopole/addLabelTransformer
Add builtin label transformer plugin.
2019-05-19 18:30:10 -07:00
jregan
45901219b7 Add builtin label transformer. 2019-05-19 18:20:18 -07:00
Jeff Regan
6ba6f305cc Merge pull request #1085 from monopole/onePluginPerDir
One plugin per dir.
2019-05-19 17:52:01 -07:00
jregan
5653ae69e4 One plugin per dir. 2019-05-19 17:32:02 -07:00
Jeff Regan
31534fe47d Merge pull request #1084 from monopole/simplifyPluginTesting
Simplifications to the plugin test code.
2019-05-18 12:02:15 -07:00
Jeffrey Regan
3a85fcd365 Simplify some of the plugin testing code. 2019-05-17 16:13:55 -07:00
Kubernetes Prow Robot
f9c631e9ee Merge pull request #1079 from monopole/nameTransformer
Add builtin NameTransformer plugin.
2019-05-16 13:32:29 -07:00
Jeffrey Regan
621bb7c6c5 Add builtin NameTransformer plugin. 2019-05-16 12:34:08 -07:00
Kubernetes Prow Robot
9590eaf342 Merge pull request #1075 from monopole/pluginDogfooding
Dogfood the plugin framework.
2019-05-16 11:26:30 -07:00
Jeffrey Regan
939de0cdbe Dogfood the plugin framework.
This PR:

* provides a code generator that converts
  kustomize Go plugins to normal code, i.e.
  the plugin appears as
    t := builtin.NewImageTagTransformer()
  instead of
    p := plugin.Open("imagetagtransformer.so")
    s := p.Lookup(someSymbol)
    t, ok = s.(Transformer)

* converts the main processing thread in
  kusttarget.go to use those factory calls to run
  builtin generators and transformer before
  calling user-supplied plugins,

* as an example, provides an imagetag transformer
  plugin, converting a legacy transformer to
  builtin plugin form with its own isolated test.
  This test can be expanded by moving more code
  into it, but that can be done in a later PR.

Writing core functionality as plugins assures a
maintained plugin authoring and testing framework,
assures modularity, provides meaningful plugin
examples, and gives us a means to make informed
choices on which kustomize packages to publish
(and which to move to internal/).  The code
generator allows all this without losing "go get
sigs.k8s.io/kustomize" functionality.

TODO:

  1) Convert remaining legacy transformers to
     plugins (patch SMP/JSON, name prefix/suffix,
     labels/annos) with their own tests.  The
     generators are already done; this PR wires
     them up, and all tests & examples pass.

  2) Push code down into the plugins, as the first
     pass at conversion writes plugins as thin
     layers over calls into code under the mess
     that is pkg/.  Once this is done, we can
     reasonably move all the packages that aren't
     imported by plugins to internal/.

This PR could be split in two, one to merge the
the generator, and the second to merge the
ImageTagTransformer plugin and its wiring into the
main flow.

The latter PR could then serve as an example for
converting the remaining transformers.
2019-05-16 10:07:28 -07:00
Jeff Regan
c8be17c91f Merge pull request #1077 from monopole/minecraftUpgrade
Upgrade version of minecraft used in tests.
2019-05-16 10:07:01 -07:00
Kubernetes Prow Robot
c6476d16e7 Upgrade version of minecraft used in tests. 2019-05-16 10:06:24 -07:00
Kubernetes Prow Robot
14668f794d Merge pull request #1074 from Benjamintf1/patch-1
Update order of resources to include psps
2019-05-15 11:58:21 -07:00
Benjamin Fuller
efcf8757b0 Update order of resources to include psps
Add pod security policy to list of order after service account but before the roles that would use them
2019-05-14 11:38:17 -06:00
Kubernetes Prow Robot
ac9f2ded6e Merge pull request #1073 from kbhawkey/fix-empty-yaml-read
add test for empty patch file
2019-05-14 10:29:15 -07:00
Karen Bradshaw
c836de5ca8 update error msg 2019-05-14 13:03:24 -04:00
Karen Bradshaw
2aa7e30aff minimize test 2019-05-14 12:35:30 -04:00
Karen Bradshaw
c724cb7178 add test for empty patch file 2019-05-14 10:54:28 -04:00
Jeff Regan
858c7493df Merge pull request #1070 from monopole/deleteUnused
Delete some code.
2019-05-13 12:42:59 -07:00
Jeff Regan
8b433b0ff9 Merge pull request #1072 from monopole/standaloneServiceGenTest
Standalone service generator test
2019-05-13 12:33:08 -07:00
Jeffrey Regan
5614649d14 Standalone service generator test 2019-05-13 12:30:51 -07:00
Jeffrey Regan
9a4cb6c991 Delete unused code. 2019-05-13 12:15:30 -07:00
Jeff Regan
2a090e9118 Merge pull request #1071 from monopole/standaloneChartInflatorTest
Standalone ChartInflator plugin test.
2019-05-13 12:09:57 -07:00
Jingfang Liu
7fa02ce5b3 add document to explain inventory field (#997) 2019-05-13 12:03:30 -07:00
Jeffrey Regan
44ac9a9f44 Standalone ChartInflator plugin test. 2019-05-13 11:42:31 -07:00
Jeff Regan
95e4cc1aec Merge pull request #1057 from narg95/feature/remove_resource
add remove resource subcommand
2019-05-13 10:11:33 -07:00
Jeff Regan
fa4dc14c97 Update all.go 2019-05-13 10:01:55 -07:00
Kubernetes Prow Robot
69f59bfb2a Merge pull request #1068 from yujunz/patch-1
Fix typo
2019-05-13 08:50:21 -07:00
Kubernetes Prow Robot
eb2bdc3105 Merge pull request #1063 from narg95/fix_replace_image
allow set image without tag
2019-05-13 08:48:14 -07:00
Yujun Zhang
e079c20ceb Fix typo 2019-05-13 16:46:41 +08:00
Jeff Regan
27324c8236 Merge pull request #1067 from monopole/noKunstruct
Convert example plugins to accept bytes instead of unstruct.
2019-05-12 13:10:56 -07:00
Jeffrey Regan
2e71a3b862 Convert plugins to accept bytes instead of unstruct. 2019-05-12 12:58:56 -07:00
Jeff Regan
06acd3caa9 Merge pull request #1066 from monopole/addSedTransformerTest
Add SedTransformerTest
2019-05-12 11:34:57 -07:00
jregan
4df576869f Add SedTransformerTest 2019-05-12 11:32:33 -07:00
Jingfang Liu
61d46c26b8 fix the boilerplate copyright header (#1064) 2019-05-10 10:20:20 -07:00
Kubernetes Prow Robot
8eee69bd8f Merge pull request #1056 from sunny0826/master
Translate kustomization.yaml
2019-05-10 09:16:00 -07:00
Nestor
e4159d9411 allow to set image without a tag 2019-05-10 17:35:15 +02:00
郭旭东
7ab4d284ee fix translation 2019-05-10 09:34:41 +08:00
郭旭东
3e6ee23a17 fix README 2019-05-09 09:43:48 +08:00
郭旭东
faaf600276 translate kustomization.yaml & update zh/README 2019-05-09 09:42:50 +08:00
Nestor
ca6228b526 add remove resource subcommand 2019-05-08 15:34:29 +02:00
郭旭东
16924d7913 translate kustomization.yaml 2019-05-08 18:54:07 +08:00
Jeff Regan
540e4023da typo in README 2019-05-08 01:41:48 -07:00
Jeff Regan
2ecb2e3c80 Merge pull request #1054 from monopole/docFixes
add older release notes
2019-05-08 01:39:30 -07:00
jregan
2675bf4b73 add older release notes 2019-05-08 01:37:51 -07:00
Jeff Regan
01df12cf3c Merge pull request #1051 from monopole/fixNits
Fix a plugin nit.
2019-05-07 17:58:15 -07:00
Jeffrey Regan
7295a9b32e Fix some nits. 2019-05-07 17:56:48 -07:00
Jeff Regan
607eb13a52 Merge pull request #1050 from monopole/morePluginTests
Add ConfigMapGenerator and test.
2019-05-07 17:35:41 -07:00
Jeffrey Regan
2d70526eab Add ConfigMapGenerator and test. 2019-05-07 17:25:43 -07:00
Kubernetes Prow Robot
e29261033f Merge pull request #1048 from Liujingfang1/transformer
fix the bug for setting annotations when triggering transformers
2019-05-07 17:14:34 -07:00
Jingfang Liu
9390860288 fix the bug for setting annotations when triggering transformers 2019-05-07 16:54:20 -07:00
Jeff Regan
c6764ab31f Merge pull request #1047 from monopole/pluginTests
Add test for builtin secretgenerator plugin.
2019-05-07 16:34:17 -07:00
Jeffrey Regan
2825888ffd Add test for builtin secretgenerator plugin. 2019-05-07 16:16:07 -07:00
Kubernetes Prow Robot
34e8de3fc8 Merge pull request #1045 from Liujingfang1/transformer
pass resources to transformer plugin all together
2019-05-07 15:50:34 -07:00
Jingfang Liu
86f0f9a435 address comments 2019-05-07 15:43:36 -07:00
Jeff Regan
03ad8efcba Merge pull request #1046 from monopole/shareableKustTestHarness
Make kusttestharness shareable.
2019-05-07 14:56:07 -07:00
Jeffrey Regan
bcc7412ef2 Make kusttestharness shareable. 2019-05-07 14:23:33 -07:00
Jingfang Liu
c1e2b27c60 pass resources to transformer plugin all together 2019-05-07 13:42:28 -07:00
Kubernetes Prow Robot
8c5d4128e0 Merge pull request #1041 from monopole/introduceEnvs
Introduce envs field.
2019-05-06 18:21:39 -07:00
Jeff Regan
f2295acfdd Update v_2.1.0.md 2019-05-06 15:16:44 -07:00
Jeffrey Regan
529db0493b Introduce envs field. 2019-05-06 14:35:48 -07:00
guoxudong
a8c476f7c0 add the Chhinese translation of docs list & install (#1022)
* Chinese docs list

* translate INSTALL.md

* supplement

* translate workflows.md

* fix

* update README & INSTALL

* Fix bad links

* squash all the commits of Chinese docs
2019-05-02 08:46:15 -07:00
Jesse Newland
f38d0c690c Apply LimitRange resources before workloads 2019-05-02 08:40:14 -05:00
Kubernetes Prow Robot
e42933ec54 Merge pull request #1006 from Liujingfang1/inventory
add inventory package and refactor inventory transformer
2019-05-01 11:09:58 -07:00
Jingfang Liu
ad7ca6977b address comments 2019-05-01 09:17:36 -07:00
Jeff Regan
0045d7b716 Update plugins.md 2019-04-30 11:26:52 -07:00
Jeff Regan
64bd069290 Update plugins.md 2019-04-30 11:19:36 -07:00
Jeff Regan
70def86613 fix a link 2019-04-30 10:43:08 -07:00
Jeff Regan
cff5349426 Merge pull request #1020 from monopole/chartExample
Helm chart generator plugin example.
2019-04-30 10:20:37 -07:00
Jeff Regan
54d1c557b2 Update plugins.md 2019-04-30 09:44:53 -07:00
Jeff Regan
a889f97fd1 fix some example ptrs 2019-04-30 09:42:50 -07:00
Jeff Regan
9ffe20a18b Merge pull request #1031 from monopole/bugReportPage
Add bug report page.
2019-04-30 09:35:48 -07:00
Jeffrey Regan
9bd456c6df Add bug report page. 2019-04-30 09:34:45 -07:00
Jeff Regan
a43dffdeda Merge pull request #1030 from monopole/startReleaseNotes
start v2.1 release notes
2019-04-30 07:10:21 -07:00
Jeffrey Regan
61cf67fb95 start v2.1 release notes 2019-04-30 07:09:26 -07:00
Jeff Regan
09f2157a92 Merge pull request #1025 from monopole/updateGlossary
doc/glossary updates for v2.1
2019-04-29 19:54:44 -07:00
Jeffrey Regan
ca4aea173c doc/glossary updates for v2.1 2019-04-29 19:52:03 -07:00
Jeffrey Regan
76d370a8f2 Chart last mile example 2019-04-29 13:53:51 -07:00
Jeff Regan
f4364eb990 Merge pull request #1024 from kubernetes-sigs/change-language-in-remote-demo
Update remoteBuild.md
2019-04-29 10:12:39 -07:00
Jeff Regan
865348695f Update remoteBuild.md 2019-04-29 10:06:41 -07:00
Jeff Regan
2ec8189c1c Update remoteBuild.md 2019-04-29 09:59:00 -07:00
Kubernetes Prow Robot
a5dfc65440 Merge pull request #828 from kenmaglio/add-choco-documentation
Adds documentation for choco package for windows
2019-04-29 08:26:21 -07:00
Kubernetes Prow Robot
45302f0790 Merge pull request #1021 from max-sixty/patch-1
Update strategic-merge link
2019-04-29 08:24:25 -07:00
Maximilian Roos
1afc6c775b Update strategic-merge link
The existing link has been deprecated
2019-04-26 21:44:30 -04:00
Kubernetes Prow Robot
ca4d5ed42b Merge pull request #1019 from monopole/addIfToInflator
Mods to chart inflator plugin
2019-04-26 15:56:22 -07:00
Jeffrey Regan
cd9572e0bb hey 2019-04-26 15:48:41 -07:00
Jeff Regan
ac3ea4d6f3 Merge pull request #1014 from rohitsardesai83/replace_ghodss_yaml_with_sigsk8sio_yaml_dep
Remove dependency on ghodss/yaml
2019-04-26 09:50:51 -07:00
Jeff Regan
030824b196 Merge pull request #1016 from monopole/frog
Make plugin dir match Go conventions.
2019-04-26 09:07:19 -07:00
jregan
cfb0c5efad Make plugin dir match Go conventions. 2019-04-25 20:30:10 -07:00
rohitsardesai83
b67d713bc0 Remove dependency on ghodss/yaml 2019-04-25 23:47:01 +05:30
Kubernetes Prow Robot
0ac48f60a5 Merge pull request #1011 from Liujingfang1/execdir
pass loader root to exec plugins
2019-04-24 19:46:44 -07:00
Jingfang Liu
445f739234 add test for ensuirng the loader root is correctly passed 2019-04-24 18:32:03 -07:00
Jingfang Liu
fc8063f752 pass loader root to exec plugins 2019-04-24 12:09:25 -07:00
Jingfang Liu
d5abe39d53 add inventory package and refactor inventory transformer 2019-04-24 11:07:06 -07:00
Kubernetes Prow Robot
520acc7d97 Merge pull request #1008 from Liujingfang1/resid
add ItemId type
2019-04-23 17:30:00 -07:00
Jeff Regan
ae0510f648 Update chartinflatorexecplugin_test.go 2019-04-23 17:23:55 -07:00
Jeff Regan
0f50be877c Update ChartInflatorExec 2019-04-23 17:05:12 -07:00
Jingfang Liu
5b18c4de0c add ItemId type 2019-04-23 16:31:48 -07:00
Jeff Regan
72fd31fd20 Update FAQ.md 2019-04-23 16:29:32 -07:00
Jeff Regan
256ffdb932 Merge pull request #1007 from monopole/collectInternal
Collect existing internal pkgs under one roof.
2019-04-23 12:01:40 -07:00
Jeffrey Regan
8991bcb399 Collect existing internal pkgs under one roof. 2019-04-23 11:53:50 -07:00
Jeff Regan
185ae510e8 Update README.md 2019-04-23 11:24:14 -07:00
Kubernetes Prow Robot
40303cb329 Merge pull request #1005 from monopole/addLoaderTest
Add a plugin loader test.
2019-04-22 15:40:06 -07:00
Kubernetes Prow Robot
38ec207609 Merge pull request #1004 from Liujingfang1/prune
change field name: prune -> inventory
2019-04-22 15:14:07 -07:00
Jeffrey Regan
1545e07dd6 Add a plugin loader test. 2019-04-22 15:00:32 -07:00
Kubernetes Prow Robot
f123380917 Merge pull request #1003 from monopole/simplifyPluginLoader
Simplify plugin loader code.
2019-04-22 11:27:45 -07:00
Jingfang Liu
b4fc1e4357 change field name: prune -> inventory 2019-04-22 11:25:14 -07:00
jregan
76a3179868 Simplify plugin loader code.
* use one place to build plugin file names,
 * use one loader instance,
 * test for plugin enabled flag in just one place to
   avoid errors and reduce if statements,
 * don't return private objects,
 * factor goplugin loading to a method,
 * fix a related test that was commented out.
2019-04-22 10:13:40 -07:00
Kubernetes Prow Robot
c9bf70fd4b Merge pull request #1002 from monopole/deleteKustomizationError
Delete kustomizationerror.
2019-04-22 09:53:45 -07:00
jregan
9a85071085 Delete kustomizationerror.
Do a longstanding TODO to remove kustomizationerror.

It wasn't used much, and it wasn't used consistently,
because it's complicated to decided when it's worth
proceeding to accumulate errors when one already knows
that one has a fatal error in the kustomization.  Its
use was blocking refactoring for simplicity and making
tests harder to write.

Removing it lets us reinstate the cyclomatic complexity
check in KustTarget.

Also added more info to the affected error messages.
2019-04-21 16:10:58 -07:00
Jeff Regan
a6f41bb96d Merge pull request #1000 from monopole/faq
Add faq
2019-04-20 07:50:10 -07:00
Jeffrey Regan
3f2acc90aa Add faq 2019-04-20 07:47:31 -07:00
Jeff Regan
aba9f7d1e5 Merge pull request #998 from monopole/addLoadRestrictorFlag
Add load_restrictor flag.
2019-04-20 07:09:01 -07:00
Jeffrey Regan
3b8c5ee96d Add load_restrictor flag. 2019-04-19 17:33:51 -07:00
Kubernetes Prow Robot
a5bb5479fb Merge pull request #995 from monopole/removeLocalLoadRestrictions
Remove local load restrictions.
2019-04-19 16:27:54 -07:00
Jeffrey Regan
3c58c9d132 Remove local load restrictions. 2019-04-19 15:47:13 -07:00
Kubernetes Prow Robot
1b1f91580e Merge pull request #996 from monopole/addTestShowingSharedPatchesDisallowed
Add test showing shared patches disallowed
2019-04-19 14:59:55 -07:00
Jeffrey Regan
644dc4b9a7 Add test showing shared patches disallowed. 2019-04-19 14:42:30 -07:00
Jeffrey Regan
96707645e2 Add test showing shared patches disallowed. 2019-04-19 14:39:02 -07:00
Jeff Regan
b878e5f10d Merge pull request #993 from monopole/fixNits
Fix some comment nits.
2019-04-19 09:29:18 -07:00
Jeffrey Regan
a914570240 Fix some comment nits. 2019-04-19 09:26:54 -07:00
Kubernetes Prow Robot
b3d2ab29e9 Merge pull request #992 from sunny0826/master
docs add kubectl command
2019-04-19 09:09:55 -07:00
郭旭东
3ff5c793e3 docs add kubectl command 2019-04-19 18:09:01 +08:00
Kubernetes Prow Robot
c752660aa6 Merge pull request #990 from monopole/removeSomeDupes
Remove some duped code.
2019-04-18 11:51:27 -07:00
Jeff Regan
efded10e26 Merge pull request #971 from pohly/base-renaming-json-patch
tests: demonstrate issue with JSON patch when base adds name prefix
2019-04-18 11:48:55 -07:00
Jeffrey Regan
8767495b5a Remove some duped code. 2019-04-18 11:37:42 -07:00
Patrick Ohly
403ede788c tests: demonstrate issue with JSON patch when base adds name prefix
The expectation is that the base entity can be referenced by its name
with prefix, because the overlay shouldn't have to know how the base
is generated. But currently the entity is only found when using the
name without prefix.

Related-To: #972
2019-04-18 20:36:39 +02:00
Jeff Regan
c444f93eb5 Merge pull request #960 from zeeZ/individual-output
Write individual files to output path if it is a directory
2019-04-18 11:26:14 -07:00
Kubernetes Prow Robot
ed146f656e Merge pull request #988 from mengqiy/nscluster
fix namespace transformer for cluster-scoped resources
2019-04-18 11:16:04 -07:00
Mengqi Yu
bcb697eb0b fix namespace transformer for cluster-scoped resources 2019-04-18 11:03:19 -07:00
Kubernetes Prow Robot
3ac66049c7 Merge pull request #989 from Liujingfang1/prune
update PruneString for resources
2019-04-18 10:54:02 -07:00
Kubernetes Prow Robot
7a1a231041 Merge pull request #984 from afirth/20190516_vars_for_secretName
Vars should expand in ingress/spec/tls/secretName
2019-04-18 10:52:06 -07:00
Jingfang Liu
748c88c276 update PruneString for resources 2019-04-18 10:39:22 -07:00
Mengqi Yu
6f4b104c9e add admission webhook types in the default cluster-scoped resource list 2019-04-18 10:30:04 -07:00
Kubernetes Prow Robot
867201a075 Merge pull request #980 from monopole/helmChartInflatorExec
Helm chart generator exec plugin
2019-04-18 08:54:09 -07:00
Jeffrey Regan
2545ea1019 Helm chart generator exec plugin 2019-04-17 19:07:20 -07:00
Alastair Firth
5be42092af Vars should expand in ingress/spec/tls/secretName
https://github.com/kubernetes-sigs/kustomize/issues/799
2019-04-16 23:36:05 +02:00
Kubernetes Prow Robot
50c076eb3f Merge pull request #983 from Liujingfang1/exec
add the unstructured to ENV of exec plugins
2019-04-16 13:49:10 -07:00
Jingfang Liu
fb9e00bf33 add the unstructured to ENV of exec plugins 2019-04-16 13:12:42 -07:00
Kubernetes Prow Robot
b9007fcc29 Merge pull request #974 from Liujingfang1/exec
add support for exec plugins
2019-04-16 10:39:09 -07:00
Jingfang Liu
f6e01cfda7 add support for exec plugins 2019-04-16 09:26:38 -07:00
Christian
9203478a8a Write individual files to output path if it is a directory 2019-04-13 09:46:43 +02:00
Kubernetes Prow Robot
28cb6daec7 Merge pull request #968 from monopole/switchToVGo
Switch to vgo
2019-04-12 09:38:47 -07:00
Jeffrey Regan
e191ff53dd Switch to vgo 2019-04-11 22:25:37 -07:00
Kubernetes Prow Robot
177297c0ef Merge pull request #959 from Liujingfang1/execplugins
add goplugin for exec generators and transformers
2019-04-09 15:48:11 -07:00
Jingfang Liu
e5d730e1fe address comments 2019-04-09 15:42:08 -07:00
Jingfang Liu
ba43ecbcb7 add goplugin for exec generators and transformers 2019-04-09 13:13:21 -07:00
Kubernetes Prow Robot
ee68a9c450 Merge pull request #957 from monopole/justTheFactsMaam
Define a plugin compiler.
2019-04-08 18:33:04 -07:00
jregan
175c754f61 Define a plugin compiler. 2019-04-08 18:05:31 -07:00
Kubernetes Prow Robot
e8eed838b5 Merge pull request #926 from Liujingfang1/prune
generate configmap for pruning
2019-04-08 15:24:27 -07:00
Jingfang Liu
e9a3f9f5f6 address comments 2019-04-08 15:17:18 -07:00
Jingfang Liu
826affb8dd generate configmap for pruning 2019-04-08 14:10:49 -07:00
Kubernetes Prow Robot
4937b1c75e Merge pull request #955 from monopole/addSecretGenerator
Add secret generator.
2019-04-08 09:02:30 -07:00
jregan
ffc16d51e0 Add secret generator. 2019-04-06 18:38:22 -07:00
Jeff Regan
1623f1e4c0 Merge pull request #954 from monopole/genGen
Consolidate some generator and transformer code.
2019-04-06 18:38:04 -07:00
jregan
b32e041bfe Remove some duped code. 2019-04-06 16:14:12 -07:00
Kubernetes Prow Robot
38029d1836 Merge pull request #951 from Liujingfang1/generatorplugins
add support for generator go-plugins
2019-04-06 13:40:26 -07:00
Jeff Regan
b2dd74ab97 Merge pull request #953 from monopole/cleanPluginBuilds
Cleanup plugin builds.
2019-04-06 13:23:16 -07:00
jregan
16fe7ced6a Cleanup plugin builds. 2019-04-06 13:16:46 -07:00
Kubernetes Prow Robot
cb4af7a9d4 Merge pull request #950 from 2opremio/564-add-force-flag-to-annotations-and-labels
Add --force flag to modify annotations and labels
2019-04-05 14:05:52 -07:00
Jingfang Liu
7493732176 add generator plugins 2019-04-05 13:51:56 -07:00
Alfonso Acosta
2cf8371add Add --force flag to modify annotations and labels
This change adds a new flag (`--force`) to commands `edit add annotation` and
`edit add label` so that annotations and labels are modified if they already
existed.
2019-04-05 22:49:28 +02:00
Jeff Regan
a575c24a24 Merge pull request #948 from bells17/fix-path
Fix path
2019-04-05 12:56:15 -07:00
Kubernetes Prow Robot
9e8d06e7ce Merge pull request #946 from Liujingfang1/moreplugins
add support for transformer goplugins
2019-04-05 11:25:20 -07:00
Jingfang Liu
4f1a2350ce add transformer plugins 2019-04-05 10:16:10 -07:00
Daiki Hayakawa
cefb64b6a9 Fix path 2019-04-05 18:02:37 +09:00
jregan
440d036176 some transformer plugins 2019-04-04 13:23:41 -07:00
Kubernetes Prow Robot
53f0deec8f Merge pull request #941 from Liujingfang1/gentran
add generators/transformers fields in kusotmization.yaml
2019-04-03 16:44:48 -07:00
Kubernetes Prow Robot
3c495e3b23 Merge pull request #939 from kbhawkey/doc-images-take2
add tutorial for custom images transformer
2019-04-03 14:36:49 -07:00
Jingfang Liu
deaf0779a1 add generators/transformers fields in kusotmization.yaml 2019-04-03 14:05:25 -07:00
Jeff Regan
fd7a353df6 Merge pull request #938 from monopole/tweakDoc
Expound on plugin caveats
2019-04-01 09:40:53 -07:00
Karen Bradshaw
927b497feb fix tests 2019-03-31 19:05:35 -04:00
Karen Bradshaw
237c54f47e add tutorial for custom images transformer 2019-03-31 16:29:52 -04:00
Kubernetes Prow Robot
8c23db47a7 Merge pull request #936 from Liujingfang1/note
add note for availability in kubectl
2019-03-30 18:38:34 -07:00
jregan
7971ac1cb8 Tweak secret docs. 2019-03-30 18:22:43 -07:00
Yujun Zhang
2490e605c3 Updates in image transformer (#911)
- Decouple `mutateImage` from `updateContainers` to be reused as `mutateFunc`
- Ignore default image transform error for CRD which may contain non-array type `containers` field

Related to #890, #904, fixes #890
2019-03-29 13:11:07 -07:00
Jingfang Liu
21a0cba43e fix the regression of building remote url (#935) 2019-03-29 13:10:11 -07:00
Kubernetes Prow Robot
42d9287985 Merge pull request #931 from michaelheyvaert/fix-cronjob-projected-volume-namerefs
fix configmap/secret name references for cronjobs with projected volumes
2019-03-29 09:28:23 -07:00
Michael Heyvaert
4848987a1f fix configmap/secret name references for cronjobs with projected volumes 2019-03-29 09:00:00 +01:00
Jingfang Liu
53a22cbe9b add note for availability in kubectl 2019-03-28 15:22:49 -07:00
Jeff Regan
c3700e0c88 Merge pull request #934 from monopole/tweakPluginDoc
Improve plugin doc.
2019-03-28 12:51:49 -07:00
Jeffrey Regan
58d9a51040 Improve plugin doc. 2019-03-28 12:50:19 -07:00
Jeff Regan
8f395ad86f Merge pull request #925 from monopole/addGoPluginExample
Add goplugin KV generator example.
2019-03-28 10:24:06 -07:00
Jeffrey Regan
99391157ec Add goplugin KV generator example. 2019-03-28 09:55:44 -07:00
Jeff Regan
99406d4412 Merge pull request #933 from monopole/fixTravisMaybe
Update travis file.
2019-03-28 09:54:30 -07:00
Jeffrey Regan
c1dea6676f Update travis file. 2019-03-28 09:42:18 -07:00
Kubernetes Prow Robot
afa4664511 Merge pull request #920 from monopole/fix918
fix a bool check
2019-03-26 11:03:22 -07:00
Jeffrey Regan
267eec5509 Fix 918 2019-03-26 10:47:31 -07:00
Jeff Regan
9764eb2f83 Merge pull request #919 from monopole/accumulatorPkg
Move accumulator code to its own package.
2019-03-26 10:04:46 -07:00
Jeffrey Regan
9a12b55139 Move accumulator code to its own package. 2019-03-26 09:53:52 -07:00
Kubernetes Prow Robot
f8cffef977 Merge pull request #889 from sethpollack/edit_add_plugins
update edit add secrets/configmaps to use plugins
2019-03-21 13:51:37 -07:00
Seth Pollack
822420e4ab fix mergeFlags 2019-03-21 14:58:06 -04:00
Seth Pollack
b60fca05bd update edit add secrets/configmaps to use plugins 2019-03-20 09:24:10 -04:00
Kubernetes Prow Robot
1a35071672 Merge pull request #895 from Liujingfang1/patchnamespace
skip adding namespace when the object is empty
2019-03-19 15:42:22 -07:00
Jingfang Liu
bfc3655bad skip adding namespace when the object is empty 2019-03-19 15:34:29 -07:00
Kubernetes Prow Robot
2c0c0c9497 Merge pull request #841 from yujunz/transformers/image
Support custom configuration for image transformer
2019-03-19 14:08:22 -07:00
Kubernetes Prow Robot
46bd38e89d Merge pull request #891 from sethpollack/envfiles
add builtin envfiles plugin
2019-03-18 12:58:21 -07:00
Seth Pollack
9fc4d388ce add builtin envfiles plugin 2019-03-18 13:58:38 -04:00
Jeff Regan
2965134f89 Merge pull request #892 from monopole/defaultToBuiltin
Make builtin the default pluginType
2019-03-18 10:29:22 -07:00
Jeffrey Regan
3a7c8a03f4 Make builtin the default pluginType 2019-03-18 10:21:24 -07:00
Kubernetes Prow Robot
449b1b68e0 Merge pull request #888 from sethpollack/files
add builtin files plugin
2019-03-18 09:46:20 -07:00
Seth Pollack
dd59eb38d0 add test case 2019-03-17 20:44:07 -04:00
Seth Pollack
a8465c95e1 add builtin files plugin 2019-03-17 17:22:52 -04:00
Kubernetes Prow Robot
df2f67b191 Merge pull request #883 from sethpollack/builtins
add builtin plugin for literals
2019-03-17 14:05:09 -07:00
Seth Pollack
7764dee59d Merge branch 'master' into builtins 2019-03-17 17:01:06 -04:00
Jeff Regan
6465a36176 Merge pull request #887 from monopole/addNannyFlag
Put goplugins behind flag.
2019-03-17 13:46:03 -07:00
jregan
103c1b3a4f Put goplugins behind flag. 2019-03-17 13:39:48 -07:00
Seth Pollack
29cbec37b8 move parse helpers to util 2019-03-17 12:34:52 -04:00
Kubernetes Prow Robot
2c9e4507a7 Merge pull request #861 from kbhawkey/fix-spelling-transformerconfig
correct spelling, minor word ordering
2019-03-17 06:38:55 -07:00
Kubernetes Prow Robot
d5d5c076a7 Merge pull request #882 from sethpollack/xdg_home
honor XDG_CONFIG_HOME
2019-03-17 06:36:55 -07:00
Kubernetes Prow Robot
f09bbff35c Merge pull request #884 from vreon/fix-varrefs
Fix incorrect and missing varReferences
2019-03-17 06:12:56 -07:00
Kubernetes Prow Robot
2627e2507b Merge pull request #885 from yujunz/imagetransformer/test
Convert image transformer test to a more readable format
2019-03-17 06:08:55 -07:00
Seth Pollack
1bd7afe6e7 fix linter 2019-03-17 08:53:49 -04:00
Yujun Zhang
e6c1b14108 Add test for transformers/image custom config 2019-03-17 16:59:41 +08:00
Yujun Zhang
7130e3ff1d Leave defautconfig empty for images
`containers` and `initContainers` of *ANY* kind in *ANY*
path are builtin supported in code
2019-03-17 16:43:31 +08:00
Yujun Zhang
abf538d80d Keep backward compatibility for image transformer 2019-03-17 16:43:31 +08:00
Yujun Zhang
f311ba8d4f Support custom config for image transformer 2019-03-17 16:43:31 +08:00
Yujun Zhang
3e85c4589b Load default config for image transformer 2019-03-17 16:43:31 +08:00
Yujun Zhang
d0cf047381 Convert image transformer test to a more readable format 2019-03-17 16:41:42 +08:00
Jesse Dubay
31091a8df2 Fix missing varrefs for CronJob, Job, ReplicaSet 2019-03-16 19:15:56 -07:00
Jesse Dubay
e207ae4c01 Fix incorrect default varrefs for CronJob volumeMounts 2019-03-16 19:12:58 -07:00
Jesse Dubay
3011f18047 Sort default varReference config by kind, path 2019-03-16 19:11:42 -07:00
Seth Pollack
388d5c2d7c add builtin plugins 2019-03-16 21:21:15 -04:00
Seth Pollack
5c4719651e honor XDG_CONFIG_HOME 2019-03-16 20:46:37 -04:00
Karen Bradshaw
f850ca63f4 remove extra comment 2019-03-16 16:49:16 -04:00
Karen Bradshaw
65886f1258 address comments 2019-03-16 16:40:30 -04:00
Karen Bradshaw
942e36e19f a few more changes 2019-03-16 16:40:29 -04:00
Karen Bradshaw
7b82154c4c correct spelling, minor word ordering 2019-03-16 16:40:29 -04:00
Kubernetes Prow Robot
284efc709c Merge pull request #760 from sethpollack/plugins
add secret and configmap generator plugins
2019-03-15 18:00:58 -07:00
Seth Pollack
56965a0046 fix test 2019-03-15 17:33:17 -04:00
Seth Pollack
18f6328284 add secret and configmap generator plugins 2019-03-15 14:28:18 -04:00
Jeff Regan
e7be999bc9 Merge pull request #879 from monopole/removeTheSet
Secret/configmap factory cleanup.
2019-03-15 10:17:29 -07:00
jregan
c06b95077d Secret/configmap factory cleanup. 2019-03-15 09:25:59 -07:00
Kubernetes Prow Robot
c4da063934 Merge pull request #877 from YP28/fix-typo-in-namereference
fix typo in namereference where serviceaccount name would not resolve
2019-03-14 08:46:29 -07:00
Yordi Pauptit
62d3200e4f fix typo in namereference where serviceaccount name would not resolve 2019-03-14 09:36:21 +01:00
Kubernetes Prow Robot
9a419824ae Merge pull request #874 from CodeLingoBot/rewrite
Fix function comments based on best practices from Effective Go
2019-03-12 14:50:39 -07:00
Kubernetes Prow Robot
a94eab0398 Merge pull request #867 from yujunz/docs/versioning-policy
Fix field names
2019-03-12 14:48:39 -07:00
Kubernetes Prow Robot
01b8ab8524 Merge pull request #872 from kbhawkey/fix-set-image-help-msg
fix help msg for set image cmd
2019-03-11 14:44:37 -07:00
Karen Bradshaw
fa552d7773 fix help msg for set image cmd 2019-03-11 17:23:30 -04:00
Kubernetes Prow Robot
7acbd4d3e0 Merge pull request #870 from YP28/job-initctr-varref
Add Job initContainer to varreference config
2019-03-11 10:39:29 -07:00
Kubernetes Prow Robot
9811123e2e Merge pull request #866 from yujunz/edit-fix
Fix error message
2019-03-11 10:13:28 -07:00
Yordi Pauptit
f7cd44be42 add job initcontainer to varreference config 2019-03-11 15:13:58 +01:00
CodeLingo Bot
9a4692e6ee Fix function comments based on best practices from Effective Go
Signed-off-by: CodeLingo Bot <bot@codelingo.io>
2019-03-11 00:45:21 +00:00
Yujun Zhang
3d0e29075d Fix markdownlint warnings 2019-03-09 17:02:39 +08:00
Yujun Zhang
0f571b9120 Fix field names 2019-03-09 16:58:32 +08:00
Yujun Zhang
3a44508d6f Fix error message
Closes #862
2019-03-09 16:43:32 +08:00
Kubernetes Prow Robot
5294355c98 Merge pull request #864 from mnatsu31/fix-typo-namereference
Fix typo in namereference path for cronjobs initContainers.
2019-03-08 09:25:30 -08:00
mnatsu31
559efd6477 Fix typo in namereference path for cronjobs initContainers. 2019-03-08 13:20:34 +09:00
Kubernetes Prow Robot
a59577c08d Merge pull request #857 from pst/fastergitclone
Reduce time required for cloning remote bases
2019-03-06 21:24:57 -08:00
Philipp Strube
4f429d6b86 Reduce time required for cloning remote bases
This commit changes git/cloner.go from cloning the whole history
and then checking out the desired ref to a implementation that
only downloads the history for the desired ref.

It does so by first initializing an empty repository, setting the
source repository as a remote, fetching just the desired ref and
then hard resetting the empty local repo to that ref.

This reduces the time it takes to build the multibases example
as a remote base at ref v2.0.3 from an avg of 8s with the
current implementation to an avg of 2s out of 10 runs each, by
drastically decreasing the data transferred.

The improvement should increase as repositories grow.
2019-03-06 19:31:24 +01:00
Ken Maglio
5e7ddc8616 Adds precommit for windows + documentation 2019-03-05 12:08:11 -06:00
Ken Maglio
bb69e9e70b Updates documentation for support and source 2019-02-28 21:45:40 -06:00
Ken Maglio
852e7ed5aa Typo Fix 2019-02-26 17:19:33 -06:00
Ken Maglio
1d65f24b04 adds documentation for choco package 2019-02-21 19:54:48 -06:00
4946 changed files with 827623 additions and 466571 deletions

4
.gitignore vendored
View File

@@ -4,7 +4,9 @@
*.dll
*.so
*.dylib
kustomize
.idea
*.iml
# Test binary, build with `go test -c`
*.test

View File

@@ -1,45 +1,42 @@
os:
# TODO: Enable this when we can get the tests to work
# - windows
- linux
- osx
# TODO: Speed up the slowness of the osx travis runs
# Maybe cache brew installs?
#
# TODO: Uncomment when some gets the tests running on Windows.
# - windows
addons:
apt:
packages: tree
packages:
- tree
homebrew:
packages: tree
language: go
go:
- 1.11.x
go_import_path: sigs.k8s.io/kustomize
# Maybe, maybe not.
# sudo: false
packages:
- tree
update: true
# Only clone the most recent commit.
git:
depth: 1
env:
- GOLANGCI_RELEASE="v1.10.2"
language: go
go:
- "1.13"
go_import_path: sigs.k8s.io/kustomize
before_install:
- source ./bin/consider-early-travis-exit.sh
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $GOPATH/bin ${GOLANGCI_RELEASE}
- go get -u github.com/monopole/mdrip
- source ./travis/consider-early-travis-exit.sh
# Install must be set to prevent default `go get` to run.
# The dependencies have already been vendored by `dep` so
# we don't need to fetch them.
install:
-
# Skip the install process; let pre-commit.sh do it.
install: true
script:
- ./bin/pre-commit.sh
- ./travis/verify-deps.sh
- ./travis/pre-commit.sh
- ./travis/kyaml-pre-commit.sh
# TBD. Suppressing for now.
notifications:

View File

@@ -6,6 +6,10 @@ _As contributors and maintainers of this project, and in the interest of fosteri
## Getting Started
Dev guides:
- [Mac](docs/macDevGuide.md)
We have full documentation on how to get started contributing here:
- [Contributor License Agreement](https://git.k8s.io/community/CLA.md) Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests

389
Gopkg.lock generated
View File

@@ -1,389 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
digest = "1:d8ebbd207f3d3266d4423ce4860c9f3794956306ded6c7ba312ecc69cdfbf04c"
name = "github.com/PuerkitoBio/purell"
packages = ["."]
pruneopts = "NUT"
revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4"
version = "v1.1.0"
[[projects]]
branch = "master"
digest = "1:8098cd40cd09879efbf12e33bcd51ead4a66006ac802cd563a66c4f3373b9727"
name = "github.com/PuerkitoBio/urlesc"
packages = ["."]
pruneopts = "NUT"
revision = "de5bf2ad457846296e2031421a34e2568e304e35"
[[projects]]
digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39"
name = "github.com/davecgh/go-spew"
packages = ["spew"]
pruneopts = "NUT"
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
digest = "1:f8e6f07329067bc182633dcb19a3df53ce5d454b551e1b5a1cac2163748648d9"
name = "github.com/emicklei/go-restful"
packages = [
".",
"log",
]
pruneopts = "NUT"
revision = "3658237ded108b4134956c1b3050349d93e7b895"
version = "v2.7.1"
[[projects]]
digest = "1:ad32dc29f37281bacb5dcedff17c9461dc1739dc8a5f63a71ab491c6e92edf8d"
name = "github.com/evanphx/json-patch"
packages = ["."]
pruneopts = "NUT"
revision = "afac545df32f2287a079e2dfb7ba2745a643747e"
version = "v3.0.0"
[[projects]]
digest = "1:81466b4218bf6adddac2572a30ac733a9255919bc2f470b4827a317bd4ee1756"
name = "github.com/ghodss/yaml"
packages = ["."]
pruneopts = "NUT"
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
version = "v1.0.0"
[[projects]]
branch = "master"
digest = "1:260f7ebefc63024c8dfe2c9f1a2935a89fa4213637a1f522f592f80c001cc441"
name = "github.com/go-openapi/jsonpointer"
packages = ["."]
pruneopts = "NUT"
revision = "3a0015ad55fa9873f41605d3e8f28cd279c32ab2"
[[projects]]
branch = "master"
digest = "1:98abd61947ff5c7c6fcfec5473d02a4821ed3a2dd99a4fbfdb7925b0dd745546"
name = "github.com/go-openapi/jsonreference"
packages = ["."]
pruneopts = "NUT"
revision = "3fb327e6747da3043567ee86abd02bb6376b6be2"
[[projects]]
branch = "master"
digest = "1:e95b560c49fb849a61957a5fb3346ce23b3f67426e00e01179e5396cabc9a12c"
name = "github.com/go-openapi/spec"
packages = ["."]
pruneopts = "NUT"
revision = "bcff419492eeeb01f76e77d2ebc714dc97b607f5"
[[projects]]
branch = "master"
digest = "1:a610c604eb06f0be4b0fc667388b7a221155d77d7f9089f70ac142a4a9daf014"
name = "github.com/go-openapi/swag"
packages = ["."]
pruneopts = "NUT"
revision = "811b1089cde9dad18d4d0c2d09fbdbf28dbd27a5"
[[projects]]
digest = "1:1b3dd24f14a5280710fc7a3aa2480b6e4d20fdfc905841de9a3aa2aa2f1d4ee9"
name = "github.com/gogo/protobuf"
packages = [
"proto",
"sortkeys",
]
pruneopts = "NUT"
revision = "1adfc126b41513cc696b209667c8656ea7aac67c"
version = "v1.0.0"
[[projects]]
branch = "master"
digest = "1:e2b86e41f3d669fc36b50d31d32d22c8ac656c75aa5ea89717ce7177e134ff2a"
name = "github.com/golang/glog"
packages = ["."]
pruneopts = "NUT"
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
[[projects]]
digest = "1:03e14cff610a8a58b774e36bd337fa979482be86aab01be81fb8bbd6d0f07fc8"
name = "github.com/golang/protobuf"
packages = [
"proto",
"ptypes",
"ptypes/any",
"ptypes/duration",
"ptypes/timestamp",
]
pruneopts = "NUT"
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
version = "v1.1.0"
[[projects]]
branch = "master"
digest = "1:52c5834e2bebac9030c97cc0798ac11c3aa8a39f098aeb419f142533da6cd3cc"
name = "github.com/google/gofuzz"
packages = ["."]
pruneopts = "NUT"
revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1"
[[projects]]
digest = "1:3d7c1446fc5c710351b246c0dc6700fae843ca27f5294d0bd9f68bab2a810c44"
name = "github.com/googleapis/gnostic"
packages = [
"OpenAPIv2",
"compiler",
"extensions",
]
pruneopts = "NUT"
revision = "ee43cbb60db7bd22502942cccbc39059117352ab"
version = "v0.1.0"
[[projects]]
digest = "1:406338ad39ab2e37b7f4452906442a3dbf0eb3379dd1f06aafb5c07e769a5fbb"
name = "github.com/inconshreveable/mousetrap"
packages = ["."]
pruneopts = "NUT"
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
version = "v1.0"
[[projects]]
digest = "1:42c47ace7ccb114261ef7e0d418d274921514ab50a3bf6bdb9e51c3dde8ce13d"
name = "github.com/json-iterator/go"
packages = ["."]
pruneopts = "NUT"
revision = "ca39e5af3ece67bbcda3d0f4f56a8e24d9f2dad4"
version = "1.1.3"
[[projects]]
branch = "master"
digest = "1:ada518b8c338e10e0afa443d84671476d3bd1d926e13713938088e8ddbee1a3e"
name = "github.com/mailru/easyjson"
packages = [
"buffer",
"jlexer",
"jwriter",
]
pruneopts = "NUT"
revision = "3fdea8d05856a0c8df22ed4bc71b3219245e4485"
[[projects]]
digest = "1:2f42fa12d6911c7b7659738758631bec870b7e9b4c6be5444f963cdcfccc191f"
name = "github.com/modern-go/concurrent"
packages = ["."]
pruneopts = "NUT"
revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
version = "1.0.3"
[[projects]]
digest = "1:314a5881fab303a80d6d2e35a77000f2224bb50f09ef63a9aa4c1f9eaef985d8"
name = "github.com/modern-go/reflect2"
packages = ["."]
pruneopts = "NUT"
revision = "1df9eeb2bb81f327b96228865c5687bc2194af3f"
version = "1.0.0"
[[projects]]
digest = "1:5cf3f025cbee5951a4ee961de067c8a89fc95a5adabead774f82822efabab121"
name = "github.com/pkg/errors"
packages = ["."]
pruneopts = "NUT"
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
digest = "1:0f156dbd01b40676bdcbc64e51535c09b50f83c9cca5faef3090f82f18bda3c2"
name = "github.com/spf13/cobra"
packages = ["."]
pruneopts = "NUT"
revision = "a1f051bc3eba734da4772d60e2d677f47cf93ef4"
version = "v0.0.2"
[[projects]]
digest = "1:15e5c398fbd9d2c439b635a08ac161b13d04f0c2aa587fe256b65dc0c3efe8b7"
name = "github.com/spf13/pflag"
packages = ["."]
pruneopts = "NUT"
revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
version = "v1.0.1"
[[projects]]
branch = "master"
digest = "1:18108bc7e384e395b4805632a637405a3df71fa518e22f9b39b0c08b89a52b96"
name = "golang.org/x/net"
packages = [
"http/httpguts",
"http2",
"http2/hpack",
"idna",
]
pruneopts = "NUT"
revision = "fe579d43d83210096a79b46dcca0e3721058393a"
[[projects]]
digest = "1:e33513a825fcd765e97b5de639a2f7547542d1a8245df0cef18e1fd390b778a9"
name = "golang.org/x/text"
packages = [
"collate",
"collate/build",
"internal/colltab",
"internal/gen",
"internal/tag",
"internal/triegen",
"internal/ucd",
"language",
"secure/bidirule",
"transform",
"unicode/bidi",
"unicode/cldr",
"unicode/norm",
"unicode/rangetable",
"width",
]
pruneopts = "NUT"
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
[[projects]]
digest = "1:2d1fbdc6777e5408cabeb02bf336305e724b925ff4546ded0fa8715a7267922a"
name = "gopkg.in/inf.v0"
packages = ["."]
pruneopts = "NUT"
revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf"
version = "v0.9.1"
[[projects]]
digest = "1:7c95b35057a0ff2e19f707173cc1a947fa43a6eb5c4d300d196ece0334046082"
name = "gopkg.in/yaml.v2"
packages = ["."]
pruneopts = "NUT"
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
version = "v2.2.1"
[[projects]]
branch = "master"
digest = "1:d895c7c24a0dd1ed2ecd061fd88dfea9e1e84d6f280ed859942a2d1aabee10ec"
name = "k8s.io/api"
packages = [
"admissionregistration/v1alpha1",
"admissionregistration/v1beta1",
"apps/v1",
"apps/v1beta1",
"apps/v1beta2",
"authentication/v1",
"authentication/v1beta1",
"authorization/v1",
"authorization/v1beta1",
"autoscaling/v1",
"autoscaling/v2beta1",
"batch/v1",
"batch/v1beta1",
"batch/v2alpha1",
"certificates/v1beta1",
"core/v1",
"events/v1beta1",
"extensions/v1beta1",
"networking/v1",
"policy/v1beta1",
"rbac/v1",
"rbac/v1alpha1",
"rbac/v1beta1",
"scheduling/v1alpha1",
"settings/v1alpha1",
"storage/v1",
"storage/v1alpha1",
"storage/v1beta1",
]
pruneopts = "NUT"
revision = "53d615ae3f440f957cb9989d989d597f047262d9"
[[projects]]
branch = "master"
digest = "1:dff69dd9d9fc681ae077ce5a409aca3c24894d09102ab0395ca7972f6ec01811"
name = "k8s.io/apimachinery"
packages = [
"pkg/api/equality",
"pkg/api/meta",
"pkg/api/resource",
"pkg/api/validation",
"pkg/apis/meta/v1",
"pkg/apis/meta/v1/unstructured",
"pkg/apis/meta/v1/validation",
"pkg/apis/meta/v1beta1",
"pkg/conversion",
"pkg/conversion/queryparams",
"pkg/fields",
"pkg/labels",
"pkg/runtime",
"pkg/runtime/schema",
"pkg/runtime/serializer",
"pkg/runtime/serializer/json",
"pkg/runtime/serializer/protobuf",
"pkg/runtime/serializer/recognizer",
"pkg/runtime/serializer/versioning",
"pkg/selection",
"pkg/types",
"pkg/util/errors",
"pkg/util/framer",
"pkg/util/intstr",
"pkg/util/json",
"pkg/util/mergepatch",
"pkg/util/net",
"pkg/util/runtime",
"pkg/util/sets",
"pkg/util/strategicpatch",
"pkg/util/validation",
"pkg/util/validation/field",
"pkg/util/wait",
"pkg/util/yaml",
"pkg/watch",
"third_party/forked/golang/json",
"third_party/forked/golang/reflect",
]
pruneopts = "NUT"
revision = "13b73596e4b63e03203e86f6d9c7bcc1b937c62f"
[[projects]]
digest = "1:ae9ced9ef7b8eb2794a4f80bc3af9d2bc38ec7d60337367bad9a655c1d641458"
name = "k8s.io/client-go"
packages = ["kubernetes/scheme"]
pruneopts = "NUT"
revision = "23781f4d6632d88e869066eaebb743857aa1ef9b"
version = "v7.0.0"
[[projects]]
branch = "master"
digest = "1:f4fb3421360af5c51070bfe0c1c7467f8809fa70e278e129f068f5106b5c8a65"
name = "k8s.io/kube-openapi"
packages = [
"pkg/common",
"pkg/util/proto",
]
pruneopts = "NUT"
revision = "b3f03f55328800731ce03a164b80973014ecd455"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
input-imports = [
"github.com/evanphx/json-patch",
"github.com/ghodss/yaml",
"github.com/go-openapi/spec",
"github.com/pkg/errors",
"github.com/spf13/cobra",
"gopkg.in/yaml.v2",
"k8s.io/api/core/v1",
"k8s.io/apimachinery/pkg/api/validation",
"k8s.io/apimachinery/pkg/apis/meta/v1",
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
"k8s.io/apimachinery/pkg/apis/meta/v1/validation",
"k8s.io/apimachinery/pkg/runtime",
"k8s.io/apimachinery/pkg/runtime/schema",
"k8s.io/apimachinery/pkg/util/mergepatch",
"k8s.io/apimachinery/pkg/util/strategicpatch",
"k8s.io/apimachinery/pkg/util/validation",
"k8s.io/apimachinery/pkg/util/validation/field",
"k8s.io/apimachinery/pkg/util/yaml",
"k8s.io/client-go/kubernetes/scheme",
"k8s.io/kube-openapi/pkg/common",
]
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -1,58 +0,0 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
# prune out unused content from vendor
[prune]
go-tests = true
non-go = true
unused-packages = true
[[constraint]]
name = "github.com/evanphx/json-patch"
version = "3.0.0"
[[constraint]]
name = "github.com/ghodss/yaml"
version = "1.0.0"
[[constraint]]
name = "github.com/spf13/cobra"
version = "0.0.2"
[[constraint]]
branch = "master"
name = "k8s.io/api"
[[constraint]]
branch = "master"
name = "k8s.io/apimachinery"
[[constraint]]
name = "k8s.io/client-go"
version = "7.0.0"
[[override]]
branch = "master"
name = "k8s.io/utils"
[[override]]
branch = "master"
name = "github.com/go-openapi/spec"

145
Makefile Normal file
View File

@@ -0,0 +1,145 @@
# This Makefile is (and must be) used by
# travis/pre-commit.sh to qualify pull requests.
#
# That script generates all the code that needs
# to be generated, and runs all the tests.
#
# Functionality in that script is gradually moving here.
MYGOBIN := $(shell go env GOPATH)/bin
PATH := $(PATH):$(MYGOBIN)
SHELL := env PATH=$(PATH) /bin/bash
.PHONY: all
all: pre-commit
# The pre-commit.sh script generates, lints and tests.
# It uses this makefile. For more clarity, would like
# to stop that - any scripts invoked by targets here
# shouldn't "call back" to the makefile.
.PHONY: pre-commit
pre-commit:
./travis/pre-commit.sh
# Version pinned by api/go.mod
$(MYGOBIN)/golangci-lint:
cd api; \
go install github.com/golangci/golangci-lint/cmd/golangci-lint
# Version pinned by api/go.mod
$(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
# TODO: need a new release of the API, followed by a new pluginator.
# pluginator v1.1.0 is too old for the code currently needed in the API.
# Can release a new one at any time, just haven't done so.
# When one has been released,
# - uncomment the pluginator line in './api/internal/tools/tools.go'
# - pin the version tag in './api/go.mod' to match the new release
# - change the following to 'cd api; go install sigs.k8s.io/kustomize/pluginator'
$(MYGOBIN)/pluginator:
cd pluginator; \
go install .
.PHONY: install-tools
install-tools: \
$(MYGOBIN)/goimports \
$(MYGOBIN)/golangci-lint \
$(MYGOBIN)/mdrip \
$(MYGOBIN)/pluginator \
$(MYGOBIN)/stringer
# Builtin plugins are generated code.
# Add new items here to create new builtins.
builtinplugins = \
api/builtins/annotationstransformer.go \
api/builtins/configmapgenerator.go \
api/builtins/hashtransformer.go \
api/builtins/imagetagtransformer.go \
api/builtins/inventorytransformer.go \
api/builtins/labeltransformer.go \
api/builtins/legacyordertransformer.go \
api/builtins/namespacetransformer.go \
api/builtins/patchjson6902transformer.go \
api/builtins/patchstrategicmergetransformer.go \
api/builtins/patchtransformer.go \
api/builtins/prefixsuffixtransformer.go \
api/builtins/replicacounttransformer.go \
api/builtins/secretgenerator.go
.PHONY: lint
lint: install-tools $(builtinplugins)
cd api; $(MYGOBIN)/golangci-lint run ./...
cd kustomize; $(MYGOBIN)/golangci-lint run ./...
cd pluginator; $(MYGOBIN)/golangci-lint run ./...
api/builtins/%.go: $(MYGOBIN)/pluginator
@echo "generating $*"; \
cd plugin/builtin/$*; \
go generate .; \
cd ../../../api/builtins; \
$(MYGOBIN)/goimports -w $*.go
.PHONY: generate
generate: $(builtinplugins)
.PHONY: unit-test-api
unit-test-api: $(builtinplugins)
cd api; go test ./...
.PHONY: unit-test-plugins
unit-test-plugins:
./hack/runPluginUnitTests.sh
.PHONY: unit-test-kustomize
unit-test-kustomize:
cd kustomize; go test ./...
.PHONY: unit-test-all
unit-test-all: unit-test-api unit-test-kustomize unit-test-plugins
# linux only.
# This is for testing an example plugin that
# uses kubeval for validation.
# Don't want to add a hard dependence in go.mod file
# to github.com/instrumenta/kubeval.
# Instead, download the binary.
$(MYGOBIN)/kubeval:
d=$(shell mktemp -d); cd $$d; \
wget https://github.com/instrumenta/kubeval/releases/latest/download/kubeval-linux-amd64.tar.gz; \
tar xf kubeval-linux-amd64.tar.gz; \
mv kubeval $(MYGOBIN); \
rm -rf $$d
# linux only.
# This is for testing an example plugin that
# uses helm to inflate a chart for subsequent kustomization.
# Don't want to add a hard dependence in go.mod file
# to helm.
# Instead, download the binary.
$(MYGOBIN)/helm:
d=$(shell mktemp -d); cd $$d; \
wget https://storage.googleapis.com/kubernetes-helm/helm-v2.13.1-linux-amd64.tar.gz; \
tar -xvzf helm-v2.13.1-linux-amd64.tar.gz; \
mv linux-amd64/helm $(MYGOBIN); \
rm -rf $$d
.PHONY: clean
clean:
rm -f $(builtinplugins)
rm -f $(MYGOBIN)/pluginator
.PHONY: nuke
nuke: clean
sudo rm -rf $(shell go env GOPATH)/pkg/mod/sigs.k8s.io

View File

@@ -7,7 +7,7 @@ untouched and usable as is.
`kustomize` targets kubernetes; it understands and can
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 editted text.
and it's like [`sed`], in that it emits edited text.
This tool is sponsored by [sig-cli] ([KEP]), and
inspired by [DAM].
@@ -16,9 +16,23 @@ inspired by [DAM].
[![Build Status](https://travis-ci.org/kubernetes-sigs/kustomize.svg?branch=master)](https://travis-ci.org/kubernetes-sigs/kustomize)
[![Go Report Card](https://goreportcard.com/badge/github.com/kubernetes-sigs/kustomize)](https://goreportcard.com/report/github.com/kubernetes-sigs/kustomize)
**Installation**: Download a binary from the [release
page], or see these [install] notes. Then try one of
the tested [examples].
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.
| kubectl version | kustomize version |
|---------|--------|
| v1.16.0 | [v2.0.3](https://github.com/kubernetes-sigs/kustomize/tree/v2.0.3) |
| v1.15.x | [v2.0.3](https://github.com/kubernetes-sigs/kustomize/tree/v2.0.3) |
| v1.14.x | [v2.0.3](https://github.com/kubernetes-sigs/kustomize/tree/v2.0.3) |
For examples and guides for using the kubectl integration please see the [kubectl book] or the [kubernetes documentation].
## Usage
@@ -119,51 +133,10 @@ The YAML can be directly [applied] to a cluster:
## Community
### Filing bug reports
##### A good report specifies
* the output of `kustomize version`,
* the input (the content of `kustomization.yaml`
and any files it refers to),
* the expected YAML output.
##### A _great_ report is a bug reproduction test
Kustomize has a simple test harness in the
[target package] for specifying a kustomization's
input and the expected output.
See this [example of a target test].
The pattern is
* call `NewKustTestHarness`
* specify kustomization input data (resources,
patches, etc.) as inline strings,
* call `makeKustTarget().MakeCustomizedResMap()`
* compare the actual output to expected output
In a bug reproduction test, the expected output string
initially contains the _wrong_ (unexpected) output,
thus unambiguously reproducing the bug.
Nearby comments should explain what the output
_should_ be, and have a TODO pointing to the related
issue.
The person who fixes the bug then has a clear
bug reproduction and a test to modify when
the bug is fixed.
The bug reporter can then see the bug was fixed,
and has permanent regression coverage to prevent
its reintroduction.
### Feature requests
Feature requests are welcome.
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
@@ -192,12 +165,12 @@ is governed by the [Kubernetes Code of Conduct].
[community page]: http://kubernetes.io/community/
[declarative configuration]: docs/glossary.md#declarative-application-management
[eschewed feature list]: docs/eschewedFeatures.md
[example of a target test]: https://github.com/kubernetes-sigs/kustomize/blob/master/pkg/target/baseandoverlaysmall_test.go
[examples]: examples/README.md
[imageBase]: docs/base.jpg
[imageOverlay]: docs/overlay.jpg
[install]: docs/INSTALL.md
[imageBase]: docs/images/base.jpg
[imageOverlay]: docs/images/overlay.jpg
[kind/feature]: https://github.com/kubernetes-sigs/kustomize/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
@@ -206,7 +179,8 @@ is governed by the [Kubernetes Code of Conduct].
[resource]: docs/glossary.md#resource
[resources]: docs/glossary.md#resource
[sig-cli]: https://github.com/kubernetes/community/blob/master/sig-cli/README.md
[target package]: https://github.com/kubernetes-sigs/kustomize/tree/master/pkg/target
[variant]: docs/glossary.md#variant
[variants]: docs/glossary.md#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]: docs/workflows.md

View File

@@ -0,0 +1,39 @@
// Code generated by pluginator on AnnotationsTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
package builtins
import (
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
// Add the given annotations to the given field specifications.
type AnnotationsTransformerPlugin struct {
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
func (p *AnnotationsTransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
p.Annotations = nil
p.FieldSpecs = nil
return yaml.Unmarshal(c, p)
}
func (p *AnnotationsTransformerPlugin) Transform(m resmap.ResMap) error {
t, err := transform.NewMapTransformer(
p.FieldSpecs,
p.Annotations,
)
if err != nil {
return err
}
return t.Transform(m)
}
func NewAnnotationsTransformerPlugin() resmap.TransformerPlugin {
return &AnnotationsTransformerPlugin{}
}

View File

@@ -0,0 +1,43 @@
// Code generated by pluginator on ConfigMapGenerator; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
package builtins
import (
"sigs.k8s.io/kustomize/api/kv"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
type ConfigMapGeneratorPlugin struct {
h *resmap.PluginHelpers
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
types.GeneratorOptions
types.ConfigMapArgs
}
func (p *ConfigMapGeneratorPlugin) Config(
h *resmap.PluginHelpers, config []byte) (err error) {
p.GeneratorOptions = types.GeneratorOptions{}
p.ConfigMapArgs = types.ConfigMapArgs{}
err = yaml.Unmarshal(config, p)
if p.ConfigMapArgs.Name == "" {
p.ConfigMapArgs.Name = p.Name
}
if p.ConfigMapArgs.Namespace == "" {
p.ConfigMapArgs.Namespace = p.Namespace
}
p.h = h
return
}
func (p *ConfigMapGeneratorPlugin) Generate() (resmap.ResMap, error) {
return p.h.ResmapFactory().FromConfigMapArgs(
kv.NewLoader(p.h.Loader(), p.h.Validator()),
&p.GeneratorOptions, p.ConfigMapArgs)
}
func NewConfigMapGeneratorPlugin() resmap.GeneratorPlugin {
return &ConfigMapGeneratorPlugin{}
}

8
api/builtins/doc.go Normal file
View File

@@ -0,0 +1,8 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package builtins holds code generated from the builtin plugins.
// The "builtin" plugins are written as normal plugins and can
// be used as such, but they are also used to generate the code
// in this package so they can be statically linked to client code.
package builtins

View File

@@ -0,0 +1,39 @@
// Code generated by pluginator on HashTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
package builtins
import (
"fmt"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/resmap"
)
type HashTransformerPlugin struct {
hasher ifc.KunstructuredHasher
}
func (p *HashTransformerPlugin) Config(
h *resmap.PluginHelpers, config []byte) (err error) {
p.hasher = h.ResmapFactory().RF().Hasher()
return nil
}
// Transform appends hash to generated resources.
func (p *HashTransformerPlugin) Transform(m resmap.ResMap) error {
for _, res := range m.Resources() {
if res.NeedHashSuffix() {
h, err := p.hasher.Hash(res)
if err != nil {
return err
}
res.SetName(fmt.Sprintf("%s-%s", res.GetName(), h))
}
}
return nil
}
func NewHashTransformerPlugin() resmap.TransformerPlugin {
return &HashTransformerPlugin{}
}

View File

@@ -0,0 +1,185 @@
// Code generated by pluginator on ImageTagTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
package builtins
import (
"fmt"
"regexp"
"strings"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/yaml"
)
// Find matching image declarations and replace
// the name, tag and/or digest.
type ImageTagTransformerPlugin struct {
ImageTag types.Image `json:"imageTag,omitempty" yaml:"imageTag,omitempty"`
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
func (p *ImageTagTransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
p.ImageTag = types.Image{}
p.FieldSpecs = nil
return yaml.Unmarshal(c, p)
}
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
}
}
// Kept for backward compatibility
if err := p.findAndReplaceImage(r.Map()); err != nil && r.OrgId().Kind != `CustomResourceDefinition` {
return err
}
}
return nil
}
func (p *ImageTagTransformerPlugin) mutateImage(in interface{}) (interface{}, error) {
original, ok := in.(string)
if !ok {
return nil, fmt.Errorf("image path is not of type string but %T", in)
}
if !isImageMatched(original, p.ImageTag.Name) {
return original, nil
}
name, tag := split(original)
if p.ImageTag.NewName != "" {
name = p.ImageTag.NewName
}
if p.ImageTag.NewTag != "" {
tag = ":" + p.ImageTag.NewTag
}
if p.ImageTag.Digest != "" {
tag = "@" + p.ImageTag.Digest
}
return name + tag, nil
}
// findAndReplaceImage replaces the image name and
// tags inside one object.
// It searches the object for container session
// then loops though all images inside containers
// session, finds matched ones and update the
// image name and tag name
func (p *ImageTagTransformerPlugin) findAndReplaceImage(obj map[string]interface{}) error {
paths := []string{"containers", "initContainers"}
updated := false
for _, path := range paths {
containers, found := obj[path]
if found {
if _, err := p.updateContainers(containers); err != nil {
return err
}
updated = true
}
}
if !updated {
return p.findContainers(obj)
}
return nil
}
func (p *ImageTagTransformerPlugin) updateContainers(in interface{}) (interface{}, error) {
containers, ok := in.([]interface{})
if !ok {
return nil, fmt.Errorf(
"containers path is not of type []interface{} but %T", in)
}
for i := range containers {
container := containers[i].(map[string]interface{})
containerImage, found := container["image"]
if !found {
continue
}
imageName := containerImage.(string)
if isImageMatched(imageName, p.ImageTag.Name) {
newImage, err := p.mutateImage(imageName)
if err != nil {
return nil, err
}
container["image"] = newImage
}
}
return containers, nil
}
func (p *ImageTagTransformerPlugin) findContainers(obj map[string]interface{}) error {
for key := range obj {
switch typedV := obj[key].(type) {
case map[string]interface{}:
err := p.findAndReplaceImage(typedV)
if err != nil {
return err
}
case []interface{}:
for i := range typedV {
item := typedV[i]
typedItem, ok := item.(map[string]interface{})
if ok {
err := p.findAndReplaceImage(typedItem)
if err != nil {
return err
}
}
}
}
}
return nil
}
func isImageMatched(s, t string) bool {
// Tag values are limited to [a-zA-Z0-9_.-].
pattern, _ := regexp.Compile("^" + t + "(@sha256)?(:[a-zA-Z0-9_.-]*)?$")
return pattern.MatchString(s)
}
// split separates and returns the name and tag parts
// from the image string using either colon `:` or at `@` separators.
// Note that the returned tag keeps its separator.
func split(imageName string) (name string, tag string) {
// check if image name contains a domain
// if domain is present, ignore domain and check for `:`
ic := -1
if slashIndex := strings.Index(imageName, "/"); slashIndex < 0 {
ic = strings.LastIndex(imageName, ":")
} else {
lastIc := strings.LastIndex(imageName[slashIndex:], ":")
// set ic only if `:` is present
if lastIc > 0 {
ic = slashIndex + lastIc
}
}
ia := strings.LastIndex(imageName, "@")
if ic < 0 && ia < 0 {
return imageName, ""
}
i := ic
if ia > 0 {
i = ia
}
name = imageName[:i]
tag = imageName[i:]
return
}
func NewImageTagTransformerPlugin() resmap.TransformerPlugin {
return &ImageTagTransformerPlugin{}
}

View File

@@ -0,0 +1,128 @@
// Code generated by pluginator on InventoryTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
package builtins
import (
"fmt"
"sigs.k8s.io/kustomize/api/hasher"
"sigs.k8s.io/kustomize/api/inventory"
"sigs.k8s.io/kustomize/api/kv"
"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/yaml"
)
type InventoryTransformerPlugin struct {
h *resmap.PluginHelpers
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
Policy string `json:"policy,omitempty" yaml:"policy,omitempty"`
}
func (p *InventoryTransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
p.h = h
err = yaml.Unmarshal(c, p)
if err != nil {
return err
}
if p.Policy == "" {
p.Policy = types.GarbageIgnore.String()
}
if p.Policy != types.GarbageCollect.String() &&
p.Policy != types.GarbageIgnore.String() {
return fmt.Errorf(
"unrecognized garbagePolicy '%s'", p.Policy)
}
return nil
}
// Transform generates an inventory object from the input ResMap.
// This ConfigMap supports the pruning command in
// the client side tool proposed here:
// https://github.com/kubernetes/enhancements/pull/810
//
// The inventory data is written to the ConfigMap's
// annotations, rather than to the key-value pairs in
// the ConfigMap's data field, since
// 1. Keys in a ConfigMap's data field are too
// constrained for this purpose.
// 2. Using annotations allow any object to be used,
// not just a ConfigMap, should some other object
// (e.g. some App object) become more desirable
// for this purpose.
func (p *InventoryTransformerPlugin) Transform(m resmap.ResMap) error {
inv, h, err := makeInventory(m)
if err != nil {
return err
}
args := types.ConfigMapArgs{}
args.Name = p.Name
args.Namespace = p.Namespace
opts := &types.GeneratorOptions{
Annotations: make(map[string]string),
}
opts.Annotations[inventory.HashAnnotation] = h
err = inv.UpdateAnnotations(opts.Annotations)
if err != nil {
return err
}
cm, err := p.h.ResmapFactory().RF().MakeConfigMap(
kv.NewLoader(p.h.Loader(), p.h.Validator()), opts, &args)
if err != nil {
return err
}
if p.Policy == types.GarbageCollect.String() {
for _, byeBye := range m.AllIds() {
m.Remove(byeBye)
}
}
return m.Append(cm)
}
func makeInventory(m resmap.ResMap) (
inv *inventory.Inventory, hash string, err error) {
inv = inventory.NewInventory()
var keys []string
for _, r := range m.Resources() {
ns := r.GetNamespace()
item := resid.NewResIdWithNamespace(r.GetGvk(), r.GetName(), ns)
if _, ok := inv.Current[item]; ok {
return nil, "", fmt.Errorf(
"item '%v' already in inventory", item)
}
inv.Current[item], err = computeRefs(r, m)
if err != nil {
return nil, "", err
}
keys = append(keys, item.String())
}
h, err := hasher.SortArrayAndComputeHash(keys)
return inv, h, err
}
func computeRefs(
r *resource.Resource, m resmap.ResMap) (refs []resid.ResId, err error) {
for _, refid := range r.GetRefBy() {
ref, err := m.GetByCurrentId(refid)
if err != nil {
return nil, err
}
refs = append(
refs,
resid.NewResIdWithNamespace(
ref.GetGvk(), ref.GetName(), ref.GetNamespace()))
}
return
}
func NewInventoryTransformerPlugin() resmap.TransformerPlugin {
return &InventoryTransformerPlugin{}
}

View File

@@ -0,0 +1,39 @@
// Code generated by pluginator on LabelTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
package builtins
import (
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
// Add the given labels to the given field specifications.
type LabelTransformerPlugin struct {
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
func (p *LabelTransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
p.Labels = nil
p.FieldSpecs = nil
return yaml.Unmarshal(c, p)
}
func (p *LabelTransformerPlugin) Transform(m resmap.ResMap) error {
t, err := transform.NewMapTransformer(
p.FieldSpecs,
p.Labels,
)
if err != nil {
return err
}
return t.Transform(m)
}
func NewLabelTransformerPlugin() resmap.TransformerPlugin {
return &LabelTransformerPlugin{}
}

View File

@@ -0,0 +1,46 @@
// Code generated by pluginator on LegacyOrderTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
package builtins
import (
"sort"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
)
// Sort the resources using an ordering defined in the Gvk class.
// This puts cluster-wide basic resources with no
// dependencies (like Namespace, StorageClass, etc.)
// first, and resources with a high number of dependencies
// (like ValidatingWebhookConfiguration) last.
type LegacyOrderTransformerPlugin struct{}
// Nothing needed for configuration.
func (p *LegacyOrderTransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
return nil
}
func (p *LegacyOrderTransformerPlugin) Transform(m resmap.ResMap) (err error) {
resources := make([]*resource.Resource, m.Size())
ids := m.AllIds()
sort.Sort(resmap.IdSlice(ids))
for i, id := range ids {
resources[i], err = m.GetByCurrentId(id)
if err != nil {
return errors.Wrap(err, "expected match for sorting")
}
}
m.Clear()
for _, r := range resources {
m.Append(r)
}
return nil
}
func NewLegacyOrderTransformerPlugin() resmap.TransformerPlugin {
return &LegacyOrderTransformerPlugin{}
}

View File

@@ -0,0 +1,131 @@
// Code generated by pluginator on NamespaceTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
package builtins
import (
"fmt"
"sigs.k8s.io/kustomize/api/transform"
"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/yaml"
)
// Change or set the namespace of non-cluster level resources.
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"`
}
func (p *NamespaceTransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
p.Namespace = ""
p.FieldSpecs = nil
return yaml.Unmarshal(c, p)
}
func (p *NamespaceTransformerPlugin) Transform(m resmap.ResMap) error {
if len(p.Namespace) == 0 {
return nil
}
for _, r := range m.Resources() {
if len(r.Map()) == 0 {
// Don't mutate empty objects?
continue
}
id := r.OrgId()
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
}
}
matches := m.GetMatchingResourcesByCurrentId(r.CurId().Equals)
if len(matches) != 1 {
return fmt.Errorf("namespace tranformation produces ID conflict: %#v", matches)
}
}
return nil
}
const metaNamespace = "metadata/namespace"
// Special casing metadata.namespace since
// all objects have it, even "ClusterKind" objects
// that don't exist in a namespace (the Namespace
// object itself doesn't live in a namespace).
func (p *NamespaceTransformerPlugin) applicableFieldSpecs(id resid.ResId) []types.FieldSpec {
var res []types.FieldSpec
for _, fs := range p.FieldSpecs {
if id.IsSelected(&fs.Gvk) && (fs.Path != metaNamespace || (fs.Path == metaNamespace && id.IsNamespaceableKind())) {
res = append(res, fs)
}
}
return res
}
func (p *NamespaceTransformerPlugin) changeNamespace(
referrer *resource.Resource) func(in interface{}) (interface{}, error) {
return func(in interface{}) (interface{}, error) {
switch in.(type) {
case string:
// will happen when the metadata/namespace
// value is replaced
return p.Namespace, nil
case []interface{}:
l, _ := in.([]interface{})
for idx, item := range l {
switch item.(type) {
case map[string]interface{}:
// Will happen when mutating the subjects
// field of ClusterRoleBinding and RoleBinding
inMap, _ := item.(map[string]interface{})
if _, ok := inMap["name"]; !ok {
continue
}
name, ok := inMap["name"].(string)
if !ok {
continue
}
// The only case we need to force the namespace
// if for the "service account". "default" is
// kind of hardcoded here for right now.
if name != "default" {
continue
}
inMap["namespace"] = p.Namespace
l[idx] = inMap
default:
// nothing to do for right now
}
}
return in, nil
case map[string]interface{}:
// Will happen if the createField=true
// when the namespace is added to the
// object
inMap := in.(map[string]interface{})
if len(inMap) == 0 {
return p.Namespace, nil
} else {
return in, nil
}
default:
return in, nil
}
}
}
func NewNamespaceTransformerPlugin() resmap.TransformerPlugin {
return &NamespaceTransformerPlugin{}
}

View File

@@ -0,0 +1,100 @@
// Code generated by pluginator on PatchJson6902Transformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
package builtins
import (
"fmt"
jsonpatch "github.com/evanphx/json-patch"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
type PatchJson6902TransformerPlugin struct {
ldr ifc.Loader
decodedPatch jsonpatch.Patch
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"`
}
func (p *PatchJson6902TransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
p.ldr = h.Loader()
err = yaml.Unmarshal(c, p)
if err != nil {
return err
}
if p.Target.Name == "" {
return fmt.Errorf("must specify the target name")
}
if p.Path == "" && p.JsonOp == "" {
return fmt.Errorf("empty file path and empty jsonOp")
}
if p.Path != "" {
if p.JsonOp != "" {
return fmt.Errorf("must specify a file path or jsonOp, not both")
}
rawOp, err := p.ldr.Load(p.Path)
if err != nil {
return err
}
p.JsonOp = string(rawOp)
if p.JsonOp == "" {
return fmt.Errorf("patch file '%s' empty seems to be empty", p.Path)
}
}
if p.JsonOp[0] != '[' {
// if it doesn't seem to be JSON, imagine
// it is YAML, and convert to JSON.
op, err := yaml.YAMLToJSON([]byte(p.JsonOp))
if err != nil {
return err
}
p.JsonOp = string(op)
}
p.decodedPatch, err = jsonpatch.DecodePatch([]byte(p.JsonOp))
if err != nil {
return errors.Wrapf(err, "decoding %s", p.JsonOp)
}
if len(p.decodedPatch) == 0 {
return fmt.Errorf(
"patch appears to be empty; file=%s, JsonOp=%s", p.Path, p.JsonOp)
}
return err
}
func (p *PatchJson6902TransformerPlugin) Transform(m resmap.ResMap) error {
id := resid.NewResIdWithNamespace(
resid.Gvk{
Group: p.Target.Group,
Version: p.Target.Version,
Kind: p.Target.Kind,
},
p.Target.Name,
p.Target.Namespace,
)
obj, err := m.GetById(id)
if err != nil {
return err
}
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)
}
func NewPatchJson6902TransformerPlugin() resmap.TransformerPlugin {
return &PatchJson6902TransformerPlugin{}
}

View File

@@ -0,0 +1,90 @@
// Code generated by pluginator on PatchStrategicMergeTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
package builtins
import (
"fmt"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
type PatchStrategicMergeTransformerPlugin struct {
h *resmap.PluginHelpers
loadedPatches []*resource.Resource
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
}
func (p *PatchStrategicMergeTransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
p.h = h
err = yaml.Unmarshal(c, p)
if err != nil {
return err
}
if len(p.Paths) == 0 && p.Patches == "" {
return fmt.Errorf("empty file path and empty patch content")
}
if len(p.Paths) != 0 {
for _, onePath := range p.Paths {
res, err := p.h.ResmapFactory().RF().SliceFromBytes([]byte(onePath))
if err == nil {
p.loadedPatches = append(p.loadedPatches, res...)
continue
}
res, err = p.h.ResmapFactory().RF().SliceFromPatches(
p.h.Loader(), []types.PatchStrategicMerge{onePath})
if err != nil {
return err
}
p.loadedPatches = append(p.loadedPatches, res...)
}
}
if p.Patches != "" {
res, err := p.h.ResmapFactory().RF().SliceFromBytes([]byte(p.Patches))
if err != nil {
return err
}
p.loadedPatches = append(p.loadedPatches, res...)
}
if len(p.loadedPatches) == 0 {
return fmt.Errorf(
"patch appears to be empty; files=%v, Patch=%s", p.Paths, p.Patches)
}
return err
}
func (p *PatchStrategicMergeTransformerPlugin) Transform(m resmap.ResMap) error {
patches, err := p.h.ResmapFactory().MergePatches(p.loadedPatches)
if err != nil {
return err
}
for _, patch := range patches.Resources() {
target, err := m.GetById(patch.OrgId())
if err != nil {
return err
}
err = target.Patch(patch.Kunstructured)
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
}
}
}
return nil
}
func NewPatchStrategicMergeTransformerPlugin() resmap.TransformerPlugin {
return &PatchStrategicMergeTransformerPlugin{}
}

View File

@@ -0,0 +1,145 @@
// Code generated by pluginator on PatchTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
package builtins
import (
"fmt"
jsonpatch "github.com/evanphx/json-patch"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
type PatchTransformerPlugin struct {
loadedPatch *resource.Resource
decodedPatch jsonpatch.Patch
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"`
}
func (p *PatchTransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
err = yaml.Unmarshal(c, p)
if err != nil {
return err
}
if p.Patch == "" && p.Path == "" {
err = fmt.Errorf(
"must specify one of patch and path in\n%s", string(c))
return
}
if p.Patch != "" && p.Path != "" {
err = fmt.Errorf(
"patch and path can't be set at the same time\n%s", string(c))
return
}
var in []byte
if p.Path != "" {
in, err = h.Loader().Load(p.Path)
if err != nil {
return
}
}
if p.Patch != "" {
in = []byte(p.Patch)
}
patchSM, errSM := h.ResmapFactory().RF().FromBytes(in)
patchJson, errJson := jsonPatchFromBytes(in)
if errSM != nil && errJson != nil {
err = fmt.Errorf(
"unable to get either a Strategic Merge Patch or JSON patch 6902 from %s", p.Patch)
return
}
if errSM == nil && errJson != nil {
p.loadedPatch = patchSM
}
if errJson == nil && errSM != nil {
p.decodedPatch = patchJson
}
if patchSM != nil && patchJson != nil {
err = fmt.Errorf(
"a patch can't be both a Strategic Merge Patch and JSON patch 6902 %s", p.Patch)
}
return nil
}
func (p *PatchTransformerPlugin) Transform(m resmap.ResMap) error {
if p.loadedPatch != nil && p.Target == nil {
target, err := m.GetById(p.loadedPatch.OrgId())
if err != nil {
return err
}
err = target.Patch(p.loadedPatch.Kunstructured)
if err != nil {
return err
}
return nil
}
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 {
if p.decodedPatch != nil {
rawObj, err := res.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.Patch)
}
err = res.UnmarshalJSON(modifiedObj)
if err != nil {
return err
}
}
if p.loadedPatch != nil {
patchCopy := p.loadedPatch.DeepCopy()
patchCopy.SetName(res.GetName())
patchCopy.SetNamespace(res.GetNamespace())
patchCopy.SetGvk(res.GetGvk())
err = res.Patch(patchCopy.Kunstructured)
if err != nil {
return err
}
}
}
return nil
}
// jsonPatchFromBytes loads a Json 6902 patch from
// a bytes input
func jsonPatchFromBytes(
in []byte) (jsonpatch.Patch, error) {
ops := string(in)
if ops == "" {
return nil, fmt.Errorf("empty json patch operations")
}
if ops[0] != '[' {
jsonOps, err := yaml.YAMLToJSON(in)
if err != nil {
return nil, err
}
ops = string(jsonOps)
}
return jsonpatch.DecodePatch([]byte(ops))
}
func NewPatchTransformerPlugin() resmap.TransformerPlugin {
return &PatchTransformerPlugin{}
}

View File

@@ -0,0 +1,123 @@
// Code generated by pluginator on PrefixSuffixTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
package builtins
import (
"errors"
"fmt"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"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"`
}
// 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"},
},
}
func (p *PrefixSuffixTransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
p.Prefix = ""
p.Suffix = ""
p.FieldSpecs = nil
err = yaml.Unmarshal(c, p)
if err != nil {
return
}
if p.FieldSpecs == nil {
return errors.New("fieldSpecs is not expected to be nil")
}
return
}
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() {
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
continue
}
if smellsLikeANameChange(&path) {
// "metadata/name" is the only field.
// this will add a prefix and a suffix
// to the resource even if those are
// empty
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)
if err != nil {
return err
}
}
}
return nil
}
func smellsLikeANameChange(fs *types.FieldSpec) bool {
return fs.Path == "metadata/name"
}
func (p *PrefixSuffixTransformerPlugin) shouldSkip(
id resid.ResId) bool {
for _, path := range prefixSuffixFieldSpecsToSkip {
if id.IsSelected(&path.Gvk) {
return true
}
}
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

@@ -0,0 +1,89 @@
// Code generated by pluginator on ReplicaCountTransformer; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
package builtins
import (
"fmt"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
// Find matching replicas declarations and replace the count.
// Eases the kustomization configuration of replica changes.
type ReplicaCountTransformerPlugin struct {
Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"`
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
}
func (p *ReplicaCountTransformerPlugin) Config(
h *resmap.PluginHelpers, c []byte) (err error) {
p.Replica = types.Replica{}
p.FieldSpecs = nil
return yaml.Unmarshal(c, p)
}
func (p *ReplicaCountTransformerPlugin) Transform(m resmap.ResMap) error {
found := false
for i, replicaSpec := range p.FieldSpecs {
matcher := p.createMatcher(i)
matchOriginal := m.GetMatchingResourcesByOriginalId(matcher)
matchCurrent := m.GetMatchingResourcesByCurrentId(matcher)
for _, res := range append(matchOriginal, matchCurrent...) {
found = true
err := transform.MutateField(
res.Map(), replicaSpec.PathSlice(),
replicaSpec.CreateIfNotPresent, p.addReplicas)
if err != nil {
return err
}
}
}
if !found {
gvks := make([]string, len(p.FieldSpecs))
for i, replicaSpec := range p.FieldSpecs {
gvks[i] = replicaSpec.Gvk.String()
}
return fmt.Errorf("resource with name %s does not match a config with the following GVK %v",
p.Replica.Name, gvks)
}
return nil
}
// Match Replica.Name and FieldSpec
func (p *ReplicaCountTransformerPlugin) createMatcher(i int) resmap.IdMatcher {
return func(r resid.ResId) bool {
return r.Name == p.Replica.Name &&
r.Gvk.IsSelected(&p.FieldSpecs[i].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

@@ -0,0 +1,42 @@
// Code generated by pluginator on SecretGenerator; DO NOT EDIT.
// pluginator {unknown 1970-01-01T00:00:00Z }
package builtins
import (
"sigs.k8s.io/kustomize/api/kv"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
type SecretGeneratorPlugin struct {
h *resmap.PluginHelpers
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
types.GeneratorOptions
types.SecretArgs
}
func (p *SecretGeneratorPlugin) Config(h *resmap.PluginHelpers, config []byte) (err error) {
p.GeneratorOptions = types.GeneratorOptions{}
p.SecretArgs = types.SecretArgs{}
err = yaml.Unmarshal(config, p)
if p.SecretArgs.Name == "" {
p.SecretArgs.Name = p.Name
}
if p.SecretArgs.Namespace == "" {
p.SecretArgs.Namespace = p.Namespace
}
p.h = h
return
}
func (p *SecretGeneratorPlugin) Generate() (resmap.ResMap, error) {
return p.h.ResmapFactory().FromSecretArgs(
kv.NewLoader(p.h.Loader(), p.h.Validator()),
&p.GeneratorOptions, p.SecretArgs)
}
func NewSecretGeneratorPlugin() resmap.GeneratorPlugin {
return &SecretGeneratorPlugin{}
}

View File

@@ -0,0 +1,79 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package filesys
import (
"io/ioutil"
"path/filepath"
"strings"
)
// ConfirmedDir is a clean, absolute, delinkified path
// that was confirmed to point to an existing directory.
type ConfirmedDir string
// NewTmpConfirmedDir returns a temporary dir, else error.
// The directory is cleaned, no symlinks, etc. so it's
// returned as a ConfirmedDir.
func NewTmpConfirmedDir() (ConfirmedDir, error) {
n, err := ioutil.TempDir("", "kustomize-")
if err != nil {
return "", err
}
// In MacOs `ioutil.TempDir` creates a directory
// with root in the `/var` folder, which is in turn
// a symlinked path to `/private/var`.
// Function `filepath.EvalSymlinks`is used to
// resolve the real absolute path.
deLinked, err := filepath.EvalSymlinks(n)
return ConfirmedDir(deLinked), err
}
// HasPrefix returns true if the directory argument
// is a prefix of self (d) from the point of view of
// a file system.
//
// I.e., it's true if the argument equals or contains
// self (d) in a file path sense.
//
// HasPrefix emulates the semantics of strings.HasPrefix
// such that the following are true:
//
// strings.HasPrefix("foobar", "foobar")
// strings.HasPrefix("foobar", "foo")
// strings.HasPrefix("foobar", "")
//
// d := fSys.ConfirmDir("/foo/bar")
// d.HasPrefix("/foo/bar")
// d.HasPrefix("/foo")
// d.HasPrefix("/")
//
// Not contacting a file system here to check for
// actual path existence.
//
// This is tested on linux, but will have trouble
// on other operating systems.
// TODO(monopole) Refactor when #golang/go/18358 closes.
// See also:
// https://github.com/golang/go/issues/18358
// https://github.com/golang/dep/issues/296
// https://github.com/golang/dep/blob/master/internal/fs/fs.go#L33
// https://codereview.appspot.com/5712045
func (d ConfirmedDir) HasPrefix(path ConfirmedDir) bool {
if path.String() == string(filepath.Separator) || path == d {
return true
}
return strings.HasPrefix(
string(d),
string(path)+string(filepath.Separator))
}
func (d ConfirmedDir) Join(path string) string {
return filepath.Join(string(d), path)
}
func (d ConfirmedDir) String() string {
return string(d)
}

View File

@@ -1,28 +1,17 @@
/*
Copyright 2018 The Kubernetes Authors.
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fs
package filesys_test
import (
"path/filepath"
"testing"
. "sigs.k8s.io/kustomize/api/filesys"
)
func TestJoin(t *testing.T) {
fSys := MakeFakeFS()
fSys := MakeFsInMemory()
err := fSys.Mkdir("/foo")
if err != nil {
t.Fatalf("unexpected err: %v", err)
@@ -40,7 +29,8 @@ func TestJoin(t *testing.T) {
}
func TestHasPrefix_Slash(t *testing.T) {
d, f, err := MakeFakeFS().CleanedAbs("/")
fSys := MakeFsInMemory()
d, f, err := fSys.CleanedAbs("/")
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
@@ -56,7 +46,7 @@ func TestHasPrefix_Slash(t *testing.T) {
}
func TestHasPrefix_SlashFoo(t *testing.T) {
fSys := MakeFakeFS()
fSys := MakeFsInMemory()
err := fSys.Mkdir("/foo")
if err != nil {
t.Fatalf("unexpected err: %v", err)
@@ -77,7 +67,7 @@ func TestHasPrefix_SlashFoo(t *testing.T) {
}
func TestHasPrefix_SlashFooBar(t *testing.T) {
fSys := MakeFakeFS()
fSys := MakeFsInMemory()
err := fSys.MkdirAll("/foo/bar")
if err != nil {
t.Fatalf("unexpected err: %v", err)

41
api/filesys/file.go Normal file
View File

@@ -0,0 +1,41 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package filesys
import (
"io"
"os"
"time"
)
var _ os.FileInfo = &fileInfo{}
// fileInfo implements os.FileInfo for a fileInMemory instance.
type fileInfo struct {
*fileInMemory
}
// Name returns the name of the file
func (fi *fileInfo) Name() string { return fi.name }
// Size returns the size of the file
func (fi *fileInfo) Size() int64 { return int64(len(fi.content)) }
// Mode returns the file mode
func (fi *fileInfo) Mode() os.FileMode { return 0777 }
// ModTime returns the modification time
func (fi *fileInfo) ModTime() time.Time { return time.Time{} }
// IsDir returns if it is a directory
func (fi *fileInfo) IsDir() bool { return fi.dir }
// Sys should return underlying data source, but it now returns nil
func (fi *fileInfo) Sys() interface{} { return nil }
// File groups the basic os.File methods.
type File interface {
io.ReadWriteCloser
Stat() (os.FileInfo, error)
}

View File

@@ -0,0 +1,56 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package filesys
import (
"bytes"
"os"
)
var _ File = &fileInMemory{}
// fileInMemory implements File in-memory for tests.
type fileInMemory struct {
name string
content []byte
dir bool
open bool
}
// makeDir makes a fake directory.
func makeDir(name string) *fileInMemory {
return &fileInMemory{name: name, dir: true}
}
// Close marks the fake file closed.
func (f *fileInMemory) Close() error {
f.open = false
return nil
}
// Read never fails, and doesn't mutate p.
func (f *fileInMemory) Read(p []byte) (n int, err error) {
return len(p), nil
}
// Write saves the contents of the argument to memory.
func (f *fileInMemory) Write(p []byte) (n int, err error) {
f.content = p
return len(p), nil
}
// ContentMatches returns true if v matches fake file's content.
func (f *fileInMemory) ContentMatches(v []byte) bool {
return bytes.Equal(v, f.content)
}
// GetContent the content of a fake file.
func (f *fileInMemory) GetContent() []byte {
return f.content
}
// Stat returns nil.
func (f *fileInMemory) Stat() (os.FileInfo, error) {
return nil, nil
}

27
api/filesys/fileondisk.go Normal file
View File

@@ -0,0 +1,27 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package filesys
import (
"os"
)
var _ File = &fileOnDisk{}
// fileOnDisk implements File using the local filesystem.
type fileOnDisk struct {
file *os.File
}
// Close closes a file.
func (f *fileOnDisk) Close() error { return f.file.Close() }
// Read reads a file's content.
func (f *fileOnDisk) Read(p []byte) (n int, err error) { return f.file.Read(p) }
// Write writes bytes to a file
func (f *fileOnDisk) Write(p []byte) (n int, err error) { return f.file.Write(p) }
// Stat returns an interface which has all the information regarding the file.
func (f *fileOnDisk) Stat() (os.FileInfo, error) { return f.file.Stat() }

41
api/filesys/filesystem.go Normal file
View File

@@ -0,0 +1,41 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package filesys provides a file system abstraction layer.
package filesys
import (
"path/filepath"
)
// FileSystem groups basic os filesystem methods.
type FileSystem interface {
// Create a file.
Create(name string) (File, error)
// MkDir makes a directory.
Mkdir(path string) error
// MkDir makes a directory path, creating intervening directories.
MkdirAll(path string) error
// RemoveAll removes path and any children it contains.
RemoveAll(path string) error
// Open opens the named file for reading.
Open(path string) (File, error)
// IsDir returns true if the path is a directory.
IsDir(path string) bool
// CleanedAbs converts the given path into a
// directory and a file name, where the directory
// is represented as a ConfirmedDir and all that implies.
// If the entire path is a directory, the file component
// is an empty string.
CleanedAbs(path string) (ConfirmedDir, string, error)
// Exists is true if the path exists in the file system.
Exists(path string) bool
// Glob returns the list of matching files
Glob(pattern string) ([]string, error)
// ReadFile returns the contents of the file at the given path.
ReadFile(path string) ([]byte, error)
// WriteFile writes the data to a file at the given path.
WriteFile(path string, data []byte) error
// Walk walks the file system with the given WalkFunc.
Walk(path string, walkFn filepath.WalkFunc) error
}

223
api/filesys/fsinmemory.go Normal file
View File

@@ -0,0 +1,223 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package filesys
import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"
)
var _ FileSystem = &fsInMemory{}
// fsInMemory implements FileSystem using a in-memory filesystem
// primarily for use in tests.
type fsInMemory struct {
m map[string]*fileInMemory
}
// MakeFsInMemory returns an instance of fsInMemory with no files in it.
func MakeFsInMemory() FileSystem {
result := &fsInMemory{m: map[string]*fileInMemory{}}
result.Mkdir(separator)
return result
}
const (
separator = string(filepath.Separator)
doubleSep = separator + separator
)
// Create assures a fake file appears in the in-memory file system.
func (fs *fsInMemory) Create(name string) (File, error) {
f := &fileInMemory{}
f.open = true
fs.m[name] = f
return fs.m[name], nil
}
// Mkdir assures a fake directory appears in the in-memory file system.
func (fs *fsInMemory) Mkdir(name string) error {
fs.m[name] = makeDir(name)
return nil
}
// MkdirAll delegates to Mkdir
func (fs *fsInMemory) MkdirAll(name string) error {
return fs.Mkdir(name)
}
// RemoveAll presumably does rm -r on a path.
// There's no error.
func (fs *fsInMemory) RemoveAll(name string) error {
var toRemove []string
for k := range fs.m {
if strings.HasPrefix(k, name) {
toRemove = append(toRemove, k)
}
}
for _, k := range toRemove {
delete(fs.m, k)
}
return nil
}
// Open returns a fake file in the open state.
func (fs *fsInMemory) Open(name string) (File, error) {
if _, found := fs.m[name]; !found {
return nil, fmt.Errorf("file %q cannot be opened", name)
}
return fs.m[name], nil
}
// CleanedAbs cannot fail.
func (fs *fsInMemory) CleanedAbs(path string) (ConfirmedDir, string, error) {
if fs.IsDir(path) {
return ConfirmedDir(path), "", nil
}
d := filepath.Dir(path)
if d == path {
return ConfirmedDir(d), "", nil
}
return ConfirmedDir(d), filepath.Base(path), nil
}
// Exists returns true if file is known.
func (fs *fsInMemory) Exists(name string) bool {
_, found := fs.m[name]
return found
}
// Glob returns the list of matching files
func (fs *fsInMemory) Glob(pattern string) ([]string, error) {
var result []string
for p := range fs.m {
if fs.pathMatch(p, pattern) {
result = append(result, p)
}
}
sort.Strings(result)
return result, nil
}
// IsDir returns true if the file exists and is a directory.
func (fs *fsInMemory) IsDir(name string) bool {
f, found := fs.m[name]
if found && f.dir {
return true
}
if !strings.HasSuffix(name, separator) {
name = name + separator
}
for k := range fs.m {
if strings.HasPrefix(k, name) {
return true
}
}
return false
}
// ReadFile always returns an empty bytes and error depending on content of m.
func (fs *fsInMemory) ReadFile(name string) ([]byte, error) {
if ff, found := fs.m[name]; found {
return ff.content, nil
}
return nil, fmt.Errorf("cannot read file %q", name)
}
// WriteFile always succeeds and does nothing.
func (fs *fsInMemory) WriteFile(name string, c []byte) error {
ff := &fileInMemory{}
ff.Write(c)
fs.m[name] = ff
return nil
}
// Walk implements filepath.Walk using the fake filesystem.
func (fs *fsInMemory) Walk(path string, walkFn filepath.WalkFunc) error {
info, err := fs.lstat(path)
if err != nil {
err = walkFn(path, info, err)
} else {
err = fs.walk(path, info, walkFn)
}
if err == filepath.SkipDir {
return nil
}
return err
}
func (fs *fsInMemory) pathMatch(path, pattern string) bool {
match, _ := filepath.Match(pattern, path)
return match
}
func (fs *fsInMemory) lstat(path string) (*fileInfo, error) {
f, found := fs.m[path]
if !found {
return nil, os.ErrNotExist
}
return &fileInfo{f}, nil
}
func (fs *fsInMemory) join(elem ...string) string {
for i, e := range elem {
if e != "" {
return strings.Replace(
strings.Join(elem[i:], separator), doubleSep, separator, -1)
}
}
return ""
}
func (fs *fsInMemory) readDirNames(path string) []string {
var names []string
if !strings.HasSuffix(path, separator) {
path += separator
}
pathSegments := strings.Count(path, separator)
for name := range fs.m {
if name == path {
continue
}
if strings.Count(name, separator) > pathSegments {
continue
}
if strings.HasPrefix(name, path) {
names = append(names, filepath.Base(name))
}
}
sort.Strings(names)
return names
}
func (fs *fsInMemory) walk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
if !info.IsDir() {
return walkFn(path, info, nil)
}
names := fs.readDirNames(path)
if err := walkFn(path, info, nil); err != nil {
return err
}
for _, name := range names {
filename := fs.join(path, name)
fileInfo, err := fs.lstat(filename)
if err != nil {
if err := walkFn(filename, fileInfo, os.ErrNotExist); err != nil && err != filepath.SkipDir {
return err
}
} else {
err = fs.walk(filename, fileInfo, walkFn)
if err != nil {
if !fileInfo.IsDir() || err != filepath.SkipDir {
return err
}
}
}
}
return nil
}

View File

@@ -0,0 +1,149 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package filesys_test
import (
"bytes"
"reflect"
"testing"
. "sigs.k8s.io/kustomize/api/filesys"
)
func TestExists(t *testing.T) {
fSys := MakeFsInMemory()
if fSys.Exists("foo") {
t.Fatalf("expected no foo")
}
fSys.Mkdir("/")
if !fSys.IsDir("/") {
t.Fatalf("expected dir at /")
}
}
func TestIsDir(t *testing.T) {
fSys := MakeFsInMemory()
expectedName := "my-dir"
err := fSys.Mkdir(expectedName)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
shouldExist(t, fSys, expectedName)
if !fSys.IsDir(expectedName) {
t.Fatalf(expectedName + " should be a dir")
}
}
func shouldExist(t *testing.T, fSys FileSystem, name string) {
if !fSys.Exists(name) {
t.Fatalf(name + " should exist")
}
}
func shouldNotExist(t *testing.T, fSys FileSystem, name string) {
if fSys.Exists(name) {
t.Fatalf(name + " should not exist")
}
}
func TestRemoveAll(t *testing.T) {
fSys := MakeFsInMemory()
fSys.WriteFile("/foo/project/file.yaml", []byte("Unused"))
fSys.WriteFile("/foo/project/subdir/file.yaml", []byte("Unused"))
fSys.WriteFile("/foo/apple/subdir/file.yaml", []byte("Unused"))
shouldExist(t, fSys, "/foo/project/file.yaml")
shouldExist(t, fSys, "/foo/project/subdir/file.yaml")
shouldExist(t, fSys, "/foo/apple/subdir/file.yaml")
err := fSys.RemoveAll("/foo/project")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
shouldNotExist(t, fSys, "/foo/project/file.yaml")
shouldNotExist(t, fSys, "/foo/project/subdir/file.yaml")
shouldExist(t, fSys, "/foo/apple/subdir/file.yaml")
}
func TestIsDirDeeper(t *testing.T) {
fSys := MakeFsInMemory()
fSys.WriteFile("/foo/project/file.yaml", []byte("Unused"))
fSys.WriteFile("/foo/project/subdir/file.yaml", []byte("Unused"))
if !fSys.IsDir("/") {
t.Fatalf("/ should be a dir")
}
if !fSys.IsDir("/foo") {
t.Fatalf("/foo should be a dir")
}
if !fSys.IsDir("/foo/project") {
t.Fatalf("/foo/project should be a dir")
}
if fSys.IsDir("/fo") {
t.Fatalf("/fo should not be a dir")
}
if fSys.IsDir("/x") {
t.Fatalf("/x should not be a dir")
}
}
func TestCreate(t *testing.T) {
fSys := MakeFsInMemory()
f, err := fSys.Create("foo")
if f == nil {
t.Fatalf("expected file")
}
if err != nil {
t.Fatalf("unexpected error")
}
shouldExist(t, fSys, "foo")
}
func TestReadFile(t *testing.T) {
fSys := MakeFsInMemory()
f, err := fSys.Create("foo")
if f == nil {
t.Fatalf("expected file")
}
if err != nil {
t.Fatalf("unexpected error")
}
content, err := fSys.ReadFile("foo")
if len(content) != 0 {
t.Fatalf("expected no content")
}
if err != nil {
t.Fatalf("expected no error")
}
}
func TestWriteFile(t *testing.T) {
fSys := MakeFsInMemory()
c := []byte("heybuddy")
err := fSys.WriteFile("foo", c)
if err != nil {
t.Fatalf("expected no error")
}
content, err := fSys.ReadFile("foo")
if err != nil {
t.Fatalf("expected read to work: %v", err)
}
if bytes.Compare(c, content) != 0 {
t.Fatalf("incorrect content: %v", content)
}
}
func TestGlob(t *testing.T) {
fSys := MakeFsInMemory()
fSys.Create("dir/foo")
fSys.Create("dir/bar")
files, err := fSys.Glob("dir/*")
if err != nil {
t.Fatalf("expected no error")
}
expected := []string{
"dir/bar",
"dir/foo",
}
if !reflect.DeepEqual(files, expected) {
t.Fatalf("incorrect files found by glob: %v", files)
}
}

114
api/filesys/fsondisk.go Normal file
View File

@@ -0,0 +1,114 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package filesys
import (
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
)
var _ FileSystem = fsOnDisk{}
// fsOnDisk implements FileSystem using the local filesystem.
type fsOnDisk struct{}
// MakeFsOnDisk makes an instance of fsOnDisk.
func MakeFsOnDisk() FileSystem {
return fsOnDisk{}
}
// Create delegates to os.Create.
func (fsOnDisk) Create(name string) (File, error) { return os.Create(name) }
// Mkdir delegates to os.Mkdir.
func (fsOnDisk) Mkdir(name string) error {
return os.Mkdir(name, 0777|os.ModeDir)
}
// MkdirAll delegates to os.MkdirAll.
func (fsOnDisk) MkdirAll(name string) error {
return os.MkdirAll(name, 0777|os.ModeDir)
}
// RemoveAll delegates to os.RemoveAll.
func (fsOnDisk) RemoveAll(name string) error {
return os.RemoveAll(name)
}
// Open delegates to os.Open.
func (fsOnDisk) Open(name string) (File, error) { return os.Open(name) }
// CleanedAbs converts the given path into a
// directory and a file name, where the directory
// is represented as a ConfirmedDir and all that implies.
// If the entire path is a directory, the file component
// is an empty string.
func (x fsOnDisk) CleanedAbs(
path string) (ConfirmedDir, string, error) {
absRoot, err := filepath.Abs(path)
if err != nil {
return "", "", fmt.Errorf(
"abs path error on '%s' : %v", path, err)
}
deLinked, err := filepath.EvalSymlinks(absRoot)
if err != nil {
return "", "", fmt.Errorf(
"evalsymlink failure on '%s' : %v", path, err)
}
if x.IsDir(deLinked) {
return ConfirmedDir(deLinked), "", nil
}
d := filepath.Dir(deLinked)
if !x.IsDir(d) {
// Programmer/assumption error.
log.Fatalf("first part of '%s' not a directory", deLinked)
}
if d == deLinked {
// Programmer/assumption error.
log.Fatalf("d '%s' should be a subset of deLinked", d)
}
f := filepath.Base(deLinked)
if filepath.Join(d, f) != deLinked {
// Programmer/assumption error.
log.Fatalf("these should be equal: '%s', '%s'",
filepath.Join(d, f), deLinked)
}
return ConfirmedDir(d), f, nil
}
// Exists returns true if os.Stat succeeds.
func (fsOnDisk) Exists(name string) bool {
_, err := os.Stat(name)
return err == nil
}
// Glob returns the list of matching files
func (fsOnDisk) Glob(pattern string) ([]string, error) {
return filepath.Glob(pattern)
}
// IsDir delegates to os.Stat and FileInfo.IsDir
func (fsOnDisk) IsDir(name string) bool {
info, err := os.Stat(name)
if err != nil {
return false
}
return info.IsDir()
}
// ReadFile delegates to ioutil.ReadFile.
func (fsOnDisk) ReadFile(name string) ([]byte, error) { return ioutil.ReadFile(name) }
// WriteFile delegates to ioutil.WriteFile with read/write permissions.
func (fsOnDisk) WriteFile(name string, c []byte) error {
return ioutil.WriteFile(name, c, 0666)
}
// Walk delegates to filepath.Walk.
func (fsOnDisk) Walk(path string, walkFn filepath.WalkFunc) error {
return filepath.Walk(path, walkFn)
}

View File

@@ -0,0 +1,165 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package filesys_test
import (
"io/ioutil"
"os"
"path"
"path/filepath"
"reflect"
"testing"
. "sigs.k8s.io/kustomize/api/filesys"
)
func makeTestDir(t *testing.T) (FileSystem, string) {
fSys := MakeFsOnDisk()
td, err := ioutil.TempDir("", "kustomize_testing_dir")
if err != nil {
t.Fatalf("unexpected error %s", err)
}
testDir, err := filepath.EvalSymlinks(td)
if err != nil {
t.Fatalf("unexpected error %s", err)
}
if !fSys.Exists(testDir) {
t.Fatalf("expected existence")
}
if !fSys.IsDir(testDir) {
t.Fatalf("expected directory")
}
return fSys, testDir
}
func TestCleanedAbs_1(t *testing.T) {
fSys, testDir := makeTestDir(t)
defer os.RemoveAll(testDir)
d, f, err := fSys.CleanedAbs("")
if err != nil {
t.Fatalf("unexpected err=%v", err)
}
wd, err := os.Getwd()
if err != nil {
t.Fatalf("unexpected err=%v", err)
}
if d.String() != wd {
t.Fatalf("unexpected d=%s", d)
}
if f != "" {
t.Fatalf("unexpected f=%s", f)
}
}
func TestCleanedAbs_2(t *testing.T) {
fSys, testDir := makeTestDir(t)
defer os.RemoveAll(testDir)
d, f, err := fSys.CleanedAbs("/")
if err != nil {
t.Fatalf("unexpected err=%v", err)
}
if d != "/" {
t.Fatalf("unexpected d=%s", d)
}
if f != "" {
t.Fatalf("unexpected f=%s", f)
}
}
func TestCleanedAbs_3(t *testing.T) {
fSys, testDir := makeTestDir(t)
defer os.RemoveAll(testDir)
err := fSys.WriteFile(
filepath.Join(testDir, "foo"), []byte(`foo`))
if err != nil {
t.Fatalf("unexpected err=%v", err)
}
d, f, err := fSys.CleanedAbs(filepath.Join(testDir, "foo"))
if err != nil {
t.Fatalf("unexpected err=%v", err)
}
if d.String() != testDir {
t.Fatalf("unexpected d=%s", d)
}
if f != "foo" {
t.Fatalf("unexpected f=%s", f)
}
}
func TestCleanedAbs_4(t *testing.T) {
fSys, testDir := makeTestDir(t)
defer os.RemoveAll(testDir)
err := fSys.MkdirAll(filepath.Join(testDir, "d1", "d2"))
if err != nil {
t.Fatalf("unexpected err=%v", err)
}
err = fSys.WriteFile(
filepath.Join(testDir, "d1", "d2", "bar"),
[]byte(`bar`))
if err != nil {
t.Fatalf("unexpected err=%v", err)
}
d, f, err := fSys.CleanedAbs(
filepath.Join(testDir, "d1", "d2"))
if err != nil {
t.Fatalf("unexpected err=%v", err)
}
if d.String() != filepath.Join(testDir, "d1", "d2") {
t.Fatalf("unexpected d=%s", d)
}
if f != "" {
t.Fatalf("unexpected f=%s", f)
}
d, f, err = fSys.CleanedAbs(
filepath.Join(testDir, "d1", "d2", "bar"))
if err != nil {
t.Fatalf("unexpected err=%v", err)
}
if d.String() != filepath.Join(testDir, "d1", "d2") {
t.Fatalf("unexpected d=%s", d)
}
if f != "bar" {
t.Fatalf("unexpected f=%s", f)
}
}
func TestReadFilesRealFS(t *testing.T) {
fSys, testDir := makeTestDir(t)
defer os.RemoveAll(testDir)
err := fSys.WriteFile(path.Join(testDir, "foo"), []byte(`foo`))
if err != nil {
t.Fatalf("unexpected error %s", err)
}
if !fSys.Exists(path.Join(testDir, "foo")) {
t.Fatalf("expected foo")
}
if fSys.IsDir(path.Join(testDir, "foo")) {
t.Fatalf("expected foo not to be a directory")
}
err = fSys.WriteFile(path.Join(testDir, "bar"), []byte(`bar`))
if err != nil {
t.Fatalf("unexpected error %s", err)
}
files, err := fSys.Glob(path.Join("testDir", "*"))
expected := []string{
path.Join(testDir, "bar"),
path.Join(testDir, "foo"),
}
if err != nil {
t.Fatalf("expected no error")
}
if reflect.DeepEqual(files, expected) {
t.Fatalf("incorrect files found by glob: %v", files)
}
}

12
api/filesys/rpath.go Normal file
View File

@@ -0,0 +1,12 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package filesys
import "path/filepath"
// RootedPath returns a rooted path, e.g. "/foo/bar" as
// opposed to "foo/bar".
func RootedPath(elem ...string) string {
return separator + filepath.Join(elem...)
}

18
api/go.mod Normal file
View File

@@ -0,0 +1,18 @@
module sigs.k8s.io/kustomize/api
go 1.13
require (
github.com/emicklei/go-restful v2.9.6+incompatible // indirect
github.com/evanphx/json-patch v4.5.0+incompatible
github.com/go-openapi/spec v0.19.4
github.com/golangci/golangci-lint v1.19.1
github.com/googleapis/gnostic v0.3.0 // indirect
github.com/monopole/mdrip v1.0.0
github.com/pkg/errors v0.8.1
golang.org/x/tools v0.0.0-20190912215617-3720d1ec3678
gopkg.in/yaml.v2 v2.2.4
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
sigs.k8s.io/kustomize/pseudo/k8s v0.1.0
sigs.k8s.io/yaml v1.1.0
)

463
api/go.sum Normal file
View File

@@ -0,0 +1,463 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
github.com/Azure/go-autorest/autorest v0.9.2/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OpenPeeDeeP/depguard v1.0.1 h1:VlW4R6jmBIv3/u1JNlawEvJMM4J+dPORPaZasQee8Us=
github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM=
github.com/PuerkitoBio/purell v1.0.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/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.6+incompatible h1:tfrHha8zJ01ywiOEC1miGY8st1/igzWB8OmvPgoYX7w=
github.com/emicklei/go-restful v2.9.6+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db h1:GYXWx7Vr3+zv833u+8IoXbNnQY0AdXsxAgI0kX7xcwA=
github.com/go-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-lintpack/lintpack v0.5.2 h1:DI5mA3+eKdWeJ40nU4d6Wc26qmdG8RCi/btYq0TuRN0=
github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
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.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=
github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g=
github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
github.com/go-toolsmith/astcopy v1.0.0 h1:OMgl1b1MEpjFQ1m5ztEO06rz5CUd3oBv9RF7+DyvdG8=
github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ=
github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
github.com/go-toolsmith/astequal v1.0.0 h1:4zxD8j3JRFNyLN46lodQuqz3xdKSrur7U/sr0SDS/gQ=
github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg=
github.com/go-toolsmith/astfmt v1.0.0 h1:A0vDDXt+vsvLEdbMFJAUBI/uTbRw1ffOPnxsILnFL6k=
github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw=
github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU=
github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk=
github.com/go-toolsmith/astp v1.0.0 h1:alXE75TXgcmupDsMK1fRAy0YUzLzqPVvBKoyWV+KPXg=
github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI=
github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks=
github.com/go-toolsmith/pkgload v1.0.0 h1:4DFWWMXVfbcN5So1sBNW9+yeiMqLFGl1wFLTL5R0Tgg=
github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc=
github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4=
github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
github.com/go-toolsmith/typep v1.0.0 h1:zKymWyA1TRYvqYrYDrfEMZULyrhcnGY3x7LDKU2XQaA=
github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/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-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0=
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM=
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6 h1:YYWNAGTKWhKpcLLt7aSj/odlKrSrelQwlovBpDuf19w=
github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0=
github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 h1:9kfjN3AdxcbsZBf8NjltjWihK2QfBBBZuv91cMFfDHw=
github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8=
github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3 h1:pe9JHs3cHHDQgOFXJJdYkK6fLz2PWyYtP4hthoCMvs8=
github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o=
github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee h1:J2XAy40+7yz70uaOiMbNnluTg7gyQhtGqLQncQh+4J8=
github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU=
github.com/golangci/gofmt v0.0.0-20181222123516-0b8337e80d98 h1:0OkFarm1Zy2CjCiDKfK9XHgmc2wbDlRMD2hD8anAJHU=
github.com/golangci/gofmt v0.0.0-20181222123516-0b8337e80d98/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU=
github.com/golangci/golangci-lint v1.19.1 h1:g9xL8KW7UZDCkVlgHYJMA6F4Sj/sRVa0FoCeXI+Z3iM=
github.com/golangci/golangci-lint v1.19.1/go.mod h1:2CEc4Fxx3vxDv7g8DyXkHCBF73AOzAymcJAprs2vCps=
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc h1:gLLhTLMk2/SutryVJ6D4VZCU3CUqr8YloG7FPIBWFpI=
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU=
github.com/golangci/lint-1 v0.0.0-20190420132249-ee948d087217 h1:En/tZdwhAn0JNwLuXzP3k2RVtMqMmOEK7Yu/g3tmtJE=
github.com/golangci/lint-1 v0.0.0-20190420132249-ee948d087217/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA=
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o=
github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770 h1:EL/O5HGrF7Jaq0yNhBLucz9hTuRzj2LdwGBOaENgxIk=
github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA=
github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21 h1:leSNB7iYzLYSSx3J/s5sVf4Drkc68W2wm4Ixh/mr0us=
github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI=
github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0 h1:HVfrLniijszjS1aiNg8JbBMO2+E1WIQ+j/gL4SQqGPg=
github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4=
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys=
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0=
github.com/googleapis/gnostic v0.3.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gophercloud/gophercloud v0.6.0/go.mod h1:GICNByuaEBibcjmjvI7QvYJSZEbGkcYwAR7EZK2WMqM=
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f h1:9oNbS1z4rVpbnkHBdPZU4jo9bSmrLpII768arSyMFgk=
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.0 h1:UykbtMB/w5No2LmE16gINgLj+r/vbziTgaoERQv6U+0=
github.com/gorilla/mux v1.6.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/securecookie v0.0.0-20160422134519-667fe4e3466a h1:YH0IojQwndMQdeRWdw1aPT8bkbiWaYR3WD+Zf5e09DU=
github.com/gorilla/securecookie v0.0.0-20160422134519-667fe4e3466a/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v0.0.0-20160922145804-ca9ada445741 h1:OuuPl66BpF1q3OEkaPpp+VfzxrBBY62ATGdWqql/XX8=
github.com/gorilla/sessions v0.0.0-20160922145804-ca9ada445741/go.mod h1:+WVp8kdw6VhyKExm03PAMRn2ZxnPtm58pV0dBVPdhHE=
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3 h1:JVnpOZS+qxli+rgVl98ILOXVNbW+kb5wcxeGx8ShUIw=
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
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=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/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/matoous/godox v0.0.0-20190910121045-032ad8106c86 h1:q6SrfsK4FojRnJ1j8+8OJzyq3g9Y1oSVyL6nYGJXXBk=
github.com/matoous/godox v0.0.0-20190910121045-032ad8106c86/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
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/monopole/mdrip v1.0.0 h1:RFDBa+tab6mW+gX4Ww2SZDc4kS6p01FwnLtgz64Il+I=
github.com/monopole/mdrip v1.0.0/go.mod h1:N1/ppRG9CaPeUKAUHZ3dUlfOT81lTpKZLkyhCvTETwM=
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=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d h1:AREM5mwr4u1ORQBMvzfzBgpsctsbQikCVpvC+tX285E=
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
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/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=
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday v2.0.0+incompatible h1:cBXrhZNUf9C+La9/YpS+UHpUT8YD6Td9ZMSU9APFcsk=
github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/securego/gosec v0.0.0-20190912120752-140048b2a218 h1:O0yPHYL49quNL4Oj2wVq+zbGMu4dAM6iLoOQtm49TrQ=
github.com/securego/gosec v0.0.0-20190912120752-140048b2a218/go.mod h1:q6oYAujd2qyeU4cJqIri4LBIgdHXGvxWHZ1E29HNFRE=
github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e h1:MZM7FHLqUHYI0Y/mQAt3d2aYa0SiNms/hFqC9qJYolM=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041 h1:llrF3Fs4018ePo4+G/HV/uQUqEI1HMDjCeOf2V6puPc=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sourcegraph/go-diff v0.5.1 h1:gO6i5zugwzo1RVTvgvfwCOSVegNuvnNi6bAD1QCmkHs=
github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
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/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
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=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec h1:AmoEvWAO3nDx1MEcMzPh+GzOOIA5Znpv6++c7bePPY0=
github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ultraware/funlen v0.0.2 h1:Av96YVBwwNSe4MLR7iI/BIa3VyI7/djnto/pK3Uxbdo=
github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
github.com/ultraware/whitespace v0.0.3 h1:S5BCRRB5sttNy0bSOhbpw+0mb+cHiCmWfrvxpEzuUk0=
github.com/ultraware/whitespace v0.0.3/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s=
github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
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=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190909003024-a7b16738d86b h1:XfVGCX+0T4WOStkaOsJRllbsiImhB2jgVBGc9L0lPGc=
golang.org/x/net v0.0.0-20190909003024-a7b16738d86b/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-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=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190911201528-7ad0cfa0b7b5 h1:SW/0nsKCUaozCUtZTakri5laocGx/5bkDSSLrFUsa5s=
golang.org/x/sys v0.0.0-20190911201528-7ad0cfa0b7b5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/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=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911230505-6bfd74cf029c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190912215617-3720d1ec3678 h1:rM1Udd0CgtYI3KUIhu9ROz0QCqjW+n/ODp/hH7c60Xc=
golang.org/x/tools v0.0.0-20190912215617-3720d1ec3678/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
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=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
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-20191030222137-2b95a09bc58d/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=
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo=
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/pseudo/k8s v0.0.0-20191108212413-1f86a0ca5d6c h1:t7fk+ljA3Ru4pro+/0RuOAZcODDhByL1fvIdyHLhjTY=
sigs.k8s.io/kustomize/pseudo/k8s v0.0.0-20191108212413-1f86a0ca5d6c/go.mod h1:bl/gVJgYYhJZCZdYU2BfnaKYAlqFkgbJEkpl302jEss=
sigs.k8s.io/kustomize/pseudo/k8s v0.1.0 h1:otg4dLFc03c3gzl+2CV8GPGcd1kk8wjXwD+UhhcCn5I=
sigs.k8s.io/kustomize/pseudo/k8s v0.1.0/go.mod h1:bl/gVJgYYhJZCZdYU2BfnaKYAlqFkgbJEkpl302jEss=
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=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4 h1:JPJh2pk3+X4lXAkZIk2RuE/7/FoK9maXw+TNPJhVS/c=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=

52
api/hasher/hasher.go Normal file
View File

@@ -0,0 +1,52 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package hasher
import (
"crypto/sha256"
"encoding/json"
"fmt"
"sort"
)
// SortArrayAndComputeHash sorts a string array and
// returns a hash for it
func SortArrayAndComputeHash(s []string) (string, error) {
sort.Strings(s)
data, err := json.Marshal(s)
if err != nil {
return "", err
}
return Encode(Hash(string(data)))
}
// Copied from https://github.com/kubernetes/kubernetes
// /blob/master/pkg/kubectl/util/hash/hash.go
func Encode(hex string) (string, error) {
if len(hex) < 10 {
return "", fmt.Errorf(
"input length must be at least 10")
}
enc := []rune(hex[:10])
for i := range enc {
switch enc[i] {
case '0':
enc[i] = 'g'
case '1':
enc[i] = 'h'
case '3':
enc[i] = 'k'
case 'a':
enc[i] = 'm'
case 'e':
enc[i] = 't'
}
}
return string(enc), nil
}
// Hash returns the hex form of the sha256 of the argument.
func Hash(data string) string {
return fmt.Sprintf("%x", sha256.Sum256([]byte(data)))
}

41
api/hasher/hasher_test.go Normal file
View File

@@ -0,0 +1,41 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package hasher_test
import (
"testing"
. "sigs.k8s.io/kustomize/api/hasher"
)
func TestSortArrayAndComputeHash(t *testing.T) {
array1 := []string{"a", "b", "c", "d"}
array2 := []string{"c", "b", "d", "a"}
h1, err := SortArrayAndComputeHash(array1)
if err != nil {
t.Errorf("unexpected error %v", err)
}
if h1 == "" {
t.Errorf("failed to hash %v", array1)
}
h2, err := SortArrayAndComputeHash(array2)
if err != nil {
t.Errorf("unexpected error %v", err)
}
if h2 == "" {
t.Errorf("failed to hash %v", array2)
}
if h1 != h2 {
t.Errorf("hash is not consistent with reordered list: %s %s", h1, h2)
}
}
func TestHash(t *testing.T) {
// hash the empty string to be sure that sha256 is being used
expect := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
sum := Hash("")
if expect != sum {
t.Errorf("expected hash %q but got %q", expect, sum)
}
}

95
api/ifc/ifc.go Normal file
View File

@@ -0,0 +1,95 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package ifc holds miscellaneous interfaces used by kustomize.
package ifc
import (
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/types"
)
// Validator provides functions to validate annotations and labels
type Validator interface {
MakeAnnotationValidator() func(map[string]string) error
MakeAnnotationNameValidator() func([]string) error
MakeLabelValidator() func(map[string]string) error
MakeLabelNameValidator() func([]string) error
ValidateNamespace(string) []string
ErrIfInvalidKey(string) error
IsEnvVarName(k string) error
}
// KvLoader reads and validates KV pairs.
type KvLoader interface {
Validator() Validator
Load(args types.KvPairSources) (all []types.Pair, err error)
}
// Loader interface exposes methods to read bytes.
type Loader interface {
// Root returns the root location for this Loader.
Root() string
// New returns Loader located at newRoot.
New(newRoot string) (Loader, error)
// Load returns the bytes read from the location or an error.
Load(location string) ([]byte, error)
// Cleanup cleans the loader
Cleanup() error
}
// Kunstructured allows manipulation of k8s objects
// that do not have Golang structs.
type Kunstructured interface {
Map() map[string]interface{}
SetMap(map[string]interface{})
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)
GetAnnotations() map[string]string
SetAnnotations(map[string]string)
MatchesLabelSelector(selector string) (bool, error)
MatchesAnnotationSelector(selector string) (bool, error)
Patch(Kunstructured) error
}
// KunstructuredFactory makes instances of Kunstructured.
type KunstructuredFactory interface {
SliceFromBytes([]byte) ([]Kunstructured, error)
FromMap(m map[string]interface{}) Kunstructured
Hasher() KunstructuredHasher
MakeConfigMap(
kvLdr KvLoader,
options *types.GeneratorOptions,
args *types.ConfigMapArgs) (Kunstructured, error)
MakeSecret(
kvLdr KvLoader,
options *types.GeneratorOptions,
args *types.SecretArgs) (Kunstructured, error)
}
// KunstructuredHasher returns a hash of the argument
// or an error.
type KunstructuredHasher interface {
Hash(Kunstructured) (string, error)
}
// See core.v1.SecretTypeOpaque
const SecretTypeOpaque = "Opaque"

View File

@@ -1,24 +1,12 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package expansion provides functions find and replace $(FOO) style variables in strings.
package expansion
import (
"bytes"
"fmt"
)
const (
@@ -38,13 +26,18 @@ func syntaxWrap(input string) string {
// for the input is found.
func MappingFuncFor(
counts map[string]int,
context ...map[string]string) func(string) string {
return func(input string) string {
context ...map[string]interface{}) func(string) interface{} {
return func(input string) interface{} {
for _, vars := range context {
val, ok := vars[input]
if ok {
counts[input]++
return val
switch typedV := val.(type) {
case string, int64, float64, bool:
return typedV
default:
return syntaxWrap(input)
}
}
}
return syntaxWrap(input)
@@ -54,7 +47,7 @@ func MappingFuncFor(
// Expand replaces variable references in the input string according to
// the expansion spec using the given mapping function to resolve the
// values of variables.
func Expand(input string, mapping func(string) string) string {
func Expand(input string, mapping func(string) interface{}) interface{} {
var buf bytes.Buffer
checkpoint := 0
for cursor := 0; cursor < len(input); cursor++ {
@@ -71,7 +64,14 @@ func Expand(input string, mapping func(string) string) string {
// We were able to read a variable name correctly;
// apply the mapping to the variable name and copy the
// bytes into the buffer
buf.WriteString(mapping(read))
mapped := mapping(read)
if input == syntaxWrap(read) {
// Preserve the type of variable
return mapped
}
// Variable is used in a middle of a string
buf.WriteString(fmt.Sprintf("%v", mapped))
} else {
// Not a variable name; copy the read bytes into the buffer
buf.WriteString(read)

View File

@@ -1,25 +1,13 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package expansion_test
import (
"fmt"
"testing"
. "sigs.k8s.io/kustomize/pkg/expansion"
. "sigs.k8s.io/kustomize/api/internal/accumulator/expansion"
)
type expected struct {
@@ -30,7 +18,7 @@ type expected struct {
func TestMapReference(t *testing.T) {
type env struct {
Name string
Value string
Value interface{}
}
envs := []env{
{
@@ -45,25 +33,49 @@ func TestMapReference(t *testing.T) {
Name: "BLU",
Value: "$(ZOO)-2",
},
{
Name: "INT",
Value: 2,
},
{
Name: "ZINT",
Value: "$(INT)",
},
{
Name: "BOOL",
Value: true,
},
{
Name: "ZBOOL",
Value: "$(BOOL)",
},
}
declaredEnv := map[string]string{
"FOO": "bar",
"ZOO": "$(FOO)-1",
"BLU": "$(ZOO)-2",
declaredEnv := map[string]interface{}{
"FOO": "bar",
"ZOO": "$(FOO)-1",
"BLU": "$(ZOO)-2",
"INT": "2",
"ZINT": "$(INT)",
"BOOL": "true",
"ZBOOL": "$(BOOL)",
}
counts := make(map[string]int)
mapping := MappingFuncFor(counts, declaredEnv)
for _, env := range envs {
declaredEnv[env.Name] = Expand(env.Value, mapping)
declaredEnv[env.Name] = Expand(fmt.Sprintf("%v", env.Value), mapping)
}
expectedEnv := map[string]expected{
"FOO": {count: 1, edited: "bar"},
"ZOO": {count: 1, edited: "bar-1"},
"BLU": {count: 0, edited: "bar-1-2"},
"FOO": {count: 1, edited: "bar"},
"ZOO": {count: 1, edited: "bar-1"},
"BLU": {count: 0, edited: "bar-1-2"},
"INT": {count: 1, edited: "2"},
"ZINT": {count: 0, edited: "2"},
"BOOL": {count: 1, edited: "true"},
"ZBOOL": {count: 0, edited: "true"},
}
for k, v := range expectedEnv {
@@ -81,7 +93,7 @@ func TestMapReference(t *testing.T) {
}
func TestMapping(t *testing.T) {
context := map[string]string{
context := map[string]interface{}{
"VAR_A": "A",
"VAR_B": "B",
"VAR_C": "C",
@@ -92,11 +104,11 @@ func TestMapping(t *testing.T) {
}
func TestMappingDual(t *testing.T) {
context := map[string]string{
context := map[string]interface{}{
"VAR_A": "A",
"VAR_EMPTY": "",
}
context2 := map[string]string{
context2 := map[string]interface{}{
"VAR_B": "B",
"VAR_C": "C",
"VAR_REF": "$(VAR_A)",
@@ -105,7 +117,7 @@ func TestMappingDual(t *testing.T) {
doExpansionTest(t, context, context2)
}
func doExpansionTest(t *testing.T, context ...map[string]string) {
func doExpansionTest(t *testing.T, context ...map[string]interface{}) {
cases := []struct {
name string
input string
@@ -325,7 +337,7 @@ func doExpansionTest(t *testing.T, context ...map[string]string) {
for _, tc := range cases {
counts := make(map[string]int)
mapping := MappingFuncFor(counts, context...)
expanded := Expand(tc.input, mapping)
expanded := Expand(fmt.Sprintf("%v", tc.input), mapping)
if e, a := tc.expected, expanded; e != a {
t.Errorf("%v: expected %q, got %q", tc.name, e, a)
}

View File

@@ -0,0 +1,190 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package accumulator
import (
"encoding/json"
"strings"
"github.com/go-openapi/spec"
"github.com/pkg/errors"
"k8s.io/kube-openapi/pkg/common"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
)
type myProperties map[string]spec.Schema
type nameToApiMap map[string]common.OpenAPIDefinition
// LoadConfigFromCRDs parse CRD schemas from paths into a TransformerConfig
func LoadConfigFromCRDs(
ldr ifc.Loader, paths []string) (*builtinconfig.TransformerConfig, error) {
tc := builtinconfig.MakeEmptyConfig()
for _, path := range paths {
content, err := ldr.Load(path)
if err != nil {
return nil, err
}
m, err := makeNameToApiMap(content)
if err != nil {
return nil, errors.Wrapf(err, "unable to parse open API definition from '%s'", path)
}
otherTc, err := makeConfigFromApiMap(m)
if err != nil {
return nil, err
}
tc, err = tc.Merge(otherTc)
if err != nil {
return nil, err
}
}
return tc, nil
}
func makeNameToApiMap(content []byte) (result nameToApiMap, err error) {
if content[0] == '{' {
err = json.Unmarshal(content, &result)
} else {
err = yaml.Unmarshal(content, &result)
}
return
}
func makeConfigFromApiMap(m nameToApiMap) (*builtinconfig.TransformerConfig, error) {
result := builtinconfig.MakeEmptyConfig()
for name, api := range m {
if !looksLikeAk8sType(api.Schema.SchemaProps.Properties) {
continue
}
tc := builtinconfig.MakeEmptyConfig()
err := loadCrdIntoConfig(
tc, makeGvkFromTypeName(name), m, name, []string{})
if err != nil {
return result, err
}
result, err = result.Merge(tc)
if err != nil {
return result, err
}
}
return result, nil
}
// TODO: Get Group and Version for CRD from the
// openAPI definition once
// "x-kubernetes-group-version-kind" is available in CRD
func makeGvkFromTypeName(n string) resid.Gvk {
names := strings.Split(n, ".")
kind := names[len(names)-1]
return resid.Gvk{Kind: kind}
}
func looksLikeAk8sType(properties myProperties) bool {
_, ok := properties["kind"]
if !ok {
return false
}
_, ok = properties["apiVersion"]
if !ok {
return false
}
_, ok = properties["metadata"]
if !ok {
return false
}
return true
}
const (
// "x-kubernetes-annotation": ""
xAnnotation = "x-kubernetes-annotation"
// "x-kubernetes-label-selector": ""
xLabelSelector = "x-kubernetes-label-selector"
// "x-kubernetes-identity": ""
xIdentity = "x-kubernetes-identity"
// "x-kubernetes-object-ref-api-version": <apiVersion name>
xVersion = "x-kubernetes-object-ref-api-version"
// "x-kubernetes-object-ref-kind": <kind name>
xKind = "x-kubernetes-object-ref-kind"
// "x-kubernetes-object-ref-name-key": "name"
// default is "name"
xNameKey = "x-kubernetes-object-ref-name-key"
)
// loadCrdIntoConfig loads a CRD spec into a TransformerConfig
func loadCrdIntoConfig(
theConfig *builtinconfig.TransformerConfig, theGvk resid.Gvk, theMap nameToApiMap,
typeName string, path []string) (err error) {
api, ok := theMap[typeName]
if !ok {
return nil
}
for propName, property := range api.Schema.SchemaProps.Properties {
_, annotate := property.Extensions.GetString(xAnnotation)
if annotate {
err = theConfig.AddAnnotationFieldSpec(
makeFs(theGvk, append(path, propName)))
if err != nil {
return
}
}
_, label := property.Extensions.GetString(xLabelSelector)
if label {
err = theConfig.AddLabelFieldSpec(
makeFs(theGvk, append(path, propName)))
if err != nil {
return
}
}
_, identity := property.Extensions.GetString(xIdentity)
if identity {
err = theConfig.AddPrefixFieldSpec(
makeFs(theGvk, append(path, propName)))
if err != nil {
return
}
}
version, ok := property.Extensions.GetString(xVersion)
if ok {
kind, ok := property.Extensions.GetString(xKind)
if ok {
nameKey, ok := property.Extensions.GetString(xNameKey)
if !ok {
nameKey = "name"
}
err = theConfig.AddNamereferenceFieldSpec(
builtinconfig.NameBackReferences{
Gvk: resid.Gvk{Kind: kind, Version: version},
FieldSpecs: []types.FieldSpec{
makeFs(theGvk, append(path, propName, nameKey))},
})
if err != nil {
return
}
}
}
if property.Ref.GetURL() != nil {
loadCrdIntoConfig(
theConfig, theGvk, theMap,
property.Ref.String(), append(path, propName))
}
}
return nil
}
func makeFs(in resid.Gvk, path []string) types.FieldSpec {
return types.FieldSpec{
CreateIfNotPresent: false,
Gvk: in,
Path: strings.Join(path, "/"),
}
}

View File

@@ -0,0 +1,182 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package accumulator_test
import (
"reflect"
"testing"
"sigs.k8s.io/kustomize/api/ifc"
. "sigs.k8s.io/kustomize/api/internal/accumulator"
"sigs.k8s.io/kustomize/api/internal/loadertest"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/types"
)
// This defines two CRD's: Bee and MyKind.
//
// Bee is boring, it's spec has no dependencies.
//
// MyKind, however, has a spec that contains
// a Bee and a (k8s native) Secret.
const (
crdContent = `
{
"github.com/example/pkg/apis/jingfang/v1beta1.Bee": {
"Schema": {
"description": "Bee",
"properties": {
"apiVersion": {
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert
recognized schemas to the latest internal value, and may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources",
"type": "string"
},
"kind": {
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer
this from the endpoint the client submits requests to. Cannot be updated. In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
"type": "string"
},
"metadata": {
"$ref": "sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1.ObjectMeta"
},
"spec": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.BeeSpec"
},
"status": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.BeeStatus"
}
}
},
"Dependencies": [
"github.com/example/pkg/apis/jingfang/v1beta1.BeeSpec",
"github.com/example/pkg/apis/jingfang/v1beta1.BeeStatus",
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1.ObjectMeta"
]
},
"github.com/example/pkg/apis/jingfang/v1beta1.BeeSpec": {
"Schema": {
"description": "BeeSpec defines the desired state of Bee"
},
"Dependencies": []
},
"github.com/example/pkg/apis/jingfang/v1beta1.BeeStatus": {
"Schema": {
"description": "BeeStatus defines the observed state of Bee"
},
"Dependencies": []
},
"github.com/example/pkg/apis/jingfang/v1beta1.MyKind": {
"Schema": {
"description": "MyKind",
"properties": {
"apiVersion": {
"description": "APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources",
"type": "string"
},
"kind": {
"description": "Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to. Cannot be updated.
In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
"type": "string"
},
"metadata": {
"$ref": "sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1.ObjectMeta"
},
"spec": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.MyKindSpec"
},
"status": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.MyKindStatus"
}
}
},
"Dependencies": [
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindSpec",
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindStatus",
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1.ObjectMeta"
]
},
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindSpec": {
"Schema": {
"description": "MyKindSpec defines the desired state of MyKind",
"properties": {
"beeRef": {
"x-kubernetes-object-ref-api-version": "v1beta1",
"x-kubernetes-object-ref-kind": "Bee",
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.Bee"
},
"secretRef": {
"description": "If defined, we use this secret for configuring the MYSQL_ROOT_PASSWORD
If it is not set we generate a secret dynamically",
"x-kubernetes-object-ref-api-version": "v1",
"x-kubernetes-object-ref-kind": "Secret",
"$ref": "sigs.k8s.io/kustomize/pseudo/k8s/api/core/v1.LocalObjectReference"
}
}
},
"Dependencies": [
"github.com/example/pkg/apis/jingfang/v1beta1.Bee",
"sigs.k8s.io/kustomize/pseudo/k8s/api/core/v1.LocalObjectReference"
]
},
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindStatus": {
"Schema": {
"description": "MyKindStatus defines the observed state of MyKind"
},
"Dependencies": []
}
}
`
)
func makeLoader(t *testing.T) ifc.Loader {
ldr := loadertest.NewFakeLoader("/testpath")
err := ldr.AddFile("/testpath/crd.json", []byte(crdContent))
if err != nil {
t.Fatalf("Failed to setup fake ldr.")
}
return ldr
}
func TestLoadCRDs(t *testing.T) {
nbrs := []builtinconfig.NameBackReferences{
{
Gvk: resid.Gvk{Kind: "Secret", Version: "v1"},
FieldSpecs: []types.FieldSpec{
{
CreateIfNotPresent: false,
Gvk: resid.Gvk{Kind: "MyKind"},
Path: "spec/secretRef/name",
},
},
},
{
Gvk: resid.Gvk{Kind: "Bee", Version: "v1beta1"},
FieldSpecs: []types.FieldSpec{
{
CreateIfNotPresent: false,
Gvk: resid.Gvk{Kind: "MyKind"},
Path: "spec/beeRef/name",
},
},
},
}
expectedTc := &builtinconfig.TransformerConfig{
NameReference: nbrs,
}
actualTc, err := LoadConfigFromCRDs(makeLoader(t), []string{"crd.json"})
if err != nil {
t.Fatalf("unexpected error:%v", err)
}
if !reflect.DeepEqual(actualTc, expectedTc) {
t.Fatalf("expected\n %v\n but got\n %v\n", expectedTc, actualTc)
}
}

View File

@@ -0,0 +1,274 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package accumulator
import (
"fmt"
"log"
"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"
)
type nameReferenceTransformer struct {
backRefs []builtinconfig.NameBackReferences
}
var _ resmap.Transformer = &nameReferenceTransformer{}
// newNameReferenceTransformer constructs a nameReferenceTransformer
// with a given slice of NameBackReferences.
func newNameReferenceTransformer(br []builtinconfig.NameBackReferences) resmap.Transformer {
if br == nil {
log.Fatal("backrefs not expected to be nil")
}
return &nameReferenceTransformer{backRefs: br}
}
// Transform updates name references in resource A that
// refer to resource B, given that B's name may have
// changed.
//
// For example, a HorizontalPodAutoscaler (HPA)
// necessarily refers to a Deployment, the thing that
// the HPA scales. The Deployment name might change
// (e.g. prefix added), and the reference in the HPA
// has to be fixed.
//
// In the outer loop over the ResMap below, say we
// encounter a specific HPA. Then, in scanning backrefs,
// we encounter an entry like
//
// - kind: Deployment
// fieldSpecs:
// - kind: HorizontalPodAutoscaler
// path: spec/scaleTargetRef/name
//
// This entry says that an HPA, via its
// 'spec/scaleTargetRef/name' field, may refer to a
// Deployment. This match to HPA means we may need to
// modify the value in its 'spec/scaleTargetRef/name'
// field, by searching for the thing it refers to,
// and getting its new name.
//
// As a filter, and search optimization, we compute a
// subset of all resources that the HPA could refer to,
// by excluding objects from other namespaces, and
// excluding objects that don't have the same prefix-
// suffix mods as the HPA.
//
// We look in this subset for all Deployment objects
// with a resId that has a Name matching the field value
// present in the HPA. If no match do nothing; if more
// than one match, it's an error.
//
// We overwrite the HPA name field with the value found
// in the Deployment's name field (the name in the raw
// object - the modified name - not the unmodified name
// in the Deployment's resId).
//
// This process assumes that the name stored in a ResId
// (the ResMap key) isn't modified by name transformers.
// Name transformers should only modify the name in the
// body of the resource object (the value in the ResMap).
//
func (o *nameReferenceTransformer) Transform(m resmap.ResMap) error {
// TODO: Too much looping, here and in transitive calls.
for _, referrer := range m.Resources() {
var candidates resmap.ResMap
for _, target := range o.backRefs {
for _, fSpec := range target.FieldSpecs {
if referrer.OrgId().IsSelected(&fSpec.Gvk) {
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))
if err != nil {
return err
}
}
}
}
}
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 in.(type) {
case string:
oldName, _ := in.(string)
return o.getSimpleNameField(oldName, referrer, target,
referralCandidates, referralCandidates.Resources())
case map[string]interface{}:
// Kind: ValidatingWebhookConfiguration
// FieldSpec is webhooks/clientConfig/service
oldMap, _ := in.(map[string]interface{})
return o.getNameAndNsStruct(oldMap, referrer, target,
referralCandidates)
case []interface{}:
l, _ := in.([]interface{})
for idx, item := range l {
switch item.(type) {
case string:
// Kind: Role/ClusterRole
// FieldSpec is rules.resourceNames
oldName, _ := item.(string)
newName, err := o.getSimpleNameField(oldName, referrer, target,
referralCandidates, referralCandidates.Resources())
if err != nil {
return nil, err
}
l[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
oldMap, _ := item.(map[string]interface{})
newMap, err := o.getNameAndNsStruct(oldMap, referrer, target,
referralCandidates)
if err != nil {
return nil, err
}
l[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
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,110 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package accumulator
import (
"fmt"
expansion2 "sigs.k8s.io/kustomize/api/internal/accumulator/expansion"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/transform"
"sigs.k8s.io/kustomize/api/types"
)
type refVarTransformer struct {
varMap map[string]interface{}
replacementCounts map[string]int
fieldSpecs []types.FieldSpec
mappingFunc func(string) interface{}
}
// newRefVarTransformer returns a new refVarTransformer
// that replaces $(VAR) style variables with values.
// The fieldSpecs are the places to look for occurrences of $(VAR).
func newRefVarTransformer(
varMap map[string]interface{}, fs []types.FieldSpec) *refVarTransformer {
return &refVarTransformer{
varMap: varMap,
fieldSpecs: fs,
}
}
// 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{}) {
xs = append(xs, expansion2.Expand(a.(string), 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 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 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
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 {
var unused []string
for k := range rv.varMap {
_, ok := rv.replacementCounts[k]
if !ok {
unused = append(unused, k)
}
}
return unused
}
// Transform replaces $(VAR) style variables with values.
func (rv *refVarTransformer) Transform(m resmap.ResMap) error {
rv.replacementCounts = make(map[string]int)
rv.mappingFunc = expansion2.MappingFuncFor(
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
}
}
}
}
return nil
}

View File

@@ -0,0 +1,137 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package accumulator
import (
"reflect"
"testing"
"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"
"sigs.k8s.io/kustomize/api/testutils/resmaptest"
"sigs.k8s.io/kustomize/api/types"
)
func TestRefVarTransformer(t *testing.T) {
type given struct {
varMap map[string]interface{}
fs []types.FieldSpec
res resmap.ResMap
}
type expected struct {
res resmap.ResMap
unused []string
}
testCases := []struct {
description string
given given
expected expected
}{
{
description: "var replacement in map[string]",
given: given{
varMap: map[string]interface{}{
"FOO": "replacementForFoo",
"BAR": "replacementForBar",
"BAZ": int64(5),
"BOO": true,
},
fs: []types.FieldSpec{
{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(
t, resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())).
Add(map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "cm1",
},
"data": map[string]interface{}{
"map": map[string]interface{}{
"item1": "$(FOO)",
"item2": "bla",
"item3": "$(BAZ)",
"item4": "$(BAZ)+$(BAZ)",
"item5": "$(BOO)",
"item6": "if $(BOO)",
"item7": 2019,
},
"slice": []interface{}{
"$(FOO)",
"bla",
"$(BAZ)",
"$(BAZ)+$(BAZ)",
"$(BOO)",
"if $(BOO)",
},
"interface": "$(FOO)",
"nil": nil,
"num": 2019,
}}).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{}{
"map": map[string]interface{}{
"item1": "replacementForFoo",
"item2": "bla",
"item3": int64(5),
"item4": "5+5",
"item5": true,
"item6": "if true",
"item7": 2019,
},
"slice": []interface{}{
"replacementForFoo",
"bla",
int64(5),
"5+5",
true,
"if true",
},
"interface": "replacementForFoo",
"nil": nil,
"num": 2019,
}}).ResMap(),
unused: []string{"BAR"},
},
},
}
for _, tc := range testCases {
t.Run(tc.description, func(t *testing.T) {
// arrange
tr := newRefVarTransformer(tc.given.varMap, tc.given.fs)
// act
err := tr.Transform(tc.given.res)
// assert
if err != nil {
t.Errorf("unexpected error: %v", err)
}
a, e := tc.given.res, tc.expected.res
if !reflect.DeepEqual(a, e) {
err = e.ErrorIfNotEqualLists(a)
t.Fatalf("actual doesn't match expected: \nACTUAL:\n%v\nEXPECTED:\n%v\nERR: %v", a, e, err)
}
})
}
}

View File

@@ -0,0 +1,166 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package accumulator
import (
"fmt"
"log"
"strings"
"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/types"
)
// ResAccumulator accumulates resources and the rules
// used to customize those resources. It's a ResMap
// plus stuff needed to modify the ResMap.
type ResAccumulator struct {
resMap resmap.ResMap
tConfig *builtinconfig.TransformerConfig
varSet types.VarSet
}
func MakeEmptyAccumulator() *ResAccumulator {
ra := &ResAccumulator{}
ra.resMap = resmap.New()
ra.tConfig = &builtinconfig.TransformerConfig{}
ra.varSet = types.NewVarSet()
return ra
}
// ResMap returns a copy of the internal resMap.
func (ra *ResAccumulator) ResMap() resmap.ResMap {
return ra.resMap.ShallowCopy()
}
// Vars returns a copy of underlying vars.
func (ra *ResAccumulator) Vars() []types.Var {
return ra.varSet.AsSlice()
}
func (ra *ResAccumulator) AppendAll(
resources resmap.ResMap) error {
return ra.resMap.AppendAll(resources)
}
func (ra *ResAccumulator) AbsorbAll(
resources resmap.ResMap) error {
return ra.resMap.AbsorbAll(resources)
}
func (ra *ResAccumulator) MergeConfig(
tConfig *builtinconfig.TransformerConfig) (err error) {
ra.tConfig, err = ra.tConfig.Merge(tConfig)
return err
}
func (ra *ResAccumulator) GetTransformerConfig() *builtinconfig.TransformerConfig {
return ra.tConfig
}
func (ra *ResAccumulator) MergeVars(incoming []types.Var) error {
for _, v := range incoming {
targetId := resid.NewResIdWithNamespace(v.ObjRef.GVK(), v.ObjRef.Name, v.ObjRef.Namespace)
idMatcher := targetId.GvknEquals
if targetId.Namespace != "" || !targetId.IsNamespaceableKind() {
// Preserve backward compatibility. An empty namespace means
// wildcard search on the namespace hence we still use GvknEquals
idMatcher = targetId.Equals
}
matched := ra.resMap.GetMatchingResourcesByOriginalId(idMatcher)
if len(matched) > 1 {
return fmt.Errorf(
"found %d resId matches for var %s "+
"(unable to disambiguate)",
len(matched), v)
}
if len(matched) == 1 {
matched[0].AppendRefVarName(v)
}
}
return ra.varSet.MergeSlice(incoming)
}
func (ra *ResAccumulator) MergeAccumulator(other *ResAccumulator) (err error) {
err = ra.AppendAll(other.resMap)
if err != nil {
return err
}
err = ra.MergeConfig(other.tConfig)
if err != nil {
return err
}
return ra.varSet.MergeSet(other.varSet)
}
func (ra *ResAccumulator) findVarValueFromResources(v types.Var) (interface{}, error) {
for _, res := range ra.resMap.Resources() {
for _, varName := range res.GetRefVarNames() {
if varName == v.Name {
s, err := res.GetFieldValue(v.FieldRef.FieldPath)
if err != nil {
return "", fmt.Errorf(
"field specified in var '%v' "+
"not found in corresponding resource", v)
}
return s, nil
}
}
}
return "", fmt.Errorf(
"var '%v' cannot be mapped to a field "+
"in the set of known resources", v)
}
// makeVarReplacementMap returns a map of Var names to
// their final values. The values are strings intended
// for substitution wherever the $(var.Name) occurs.
func (ra *ResAccumulator) makeVarReplacementMap() (map[string]interface{}, error) {
result := map[string]interface{}{}
for _, v := range ra.Vars() {
s, err := ra.findVarValueFromResources(v)
if err != nil {
return nil, err
}
result[v.Name] = s
}
return result, nil
}
func (ra *ResAccumulator) Transform(t resmap.Transformer) error {
return t.Transform(ra.resMap)
}
func (ra *ResAccumulator) ResolveVars() error {
replacementMap, err := ra.makeVarReplacementMap()
if err != nil {
return err
}
if len(replacementMap) == 0 {
return nil
}
t := newRefVarTransformer(
replacementMap, ra.tConfig.VarReference)
err = ra.Transform(t)
if len(t.UnusedVars()) > 0 {
log.Printf(
"well-defined vars that were never replaced: %s\n",
strings.Join(t.UnusedVars(), ","))
}
return err
}
func (ra *ResAccumulator) FixBackReferences() (err error) {
if ra.tConfig.NameReference == nil {
return nil
}
return ra.Transform(newNameReferenceTransformer(
ra.tConfig.NameReference))
}

View File

@@ -0,0 +1,417 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package accumulator_test
import (
"bytes"
"log"
"os"
"strings"
"testing"
. "sigs.k8s.io/kustomize/api/internal/accumulator"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
"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"
"sigs.k8s.io/kustomize/api/testutils/resmaptest"
"sigs.k8s.io/kustomize/api/types"
)
func makeResAccumulator(t *testing.T) (*ResAccumulator, *resource.Factory) {
ra := MakeEmptyAccumulator()
err := ra.MergeConfig(builtinconfig.MakeDefaultConfig())
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
rf := resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl())
err = ra.AppendAll(
resmaptest_test.NewRmBuilder(t, rf).
Add(map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "deploy1",
},
"spec": map[string]interface{}{
"template": map[string]interface{}{
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"command": []interface{}{
"myserver",
"--somebackendService $(SERVICE_ONE)",
"--yetAnother $(SERVICE_TWO)",
},
},
},
},
},
}}).
Add(map[string]interface{}{
"apiVersion": "v1",
"kind": "Service",
"metadata": map[string]interface{}{
"name": "backendOne",
}}).
Add(map[string]interface{}{
"apiVersion": "v1",
"kind": "Service",
"metadata": map[string]interface{}{
"name": "backendTwo",
}}).ResMap())
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
return ra, rf
}
func TestResolveVarsHappy(t *testing.T) {
ra, _ := makeResAccumulator(t)
err := ra.MergeVars([]types.Var{
{
Name: "SERVICE_ONE",
ObjRef: types.Target{
Gvk: resid.Gvk{Version: "v1", Kind: "Service"},
Name: "backendOne"},
},
{
Name: "SERVICE_TWO",
ObjRef: types.Target{
Gvk: resid.Gvk{Version: "v1", Kind: "Service"},
Name: "backendTwo"},
},
})
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
err = ra.ResolveVars()
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
c := getCommand(find("deploy1", ra.ResMap()))
if c != "myserver --somebackendService backendOne --yetAnother backendTwo" {
t.Fatalf("unexpected command: %s", c)
}
}
func TestResolveVarsOneUnused(t *testing.T) {
ra, _ := makeResAccumulator(t)
err := ra.MergeVars([]types.Var{
{
Name: "SERVICE_ONE",
ObjRef: types.Target{
Gvk: resid.Gvk{Version: "v1", Kind: "Service"},
Name: "backendOne"},
},
{
Name: "SERVICE_UNUSED",
ObjRef: types.Target{
Gvk: resid.Gvk{Version: "v1", Kind: "Service"},
Name: "backendTwo"},
},
})
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
var buf bytes.Buffer
log.SetOutput(&buf)
defer func() {
log.SetOutput(os.Stderr)
}()
err = ra.ResolveVars()
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
expectLog(t, buf, "well-defined vars that were never replaced: SERVICE_UNUSED")
c := getCommand(find("deploy1", ra.ResMap()))
if c != "myserver --somebackendService backendOne --yetAnother $(SERVICE_TWO)" {
t.Fatalf("unexpected command: %s", c)
}
}
func expectLog(t *testing.T, log bytes.Buffer, expect string) {
if !strings.Contains(log.String(), expect) {
t.Fatalf("expected log containing '%s', got '%s'", expect, log.String())
}
}
func TestResolveVarsVarNeedsDisambiguation(t *testing.T) {
ra, rf := makeResAccumulator(t)
rm0 := resmap.New()
err := rm0.Append(
rf.FromMap(
map[string]interface{}{
"apiVersion": "v1",
"kind": "Service",
"metadata": map[string]interface{}{
"name": "backendOne",
"namespace": "fooNamespace",
},
}))
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
err = ra.AppendAll(rm0)
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
err = ra.MergeVars([]types.Var{
{
Name: "SERVICE_ONE",
ObjRef: types.Target{
Gvk: resid.Gvk{Version: "v1", Kind: "Service"},
Name: "backendOne",
},
},
})
if err == nil {
t.Fatalf("expected error")
}
if !strings.Contains(
err.Error(), "unable to disambiguate") {
t.Fatalf("unexpected err: %v", err)
}
}
func makeNamespacedConfigMapWithDataProviderValue(
namespace string,
value string,
) map[string]interface{} {
return map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "environment",
"namespace": namespace,
},
"data": map[string]interface{}{
"provider": value,
},
}
}
func makeVarToNamepaceAndPath(
name string,
namespace string,
path string,
) types.Var {
return types.Var{
Name: name,
ObjRef: types.Target{
Gvk: resid.Gvk{Version: "v1", Kind: "ConfigMap"},
Name: "environment",
Namespace: namespace,
},
FieldRef: types.FieldSelector{FieldPath: path},
}
}
func TestResolveVarConflicts(t *testing.T) {
rf := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
// create configmaps in foo and bar namespaces with `data.provider` values.
fooAws := makeNamespacedConfigMapWithDataProviderValue("foo", "aws")
barAws := makeNamespacedConfigMapWithDataProviderValue("bar", "aws")
barGcp := makeNamespacedConfigMapWithDataProviderValue("bar", "gcp")
// create two variables with (apparently) conflicting names that point to
// fieldpaths that could be generalized.
varFoo := makeVarToNamepaceAndPath("PROVIDER", "foo", "data.provider")
varBar := makeVarToNamepaceAndPath("PROVIDER", "bar", "data.provider")
// create accumulators holding apparently conflicting vars that are not
// actually in conflict because they point to the same concrete value.
rm0 := resmap.New()
rm0.Append(rf.FromMap(fooAws))
ac0 := MakeEmptyAccumulator()
ac0.AppendAll(rm0)
ac0.MergeVars([]types.Var{varFoo})
rm1 := resmap.New()
rm1.Append(rf.FromMap(barAws))
ac1 := MakeEmptyAccumulator()
ac1.AppendAll(rm1)
ac1.MergeVars([]types.Var{varBar})
// validate that two vars of the same name which reference the same concrete
// value do not produce a conflict.
err := ac0.MergeAccumulator(ac1)
if err == nil {
t.Fatalf("see bug gh-1600")
}
// create an accumulator will have an actually conflicting value with the
// two above (because it contains a variable whose name is used in the other
// accumulators AND whose concrete values are different).
rm2 := resmap.New()
rm2.Append(rf.FromMap(barGcp))
ac2 := MakeEmptyAccumulator()
ac2.AppendAll(rm2)
ac2.MergeVars([]types.Var{varBar})
err = ac1.MergeAccumulator(ac2)
if err == nil {
t.Fatalf("dupe vars w/ different concrete values should conflict")
}
}
func TestResolveVarsGoodResIdBadField(t *testing.T) {
ra, _ := makeResAccumulator(t)
err := ra.MergeVars([]types.Var{
{
Name: "SERVICE_ONE",
ObjRef: types.Target{
Gvk: resid.Gvk{Version: "v1", Kind: "Service"},
Name: "backendOne"},
FieldRef: types.FieldSelector{FieldPath: "nope_nope_nope"},
},
})
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
err = ra.ResolveVars()
if err == nil {
t.Fatalf("expected error")
}
if !strings.Contains(
err.Error(),
"not found in corresponding resource") {
t.Fatalf("unexpected err: %v", err)
}
}
func TestResolveVarsUnmappableVar(t *testing.T) {
ra, _ := makeResAccumulator(t)
err := ra.MergeVars([]types.Var{
{
Name: "SERVICE_THREE",
ObjRef: types.Target{
Gvk: resid.Gvk{Version: "v1", Kind: "Service"},
Name: "doesNotExist"},
},
})
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
err = ra.ResolveVars()
if err == nil {
t.Fatalf("expected error")
}
if !strings.Contains(
err.Error(),
"cannot be mapped to a field in the set of known resources") {
t.Fatalf("unexpected err: %v", err)
}
}
func TestResolveVarsWithNoambiguation(t *testing.T) {
ra1, rf := makeResAccumulator(t)
err := ra1.MergeVars([]types.Var{
{
Name: "SERVICE_ONE",
ObjRef: types.Target{
Gvk: resid.Gvk{Version: "v1", Kind: "Service"},
Name: "backendOne",
},
},
})
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
// Create another accumulator having a resource with different prefix
ra2 := MakeEmptyAccumulator()
m := resmaptest_test.NewRmBuilder(t, rf).
Add(map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "deploy2",
},
"spec": map[string]interface{}{
"template": map[string]interface{}{
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"command": []interface{}{
"myserver",
"--somebackendService $(SUB_SERVICE_ONE)",
},
},
},
},
},
}}).
Add(map[string]interface{}{
"apiVersion": "v1",
"kind": "Service",
"metadata": map[string]interface{}{
"name": "backendOne",
}}).ResMap()
// Make it seem like this resource
// went through a prefix transformer.
r := m.GetByIndex(1)
r.AddNamePrefix("sub-")
r.SetName("sub-backendOne") // original name remains "backendOne"
err = ra2.AppendAll(m)
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
err = ra2.MergeVars([]types.Var{
{
Name: "SUB_SERVICE_ONE",
ObjRef: types.Target{
Gvk: resid.Gvk{Version: "v1", Kind: "Service"},
Name: "backendOne",
},
},
})
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
err = ra1.MergeAccumulator(ra2)
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
err = ra1.ResolveVars()
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
}
func find(name string, resMap resmap.ResMap) *resource.Resource {
for _, r := range resMap.Resources() {
if r.GetName() == name {
return r
}
}
return nil
}
// Assumes arg is a deployment, returns the command of first container.
func getCommand(r *resource.Resource) string {
var m map[string]interface{}
var c []interface{}
m, _ = r.Map()["spec"].(map[string]interface{})
m, _ = m["template"].(map[string]interface{})
m, _ = m["spec"].(map[string]interface{})
c, _ = m["containers"].([]interface{})
m, _ = c[0].(map[string]interface{})
cmd, _ := m["command"].([]interface{})
n := make([]string, len(cmd))
for i, v := range cmd {
n[i] = v.(string)
}
return strings.Join(n, " ")
}

121
api/internal/git/cloner.go Normal file
View File

@@ -0,0 +1,121 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package git
import (
"bytes"
"log"
"os/exec"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/filesys"
)
// Cloner is a function that can clone a git repo.
type Cloner func(repoSpec *RepoSpec) error
// ClonerUsingGitExec uses a local git install, as opposed
// to say, some remote API, to obtain a local clone of
// a remote repo.
func ClonerUsingGitExec(repoSpec *RepoSpec) error {
gitProgram, err := exec.LookPath("git")
if err != nil {
return errors.Wrap(err, "no 'git' program on path")
}
repoSpec.Dir, err = filesys.NewTmpConfirmedDir()
if err != nil {
return err
}
cmd := exec.Command(
gitProgram,
"init",
repoSpec.Dir.String())
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &out
err = cmd.Run()
if err != nil {
log.Printf("Error initializing empty git repo: %s", out.String())
return errors.Wrapf(
err,
"trouble initializing empty git repo in %s",
repoSpec.Dir.String())
}
cmd = exec.Command(
gitProgram,
"remote",
"add",
"origin",
repoSpec.CloneSpec())
cmd.Stdout = &out
cmd.Stderr = &out
cmd.Dir = repoSpec.Dir.String()
err = cmd.Run()
if err != nil {
log.Printf("Error setting git remote: %s", out.String())
return errors.Wrapf(
err,
"trouble adding remote %s",
repoSpec.CloneSpec())
}
if repoSpec.Ref == "" {
repoSpec.Ref = "master"
}
cmd = exec.Command(
gitProgram,
"fetch",
"--depth=1",
"origin",
repoSpec.Ref)
cmd.Stdout = &out
cmd.Stderr = &out
cmd.Dir = repoSpec.Dir.String()
err = cmd.Run()
if err != nil {
log.Printf("Error performing git fetch: %s", out.String())
return errors.Wrapf(err, "trouble fetching %s", repoSpec.Ref)
}
cmd = exec.Command(
gitProgram,
"reset",
"--hard",
"FETCH_HEAD")
cmd.Stdout = &out
cmd.Stderr = &out
cmd.Dir = repoSpec.Dir.String()
err = cmd.Run()
if err != nil {
log.Printf("Error performing git reset: %s", out.String())
return errors.Wrapf(
err, "trouble hard resetting empty repository to %s", repoSpec.Ref)
}
cmd = exec.Command(
gitProgram,
"submodule",
"update",
"--init",
"--recursive")
cmd.Stdout = &out
cmd.Dir = repoSpec.Dir.String()
err = cmd.Run()
if err != nil {
return errors.Wrapf(err, "trouble fetching submodules for %s", repoSpec.Ref)
}
return nil
}
// DoNothingCloner returns a cloner that only sets
// cloneDir field in the repoSpec. It's assumed that
// the cloneDir is associated with some fake filesystem
// used in a test.
func DoNothingCloner(dir filesys.ConfirmedDir) Cloner {
return func(rs *RepoSpec) error {
rs.Dir = dir
return nil
}
}

View File

@@ -0,0 +1,219 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package git
import (
"fmt"
"path/filepath"
"regexp"
"strings"
"sigs.k8s.io/kustomize/api/filesys"
)
// Used as a temporary non-empty occupant of the cloneDir
// field, as something distinguishable from the empty string
// in various outputs (especially tests). Not using an
// actual directory name here, as that's a temporary directory
// with a unique name that isn't created until clone time.
const notCloned = filesys.ConfirmedDir("/notCloned")
// RepoSpec specifies a git repository and a branch and path therein.
type RepoSpec struct {
// Raw, original spec, used to look for cycles.
// TODO(monopole): Drop raw, use processed fields instead.
raw string
// Host, e.g. github.com
Host string
// orgRepo name (organization/repoName),
// e.g. kubernetes-sigs/kustomize
OrgRepo string
// Dir where the orgRepo is cloned to.
Dir filesys.ConfirmedDir
// Relative path in the repository, and in the cloneDir,
// to a Kustomization.
Path string
// Branch or tag reference.
Ref string
// e.g. .git or empty in case of _git is present
GitSuffix string
}
// CloneSpec returns a string suitable for "git clone {spec}".
func (x *RepoSpec) CloneSpec() string {
if isAzureHost(x.Host) || isAWSHost(x.Host) {
return x.Host + x.OrgRepo
}
return x.Host + x.OrgRepo + x.GitSuffix
}
func (x *RepoSpec) CloneDir() filesys.ConfirmedDir {
return x.Dir
}
func (x *RepoSpec) Raw() string {
return x.raw
}
func (x *RepoSpec) AbsPath() string {
return x.Dir.Join(x.Path)
}
func (x *RepoSpec) Cleaner(fSys filesys.FileSystem) func() error {
return func() error { return fSys.RemoveAll(x.Dir.String()) }
}
// From strings like git@github.com:someOrg/someRepo.git or
// https://github.com/someOrg/someRepo?ref=someHash, extract
// the parts.
func NewRepoSpecFromUrl(n string) (*RepoSpec, error) {
if filepath.IsAbs(n) {
return nil, fmt.Errorf("uri looks like abs path: %s", n)
}
host, orgRepo, path, gitRef, gitSuffix := parseGitUrl(n)
if orgRepo == "" {
return nil, fmt.Errorf("url lacks orgRepo: %s", n)
}
if host == "" {
return nil, fmt.Errorf("url lacks host: %s", n)
}
return &RepoSpec{
raw: n, Host: host, OrgRepo: orgRepo,
Dir: notCloned, Path: path, Ref: gitRef, GitSuffix: gitSuffix}, nil
}
const (
refQuery = "?ref="
refQueryRegex = "\\?(version|ref)="
gitSuffix = ".git"
gitDelimiter = "_git/"
)
// From strings like git@github.com:someOrg/someRepo.git or
// https://github.com/someOrg/someRepo?ref=someHash, extract
// the parts.
func parseGitUrl(n string) (
host string, orgRepo string, path string, gitRef string, gitSuff string) {
if strings.Contains(n, gitDelimiter) {
index := strings.Index(n, gitDelimiter)
// Adding _git/ to host
host = normalizeGitHostSpec(n[:index+len(gitDelimiter)])
orgRepo = strings.Split(strings.Split(n[index+len(gitDelimiter):], "/")[0], "?")[0]
path, gitRef = peelQuery(n[index+len(gitDelimiter)+len(orgRepo):])
return
}
host, n = parseHostSpec(n)
gitSuff = gitSuffix
if strings.Contains(n, gitSuffix) {
index := strings.Index(n, gitSuffix)
orgRepo = n[0:index]
n = n[index+len(gitSuffix):]
path, gitRef = peelQuery(n)
return
}
i := strings.Index(n, "/")
if i < 1 {
return "", "", "", "", ""
}
j := strings.Index(n[i+1:], "/")
if j >= 0 {
j += i + 1
orgRepo = n[:j]
path, gitRef = peelQuery(n[j+1:])
return
}
path = ""
orgRepo, gitRef = peelQuery(n)
return host, orgRepo, path, gitRef, gitSuff
}
func peelQuery(arg string) (string, string) {
r, _ := regexp.Compile(refQueryRegex)
j := r.FindStringIndex(arg)
if len(j) > 0 {
return arg[:j[0]], arg[j[0]+len(r.FindString(arg)):]
}
return arg, ""
}
func parseHostSpec(n string) (string, string) {
var host string
// Start accumulating the host part.
for _, p := range []string{
// Order matters here.
"git::", "gh:", "ssh://", "https://", "http://",
"git@", "github.com:", "github.com/"} {
if len(p) < len(n) && strings.ToLower(n[:len(p)]) == p {
n = n[len(p):]
host += p
}
}
if host == "git@" {
i := strings.Index(n, "/")
if i > -1 {
host += n[:i+1]
n = n[i+1:]
} else {
i = strings.Index(n, ":")
if i > -1 {
host += n[:i+1]
n = n[i+1:]
}
}
return host, n
}
// If host is a http(s) or ssh URL, grab the domain part.
for _, p := range []string{
"ssh://", "https://", "http://"} {
if strings.HasSuffix(host, p) {
i := strings.Index(n, "/")
if i > -1 {
host = host + n[0:i+1]
n = n[i+1:]
}
break
}
}
return normalizeGitHostSpec(host), n
}
func normalizeGitHostSpec(host string) string {
s := strings.ToLower(host)
if strings.Contains(s, "github.com") {
if strings.Contains(s, "git@") || strings.Contains(s, "ssh:") {
host = "git@github.com:"
} else {
host = "https://github.com/"
}
}
if strings.HasPrefix(s, "git::") {
host = strings.TrimPrefix(s, "git::")
}
return host
}
// The format of Azure repo URL is documented
// https://docs.microsoft.com/en-us/azure/devops/repos/git/clone?view=vsts&tabs=visual-studio#clone_url
func isAzureHost(host string) bool {
return strings.Contains(host, "dev.azure.com") ||
strings.Contains(host, "visualstudio.com")
}
// The format of AWS repo URL is documented
// https://docs.aws.amazon.com/codecommit/latest/userguide/regions.html
func isAWSHost(host string) bool {
return strings.Contains(host, "amazonaws.com")
}

View File

@@ -0,0 +1,288 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package git
import (
"fmt"
"path/filepath"
"strings"
"testing"
)
var orgRepos = []string{"someOrg/someRepo", "kubernetes/website"}
var pathNames = []string{"README.md", "foo/krusty.txt", ""}
var hrefArgs = []string{"someBranch", "master", "v0.1.0", ""}
var hostNamesRawAndNormalized = [][]string{
{"gh:", "gh:"},
{"GH:", "gh:"},
{"gitHub.com/", "https://github.com/"},
{"github.com:", "https://github.com/"},
{"http://github.com/", "https://github.com/"},
{"https://github.com/", "https://github.com/"},
{"hTTps://github.com/", "https://github.com/"},
{"https://git-codecommit.us-east-2.amazonaws.com/", "https://git-codecommit.us-east-2.amazonaws.com/"},
{"https://fabrikops2.visualstudio.com/", "https://fabrikops2.visualstudio.com/"},
{"ssh://git.example.com:7999/", "ssh://git.example.com:7999/"},
{"git::https://gitlab.com/", "https://gitlab.com/"},
{"git::http://git.example.com/", "http://git.example.com/"},
{"git::https://git.example.com/", "https://git.example.com/"},
{"git@github.com:", "git@github.com:"},
{"git@github.com/", "git@github.com:"},
{"git@gitlab2.sqtools.ru:10022/", "git@gitlab2.sqtools.ru:10022/"},
}
func makeUrl(hostFmt, orgRepo, path, href string) string {
if len(path) > 0 {
orgRepo = filepath.Join(orgRepo, path)
}
url := hostFmt + orgRepo
if href != "" {
url += refQuery + href
}
return url
}
func TestNewRepoSpecFromUrl(t *testing.T) {
var bad [][]string
for _, tuple := range hostNamesRawAndNormalized {
hostRaw := tuple[0]
hostSpec := tuple[1]
for _, orgRepo := range orgRepos {
for _, pathName := range pathNames {
for _, hrefArg := range hrefArgs {
uri := makeUrl(hostRaw, orgRepo, pathName, hrefArg)
rs, err := NewRepoSpecFromUrl(uri)
if err != nil {
t.Errorf("problem %v", err)
}
if rs.Host != hostSpec {
bad = append(bad, []string{"host", uri, rs.Host, hostSpec})
}
if rs.OrgRepo != orgRepo {
bad = append(bad, []string{"orgRepo", uri, rs.OrgRepo, orgRepo})
}
if rs.Path != pathName {
bad = append(bad, []string{"path", uri, rs.Path, pathName})
}
if rs.Ref != hrefArg {
bad = append(bad, []string{"ref", uri, rs.Ref, hrefArg})
}
}
}
}
}
if len(bad) > 0 {
for _, tuple := range bad {
fmt.Printf("\n"+
" from uri: %s\n"+
" actual %4s: %s\n"+
"expected %4s: %s\n",
tuple[1], tuple[0], tuple[2], tuple[0], tuple[3])
}
t.Fail()
}
}
var badData = [][]string{
{"/tmp", "uri looks like abs path"},
{"iauhsdiuashduas", "url lacks orgRepo"},
{"htxxxtp://github.com/", "url lacks host"},
{"ssh://git.example.com", "url lacks orgRepo"},
{"git::___", "url lacks orgRepo"},
}
func TestNewRepoSpecFromUrlErrors(t *testing.T) {
for _, tuple := range badData {
_, err := NewRepoSpecFromUrl(tuple[0])
if err == nil {
t.Error("expected error")
}
if !strings.Contains(err.Error(), tuple[1]) {
t.Errorf("unexpected error: %s", err)
}
}
}
func TestNewRepoSpecFromUrl_CloneSpecs(t *testing.T) {
testcases := []struct {
input string
cloneSpec string
absPath string
ref string
}{
{
input: "https://git-codecommit.us-east-2.amazonaws.com/someorg/somerepo/somedir",
cloneSpec: "https://git-codecommit.us-east-2.amazonaws.com/someorg/somerepo",
absPath: notCloned.Join("somedir"),
ref: "",
},
{
input: "https://git-codecommit.us-east-2.amazonaws.com/someorg/somerepo/somedir?ref=testbranch",
cloneSpec: "https://git-codecommit.us-east-2.amazonaws.com/someorg/somerepo",
absPath: notCloned.Join("somedir"),
ref: "testbranch",
},
{
input: "https://fabrikops2.visualstudio.com/someorg/somerepo?ref=master",
cloneSpec: "https://fabrikops2.visualstudio.com/someorg/somerepo",
absPath: notCloned.String(),
ref: "master",
},
{
input: "http://github.com/someorg/somerepo/somedir",
cloneSpec: "https://github.com/someorg/somerepo.git",
absPath: notCloned.Join("somedir"),
ref: "",
},
{
input: "git@github.com:someorg/somerepo/somedir",
cloneSpec: "git@github.com:someorg/somerepo.git",
absPath: notCloned.Join("somedir"),
ref: "",
},
{
input: "git@gitlab2.sqtools.ru:10022/infra/kubernetes/thanos-base.git?ref=v0.1.0",
cloneSpec: "git@gitlab2.sqtools.ru:10022/infra/kubernetes/thanos-base.git",
absPath: notCloned.String(),
ref: "v0.1.0",
},
{
input: "git@bitbucket.org:company/project.git//path?ref=branch",
cloneSpec: "git@bitbucket.org:company/project.git",
absPath: notCloned.Join("path"),
ref: "branch",
},
{
input: "https://itfs.mycompany.com/collection/project/_git/somerepos",
cloneSpec: "https://itfs.mycompany.com/collection/project/_git/somerepos",
absPath: notCloned.String(),
ref: "",
},
{
input: "https://itfs.mycompany.com/collection/project/_git/somerepos?version=v1.0.0",
cloneSpec: "https://itfs.mycompany.com/collection/project/_git/somerepos",
absPath: notCloned.String(),
ref: "v1.0.0",
},
{
input: "https://itfs.mycompany.com/collection/project/_git/somerepos/somedir?version=v1.0.0",
cloneSpec: "https://itfs.mycompany.com/collection/project/_git/somerepos",
absPath: notCloned.Join("somedir"),
ref: "v1.0.0",
},
{
input: "git::https://itfs.mycompany.com/collection/project/_git/somerepos",
cloneSpec: "https://itfs.mycompany.com/collection/project/_git/somerepos",
absPath: notCloned.String(),
ref: "",
},
}
for _, testcase := range testcases {
rs, err := NewRepoSpecFromUrl(testcase.input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if rs.CloneSpec() != testcase.cloneSpec {
t.Errorf("CloneSpec expected to be %v, but got %v on %s",
testcase.cloneSpec, rs.CloneSpec(), testcase.input)
}
if rs.AbsPath() != testcase.absPath {
t.Errorf("AbsPath expected to be %v, but got %v on %s",
testcase.absPath, rs.AbsPath(), testcase.input)
}
if rs.Ref != testcase.ref {
t.Errorf("ref expected to be %v, but got %v on %s",
testcase.ref, rs.Ref, testcase.input)
}
}
}
func TestIsAzureHost(t *testing.T) {
testcases := []struct {
input string
expect bool
}{
{
input: "https://git-codecommit.us-east-2.amazonaws.com",
expect: false,
},
{
input: "ssh://git-codecommit.us-east-2.amazonaws.com",
expect: false,
},
{
input: "https://fabrikops2.visualstudio.com/",
expect: true,
},
{
input: "https://dev.azure.com/myorg/myproject/",
expect: true,
},
}
for _, testcase := range testcases {
actual := isAzureHost(testcase.input)
if actual != testcase.expect {
t.Errorf("IsAzureHost: expected %v, but got %v on %s", testcase.expect, actual, testcase.input)
}
}
}
func TestPeelQuery(t *testing.T) {
testcases := []struct {
input string
expect [2]string
}{
{
input: "somerepos?ref=v1.0.0",
expect: [2]string{"somerepos", "v1.0.0"},
},
{
input: "somerepos?version=master",
expect: [2]string{"somerepos", "master"},
},
{
input: "somerepos",
expect: [2]string{"somerepos", ""},
},
}
for _, testcase := range testcases {
path, ref := peelQuery(testcase.input)
if path != testcase.expect[0] || ref != testcase.expect[1] {
t.Errorf("peelQuery: expected (%s, %s) got (%s, %s) on %s", testcase.expect[0], testcase.expect[1], path, ref, testcase.input)
}
}
}
func TestIsAWSHost(t *testing.T) {
testcases := []struct {
input string
expect bool
}{
{
input: "https://git-codecommit.us-east-2.amazonaws.com",
expect: true,
},
{
input: "ssh://git-codecommit.us-east-2.amazonaws.com",
expect: true,
},
{
input: "git@github.com:",
expect: false,
},
{
input: "http://github.com/",
expect: false,
},
}
for _, testcase := range testcases {
actual := isAWSHost(testcase.input)
if actual != testcase.expect {
t.Errorf("IsAWSHost: expected %v, but got %v on %s", testcase.expect, actual, testcase.input)
}
}
}

View File

@@ -0,0 +1,72 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package configmapandsecret generates configmaps and secrets per generator rules.
package configmapandsecret
import (
"fmt"
"unicode/utf8"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/pseudo/k8s/api/core/v1"
)
func makeFreshConfigMap(
args *types.ConfigMapArgs) *v1.ConfigMap {
cm := &v1.ConfigMap{}
cm.APIVersion = "v1"
cm.Kind = "ConfigMap"
cm.Name = args.Name
cm.Namespace = args.Namespace
cm.Data = map[string]string{}
return cm
}
// MakeConfigMap returns a new ConfigMap, or nil and an error.
func (f *Factory) MakeConfigMap(
args *types.ConfigMapArgs) (*v1.ConfigMap, error) {
all, err := f.kvLdr.Load(args.KvPairSources)
if err != nil {
return nil, errors.Wrap(err, "loading KV pairs")
}
cm := makeFreshConfigMap(args)
for _, p := range all {
err = f.addKvToConfigMap(cm, p)
if err != nil {
return nil, errors.Wrap(err, "trouble mapping")
}
}
if f.options != nil {
cm.SetLabels(f.options.Labels)
cm.SetAnnotations(f.options.Annotations)
}
return cm, nil
}
// addKvToConfigMap adds the given key and data to the given config map.
// Error if key invalid, or already exists.
func (f *Factory) addKvToConfigMap(configMap *v1.ConfigMap, p types.Pair) error {
if err := f.kvLdr.Validator().ErrIfInvalidKey(p.Key); err != nil {
return err
}
// If the configmap data contains byte sequences that are all in the UTF-8
// range, we will write it to .Data
if utf8.Valid([]byte(p.Value)) {
if _, entryExists := configMap.Data[p.Key]; entryExists {
return fmt.Errorf(keyExistsErrorMsg, p.Key, configMap.Data)
}
configMap.Data[p.Key] = p.Value
return nil
}
// otherwise, it's BinaryData
if configMap.BinaryData == nil {
configMap.BinaryData = map[string][]byte{}
}
if _, entryExists := configMap.BinaryData[p.Key]; entryExists {
return fmt.Errorf(keyExistsErrorMsg, p.Key, configMap.BinaryData)
}
configMap.BinaryData[p.Key] = []byte(p.Value)
return nil
}

View File

@@ -0,0 +1,158 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package configmapandsecret
import (
"path/filepath"
"reflect"
"testing"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/kv"
"sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/api/types"
corev1 "sigs.k8s.io/kustomize/pseudo/k8s/api/core/v1"
metav1 "sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1"
)
func makeEnvConfigMap(name string) *corev1.ConfigMap {
return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "ConfigMap",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Data: map[string]string{
"DB_USERNAME": "admin",
"DB_PASSWORD": "somepw",
},
}
}
func makeFileConfigMap(name string) *corev1.ConfigMap {
return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "ConfigMap",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Data: map[string]string{
"app-init.ini": `FOO=bar
BAR=baz
`,
},
BinaryData: map[string][]byte{
"app.bin": {0xff, 0xfd},
},
}
}
func makeLiteralConfigMap(name string) *corev1.ConfigMap {
cm := &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "ConfigMap",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Data: map[string]string{
"a": "x",
"b": "y",
"c": "Hello World",
"d": "true",
},
}
cm.SetLabels(map[string]string{"foo": "bar"})
return cm
}
func TestConstructConfigMap(t *testing.T) {
type testCase struct {
description string
input types.ConfigMapArgs
options *types.GeneratorOptions
expected *corev1.ConfigMap
}
testCases := []testCase{
{
description: "construct config map from env",
input: types.ConfigMapArgs{
GeneratorArgs: types.GeneratorArgs{
Name: "envConfigMap",
KvPairSources: types.KvPairSources{
EnvSources: []string{
filepath.Join("configmap", "app.env"),
},
},
},
},
options: nil,
expected: makeEnvConfigMap("envConfigMap"),
},
{
description: "construct config map from file",
input: types.ConfigMapArgs{
GeneratorArgs: types.GeneratorArgs{
Name: "fileConfigMap",
KvPairSources: types.KvPairSources{
FileSources: []string{
filepath.Join("configmap", "app-init.ini"),
filepath.Join("configmap", "app.bin"),
},
},
},
},
options: nil,
expected: makeFileConfigMap("fileConfigMap"),
},
{
description: "construct config map from literal",
input: types.ConfigMapArgs{
GeneratorArgs: types.GeneratorArgs{
Name: "literalConfigMap",
KvPairSources: types.KvPairSources{
LiteralSources: []string{"a=x", "b=y", "c=\"Hello World\"", "d='true'"},
},
},
},
options: &types.GeneratorOptions{
Labels: map[string]string{
"foo": "bar",
},
},
expected: makeLiteralConfigMap("literalConfigMap"),
},
}
fSys := filesys.MakeFsInMemory()
fSys.WriteFile(
filesys.RootedPath("configmap", "app.env"),
[]byte("DB_USERNAME=admin\nDB_PASSWORD=somepw\n"))
fSys.WriteFile(
filesys.RootedPath("configmap", "app-init.ini"),
[]byte("FOO=bar\nBAR=baz\n"))
fSys.WriteFile(
filesys.RootedPath("configmap", "app.bin"),
[]byte{0xff, 0xfd})
kvLdr := kv.NewLoader(
loader.NewFileLoaderAtRoot(fSys),
valtest_test.MakeFakeValidator())
for _, tc := range testCases {
f := NewFactory(kvLdr, tc.options)
cm, err := f.MakeConfigMap(&tc.input)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !reflect.DeepEqual(*cm, *tc.expected) {
t.Fatalf("in testcase: %q updated:\n%#v\ndoesn't match expected:\n%#v\n", tc.description, *cm, tc.expected)
}
}
}

View File

@@ -0,0 +1,23 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package configmapandsecret
import (
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/types"
)
// Factory makes ConfigMaps and Secrets.
type Factory struct {
kvLdr ifc.KvLoader
options *types.GeneratorOptions
}
// NewFactory returns a new factory that makes ConfigMaps and Secrets.
func NewFactory(
kvLdr ifc.KvLoader, o *types.GeneratorOptions) *Factory {
return &Factory{kvLdr: kvLdr, options: o}
}
const keyExistsErrorMsg = "cannot add key %s, another key by that name already exists: %v"

View File

@@ -0,0 +1,58 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package configmapandsecret
import (
"fmt"
"sigs.k8s.io/kustomize/api/types"
corev1 "sigs.k8s.io/kustomize/pseudo/k8s/api/core/v1"
)
func makeFreshSecret(
args *types.SecretArgs) *corev1.Secret {
s := &corev1.Secret{}
s.APIVersion = "v1"
s.Kind = "Secret"
s.Name = args.Name
s.Namespace = args.Namespace
s.Type = corev1.SecretType(args.Type)
if s.Type == "" {
s.Type = corev1.SecretTypeOpaque
}
s.Data = map[string][]byte{}
return s
}
// MakeSecret returns a new secret.
func (f *Factory) MakeSecret(
args *types.SecretArgs) (*corev1.Secret, error) {
all, err := f.kvLdr.Load(args.KvPairSources)
if err != nil {
return nil, err
}
s := makeFreshSecret(args)
for _, p := range all {
err = f.addKvToSecret(s, p.Key, p.Value)
if err != nil {
return nil, err
}
}
if f.options != nil {
s.SetLabels(f.options.Labels)
s.SetAnnotations(f.options.Annotations)
}
return s, nil
}
func (f *Factory) addKvToSecret(secret *corev1.Secret, keyName, data string) error {
if err := f.kvLdr.Validator().ErrIfInvalidKey(keyName); err != nil {
return err
}
if _, entryExists := secret.Data[keyName]; entryExists {
return fmt.Errorf(keyExistsErrorMsg, keyName, secret.Data)
}
secret.Data[keyName] = []byte(data)
return nil
}

View File

@@ -0,0 +1,143 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package configmapandsecret
import (
"reflect"
"testing"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/kv"
"sigs.k8s.io/kustomize/api/loader"
"sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/api/types"
corev1 "sigs.k8s.io/kustomize/pseudo/k8s/api/core/v1"
metav1 "sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1"
)
func makeEnvSecret(name string) *corev1.Secret {
return &corev1.Secret{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "Secret",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Data: map[string][]byte{
"DB_PASSWORD": []byte("somepw"),
"DB_USERNAME": []byte("admin"),
},
Type: "Opaque",
}
}
func makeFileSecret(name string) *corev1.Secret {
return &corev1.Secret{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "Secret",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Data: map[string][]byte{
"app-init.ini": []byte(`FOO=bar
BAR=baz
`),
},
Type: "Opaque",
}
}
func makeLiteralSecret(name string) *corev1.Secret {
s := &corev1.Secret{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "Secret",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Data: map[string][]byte{
"a": []byte("x"),
"b": []byte("y"),
},
Type: "Opaque",
}
s.SetLabels(map[string]string{"foo": "bar"})
return s
}
func TestConstructSecret(t *testing.T) {
type testCase struct {
description string
input types.SecretArgs
options *types.GeneratorOptions
expected *corev1.Secret
}
testCases := []testCase{
{
description: "construct secret from env",
input: types.SecretArgs{
GeneratorArgs: types.GeneratorArgs{
Name: "envSecret",
KvPairSources: types.KvPairSources{
EnvSources: []string{"secret/app.env"},
},
},
},
options: nil,
expected: makeEnvSecret("envSecret"),
},
{
description: "construct secret from file",
input: types.SecretArgs{
GeneratorArgs: types.GeneratorArgs{
Name: "fileSecret",
KvPairSources: types.KvPairSources{
FileSources: []string{"secret/app-init.ini"},
},
},
},
options: nil,
expected: makeFileSecret("fileSecret"),
},
{
description: "construct secret from literal",
input: types.SecretArgs{
GeneratorArgs: types.GeneratorArgs{
Name: "literalSecret",
KvPairSources: types.KvPairSources{
LiteralSources: []string{"a=x", "b=y"},
},
},
},
options: &types.GeneratorOptions{
Labels: map[string]string{
"foo": "bar",
},
},
expected: makeLiteralSecret("literalSecret"),
},
}
fSys := filesys.MakeFsInMemory()
fSys.WriteFile("/secret/app.env", []byte("DB_USERNAME=admin\nDB_PASSWORD=somepw\n"))
fSys.WriteFile("/secret/app-init.ini", []byte("FOO=bar\nBAR=baz\n"))
kvLdr := kv.NewLoader(
loader.NewFileLoaderAtRoot(fSys),
valtest_test.MakeFakeValidator())
for _, tc := range testCases {
f := NewFactory(kvLdr, tc.options)
cm, err := f.MakeSecret(&tc.input)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !reflect.DeepEqual(*cm, *tc.expected) {
t.Fatalf("in testcase: %q updated:\n%#v\ndoesn't match expected:\n%#v\n", tc.description, *cm, tc.expected)
}
}
}

View File

@@ -0,0 +1,25 @@
// 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,221 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package patch
import (
"encoding/json"
"fmt"
jsonpatch "github.com/evanphx/json-patch"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/runtime"
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/util/mergepatch"
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/util/strategicpatch"
"sigs.k8s.io/kustomize/pseudo/k8s/client-go/kubernetes/scheme"
)
type conflictDetector interface {
hasConflict(patch1, patch2 *resource.Resource) (bool, error)
findConflict(conflictingPatchIdx int, patches []*resource.Resource) (*resource.Resource, error)
mergePatches(patch1, patch2 *resource.Resource) (*resource.Resource, error)
}
type jsonMergePatch struct {
rf *resource.Factory
}
var _ conflictDetector = &jsonMergePatch{}
func newJMPConflictDetector(rf *resource.Factory) conflictDetector {
return &jsonMergePatch{rf: rf}
}
func (jmp *jsonMergePatch) hasConflict(
patch1, patch2 *resource.Resource) (bool, error) {
return mergepatch.HasConflicts(patch1.Map(), patch2.Map())
}
func (jmp *jsonMergePatch) findConflict(
conflictingPatchIdx int, patches []*resource.Resource) (*resource.Resource, error) {
for i, patch := range patches {
if i == conflictingPatchIdx {
continue
}
if !patches[conflictingPatchIdx].OrgId().Equals(patch.OrgId()) {
continue
}
conflict, err := mergepatch.HasConflicts(
patch.Map(),
patches[conflictingPatchIdx].Map())
if err != nil {
return nil, err
}
if conflict {
return patch, nil
}
}
return nil, nil
}
func (jmp *jsonMergePatch) mergePatches(
patch1, patch2 *resource.Resource) (*resource.Resource, error) {
baseBytes, err := json.Marshal(patch1.Map())
if err != nil {
return nil, err
}
patchBytes, err := json.Marshal(patch2.Map())
if err != nil {
return nil, err
}
mergedBytes, err := jsonpatch.MergeMergePatches(baseBytes, patchBytes)
if err != nil {
return nil, err
}
mergedMap := make(map[string]interface{})
err = json.Unmarshal(mergedBytes, &mergedMap)
return jmp.rf.FromMap(mergedMap), err
}
type strategicMergePatch struct {
lookupPatchMeta strategicpatch.LookupPatchMeta
rf *resource.Factory
}
var _ conflictDetector = &strategicMergePatch{}
func newSMPConflictDetector(
versionedObj runtime.Object,
rf *resource.Factory) (conflictDetector, error) {
lookupPatchMeta, err := strategicpatch.NewPatchMetaFromStruct(versionedObj)
return &strategicMergePatch{lookupPatchMeta: lookupPatchMeta, rf: rf}, err
}
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) {
for i, patch := range patches {
if i == conflictingPatchIdx {
continue
}
if !patches[conflictingPatchIdx].OrgId().Equals(patch.OrgId()) {
continue
}
conflict, err := strategicpatch.MergingMapsHaveConflicts(
patch.Map(),
patches[conflictingPatchIdx].Map(),
smp.lookupPatchMeta)
if err != nil {
return nil, err
}
if conflict {
return patch, nil
}
}
return nil, nil
}
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")
}
patch1, patch2 = patch2, patch1
}
mergeJSONMap, err := strategicpatch.MergeStrategicMergeMapPatchUsingLookupPatchMeta(
smp.lookupPatchMeta, patch1.Map(), patch2.Map())
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) {
rc := resmap.New()
for ix, patch := range patches {
id := patch.OrgId()
existing := rc.GetMatchingResourcesByOriginalId(id.Equals)
if len(existing) == 0 {
rc.Append(patch)
continue
}
if len(existing) > 1 {
return nil, fmt.Errorf("self conflict in patches")
}
versionedObj, err := scheme.Scheme.New(toSchemaGvk(id.Gvk))
if err != nil && !runtime.IsNotRegisteredError(err) {
return nil, err
}
var cd conflictDetector
if err != nil {
cd = newJMPConflictDetector(rf)
} else {
cd, err = newSMPConflictDetector(versionedObj, rf)
if err != nil {
return nil, err
}
}
conflict, err := cd.hasConflict(existing[0], patch)
if err != nil {
return nil, err
}
if conflict {
conflictingPatch, err := cd.findConflict(ix, patches)
if err != nil {
return nil, err
}
return nil, fmt.Errorf(
"conflict between %#v and %#v",
conflictingPatch.Map(), patch.Map())
}
merged, err := cd.mergePatches(existing[0], patch)
if err != nil {
return nil, err
}
rc.Replace(merged)
}
return rc, nil
}
// toSchemaGvk converts to a schema.GroupVersionKind.
func toSchemaGvk(x resid.Gvk) schema.GroupVersionKind {
return schema.GroupVersionKind{
Group: x.Group,
Version: x.Version,
Kind: x.Kind,
}
}
func hasDeleteDirectiveMarker(patch map[string]interface{}) bool {
if v, ok := patch["$patch"]; ok && v == "delete" {
return true
}
for _, v := range patch {
switch typedV := v.(type) {
case map[string]interface{}:
if hasDeleteDirectiveMarker(typedV) {
return true
}
case []interface{}:
for _, sv := range typedV {
typedE, ok := sv.(map[string]interface{})
if !ok {
break
}
if hasDeleteDirectiveMarker(typedE) {
return true
}
}
}
}
return false
}

View File

@@ -0,0 +1,35 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package error has contextual error types.
package kusterr
import (
"fmt"
"strings"
)
// YamlFormatError represents error with yaml file name where json/yaml format error happens.
type YamlFormatError struct {
Path string
ErrorMsg string
}
func (e YamlFormatError) Error() string {
return fmt.Sprintf("YAML file [%s] encounters a format error.\n%s\n", e.Path, e.ErrorMsg)
}
// Handler handles YamlFormatError
func Handler(e error, path string) error {
if isYAMLSyntaxError(e) {
return YamlFormatError{
Path: path,
ErrorMsg: e.Error(),
}
}
return e
}
func isYAMLSyntaxError(e error) bool {
return strings.Contains(e.Error(), "error converting YAML to JSON") || strings.Contains(e.Error(), "error unmarshaling JSON")
}

View File

@@ -0,0 +1,41 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package kusterr
import (
"fmt"
"testing"
)
const (
filepath = "/path/to/whatever"
expected = "YAML file [/path/to/whatever] encounters a format error.\n" +
"error converting YAML to JSON: yaml: line 2: found character that cannot start any token\n"
)
func TestYamlFormatError_Error(t *testing.T) {
testErr := YamlFormatError{
Path: filepath,
ErrorMsg: "error converting YAML to JSON: yaml: line 2: found character that cannot start any token",
}
if testErr.Error() != expected {
t.Errorf("Expected : %s\n, but found : %s\n", expected, testErr.Error())
}
}
func TestErrorHandler(t *testing.T) {
err := fmt.Errorf("error converting YAML to JSON: yaml: line 2: found character that cannot start any token")
testErr := Handler(err, filepath)
expectedErr := fmt.Errorf("format error message")
fmtErr := Handler(expectedErr, filepath)
if fmtErr.Error() != expectedErr.Error() {
t.Errorf("Expected returning fmt.Error, but found %T", fmtErr)
}
if _, ok := testErr.(YamlFormatError); !ok {
t.Errorf("Expected returning YamlFormatError, but found %T", testErr)
}
if testErr == nil || testErr.Error() != expected {
t.Errorf("Expected : %s\n, but found : %s\n", expected, testErr.Error())
}
}

View File

@@ -0,0 +1,76 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package loadertest holds a fake for the Loader interface.
package loadertest
import (
"log"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/loader"
)
// FakeLoader encapsulates the delegate Loader and the fake file system.
type FakeLoader struct {
fs filesys.FileSystem
delegate ifc.Loader
}
// NewFakeLoader returns a Loader that uses a fake filesystem.
// The loader will be restricted to root only.
// The initialDir argument should be an absolute file path.
func NewFakeLoader(initialDir string) FakeLoader {
return NewFakeLoaderWithRestrictor(
loader.RestrictionRootOnly, initialDir)
}
// NewFakeLoaderWithRestrictor returns a Loader that
// uses a fake filesystem.
// The initialDir argument should be an absolute file path.
func NewFakeLoaderWithRestrictor(
lr loader.LoadRestrictorFunc, initialDir string) FakeLoader {
// Create fake filesystem and inject it into initial Loader.
fSys := filesys.MakeFsInMemory()
fSys.Mkdir(initialDir)
ldr, err := loader.NewLoader(lr, initialDir, fSys)
if err != nil {
log.Fatalf("Unable to make loader: %v", err)
}
return FakeLoader{fs: fSys, delegate: ldr}
}
// AddFile adds a fake file to the file system.
func (f FakeLoader) AddFile(fullFilePath string, content []byte) error {
return f.fs.WriteFile(fullFilePath, content)
}
// AddDirectory adds a fake directory to the file system.
func (f FakeLoader) AddDirectory(fullDirPath string) error {
return f.fs.Mkdir(fullDirPath)
}
// Root delegates.
func (f FakeLoader) Root() string {
return f.delegate.Root()
}
// New creates a new loader from a new root.
func (f FakeLoader) New(newRoot string) (ifc.Loader, error) {
l, err := f.delegate.New(newRoot)
if err != nil {
return nil, err
}
return FakeLoader{fs: f.fs, delegate: l}, nil
}
// Load delegates.
func (f FakeLoader) Load(location string) ([]byte, error) {
return f.delegate.Load(location)
}
// Cleanup delegates.
func (f FakeLoader) Cleanup() error {
return f.delegate.Cleanup()
}

View File

@@ -0,0 +1,10 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package builtinconfig provides legacy methods for
// configuring builtin plugins from a common config file.
// As a user, its best to configure plugins individually
// with plugin config files specified in the `transformers:`
// or `generators:` field, than to use this legacy
// configuration technique.
package builtinconfig

View File

@@ -0,0 +1,42 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package builtinconfig
import (
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/yaml"
)
// loadDefaultConfig returns a TranformerConfig
// object from a list of files.
func loadDefaultConfig(
ldr ifc.Loader, paths []string) (*TransformerConfig, error) {
result := &TransformerConfig{}
for _, path := range paths {
data, err := ldr.Load(path)
if err != nil {
return nil, err
}
t, err := makeTransformerConfigFromBytes(data)
if err != nil {
return nil, err
}
result, err = result.Merge(t)
if err != nil {
return nil, err
}
}
return result, nil
}
// makeTransformerConfigFromBytes returns a TransformerConfig object from bytes
func makeTransformerConfigFromBytes(data []byte) (*TransformerConfig, error) {
var t TransformerConfig
err := yaml.Unmarshal(data, &t)
if err != nil {
return nil, err
}
t.sortFields()
return &t, nil
}

View File

@@ -0,0 +1,37 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package builtinconfig
import (
"reflect"
"testing"
"sigs.k8s.io/kustomize/api/internal/loadertest"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/types"
)
func TestLoadDefaultConfigsFromFiles(t *testing.T) {
ldr := loadertest.NewFakeLoader("/app")
ldr.AddFile("/app/config.yaml", []byte(`
namePrefix:
- path: nameprefix/path
kind: SomeKind
`))
tcfg, err := loadDefaultConfig(ldr, []string{"/app/config.yaml"})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expected := &TransformerConfig{
NamePrefix: []types.FieldSpec{
{
Gvk: resid.Gvk{Kind: "SomeKind"},
Path: "nameprefix/path",
},
},
}
if !reflect.DeepEqual(tcfg, expected) {
t.Fatalf("expected %v\n but go6t %v\n", expected, tcfg)
}
}

View File

@@ -0,0 +1,93 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package builtinconfig
import (
"strings"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/types"
)
// NameBackReferences is an association between a gvk.GVK and a list
// of FieldSpec instances that could refer to it.
//
// It is used to handle name changes, and can be thought of as a
// a contact list. If you change your own contact info (name,
// phone number, etc.), you must tell your contacts or they won't
// know about the change.
//
// For example, ConfigMaps can be used by Pods and everything that
// contains a Pod; Deployment, Job, StatefulSet, etc. To change
// the name of a ConfigMap instance from 'alice' to 'bob', one
// must visit all objects that could refer to the ConfigMap, see if
// they mention 'alice', and if so, change the reference to 'bob'.
//
// The NameBackReferences instance to aid in this could look like
// {
// kind: ConfigMap
// version: v1
// FieldSpecs:
// - kind: Pod
// version: v1
// path: spec/volumes/configMap/name
// - kind: Deployment
// path: spec/template/spec/volumes/configMap/name
// - kind: Job
// path: spec/template/spec/volumes/configMap/name
// (etc.)
// }
type NameBackReferences struct {
resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
FieldSpecs types.FsSlice `json:"FieldSpecs,omitempty" yaml:"FieldSpecs,omitempty"`
}
func (n NameBackReferences) String() string {
var r []string
for _, f := range n.FieldSpecs {
r = append(r, f.String())
}
return n.Gvk.String() + ": (\n" +
strings.Join(r, "\n") + "\n)"
}
type nbrSlice []NameBackReferences
func (s nbrSlice) Len() int { return len(s) }
func (s nbrSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s nbrSlice) Less(i, j int) bool {
return s[i].Gvk.IsLessThan(s[j].Gvk)
}
func (s nbrSlice) mergeAll(o nbrSlice) (result nbrSlice, err error) {
result = s
for _, r := range o {
result, err = result.mergeOne(r)
if err != nil {
return nil, err
}
}
return result, nil
}
func (s nbrSlice) mergeOne(other NameBackReferences) (nbrSlice, error) {
var result nbrSlice
var err error
found := false
for _, c := range s {
if c.Gvk.Equals(other.Gvk) {
c.FieldSpecs, err = c.FieldSpecs.MergeAll(other.FieldSpecs)
if err != nil {
return nil, err
}
found = true
}
result = append(result, c)
}
if !found {
result = append(result, other)
}
return result, nil
}

View File

@@ -0,0 +1,97 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package builtinconfig
import (
"reflect"
"testing"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/types"
)
func TestMergeAll(t *testing.T) {
fsSlice1 := []types.FieldSpec{
{
Gvk: resid.Gvk{
Kind: "Pod",
},
Path: "path/to/a/name",
CreateIfNotPresent: false,
},
{
Gvk: resid.Gvk{
Kind: "Deployment",
},
Path: "another/path/to/some/name",
CreateIfNotPresent: false,
},
}
fsSlice2 := []types.FieldSpec{
{
Gvk: resid.Gvk{
Kind: "Job",
},
Path: "morepath/to/name",
CreateIfNotPresent: false,
},
{
Gvk: resid.Gvk{
Kind: "StatefulSet",
},
Path: "yet/another/path/to/a/name",
CreateIfNotPresent: false,
},
}
nbrsSlice1 := nbrSlice{
{
Gvk: resid.Gvk{
Kind: "ConfigMap",
},
FieldSpecs: fsSlice1,
},
{
Gvk: resid.Gvk{
Kind: "Secret",
},
FieldSpecs: fsSlice2,
},
}
nbrsSlice2 := nbrSlice{
{
Gvk: resid.Gvk{
Kind: "ConfigMap",
},
FieldSpecs: fsSlice1,
},
{
Gvk: resid.Gvk{
Kind: "Secret",
},
FieldSpecs: fsSlice2,
},
}
expected := nbrSlice{
{
Gvk: resid.Gvk{
Kind: "ConfigMap",
},
FieldSpecs: fsSlice1,
},
{
Gvk: resid.Gvk{
Kind: "Secret",
},
FieldSpecs: fsSlice2,
},
}
actual, err := nbrsSlice1.mergeAll(nbrsSlice2)
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("expected\n %v\n but got\n %v\n", expected, actual)
}
}

View File

@@ -0,0 +1,148 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package builtinconfig
import (
"log"
"sort"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts"
"sigs.k8s.io/kustomize/api/types"
)
// TransformerConfig holds the data needed to perform transformations.
type TransformerConfig struct {
NamePrefix types.FsSlice `json:"namePrefix,omitempty" yaml:"namePrefix,omitempty"`
NameSuffix types.FsSlice `json:"nameSuffix,omitempty" yaml:"nameSuffix,omitempty"`
NameSpace types.FsSlice `json:"namespace,omitempty" yaml:"namespace,omitempty"`
CommonLabels types.FsSlice `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"`
CommonAnnotations types.FsSlice `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"`
NameReference nbrSlice `json:"nameReference,omitempty" yaml:"nameReference,omitempty"`
VarReference types.FsSlice `json:"varReference,omitempty" yaml:"varReference,omitempty"`
Images types.FsSlice `json:"images,omitempty" yaml:"images,omitempty"`
Replicas types.FsSlice `json:"replicas,omitempty" yaml:"replicas,omitempty"`
}
// MakeEmptyConfig returns an empty TransformerConfig object
func MakeEmptyConfig() *TransformerConfig {
return &TransformerConfig{}
}
// MakeDefaultConfig returns a default TransformerConfig.
func MakeDefaultConfig() *TransformerConfig {
c, err := makeTransformerConfigFromBytes(
builtinpluginconsts.GetDefaultFieldSpecs())
if err != nil {
log.Fatalf("Unable to make default transformconfig: %v", err)
}
return c
}
// MakeTransformerConfig returns a merger of custom config,
// if any, with default config.
func MakeTransformerConfig(
ldr ifc.Loader, paths []string) (*TransformerConfig, error) {
t1 := MakeDefaultConfig()
if len(paths) == 0 {
return t1, nil
}
t2, err := loadDefaultConfig(ldr, paths)
if err != nil {
return nil, err
}
return t1.Merge(t2)
}
// sortFields provides determinism in logging, tests, etc.
func (t *TransformerConfig) sortFields() {
sort.Sort(t.NamePrefix)
sort.Sort(t.NameSpace)
sort.Sort(t.CommonLabels)
sort.Sort(t.CommonAnnotations)
sort.Sort(t.NameReference)
sort.Sort(t.VarReference)
sort.Sort(t.Images)
sort.Sort(t.Replicas)
}
// AddPrefixFieldSpec adds a FieldSpec to NamePrefix
func (t *TransformerConfig) AddPrefixFieldSpec(fs types.FieldSpec) (err error) {
t.NamePrefix, err = t.NamePrefix.MergeOne(fs)
return err
}
// AddSuffixFieldSpec adds a FieldSpec to NameSuffix
func (t *TransformerConfig) AddSuffixFieldSpec(fs types.FieldSpec) (err error) {
t.NameSuffix, err = t.NameSuffix.MergeOne(fs)
return err
}
// AddLabelFieldSpec adds a FieldSpec to CommonLabels
func (t *TransformerConfig) AddLabelFieldSpec(fs types.FieldSpec) (err error) {
t.CommonLabels, err = t.CommonLabels.MergeOne(fs)
return err
}
// AddAnnotationFieldSpec adds a FieldSpec to CommonAnnotations
func (t *TransformerConfig) AddAnnotationFieldSpec(fs types.FieldSpec) (err error) {
t.CommonAnnotations, err = t.CommonAnnotations.MergeOne(fs)
return err
}
// AddNamereferenceFieldSpec adds a NameBackReferences to NameReference
func (t *TransformerConfig) AddNamereferenceFieldSpec(
nbrs NameBackReferences) (err error) {
t.NameReference, err = t.NameReference.mergeOne(nbrs)
return err
}
// Merge merges two TransformerConfigs objects into
// a new TransformerConfig object
func (t *TransformerConfig) Merge(input *TransformerConfig) (
merged *TransformerConfig, err error) {
if input == nil {
return t, nil
}
merged = &TransformerConfig{}
merged.NamePrefix, err = t.NamePrefix.MergeAll(input.NamePrefix)
if err != nil {
return nil, err
}
merged.NameSuffix, err = t.NameSuffix.MergeAll(input.NameSuffix)
if err != nil {
return nil, err
}
merged.NameSpace, err = t.NameSpace.MergeAll(input.NameSpace)
if err != nil {
return nil, err
}
merged.CommonAnnotations, err = t.CommonAnnotations.MergeAll(
input.CommonAnnotations)
if err != nil {
return nil, err
}
merged.CommonLabels, err = t.CommonLabels.MergeAll(input.CommonLabels)
if err != nil {
return nil, err
}
merged.VarReference, err = t.VarReference.MergeAll(input.VarReference)
if err != nil {
return nil, err
}
merged.NameReference, err = t.NameReference.mergeAll(input.NameReference)
if err != nil {
return nil, err
}
merged.Images, err = t.Images.MergeAll(input.Images)
if err != nil {
return nil, err
}
merged.Replicas, err = t.Replicas.MergeAll(input.Replicas)
if err != nil {
return nil, err
}
merged.sortFields()
return merged, nil
}

View File

@@ -1,39 +1,32 @@
/*
Copyright 2018 The Kubernetes Authors.
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
package builtinconfig_test
import (
"reflect"
"testing"
"reflect"
"sigs.k8s.io/kustomize/pkg/gvk"
. "sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/types"
)
func TestMakeDefaultConfig(t *testing.T) {
// Confirm default can be made without fatal error inside call.
_ = MakeDefaultConfig()
}
func TestAddNamereferenceFieldSpec(t *testing.T) {
cfg := &TransformerConfig{}
nbrs := NameBackReferences{
Gvk: gvk.Gvk{
Gvk: resid.Gvk{
Kind: "KindA",
},
FieldSpecs: []FieldSpec{
FieldSpecs: []types.FieldSpec{
{
Gvk: gvk.Gvk{
Gvk: resid.Gvk{
Kind: "KindB",
},
Path: "path/to/a/field",
@@ -54,8 +47,8 @@ func TestAddNamereferenceFieldSpec(t *testing.T) {
func TestAddFieldSpecs(t *testing.T) {
cfg := &TransformerConfig{}
fieldSpec := FieldSpec{
Gvk: gvk.Gvk{Group: "GroupA", Kind: "KindB"},
fieldSpec := types.FieldSpec{
Gvk: resid.Gvk{Group: "GroupA", Kind: "KindB"},
Path: "path/to/a/field",
CreateIfNotPresent: true,
}
@@ -93,12 +86,12 @@ func TestAddFieldSpecs(t *testing.T) {
func TestMerge(t *testing.T) {
nameReference := []NameBackReferences{
{
Gvk: gvk.Gvk{
Gvk: resid.Gvk{
Kind: "KindA",
},
FieldSpecs: []FieldSpec{
FieldSpecs: []types.FieldSpec{
{
Gvk: gvk.Gvk{
Gvk: resid.Gvk{
Kind: "KindB",
},
Path: "path/to/a/field",
@@ -107,12 +100,12 @@ func TestMerge(t *testing.T) {
},
},
{
Gvk: gvk.Gvk{
Gvk: resid.Gvk{
Kind: "KindA",
},
FieldSpecs: []FieldSpec{
FieldSpecs: []types.FieldSpec{
{
Gvk: gvk.Gvk{
Gvk: resid.Gvk{
Kind: "KindC",
},
Path: "path/to/a/field",
@@ -121,14 +114,14 @@ func TestMerge(t *testing.T) {
},
},
}
fieldSpecs := []FieldSpec{
fieldSpecs := []types.FieldSpec{
{
Gvk: gvk.Gvk{Group: "GroupA", Kind: "KindB"},
Gvk: resid.Gvk{Group: "GroupA", Kind: "KindB"},
Path: "path/to/a/field",
CreateIfNotPresent: true,
},
{
Gvk: gvk.Gvk{Group: "GroupA", Kind: "KindC"},
Gvk: resid.Gvk{Group: "GroupA", Kind: "KindC"},
Path: "path/to/a/field",
CreateIfNotPresent: true,
},

View File

@@ -0,0 +1,37 @@
// Code generated by "stringer -type=BuiltinPluginType"; DO NOT EDIT.
package builtinhelpers
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[Unknown-0]
_ = x[AnnotationsTransformer-1]
_ = x[ConfigMapGenerator-2]
_ = x[HashTransformer-3]
_ = x[ImageTagTransformer-4]
_ = x[InventoryTransformer-5]
_ = x[LabelTransformer-6]
_ = x[LegacyOrderTransformer-7]
_ = x[NamespaceTransformer-8]
_ = x[PatchJson6902Transformer-9]
_ = x[PatchStrategicMergeTransformer-10]
_ = x[PatchTransformer-11]
_ = x[PrefixSuffixTransformer-12]
_ = x[ReplicaCountTransformer-13]
_ = x[SecretGenerator-14]
}
const _BuiltinPluginType_name = "UnknownAnnotationsTransformerConfigMapGeneratorHashTransformerImageTagTransformerInventoryTransformerLabelTransformerLegacyOrderTransformerNamespaceTransformerPatchJson6902TransformerPatchStrategicMergeTransformerPatchTransformerPrefixSuffixTransformerReplicaCountTransformerSecretGenerator"
var _BuiltinPluginType_index = [...]uint16{0, 7, 29, 47, 62, 81, 101, 117, 139, 159, 183, 213, 229, 252, 275, 290}
func (i BuiltinPluginType) String() string {
if i < 0 || i >= BuiltinPluginType(len(_BuiltinPluginType_index)-1) {
return "BuiltinPluginType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _BuiltinPluginType_name[_BuiltinPluginType_index[i]:_BuiltinPluginType_index[i+1]]
}

View File

@@ -0,0 +1,75 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package builtinhelpers
import (
"sigs.k8s.io/kustomize/api/builtins"
"sigs.k8s.io/kustomize/api/resmap"
)
//go:generate stringer -type=BuiltinPluginType
type BuiltinPluginType int
const (
Unknown BuiltinPluginType = iota
AnnotationsTransformer
ConfigMapGenerator
HashTransformer
ImageTagTransformer
InventoryTransformer
LabelTransformer
LegacyOrderTransformer
NamespaceTransformer
PatchJson6902Transformer
PatchStrategicMergeTransformer
PatchTransformer
PrefixSuffixTransformer
ReplicaCountTransformer
SecretGenerator
)
var stringToBuiltinPluginTypeMap map[string]BuiltinPluginType
func init() {
stringToBuiltinPluginTypeMap = makeStringToBuiltinPluginTypeMap()
}
func makeStringToBuiltinPluginTypeMap() (result map[string]BuiltinPluginType) {
result = make(map[string]BuiltinPluginType, 23)
for k := range GeneratorFactories {
result[k.String()] = k
}
for k := range TransformerFactories {
result[k.String()] = k
}
return
}
func GetBuiltinPluginType(n string) BuiltinPluginType {
result, ok := stringToBuiltinPluginTypeMap[n]
if ok {
return result
}
return Unknown
}
var GeneratorFactories = map[BuiltinPluginType]func() resmap.GeneratorPlugin{
ConfigMapGenerator: builtins.NewConfigMapGeneratorPlugin,
SecretGenerator: builtins.NewSecretGeneratorPlugin,
}
var TransformerFactories = map[BuiltinPluginType]func() resmap.TransformerPlugin{
AnnotationsTransformer: builtins.NewAnnotationsTransformerPlugin,
HashTransformer: builtins.NewHashTransformerPlugin,
ImageTagTransformer: builtins.NewImageTagTransformerPlugin,
InventoryTransformer: builtins.NewInventoryTransformerPlugin,
LabelTransformer: builtins.NewLabelTransformerPlugin,
LegacyOrderTransformer: builtins.NewLegacyOrderTransformerPlugin,
NamespaceTransformer: builtins.NewNamespaceTransformerPlugin,
PatchJson6902Transformer: builtins.NewPatchJson6902TransformerPlugin,
PatchStrategicMergeTransformer: builtins.NewPatchStrategicMergeTransformerPlugin,
PatchTransformer: builtins.NewPatchTransformerPlugin,
PrefixSuffixTransformer: builtins.NewPrefixSuffixTransformerPlugin,
ReplicaCountTransformer: builtins.NewReplicaCountTransformerPlugin,
}

View File

@@ -0,0 +1,173 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package compiler
import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/konfig"
)
// Compiler creates Go plugin object files.
//
// Source code is read from
// ${srcRoot}/${g}/${v}/${k}.go
//
// Object code is written to
// ${objRoot}/${g}/${v}/${k}.so
type Compiler struct {
srcRoot string
objRoot string
}
// DeterminePluginSrcRoot guesses where the user
// has her ${g}/${v}/$lower(${k})/${k}.go files.
func DeterminePluginSrcRoot(fSys filesys.FileSystem) (string, error) {
return konfig.FirstDirThatExistsElseError(
"source directory", fSys, []konfig.NotedFunc{
{
Note: "relative to unit test",
F: func() string {
return filepath.Clean(
filepath.Join(
os.Getenv("PWD"),
"..", "..", "..", "..",
konfig.RelPluginHome))
},
},
{
Note: "relative to api package",
F: func() string {
return filepath.Clean(
filepath.Join(
os.Getenv("PWD"),
"..", "..", "..",
konfig.RelPluginHome))
},
},
{
Note: "old style $GOPATH",
F: func() string {
return filepath.Join(
os.Getenv("GOPATH"),
"src", konfig.DomainName,
konfig.ProgramName, konfig.RelPluginHome)
},
},
{
Note: "HOME with literal 'gopath'",
F: func() string {
return filepath.Join(
konfig.HomeDir(), "gopath",
"src", konfig.DomainName,
konfig.ProgramName, konfig.RelPluginHome)
},
},
{
Note: "home directory",
F: func() string {
return filepath.Join(
konfig.HomeDir(), konfig.DomainName,
konfig.ProgramName, konfig.RelPluginHome)
},
},
})
}
// NewCompiler returns a new compiler instance.
func NewCompiler(srcRoot, objRoot string) *Compiler {
return &Compiler{srcRoot: srcRoot, objRoot: objRoot}
}
// ObjRoot is root of compilation target tree.
func (b *Compiler) ObjRoot() string {
return b.objRoot
}
// SrcRoot is where to find src.
func (b *Compiler) SrcRoot() string {
return b.srcRoot
}
func goBin() string {
return filepath.Join(runtime.GOROOT(), "bin", "go")
}
// Compile reads ${srcRoot}/${g}/${v}/${k}.go
// and writes ${objRoot}/${g}/${v}/${k}.so
func (b *Compiler) Compile(g, v, k string) error {
lowK := strings.ToLower(k)
objDir := filepath.Join(b.objRoot, g, v, lowK)
objFile := filepath.Join(objDir, k) + ".so"
if RecentFileExists(objFile) {
// Skip rebuilding it.
return nil
}
err := os.MkdirAll(objDir, os.ModePerm)
if err != nil {
return err
}
srcFile := filepath.Join(b.srcRoot, g, v, lowK, k) + ".go"
if !FileExists(srcFile) {
// Handy for tests of lone plugins.
s := k + ".go"
if !FileExists(s) {
return fmt.Errorf(
"cannot find source at '%s' or '%s'", srcFile, s)
}
srcFile = s
}
commands := []string{
"build",
"-buildmode",
"plugin",
"-o", objFile, srcFile,
}
goBin := goBin()
if !FileExists(goBin) {
return fmt.Errorf(
"cannot find go compiler %s", goBin)
}
cmd := exec.Command(goBin, commands...)
var stderr bytes.Buffer
cmd.Stderr = &stderr
cmd.Env = os.Environ()
if err := cmd.Run(); err != nil {
return errors.Wrapf(
err, "cannot compile %s:\nSTDERR\n%s\n", srcFile, stderr.String())
}
return nil
}
// True if file less than 3 minutes old, i.e. not
// accidentally left over from some earlier build.
func RecentFileExists(path string) bool {
fi, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return false
}
}
age := time.Now().Sub(fi.ModTime())
return age.Minutes() < 3
}
func FileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
return false
}
}
return true
}

View File

@@ -0,0 +1,67 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package compiler_test
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"sigs.k8s.io/kustomize/api/filesys"
. "sigs.k8s.io/kustomize/api/internal/plugins/compiler"
)
// Regression coverage over compiler behavior.
func TestCompiler(t *testing.T) {
configRoot, err := ioutil.TempDir("", "kustomize-compiler-test")
if err != nil {
t.Errorf("failed to make temp dir: %v", err)
}
srcRoot, err := DeterminePluginSrcRoot(filesys.MakeFsOnDisk())
if err != nil {
t.Error(err)
}
c := NewCompiler(srcRoot, configRoot)
if configRoot != c.ObjRoot() {
t.Errorf("unexpected objRoot %s", c.ObjRoot())
}
expectObj := filepath.Join(
c.ObjRoot(),
"someteam.example.com", "v1", "dateprefixer", "DatePrefixer.so")
if FileExists(expectObj) {
t.Errorf("obj file should not exist yet: %s", expectObj)
}
err = c.Compile("someteam.example.com", "v1", "DatePrefixer")
if err != nil {
t.Error(err)
}
if !RecentFileExists(expectObj) {
t.Errorf("didn't find expected obj file %s", expectObj)
}
expectObj = filepath.Join(
c.ObjRoot(),
"builtin", "", "secretgenerator", "SecretGenerator.so")
if FileExists(expectObj) {
t.Errorf("obj file should not exist yet: %s", expectObj)
}
err = c.Compile("builtin", "", "SecretGenerator")
if err != nil {
t.Error(err)
}
if !RecentFileExists(expectObj) {
t.Errorf("didn't find expected obj file %s", expectObj)
}
err = os.RemoveAll(c.ObjRoot())
if err != nil {
t.Errorf(
"removing temp dir: %s %v", c.ObjRoot(), err)
}
if FileExists(expectObj) {
t.Errorf("cleanup failed; still see: %s", expectObj)
}
}

118
api/internal/plugins/doc.go Normal file
View File

@@ -0,0 +1,118 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
/*
Read docs/plugins.md first for an overview of kustomize plugins.
BUILTIN PLUGIN CONFIGURATION
There are two kinds of plugins, Go plugins (shared
object library) and exec plugins (independent binary).
For performance and standardized testing reasons, all
builtin plugins are Go plugins (not exec plugins).
Using "SecretGenerator" as an example in what
follows.
The plugin config file looks like
apiVersion: builtin
kind: SecretGenerator
metadata:
name: whatever
otherField1: whatever
otherField2: whatever
...
The apiVersion must be 'builtin'.
The kind is the CamelCase name of the plugin.
The source for a builtin plugin must be at:
repo=$GOPATH/src/sigs.k8s.io/kustomize
${repo}/plugin/builtin/LOWERCASE(${kind})/${kind}
k8s wants 'kind' values to follow CamelCase, while
Go style doesn't like but does allow such names.
The lowercased value of kind is used as the name of the
directory holding the plugin, its test, and any
optional associated files (possibly a go.mod file).
BUILTIN PLUGIN GENERATION
The `pluginator` program is a code generator that
converts kustomize generator (G) and/or
transformer (T) Go plugins to statically linkable
code.
It arises from following requirements:
* extension
kustomize does two things - generate or
transform k8s resources. Plugins let
users write their own G&T's without
having to fork kustomize and learn its
internals.
* dogfooding
A G&T extension framework one can trust
should be used by its authors to deliver
builtin G&T's.
* distribution
kustomize should be distributable via
`go get` and should run where Go
programs are expected to run.
The extension requirement led to building
a framework that accommodates writing a
G or T as either
* an 'exec' plugin (any executable file
runnable as a kustomize subprocess), or
* as a Go plugin - see
https://golang.org/pkg/plugin.
The dogfooding (and an implicit performance
requirement) requires a 'builtin' G or T to
be written as a Go plugin.
The distribution ('go get') requirement demands
conversion of Go plugins to statically linked
code, hence this program.
TO GENERATE CODE
repo=$GOPATH/src/sigs.k8s.io/kustomize
cd $repo/plugin/builtin
go generate ./...
See travis/pre-commit.sh for canonical way
to execute the above.
This creates
$repo/api/plugins/builtins/SecretGenerator.go
etc.
Generated plugins are used in kustomize via
package whatever
import sigs.k8s.io/kustomize/api/plugins/builtins
...
g := builtin.NewSecretGenerator()
g.Config(h, k)
resources, err := g.Generate()
err = g.Transform(resources)
// Eventually emit resources.
*/
package plugins

View File

@@ -0,0 +1,270 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package execplugin
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
"strconv"
"strings"
"github.com/pkg/errors"
"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"
tmpConfigFilePrefix = "kust-plugin-config-"
)
// ExecPlugin record the name and args of an executable
// It triggers the executable generator and transformer
type ExecPlugin struct {
// absolute path of the executable
path string
// Optional command line arguments to the executable
// pulled from specially named fields in cfg.
// This is for executables that don't want to parse YAML.
args []string
// Plugin configuration data.
cfg []byte
// PluginHelpers
h *resmap.PluginHelpers
}
func NewExecPlugin(p string) *ExecPlugin {
return &ExecPlugin{path: p}
}
func (p *ExecPlugin) ErrIfNotExecutable() error {
f, err := os.Stat(p.path)
if err != nil {
return err
}
if f.Mode()&0111 == 0000 {
return fmt.Errorf("unexecutable plugin at: %s", p.path)
}
return nil
}
func (p *ExecPlugin) Path() string {
return p.path
}
func (p *ExecPlugin) Args() []string {
return p.args
}
func (p *ExecPlugin) Cfg() []byte {
return p.cfg
}
func (p *ExecPlugin) Config(h *resmap.PluginHelpers, config []byte) error {
p.h = h
p.cfg = config
return p.processOptionalArgsFields()
}
type argsConfig struct {
ArgsOneLiner string `json:"argsOneLiner,omitempty" yaml:"argsOneLiner,omitempty"`
ArgsFromFile string `json:"argsFromFile,omitempty" yaml:"argsFromFile,omitempty"`
}
func (p *ExecPlugin) processOptionalArgsFields() error {
var c argsConfig
yaml.Unmarshal(p.cfg, &c)
if c.ArgsOneLiner != "" {
p.args = strings.Split(c.ArgsOneLiner, " ")
}
if c.ArgsFromFile != "" {
content, err := p.h.Loader().Load(c.ArgsFromFile)
if err != nil {
return err
}
for _, x := range strings.Split(string(content), "\n") {
x := strings.TrimLeft(x, " ")
if x != "" {
p.args = append(p.args, x)
}
}
}
return nil
}
func (p *ExecPlugin) 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 p.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)
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 p.updateResMapValues(output, rm)
}
// invokePlugin writes plugin config to a temp file, then
// passes the full temp file path as the first arg to a process
// running the plugin binary. Process output is returned.
func (p *ExecPlugin) invokePlugin(input []byte) ([]byte, error) {
f, err := ioutil.TempFile("", tmpConfigFilePrefix)
if err != nil {
return nil, errors.Wrap(
err, "creating tmp plugin config file")
}
_, err = f.Write(p.cfg)
if err != nil {
return nil, errors.Wrap(
err, "writing plugin config to "+f.Name())
}
err = f.Close()
if err != nil {
return nil, errors.Wrap(
err, "closing plugin config file "+f.Name())
}
cmd := exec.Command(
p.path, append([]string{f.Name()}, p.args...)...)
cmd.Env = p.getEnv()
cmd.Stdin = bytes.NewReader(input)
cmd.Stderr = os.Stderr
if _, err := os.Stat(p.h.Loader().Root()); err == nil {
cmd.Dir = p.h.Loader().Root()
}
result, err := cmd.Output()
if err != nil {
return nil, errors.Wrapf(
err, "failure in plugin configured via %s; %v",
f.Name(), err.Error())
}
return result, os.Remove(f.Name())
}
func (p *ExecPlugin) getEnv() []string {
env := os.Environ()
env = append(env,
"KUSTOMIZE_PLUGIN_CONFIG_STRING="+string(p.cfg),
"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},
&types.GeneratorOptions{DisableNameSuffixHash: !needsHash}))
}
return rm, nil
}

View File

@@ -0,0 +1,190 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package execplugin_test
import (
"fmt"
"strings"
"testing"
"sigs.k8s.io/kustomize/api/internal/loadertest"
. "sigs.k8s.io/kustomize/api/internal/plugins/execplugin"
"sigs.k8s.io/kustomize/api/internal/plugins/loader"
"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"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/api/types"
)
func TestExecPluginConfig(t *testing.T) {
path := "/app"
rf := resmap.NewFactory(
resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl()), nil)
ldr := loadertest.NewFakeLoader(path)
v := valtest_test.MakeFakeValidator()
pluginConfig := rf.RF().FromMap(
map[string]interface{}{
"apiVersion": "someteam.example.com/v1",
"kind": "SedTransformer",
"metadata": map[string]interface{}{
"name": "some-random-name",
},
"argsOneLiner": "one two",
"argsFromFile": "sed-input.txt",
})
ldr.AddFile("/app/sed-input.txt", []byte(`
s/$FOO/foo/g
s/$BAR/bar/g
\ \ \
`))
p := NewExecPlugin(
loader.AbsolutePluginPath(
konfig.DisabledPluginConfig(),
pluginConfig.OrgId()))
// Not checking to see if the plugin is executable,
// because this test does not run it.
// This tests only covers sending configuration
// to the plugin wrapper object and confirming
// that it's properly prepared for execution.
yaml, err := pluginConfig.AsYAML()
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
p.Config(resmap.NewPluginHelpers(ldr, v, rf), yaml)
expected := "someteam.example.com/v1/sedtransformer/SedTransformer"
if !strings.HasSuffix(p.Path(), expected) {
t.Fatalf("expected suffix '%s', got '%s'", expected, p.Path())
}
expected = `apiVersion: someteam.example.com/v1
argsFromFile: sed-input.txt
argsOneLiner: one two
kind: SedTransformer
metadata:
name: some-random-name
`
if expected != string(p.Cfg()) {
t.Fatalf("expected cfg '%s', got '%s'", expected, string(p.Cfg()))
}
if len(p.Args()) != 5 {
t.Fatalf("unexpected arg len %d, %v", len(p.Args()), p.Args())
}
if p.Args()[0] != "one" ||
p.Args()[1] != "two" ||
p.Args()[2] != "s/$FOO/foo/g" ||
p.Args()[3] != "s/$BAR/bar/g" ||
p.Args()[4] != "\\ \\ \\ " {
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}, &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,211 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package loader
import (
"fmt"
"os"
"path/filepath"
"plugin"
"reflect"
"strings"
"github.com/pkg/errors"
"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/konfig"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
)
type Loader struct {
pc *types.PluginConfig
rf *resmap.Factory
}
func NewLoader(
pc *types.PluginConfig, rf *resmap.Factory) *Loader {
return &Loader{pc: pc, rf: rf}
}
func (l *Loader) LoadGenerators(
ldr ifc.Loader, v ifc.Validator, rm resmap.ResMap) ([]resmap.Generator, error) {
var result []resmap.Generator
for _, res := range rm.Resources() {
g, err := l.LoadGenerator(ldr, v, res)
if err != nil {
return nil, err
}
result = append(result, g)
}
return result, nil
}
func (l *Loader) LoadGenerator(
ldr ifc.Loader, v ifc.Validator, res *resource.Resource) (resmap.Generator, error) {
c, err := l.loadAndConfigurePlugin(ldr, v, res)
if err != nil {
return nil, err
}
g, ok := c.(resmap.Generator)
if !ok {
return nil, fmt.Errorf("plugin %s not a generator", res.OrgId())
}
return g, nil
}
func (l *Loader) LoadTransformers(
ldr ifc.Loader, v ifc.Validator, rm resmap.ResMap) ([]resmap.Transformer, error) {
var result []resmap.Transformer
for _, res := range rm.Resources() {
t, err := l.LoadTransformer(ldr, v, res)
if err != nil {
return nil, err
}
result = append(result, t)
}
return result, nil
}
func (l *Loader) LoadTransformer(
ldr ifc.Loader, v ifc.Validator, res *resource.Resource) (resmap.Transformer, error) {
c, err := l.loadAndConfigurePlugin(ldr, v, res)
if err != nil {
return nil, err
}
t, ok := c.(resmap.Transformer)
if !ok {
return nil, fmt.Errorf("plugin %s not a transformer", res.OrgId())
}
return t, nil
}
func relativePluginPath(id resid.ResId) string {
return filepath.Join(
id.Group,
id.Version,
strings.ToLower(id.Kind))
}
func AbsolutePluginPath(pc *types.PluginConfig, id resid.ResId) string {
return filepath.Join(
pc.AbsPluginHome, relativePluginPath(id), id.Kind)
}
func (l *Loader) absolutePluginPath(id resid.ResId) string {
return AbsolutePluginPath(l.pc, id)
}
func isBuiltinPlugin(res *resource.Resource) bool {
// TODO: the special string should appear in Group, not Version.
return res.GetGvk().Group == "" &&
res.GetGvk().Version == konfig.BuiltinPluginApiVersion
}
func (l *Loader) loadAndConfigurePlugin(
ldr ifc.Loader, v ifc.Validator, res *resource.Resource) (c resmap.Configurable, err error) {
if isBuiltinPlugin(res) {
// Instead of looking for and loading a .so file, just
// instantiate the plugin from a generated factory
// function (see "pluginator"). Being able to do this
// is what makes a plugin "builtin".
c, err = l.makeBuiltinPlugin(res.GetGvk())
} else if l.pc.PluginRestrictions == types.PluginRestrictionsNone {
c, err = l.loadPlugin(res.OrgId())
} else {
err = types.NewErrOnlyBuiltinPluginsAllowed(res.OrgId().Kind)
}
if err != nil {
return nil, err
}
yaml, err := res.AsYAML()
if err != nil {
return nil, errors.Wrapf(err, "marshalling yaml from res %s", res.OrgId())
}
err = c.Config(resmap.NewPluginHelpers(ldr, v, l.rf), yaml)
if err != nil {
return nil, errors.Wrapf(
err, "plugin %s fails configuration", res.OrgId())
}
return c, nil
}
func (l *Loader) makeBuiltinPlugin(r resid.Gvk) (resmap.Configurable, error) {
bpt := builtinhelpers.GetBuiltinPluginType(r.Kind)
if f, ok := builtinhelpers.GeneratorFactories[bpt]; ok {
return f(), nil
}
if f, ok := builtinhelpers.TransformerFactories[bpt]; ok {
return f(), nil
}
return nil, errors.Errorf("unable to load builtin %s", r)
}
func (l *Loader) loadPlugin(resId resid.ResId) (resmap.Configurable, error) {
// First try to load the plugin as an executable.
p := execplugin.NewExecPlugin(l.absolutePluginPath(resId))
err := p.ErrIfNotExecutable()
if err == nil {
return p, nil
}
if !os.IsNotExist(err) {
// The file exists, but something else is wrong,
// likely it's not executable.
// Assume the user forgot to set the exec bit,
// and return an error, rather than adding ".so"
// to the name and attempting to load it as a Go
// plugin, which will likely fail and result
// in an obscure message.
return nil, err
}
// Failing the above, try loading it as a Go plugin.
c, err := l.loadGoPlugin(resId)
if err != nil {
return nil, err
}
return c, nil
}
// registry is a means to avoid trying to load the same .so file
// into memory more than once, which results in an error.
// Each test makes its own loader, and tries to load its own plugins,
// but the loaded .so files are in shared memory, so one will get
// "this plugin already loaded" errors if the registry is maintained
// as a Loader instance variable. So make it a package variable.
var registry = make(map[string]resmap.Configurable)
func (l *Loader) loadGoPlugin(id resid.ResId) (resmap.Configurable, error) {
regId := relativePluginPath(id)
if c, ok := registry[regId]; ok {
return copyPlugin(c), nil
}
absPath := l.absolutePluginPath(id)
p, err := plugin.Open(absPath + ".so")
if err != nil {
return nil, errors.Wrapf(err, "plugin %s fails to load", absPath)
}
symbol, err := p.Lookup(konfig.PluginSymbol)
if err != nil {
return nil, errors.Wrapf(
err, "plugin %s doesn't have symbol %s",
regId, konfig.PluginSymbol)
}
c, ok := symbol.(resmap.Configurable)
if !ok {
return nil, fmt.Errorf("plugin '%s' not configurable", regId)
}
registry[regId] = c
return copyPlugin(c), nil
}
func copyPlugin(c resmap.Configurable) resmap.Configurable {
indirect := reflect.Indirect(reflect.ValueOf(c))
newIndirect := reflect.New(indirect.Type())
newIndirect.Elem().Set(reflect.ValueOf(indirect.Interface()))
newNamed := newIndirect.Interface()
return newNamed.(resmap.Configurable)
}

View File

@@ -0,0 +1,80 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package loader_test
import (
"testing"
"sigs.k8s.io/kustomize/api/internal/loadertest"
. "sigs.k8s.io/kustomize/api/internal/plugins/loader"
"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"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
)
const (
secretGenerator = `
apiVersion: builtin
kind: SecretGenerator
metadata:
name: secretGenerator
name: mySecret
behavior: merge
envFiles:
- a.env
- b.env
valueFiles:
- longsecret.txt
literals:
- FRUIT=apple
- VEGETABLE=carrot
`
someServiceGenerator = `
apiVersion: someteam.example.com/v1
kind: SomeServiceGenerator
metadata:
name: myServiceGenerator
service: my-service
port: "12345"
`
)
func TestLoader(t *testing.T) {
tc := kusttest_test.NewPluginTestEnv(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "SecretGenerator")
tc.BuildGoPlugin(
"someteam.example.com", "v1", "SomeServiceGenerator")
rmF := resmap.NewFactory(resource.NewFactory(
kunstruct.NewKunstructuredFactoryImpl()), nil)
ldr := loadertest.NewFakeLoader("/foo")
c, err := konfig.EnabledPluginConfig()
if err != nil {
t.Fatal(err)
}
pLdr := NewLoader(c, rmF)
if pLdr == nil {
t.Fatal("expect non-nil loader")
}
m, err := rmF.NewResMapFromBytes([]byte(
someServiceGenerator + "---\n" + secretGenerator))
if err != nil {
t.Fatal(err)
}
_, err = pLdr.LoadGenerators(ldr, valtest_test.MakeFakeValidator(), m)
if err != nil {
t.Fatal(err)
}
}

View File

@@ -0,0 +1,60 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target_test
import (
"testing"
. "sigs.k8s.io/kustomize/api/internal/target"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func TestTargetMustHaveKustomizationFile(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app")
th.WriteF("/app/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: aService
`)
th.WriteF("/app/deeper/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: anotherService
`)
_, err := th.MakeKustTargetOrErr()
if err == nil {
t.Fatalf("expected an error")
}
if !IsMissingKustomizationFileError(err) {
t.Fatalf("unexpected error: %q", err)
}
}
func TestResourceDirectoryMustHaveKustomizationFile(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app")
th.WriteK("/app", `
resources:
- base
`)
th.WriteF("/app/base/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: myService
spec:
selector:
backend: bungie
ports:
- port: 7002
`)
_, err := th.MakeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("expected an error")
}
if !IsMissingKustomizationFileError(err) {
t.Fatalf("unexpected error: %q", err)
}
}

View File

@@ -0,0 +1,313 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target_test
import (
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func writeMediumBase(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/base", `
namePrefix: baseprefix-
commonLabels:
foo: bar
commonAnnotations:
baseAnno: This is a base annotation
resources:
- deployment/deployment.yaml
- service/service.yaml
`)
th.WriteF("/app/base/service/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: mungebot-service
labels:
app: mungebot
spec:
ports:
- port: 7002
selector:
app: mungebot
`)
th.WriteF("/app/base/deployment/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: mungebot
labels:
app: mungebot
spec:
replicas: 1
template:
metadata:
labels:
app: mungebot
spec:
containers:
- name: nginx
image: nginx
env:
- name: foo
value: bar
ports:
- containerPort: 80
`)
}
func TestMediumBase(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/base")
writeMediumBase(th)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
baseAnno: This is a base annotation
labels:
app: mungebot
foo: bar
name: baseprefix-mungebot
spec:
replicas: 1
selector:
matchLabels:
foo: bar
template:
metadata:
annotations:
baseAnno: This is a base annotation
labels:
app: mungebot
foo: bar
spec:
containers:
- env:
- name: foo
value: bar
image: nginx
name: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
annotations:
baseAnno: This is a base annotation
labels:
app: mungebot
foo: bar
name: baseprefix-mungebot-service
spec:
ports:
- port: 7002
selector:
app: mungebot
foo: bar
`)
}
func TestMediumOverlay(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/overlay")
writeMediumBase(th)
th.WriteK("/app/overlay", `
namePrefix: test-infra-
commonLabels:
app: mungebot
org: kubernetes
repo: test-infra
commonAnnotations:
note: This is a test annotation
resources:
- ../base
patchesStrategicMerge:
- deployment/deployment.yaml
configMapGenerator:
- name: app-env
envs:
- configmap/db.env
- configmap/units.ini
- configmap/food.ini
- name: app-config
files:
- nonsense=configmap/dummy.txt
images:
- name: nginx
newTag: 1.8.0`)
th.WriteF("/app/overlay/configmap/db.env", `
DB_USERNAME=admin
DB_PASSWORD=somepw
`)
th.WriteF("/app/overlay/configmap/units.ini", `
LENGTH=kilometer
ENERGY=electronvolt
`)
th.WriteF("/app/overlay/configmap/food.ini", `
FRUIT=banana
LEGUME=chickpea
`)
th.WriteF("/app/overlay/configmap/dummy.txt",
`Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua.
`)
th.WriteF("/app/overlay/deployment/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: mungebot
spec:
replicas: 2
template:
spec:
containers:
- name: nginx
image: nginx:1.7.9
env:
- name: FOO
valueFrom:
configMapKeyRef:
name: app-env
key: somekey
- name: busybox
image: busybox
envFrom:
- configMapRef:
name: someConfigMap
- configMapRef:
name: app-env
volumeMounts:
- mountPath: /tmp/env
name: app-env
volumes:
- configMap:
name: app-env
name: app-env
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
baseAnno: This is a base annotation
note: This is a test annotation
labels:
app: mungebot
foo: bar
org: kubernetes
repo: test-infra
name: test-infra-baseprefix-mungebot
spec:
replicas: 2
selector:
matchLabels:
app: mungebot
foo: bar
org: kubernetes
repo: test-infra
template:
metadata:
annotations:
baseAnno: This is a base annotation
note: This is a test annotation
labels:
app: mungebot
foo: bar
org: kubernetes
repo: test-infra
spec:
containers:
- env:
- name: FOO
valueFrom:
configMapKeyRef:
key: somekey
name: test-infra-app-env-ffmd9b969m
- name: foo
value: bar
image: nginx:1.8.0
name: nginx
ports:
- containerPort: 80
- envFrom:
- configMapRef:
name: someConfigMap
- configMapRef:
name: test-infra-app-env-ffmd9b969m
image: busybox
name: busybox
volumeMounts:
- mountPath: /tmp/env
name: app-env
volumes:
- configMap:
name: test-infra-app-env-ffmd9b969m
name: app-env
---
apiVersion: v1
kind: Service
metadata:
annotations:
baseAnno: This is a base annotation
note: This is a test annotation
labels:
app: mungebot
foo: bar
org: kubernetes
repo: test-infra
name: test-infra-baseprefix-mungebot-service
spec:
ports:
- port: 7002
selector:
app: mungebot
foo: bar
org: kubernetes
repo: test-infra
---
apiVersion: v1
data:
DB_PASSWORD: somepw
DB_USERNAME: admin
ENERGY: electronvolt
FRUIT: banana
LEGUME: chickpea
LENGTH: kilometer
kind: ConfigMap
metadata:
annotations:
note: This is a test annotation
labels:
app: mungebot
org: kubernetes
repo: test-infra
name: test-infra-app-env-ffmd9b969m
---
apiVersion: v1
data:
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:
note: This is a test annotation
labels:
app: mungebot
org: kubernetes
repo: test-infra
name: test-infra-app-config-f462h769f9
`)
}

View File

@@ -0,0 +1,456 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target_test
import (
"strings"
"testing"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/loader"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func TestOrderPreserved(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/prod")
th.WriteK("/app/base", `
namePrefix: b-
resources:
- namespace.yaml
- role.yaml
- service.yaml
- deployment.yaml
`)
th.WriteF("/app/base/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: myService
`)
th.WriteF("/app/base/namespace.yaml", `
apiVersion: v1
kind: Namespace
metadata:
name: myNs
`)
th.WriteF("/app/base/role.yaml", `
apiVersion: v1
kind: Role
metadata:
name: myRole
`)
th.WriteF("/app/base/deployment.yaml", `
apiVersion: v1
kind: Deployment
metadata:
name: myDep
`)
th.WriteK("/app/prod", `
namePrefix: p-
resources:
- ../base
- service.yaml
- namespace.yaml
`)
th.WriteF("/app/prod/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: myService2
`)
th.WriteF("/app/prod/namespace.yaml", `
apiVersion: v1
kind: Namespace
metadata:
name: myNs2
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: Namespace
metadata:
name: p-b-myNs
---
apiVersion: v1
kind: Role
metadata:
name: p-b-myRole
---
apiVersion: v1
kind: Service
metadata:
name: p-b-myService
---
apiVersion: v1
kind: Deployment
metadata:
name: p-b-myDep
---
apiVersion: v1
kind: Service
metadata:
name: p-myService2
---
apiVersion: v1
kind: Namespace
metadata:
name: p-myNs2
`)
}
func TestBaseInResourceList(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/prod")
th.WriteK("/app/prod", `
namePrefix: b-
resources:
- ../base
`)
th.WriteK("/app/base", `
namePrefix: a-
resources:
- service.yaml
`)
th.WriteF("/app/base/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: myService
spec:
selector:
backend: bungie
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: Service
metadata:
name: b-a-myService
spec:
selector:
backend: bungie
`)
}
func writeSmallBase(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/base", `
namePrefix: a-
commonLabels:
app: myApp
resources:
- deployment.yaml
- service.yaml
`)
th.WriteF("/app/base/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: myService
spec:
selector:
backend: bungie
ports:
- port: 7002
`)
th.WriteF("/app/base/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeployment
spec:
template:
metadata:
labels:
backend: awesome
spec:
containers:
- name: whatever
image: whatever
`)
}
func TestSmallBase(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/base")
writeSmallBase(th)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myApp
name: a-myDeployment
spec:
selector:
matchLabels:
app: myApp
template:
metadata:
labels:
app: myApp
backend: awesome
spec:
containers:
- image: whatever
name: whatever
---
apiVersion: v1
kind: Service
metadata:
labels:
app: myApp
name: a-myService
spec:
ports:
- port: 7002
selector:
app: myApp
backend: bungie
`)
}
func TestSmallOverlay(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/overlay")
writeSmallBase(th)
th.WriteK("/app/overlay", `
namePrefix: b-
commonLabels:
env: prod
resources:
- ../base
patchesStrategicMerge:
- deployment/deployment.yaml
images:
- name: whatever
newTag: 1.8.0
`)
th.WriteF("/app/overlay/configmap/app.env", `
DB_USERNAME=admin
DB_PASSWORD=somepw
`)
th.WriteF("/app/overlay/configmap/app-init.ini", `
FOO=bar
BAR=baz
`)
th.WriteF("/app/overlay/deployment/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeployment
spec:
replicas: 1000
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myApp
env: prod
name: b-a-myDeployment
spec:
replicas: 1000
selector:
matchLabels:
app: myApp
env: prod
template:
metadata:
labels:
app: myApp
backend: awesome
env: prod
spec:
containers:
- image: whatever:1.8.0
name: whatever
---
apiVersion: v1
kind: Service
metadata:
labels:
app: myApp
env: prod
name: b-a-myService
spec:
ports:
- port: 7002
selector:
app: myApp
backend: bungie
env: prod
`)
}
func TestSharedPatchDisAllowed(t *testing.T) {
th := kusttest_test.NewKustTestHarnessFull(
t, "/app/overlay",
loader.RestrictionRootOnly, konfig.DisabledPluginConfig())
writeSmallBase(th)
th.WriteK("/app/overlay", `
commonLabels:
env: prod
resources:
- ../base
patchesStrategicMerge:
- ../shared/deployment-patch.yaml
`)
th.WriteF("/app/shared/deployment-patch.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeployment
spec:
replicas: 1000
`)
_, err := th.MakeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("expected error")
}
if !strings.Contains(
err.Error(),
"security; file '/app/shared/deployment-patch.yaml' is not in or below '/app/overlay'") {
t.Fatalf("unexpected error: %s", err)
}
}
func TestSharedPatchAllowed(t *testing.T) {
th := kusttest_test.NewKustTestHarnessFull(
t, "/app/overlay",
loader.RestrictionNone, konfig.DisabledPluginConfig())
writeSmallBase(th)
th.WriteK("/app/overlay", `
commonLabels:
env: prod
resources:
- ../base
patchesStrategicMerge:
- ../shared/deployment-patch.yaml
`)
th.WriteF("/app/shared/deployment-patch.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeployment
spec:
replicas: 1000
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myApp
env: prod
name: a-myDeployment
spec:
replicas: 1000
selector:
matchLabels:
app: myApp
env: prod
template:
metadata:
labels:
app: myApp
backend: awesome
env: prod
spec:
containers:
- image: whatever
name: whatever
---
apiVersion: v1
kind: Service
metadata:
labels:
app: myApp
env: prod
name: a-myService
spec:
ports:
- port: 7002
selector:
app: myApp
backend: bungie
env: prod
`)
}
func TestSmallOverlayJSONPatch(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/overlay")
writeSmallBase(th)
th.WriteK("/app/overlay", `
resources:
- ../base
patchesJson6902:
- target:
version: v1
kind: Service
name: a-myService
path: service-patch.yaml
`)
th.WriteF("/app/overlay/service-patch.yaml", `
- op: add
path: /spec/selector/backend
value: beagle
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myApp
name: a-myDeployment
spec:
selector:
matchLabels:
app: myApp
template:
metadata:
labels:
app: myApp
backend: awesome
spec:
containers:
- image: whatever
name: whatever
---
apiVersion: v1
kind: Service
metadata:
labels:
app: myApp
name: a-myService
spec:
ports:
- port: 7002
selector:
app: myApp
backend: beagle
`)
}

View File

@@ -0,0 +1,199 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target_test
import (
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
// Here is a structure of a kustomization of two components, component1
// and component2, that both use a shared postgres definition, which
// they would individually adjust. This test case checks that the name
// prefix does not cause a name reference conflict.
//
// root
// / \
// component1/overlay component2/overlay
// | |
// component1/base component2/base
// \ /
// base
//
// This is the directory layout:
//
// ├── component1
// │ ├── base
// │ │ └── kustomization.yaml
// │ └── overlay
// │ └── kustomization.yaml
// ├── component2
// │ ├── base
// │ │ └── kustomization.yaml
// │ └── overlay
// │ └── kustomization.yaml
// ├── shared
// │ ├── kustomization.yaml
// │ └── resources.yaml
// ├── kustomization.yaml
func TestBaseReuseNameConflict(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app")
th.WriteK("/app/component1/base", `
resources:
- ../../shared
namePrefix: component1-
`)
th.WriteK("/app/component1/overlay", `
resources:
- ../base
namePrefix: overlay-
`)
th.WriteK("/app/component2/base", `
resources:
- ../../shared
namePrefix: component2-
`)
th.WriteK("/app/component2/overlay", `
resources:
- ../base
namePrefix: overlay-
`)
th.WriteK("/app/shared", `
resources:
- resources.yaml
`)
th.WriteF("/app/shared/resources.yaml", `
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: postgres
spec:
resources:
requests:
storage: 1Gi
accessModes:
- ReadWriteOnce
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
spec:
selector:
matchLabels: {}
strategy:
type: Recreate
template:
spec:
containers:
- name: postgres
image: postgres
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /var/lib/postgresql
name: data
ports:
- name: postgres
containerPort: 5432
volumes:
- name: data
persistentVolumeClaim:
claimName: postgres
`)
th.WriteK("/app", `
resources:
- component1/overlay
- component2/overlay
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: overlay-component1-postgres
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: overlay-component1-postgres
spec:
selector:
matchLabels: {}
strategy:
type: Recreate
template:
spec:
containers:
- image: postgres
imagePullPolicy: IfNotPresent
name: postgres
ports:
- containerPort: 5432
name: postgres
volumeMounts:
- mountPath: /var/lib/postgresql
name: data
volumes:
- name: data
persistentVolumeClaim:
claimName: overlay-component1-postgres
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: overlay-component2-postgres
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: overlay-component2-postgres
spec:
selector:
matchLabels: {}
strategy:
type: Recreate
template:
spec:
containers:
- image: postgres
imagePullPolicy: IfNotPresent
name: postgres
ports:
- containerPort: 5432
name: postgres
volumeMounts:
- mountPath: /var/lib/postgresql
name: data
volumes:
- name: data
persistentVolumeClaim:
claimName: overlay-component2-postgres
`)
}

View File

@@ -0,0 +1,111 @@
// +build notravis
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Disabled on travis, because don't want to install helm on travis.
package target_test
import (
"regexp"
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
// This is an example of using a helm chart as a base,
// inflating it and then customizing it with a nameprefix
// applied to all its resources.
//
// The helm chart used is downloaded from
// https://github.com/helm/charts/tree/master/stable/minecraft
// with each test run, so it's a bit brittle as that
// chart could change obviously and break the test.
//
// This test requires having the helm binary on the PATH.
//
// TODO: Download and inflate the chart, and check that
// in for the test.
func TestChartInflatorPlugin(t *testing.T) {
tc := kusttest_test.NewPluginTestEnv(t).Set()
defer tc.Reset()
tc.BuildExecPlugin(
"someteam.example.com", "v1", "ChartInflator")
th := kusttest_test.NewKustTestHarnessAllowPlugins(t, "/app")
th.WriteK("/app", `
generators:
- chartInflator.yaml
namePrefix: LOOOOOOOONG-
`)
th.WriteF("/app/chartInflator.yaml", `
apiVersion: someteam.example.com/v1
kind: ChartInflator
metadata:
name: notImportantHere
chartName: minecraft
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
chartName := regexp.MustCompile("chart: minecraft-[0-9.]+")
th.AssertActualEqualsExpectedWithTweak(m,
func(x []byte) []byte {
return chartName.ReplaceAll(x, []byte("chart: minecraft-SOMEVERSION"))
}, `
apiVersion: v1
data:
rcon-password: Q0hBTkdFTUUh
kind: Secret
metadata:
labels:
app: release-name-minecraft
chart: minecraft-SOMEVERSION
heritage: Tiller
release: release-name
name: LOOOOOOOONG-release-name-minecraft
type: Opaque
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
volume.alpha.kubernetes.io/storage-class: default
labels:
app: release-name-minecraft
chart: minecraft-SOMEVERSION
heritage: Tiller
release: release-name
name: LOOOOOOOONG-release-name-minecraft-datadir
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
labels:
app: release-name-minecraft
chart: minecraft-SOMEVERSION
heritage: Tiller
release: release-name
name: LOOOOOOOONG-release-name-minecraft
spec:
ports:
- name: minecraft
port: 25565
protocol: TCP
targetPort: minecraft
selector:
app: release-name-minecraft
type: LoadBalancer
`)
}

View File

@@ -0,0 +1,557 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target_test
import (
"strings"
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
const httpsService = `
apiVersion: v1
kind: Service
metadata:
name: my-https-svc
spec:
ports:
- port: 443
protocol: TCP
name: https
selector:
app: my-app
`
func writeStatefulSetBase(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/base", `
resources:
- statefulset.yaml
`)
th.WriteF("/app/base/statefulset.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
serviceName: my-svc
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-image
volumeClaimTemplates:
- spec:
storageClassName: default
`)
}
func writeHTTPSOverlay(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/https", `
resources:
- ../base
- https-svc.yaml
patchesStrategicMerge:
- sts-patch.yaml
`)
th.WriteF("/app/https/https-svc.yaml", httpsService)
th.WriteF("/app/https/sts-patch.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
serviceName: my-https-svc
`)
}
func writeHTTPSTransformerRaw(th *kusttest_test.KustTestHarness) {
th.WriteF("/app/https/service/https-svc.yaml", httpsService)
th.WriteF("/app/https/transformer/transformer.yaml", `
apiVersion: builtin
kind: PatchTransformer
metadata:
name: svcNameTran
target:
group: apps
version: v1
kind: StatefulSet
name: my-sts
patch: |-
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
serviceName: my-https-svc
`)
}
func writeHTTPSTransformerBase(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/https/service", `
resources:
- https-svc.yaml
`)
th.WriteK("/app/https/transformer", `
resources:
- transformer.yaml
`)
writeHTTPSTransformerRaw(th)
}
func writeConfigFromEnvOverlay(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/config", `
resources:
- ../base
configMapGenerator:
- name: my-config
literals:
- MY_ENV=foo
generatorOptions:
disableNameSuffixHash: true
patchesStrategicMerge:
- sts-patch.yaml
`)
th.WriteF("/app/config/sts-patch.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
template:
spec:
containers:
- name: app
envFrom:
- configMapRef:
name: my-config
`)
}
func writeConfigFromEnvTransformerRaw(th *kusttest_test.KustTestHarness) {
th.WriteF("/app/config/map/generator.yaml", `
apiVersion: builtin
kind: ConfigMapGenerator
metadata:
name: my-config
disableNameSuffixHash: true
literals:
- MY_ENV=foo
`)
th.WriteF("/app/config/transformer/transformer.yaml", `
apiVersion: builtin
kind: PatchTransformer
metadata:
name: envFromConfigTrans
target:
group: apps
version: v1
kind: StatefulSet
name: my-sts
patch: |-
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
template:
spec:
containers:
- name: app
envFrom:
- configMapRef:
name: my-config
`)
}
func writeConfigFromEnvTransformerBase(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/config/map", `
resources:
- generator.yaml
`)
th.WriteK("/app/config/transformer", `
resources:
- transformer.yaml
`)
writeConfigFromEnvTransformerRaw(th)
}
func writeTolerationsOverlay(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/tolerations", `
resources:
- ../base
patchesStrategicMerge:
- sts-patch.yaml
`)
th.WriteF("/app/tolerations/sts-patch.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
template:
spec:
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
tolerationSeconds: 30
`)
}
func writeTolerationsTransformerRaw(th *kusttest_test.KustTestHarness) {
th.WriteF("/app/tolerations/transformer.yaml", `
apiVersion: builtin
kind: PatchTransformer
metadata:
name: tolTrans
target:
group: apps
version: v1
kind: StatefulSet
name: my-sts
patch: |-
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
template:
spec:
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
tolerationSeconds: 30
`)
}
func writeTolerationsTransformerBase(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/tolerations", `
resources:
- transformer.yaml
`)
writeTolerationsTransformerRaw(th)
}
func writeStorageOverlay(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/storage", `
resources:
- ../base
patchesJson6902:
- target:
group: apps
version: v1
kind: StatefulSet
name: my-sts
path: sts-patch.json
`)
th.WriteF("/app/storage/sts-patch.json", `
[{"op": "replace", "path": "/spec/volumeClaimTemplates/0/spec/storageClassName", "value": "my-sc"}]
`)
}
func writeStorageTransformerRaw(th *kusttest_test.KustTestHarness) {
th.WriteF("/app/storage/transformer.yaml", `
apiVersion: builtin
kind: PatchTransformer
metadata:
name: storageTrans
target:
group: apps
version: v1
kind: StatefulSet
name: my-sts
patch: |-
[{"op": "replace", "path": "/spec/volumeClaimTemplates/0/spec/storageClassName", "value": "my-sc"}]
`)
}
func writeStorageTransformerBase(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/storage", `
resources:
- transformer.yaml
`)
writeStorageTransformerRaw(th)
}
func writePatchingOverlays(th *kusttest_test.KustTestHarness) {
writeStorageOverlay(th)
writeConfigFromEnvOverlay(th)
writeTolerationsOverlay(th)
writeHTTPSOverlay(th)
}
func writePatchingTransformersRaw(th *kusttest_test.KustTestHarness) {
writeStorageTransformerRaw(th)
writeConfigFromEnvTransformerRaw(th)
writeTolerationsTransformerRaw(th)
writeHTTPSTransformerRaw(th)
}
// Similar to writePatchingTransformersRaw, except here the
// transformers and related artifacts are addressable as _bases_.
// They are listed in a kustomization file, and consumers of
// the plugin refer to the kustomization instead of to the local
// file in the "transformers:" field.
//
// Using bases makes the set of files relocatable with
// respect to the overlays, and avoids the need to relax load
// restrictions on file paths reaching outside the `dev` and
// `prod` kustomization roots. I.e. with bases tests can use
// NewKustTestHarness instead of NewKustTestHarnessNoLoadRestrictor.
//
// Using transformer plugins from _bases_ means the plugin config
// must be self-contained, i.e. the config may not have fields that
// refer to local files, since those files won't be present when
// the plugin is instantiated and used.
func writePatchingTransformerBases(th *kusttest_test.KustTestHarness) {
writeStorageTransformerBase(th)
writeConfigFromEnvTransformerBase(th)
writeTolerationsTransformerBase(th)
writeHTTPSTransformerBase(th)
}
// Here's a complex kustomization scenario that combines multiple overlays
// on a common base:
//
// dev prod
// | |
// | |
// + ------- + + ------------ + ------------- +
// | | | | |
// | | | | |
// v | v v v
// storage + -----> config tolerations https
// | | | |
// | | | |
// | + --- + + --- + |
// | | | |
// | v v |
// + -----------------------> base <------------------ +
//
// The base resource is a statefulset. Each intermediate overlay manages or
// generates new resources and patches different aspects of the same base
// resource, without using any of the `namePrefix`, `nameSuffix` or `namespace`
// kustomization keywords.
//
// Intermediate overlays:
// - storage: Changes the storage class of the stateful set with a JSON patch.
// - config: Generates a config map and adds a field as an environment
// variable.
// - tolerations: Adds a new tolerations field in the spec.
// - https: Adds a new service resource and changes the service name in the
// stateful set.
//
// Top overlays:
// - dev: Combines the storage and config intermediate overlays.
// - prod: Combines the config, tolerations and https intermediate overlays.
func TestComplexComposition_Dev_Failure(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/dev")
writeStatefulSetBase(th)
writePatchingOverlays(th)
th.WriteK("/app/dev", `
resources:
- ../storage
- ../config
`)
_, err := th.MakeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("Expected resource accumulation error")
}
if !strings.Contains(
err.Error(), "already registered id: apps_v1_StatefulSet|~X|my-sts") {
t.Fatalf("Unexpected err: %v", err)
}
}
const devDesiredResult = `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
selector:
matchLabels:
app: my-app
serviceName: my-svc
template:
metadata:
labels:
app: my-app
spec:
containers:
- envFrom:
- configMapRef:
name: my-config
image: my-image
name: app
volumeClaimTemplates:
- spec:
storageClassName: my-sc
---
apiVersion: v1
data:
MY_ENV: foo
kind: ConfigMap
metadata:
name: my-config
`
func TestComplexComposition_Dev_SuccessWithRawTransformers(t *testing.T) {
th := kusttest_test.NewKustTestHarnessNoLoadRestrictor(t, "/app/dev")
writeStatefulSetBase(th)
writePatchingTransformersRaw(th)
th.WriteK("/app/dev", `
resources:
- ../base
generators:
- ../config/map/generator.yaml
transformers:
- ../config/transformer/transformer.yaml
- ../storage/transformer.yaml
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Unexpected err: %v", err)
}
th.AssertActualEqualsExpected(m, devDesiredResult)
}
func TestComplexComposition_Dev_SuccessWithBaseTransformers(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/dev")
writeStatefulSetBase(th)
writePatchingTransformerBases(th)
th.WriteK("/app/dev", `
resources:
- ../base
generators:
- ../config/map
transformers:
- ../config/transformer
- ../storage
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Unexpected err: %v", err)
}
th.AssertActualEqualsExpected(m, devDesiredResult)
}
func TestComplexComposition_Prod_Failure(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/prod")
writeStatefulSetBase(th)
writePatchingOverlays(th)
th.WriteK("/app/prod", `
resources:
- ../config
- ../tolerations
- ../https
`)
_, err := th.MakeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("Expected resource accumulation error")
}
if !strings.Contains(
err.Error(), "already registered id: apps_v1_StatefulSet|~X|my-sts") {
t.Fatalf("Unexpected err: %v", err)
}
}
const prodDesiredResult = `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
selector:
matchLabels:
app: my-app
serviceName: my-https-svc
template:
metadata:
labels:
app: my-app
spec:
containers:
- envFrom:
- configMapRef:
name: my-config
image: my-image
name: app
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
tolerationSeconds: 30
volumeClaimTemplates:
- spec:
storageClassName: default
---
apiVersion: v1
kind: Service
metadata:
name: my-https-svc
spec:
ports:
- name: https
port: 443
protocol: TCP
selector:
app: my-app
---
apiVersion: v1
data:
MY_ENV: foo
kind: ConfigMap
metadata:
name: my-config
`
func TestComplexComposition_Prod_SuccessWithRawTransformers(t *testing.T) {
th := kusttest_test.NewKustTestHarnessNoLoadRestrictor(t, "/app/prod")
writeStatefulSetBase(th)
writePatchingTransformersRaw(th)
th.WriteK("/app/prod", `
resources:
- ../base
- ../https/service/https-svc.yaml
generators:
- ../config/map/generator.yaml
transformers:
- ../config/transformer/transformer.yaml
- ../https/transformer/transformer.yaml
- ../tolerations/transformer.yaml
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Unexpected err: %v", err)
}
th.AssertActualEqualsExpected(m, prodDesiredResult)
}
func TestComplexComposition_Prod_SuccessWithBaseTransformers(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/prod")
writeStatefulSetBase(th)
writePatchingTransformerBases(th)
th.WriteK("/app/prod", `
resources:
- ../base
- ../https/service
generators:
- ../config/map
transformers:
- ../config/transformer
- ../https/transformer
- ../tolerations
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Unexpected err: %v", err)
}
th.AssertActualEqualsExpected(m, prodDesiredResult)
}

View File

@@ -0,0 +1,313 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package target_test
import (
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
// Generate a Secret and a ConfigMap from the same data
// to compare the result.
func TestGeneratorBasics(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app")
th.WriteK("/app", `
namePrefix: blah-
configMapGenerator:
- name: bob
literals:
- fruit=apple
- vegetable=broccoli
envs:
- foo.env
files:
- passphrase=phrase.dat
- forces.txt
- name: json
literals:
- 'v2=[{"path": "var/druid/segment-cache"}]'
- >-
druid_segmentCache_locations=[{"path":
"var/druid/segment-cache",
"maxSize": 32000000000,
"freeSpacePercent": 1.0}]
secretGenerator:
- name: bob
literals:
- fruit=apple
- vegetable=broccoli
envs:
- foo.env
files:
- passphrase=phrase.dat
- forces.txt
`)
th.WriteF("/app/foo.env", `
MOUNTAIN=everest
OCEAN=pacific
`)
th.WriteF("/app/phrase.dat", `
Life is short.
But the years are long.
Not while the evil days come not.
`)
th.WriteF("/app/forces.txt", `
gravitational
electromagnetic
strong nuclear
weak nuclear
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
data:
MOUNTAIN: everest
OCEAN: pacific
forces.txt: |2
gravitational
electromagnetic
strong nuclear
weak nuclear
fruit: apple
passphrase: |2
Life is short.
But the years are long.
Not while the evil days come not.
vegetable: broccoli
kind: ConfigMap
metadata:
name: blah-bob-k772g5db55
---
apiVersion: v1
data:
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
---
apiVersion: v1
data:
MOUNTAIN: ZXZlcmVzdA==
OCEAN: cGFjaWZpYw==
forces.txt: CmdyYXZpdGF0aW9uYWwKZWxlY3Ryb21hZ25ldGljCnN0cm9uZyBudWNsZWFyCndlYWsgbnVjbGVhcgo=
fruit: YXBwbGU=
passphrase: CkxpZmUgaXMgc2hvcnQuCkJ1dCB0aGUgeWVhcnMgYXJlIGxvbmcuCk5vdCB3aGlsZSB0aGUgZXZpbCBkYXlzIGNvbWUgbm90Lgo=
vegetable: YnJvY2NvbGk=
kind: Secret
metadata:
name: blah-bob-gmc2824f4b
type: Opaque
`)
}
// TODO: These should be errors instead.
func TestGeneratorRepeatsInKustomization(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app")
th.WriteK("/app", `
namePrefix: blah-
configMapGenerator:
- name: bob
behavior: create
literals:
- bean=pinto
- star=wolf-rayet
literals:
- fruit=apple
- vegetable=broccoli
files:
- forces.txt
files:
- nobles=nobility.txt
`)
th.WriteF("/app/forces.txt", `
gravitational
electromagnetic
strong nuclear
weak nuclear
`)
th.WriteF("/app/nobility.txt", `
helium
neon
argon
krypton
xenon
radon
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
data:
fruit: apple
nobles: |2
helium
neon
argon
krypton
xenon
radon
vegetable: broccoli
kind: ConfigMap
metadata:
name: blah-bob-gfkcbk5ckf
`)
}
func TestGeneratorOverlays(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/overlay")
th.WriteK("/app/base1", `
namePrefix: p1-
configMapGenerator:
- name: com1
behavior: create
literals:
- from=base
`)
th.WriteK("/app/base2", `
namePrefix: p2-
configMapGenerator:
- name: com2
behavior: create
literals:
- from=base
`)
th.WriteK("/app/overlay/o1", `
resources:
- ../../base1
configMapGenerator:
- name: com1
behavior: merge
literals:
- from=overlay
`)
th.WriteK("/app/overlay/o2", `
resources:
- ../../base2
configMapGenerator:
- name: com2
behavior: merge
literals:
- from=overlay
`)
th.WriteK("/app/overlay", `
resources:
- o1
- o2
configMapGenerator:
- name: com1
behavior: merge
literals:
- foo=bar
- baz=qux
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
data:
baz: qux
foo: bar
from: overlay
kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: p1-com1-dhbbm922gd
---
apiVersion: v1
data:
from: overlay
kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: p2-com2-c4b8md75k9
`)
}
func TestConfigMapGeneratorMergeNamePrefix(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app")
th.WriteK("/app/base", `
configMapGenerator:
- name: cm
behavior: create
literals:
- foo=bar
`)
th.WriteK("/app/o1", `
resources:
- ../base
namePrefix: o1-
`)
th.WriteK("/app/o2", `
resources:
- ../base
nameSuffix: -o2
`)
th.WriteK("/app", `
resources:
- o1
- o2
configMapGenerator:
- name: o1-cm
behavior: merge
literals:
- big=bang
- name: cm-o2
behavior: merge
literals:
- big=crunch
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
data:
big: bang
foo: bar
kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: o1-cm-28g596k77k
---
apiVersion: v1
data:
big: crunch
foo: bar
kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: cm-o2-gfcc59fg5m
`)
}

View File

@@ -0,0 +1,384 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package target_test
import (
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func writeBaseWithCrd(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/base", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
crds:
- mycrd.json
resources:
- secret.yaml
- mykind.yaml
- bee.yaml
namePrefix: x-
`)
th.WriteF("/app/base/bee.yaml", `
apiVersion: v1beta1
kind: Bee
metadata:
name: bee
spec:
action: fly
`)
th.WriteF("/app/base/mykind.yaml", `
apiVersion: jingfang.example.com/v1beta1
kind: MyKind
metadata:
name: mykind
spec:
secretRef:
name: crdsecret
beeRef:
name: bee
`)
th.WriteF("/app/base/secret.yaml", `
apiVersion: v1
kind: Secret
metadata:
name: crdsecret
data:
PATH: yellowBrickRoad
`)
th.WriteF("/app/base/mycrd.json", `
{
"github.com/example/pkg/apis/jingfang/v1beta1.Bee": {
"Schema": {
"description": "Bee",
"properties": {
"apiVersion": {
"description": "APIVersion defines the versioned schema of this representation of an object.",
"type": "string"
},
"kind": {
"description": "Kind is a string value representing the REST resource this object represents.",
"type": "string"
},
"metadata": {
"$ref": "sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1.ObjectMeta"
},
"spec": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.BeeSpec"
},
"status": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.BeeStatus"
}
}
},
"Dependencies": [
"github.com/example/pkg/apis/jingfang/v1beta1.BeeSpec",
"github.com/example/pkg/apis/jingfang/v1beta1.BeeStatus",
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1.ObjectMeta"
]
},
"github.com/example/pkg/apis/jingfang/v1beta1.BeeList": {
"Schema": {
"required": [
"items"
],
"properties": {
"apiVersion": {
"description": "APIVersion defines the versioned schema of this representation of an object.",
"type": "string"
},
"items": {
"type": "array",
"items": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.Bee"
}
},
"kind": {
"description": "Kind is a string value representing the REST resource this object represents.",
"type": "string"
},
"metadata": {
"$ref": "sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1.ListMeta"
}
}
},
"Dependencies": [
"github.com/example/pkg/apis/jingfang/v1beta1.Bee",
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1.ListMeta"
]
},
"github.com/example/pkg/apis/jingfang/v1beta1.BeeObjectReference": {
"Schema": {
"properties": {
"name": {
"type": "string"
}
}
},
"Dependencies": []
},
"github.com/example/pkg/apis/jingfang/v1beta1.BeeSpec": {
"Schema": {
"description": "BeeSpec defines the desired state of Bee"
},
"Dependencies": []
},
"github.com/example/pkg/apis/jingfang/v1beta1.BeeStatus": {
"Schema": {
"description": "BeeStatus defines the observed state of Bee"
},
"Dependencies": []
},
"github.com/example/pkg/apis/jingfang/v1beta1.MyKind": {
"Schema": {
"description": "MyKind",
"properties": {
"apiVersion": {
"description": "APIVersion defines the versioned schema of this representation of an object.",
"type": "string"
},
"kind": {
"description": "Kind is a string value representing the REST resource this object represents.",
"type": "string"
},
"metadata": {
"$ref": "sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1.ObjectMeta"
},
"spec": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.MyKindSpec"
},
"status": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.MyKindStatus"
}
}
},
"Dependencies": [
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindSpec",
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindStatus",
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1.ObjectMeta"
]
},
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindList": {
"Schema": {
"required": [
"items"
],
"properties": {
"apiVersion": {
"description": "APIVersion defines the versioned schema of this representation of an object.",
"type": "string"
},
"items": {
"type": "array",
"items": {
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.MyKind"
}
},
"kind": {
"description": "Kind is a string value representing the REST resource this object represents.",
"type": "string"
},
"metadata": {
"$ref": "sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1.ListMeta"
}
}
},
"Dependencies": [
"github.com/example/pkg/apis/jingfang/v1beta1.MyKind",
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1.ListMeta"
]
},
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindSpec": {
"Schema": {
"description": "MyKindSpec defines the desired state of MyKind",
"properties": {
"beeRef": {
"x-kubernetes-object-ref-api-version": "v1beta1",
"x-kubernetes-object-ref-kind": "Bee",
"$ref": "github.com/example/pkg/apis/jingfang/v1beta1.BeeObjectReference"
},
"secretRef": {
"description": "If defined, use this secret for configuring the MYSQL_ROOT_PASSWORD",
"x-kubernetes-object-ref-api-version": "v1",
"x-kubernetes-object-ref-kind": "Secret",
"$ref": "sigs.k8s.io/kustomize/pseudo/k8s/api/core/v1.LocalObjectReference"
}
}
},
"Dependencies": [
"github.com/example/pkg/apis/jingfang/v1beta1.BeeObjectReference",
"sigs.k8s.io/kustomize/pseudo/k8s/api/core/v1.LocalObjectReference"
]
},
"github.com/example/pkg/apis/jingfang/v1beta1.MyKindStatus": {
"Schema": {
"description": "MyKindStatus defines the observed state of MyKind"
},
"Dependencies": []
}
}
`)
}
func TestCrdBase(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/base")
writeBaseWithCrd(th)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
data:
PATH: yellowBrickRoad
kind: Secret
metadata:
name: x-crdsecret
---
apiVersion: jingfang.example.com/v1beta1
kind: MyKind
metadata:
name: x-mykind
spec:
beeRef:
name: x-bee
secretRef:
name: x-crdsecret
---
apiVersion: v1beta1
kind: Bee
metadata:
name: x-bee
spec:
action: fly
`)
}
func TestCrdWithOverlay(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/overlay")
writeBaseWithCrd(th)
th.WriteK("/app/overlay", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: prod-
resources:
- ../base
patchesStrategicMerge:
- bee.yaml
`)
th.WriteF("/app/overlay/bee.yaml", `
apiVersion: v1beta1
kind: Bee
metadata:
name: bee
spec:
action: makehoney
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
data:
PATH: yellowBrickRoad
kind: Secret
metadata:
name: prod-x-crdsecret
---
apiVersion: jingfang.example.com/v1beta1
kind: MyKind
metadata:
name: prod-x-mykind
spec:
beeRef:
name: prod-x-bee
secretRef:
name: prod-x-crdsecret
---
apiVersion: v1beta1
kind: Bee
metadata:
name: prod-x-bee
spec:
action: makehoney
`)
}
func TestCrdWithContainers(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/crd/containers")
th.WriteK("/app/crd/containers", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- crd.yaml
images:
- name: test/test
newName: registry.gitlab.com/test
newTag: latest
`)
th.WriteF("/app/crd/containers/crd.yaml", `
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: crontabs.stable.example.com
spec:
group: stable.example.com
scope: Namespaced
names:
plural: crontabs
singular: crontab
kind: CronTab
shortNames:
- ct
validation:
openAPIV3Schema:
properties:
spec:
containers:
description: Containers allows injecting additional containers
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: crontabs.stable.example.com
spec:
group: stable.example.com
names:
kind: CronTab
plural: crontabs
shortNames:
- ct
singular: crontab
scope: Namespaced
validation:
openAPIV3Schema:
properties:
spec:
containers:
description: Containers allows injecting additional containers
`)
}

View File

@@ -18,10 +18,12 @@ package target_test
import (
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func makeBaseReferencingCustomConfig(th *KustTestHarness) {
th.writeK("/app/base", `
func makeBaseReferencingCustomConfig(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/base", `
namePrefix: x-
commonLabels:
app: myApp
@@ -39,29 +41,29 @@ vars:
fieldref:
fieldpath: spec.diet
resources:
- animalPark.yaml
- giraffes.yaml
- gorilla.yaml
- animalPark.yaml
configurations:
- config/defaults.yaml
- config/custom.yaml
`)
th.writeF("/app/base/giraffes.yaml", `
kind: Giraffe
metadata:
name: may
spec:
diet: acacia
location: SE
---
th.WriteF("/app/base/giraffes.yaml", `
kind: Giraffe
metadata:
name: april
spec:
diet: mimosa
location: NE
---
kind: Giraffe
metadata:
name: may
spec:
diet: acacia
location: SE
`)
th.writeF("/app/base/gorilla.yaml", `
th.WriteF("/app/base/gorilla.yaml", `
kind: Gorilla
metadata:
name: koko
@@ -69,7 +71,7 @@ spec:
diet: bambooshoots
location: SW
`)
th.writeF("/app/base/animalPark.yaml", `
th.WriteF("/app/base/animalPark.yaml", `
kind: AnimalPark
metadata:
name: sandiego
@@ -85,10 +87,10 @@ spec:
}
func TestCustomConfig(t *testing.T) {
th := NewKustTestHarness(t, "/app/base")
th := kusttest_test.NewKustTestHarness(t, "/app/base")
makeBaseReferencingCustomConfig(th)
th.writeDefaultConfigs("/app/base/config/defaults.yaml")
th.writeF("/app/base/config/custom.yaml", `
th.WriteDefaultConfigs("/app/base/config/defaults.yaml")
th.WriteF("/app/base/config/custom.yaml", `
nameReference:
- kind: Gorilla
fieldSpecs:
@@ -102,11 +104,11 @@ varReference:
- path: spec/food
kind: AnimalPark
`)
m, err := th.makeKustTarget().MakeCustomizedResMap()
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.assertActualEqualsExpected(m, `
th.AssertActualEqualsExpected(m, `
kind: AnimalPark
metadata:
labels:
@@ -151,13 +153,13 @@ spec:
}
func TestCustomConfigWithDefaultOverspecification(t *testing.T) {
th := NewKustTestHarness(t, "/app/base")
th := kusttest_test.NewKustTestHarness(t, "/app/base")
makeBaseReferencingCustomConfig(th)
th.writeDefaultConfigs("/app/base/config/defaults.yaml")
th.WriteDefaultConfigs("/app/base/config/defaults.yaml")
// Specifying namePrefix here conflicts with (is the same as)
// the defaults written above. This is intentional in the
// test to assure duplicate config doesn't cause problems.
th.writeF("/app/base/config/custom.yaml", `
th.WriteF("/app/base/config/custom.yaml", `
namePrefix:
- path: metadata/name
nameReference:
@@ -173,11 +175,11 @@ varReference:
- path: spec/food
kind: AnimalPark
`)
m, err := th.makeKustTarget().MakeCustomizedResMap()
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.assertActualEqualsExpected(m, `
th.AssertActualEqualsExpected(m, `
kind: AnimalPark
metadata:
labels:
@@ -222,10 +224,10 @@ spec:
}
func TestFixedBug605_BaseCustomizationAvailableInOverlay(t *testing.T) {
th := NewKustTestHarness(t, "/app/overlay")
th := kusttest_test.NewKustTestHarness(t, "/app/overlay")
makeBaseReferencingCustomConfig(th)
th.writeDefaultConfigs("/app/base/config/defaults.yaml")
th.writeF("/app/base/config/custom.yaml", `
th.WriteDefaultConfigs("/app/base/config/defaults.yaml")
th.WriteF("/app/base/config/custom.yaml", `
nameReference:
- kind: Gorilla
fieldSpecs:
@@ -239,18 +241,17 @@ varReference:
- path: spec/food
kind: AnimalPark
`)
th.writeK("/app/overlay", `
th.WriteK("/app/overlay", `
namePrefix: o-
commonLabels:
movie: planetOfTheApes
patchesStrategicMerge:
- animalPark.yaml
resources:
- ursus.yaml
bases:
- ../base
- ursus.yaml
`)
th.writeF("/app/overlay/ursus.yaml", `
th.WriteF("/app/overlay/ursus.yaml", `
kind: Gorilla
metadata:
name: ursus
@@ -259,7 +260,7 @@ spec:
location: Arizona
`)
// The following replaces the gorillaRef in the AnimalPark.
th.writeF("/app/overlay/animalPark.yaml", `
th.WriteF("/app/overlay/animalPark.yaml", `
kind: AnimalPark
metadata:
name: sandiego
@@ -268,19 +269,18 @@ spec:
name: ursus
`)
m, err := th.makeKustTarget().MakeCustomizedResMap()
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
// TODO(#669): The name of AnimalPark should be x-o-sandiego,
// not o-sandiego, since AnimalPark appears in the base.
th.assertActualEqualsExpected(m, `
th.AssertActualEqualsExpected(m, `
kind: AnimalPark
metadata:
labels:
app: myApp
movie: planetOfTheApes
name: o-sandiego
name: o-x-sandiego
spec:
food:
- mimosa

View File

@@ -0,0 +1,216 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target_test
import (
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
// Demo custom configuration of a builtin transformation.
// This is a NamePrefixer that only touches Deployments
// and Services.
func TestCustomNamePrefixer(t *testing.T) {
tc := kusttest_test.NewPluginTestEnv(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PrefixSuffixTransformer")
th := kusttest_test.NewKustTestHarnessAllowPlugins(t, "/app")
th.WriteK("/app", `
resources:
- deployment.yaml
- role.yaml
- service.yaml
transformers:
- prefixer.yaml
`)
th.WriteF("/app/prefixer.yaml", `
apiVersion: builtin
kind: PrefixSuffixTransformer
metadata:
name: customPrefixer
prefix: zzz-
fieldSpecs:
- kind: Deployment
path: metadata/name
- kind: Service
path: metadata/name
`)
th.WriteF("/app/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeployment
spec:
template:
metadata:
labels:
backend: awesome
spec:
containers:
- name: whatever
image: whatever
`)
th.WriteF("/app/role.yaml", `
apiVersion: v1
kind: Role
metadata:
name: myRole
`)
th.WriteF("/app/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: myService
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: zzz-myDeployment
spec:
template:
metadata:
labels:
backend: awesome
spec:
containers:
- image: whatever
name: whatever
---
apiVersion: v1
kind: Role
metadata:
name: myRole
---
apiVersion: v1
kind: Service
metadata:
name: zzz-myService
`)
}
// Demo custom configuration as a base.
func TestReusableCustomNamePrefixer(t *testing.T) {
tc := kusttest_test.NewPluginTestEnv(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PrefixSuffixTransformer")
tc.BuildGoPlugin(
"builtin", "", "LabelTransformer")
th := kusttest_test.NewKustTestHarnessAllowPlugins(t, "/app/foo")
// This kustomization file contains resources that
// all happen to be plugin configurations. This makes
// these plugins all available as part of a base,
// re-usable in any number of other kustomizations.
// Just specify the path (or URL) to this base in the
// "transformers:" field (not the "resources" field).
th.WriteK("/app/mytransformers", `
resources:
- prefixer.yaml
- labeller.yaml
`)
th.WriteF("/app/mytransformers/prefixer.yaml", `
apiVersion: builtin
kind: PrefixSuffixTransformer
metadata:
name: myPrefixer
prefix: zzz-
fieldSpecs:
- kind: Deployment
path: metadata/name
- kind: Service
path: metadata/name
`)
th.WriteF("/app/mytransformers/labeller.yaml", `
apiVersion: builtin
kind: LabelTransformer
metadata:
name: myLabeller
labels:
company: acmeCorp
fieldSpecs:
- path: spec/template/metadata/labels
kind: Deployment
`)
th.WriteK("/app/foo", `
resources:
- deployment.yaml
- role.yaml
- service.yaml
transformers:
- ../mytransformers
`)
th.WriteF("/app/foo/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: myDeployment
spec:
template:
metadata:
labels:
backend: awesome
spec:
containers:
- name: whatever
image: whatever
`)
th.WriteF("/app/foo/role.yaml", `
apiVersion: v1
kind: Role
metadata:
name: myRole
`)
th.WriteF("/app/foo/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: myService
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: zzz-myDeployment
spec:
template:
metadata:
labels:
backend: awesome
company: acmeCorp
spec:
containers:
- image: whatever
name: whatever
---
apiVersion: v1
kind: Role
metadata:
name: myRole
---
apiVersion: v1
kind: Service
metadata:
name: zzz-myService
`)
}

View File

@@ -0,0 +1,490 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target_test
import (
"fmt"
"path/filepath"
"strings"
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
const patchAddProbe = `
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
template:
spec:
containers:
- name: my-deployment
livenessProbe:
httpGet:
path: /healthz
port: 8080
`
const container = `{ "image": "my-image", "livenessProbe": { "httpGet" : {"path": "/healthz", "port": 8080 } }, "name": "my-deployment"}`
const patchJsonAddProbe = `[{"op": "replace", "path": "/spec/template/spec/containers/0", "value": ` +
container + `}]`
const patchDnsPolicy = `
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
template:
spec:
dnsPolicy: ClusterFirst
`
const patchJsonDnsPolicy = `[{"op": "add", "path": "/spec/template/spec/dnsPolicy", "value": "ClusterFirst"}]`
const patchRestartPolicy = `
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
template:
spec:
restartPolicy: Always
`
const patchJsonRestartPolicy = `[{"op": "add", "path": "/spec/template/spec/restartPolicy", "value": "Always"}]`
func writeDeploymentBase(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/base", `
resources:
- deployment.yaml
`)
th.WriteF("/app/base/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
template:
spec:
dnsPolicy: "None"
containers:
- name: my-deployment
image: my-image
`)
}
func writeProbeOverlay(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/probe", `
resources:
- ../base
patchesStrategicMerge:
- dep-patch.yaml
`)
th.WriteF("/app/probe/dep-patch.yaml", patchAddProbe)
}
func writeDNSOverlay(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/dns", `
resources:
- ../base
patchesStrategicMerge:
- dep-patch.yaml
`)
th.WriteF("/app/dns/dep-patch.yaml", patchDnsPolicy)
}
func writeRestartOverlay(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/restart", `
resources:
- ../base
patchesStrategicMerge:
- dep-patch.yaml
`)
th.WriteF("/app/restart/dep-patch.yaml", patchRestartPolicy)
}
// Here's a composite kustomization, that combines multiple overlays
// (replicas, dns and metadata) which patch the same base resource.
//
// The base resource is a deployment and the overlays patch aspects
// of it, without using any of the `namePrefix`, `nameSuffix` or `namespace`
// kustomization keywords.
//
// composite
// / | \
// probe dns restart
// \ | /
// base
//
func TestIssue1251_CompositeDiamond_Failure(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/composite")
writeDeploymentBase(th)
writeProbeOverlay(th)
writeDNSOverlay(th)
writeRestartOverlay(th)
th.WriteK("/app/composite", `
resources:
- ../probe
- ../dns
- ../restart
`)
_, err := th.MakeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("Expected resource accumulation error")
}
if !strings.Contains(
err.Error(), "already registered id: apps_v1_Deployment|~X|my-deployment") {
t.Fatalf("Unexpected err: %v", err)
}
}
const expectedPatchedDeployment = `
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
template:
spec:
containers:
- image: my-image
livenessProbe:
httpGet:
path: /healthz
port: 8080
name: my-deployment
dnsPolicy: ClusterFirst
restartPolicy: Always
`
// This test reuses some methods from TestIssue1251_CompositeDiamond,
// but overwrites the kustomization files in the overlays.
func TestIssue1251_Patches_Overlayed(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/restart")
writeDeploymentBase(th)
// probe overlays base.
writeProbeOverlay(th)
// dns overlays probe.
writeDNSOverlay(th)
th.WriteK("/app/dns", `
resources:
- ../probe
patchesStrategicMerge:
- dep-patch.yaml
`)
// restart overlays dns.
writeRestartOverlay(th)
th.WriteK("/app/restart", `
resources:
- ../dns
patchesStrategicMerge:
- dep-patch.yaml
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, expectedPatchedDeployment)
}
func TestIssue1251_Patches_Local(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/composite")
writeDeploymentBase(th)
th.WriteK("/app/composite", `
resources:
- ../base
patchesStrategicMerge:
- patchAddProbe.yaml
- patchDnsPolicy.yaml
- patchRestartPolicy.yaml
`)
th.WriteF("/app/composite/patchRestartPolicy.yaml", patchRestartPolicy)
th.WriteF("/app/composite/patchDnsPolicy.yaml", patchDnsPolicy)
th.WriteF("/app/composite/patchAddProbe.yaml", patchAddProbe)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, expectedPatchedDeployment)
}
func definePatchDirStructure(th *kusttest_test.KustTestHarness) {
writeDeploymentBase(th)
th.WriteF("/app/patches/patchRestartPolicy.yaml", patchRestartPolicy)
th.WriteF("/app/patches/patchDnsPolicy.yaml", patchDnsPolicy)
th.WriteF("/app/patches/patchAddProbe.yaml", patchAddProbe)
}
// Fails due to file load restrictor.
func TestIssue1251_Patches_ProdVsDev_Failure(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/prod")
definePatchDirStructure(th)
th.WriteK("/app/prod", `
resources:
- ../base
patchesStrategicMerge:
- ../patches/patchAddProbe.yaml
- ../patches/patchDnsPolicy.yaml
`)
_, err := th.MakeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("expected error")
}
if !strings.Contains(
err.Error(),
"security; file '/app/patches/patchAddProbe.yaml' is not in or below '/app/prod'") {
t.Fatalf("unexpected error: %v", err)
}
}
const prodDevMergeResult1 = `
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
template:
spec:
containers:
- image: my-image
livenessProbe:
httpGet:
path: /healthz
port: 8080
name: my-deployment
dnsPolicy: ClusterFirst
`
const prodDevMergeResult2 = `
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
template:
spec:
containers:
- image: my-image
name: my-deployment
dnsPolicy: ClusterFirst
restartPolicy: Always
`
// This test does what
// TestIssue1251_Patches_ProdVsDev_Failure
// failed to do, because this test does the equivalent
// os specifying `--load_restrictor none` on the build.
//
// This allows the use patch files located outside the
// kustomization root, and not in a kustomization
// themselves.
//
// Doing so means the kustomization using them is no
// longer relocatable, not addressible via a git URL,
// and not git clonable. It's no longer self-contained.
//
// Likewise suppressing load restrictions happens for
// the entire build (i.e. everything can reach outside
// the kustomization root), opening the user to whatever
// threat the load restrictor was meant to address.
func TestIssue1251_Patches_ProdVsDev(t *testing.T) {
th := kusttest_test.NewKustTestHarnessNoLoadRestrictor(t, "/app/prod")
definePatchDirStructure(th)
th.WriteK("/app/prod", `
resources:
- ../base
patchesStrategicMerge:
- ../patches/patchAddProbe.yaml
- ../patches/patchDnsPolicy.yaml
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
th.AssertActualEqualsExpected(m, prodDevMergeResult1)
th = kusttest_test.NewKustTestHarnessNoLoadRestrictor(t, "/app/dev")
definePatchDirStructure(th)
th.WriteK("/app/dev", `
resources:
- ../base
patchesStrategicMerge:
- ../patches/patchDnsPolicy.yaml
- ../patches/patchRestartPolicy.yaml
`)
m, err = th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, prodDevMergeResult2)
}
func TestIssue1251_Plugins_ProdVsDev(t *testing.T) {
tc := kusttest_test.NewPluginTestEnv(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PatchJson6902Transformer")
th := kusttest_test.NewKustTestHarnessAllowPlugins(t, "/app/prod")
defineTransformerDirStructure(th)
th.WriteK("/app/prod", `
resources:
- ../base
transformers:
- ../patches/addProbe
- ../patches/addDnsPolicy
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, prodDevMergeResult1)
th = kusttest_test.NewKustTestHarnessAllowPlugins(t, "/app/dev")
defineTransformerDirStructure(th)
th.WriteK("/app/dev", `
resources:
- ../base
transformers:
- ../patches/addRestartPolicy
- ../patches/addDnsPolicy
`)
m, err = th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, prodDevMergeResult2)
}
func TestIssue1251_Plugins_Local(t *testing.T) {
tc := kusttest_test.NewPluginTestEnv(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PatchJson6902Transformer")
th := kusttest_test.NewKustTestHarnessAllowPlugins(t, "/app/composite")
writeDeploymentBase(th)
writeJsonTransformerPluginConfig(
th, "/app/composite", "addDnsPolicy", patchJsonDnsPolicy)
writeJsonTransformerPluginConfig(
th, "/app/composite", "addRestartPolicy", patchJsonRestartPolicy)
writeJsonTransformerPluginConfig(
th, "/app/composite", "addProbe", patchJsonAddProbe)
th.WriteK("/app/composite", `
resources:
- ../base
transformers:
- addDnsPolicyConfig.yaml
- addRestartPolicyConfig.yaml
- addProbeConfig.yaml
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, expectedPatchedDeployment)
}
func writeJsonTransformerPluginConfig(
th *kusttest_test.KustTestHarness, path, name, patch string) {
th.WriteF(filepath.Join(path, name+"Config.yaml"),
fmt.Sprintf(`
apiVersion: builtin
kind: PatchJson6902Transformer
metadata:
name: %s
target:
group: apps
version: v1
kind: Deployment
name: my-deployment
jsonOp: '%s'
`, name, patch))
}
// Remote in the sense that they are bundled in a different kustomization.
func TestIssue1251_Plugins_Bundled(t *testing.T) {
tc := kusttest_test.NewPluginTestEnv(t).Set()
defer tc.Reset()
tc.BuildGoPlugin(
"builtin", "", "PatchJson6902Transformer")
th := kusttest_test.NewKustTestHarnessAllowPlugins(t, "/app/composite")
writeDeploymentBase(th)
th.WriteK("/app/patches", `
resources:
- addDnsPolicyConfig.yaml
- addRestartPolicyConfig.yaml
- addProbeConfig.yaml
`)
writeJsonTransformerPluginConfig(
th, "/app/patches", "addDnsPolicy", patchJsonDnsPolicy)
writeJsonTransformerPluginConfig(
th, "/app/patches", "addRestartPolicy", patchJsonRestartPolicy)
writeJsonTransformerPluginConfig(
th, "/app/patches", "addProbe", patchJsonAddProbe)
th.WriteK("/app/composite", `
resources:
- ../base
transformers:
- ../patches
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, expectedPatchedDeployment)
}
func defineTransformerDirStructure(th *kusttest_test.KustTestHarness) {
writeDeploymentBase(th)
th.WriteK("/app/patches/addDnsPolicy", `
resources:
- addDnsPolicyConfig.yaml
`)
writeJsonTransformerPluginConfig(
th, "/app/patches/addDnsPolicy", "addDnsPolicy", patchJsonDnsPolicy)
th.WriteK("/app/patches/addRestartPolicy", `
resources:
- addRestartPolicyConfig.yaml
`)
writeJsonTransformerPluginConfig(
th, "/app/patches/addRestartPolicy", "addRestartPolicy", patchJsonRestartPolicy)
th.WriteK("/app/patches/addProbe", `
resources:
- addProbeConfig.yaml
`)
writeJsonTransformerPluginConfig(
th, "/app/patches/addProbe", "addProbe", patchJsonAddProbe)
}

View File

@@ -0,0 +1,225 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target_test
import (
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
// Here's a structure of two kustomizations,
// `dev` and `prod`, individually deployable,
// that depend on a diamond that combines
// multiple tenants (kirk, spock and bones),
// each sharing a common base.
//
// The objects used are contrived to avoid
// clouding the example with authentic
// but verbose Deployment boilerplate.
//
// Patches are applied at various levels,
// requiring more specificity as needed.
//
// dev prod
// \ /
// tenants
// / | \
// kirk spock bones
// \ | /
// base
//
func writeDiamondBase(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/base", `
resources:
- deploy.yaml
`)
th.WriteF("/app/base/deploy.yaml", `
apiVersion: v1
kind: Deployment
metadata:
name: storefront
spec:
numReplicas: 1
`)
}
func writeKirk(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/kirk", `
namePrefix: kirk-
resources:
- ../base
- configmap.yaml
patchesStrategicMerge:
- dep-patch.yaml
`)
th.WriteF("/app/kirk/dep-patch.yaml", `
apiVersion: v1
kind: Deployment
metadata:
name: storefront
spec:
type: Confident
`)
th.WriteF("/app/kirk/configmap.yaml", `
apiVersion: v1
kind: ConfigMap
metadata:
name: settings
data:
phaser: caress
`)
}
func writeSpock(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/spock", `
namePrefix: spock-
resources:
- ../base
patchesStrategicMerge:
- dep-patch.yaml
`)
th.WriteF("/app/spock/dep-patch.yaml", `
apiVersion: v1
kind: Deployment
metadata:
name: storefront
spec:
type: Logical
`)
}
func writeBones(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/bones", `
namePrefix: bones-
resources:
- ../base
patchesStrategicMerge:
- dep-patch.yaml
`)
th.WriteF("/app/bones/dep-patch.yaml", `
apiVersion: v1
kind: Deployment
metadata:
name: storefront
spec:
type: Concerned
`)
}
func writeTenants(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/tenants", `
namePrefix: t-
resources:
- ../kirk
- ../spock
- ../bones
- configMap.yaml
patchesStrategicMerge:
- bones-patch.yaml
`)
th.WriteF("/app/tenants/bones-patch.yaml", `
apiVersion: v1
kind: Deployment
metadata:
name: bones-storefront
spec:
mood: Cantankerous
`)
th.WriteF("/app/tenants/configMap.yaml", `
apiVersion: v1
kind: ConfigMap
metadata:
name: federation
data:
zone: neutral
guardian: forever
`)
}
func TestBasicDiamond(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/prod")
writeDiamondBase(th)
writeKirk(th)
writeSpock(th)
writeBones(th)
writeTenants(th)
th.WriteK("/app/prod", `
namePrefix: prod-
resources:
- ../tenants
patchesStrategicMerge:
- patches.yaml
`)
// The patch only has to be specific enough
// to match the item.
th.WriteF("/app/prod/patches.yaml", `
apiVersion: v1
kind: Deployment
metadata:
name: t-kirk-storefront
spec:
numReplicas: 10000
---
apiVersion: v1
kind: ConfigMap
metadata:
name: federation
data:
guardian: ofTheGalaxy
---
apiVersion: v1
kind: ConfigMap
metadata:
name: t-federation
data:
zone: twilight
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: Deployment
metadata:
name: prod-t-kirk-storefront
spec:
numReplicas: 10000
type: Confident
---
apiVersion: v1
data:
phaser: caress
kind: ConfigMap
metadata:
name: prod-t-kirk-settings
---
apiVersion: v1
kind: Deployment
metadata:
name: prod-t-spock-storefront
spec:
numReplicas: 1
type: Logical
---
apiVersion: v1
kind: Deployment
metadata:
name: prod-t-bones-storefront
spec:
mood: Cantankerous
numReplicas: 1
type: Concerned
---
apiVersion: v1
data:
guardian: ofTheGalaxy
zone: twilight
kind: ConfigMap
metadata:
name: prod-t-federation
`)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,597 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package target_test
import (
"strings"
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func TestSimpleBase(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/base")
th.WriteK("/app/base", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: team-foo-
commonLabels:
app: mynginx
org: example.com
team: foo
commonAnnotations:
note: This is a test annotation
resources:
- service.yaml
- deployment.yaml
- networkpolicy.yaml
`)
th.WriteF("/app/base/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
selector:
app: nginx
`)
th.WriteF("/app/base/networkpolicy.yaml", `
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: nginx
spec:
podSelector:
matchExpressions:
- {key: app, operator: In, values: [test]}
ingress:
- from:
- podSelector:
matchLabels:
app: nginx
`)
th.WriteF("/app/base/deployment.yaml", `
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: Service
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
org: example.com
team: foo
name: team-foo-nginx
spec:
ports:
- port: 80
selector:
app: mynginx
org: example.com
team: foo
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
org: example.com
team: foo
name: team-foo-nginx
spec:
selector:
matchLabels:
app: mynginx
org: example.com
team: foo
template:
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
org: example.com
team: foo
spec:
containers:
- image: nginx
name: nginx
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
org: example.com
team: foo
name: team-foo-nginx
spec:
ingress:
- from:
- podSelector:
matchLabels:
app: mynginx
org: example.com
team: foo
podSelector:
matchExpressions:
- key: app
operator: In
values:
- test
`)
}
func makeBaseWithGenerators(th *kusttest_test.KustTestHarness) {
th.WriteK("/app", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: team-foo-
commonLabels:
app: mynginx
org: example.com
team: foo
commonAnnotations:
note: This is a test annotation
resources:
- deployment.yaml
- service.yaml
configMapGenerator:
- name: configmap-in-base
literals:
- foo=bar
secretGenerator:
- name: secret-in-base
literals:
- username=admin
- password=somepw
`)
th.WriteF("/app/deployment.yaml", `
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: nginx-persistent-storage
mountPath: /tmp/ps
volumes:
- name: nginx-persistent-storage
emptyDir: {}
- configMap:
name: configmap-in-base
name: configmap-in-base
`)
th.WriteF("/app/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
selector:
app: nginx
`)
}
func TestBaseWithGeneratorsAlone(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app")
makeBaseWithGenerators(th)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1beta2
kind: Deployment
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
org: example.com
team: foo
name: team-foo-nginx
spec:
selector:
matchLabels:
app: mynginx
org: example.com
team: foo
template:
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
org: example.com
team: foo
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: nginx-persistent-storage
volumes:
- emptyDir: {}
name: nginx-persistent-storage
- configMap:
name: team-foo-configmap-in-base-bbdmdh7m8t
name: configmap-in-base
---
apiVersion: v1
kind: Service
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
org: example.com
team: foo
name: team-foo-nginx
spec:
ports:
- port: 80
selector:
app: mynginx
org: example.com
team: foo
---
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
org: example.com
team: foo
name: team-foo-configmap-in-base-bbdmdh7m8t
---
apiVersion: v1
data:
password: c29tZXB3
username: YWRtaW4=
kind: Secret
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
org: example.com
team: foo
name: team-foo-secret-in-base-tkm7hhtf8d
type: Opaque
`)
}
func TestMergeAndReplaceGenerators(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/overlay")
makeBaseWithGenerators(th)
th.WriteF("/overlay/deployment.yaml", `
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
volumes:
- name: nginx-persistent-storage
emptyDir: null
gcePersistentDisk:
pdName: nginx-persistent-storage
- configMap:
name: configmap-in-overlay
name: configmap-in-overlay
`)
th.WriteK("/overlay", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: staging-
commonLabels:
env: staging
team: override-foo
patchesStrategicMerge:
- deployment.yaml
resources:
- ../app
configMapGenerator:
- name: configmap-in-overlay
literals:
- hello=world
- name: configmap-in-base
behavior: replace
literals:
- foo=override-bar
secretGenerator:
- name: secret-in-base
behavior: merge
literals:
- proxy=haproxy
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1beta2
kind: Deployment
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: override-foo
name: staging-team-foo-nginx
spec:
selector:
matchLabels:
app: mynginx
env: staging
org: example.com
team: override-foo
template:
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: override-foo
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: nginx-persistent-storage
volumes:
- gcePersistentDisk:
pdName: nginx-persistent-storage
name: nginx-persistent-storage
- configMap:
name: staging-configmap-in-overlay-k7cbc75tg8
name: configmap-in-overlay
- configMap:
name: staging-team-foo-configmap-in-base-gh9d7t85gb
name: configmap-in-base
---
apiVersion: v1
kind: Service
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: override-foo
name: staging-team-foo-nginx
spec:
ports:
- port: 80
selector:
app: mynginx
env: staging
org: example.com
team: override-foo
---
apiVersion: v1
data:
foo: override-bar
kind: ConfigMap
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: override-foo
name: staging-team-foo-configmap-in-base-gh9d7t85gb
---
apiVersion: v1
data:
password: c29tZXB3
proxy: aGFwcm94eQ==
username: YWRtaW4=
kind: Secret
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: override-foo
name: staging-team-foo-secret-in-base-c8db7gk2m2
type: Opaque
---
apiVersion: v1
data:
hello: world
kind: ConfigMap
metadata:
labels:
env: staging
team: override-foo
name: staging-configmap-in-overlay-k7cbc75tg8
`)
}
func TestGeneratingIntoNamespaces(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app")
th.WriteK("/app", `
configMapGenerator:
- name: test
namespace: default
literals:
- key=value
- name: test
namespace: kube-system
literals:
- key=value
secretGenerator:
- name: test
namespace: default
literals:
- username=admin
- password=somepw
- name: test
namespace: kube-system
literals:
- username=admin
- password=somepw
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
data:
key: value
kind: ConfigMap
metadata:
name: test-t5t4md8fdm
namespace: default
---
apiVersion: v1
data:
key: value
kind: ConfigMap
metadata:
name: test-t5t4md8fdm
namespace: kube-system
---
apiVersion: v1
data:
password: c29tZXB3
username: YWRtaW4=
kind: Secret
metadata:
name: test-h65t9hg6kc
namespace: default
type: Opaque
---
apiVersion: v1
data:
password: c29tZXB3
username: YWRtaW4=
kind: Secret
metadata:
name: test-h65t9hg6kc
namespace: kube-system
type: Opaque
`)
}
// Valid that conflict is detected is the name are identical
// and namespace left to default
func TestConfigMapGeneratingIntoSameNamespace(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app")
th.WriteK("/app", `
configMapGenerator:
- name: test
namespace: default
literals:
- key=value
- name: test
literals:
- key=value
`)
_, err := th.MakeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("expected error")
}
if !strings.Contains(err.Error(), "must merge or replace") {
t.Fatalf("unexpected error %v", err)
}
}
// Valid that conflict is detected is the name are identical
// and namespace left to default
func TestSecretGeneratingIntoSameNamespace(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app")
th.WriteK("/app", `
secretGenerator:
- name: test
namespace: default
literals:
- username=admin
- password=somepw
- name: test
literals:
- username=admin
- password=somepw
`)
_, err := th.MakeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("expected error")
}
if !strings.Contains(err.Error(), "must merge or replace") {
t.Fatalf("unexpected error %v", err)
}
}

View File

@@ -0,0 +1,115 @@
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package target_test
import (
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func TestSecretGenerator(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app")
th.WriteK("/app", `
secretGenerator:
- name: bob
literals:
- FRUIT=apple
- VEGETABLE=carrot
files:
- foo.env
- passphrase=phrase.dat
envs:
- foo.env
`)
th.WriteF("/app/foo.env", `
MOUNTAIN=everest
OCEAN=pacific
`)
th.WriteF("/app/phrase.dat", "dat phrase")
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
data:
FRUIT: YXBwbGU=
MOUNTAIN: ZXZlcmVzdA==
OCEAN: cGFjaWZpYw==
VEGETABLE: Y2Fycm90
foo.env: Ck1PVU5UQUlOPWV2ZXJlc3QKT0NFQU49cGFjaWZpYwo=
passphrase: ZGF0IHBocmFzZQ==
kind: Secret
metadata:
name: bob-kf5c9fccbt
type: Opaque
`)
}
func TestGeneratorOptionsWithBases(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/overlay")
th.WriteK("/app/base", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
generatorOptions:
disableNameSuffixHash: true
labels:
foo: bar
configMapGenerator:
- name: shouldNotHaveHash
literals:
- foo=bar
`)
th.WriteK("/app/overlay", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base
generatorOptions:
disableNameSuffixHash: false
labels:
fruit: apple
configMapGenerator:
- name: shouldHaveHash
literals:
- fruit=apple
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
labels:
foo: bar
name: shouldNotHaveHash
---
apiVersion: v1
data:
fruit: apple
kind: ConfigMap
metadata:
labels:
fruit: apple
name: shouldHaveHash-2k9hc848ff
`)
}

View File

@@ -0,0 +1,244 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target_test
import (
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func makeResourcesForPatchTest(th *kusttest_test.KustTestHarness) {
th.WriteF("/app/base/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: nginx-persistent-storage
mountPath: /tmp/ps
volumes:
- name: nginx-persistent-storage
emptyDir: {}
- configMap:
name: configmap-in-base
name: configmap-in-base
`)
}
func TestStrategicMergePatchInline(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/base")
makeResourcesForPatchTest(th)
th.WriteK("/app/base", `
resources:
- deployment.yaml
patchesStrategicMerge:
- |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
image: image1
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: image1
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: nginx-persistent-storage
volumes:
- emptyDir: {}
name: nginx-persistent-storage
- configMap:
name: configmap-in-base
name: configmap-in-base
`)
}
func TestJSONPatchInline(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/base")
makeResourcesForPatchTest(th)
th.WriteK("/app/base", `
resources:
- deployment.yaml
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: nginx
patch: |-
- op: replace
path: /spec/template/spec/containers/0/image
value: image1
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: image1
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: nginx-persistent-storage
volumes:
- emptyDir: {}
name: nginx-persistent-storage
- configMap:
name: configmap-in-base
name: configmap-in-base
`)
}
func TestExtendedPatchInlineJSON(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/base")
makeResourcesForPatchTest(th)
th.WriteK("/app/base", `
resources:
- deployment.yaml
patches:
- target:
kind: Deployment
name: nginx
patch: |-
- op: replace
path: /spec/template/spec/containers/0/image
value: image1
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: image1
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: nginx-persistent-storage
volumes:
- emptyDir: {}
name: nginx-persistent-storage
- configMap:
name: configmap-in-base
name: configmap-in-base
`)
}
func TestExtendedPatchInlineYAML(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/base")
makeResourcesForPatchTest(th)
th.WriteK("/app/base", `
resources:
- deployment.yaml
patches:
- target:
kind: Deployment
name: nginx
patch: |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
image: image1
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: image1
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: nginx-persistent-storage
volumes:
- emptyDir: {}
name: nginx-persistent-storage
- configMap:
name: configmap-in-base
name: configmap-in-base
`)
}

View File

@@ -0,0 +1,411 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package target implements state for the set of all
// resources to customize.
package target
import (
"bytes"
"encoding/json"
"fmt"
"log"
"strings"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/builtins"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/internal/accumulator"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers"
"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"
)
// KustTarget encapsulates the entirety of a kustomization build.
type KustTarget struct {
kustomization *types.Kustomization
ldr ifc.Loader
validator ifc.Validator
rFactory *resmap.Factory
tFactory resmap.PatchFactory
pLdr *loader.Loader
}
// NewKustTarget returns a new instance of KustTarget primed with a Loader.
func NewKustTarget(
ldr ifc.Loader,
validator ifc.Validator,
rFactory *resmap.Factory,
tFactory resmap.PatchFactory,
pLdr *loader.Loader) (*KustTarget, error) {
content, err := loadKustFile(ldr)
if err != nil {
return nil, err
}
content = types.FixKustomizationPreUnmarshalling(content)
var k types.Kustomization
err = unmarshal(content, &k)
if err != nil {
return nil, err
}
k.FixKustomizationPostUnmarshalling()
errs := k.EnforceFields()
if len(errs) > 0 {
return nil, fmt.Errorf(
"Failed to read kustomization file under %s:\n"+
strings.Join(errs, "\n"), ldr.Root())
}
return &KustTarget{
kustomization: &k,
ldr: ldr,
validator: validator,
rFactory: rFactory,
tFactory: tFactory,
pLdr: pLdr,
}, nil
}
func quoted(l []string) []string {
r := make([]string, len(l))
for i, v := range l {
r[i] = "'" + v + "'"
}
return r
}
func commaOr(q []string) string {
return strings.Join(q[:len(q)-1], ", ") + " or " + q[len(q)-1]
}
func loadKustFile(ldr ifc.Loader) ([]byte, error) {
var content []byte
match := 0
for _, kf := range konfig.RecognizedKustomizationFileNames() {
c, err := ldr.Load(kf)
if err == nil {
match += 1
content = c
}
}
switch match {
case 0:
return nil, NewErrMissingKustomization(ldr.Root())
case 1:
return content, nil
default:
return nil, fmt.Errorf(
"Found multiple kustomization files under: %s\n", ldr.Root())
}
}
type errMissingKustomization struct {
path string
}
func (e *errMissingKustomization) Error() string {
return fmt.Sprintf(
"unable to find one of %v in directory '%s'",
commaOr(quoted(konfig.RecognizedKustomizationFileNames())),
e.path)
}
func NewErrMissingKustomization(p string) *errMissingKustomization {
return &errMissingKustomization{path: p}
}
func IsMissingKustomizationFileError(err error) bool {
_, ok := err.(*errMissingKustomization)
if ok {
return true
}
_, ok = errors.Cause(err).(*errMissingKustomization)
return ok
}
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 ResMap per kustomization instructions.
// The Resources in the returned ResMap are fully customized.
func (kt *KustTarget) MakeCustomizedResMap() (resmap.ResMap, error) {
return kt.makeCustomizedResMap(types.GarbageIgnore)
}
func (kt *KustTarget) MakePruneConfigMap() (resmap.ResMap, error) {
return kt.makeCustomizedResMap(types.GarbageCollect)
}
func (kt *KustTarget) makeCustomizedResMap(
garbagePolicy types.GarbagePolicy) (resmap.ResMap, error) {
ra, err := kt.AccumulateTarget()
if err != nil {
return nil, err
}
// The following steps must be done last, not as part of
// the recursion implicit in AccumulateTarget.
err = kt.addHashesToNames(ra)
if err != nil {
return nil, err
}
// Given that names have changed (prefixs/suffixes added),
// fix all the back references to those names.
err = ra.FixBackReferences()
if err != nil {
return nil, err
}
// With all the back references fixed, it's OK to resolve Vars.
err = ra.ResolveVars()
if err != nil {
return nil, err
}
err = kt.computeInventory(ra, garbagePolicy)
if err != nil {
return nil, err
}
return ra.ResMap(), nil
}
func (kt *KustTarget) addHashesToNames(
ra *accumulator.ResAccumulator) error {
p := builtins.NewHashTransformerPlugin()
err := kt.configureBuiltinPlugin(p, nil, builtinhelpers.HashTransformer)
if err != nil {
return err
}
return ra.Transform(p)
}
func (kt *KustTarget) computeInventory(
ra *accumulator.ResAccumulator, garbagePolicy types.GarbagePolicy) error {
inv := kt.kustomization.Inventory
if inv == nil {
return nil
}
if inv.Type != "ConfigMap" {
return fmt.Errorf("don't know how to do that")
}
if inv.ConfigMap.Namespace != kt.kustomization.Namespace {
return fmt.Errorf("namespace mismatch")
}
var c struct {
Policy string
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
}
c.Name = inv.ConfigMap.Name
c.Namespace = inv.ConfigMap.Namespace
c.Policy = garbagePolicy.String()
p := builtins.NewInventoryTransformerPlugin()
err := kt.configureBuiltinPlugin(p, c, builtinhelpers.InventoryTransformer)
if err != nil {
return err
}
return ra.Transform(p)
}
func (kt *KustTarget) shouldAddHashSuffixesToGeneratedResources() bool {
return kt.kustomization.GeneratorOptions == nil ||
!kt.kustomization.GeneratorOptions.DisableNameSuffixHash
}
// AccumulateTarget returns a new ResAccumulator,
// holding customized resources and the data/rules used
// to do so. The name back references and vars are
// not yet fixed.
func (kt *KustTarget) AccumulateTarget() (
ra *accumulator.ResAccumulator, err error) {
ra = accumulator.MakeEmptyAccumulator()
err = kt.accumulateResources(ra, kt.kustomization.Resources)
if err != nil {
return nil, errors.Wrap(err, "accumulating resources")
}
tConfig, err := builtinconfig.MakeTransformerConfig(
kt.ldr, kt.kustomization.Configurations)
if err != nil {
return nil, err
}
err = ra.MergeConfig(tConfig)
if err != nil {
return nil, errors.Wrapf(
err, "merging config %v", tConfig)
}
crdTc, err := accumulator.LoadConfigFromCRDs(kt.ldr, kt.kustomization.Crds)
if err != nil {
return nil, errors.Wrapf(
err, "loading CRDs %v", kt.kustomization.Crds)
}
err = ra.MergeConfig(crdTc)
if err != nil {
return nil, errors.Wrapf(
err, "merging CRDs %v", crdTc)
}
err = kt.runGenerators(ra)
if err != nil {
return nil, err
}
err = kt.runTransformers(ra)
if err != nil {
return nil, err
}
err = ra.MergeVars(kt.kustomization.Vars)
if err != nil {
return nil, errors.Wrapf(
err, "merging vars %v", kt.kustomization.Vars)
}
return ra, nil
}
func (kt *KustTarget) runGenerators(
ra *accumulator.ResAccumulator) error {
var generators []resmap.Generator
gs, err := kt.configureBuiltinGenerators()
if err != nil {
return err
}
generators = append(generators, gs...)
gs, err = kt.configureExternalGenerators()
if err != nil {
return errors.Wrap(err, "loading generator plugins")
}
generators = append(generators, gs...)
for _, g := range generators {
resMap, err := g.Generate()
if err != nil {
return err
}
err = ra.AbsorbAll(resMap)
if err != nil {
return errors.Wrapf(err, "merging from generator %v", g)
}
}
return nil
}
func (kt *KustTarget) configureExternalGenerators() ([]resmap.Generator, error) {
ra := accumulator.MakeEmptyAccumulator()
err := kt.accumulateResources(ra, kt.kustomization.Generators)
if err != nil {
return nil, err
}
return kt.pLdr.LoadGenerators(kt.ldr, kt.validator, ra.ResMap())
}
func (kt *KustTarget) runTransformers(ra *accumulator.ResAccumulator) error {
var r []resmap.Transformer
tConfig := ra.GetTransformerConfig()
lts, err := kt.configureBuiltinTransformers(tConfig)
if err != nil {
return err
}
r = append(r, lts...)
lts, err = kt.configureExternalTransformers()
if err != nil {
return err
}
r = append(r, lts...)
t := transform.NewMultiTransformer(r)
return ra.Transform(t)
}
func (kt *KustTarget) configureExternalTransformers() ([]resmap.Transformer, error) {
ra := accumulator.MakeEmptyAccumulator()
err := kt.accumulateResources(ra, kt.kustomization.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 {
ldr, err := kt.ldr.New(path)
if err == nil {
err = kt.accumulateDirectory(ra, ldr)
if err != nil {
return err
}
} else {
err2 := kt.accumulateFile(ra, path)
if err2 != nil {
// Log ldr.New() error to highlight git failures.
log.Print(err.Error())
return err2
}
}
}
return nil
}
func (kt *KustTarget) accumulateDirectory(
ra *accumulator.ResAccumulator, ldr ifc.Loader) error {
defer ldr.Cleanup()
subKt, err := NewKustTarget(
ldr, kt.validator, kt.rFactory, kt.tFactory, kt.pLdr)
if err != nil {
return errors.Wrapf(
err, "couldn't make target for path '%s'", ldr.Root())
}
subRa, err := subKt.AccumulateTarget()
if err != nil {
return errors.Wrapf(
err, "recursed accumulation of path '%s'", ldr.Root())
}
err = ra.MergeAccumulator(subRa)
if err != nil {
return errors.Wrapf(
err, "recursed merging from path '%s'", ldr.Root())
}
return nil
}
func (kt *KustTarget) accumulateFile(
ra *accumulator.ResAccumulator, path string) error {
resources, err := kt.rFactory.FromFile(kt.ldr, path)
if err != nil {
return errors.Wrapf(err, "accumulating resources from '%s'", path)
}
err = ra.AppendAll(resources)
if err != nil {
return errors.Wrapf(err, "merging resources from '%s'", path)
}
return nil
}
func (kt *KustTarget) configureBuiltinPlugin(
p resmap.Configurable, c interface{}, bpt builtinhelpers.BuiltinPluginType) (err error) {
var y []byte
if c != nil {
y, err = yaml.Marshal(c)
if err != nil {
return errors.Wrapf(
err, "builtin %s marshal", bpt)
}
}
err = p.Config(resmap.NewPluginHelpers(kt.ldr, kt.validator, kt.rFactory), y)
if err != nil {
return errors.Wrapf(err, "builtin %s config: %v", bpt, y)
}
return nil
}

View File

@@ -0,0 +1,297 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target
import (
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
)
// Functions dedicated to configuring the builtin
// transformer and generator plugins using config data
// read from a kustomization file and from the
// config.TransformerConfig, whose data may be a
// mix of hardcoded values and data read from file.
//
// Non-builtin plugins will get their configuration
// from their own dedicated structs and YAML files.
//
// There are some loops in the functions below because
// the kustomization file would, say, allow someone to
// request multiple secrets be made, or run multiple
// image tag transforms. In these cases, we'll need
// N plugin instances with differing configurations.
func (kt *KustTarget) configureBuiltinGenerators() (
result []resmap.Generator, err error) {
for _, bpt := range []builtinhelpers.BuiltinPluginType{
builtinhelpers.ConfigMapGenerator,
builtinhelpers.SecretGenerator,
} {
r, err := generatorConfigurators[bpt](
kt, bpt, builtinhelpers.GeneratorFactories[bpt])
if err != nil {
return nil, err
}
result = append(result, r...)
}
return result, nil
}
func (kt *KustTarget) configureBuiltinTransformers(
tc *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
for _, bpt := range []builtinhelpers.BuiltinPluginType{
builtinhelpers.PatchStrategicMergeTransformer,
builtinhelpers.PatchTransformer,
builtinhelpers.NamespaceTransformer,
builtinhelpers.PrefixSuffixTransformer,
builtinhelpers.LabelTransformer,
builtinhelpers.AnnotationsTransformer,
builtinhelpers.PatchJson6902Transformer,
builtinhelpers.ReplicaCountTransformer,
builtinhelpers.ImageTagTransformer,
} {
r, err := transformerConfigurators[bpt](
kt, bpt, builtinhelpers.TransformerFactories[bpt], tc)
if err != nil {
return nil, err
}
result = append(result, r...)
}
return result, nil
}
type gFactory func() resmap.GeneratorPlugin
var generatorConfigurators = map[builtinhelpers.BuiltinPluginType]func(
kt *KustTarget,
bpt builtinhelpers.BuiltinPluginType,
factory gFactory) (result []resmap.Generator, err error){
builtinhelpers.SecretGenerator: func(kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f gFactory) (
result []resmap.Generator, err error) {
var c struct {
types.GeneratorOptions
types.SecretArgs
}
if kt.kustomization.GeneratorOptions != nil {
c.GeneratorOptions = *kt.kustomization.GeneratorOptions
}
for _, args := range kt.kustomization.SecretGenerator {
c.SecretArgs = args
p := f()
err := kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
}
return
},
builtinhelpers.ConfigMapGenerator: func(kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f gFactory) (
result []resmap.Generator, err error) {
var c struct {
types.GeneratorOptions
types.ConfigMapArgs
}
if kt.kustomization.GeneratorOptions != nil {
c.GeneratorOptions = *kt.kustomization.GeneratorOptions
}
for _, args := range kt.kustomization.ConfigMapGenerator {
c.ConfigMapArgs = args
p := f()
err := kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
}
return
},
}
type tFactory func() resmap.TransformerPlugin
var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func(
kt *KustTarget,
bpt builtinhelpers.BuiltinPluginType,
f tFactory,
tc *builtinconfig.TransformerConfig) (result []resmap.Transformer, err error){
builtinhelpers.NamespaceTransformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
var c struct {
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
FieldSpecs []types.FieldSpec
}
c.Namespace = kt.kustomization.Namespace
c.FieldSpecs = tc.NameSpace
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
return
},
builtinhelpers.PatchJson6902Transformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, _ *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
var c 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"`
}
for _, args := range kt.kustomization.PatchesJson6902 {
c.Target = *args.Target
c.Path = args.Path
c.JsonOp = args.Patch
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
}
return
},
builtinhelpers.PatchStrategicMergeTransformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, _ *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
if len(kt.kustomization.PatchesStrategicMerge) == 0 {
return
}
var c struct {
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
Patches string `json:"patches,omitempty" yaml:"patches,omitempty"`
}
c.Paths = kt.kustomization.PatchesStrategicMerge
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
return
},
builtinhelpers.PatchTransformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, _ *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
if len(kt.kustomization.Patches) == 0 {
return
}
var c 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"`
}
for _, pc := range kt.kustomization.Patches {
c.Target = pc.Target
c.Patch = pc.Patch
c.Path = pc.Path
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
}
return
},
builtinhelpers.LabelTransformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
var c struct {
Labels map[string]string
FieldSpecs []types.FieldSpec
}
c.Labels = kt.kustomization.CommonLabels
c.FieldSpecs = tc.CommonLabels
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
return
},
builtinhelpers.AnnotationsTransformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
var c struct {
Annotations map[string]string
FieldSpecs []types.FieldSpec
}
c.Annotations = kt.kustomization.CommonAnnotations
c.FieldSpecs = tc.CommonAnnotations
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
return
},
builtinhelpers.PrefixSuffixTransformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
var c struct {
Prefix string
Suffix string
FieldSpecs []types.FieldSpec
}
c.Prefix = kt.kustomization.NamePrefix
c.Suffix = kt.kustomization.NameSuffix
c.FieldSpecs = tc.NamePrefix
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
return
},
builtinhelpers.ImageTagTransformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
var c struct {
ImageTag types.Image
FieldSpecs []types.FieldSpec
}
for _, args := range kt.kustomization.Images {
c.ImageTag = args
c.FieldSpecs = tc.Images
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
}
return
},
builtinhelpers.ReplicaCountTransformer: func(
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
var c struct {
Replica types.Replica
FieldSpecs []types.FieldSpec
}
for _, args := range kt.kustomization.Replicas {
c.Replica = args
c.FieldSpecs = tc.Replicas
p := f()
err = kt.configureBuiltinPlugin(p, c, bpt)
if err != nil {
return nil, err
}
result = append(result, p)
}
return
},
}

View File

@@ -0,0 +1,446 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target_test
import (
"encoding/base64"
"fmt"
"strings"
"testing"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/internal/loadertest"
. "sigs.k8s.io/kustomize/api/internal/target"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
"sigs.k8s.io/kustomize/api/types"
)
const (
kustomizationContent = `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: foo-
nameSuffix: -bar
namespace: ns1
commonLabels:
app: nginx
commonAnnotations:
note: This is a test annotation
resources:
- deployment.yaml
- namespace.yaml
generatorOptions:
disableNameSuffixHash: false
configMapGenerator:
- name: literalConfigMap
literals:
- DB_USERNAME=admin
- DB_PASSWORD=somepw
secretGenerator:
- name: secret
literals:
- DB_USERNAME=admin
- DB_PASSWORD=somepw
type: Opaque
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: dply1
path: jsonpatch.json
`
deploymentContent = `
apiVersion: apps/v1
metadata:
name: dply1
kind: Deployment
`
namespaceContent = `
apiVersion: v1
kind: Namespace
metadata:
name: ns1
`
jsonpatchContent = `[
{"op": "add", "path": "/spec/replica", "value": "3"}
]`
)
func TestResources(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/whatever")
th.WriteK("/whatever/", kustomizationContent)
th.WriteF("/whatever/deployment.yaml", deploymentContent)
th.WriteF("/whatever/namespace.yaml", namespaceContent)
th.WriteF("/whatever/jsonpatch.json", jsonpatchContent)
resources := []*resource.Resource{
th.RF().FromMapWithName("dply1", map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "foo-dply1-bar",
"namespace": "ns1",
"labels": map[string]interface{}{
"app": "nginx",
},
"annotations": map[string]interface{}{
"note": "This is a test annotation",
},
},
"spec": map[string]interface{}{
"replica": "3",
"selector": map[string]interface{}{
"matchLabels": map[string]interface{}{
"app": "nginx",
},
},
"template": map[string]interface{}{
"metadata": map[string]interface{}{
"annotations": map[string]interface{}{
"note": "This is a test annotation",
},
"labels": map[string]interface{}{
"app": "nginx",
},
},
},
},
}),
th.RF().FromMapWithName("ns1", map[string]interface{}{
"apiVersion": "v1",
"kind": "Namespace",
"metadata": map[string]interface{}{
"name": "foo-ns1-bar",
"labels": map[string]interface{}{
"app": "nginx",
},
"annotations": map[string]interface{}{
"note": "This is a test annotation",
},
},
}),
th.RF().FromMapWithName("literalConfigMap",
map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "foo-literalConfigMap-bar-8d2dkb8k24",
"namespace": "ns1",
"labels": map[string]interface{}{
"app": "nginx",
},
"annotations": map[string]interface{}{
"note": "This is a test annotation",
},
},
"data": map[string]interface{}{
"DB_USERNAME": "admin",
"DB_PASSWORD": "somepw",
},
}),
th.RF().FromMapWithName("secret",
map[string]interface{}{
"apiVersion": "v1",
"kind": "Secret",
"metadata": map[string]interface{}{
"name": "foo-secret-bar-9btc7bt4kb",
"namespace": "ns1",
"labels": map[string]interface{}{
"app": "nginx",
},
"annotations": map[string]interface{}{
"note": "This is a test annotation",
},
},
"type": ifc.SecretTypeOpaque,
"data": map[string]interface{}{
"DB_USERNAME": base64.StdEncoding.EncodeToString([]byte("admin")),
"DB_PASSWORD": base64.StdEncoding.EncodeToString([]byte("somepw")),
},
}),
}
expected := resmap.New()
for _, r := range resources {
if err := expected.Append(r); err != nil {
t.Fatalf("unexpected error %v", err)
}
}
actual, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("unexpected Resources error %v", err)
}
if err = expected.ErrorIfNotEqualLists(actual); err != nil {
t.Fatalf("unexpected inequality: %v", err)
}
}
func TestKustomizationNotFound(t *testing.T) {
_, err := NewKustTarget(
loadertest.NewFakeLoader("/foo"),
valtest_test.MakeFakeValidator(), nil, nil, nil)
if err == nil {
t.Fatalf("expected an error")
}
if err.Error() !=
`unable to find one of 'kustomization.yaml', 'kustomization.yml' or 'Kustomization' in directory '/foo'` {
t.Fatalf("unexpected error: %q", err)
}
}
func TestResourceNotFound(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/whatever")
th.WriteK("/whatever", kustomizationContent)
_, err := th.MakeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("Didn't get the expected error for an unknown resource")
}
if !strings.Contains(err.Error(), `cannot read file`) {
t.Fatalf("unexpected error: %q", err)
}
}
func findSecret(m resmap.ResMap) *resource.Resource {
for _, r := range m.Resources() {
if r.OrgId().Kind == "Secret" {
return r
}
}
return nil
}
func TestDisableNameSuffixHash(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/whatever")
th.WriteK("/whatever/", kustomizationContent)
th.WriteF("/whatever/deployment.yaml", deploymentContent)
th.WriteF("/whatever/namespace.yaml", namespaceContent)
th.WriteF("/whatever/jsonpatch.json", jsonpatchContent)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("unexpected Resources error %v", err)
}
secret := findSecret(m)
if secret == nil {
t.Errorf("Expected to find a Secret")
}
if secret.GetName() != "foo-secret-bar-9btc7bt4kb" {
t.Errorf("unexpected secret resource name: %s", secret.GetName())
}
th.WriteK("/whatever/",
strings.Replace(kustomizationContent,
"disableNameSuffixHash: false",
"disableNameSuffixHash: true", -1))
m, err = th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("unexpected Resources error %v", err)
}
secret = findSecret(m)
if secret == nil {
t.Errorf("Expected to find a Secret")
}
if secret.GetName() != "foo-secret-bar" { // No hash at end.
t.Errorf("unexpected secret resource name: %s", secret.GetName())
}
}
func TestIssue596AllowDirectoriesThatAreSubstringsOfEachOther(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/overlays/aws-sandbox2.us-east-1")
th.WriteK("/app/base", "")
th.WriteK("/app/overlays/aws", `
resources:
- ../../base
`)
th.WriteK("/app/overlays/aws-nonprod", `
resources:
- ../aws
`)
th.WriteK("/app/overlays/aws-sandbox2.us-east-1", `
resources:
- ../aws-nonprod
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, "")
}
// To simplify tests, these vars specified in alphabetical order.
var someVars = []types.Var{
{
Name: "AWARD",
ObjRef: types.Target{
APIVersion: "v7",
Gvk: resid.Gvk{Kind: "Service"},
Name: "nobelPrize"},
FieldRef: types.FieldSelector{FieldPath: "some.arbitrary.path"},
},
{
Name: "BIRD",
ObjRef: types.Target{
APIVersion: "v300",
Gvk: resid.Gvk{Kind: "Service"},
Name: "heron"},
FieldRef: types.FieldSelector{FieldPath: "metadata.name"},
},
{
Name: "FRUIT",
ObjRef: types.Target{
Gvk: resid.Gvk{Kind: "Service"},
Name: "apple"},
FieldRef: types.FieldSelector{FieldPath: "metadata.name"},
},
{
Name: "VEGETABLE",
ObjRef: types.Target{
Gvk: resid.Gvk{Kind: "Leafy"},
Name: "kale"},
FieldRef: types.FieldSelector{FieldPath: "metadata.name"},
},
}
func TestGetAllVarsSimple(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app")
th.WriteK("/app", `
vars:
- name: AWARD
objref:
kind: Service
name: nobelPrize
apiVersion: v7
fieldref:
fieldpath: some.arbitrary.path
- name: BIRD
objref:
kind: Service
name: heron
apiVersion: v300
`)
ra, err := th.MakeKustTarget().AccumulateTarget()
if err != nil {
t.Fatalf("Err: %v", err)
}
vars := ra.Vars()
if len(vars) != 2 {
t.Fatalf("unexpected size %d", len(vars))
}
for i := range vars[:2] {
// By using Var.DeepEqual, we are protecting the code
// from a potential invocation of vars[i].ObjRef.GVK()
// during AccumulateTarget
if !vars[i].DeepEqual(someVars[i]) {
t.Fatalf("unexpected var[%d]:\n %v\n %v", i, vars[i], someVars[i])
}
}
}
func TestGetAllVarsNested(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/overlays/o2")
th.WriteK("/app/base", `
vars:
- name: AWARD
objref:
kind: Service
name: nobelPrize
apiVersion: v7
fieldref:
fieldpath: some.arbitrary.path
- name: BIRD
objref:
kind: Service
name: heron
apiVersion: v300
`)
th.WriteK("/app/overlays/o1", `
vars:
- name: FRUIT
objref:
kind: Service
name: apple
resources:
- ../../base
`)
th.WriteK("/app/overlays/o2", `
vars:
- name: VEGETABLE
objref:
kind: Leafy
name: kale
resources:
- ../o1
`)
ra, err := th.MakeKustTarget().AccumulateTarget()
if err != nil {
t.Fatalf("Err: %v", err)
}
vars := ra.Vars()
if len(vars) != 4 {
for i, v := range vars {
fmt.Printf("%v: %v\n", i, v)
}
t.Fatalf("expected 4 vars, got %d", len(vars))
}
for i := range vars {
// By using Var.DeepEqual, we are protecting the code
// from a potential invocation of vars[i].ObjRef.GVK()
// during AccumulateTarget
if !vars[i].DeepEqual(someVars[i]) {
t.Fatalf("unexpected var[%d]:\n %v\n %v", i, vars[i], someVars[i])
}
}
}
func TestVarCollisionsForbidden(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/overlays/o2")
th.WriteK("/app/base", `
vars:
- name: AWARD
objref:
kind: Service
name: nobelPrize
apiVersion: v7
fieldref:
fieldpath: some.arbitrary.path
- name: BIRD
objref:
kind: Service
name: heron
apiVersion: v300
`)
th.WriteK("/app/overlays/o1", `
vars:
- name: AWARD
objref:
kind: Service
name: academy
resources:
- ../../base
`)
th.WriteK("/app/overlays/o2", `
vars:
- name: VEGETABLE
objref:
kind: Leafy
name: kale
resources:
- ../o1
`)
_, err := th.MakeKustTarget().AccumulateTarget()
if err == nil {
t.Fatalf("expected var collision")
}
if !strings.Contains(err.Error(),
"var 'AWARD' already encountered") {
t.Fatalf("unexpected error: %v", err)
}
}

View File

@@ -0,0 +1,477 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package target_test
import (
"strings"
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func makeCommonFileForMultiplePatchTest(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/base", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: team-foo-
commonLabels:
app: mynginx
org: example.com
team: foo
commonAnnotations:
note: This is a test annotation
resources:
- deployment.yaml
- service.yaml
configMapGenerator:
- name: configmap-in-base
literals:
- foo=bar
`)
th.WriteF("/app/base/deployment.yaml", `
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: nginx-persistent-storage
mountPath: /tmp/ps
- name: sidecar
image: sidecar:latest
volumes:
- name: nginx-persistent-storage
emptyDir: {}
- configMap:
name: configmap-in-base
name: configmap-in-base
`)
th.WriteF("/app/base/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
selector:
app: nginx
`)
th.WriteK("/app/overlay/staging", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: staging-
commonLabels:
env: staging
patchesStrategicMerge:
- deployment-patch1.yaml
- deployment-patch2.yaml
resources:
- ../../base
configMapGenerator:
- name: configmap-in-overlay
literals:
- hello=world
`)
}
func TestMultiplePatchesNoConflict(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/overlay/staging")
makeCommonFileForMultiplePatchTest(th)
th.WriteF("/app/overlay/staging/deployment-patch1.yaml", `
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
image: nginx:latest
env:
- name: ENVKEY
value: ENVVALUE
volumes:
- name: nginx-persistent-storage
emptyDir: null
gcePersistentDisk:
pdName: nginx-persistent-storage
- configMap:
name: configmap-in-overlay
name: configmap-in-overlay
`)
th.WriteF("/app/overlay/staging/deployment-patch2.yaml", `
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
env:
- name: ANOTHERENV
value: FOO
volumes:
- name: nginx-persistent-storage
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1beta2
kind: Deployment
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-nginx
spec:
selector:
matchLabels:
app: mynginx
env: staging
org: example.com
team: foo
template:
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
spec:
containers:
- env:
- name: ANOTHERENV
value: FOO
- name: ENVKEY
value: ENVVALUE
image: nginx:latest
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: nginx-persistent-storage
- image: sidecar:latest
name: sidecar
volumes:
- gcePersistentDisk:
pdName: nginx-persistent-storage
name: nginx-persistent-storage
- configMap:
name: staging-configmap-in-overlay-k7cbc75tg8
name: configmap-in-overlay
- configMap:
name: staging-team-foo-configmap-in-base-g7k6gt2889
name: configmap-in-base
---
apiVersion: v1
kind: Service
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-nginx
spec:
ports:
- port: 80
selector:
app: mynginx
env: staging
org: example.com
team: foo
---
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-configmap-in-base-g7k6gt2889
---
apiVersion: v1
data:
hello: world
kind: ConfigMap
metadata:
labels:
env: staging
name: staging-configmap-in-overlay-k7cbc75tg8
`)
}
func TestMultiplePatchesWithConflict(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/overlay/staging")
makeCommonFileForMultiplePatchTest(th)
th.WriteF("/app/overlay/staging/deployment-patch1.yaml", `
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
env:
- name: ENABLE_FEATURE_FOO
value: TRUE
volumes:
- name: nginx-persistent-storage
emptyDir: null
gcePersistentDisk:
pdName: nginx-persistent-storage
- configMap:
name: configmap-in-overlay
name: configmap-in-overlay
`)
th.WriteF("/app/overlay/staging/deployment-patch2.yaml", `
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
env:
- name: ENABLE_FEATURE_FOO
value: FALSE
`)
_, err := th.MakeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("expected conflict")
}
if !strings.Contains(
err.Error(), "conflict between ") {
t.Fatalf("Unexpected err: %v", err)
}
}
func TestMultiplePatchesWithOnePatchDeleteDirective(t *testing.T) {
additivePatch := `apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
env:
- name: SOME_NAME
value: somevalue
`
deletePatch := `apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- $patch: delete
name: sidecar
`
cases := []struct {
name string
patch1 string
patch2 string
expectError bool
}{
{
name: "Patch with delete directive first",
patch1: deletePatch,
patch2: additivePatch,
},
{
name: "Patch with delete directive second",
patch1: additivePatch,
patch2: deletePatch,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/overlay/staging")
makeCommonFileForMultiplePatchTest(th)
th.WriteF("/app/overlay/staging/deployment-patch1.yaml", c.patch1)
th.WriteF("/app/overlay/staging/deployment-patch2.yaml", c.patch2)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `apiVersion: apps/v1beta2
kind: Deployment
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-nginx
spec:
selector:
matchLabels:
app: mynginx
env: staging
org: example.com
team: foo
template:
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
spec:
containers:
- env:
- name: SOME_NAME
value: somevalue
image: nginx
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: nginx-persistent-storage
volumes:
- emptyDir: {}
name: nginx-persistent-storage
- configMap:
name: staging-team-foo-configmap-in-base-g7k6gt2889
name: configmap-in-base
---
apiVersion: v1
kind: Service
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-nginx
spec:
ports:
- port: 80
selector:
app: mynginx
env: staging
org: example.com
team: foo
---
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-configmap-in-base-g7k6gt2889
---
apiVersion: v1
data:
hello: world
kind: ConfigMap
metadata:
labels:
env: staging
name: staging-configmap-in-overlay-k7cbc75tg8
`)
})
}
}
func TestMultiplePatchesBothWithPatchDeleteDirective(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/overlay/staging")
makeCommonFileForMultiplePatchTest(th)
th.WriteF("/app/overlay/staging/deployment-patch1.yaml", `
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- $patch: delete
name: sidecar
`)
th.WriteF("/app/overlay/staging/deployment-patch2.yaml", `
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- $patch: delete
name: nginx
`)
_, err := th.MakeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("Expected error")
}
if !strings.Contains(
err.Error(), "both containing ") {
t.Fatalf("Unexpected err: %v", err)
}
return
}

View File

@@ -0,0 +1,129 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package target_test
import (
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func TestNamespacedGenerator(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app")
th.WriteK("/app", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- name: the-non-default-namespace-map
namespace: non-default
literals:
- altGreeting=Good Morning from non-default namespace!
- enableRisky="false"
- name: the-map
literals:
- altGreeting=Good Morning from default namespace!
- enableRisky="false"
secretGenerator:
- name: the-non-default-namespace-secret
namespace: non-default
literals:
- password.txt=verySecret
- name: the-secret
literals:
- password.txt=anotherSecret
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
data:
altGreeting: Good Morning from non-default namespace!
enableRisky: "false"
kind: ConfigMap
metadata:
name: the-non-default-namespace-map-b6h49k7mt8
namespace: non-default
---
apiVersion: v1
data:
altGreeting: Good Morning from default namespace!
enableRisky: "false"
kind: ConfigMap
metadata:
name: the-map-4959m5tm6c
---
apiVersion: v1
data:
password.txt: dmVyeVNlY3JldA==
kind: Secret
metadata:
name: the-non-default-namespace-secret-h8d9hkgtb9
namespace: non-default
type: Opaque
---
apiVersion: v1
data:
password.txt: YW5vdGhlclNlY3JldA==
kind: Secret
metadata:
name: the-secret-fgb45h45bh
type: Opaque
`)
}
func TestNamespacedGeneratorWithOverlays(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/overlay")
th.WriteK("/app/base", `
namespace: base
configMapGenerator:
- name: testCase
literals:
- base=true
`)
th.WriteK("/app/overlay", `
resources:
- ../base
namespace: overlay
configMapGenerator:
- name: testCase
behavior: merge
literals:
- overlay=true
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
data:
base: "true"
overlay: "true"
kind: ConfigMap
metadata:
annotations: {}
labels: {}
name: testCase-4g75kbk6gm
namespace: overlay
`)
}

View File

@@ -0,0 +1,602 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package target_test
import (
"strings"
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func TestNamespacedSecrets(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app")
th.WriteF("/app/secrets.yaml", `
apiVersion: v1
kind: Secret
metadata:
name: dummy
namespace: default
type: Opaque
data:
dummy: ""
---
apiVersion: v1
kind: Secret
metadata:
name: dummy
namespace: kube-system
type: Opaque
data:
dummy: ""
`)
// This should find the proper secret.
th.WriteF("/app/role.yaml", `
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: dummy
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["dummy"]
verbs: ["get"]
`)
th.WriteK("/app", `
resources:
- secrets.yaml
- role.yaml
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
// This validates Fix #1444. This should not be an error anymore -
// the secrets have the same name but are in different namespaces.
// The ClusterRole (by def) is not in a namespace,
// an in this case applies to *any* Secret resource
// named "dummy"
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
data:
dummy: ""
kind: Secret
metadata:
name: dummy
namespace: default
type: Opaque
---
apiVersion: v1
data:
dummy: ""
kind: Secret
metadata:
name: dummy
namespace: kube-system
type: Opaque
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: dummy
rules:
- apiGroups:
- ""
resourceNames:
- dummy
resources:
- secrets
verbs:
- get
`)
}
// TestNameAndNsTransformation validates that NamespaceTransformer,
// PrefixSuffixTransformer and namereference transformers are
// able to deal with simultaneous change of namespace and name.
func TestNameAndNsTransformation(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/nameandns")
th.WriteK("/nameandns", `
namePrefix: p1-
nameSuffix: -s1
namespace: newnamespace
resources:
- resources.yaml
`)
th.WriteF("/nameandns/resources.yaml", `
apiVersion: v1
kind: ConfigMap
metadata:
name: cm1
---
apiVersion: v1
kind: ConfigMap
metadata:
name: cm2
namespace: ns1
---
apiVersion: v1
kind: Service
metadata:
name: svc1
namespace: ns1
---
apiVersion: v1
kind: Service
metadata:
name: svc2
namespace: ns1
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: sa1
namespace: ns1
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: sa2
namespace: ns1
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: manager-rolebinding
subjects:
- kind: ServiceAccount
name: sa1
namespace: ns1
- kind: ServiceAccount
name: sa2
namespace: ns1
- kind: ServiceAccount
name: sa3
namespace: random
- kind: ServiceAccount
name: default
namespace: irrelevant
---
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
name: example
webhooks:
- name: example1
clientConfig:
service:
name: svc1
namespace: ns1
- name: example2
clientConfig:
service:
name: svc2
namespace: ns1
- name: example3
clientConfig:
service:
name: svc3
namespace: random
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: crds.my.org
---
kind: ClusterRole
metadata:
name: cr1
---
kind: ClusterRoleBinding
metadata:
name: crb1
subjects:
- kind: ServiceAccount
name: default
namespace: irrelevant
---
kind: PersistentVolume
metadata:
name: pv1
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: ConfigMap
metadata:
name: p1-cm1-s1
namespace: newnamespace
---
apiVersion: v1
kind: ConfigMap
metadata:
name: p1-cm2-s1
namespace: newnamespace
---
apiVersion: v1
kind: Service
metadata:
name: p1-svc1-s1
namespace: newnamespace
---
apiVersion: v1
kind: Service
metadata:
name: p1-svc2-s1
namespace: newnamespace
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: p1-sa1-s1
namespace: newnamespace
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: p1-sa2-s1
namespace: newnamespace
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: p1-manager-rolebinding-s1
subjects:
- kind: ServiceAccount
name: p1-sa1-s1
namespace: newnamespace
- kind: ServiceAccount
name: p1-sa2-s1
namespace: newnamespace
- kind: ServiceAccount
name: sa3
namespace: random
- kind: ServiceAccount
name: default
namespace: newnamespace
---
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
name: p1-example-s1
webhooks:
- clientConfig:
service:
name: p1-svc1-s1
namespace: newnamespace
name: example1
- clientConfig:
service:
name: p1-svc2-s1
namespace: newnamespace
name: example2
- clientConfig:
service:
name: svc3
namespace: random
name: example3
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: crds.my.org
---
kind: ClusterRole
metadata:
name: p1-cr1-s1
---
kind: ClusterRoleBinding
metadata:
name: p1-crb1-s1
subjects:
- kind: ServiceAccount
name: default
namespace: newnamespace
---
kind: PersistentVolume
metadata:
name: p1-pv1-s1
`)
}
// This serie of constants is used to prove the need of
// the namespace field in the objref field of the var declaration.
// The following tests demonstrate that it creates umbiguous variable
// declaration if two entities of the kind with the same name
// but in different namespaces are declared.
// This is tracking the following issue:
// https://github.com/kubernetes-sigs/kustomize/issues/1298
const namespaceNeedInVarMyApp string = `
resources:
- elasticsearch-dev-service.yaml
- elasticsearch-test-service.yaml
vars:
- name: elasticsearch-test-service-name
objref:
kind: Service
name: elasticsearch
apiVersion: v1
fieldref:
fieldpath: metadata.name
- name: elasticsearch-test-protocol
objref:
kind: Service
name: elasticsearch
apiVersion: v1
fieldref:
fieldpath: spec.ports[0].protocol
- name: elasticsearch-dev-service-name
objref:
kind: Service
name: elasticsearch
apiVersion: v1
fieldref:
fieldpath: metadata.name
- name: elasticsearch-dev-protocol
objref:
kind: Service
name: elasticsearch
apiVersion: v1
fieldref:
fieldpath: spec.ports[0].protocol
`
const namespaceNeedInVarDevResources string = `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elasticsearch
namespace: dev
spec:
template:
spec:
containers:
- name: elasticsearch
env:
- name: DISCOVERY_SERVICE
value: "$(elasticsearch-dev-service-name).monitoring.svc.cluster.local"
- name: DISCOVERY_PROTOCOL
value: "$(elasticsearch-dev-protocol)"
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
namespace: dev
spec:
ports:
- name: transport
port: 9300
protocol: TCP
clusterIP: None
`
const namespaceNeedInVarTestResources string = `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elasticsearch
namespace: test
spec:
template:
spec:
containers:
- name: elasticsearch
env:
- name: DISCOVERY_SERVICE
value: "$(elasticsearch-test-service-name).monitoring.svc.cluster.local"
- name: DISCOVERY_PROTOCOL
value: "$(elasticsearch-test-protocol)"
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
namespace: test
spec:
ports:
- name: transport
port: 9300
protocol: UDP
clusterIP: None
`
const namespaceNeedInVarExpectedOutput string = `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elasticsearch
namespace: dev
spec:
template:
spec:
containers:
- env:
- name: DISCOVERY_SERVICE
value: elasticsearch.monitoring.svc.cluster.local
- name: DISCOVERY_PROTOCOL
value: TCP
name: elasticsearch
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
namespace: dev
spec:
clusterIP: None
ports:
- name: transport
port: 9300
protocol: TCP
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elasticsearch
namespace: test
spec:
template:
spec:
containers:
- env:
- name: DISCOVERY_SERVICE
value: elasticsearch.monitoring.svc.cluster.local
- name: DISCOVERY_PROTOCOL
value: UDP
name: elasticsearch
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
namespace: test
spec:
clusterIP: None
ports:
- name: transport
port: 9300
protocol: UDP
`
// TestVariablesAmbiguous demonstrates how two variables pointing at two different resources
// using the same name in different namespaces are treated as ambiguous if the namespace is
// not specified
func TestVariablesAmbiguous(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/namespaceNeedInVar/myapp")
th.WriteK("/namespaceNeedInVar/myapp", namespaceNeedInVarMyApp)
th.WriteF("/namespaceNeedInVar/myapp/elasticsearch-dev-service.yaml", namespaceNeedInVarDevResources)
th.WriteF("/namespaceNeedInVar/myapp/elasticsearch-test-service.yaml", namespaceNeedInVarTestResources)
_, err := th.MakeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("expected error")
}
if !strings.Contains(err.Error(), "unable to disambiguate") {
t.Fatalf("unexpected error %v", err)
}
}
const namespaceNeedInVarDevFolder string = `
resources:
- elasticsearch-dev-service.yaml
vars:
- name: elasticsearch-dev-service-name
objref:
kind: Service
name: elasticsearch
apiVersion: v1
fieldref:
fieldpath: metadata.name
- name: elasticsearch-dev-protocol
objref:
kind: Service
name: elasticsearch
apiVersion: v1
fieldref:
fieldpath: spec.ports[0].protocol
`
const namespaceNeedInVarTestFolder string = `
resources:
- elasticsearch-test-service.yaml
vars:
- name: elasticsearch-test-service-name
objref:
kind: Service
name: elasticsearch
apiVersion: v1
fieldref:
fieldpath: metadata.name
- name: elasticsearch-test-protocol
objref:
kind: Service
name: elasticsearch
apiVersion: v1
fieldref:
fieldpath: spec.ports[0].protocol
`
// TestVariablesAmbiguousWorkaround demonstrates a possible workaround
// to TestVariablesAmbiguous problem. It requires to separate the variables
// and resources into multiple kustomization context/folders instead of one.
func TestVariablesAmbiguousWorkaround(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/namespaceNeedInVar/workaround")
th.WriteK("/namespaceNeedInVar/dev", namespaceNeedInVarDevFolder)
th.WriteF("/namespaceNeedInVar/dev/elasticsearch-dev-service.yaml", namespaceNeedInVarDevResources)
th.WriteK("/namespaceNeedInVar/test", namespaceNeedInVarTestFolder)
th.WriteF("/namespaceNeedInVar/test/elasticsearch-test-service.yaml", namespaceNeedInVarTestResources)
th.WriteK("/namespaceNeedInVar/workaround", `
resources:
- ../dev
- ../test
`)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, namespaceNeedInVarExpectedOutput)
}
const namespaceNeedInVarMyAppWithNamespace string = `
resources:
- elasticsearch-dev-service.yaml
- elasticsearch-test-service.yaml
vars:
- name: elasticsearch-test-service-name
objref:
kind: Service
name: elasticsearch
namespace: test
apiVersion: v1
fieldref:
fieldpath: metadata.name
- name: elasticsearch-test-protocol
objref:
kind: Service
name: elasticsearch
namespace: test
apiVersion: v1
fieldref:
fieldpath: spec.ports[0].protocol
- name: elasticsearch-dev-service-name
objref:
kind: Service
name: elasticsearch
namespace: dev
apiVersion: v1
fieldref:
fieldpath: metadata.name
- name: elasticsearch-dev-protocol
objref:
kind: Service
name: elasticsearch
namespace: dev
apiVersion: v1
fieldref:
fieldpath: spec.ports[0].protocol
`
// TestVariablesDisambiguatedWithNamespace demonstrates that adding the namespace
// to the variable declarations allows to disambiguate the variables.
func TestVariablesDisambiguatedWithNamespace(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/namespaceNeedInVar/myapp")
th.WriteK("/namespaceNeedInVar/myapp", namespaceNeedInVarMyAppWithNamespace)
th.WriteF("/namespaceNeedInVar/myapp/elasticsearch-dev-service.yaml", namespaceNeedInVarDevResources)
th.WriteF("/namespaceNeedInVar/myapp/elasticsearch-test-service.yaml", namespaceNeedInVarTestResources)
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpected(m, namespaceNeedInVarExpectedOutput)
}

View File

@@ -18,11 +18,13 @@ package target_test
import (
"testing"
"sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func TestNullValues(t *testing.T) {
th := NewKustTestHarness(t, "/app")
th.writeF("/app/deployment.yaml", `
th := kusttest_test.NewKustTestHarness(t, "/app")
th.WriteF("/app/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -43,18 +45,18 @@ spec:
image: image
name: example
`)
th.writeF("/app/kustomization.yaml", `
th.WriteF("/app/kustomization.yaml", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
`)
m, err := th.makeKustTarget().MakeCustomizedResMap()
m, err := th.MakeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.assertActualEqualsExpected(m, `
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:

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