Compare commits

..

125 Commits

Author SHA1 Message Date
Kubernetes Prow Robot
326a57a9cc Merge pull request #4282 from KnVerey/pinToCmdConfig
Pin to cmd/config v0.10.2
2021-11-11 15:03:14 -08:00
Katrina Verey
9dfdebc6c7 Pin to cmd/config v0.10.2 2021-11-11 14:53:17 -08:00
Natasha Sarkar
b896e04c20 Merge pull request #4281 from KnVerey/pinToKyaml
Pin to kyaml v0.13.0
2021-11-11 14:39:53 -08:00
Katrina Verey
6ecae1ad50 Also pin patch and patchjson transformers 2021-11-11 14:30:39 -08:00
Katrina Verey
9abb72e4d6 Pin to kyaml v0.13.0 2021-11-11 14:12:13 -08:00
Kubernetes Prow Robot
6365b3d0cf Merge pull request #4280 from KnVerey/more_releases
Add s390x and ppc64le binaries to releases
2021-11-11 13:52:07 -08:00
Katrina Verey
33c2ea01c4 Add s390x and ppc64le binaries to releases 2021-11-11 13:37:50 -08:00
Kubernetes Prow Robot
863ff0ef1b Merge pull request #4262 from patricknelson/fix-windows-build
Fix windows build, add clarity to goreleaser build (due to race conditions).
2021-11-11 13:32:08 -08:00
Patrick Nelson
a5117083ec Step 2 of 2: Adding windows build back and added ability to reproduce goreleaser builds locally (localbuild.sh) in a way exactly consistent with Cloud Build (cloudbuild.sh) but as a *build* only, without being coupled to Cloud Build or it's dependencies (like Cloud KMS, GitHub, etc). 2021-11-11 12:17:42 -08:00
Patrick Nelson
a143688a1d Step 1 of 2: Renaming localbuild.sh to cloudbuild-local.sh (preserve commit history) to make way for new localbuild.sh which will actually be entirely local, since this script is still very specific to Cloud Build. 2021-11-10 19:03:22 -08:00
Kubernetes Prow Robot
0676d0bd11 Merge pull request #4266 from Serializator/issue-4111-patchJson6902
Fix name suffix not being applied when "patchesJson6902" is used
2021-11-10 15:13:50 -08:00
Julian van den Berkmortel
b6cb6c8ae9 fix build annotations getting lost after applying JSON 6902 patch 2021-11-10 23:02:42 +01:00
Julian van den Berkmortel
b16e4ec566 add test to demonstrate internal annotations getting lost (#4111) 2021-11-10 21:33:50 +01:00
Mohd Bilal
cb1cbbe044 Fixes 4108; remove hidden files in kustomize edit command to correctly mimic shell globbing behaviour (#4170)
* util and util_test corrected

* fixed behaviour of fsondisk with test updated

* glob behaviour fixed in fsnode

* removed commented code
2021-11-10 08:51:26 -08:00
Kubernetes Prow Robot
86fb408b2c Merge pull request #4276 from natasha41575/fixFunctionSpec
fix function spec example
2021-11-09 21:05:26 -08:00
natasha41575
ca5d691199 fix function spec example 2021-11-09 20:56:36 -08:00
Kubernetes Prow Robot
394567079d Merge pull request #4272 from mengqiy/pointer
Make ResourceList follow k8s api conventions
2021-11-09 15:41:26 -08:00
Kubernetes Prow Robot
e0c8ebc41f Merge pull request #4235 from Goodwine/kyaml-wrap-bug
Fix kyaml readwriter inconsistencies when wrapping resources
2021-11-09 12:37:48 -08:00
Kubernetes Prow Robot
8668691ade Merge pull request #4271 from natasha41575/ReplacementsEdit
Fix: replacements entries get source and targets with null value appended
2021-11-09 10:49:47 -08:00
Mengqi Yu
374d790a21 Make ResourceList follow k8s api conventions
Make optional fields as pointers.
Add omitempty for optional fields.
2021-11-08 21:35:49 -08:00
natasha41575
d8f406d06f add omitempty tag to replacement sources and targets 2021-11-08 12:33:30 -08:00
natasha41575
46b3cd2109 modify edit test for null replacements fields 2021-11-08 12:21:45 -08:00
Carlos Ortiz García
20c608989a Move kio.ByteRW tests from framework_test to byteio_readwriter_test 2021-11-08 11:55:02 -08:00
Carlos Ortiz García
ba4d83f75f only override wrapping kind if it wasn't set already 2021-11-08 11:29:57 -08:00
Carlos Ortiz García
067559127d test cases for framework wrapping/unwrapping bug 2021-11-08 10:13:00 -08:00
Kubernetes Prow Robot
37ab5579f0 Merge pull request #4229 from natasha41575/annotationAndLabelSelectionInReplacements
Annotation and label selection in replacement targets
2021-11-04 13:08:23 -07:00
natasha41575
ef5f1d347d support label and annotation selection in replacement targets 2021-11-04 12:25:15 -07:00
Kubernetes Prow Robot
2c4b195516 Merge pull request #4259 from MikaelSmith/fix-patch-example
docs: Update example for patching multiple objects
2021-11-01 16:01:54 -07:00
Kubernetes Prow Robot
04396ab4e6 Merge pull request #4203 from timofurrer/config-map-consistency
Add consistency to ConfigMap spelling
2021-11-01 15:47:54 -07:00
Kubernetes Prow Robot
4fd77b3a6e Merge pull request #4248 from natasha41575/resourceListResults
[breaking] update results field of ResourceList to implement function spec v1
2021-10-29 14:51:09 -07:00
natasha41575
3ea8b79925 update results field of ResourceList to implement function spec v1 2021-10-29 14:28:50 -07:00
Natasha Sarkar
71b978da1a Merge pull request #4253 from natasha41575/resourceListSDKHelpers
provide utility helpers for preserving internal annotations
2021-10-29 14:25:06 -07:00
Natasha Sarkar
7110298c52 Merge pull request #4249 from natasha41575/resourceListV1
bump ResourceList from v1alpha1 to v1
2021-10-29 14:24:10 -07:00
natasha41575
b4a69f08c0 provide utility helpers for preserving internal annotations 2021-10-29 12:30:55 -07:00
Michael Smith
572d5841c6 docs: Update example for patching multiple objects
Updates the example for patching multiple objects to match the
implementation in #1355, which supports name as a regular expression
(not wildcard pattern).
2021-10-26 12:28:42 -07:00
Kubernetes Prow Robot
984a2dab3d Merge pull request #4242 from natasha41575/configmapissue
fix issue with quotations being dropped in configmap generation
2021-10-24 18:54:22 -07:00
natasha41575
c3c02887ec bump ResourceList from v1alpha1 to v1 2021-10-19 16:15:27 -07:00
natasha41575
ba051c863b fix issue with quote being dropped in configmap generation 2021-10-14 18:30:28 -07:00
natasha41575
4d59146e48 test for dropped quote in configmap generation 2021-10-14 18:13:49 -07:00
Kubernetes Prow Robot
5765ab4dbc Merge pull request #4236 from Goodwine/docs-fn
Update documents from 'kustomize configuration' to 'kustomize fn'
2021-10-13 18:35:28 -07:00
Kubernetes Prow Robot
4769751943 Merge pull request #4160 from osherdp/fix/github-rate-limiter-output
Return a meaningful message if we hit the rate-limiter of GitHub
2021-10-13 18:23:28 -07:00
Kubernetes Prow Robot
e506ce021e Merge pull request #4230 from yutachaos/feature/update_unified_go_version
Update go version 1.16 for CI
2021-10-13 18:09:28 -07:00
Kubernetes Prow Robot
ed763991de Merge pull request #4227 from natasha41575/MigrateIndexPathIdAnnotations
fix bug with migrating kyaml reader path, index, and id annotations
2021-10-12 18:37:48 -07:00
natasha41575
55ac9ca88d fix bug with migrating annotations 2021-10-12 15:42:54 -07:00
Carlos Ortiz García
548f5ffca9 Update documents from 'configuration' to 'fn' 2021-10-11 12:35:22 -05:00
yutachaos
dd3377b1a0 Update CI go version 1.16
Signed-off-by: yutachaos <18604471+yutachaos@users.noreply.github.com>
2021-10-08 14:02:50 +09:00
natasha41575
605239a1e5 test to demonstrate broken annotation selection 2021-10-07 15:40:23 -07:00
Kubernetes Prow Robot
67c58ad4f4 Merge pull request #4210 from natasha41575/openapiFromComponent
fix issue with getting openapi schema from components
2021-10-04 19:27:49 -07:00
natasha41575
11e19a3d0f separate custom openapi test from the others 2021-10-04 18:48:54 -07:00
Kubernetes Prow Robot
6fffcb9203 Merge pull request #4202 from cedarkuo/update-helloworld-example-readme
Updated README to use 'resources' instead of 'bases' in overlays example.
2021-10-04 14:26:41 -07:00
Kubernetes Prow Robot
68790e00a9 Merge pull request #4216 from mengqiy/updatedockerfilegen
update the dockerfile gen command
2021-09-29 13:51:22 -07:00
Mengqi Yu
6cf06fac12 update the dockerfile gen command 2021-09-29 13:34:11 -07:00
natasha41575
0d8c107362 fix issue with openapi schema from components 2021-09-27 17:00:14 -07:00
natasha41575
f30e45c549 test to demonstrate issue with openapi from components (#4179) 2021-09-27 16:29:08 -07:00
Kubernetes Prow Robot
250ea13767 Merge pull request #4208 from KnVerey/release_instructions
Small improvements to release instructions
2021-09-27 11:41:45 -07:00
Katrina Verey
608128738d Small improvements to release instructions 2021-09-27 10:44:02 -07:00
Kubernetes Prow Robot
7153f33466 Merge pull request #4207 from KnVerey/updateProwExamplesTarget
Test examples against latest release
2021-09-27 10:11:36 -07:00
Kubernetes Prow Robot
274b12318d Merge pull request #4205 from natasha41575/releasing
add link to k8s-staging-kustomize project to releasing instructions
2021-09-27 10:01:37 -07:00
Katrina Verey
94c82f61a3 Test examples against latest release 2021-09-27 09:51:01 -07:00
Kubernetes Prow Robot
d260f50573 Merge pull request #4206 from KnVerey/unpinEverything
Back to development mode; unpin the modules
2021-09-27 09:47:37 -07:00
Katrina Verey
40c014a991 Back to development mode; unpin the modules 2021-09-27 09:37:38 -07:00
natasha41575
75c8aec29d add link to k8s-staging-kustomize project to releasing instructions 2021-09-27 09:35:40 -07:00
Kubernetes Prow Robot
fcb9c0065e Merge pull request #4200 from KnVerey/go1.17_build_tags
Add go 1.17 build tags, which go fmt auto-synchronizes
2021-09-27 09:27:36 -07:00
Katrina Verey
63ec6bdb3d Merge pull request #4199 from KnVerey/pinToApi
Pin to api v0.10.0
2021-09-27 09:13:36 -07:00
Kubernetes Prow Robot
25bfe6f306 Merge pull request #4204 from KnVerey/release_updates
Use keyring from kustomize GCP project with new token
2021-09-27 09:01:35 -07:00
Timo Furrer
635c4fd43b Merge branch 'master' into config-map-consistency 2021-09-27 09:16:42 +02:00
Timo Furrer
c455215f55 Add consistency to ConfigMap spelling 2021-09-27 09:11:56 +02:00
cedarkuo
8f56f51307 Updated README to use 'resources' instead of 'bases' in overlays example.
Kubernetes v1.21 upgrade kustomize-in-kubectl to v4.0.5. https://github.com/kubernetes/kubernetes/pull/98946
So I think this example could update back to use resources instead of bases?
2021-09-27 12:40:36 +08:00
Katrina Verey
70a8ed6ed3 Add go 1.17 build tags, which go fmt auto-synchronizes 2021-09-24 17:28:21 -07:00
Katrina Verey
febfaf16dc Use keyring from kustomize GCP project with new token 2021-09-24 20:24:10 -04:00
Katrina Verey
8268b17700 Pin to api v0.10.0 2021-09-24 16:58:20 -07:00
Kubernetes Prow Robot
0889995a61 Merge pull request #4198 from KnVerey/pinToCmdConfig
Pin to cmd/config v0.10.1
2021-09-24 16:34:21 -07:00
Katrina Verey
4e476ae574 Pin to cmd/config v0.10.1 2021-09-24 16:07:21 -07:00
Kubernetes Prow Robot
7efd7d23fe Merge pull request #4197 from KnVerey/pinToKyaml
Pin to kyaml v0.12.0
2021-09-24 14:07:50 -07:00
Katrina Verey
6fb944815b Pin to kyaml v0.12.0 2021-09-24 12:23:09 -07:00
Kubernetes Prow Robot
5e3432fbbe Merge pull request #4196 from natasha41575/test
fix tests for reader annotations
2021-09-24 08:31:24 -07:00
natasha41575
f0c6bd7773 fix tests for reader annotations 2021-09-24 08:20:44 -07:00
Jeff Regan
dd579c905d Merge pull request #4180 from yuwenma/fix-4124
[Fix 4124]  Skip local resource until all transformations have completed.
2021-09-24 08:05:19 -07:00
Jeff Regan
22b735885a Merge pull request #4190 from natasha41575/MigrateIndexPathIdAnnotations
Migrate index path id annotations
2021-09-24 08:00:15 -07:00
Kubernetes Prow Robot
b7c5058e37 Merge pull request #4177 from sylr/helm-v3.6
Upgrade Helm v3 to v3.6.3
2021-09-24 07:45:24 -07:00
Kubernetes Prow Robot
baff5f4359 Merge pull request #4187 from monopole/deanchorCall
Do YAML anchor expansion shortly after reading YAML.
2021-09-22 13:14:33 -07:00
monopole
dce4ea5846 Add AnchorsAweigh option to ByteReader to toggle YAML alias/anchor expansion 2021-09-22 12:44:08 -07:00
Kubernetes Prow Robot
c47fc48607 Merge pull request #4193 from phanimarupaka/AddressBareSeqNodeComments
Clean up bare sequence node wrapping
2021-09-20 15:46:23 -07:00
Phani Teja Marupaka
1d9b6cbe57 Clean up bare sequence node wrapping 2021-09-20 15:35:40 -07:00
Kubernetes Prow Robot
1cb93123fc Merge pull request #4189 from phanimarupaka/SkipNonKRMResources
Handle parsing of bare sequence yaml nodes
2021-09-20 11:40:24 -07:00
Kubernetes Prow Robot
c6cb42ec27 Merge pull request #4185 from KnVerey/standardize_owners_files
Use standard Kubernetes project roles for ownership
2021-09-20 10:44:10 -07:00
Natasha Sarkar
67a5f6d68f support krm spec v1 and legacy path, index, and id annotations 2021-09-17 17:10:10 -07:00
Phani Teja Marupaka
e997cc5486 Handle parsing of bare sequence yaml nodes 2021-09-17 14:19:27 -07:00
Kubernetes Prow Robot
53577a5190 Merge pull request #4176 from m-Bilal/fix-4123
Fixes 4123; Length check on originalFields of kustomizationFile to prevent panic
2021-09-16 13:15:27 -07:00
Kubernetes Prow Robot
c1ae234a64 Merge pull request #4163 from natasha41575/multipleGvksInOpenApi
support multiple gvks in custom openapi schema
2021-09-16 12:59:26 -07:00
Natasha Sarkar
02cb395ec2 support multiple gvks in custom openapi schema 2021-09-16 12:43:18 -07:00
Kubernetes Prow Robot
65e7529ca0 Merge pull request #4097 from natasha41575/deprecateFn
deprecate fn wrap, xargs, sink, source commands
2021-09-16 12:25:27 -07:00
Natasha Sarkar
f70743b267 deprecate some fn commands 2021-09-16 11:48:02 -07:00
Yuwen Ma
f4382738ab [fix 4124] Skip local resource until all transformations have completed.
Resources annotated as "local-config" are expected to be ignored. This skip local resource happens in "accumulateResources" which happens before any transformation operations.
However, the local resource may be needed in transformations.
Thus, this change removes the "drop local resource" logic from accumulateResources and removes these local resource after all transformation operations and var operations are done.

Note:
None of the existing ResMap functions can drop the resource slice easily: "Clear" will ruin the resource order, "AppendAll" only adds non-existing resource, "AbsorbAll" only add or modify but not delete.
Thus, we introduce a new func "Intersection" for resourceAccumulator that specificaly removes the resource by ID and keep the original order.
2021-09-16 11:15:05 -07:00
Yuwen Ma
a100dca303 [Fix 4124] Add unittest with the given example. 2021-09-16 11:14:07 -07:00
Jeff Regan
50414208d1 Merge pull request #4186 from monopole/cleanupTest
Clean up factor_test before adding DeAnchor call
2021-09-15 17:47:19 -07:00
monopole
e17a007719 Clean up factor_test before adding DeAnchor call 2021-09-15 17:26:50 -07:00
Katrina Verey
dd3c5f5c0a Use standard Kubernetes project roles for ownership 2021-09-15 16:04:58 -07:00
Sylvain Rabot
fb3f560e0c Upgrade Helm v3 to v3.6.3
Helm has started to build darwin/arm64 from v3.6.0.

Signed-off-by: Sylvain Rabot <sylvain@abstraction.fr>
2021-09-12 18:18:41 +02:00
m-Bilal
12c177a365 fixes 4123; added length check on originalFields of kustomizationFile to prevent panic when kustomization file began with a comment(or a blank line) followed by a document separator 2021-09-12 17:35:23 +05:30
John Howard
402f6ca72b Precompute IsNamespaceScoped to avoid expensive schema reads (#4152)
* Precompute IsNamespaceScoped to avoid expensive schema reads

See https://github.com/GoogleContainerTools/kpt/issues/2469

For the `gcr.io/kpt-fn/set-namespace:v0.1` function, over 50% of CPU
time is spent on IsNamespaceScoped. Instead of unmarshalling 100k lines
of JSON to determine this, instead just precompute it. We can ensure
this never is inaccurate as the test verifies the precomputed result is
up to date.

In real world kpt pipelines this cuts execution of set-namespace (and
similar functions, just an example of a trivial function) from 2.0s to
1.0s. Because these functions are run in long pipelines over many
resources, this adds up a lot.

* Add documentation
2021-09-09 10:08:11 -07:00
Kubernetes Prow Robot
2b8a39373e Merge pull request #4172 from phanimarupaka/CopyReferenceNodesBeforeComparing
Copy reference nodes before copying comments and syncing order
2021-09-08 11:29:56 -07:00
Phani Teja Marupaka
17f18604e4 Copy reference nodes before copying comments and syncing order 2021-09-07 16:58:06 -07:00
Kubernetes Prow Robot
99e404cb61 Merge pull request #4169 from invidian/fix-typo
api/krusty: fix typo fileystem -> filesystem
2021-09-07 11:41:17 -07:00
Kubernetes Prow Robot
d4e3b4f832 Merge pull request #4171 from justinsb/cache_orgid
Cache the OrgId for nameReferenceTransformer
2021-09-07 11:17:16 -07:00
Justin SB
6552b90657 Cache the OrgId for nameReferenceTransformer
Because this is in an inner loop and is fairly memory-allocation
expensive even on a single allocation, it comes up top-of-the-list in
memory allocation pprof profiles, for example with the coredns
ClusterAddon.

Add simple caching.
2021-09-07 14:06:38 -04:00
Mateusz Gozdek
bf57d698b1 api/krusty: fix typo fileystem -> filesystem
Part of https://github.com/kubernetes/kubernetes/pull/104747.

Signed-off-by: Mateusz Gozdek <mgozdekof@gmail.com>
2021-09-05 11:33:10 +02:00
Kubernetes Prow Robot
4d002af735 Merge pull request #4165 from natasha41575/nameRefAfterKindChange
update name references after kind change
2021-09-03 12:56:52 -07:00
Natasha Sarkar
2bfc7cc1b0 throw error instead of panic when replacements source.fieldPath doesn't exist (#4166)
* test for missing source.fieldPath in replacements

* throw error instead of panic when replacements source.fieldPath doesn't exist
2021-09-03 11:10:53 -07:00
Natasha Sarkar
0244f0919e update name references after kind change 2021-09-02 12:10:01 -07:00
Natasha Sarkar
f122fb12f3 Merge pull request #4158 from kubernetes-sigs/revert-4157-fix/github-rate-limiter-output
Revert "Return a meaningful message if we hit the rate-limiter of GitHub"
2021-08-31 13:29:11 -07:00
Osher De Paz
f7cd553044 return a meaningful message if we hit the rate-limiter of GitHub 2021-08-31 23:26:49 +03:00
Natasha Sarkar
7d0b7e2113 Revert "Return a meaningful message if we hit the rate-limiter of GitHub" 2021-08-31 13:13:36 -07:00
Kubernetes Prow Robot
c3a67cfdca Merge pull request #4157 from osherdp/fix/github-rate-limiter-output
Return a meaningful message if we hit the rate-limiter of GitHub
2021-08-31 12:42:22 -07:00
Osher De Paz
4315e982be return a meaningful message if we hit the rate-limiter of GitHub 2021-08-31 16:19:39 +03:00
Kubernetes Prow Robot
634464353f Merge pull request #4128 from KnVerey/mini_proposal_process
Introduce in-repo proposal process
2021-08-30 17:22:28 -07:00
Kubernetes Prow Robot
9c36004493 Merge pull request #4143 from KnVerey/release_updates
Release updates
2021-08-30 16:08:29 -07:00
Katrina Verey
1b1034442c Enable real release after dry run without manual cleanup 2021-08-30 15:09:40 -07:00
Katrina Verey
a89863c84c Update release instructions 2021-08-30 15:09:40 -07:00
Katrina Verey
f7340e0615 Proposal template feedback 2021-08-30 12:10:02 -07:00
Kubernetes Prow Robot
bf6b207cc9 Merge pull request #4141 from KnVerey/unpinEverything
Back to development mode; unpin the modules
2021-08-24 12:46:58 -07:00
Katrina Verey
f93b4877f7 Back to development mode; unpin the modules 2021-08-24 12:35:26 -07:00
Kubernetes Prow Robot
cd17338759 Merge pull request #4139 from KnVerey/pinToApi
Pin to api v0.9.0
2021-08-24 12:04:58 -07:00
Katrina Verey
c46867c3a7 Pin to api v0.9.0 2021-08-24 11:54:43 -07:00
Katrina Verey
3e7246690f Introduce in-repo proposal process 2021-08-19 17:00:20 -07:00
147 changed files with 4829 additions and 824 deletions

View File

@@ -16,7 +16,7 @@ jobs:
- name: Set up Go 1.x - name: Set up Go 1.x
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: ^1.13 go-version: ^1.16
id: go id: go
- name: Check out code into the Go module directory - name: Check out code into the Go module directory
@@ -35,7 +35,7 @@ jobs:
- name: Set up Go 1.x - name: Set up Go 1.x
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: ^1.13 go-version: ^1.16
id: go id: go
- name: Check out code into the Go module directory - name: Check out code into the Go module directory
@@ -63,7 +63,7 @@ jobs:
- name: Set up Go 1.x - name: Set up Go 1.x
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: ^1.13 go-version: ^1.16
id: go id: go
- name: Check out code into the Go module directory - name: Check out code into the Go module directory
@@ -91,7 +91,7 @@ jobs:
- name: Set up Go 1.x - name: Set up Go 1.x
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: ^1.13 go-version: ^1.16
id: go id: go
- name: Check out code into the Go module directory - name: Check out code into the Go module directory

View File

@@ -1,6 +1,25 @@
[SIG-CLI]: https://github.com/kubernetes/community/tree/master/sig-cli
[Slack channel]: https://kubernetes.slack.com/messages/kustomize
[Mailing list]: https://groups.google.com/forum/#!forum/kubernetes-sig-cli
[OWNERS file spec]: https://github.com/kubernetes/community/blob/master/contributors/guide/owners.md
[Kustomize OWNERS_ALIASES]: https://github.com/kubernetes-sigs/kustomize/blob/8049f7b1af52e8a7ec26faf6cf714f560d0043c5/OWNERS_ALIASES
[SIG-CLI Teams]: https://github.com/kubernetes/org/blob/main/config/kubernetes-sigs/sig-cli/teams.yaml
[Github permissions]: https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-permission-levels-for-an-organization#repository-access-for-each-permission-level
[Contributor License Agreement]: https://git.k8s.io/community/CLA.md
[Kubernetes Contributor Guide]: http://git.k8s.io/community/contributors/guide
[Contributor Cheat Sheet]: https://git.k8s.io/community/contributors/guide/contributor-cheatsheet/README.md
[CNCF Code of Conduct]: https://github.com/cncf/foundation/blob/master/code-of-conduct.md
[Kubernetes Community Membership]: https://github.com/kubernetes/community/blob/master/community-membership.md
[Contribution Guide]: https://kubectl.docs.kubernetes.io/contributing/kustomize/
[MacOS Dev Guide]: https://kubectl.docs.kubernetes.io/contributing/kustomize/mac/
[Windows Dev Guide]: https://kubectl.docs.kubernetes.io/contributing/kustomize/windows/
# Contributing Guidelines # Contributing Guidelines
Welcome to Kubernetes. We are excited about the prospect of you joining our [community](https://github.com/kubernetes/community)! The Kubernetes community abides by the CNCF [code of conduct](code-of-conduct.md). Here is an excerpt: Welcome to Kubernetes. We are excited about the prospect of you joining our [community](https://github.com/kubernetes/community)! The Kubernetes community abides by the [CNCF Code of Conduct]. Here is an excerpt:
_As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities._ _As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities._
@@ -8,13 +27,22 @@ _As contributors and maintainers of this project, and in the interest of fosteri
Dev guides: Dev guides:
- [Mac](docs/macDevGuide.md) - [Contribution Guide]
- [MacOS Dev Guide]
- [Windows Dev Guide]
We have full documentation on how to get started contributing here: General resources for contributors:
- [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 - [Contributor License Agreement] - Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests.
- [Kubernetes Contributor Guide](http://git.k8s.io/community/contributors/guide) - Main contributor documentation, or you can just jump directly to the [contributing section](http://git.k8s.io/community/contributors/guide#contributing) - [Kubernetes Contributor Guide] - Main contributor documentation.
- [Contributor Cheat Sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet/README.md) - Common resources for existing developers - [Contributor Cheat Sheet] - Common resources for existing developers.
Here are some additional ideas to help you get started with Kustomize:
- Attend a Kustomize Bug Scrub. Check the [SIG-CLI] meetings list to find the next one.
- Help triage issues by confirming validity and applying the appropriate `kind` label (e.g. comment `/kind bug`).
- Pick up an issue to fix. Issues with the `help-wanted` label are a good place to start, but you can also look for any issue with the `triage/accepted` label and no assignee. Remember to `/assign` yourself to let others know you're working on it.
- Help confirm new issues labelled `kind/bug` by reproducing them with the latest release.
- Support Kustomize users by responding to questions on issues labelled `kind/support` or in the [Slack channel].
## Mentorship ## Mentorship
@@ -22,19 +50,22 @@ We have full documentation on how to get started contributing here:
## Contributor Ladder ## Contributor Ladder
Kustomize generally follows the [Kubernetes Community Membership](https://github.com/kubernetes/community/blob/master/community-membership.md) contributor ladder. Roles are as follows: Kustomize follows the [Kubernetes Community Membership] contributor ladder. Roles are as follows:
1. Contributor: Anyone who actively contributes code, issues or reviews to the project. There are no Kustomize-specific requirements for this status. All contributors must [sign the CLA](https://github.com/kubernetes/community/tree/master/contributors/guide#prerequisites). 1. Contributor: Anyone who actively contributes code, issues or reviews to the project. All contributors must sign the [Contributor License Agreement].
1. Member/Reviewer: All Kubernetes-SIGs org members have LGTM rights on the Kustomize repo. There are no Kustomize-specific requirements. Kustomize does not currently have any formal reviewers, but the role will be created if there is interest. 1. Reviewer: Contributors with a history of review and authorship on Kustomize. Has LGTM rights on the Kustomize repo (as do all kubernetes-sigs org members). Active contributors are encouraged to join the reviewers list to be automatically pinged on PRs.
1. Maintainer/Approver: Highly experienced active reviewer and contributor to Kustomize. Has both LTGM and approval rights on the Kustomize repo, as well as [Github "maintain" rights](https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-permission-levels-for-an-organization#repository-access-for-each-permission-level). 1. Approver: Highly experienced active reviewer and contributor to Kustomize. Has both LTGM and approval rights on the Kustomize repo, as well as "maintain" [Github permissions].
1. Admin/Owner: Maintainer who sets technical direction and makes or approves design decisions for the project. Has LGTM and approval rights on the Kustomize repo as well as [Github "admin" rights](https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-permission-levels-for-an-organization#repository-access-for-each-permission-level). 1. Owner: Approver who sets technical direction and makes or approves design decisions for the project. Has LGTM and approval rights on the Kustomize repo as well as "admin" [Github permissions].
The kyaml module within the Kustomize repo has additional owners following the same ladder.
Administrative notes: Administrative notes:
- Maintainers and admins must be added to the appropriate list both [in the Kustomize repo](https://github.com/kubernetes-sigs/kustomize/blob/8049f7b1af52e8a7ec26faf6cf714f560d0043c5/OWNERS_ALIASES) and [in the community repo](https://github.com/kubernetes/org/blob/main/config/kubernetes-sigs/sig-cli/teams.yaml). If this isn't done, the individual in question will lack either PR approval rights (Kustomize list) or the appropriate Github repository permissions (community list).
- The spec for the OWNERS file is [in the community repo](https://github.com/kubernetes/community/blob/master/contributors/guide/owners.md). - The [OWNERS file spec] is a useful resources in making changes.
- Maintainers and admins must be added to the appropriate lists in both [Kustomize OWNERS_ALIASES] and [SIG-CLI Teams]. If this isn't done, the individual in question will lack either PR approval rights (Kustomize list) or the appropriate Github repository permissions (community list).
## Contact Information ## Contact Information
- [Slack channel](https://kubernetes.slack.com/messages/sig-cli) - [Slack channel]
- [Mailing list](https://groups.google.com/forum/#!forum/kubernetes-sig-cli) - [Mailing list]

View File

@@ -12,6 +12,7 @@ MYGOBIN = $(shell go env GOPATH)/bin
endif endif
export PATH := $(MYGOBIN):$(PATH) export PATH := $(MYGOBIN):$(PATH)
MODULES := '"cmd/config" "api/" "kustomize/" "kyaml/"' MODULES := '"cmd/config" "api/" "kustomize/" "kyaml/"'
LATEST_V4_RELEASE=v4.4.0
# Provide defaults for REPO_OWNER and REPO_NAME if not present. # Provide defaults for REPO_OWNER and REPO_NAME if not present.
# Typically these values would be provided by Prow. # Typically these values would be provided by Prow.
@@ -31,7 +32,7 @@ verify-kustomize: \
lint-kustomize \ lint-kustomize \
test-unit-kustomize-all \ test-unit-kustomize-all \
test-examples-kustomize-against-HEAD \ test-examples-kustomize-against-HEAD \
test-examples-kustomize-against-4.1 test-examples-kustomize-against-v4-release
# The following target referenced by a file in # The following target referenced by a file in
# https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/kustomize # https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/kustomize
@@ -44,7 +45,7 @@ prow-presubmit-check: \
test-unit-cmd-all \ test-unit-cmd-all \
test-go-mod \ test-go-mod \
test-examples-kustomize-against-HEAD \ test-examples-kustomize-against-HEAD \
test-examples-kustomize-against-4.1 test-examples-kustomize-against-v4-release
.PHONY: verify-kustomize-e2e .PHONY: verify-kustomize-e2e
verify-kustomize-e2e: test-examples-e2e-kustomize verify-kustomize-e2e: test-examples-e2e-kustomize
@@ -228,7 +229,8 @@ generate-kustomize-api: $(MYGOBIN)/k8scopy
.PHONY: test-unit-kustomize-api .PHONY: test-unit-kustomize-api
test-unit-kustomize-api: build-kustomize-api test-unit-kustomize-api: build-kustomize-api
cd api; go test ./... -ldflags "-X sigs.k8s.io/kustomize/api/provenance.version=v444.333.222" cd api; go test ./... -ldflags "-X sigs.k8s.io/kustomize/api/provenance.version=v444.333.222"; \
cd krusty; OPENAPI_TEST=true go test -run TestCustomOpenAPIFieldFromComponentWithOverlays
.PHONY: test-unit-kustomize-plugins .PHONY: test-unit-kustomize-plugins
test-unit-kustomize-plugins: test-unit-kustomize-plugins:
@@ -278,8 +280,8 @@ test-examples-kustomize-against-HEAD: $(MYGOBIN)/kustomize $(MYGOBIN)/mdrip
./hack/testExamplesAgainstKustomize.sh HEAD ./hack/testExamplesAgainstKustomize.sh HEAD
.PHONY: .PHONY:
test-examples-kustomize-against-4.1: $(MYGOBIN)/mdrip test-examples-kustomize-against-v4-release: $(MYGOBIN)/mdrip
./hack/testExamplesAgainstKustomize.sh v4@v4.1.2 ./hack/testExamplesAgainstKustomize.sh v4@$(LATEST_V4_RELEASE)
# linux only. # linux only.
# This is for testing an example plugin that # This is for testing an example plugin that
@@ -319,7 +321,7 @@ $(MYGOBIN)/helmV3:
( \ ( \
set -e; \ set -e; \
d=$(shell mktemp -d); cd $$d; \ d=$(shell mktemp -d); cd $$d; \
tgzFile=helm-v3.5.3-$(GOOS)-$(GOARCH).tar.gz; \ tgzFile=helm-v3.6.3-$(GOOS)-$(GOARCH).tar.gz; \
wget https://get.helm.sh/$$tgzFile; \ wget https://get.helm.sh/$$tgzFile; \
tar -xvzf $$tgzFile; \ tar -xvzf $$tgzFile; \
mv $(GOOS)-$(GOARCH)/helm $(MYGOBIN)/helmV3; \ mv $(GOOS)-$(GOARCH)/helm $(MYGOBIN)/helmV3; \

6
OWNERS
View File

@@ -1,4 +1,6 @@
# See https://github.com/kubernetes/community/blob/master/community-membership.md # See https://github.com/kubernetes/community/blob/master/community-membership.md
approvers: approvers:
- kustomize-admins - kustomize-approvers
- kustomize-maintainers
reviewers:
- kustomize-reviewers

View File

@@ -1,16 +1,30 @@
# Keep *-admins and *-maintainers list in sync with corresponding lists in # Keep *-owners and *-approvers lists in sync with *-admins and *-maintainers in
# https://github.com/kubernetes/org/blob/main/config/kubernetes-sigs/sig-cli/teams.yaml # https://github.com/kubernetes/org/blob/main/config/kubernetes-sigs/sig-cli/teams.yaml
aliases: aliases:
kustomize-admins: kustomize-owners:
- knverey - knverey
- monopole - monopole
- pwittrock - pwittrock
kustomize-maintainers: kustomize-approvers:
- justinsb - justinsb
- mortent - knverey
- monopole
- natasha41575 - natasha41575
- phanimarupaka - pwittrock
- Shell32-Natsu kustomize-reviewers:
emeritus-maintainers: - knverey
- liujingfang1 - monopole
- natasha41575
kyaml-approvers:
- mengqiy - mengqiy
- mortent
- phanimarupaka
kyaml-reviewers:
- mengqiy
- mortent
- phanimarupaka
emeritus-approvers:
- liujingfang1
- Shell32-Natsu

View File

@@ -12,6 +12,7 @@ import (
"sigs.k8s.io/kustomize/api/ifc" "sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
) )
@@ -78,12 +79,23 @@ func (p *PatchJson6902TransformerPlugin) Transform(m resmap.ResMap) error {
return err return err
} }
for _, res := range resources { for _, res := range resources {
internalAnnotations := kioutil.GetInternalAnnotations(&res.RNode)
err = res.ApplyFilter(patchjson6902.Filter{ err = res.ApplyFilter(patchjson6902.Filter{
Patch: p.JsonOp, Patch: p.JsonOp,
}) })
if err != nil { if err != nil {
return err return err
} }
annotations := res.GetAnnotations()
for key, value := range internalAnnotations {
annotations[key] = value
}
err = res.SetAnnotations(annotations)
if err != nil {
return err
}
} }
return nil return nil
} }

View File

@@ -12,6 +12,7 @@ import (
"sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource" "sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
) )
@@ -111,12 +112,19 @@ func (p *PatchTransformerPlugin) transformJson6902(m resmap.ResMap, patch jsonpa
} }
for _, res := range resources { for _, res := range resources {
res.StorePreviousId() res.StorePreviousId()
internalAnnotations := kioutil.GetInternalAnnotations(&res.RNode)
err = res.ApplyFilter(patchjson6902.Filter{ err = res.ApplyFilter(patchjson6902.Filter{
Patch: p.Patch, Patch: p.Patch,
}) })
if err != nil { if err != nil {
return err return err
} }
annotations := res.GetAnnotations()
for key, value := range internalAnnotations {
annotations[key] = value
}
err = res.SetAnnotations(annotations)
} }
return nil return nil
} }

View File

@@ -56,6 +56,7 @@ func (f Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
// sanity check. // sanity check.
return nil, err return nil, err
} }
f.NameFieldToUpdate.Gvk = f.Referrer.GetGvk()
if err := node.PipeE(fieldspec.Filter{ if err := node.PipeE(fieldspec.Filter{
FieldSpec: f.NameFieldToUpdate, FieldSpec: f.NameFieldToUpdate,
SetValue: f.set, SetValue: f.set,

View File

@@ -250,6 +250,7 @@ metadata:
name: dep name: dep
annotations: annotations:
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
internal.config.kubernetes.io/index: '0'
data: data:
slice: slice:
- false - false
@@ -276,6 +277,7 @@ metadata:
name: dep name: dep
annotations: annotations:
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
internal.config.kubernetes.io/index: '0'
data: data:
1: str 1: str
: invalid map key: value='1', tag='` + yaml.NodeTagInt + `'`, : invalid map key: value='1', tag='` + yaml.NodeTagInt + `'`,

View File

@@ -8,6 +8,7 @@ import (
"strings" "strings"
"sigs.k8s.io/kustomize/api/internal/utils" "sigs.k8s.io/kustomize/api/internal/utils"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/resid" "sigs.k8s.io/kustomize/kyaml/resid"
"sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml"
@@ -48,6 +49,17 @@ func applyReplacement(nodes []*yaml.RNode, value *yaml.RNode, targets []*types.T
if err != nil { if err != nil {
return nil, err return nil, err
} }
// filter targets by label and annotation selectors
selectByAnnoAndLabel, err := selectByAnnoAndLabel(n, t)
if err != nil {
return nil, err
}
if !selectByAnnoAndLabel {
continue
}
// filter targets by matching resource IDs
for _, id := range ids { for _, id := range ids {
if id.IsSelectedBy(t.Select.ResId) && !rejectId(t.Reject, &id) { if id.IsSelectedBy(t.Select.ResId) && !rejectId(t.Reject, &id) {
err := applyToNode(n, value, t) err := applyToNode(n, value, t)
@@ -62,9 +74,37 @@ func applyReplacement(nodes []*yaml.RNode, value *yaml.RNode, targets []*types.T
return nodes, nil return nodes, nil
} }
func selectByAnnoAndLabel(n *yaml.RNode, t *types.TargetSelector) (bool, error) {
if matchesSelect, err := matchesAnnoAndLabelSelector(n, t.Select); !matchesSelect || err != nil {
return false, err
}
for _, reject := range t.Reject {
if reject.AnnotationSelector == "" && reject.LabelSelector == "" {
continue
}
if m, err := matchesAnnoAndLabelSelector(n, reject); m || err != nil {
return false, err
}
}
return true, nil
}
func matchesAnnoAndLabelSelector(n *yaml.RNode, selector *types.Selector) (bool, error) {
r := resource.Resource{RNode: *n}
annoMatch, err := r.MatchesAnnotationSelector(selector.AnnotationSelector)
if err != nil {
return false, err
}
labelMatch, err := r.MatchesLabelSelector(selector.LabelSelector)
if err != nil {
return false, err
}
return annoMatch && labelMatch, nil
}
func rejectId(rejects []*types.Selector, id *resid.ResId) bool { func rejectId(rejects []*types.Selector, id *resid.ResId) bool {
for _, r := range rejects { for _, r := range rejects {
if id.IsSelectedBy(r.ResId) { if !r.ResId.IsEmpty() && id.IsSelectedBy(r.ResId) {
return true return true
} }
} }
@@ -131,10 +171,11 @@ func getReplacement(nodes []*yaml.RNode, r *types.Replacement) (*yaml.RNode, err
if err != nil { if err != nil {
return nil, err return nil, err
} }
if !rn.IsNilOrEmpty() { if rn.IsNilOrEmpty() {
return getRefinedValue(r.Source.Options, rn) return nil, fmt.Errorf("fieldPath `%s` is missing for replacement source %s", r.Source.FieldPath, r.Source)
} }
return rn, nil
return getRefinedValue(r.Source.Options, rn)
} }
func getRefinedValue(options *types.FieldOptions, rn *yaml.RNode) (*yaml.RNode, error) { func getRefinedValue(options *types.FieldOptions, rn *yaml.RNode) (*yaml.RNode, error) {

View File

@@ -1554,6 +1554,262 @@ spec:
name: nginx-tagged name: nginx-tagged
- image: nginx:1.7.9 - image: nginx:1.7.9
name: postgresdb name: postgresdb
`,
},
"replacement source.fieldPath does not exist": {
input: `apiVersion: v1
kind: ConfigMap
metadata:
name: ports-from
data:
grpcPort: 8080
---
apiVersion: v1
kind: ConfigMap
metadata:
name: ports-to
data:
grpcPort: 8081
`,
replacements: `replacements:
- source:
kind: ConfigMap
name: ports-from
fieldPath: data.httpPort
targets:
- select:
kind: ConfigMap
name: ports-to
fieldPaths:
- data.grpcPort
options:
create: true
`,
expectedErr: "fieldPath `data.httpPort` is missing for replacement source ~G_~V_ConfigMap|~X|ports-from:data.httpPort",
},
"annotationSelector": {
input: `apiVersion: v1
kind: Deployment
metadata:
name: deploy-1
annotations:
foo: bar-1
spec:
template:
spec:
containers:
- image: nginx:1.7.9
name: nginx-tagged
- image: postgres:1.8.0
name: postgresdb
---
apiVersion: v1
kind: Deployment
metadata:
name: deploy-2
annotations:
foo: bar-2
spec:
template:
spec:
containers:
- image: nginx:1.7.9
name: nginx-tagged
- image: postgres:1.8.0
name: postgresdb
`,
replacements: `replacements:
- source:
kind: Deployment
name: deploy-1
fieldPath: spec.template.spec.containers.0.image
targets:
- select:
annotationSelector: foo=bar-1
fieldPaths:
- spec.template.spec.containers.1.image
`,
expected: `apiVersion: v1
kind: Deployment
metadata:
name: deploy-1
annotations:
foo: bar-1
spec:
template:
spec:
containers:
- image: nginx:1.7.9
name: nginx-tagged
- image: nginx:1.7.9
name: postgresdb
---
apiVersion: v1
kind: Deployment
metadata:
name: deploy-2
annotations:
foo: bar-2
spec:
template:
spec:
containers:
- image: nginx:1.7.9
name: nginx-tagged
- image: postgres:1.8.0
name: postgresdb
`,
},
"labelSelector": {
input: `apiVersion: v1
kind: Deployment
metadata:
name: deploy-1
labels:
foo: bar-1
spec:
template:
spec:
containers:
- image: nginx:1.7.9
name: nginx-tagged
- image: postgres:1.8.0
name: postgresdb
---
apiVersion: v1
kind: Deployment
metadata:
name: deploy-2
labels:
foo: bar-2
spec:
template:
spec:
containers:
- image: nginx:1.7.9
name: nginx-tagged
- image: postgres:1.8.0
name: postgresdb
`,
replacements: `replacements:
- source:
kind: Deployment
name: deploy-1
fieldPath: spec.template.spec.containers.0.image
targets:
- select:
labelSelector: foo=bar-1
fieldPaths:
- spec.template.spec.containers.1.image
`,
expected: `apiVersion: v1
kind: Deployment
metadata:
name: deploy-1
labels:
foo: bar-1
spec:
template:
spec:
containers:
- image: nginx:1.7.9
name: nginx-tagged
- image: nginx:1.7.9
name: postgresdb
---
apiVersion: v1
kind: Deployment
metadata:
name: deploy-2
labels:
foo: bar-2
spec:
template:
spec:
containers:
- image: nginx:1.7.9
name: nginx-tagged
- image: postgres:1.8.0
name: postgresdb
`,
},
"reject via labelSelector": {
input: `apiVersion: v1
kind: Deployment
metadata:
name: deploy-1
labels:
foo: bar-1
spec:
template:
spec:
containers:
- image: nginx:1.7.9
name: nginx-tagged
- image: postgres:1.8.0
name: postgresdb
---
apiVersion: v1
kind: Deployment
metadata:
name: deploy-2
labels:
foo: bar-2
spec:
template:
spec:
containers:
- image: nginx:1.7.9
name: nginx-tagged
- image: postgres:1.8.0
name: postgresdb
`,
replacements: `replacements:
- source:
kind: Deployment
name: deploy-1
fieldPath: spec.template.spec.containers.0.image
targets:
- select:
kind: Deployment
reject:
- labelSelector: foo=bar-2
fieldPaths:
- spec.template.spec.containers.1.image
`,
expected: `apiVersion: v1
kind: Deployment
metadata:
name: deploy-1
labels:
foo: bar-1
spec:
template:
spec:
containers:
- image: nginx:1.7.9
name: nginx-tagged
- image: nginx:1.7.9
name: postgresdb
---
apiVersion: v1
kind: Deployment
metadata:
name: deploy-2
labels:
foo: bar-2
spec:
template:
spec:
containers:
- image: nginx:1.7.9
name: nginx-tagged
- image: postgres:1.8.0
name: postgresdb
`, `,
}, },
} }

View File

@@ -11,6 +11,6 @@ require (
github.com/stretchr/testify v1.5.1 github.com/stretchr/testify v1.5.1
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e
sigs.k8s.io/kustomize/kyaml v0.11.1 sigs.k8s.io/kustomize/kyaml v0.13.0
sigs.k8s.io/yaml v1.2.0 sigs.k8s.io/yaml v1.2.0
) )

View File

@@ -223,8 +223,8 @@ k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
sigs.k8s.io/kustomize/kyaml v0.11.1 h1:MWihd9syKG7VQnAzr/OpKb94FvH+cw96nEV1u3it7pI= sigs.k8s.io/kustomize/kyaml v0.13.0 h1:9c+ETyNfSrVhxvphs+K2dzT3dh5oVPPEqPOE/cUpScY=
sigs.k8s.io/kustomize/kyaml v0.11.1/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E= sigs.k8s.io/kustomize/kyaml v0.13.0/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

View File

@@ -11,6 +11,7 @@ import (
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig" "sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
"sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource" "sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/kyaml/resid"
) )
type nameReferenceTransformer struct { type nameReferenceTransformer struct {
@@ -109,11 +110,18 @@ func debug(fMap filterMap) {
// 'spec/scaleTargetRef/name' field. Return a filter that can do that. // 'spec/scaleTargetRef/name' field. Return a filter that can do that.
func (t *nameReferenceTransformer) determineFilters( func (t *nameReferenceTransformer) determineFilters(
resources []*resource.Resource) (fMap filterMap) { resources []*resource.Resource) (fMap filterMap) {
// We cache the resource OrgId values because they don't change and otherwise are very visible in a memory pprof
resourceOrgIds := make([]resid.ResId, len(resources))
for i, resource := range resources {
resourceOrgIds[i] = resource.OrgId()
}
fMap = make(filterMap) fMap = make(filterMap)
for _, backReference := range t.backRefs { for _, backReference := range t.backRefs {
for _, referrerSpec := range backReference.Referrers { for _, referrerSpec := range backReference.Referrers {
for _, res := range resources { for i, res := range resources {
if res.OrgId().IsSelected(&referrerSpec.Gvk) { if resourceOrgIds[i].IsSelected(&referrerSpec.Gvk) {
// If this is true, the res might be a referrer, and if // If this is true, the res might be a referrer, and if
// so, the name reference it holds might need an update. // so, the name reference it holds might need an update.
if resHasField(res, referrerSpec.Path) { if resHasField(res, referrerSpec.Path) {

View File

@@ -168,3 +168,23 @@ func (ra *ResAccumulator) FixBackReferences() (err error) {
return ra.Transform( return ra.Transform(
newNameReferenceTransformer(ra.tConfig.NameReference)) newNameReferenceTransformer(ra.tConfig.NameReference))
} }
// Intersection drops the resources which "other" does not have.
func (ra *ResAccumulator) Intersection(other resmap.ResMap) error {
for _, curId := range ra.resMap.AllIds() {
toDelete := true
for _, otherId := range other.AllIds() {
if otherId == curId {
toDelete = false
break
}
}
if toDelete {
err := ra.resMap.Remove(curId)
if err != nil {
return err
}
}
}
return nil
}

View File

@@ -10,6 +10,7 @@ import (
"strings" "strings"
"github.com/pkg/errors" "github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/builtins" "sigs.k8s.io/kustomize/api/builtins"
"sigs.k8s.io/kustomize/api/ifc" "sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/internal/accumulator" "sigs.k8s.io/kustomize/api/internal/accumulator"
@@ -218,9 +219,26 @@ func (kt *KustTarget) accumulateTarget(ra *accumulator.ResAccumulator, origin *r
return nil, errors.Wrapf( return nil, errors.Wrapf(
err, "merging vars %v", kt.kustomization.Vars) err, "merging vars %v", kt.kustomization.Vars)
} }
err = kt.IgnoreLocal(ra)
if err != nil {
return nil, err
}
return ra, nil return ra, nil
} }
// IgnoreLocal drops the local resource by checking the annotation "config.kubernetes.io/local-config".
func (kt *KustTarget) IgnoreLocal(ra *accumulator.ResAccumulator) error {
rf := kt.rFactory.RF()
if rf.IncludeLocalConfigs {
return nil
}
remainRes, err := rf.DropLocalNodes(ra.ResMap().ToRNodeSlice())
if err != nil {
return err
}
return ra.Intersection(kt.rFactory.FromResourceSlice(remainRes))
}
func (kt *KustTarget) runGenerators( func (kt *KustTarget) runGenerators(
ra *accumulator.ResAccumulator) error { ra *accumulator.ResAccumulator) error {
var generators []resmap.Generator var generators []resmap.Generator

View File

@@ -549,3 +549,26 @@ metadata:
name: testing-tt4769fb52 name: testing-tt4769fb52
`) `)
} }
// regression test for https://github.com/kubernetes-sigs/kustomize/issues/4233
func TestDataEndsWithQuotes(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK(".", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- name: test
literals:
- TEST=this is a 'test'
`)
m := th.Run(".", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(
m, `apiVersion: v1
data:
TEST: this is a 'test'
kind: ConfigMap
metadata:
name: test-k9cc55dfm5
`)
}

View File

@@ -685,3 +685,167 @@ spec:
name: new-name name: new-name
`) `)
} }
func TestNameReferenceAfterJsonPatch(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("resources.yaml", `
apiVersion: v1
data:
bar: bar
kind: ConfigMap
metadata:
name: cm
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: foo
spec:
selector:
matchLabels:
foo: foo
template:
metadata:
labels:
foo: foo
spec:
containers:
- name: foo
image: example
volumeMounts:
- mountPath: /path
name: myvol
volumes:
- configMap:
name: cm
name: myvol
`)
th.WriteK(".", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: foo-
resources:
- resources.yaml
patches:
- target:
group: apps
version: v1
name: foo
patch: |
- op: replace
path: /kind
value: Deployment
`)
m := th.Run(".", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `apiVersion: v1
data:
bar: bar
kind: ConfigMap
metadata:
name: foo-cm
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo-foo
spec:
selector:
matchLabels:
foo: foo
template:
metadata:
labels:
foo: foo
spec:
containers:
- image: example
name: foo
volumeMounts:
- mountPath: /path
name: myvol
volumes:
- configMap:
name: foo-cm
name: myvol
`)
}
func TestNameReferenceAfterJsonPatchConfigMapGenerator(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("statefulset.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: foo
spec:
selector:
matchLabels:
foo: foo
template:
metadata:
labels:
foo: foo
spec:
containers:
- name: foo
image: example
volumeMounts:
- mountPath: /path
name: myvol
volumes:
- configMap:
name: cm
name: myvol
`)
th.WriteK(".", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- statefulset.yaml
patches:
- target:
group: apps
version: v1
name: foo
patch: |
- op: replace
path: /kind
value: Deployment
configMapGenerator:
- name: cm
literals:
- bar=bar
`)
m := th.Run(".", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `apiVersion: apps/v1
kind: Deployment
metadata:
name: foo
spec:
selector:
matchLabels:
foo: foo
template:
metadata:
labels:
foo: foo
spec:
containers:
- image: example
name: foo
volumeMounts:
- mountPath: /path
name: myvol
volumes:
- configMap:
name: cm-8hm8224gfd
name: myvol
---
apiVersion: v1
data:
bar: bar
kind: ConfigMap
metadata:
name: cm-8hm8224gfd
`)
}

View File

@@ -26,7 +26,7 @@ import (
// used instead of performing an exec to a kustomize CLI subprocess. // used instead of performing an exec to a kustomize CLI subprocess.
// To use, load a filesystem with kustomization files (any // To use, load a filesystem with kustomization files (any
// number of overlays and bases), then make a Kustomizer // number of overlays and bases), then make a Kustomizer
// injected with the given fileystem, then call Run. // injected with the given filesystem, then call Run.
type Kustomizer struct { type Kustomizer struct {
options *Options options *Options
depProvider *provider.DepProvider depProvider *provider.DepProvider

View File

@@ -0,0 +1,70 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package krusty_test
import (
"testing"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
// This test checks that if a resource is annotated as "local-config", this resource won't be ignored until
// all transformations have completed. This makes sure the local resource can be used as a transformation input.
// See https://github.com/kubernetes-sigs/kustomize/issues/4124 for details.
func TestSKipLocalConfigAfterTransform(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK(".", `apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- pod.yaml
- deployment.yaml
transformers:
- replacement.yaml
`)
th.WriteF("pod.yaml", `apiVersion: v1
kind: Pod
metadata:
name: buildup
annotations:
config.kubernetes.io/local-config: "true"
spec:
containers:
- name: app
image: nginx
`)
th.WriteF("deployment.yaml", `apiVersion: apps/v1
kind: Deployment
metadata:
name: buildup
`)
th.WriteF("replacement.yaml", `
apiVersion: builtin
kind: ReplacementTransformer
metadata:
name: buildup
replacements:
- source:
kind: Pod
fieldPath: spec
targets:
- select:
kind: Deployment
fieldPaths:
- spec.template.spec
options:
create: true
`)
m := th.Run(".", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `apiVersion: apps/v1
kind: Deployment
metadata:
name: buildup
spec:
template:
spec:
containers:
- image: nginx
name: app
`)
}

View File

@@ -1646,3 +1646,64 @@ spec:
type: NodePort type: NodePort
`) `)
} }
// test for #4111
func TestPatchPreservesInternalAnnotations(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK(".", `
nameSuffix: -abc
resources:
- fluentd.yaml
patchesJson6902:
- path: patch.yaml
target:
name: fluentd-sa
kind: ServiceAccount
version: v1
`)
th.WriteF("fluentd.yaml", `
apiVersion: v1
kind: DaemonSet
metadata:
name: fluentd
spec:
template:
spec:
containers:
- image: fluentd:latest
name: fluentd
serviceAccountName: fluentd-sa
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: fluentd-sa
`)
th.WriteF("patch.yaml", `
- op: add
path: /metadata/annotations
value:
note: this is a test annotation
`)
m := th.Run(".", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: DaemonSet
metadata:
name: fluentd-abc
spec:
template:
spec:
containers:
- image: fluentd:latest
name: fluentd
serviceAccountName: fluentd-sa-abc
---
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
note: this is a test annotation
name: fluentd-sa-abc
`)
}

View File

@@ -5,6 +5,7 @@ package krusty_test
import ( import (
"io/ioutil" "io/ioutil"
"os"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -42,6 +43,26 @@ spec:
`) `)
} }
func writeOtherCustomResource(th kusttest_test.Harness, filepath string) {
th.WriteF(filepath, `
apiVersion: v1alpha1
kind: MyCRD
metadata:
name: service
spec:
template:
spec:
containers:
- name: server
image: server
command: example
ports:
- name: grpc
protocol: TCP
containerPort: 8080
`)
}
func writeTestComponentWithCustomSchema(th kusttest_test.Harness) { func writeTestComponentWithCustomSchema(th kusttest_test.Harness) {
writeTestSchema(th, "comp/") writeTestSchema(th, "comp/")
openapi.ResetOpenAPI() openapi.ResetOpenAPI()
@@ -74,6 +95,32 @@ patchesStrategicMerge:
image: nginx image: nginx
` `
const customSchemaPatchMultipleGvks = `
patchesStrategicMerge:
- |-
apiVersion: example.com/v1alpha1
kind: MyCRD
metadata:
name: service
spec:
template:
spec:
containers:
- name: server
image: nginx
- |-
apiVersion: v1alpha1
kind: MyCRD
metadata:
name: service
spec:
template:
spec:
containers:
- name: server
image: nginx
`
const patchedCustomResource = ` const patchedCustomResource = `
apiVersion: example.com/v1alpha1 apiVersion: example.com/v1alpha1
kind: MyCRD kind: MyCRD
@@ -108,6 +155,54 @@ openapi:
th.AssertActualEqualsExpected(m, patchedCustomResource) th.AssertActualEqualsExpected(m, patchedCustomResource)
} }
func TestCustomOpenApiFieldWithTwoGvks(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK(".", `
resources:
- mycrd.yaml
- myothercrd.yaml
openapi:
path: mycrd_schema.json
`+customSchemaPatchMultipleGvks)
writeCustomResource(th, "mycrd.yaml")
writeOtherCustomResource(th, "myothercrd.yaml")
writeTestSchema(th, "./")
openapi.ResetOpenAPI()
m := th.Run(".", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `apiVersion: example.com/v1alpha1
kind: MyCRD
metadata:
name: service
spec:
template:
spec:
containers:
- command: example
image: nginx
name: server
ports:
- containerPort: 8080
name: grpc
protocol: TCP
---
apiVersion: v1alpha1
kind: MyCRD
metadata:
name: service
spec:
template:
spec:
containers:
- command: example
image: nginx
name: server
ports:
- containerPort: 8080
name: grpc
protocol: TCP
`)
}
func TestCustomOpenApiFieldYaml(t *testing.T) { func TestCustomOpenApiFieldYaml(t *testing.T) {
th := kusttest_test.MakeHarness(t) th := kusttest_test.MakeHarness(t)
th.WriteK(".", ` th.WriteK(".", `
@@ -252,3 +347,109 @@ func TestCustomOpenAPIFieldFromComponent(t *testing.T) {
th.Run("prod", th.MakeDefaultOptions()) th.Run("prod", th.MakeDefaultOptions())
assert.Equal(t, "using custom schema from file provided", openapi.GetSchemaVersion()) assert.Equal(t, "using custom schema from file provided", openapi.GetSchemaVersion())
} }
// test for https://github.com/kubernetes-sigs/kustomize/issues/4179
// kustomize is not seeing the openapi field from the component defined in the overlay
func TestCustomOpenAPIFieldFromComponentWithOverlays(t *testing.T) {
if val, ok := os.LookupEnv("OPENAPI_TEST"); !ok || val != "true" {
t.SkipNow()
}
th := kusttest_test.MakeHarness(t)
// overlay declaring the component
th.WriteK("overlays/overlay-component-openapi", `resources:
- ../base/
components:
- ../../components/dc-openapi
`)
// base kustomization
th.WriteK("overlays/base", `resources:
- dc.yml
`)
// resource declared in the base kustomization
th.WriteF("overlays/base/dc.yml", `apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
name: my-dc
spec:
template:
spec:
initContainers:
- name: init
containers:
- name: container
env:
- name: foo
value: bar
volumeMounts:
- name: cm
mountPath: /opt/cm
volumes:
- name: cm
configMap:
name: cm
`)
// openapi schema referred to by the component
bytes, _ := ioutil.ReadFile("testdata/openshiftschema.json")
th.WriteF("components/dc-openapi/openapi.json", string(bytes))
// patch referred to by the component
th.WriteF("components/dc-openapi/patch.yml", `apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
name: my-dc
spec:
template:
spec:
containers:
- name: container
volumeMounts:
- name: additional-cm
mountPath: /mnt
volumes:
- name: additional-cm
configMap:
name: additional-cm
`)
// component declared in overlay with custom schema and patch
th.WriteC("components/dc-openapi", `patches:
- patch.yml
openapi:
path: openapi.json
`)
openapi.ResetOpenAPI()
m := th.Run("overlays/overlay-component-openapi", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
name: my-dc
spec:
template:
spec:
containers:
- env:
- name: foo
value: bar
name: container
volumeMounts:
- mountPath: /mnt
name: additional-cm
- mountPath: /opt/cm
name: cm
initContainers:
- name: init
volumes:
- configMap:
name: additional-cm
name: additional-cm
- configMap:
name: cm
name: cm
`)
}

View File

@@ -34,6 +34,11 @@
"group": "example.com", "group": "example.com",
"kind": "MyCRD", "kind": "MyCRD",
"version": "v1alpha1" "version": "v1alpha1"
},
{
"group": "",
"kind": "MyCRD",
"version": "v1alpha1"
} }
] ]
}, },

View File

@@ -22,6 +22,9 @@ definitions:
- group: example.com - group: example.com
kind: MyCRD kind: MyCRD
version: v1alpha1 version: v1alpha1
- group: ""
kind: MyCRD
version: v1alpha1
io.k8s.api.core.v1.PodTemplateSpec: io.k8s.api.core.v1.PodTemplateSpec:
properties: properties:
metadata: metadata:

View File

@@ -0,0 +1,76 @@
{
"definitions": {
"com.github.openshift.api.apps.v1.DeploymentConfig": {
"type": "object",
"required": [
"spec"
],
"properties": {
"apiVersion": {
"type": "string"
},
"kind": {
"type": "string"
},
"metadata": {
"$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta"
},
"spec": {
"$ref": "#/definitions/com.github.openshift.api.apps.v1.DeploymentConfigSpec"
}
},
"x-kubernetes-group-version-kind": [
{
"group": "apps.openshift.io",
"kind": "DeploymentConfig",
"version": "v1"
}
]
},
"com.github.openshift.api.apps.v1.DeploymentConfigSpec": {
"type": "object",
"properties": {
"template": {
"$ref": "#/definitions/io.k8s.api.core.v1.PodTemplateSpec"
}
}
},
"io.k8s.api.core.v1.Volume": {
"type": "object",
"required": [
"name"
],
"properties": {
"configMap": {
"$ref": "#/definitions/io.k8s.api.core.v1.ConfigMapVolumeSource"
},
"name": {
"type": "string"
}
}
},
"io.k8s.api.core.v1.VolumeMount": {
"type": "object",
"required": [
"name",
"mountPath"
],
"properties": {
"mountPath": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta": {
"type": "object",
"properties": {
"name": {
"type": "string"
}
}
}
}
}

View File

@@ -209,5 +209,17 @@ func parseLiteralSource(source string) (keyName, value string, err error) {
if len(items) != 2 { if len(items) != 2 {
return "", "", fmt.Errorf("invalid literal source %v, expected key=value", source) return "", "", fmt.Errorf("invalid literal source %v, expected key=value", source)
} }
return items[0], strings.Trim(items[1], "\"'"), nil return items[0], removeQuotes(items[1]), nil
}
// removeQuotes removes the surrounding quotes from the provided string only if it is surrounded on both sides
// rather than blindly trimming all quotation marks on either side.
func removeQuotes(str string) string {
if len(str) == 0 || str[0] != str[len(str)-1] {
return str
}
if str[0] == '"' || str[0] == '\'' {
return str[1 : len(str)-1]
}
return str
} }

View File

@@ -124,14 +124,34 @@ func (rf *Factory) SliceFromBytes(in []byte) ([]*Resource, error) {
return rf.resourcesFromRNodes(nodes), nil return rf.resourcesFromRNodes(nodes), nil
} }
// DropLocalNodes removes the local nodes by default. Local nodes are detected via the annotation `config.kubernetes.io/local-config: "true"`
func (rf *Factory) DropLocalNodes(nodes []*yaml.RNode) ([]*Resource, error) {
var result []*yaml.RNode
for _, node := range nodes {
if node.IsNilOrEmpty() {
continue
}
md, err := node.GetValidatedMetadata()
if err != nil {
return nil, err
}
if rf.IncludeLocalConfigs {
result = append(result, node)
continue
}
localConfig, exist := md.ObjectMeta.Annotations[konfig.IgnoredByKustomizeAnnotation]
if !exist || localConfig == "false" {
result = append(result, node)
}
}
return rf.resourcesFromRNodes(result), nil
}
// ResourcesFromRNodes converts RNodes to Resources. // ResourcesFromRNodes converts RNodes to Resources.
func (rf *Factory) ResourcesFromRNodes( func (rf *Factory) ResourcesFromRNodes(
nodes []*yaml.RNode) (result []*Resource, err error) { nodes []*yaml.RNode) (result []*Resource, err error) {
nodes, err = rf.dropBadNodes(nodes) return rf.DropLocalNodes(nodes)
if err != nil {
return nil, err
}
return rf.resourcesFromRNodes(nodes), nil
} }
// resourcesFromRNode assumes all nodes are good. // resourcesFromRNode assumes all nodes are good.
@@ -143,7 +163,7 @@ func (rf *Factory) resourcesFromRNodes(
return return
} }
func (rf *Factory) RNodesFromBytes(b []byte) (result []*yaml.RNode, err error) { func (rf *Factory) RNodesFromBytes(b []byte) ([]*yaml.RNode, error) {
nodes, err := kio.FromBytes(b) nodes, err := kio.FromBytes(b)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -152,9 +172,17 @@ func (rf *Factory) RNodesFromBytes(b []byte) (result []*yaml.RNode, err error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return rf.inlineAnyEmbeddedLists(nodes)
}
// inlineAnyEmbeddedLists scans the RNode slice for nodes named FooList.
// Such nodes are expected to be lists of resources, each of type Foo.
// These lists are replaced in the result by their inlined resources.
func (rf *Factory) inlineAnyEmbeddedLists(
nodes []*yaml.RNode) (result []*yaml.RNode, err error) {
var n0 *yaml.RNode
for len(nodes) > 0 { for len(nodes) > 0 {
n0 := nodes[0] n0, nodes = nodes[0], nodes[1:]
nodes = nodes[1:]
kind := n0.GetKind() kind := n0.GetKind()
if !strings.HasSuffix(kind, "List") { if !strings.HasSuffix(kind, "List") {
result = append(result, n0) result = append(result, n0)
@@ -164,7 +192,7 @@ func (rf *Factory) RNodesFromBytes(b []byte) (result []*yaml.RNode, err error) {
var m map[string]interface{} var m map[string]interface{}
m, err = n0.Map() m, err = n0.Map()
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("trouble expanding list of %s; %w", kind, err)
} }
items, ok := m["items"] items, ok := m["items"]
if !ok { if !ok {
@@ -216,38 +244,20 @@ func (rf *Factory) convertObjectSliceToNodeSlice(
func (rf *Factory) dropBadNodes(nodes []*yaml.RNode) ([]*yaml.RNode, error) { func (rf *Factory) dropBadNodes(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
var result []*yaml.RNode var result []*yaml.RNode
for _, n := range nodes { for _, n := range nodes {
ignore, err := rf.shouldIgnore(n) if n.IsNilOrEmpty() {
if err != nil { continue
}
if _, err := n.GetValidatedMetadata(); err != nil {
return nil, err return nil, err
} }
if !ignore { if foundNil, path := n.HasNilEntryInList(); foundNil {
result = append(result, n) return nil, fmt.Errorf("empty item at %v in object %v", path, n)
} }
result = append(result, n)
} }
return result, nil return result, nil
} }
// shouldIgnore returns true if there's some reason to ignore the node.
func (rf *Factory) shouldIgnore(n *yaml.RNode) (bool, error) {
if n.IsNilOrEmpty() {
return true, nil
}
if !rf.IncludeLocalConfigs {
md, err := n.GetValidatedMetadata()
if err != nil {
return true, err
}
_, ignore := md.ObjectMeta.Annotations[konfig.IgnoredByKustomizeAnnotation]
if ignore {
return true, nil
}
}
if foundNil, path := n.HasNilEntryInList(); foundNil {
return true, fmt.Errorf("empty item at %v in object %v", path, n)
}
return false, nil
}
// SliceFromBytesWithNames unmarshals bytes into a Resource slice with specified original // SliceFromBytesWithNames unmarshals bytes into a Resource slice with specified original
// name. // name.
func (rf *Factory) SliceFromBytesWithNames(names []string, in []byte) ([]*Resource, error) { func (rf *Factory) SliceFromBytesWithNames(names []string, in []byte) ([]*Resource, error) {

View File

@@ -5,7 +5,7 @@ package resource_test
import ( import (
"fmt" "fmt"
"reflect" "strings"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -13,9 +13,10 @@ import (
. "sigs.k8s.io/kustomize/api/resource" . "sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filesys" "sigs.k8s.io/kustomize/kyaml/filesys"
"sigs.k8s.io/kustomize/kyaml/kio"
) )
func TestSliceFromBytes(t *testing.T) { func TestRNodesFromBytes(t *testing.T) {
type testCase struct { type testCase struct {
input string input string
expected []string expected []string
@@ -399,60 +400,11 @@ binaryData:
} }
} }
func TestSliceFromBytesMore(t *testing.T) { func TestMoreRNodesFromBytes(t *testing.T) {
testConfigMap :=
map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "winnie",
},
}
testDeploymentSpec := map[string]interface{}{
"template": map[string]interface{}{
"spec": map[string]interface{}{
"hostAliases": []interface{}{
map[string]interface{}{
"hostnames": []interface{}{
"a.example.com",
},
"ip": "8.8.8.8",
},
},
},
},
}
testDeploymentA := map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "deployment-a",
},
"spec": testDeploymentSpec,
}
testDeploymentB := map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "deployment-b",
},
"spec": testDeploymentSpec,
}
testDeploymentList :=
map[string]interface{}{
"apiVersion": "v1",
"kind": "DeploymentList",
"items": []interface{}{
testDeploymentA,
testDeploymentB,
},
}
type expected struct { type expected struct {
out []map[string]interface{} out []string
isErr bool isErr bool
} }
testCases := map[string]struct { testCases := map[string]struct {
input []byte input []byte
exp expected exp expected
@@ -465,16 +417,16 @@ func TestSliceFromBytesMore(t *testing.T) {
}, },
"noBytes": { "noBytes": {
input: []byte{}, input: []byte{},
exp: expected{ exp: expected{},
out: []map[string]interface{}{},
},
}, },
"goodJson": { "goodJson": {
input: []byte(` input: []byte(`
{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"winnie"}} {"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"winnie"}}
`), `),
exp: expected{ exp: expected{
out: []map[string]interface{}{testConfigMap}, out: []string{
`{"apiVersion": "v1", "kind": "ConfigMap", "metadata": {"name": "winnie"}}`,
},
}, },
}, },
"goodYaml1": { "goodYaml1": {
@@ -485,7 +437,12 @@ metadata:
name: winnie name: winnie
`), `),
exp: expected{ exp: expected{
out: []map[string]interface{}{testConfigMap}, out: []string{`
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`},
}, },
}, },
"goodYaml2": { "goodYaml2": {
@@ -501,26 +458,17 @@ metadata:
name: winnie name: winnie
`), `),
exp: expected{ exp: expected{
out: []map[string]interface{}{testConfigMap, testConfigMap}, out: []string{`
},
},
"localConfigYaml": {
input: []byte(`
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie-skip
annotations:
# this annotation causes the Resource to be ignored by kustomize
config.kubernetes.io/local-config: ""
---
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
metadata: metadata:
name: winnie name: winnie
`), `, `
exp: expected{ apiVersion: v1
out: []map[string]interface{}{testConfigMap}, kind: ConfigMap
metadata:
name: winnie
`},
}, },
}, },
"garbageInOneOfTwoObjects": { "garbageInOneOfTwoObjects": {
@@ -545,7 +493,7 @@ WOOOOOOOOOOOOOOOOOOOOOOOOT: woot
`), `),
exp: expected{ exp: expected{
out: []map[string]interface{}{}, out: []string{},
}, },
}, },
"Missing .metadata.name in object": { "Missing .metadata.name in object": {
@@ -591,9 +539,18 @@ items:
name: winnie name: winnie
`), `),
exp: expected{ exp: expected{
out: []map[string]interface{}{ out: []string{`
testConfigMap, apiVersion: v1
testConfigMap}, kind: ConfigMap
metadata:
name: winnie
`, `
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`,
},
}, },
}, },
"ConfigMapList": { "ConfigMapList": {
@@ -611,9 +568,9 @@ items:
name: winnie name: winnie
`), `),
exp: expected{ exp: expected{
out: []map[string]interface{}{ out: []string{
testConfigMap, `{"apiVersion": "v1", "kind": "ConfigMap", "metadata": {"name": "winnie"}}`,
testConfigMap, `{"apiVersion": "v1", "kind": "ConfigMap", "metadata": {"name": "winnie"}}`,
}, },
}, },
}, },
@@ -626,7 +583,7 @@ items:
kind: Deployment kind: Deployment
metadata: metadata:
name: deployment-a name: deployment-a
spec: &hostAliases spec: &foo
template: template:
spec: spec:
hostAliases: hostAliases:
@@ -638,23 +595,39 @@ items:
metadata: metadata:
name: deployment-b name: deployment-b
spec: spec:
<<: *hostAliases *foo
`), `),
exp: expected{ exp: expected{
// TODO(3271): This should work. out: []string{
// https://github.com/kubernetes-sigs/kustomize/issues/3271 `{"apiVersion": "apps/v1", "kind": "Deployment", "metadata": {"name": "deployment-a"}, ` +
// json.Marshal(obj) fails on the 2nd list item. `"spec": {"template": {"spec": {"hostAliases": [{"hostnames": ["a.example.com"], "ip": "8.8.8.8"}]}}}}`,
// The value of the 1st list item's first spec field is `{"apiVersion": "apps/v1", "kind": "Deployment", "metadata": {"name": "deployment-b"}, ` +
// map[string]interface{} `"spec": {"template": {"spec": {"hostAliases": [{"hostnames": ["a.example.com"], "ip": "8.8.8.8"}]}}}}`},
// The value of the 2nd list item's first spec field is },
// map[interface{}]interface{} },
// which causes a encoding/json.UnsupportedTypeError. "simpleAnchor": {
isErr: true, input: []byte(`
out: []map[string]interface{}{testDeploymentList}, apiVersion: v1
kind: ConfigMap
metadata:
name: wildcard
data:
color: &color-used blue
feeling: *color-used
`),
exp: expected{
out: []string{`
apiVersion: v1
kind: ConfigMap
metadata:
name: wildcard
data:
color: blue
feeling: blue
`},
}, },
}, },
} }
for n := range testCases { for n := range testCases {
tc := testCases[n] tc := testCases[n]
t.Run(n, func(t *testing.T) { t.Run(n, func(t *testing.T) {
@@ -666,15 +639,100 @@ items:
assert.False(t, tc.exp.isErr) assert.False(t, tc.exp.isErr)
assert.Equal(t, len(tc.exp.out), len(rs)) assert.Equal(t, len(tc.exp.out), len(rs))
for i := range rs { for i := range rs {
rsMap, err := rs[i].Map() actual, err := rs[i].String()
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal( assert.Equal(
t, fmt.Sprintf("%v", tc.exp.out[i]), fmt.Sprintf("%v", rsMap)) t, strings.TrimSpace(tc.exp.out[i]), strings.TrimSpace(actual))
m, _ := rs[i].Map() }
if !reflect.DeepEqual(tc.exp.out[i], m) { })
t.Fatalf("%s:\nexpected: %v\n actual: %v", }
n, tc.exp.out[i], m) }
}
func TestDropLocalNodes(t *testing.T) {
testCases := map[string]struct {
input []byte
expected []byte
}{
"localConfigUnset": {
input: []byte(`apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`),
expected: []byte(`apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`),
},
"localConfigSet": {
input: []byte(`apiVersion: v1
kind: ConfigMap
metadata:
name: winnie-skip
annotations:
# this annotation causes the Resource to be ignored by kustomize
config.kubernetes.io/local-config: ""
`),
expected: nil,
},
"localConfigSetToTrue": {
input: []byte(`apiVersion: v1
kind: ConfigMap
metadata:
name: winnie-skip
annotations:
config.kubernetes.io/local-config: "true"
`),
expected: nil,
},
"localConfigSetToFalse": {
input: []byte(`apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
annotations:
config.kubernetes.io/local-config: "false"
`),
expected: []byte(`apiVersion: v1
kind: ConfigMap
metadata:
annotations:
config.kubernetes.io/local-config: "false"
name: winnie
`),
},
"localConfigMultiInput": {
input: []byte(`apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
---
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie-skip
annotations:
config.kubernetes.io/local-config: "true"
`),
expected: []byte(`apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`),
},
}
for n := range testCases {
tc := testCases[n]
t.Run(n, func(t *testing.T) {
nin, _ := kio.FromBytes(tc.input)
res, err := factory.DropLocalNodes(nin)
assert.NoError(t, err)
if tc.expected == nil {
assert.Equal(t, 0, len(res))
} else {
actual, _ := res[0].AsYAML()
assert.Equal(t, tc.expected, actual)
} }
}) })
} }

View File

@@ -26,6 +26,7 @@ type Resource struct {
refVarNames []string refVarNames []string
} }
// nolint
var BuildAnnotations = []string{ var BuildAnnotations = []string{
utils.BuildAnnotationPreviousKinds, utils.BuildAnnotationPreviousKinds,
utils.BuildAnnotationPreviousNames, utils.BuildAnnotationPreviousNames,
@@ -41,6 +42,9 @@ var BuildAnnotations = []string{
kioutil.PathAnnotation, kioutil.PathAnnotation,
kioutil.IndexAnnotation, kioutil.IndexAnnotation,
kioutil.SeqIndentAnnotation, kioutil.SeqIndentAnnotation,
kioutil.LegacyPathAnnotation,
kioutil.LegacyIndexAnnotation,
} }
func (r *Resource) ResetRNode(incoming *Resource) { func (r *Resource) ResetRNode(incoming *Resource) {

View File

@@ -16,10 +16,10 @@ const DefaultReplacementFieldPath = "metadata.name"
// where it is from and where it is to. // where it is from and where it is to.
type Replacement struct { type Replacement struct {
// The source of the value. // The source of the value.
Source *SourceSelector `json:"source" yaml:"source"` Source *SourceSelector `json:"source,omitempty" yaml:"source,omitempty"`
// The N fields to write the value to. // The N fields to write the value to.
Targets []*TargetSelector `json:"targets" yaml:"targets"` Targets []*TargetSelector `json:"targets,omitempty" yaml:"targets,omitempty"`
} }
// SourceSelector is the source of the replacement transformer. // SourceSelector is the source of the replacement transformer.

6
cmd/config/OWNERS Normal file
View File

@@ -0,0 +1,6 @@
# See https://github.com/kubernetes/community/blob/master/community-membership.md
approvers:
- kyaml-approvers
reviewers:
- kyaml-reviewers

View File

@@ -5,7 +5,7 @@ container workflow orchestrator including Tekton, Cloud Build, or run directly u
Run `config help docs-fn-spec` to see the Configuration Functions Specification. Run `config help docs-fn-spec` to see the Configuration Functions Specification.
`kustomize config run` is an example orchestrator for invoking Configuration Functions. This `kustomize fn run` is an example orchestrator for invoking Configuration Functions. This
document describes how to implement and invoke an example function. document describes how to implement and invoke an example function.
## Example Function Implementation ## Example Function Implementation
@@ -28,7 +28,7 @@ The script wraps itself using `config run wrap -- $0` which will:
```bash ```bash
#!/bin/bash #!/bin/bash
# script must run wrapped by "kustomize config run wrap" # script must run wrapped by "kustomize fn run wrap"
# for parsing input the functionConfig into env vars # for parsing input the functionConfig into env vars
if [ -z ${WRAPPED} ]; then if [ -z ${WRAPPED} ]; then
export WRAPPED=true export WRAPPED=true
@@ -82,7 +82,7 @@ End-of-message
### Dockerfile ### Dockerfile
`Dockerfile` installs `kustomize config` and copies the script into the container image. `Dockerfile` installs `kustomize fn` and copies the script into the container image.
``` ```
FROM golang:1.13-stretch FROM golang:1.13-stretch
@@ -94,9 +94,9 @@ CMD ["nginx-template.sh]
## Example Function Usage ## Example Function Usage
Following is an example of running the `kustomize config run` using the preceding API. Following is an example of running the `kustomize fn run` using the preceding API.
When run by `kustomize config run`, functions are run in containers with the When run by `kustomize fn run`, functions are run in containers with the
following environment: following environment:
- Network: `none` - Network: `none`
@@ -129,7 +129,7 @@ spec:
### Output ### Output
The function is invoked using byrunning `kustomize config run dir/`. The function is invoked using byrunning `kustomize fn run dir/`.
`dir/my-instance_deployment.yaml` contains the Deployment: `dir/my-instance_deployment.yaml` contains the Deployment:

View File

@@ -245,8 +245,8 @@ items:
labels: labels:
app: wordpress app: wordpress
annotations: annotations:
config.kubernetes.io/index: "0" internal.config.kubernetes.io/index: "0"
config.kubernetes.io/path: "service.yaml" internal.config.kubernetes.io/path: "service.yaml"
spec: # Example comment spec: # Example comment
type: LoadBalancer type: LoadBalancer
selector: selector:
@@ -271,8 +271,8 @@ items:
labels: labels:
app: wordpress app: wordpress
annotations: annotations:
config.kubernetes.io/index: "0" internal.config.kubernetes.io/index: "0"
config.kubernetes.io/path: "service.yaml" internal.config.kubernetes.io/path: "service.yaml"
spec: # Example comment spec: # Example comment
type: LoadBalancer type: LoadBalancer
selector: selector:

View File

@@ -2,7 +2,7 @@
### Synopsis ### Synopsis
`kustomize config` enables encapsulating function for manipulating Resource `kustomize fn` enables encapsulating function for manipulating Resource
configuration inside containers, which are run using `run`. configuration inside containers, which are run using `run`.
First fetch the kustomize repository, which contains a collection of example First fetch the kustomize repository, which contains a collection of example
@@ -14,7 +14,7 @@
### Templating -- CockroachDB ### Templating -- CockroachDB
This section demonstrates how to leverage templating based solutions from This section demonstrates how to leverage templating based solutions from
`kustomize config`. The templating function is implemented as a `bash` script `kustomize fn`. The templating function is implemented as a `bash` script
using a `heredoc`. using a `heredoc`.
#### 1: Generate the Resources #### 1: Generate the Resources

View File

@@ -16,5 +16,5 @@ require (
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/inf.v0 v0.9.1 gopkg.in/inf.v0 v0.9.1
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e
sigs.k8s.io/kustomize/kyaml v0.11.1 sigs.k8s.io/kustomize/kyaml v0.13.0
) )

View File

@@ -245,8 +245,8 @@ k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
sigs.k8s.io/kustomize/kyaml v0.11.1 h1:MWihd9syKG7VQnAzr/OpKb94FvH+cw96nEV1u3it7pI= sigs.k8s.io/kustomize/kyaml v0.13.0 h1:9c+ETyNfSrVhxvphs+K2dzT3dh5oVPPEqPOE/cUpScY=
sigs.k8s.io/kustomize/kyaml v0.11.1/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E= sigs.k8s.io/kustomize/kyaml v0.13.0/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

View File

@@ -164,6 +164,8 @@ metadata:
a: 'b' a: 'b'
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'f1.yaml' config.kubernetes.io/path: 'f1.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'f1.yaml'
spec: spec:
replicas: 1 replicas: 1
--- ---
@@ -175,6 +177,8 @@ metadata:
a: 'b' a: 'b'
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
config.kubernetes.io/path: 'f1.yaml' config.kubernetes.io/path: 'f1.yaml'
internal.config.kubernetes.io/index: '1'
internal.config.kubernetes.io/path: 'f1.yaml'
spec: spec:
selector: selector:
app: nginx app: nginx
@@ -191,6 +195,8 @@ metadata:
a: 'b' a: 'b'
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'f2.yaml' config.kubernetes.io/path: 'f2.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'f2.yaml'
namespace: bar namespace: bar
spec: spec:
replicas: 3 replicas: 3
@@ -206,6 +212,8 @@ metadata:
a: 'b' a: 'b'
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
config.kubernetes.io/path: 'f2.yaml' config.kubernetes.io/path: 'f2.yaml'
internal.config.kubernetes.io/index: '1'
internal.config.kubernetes.io/path: 'f2.yaml'
namespace: foo namespace: foo
spec: spec:
replicas: 3 replicas: 3
@@ -222,6 +230,8 @@ metadata:
c: 'd' c: 'd'
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'f1.yaml' config.kubernetes.io/path: 'f1.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'f1.yaml'
spec: spec:
replicas: 1 replicas: 1
--- ---
@@ -234,6 +244,8 @@ metadata:
c: 'd' c: 'd'
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
config.kubernetes.io/path: 'f1.yaml' config.kubernetes.io/path: 'f1.yaml'
internal.config.kubernetes.io/index: '1'
internal.config.kubernetes.io/path: 'f1.yaml'
spec: spec:
selector: selector:
app: nginx app: nginx
@@ -251,6 +263,8 @@ metadata:
c: 'd' c: 'd'
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'f2.yaml' config.kubernetes.io/path: 'f2.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'f2.yaml'
namespace: bar namespace: bar
spec: spec:
replicas: 3 replicas: 3
@@ -267,6 +281,8 @@ metadata:
c: 'd' c: 'd'
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
config.kubernetes.io/path: 'f2.yaml' config.kubernetes.io/path: 'f2.yaml'
internal.config.kubernetes.io/index: '1'
internal.config.kubernetes.io/path: 'f2.yaml'
namespace: foo namespace: foo
spec: spec:
replicas: 3 replicas: 3
@@ -281,6 +297,8 @@ metadata:
app: nginx2 app: nginx2
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'f1.yaml' config.kubernetes.io/path: 'f1.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'f1.yaml'
spec: spec:
replicas: 1 replicas: 1
--- ---
@@ -292,6 +310,8 @@ metadata:
a: 'b' a: 'b'
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
config.kubernetes.io/path: 'f1.yaml' config.kubernetes.io/path: 'f1.yaml'
internal.config.kubernetes.io/index: '1'
internal.config.kubernetes.io/path: 'f1.yaml'
spec: spec:
selector: selector:
app: nginx app: nginx
@@ -307,6 +327,8 @@ metadata:
config.kubernetes.io/local-config: "true" config.kubernetes.io/local-config: "true"
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'f2.yaml' config.kubernetes.io/path: 'f2.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'f2.yaml'
namespace: bar namespace: bar
spec: spec:
replicas: 3 replicas: 3
@@ -321,6 +343,8 @@ metadata:
app: nginx app: nginx
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
config.kubernetes.io/path: 'f2.yaml' config.kubernetes.io/path: 'f2.yaml'
internal.config.kubernetes.io/index: '1'
internal.config.kubernetes.io/path: 'f2.yaml'
namespace: foo namespace: foo
spec: spec:
replicas: 3 replicas: 3
@@ -335,6 +359,8 @@ metadata:
app: nginx2 app: nginx2
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'f1.yaml' config.kubernetes.io/path: 'f1.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'f1.yaml'
spec: spec:
replicas: 1 replicas: 1
--- ---
@@ -345,6 +371,8 @@ metadata:
app: nginx app: nginx
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
config.kubernetes.io/path: 'f1.yaml' config.kubernetes.io/path: 'f1.yaml'
internal.config.kubernetes.io/index: '1'
internal.config.kubernetes.io/path: 'f1.yaml'
spec: spec:
selector: selector:
app: nginx app: nginx
@@ -361,6 +389,8 @@ metadata:
a: 'b' a: 'b'
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'f2.yaml' config.kubernetes.io/path: 'f2.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'f2.yaml'
namespace: bar namespace: bar
spec: spec:
replicas: 3 replicas: 3
@@ -375,6 +405,8 @@ metadata:
app: nginx app: nginx
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
config.kubernetes.io/path: 'f2.yaml' config.kubernetes.io/path: 'f2.yaml'
internal.config.kubernetes.io/index: '1'
internal.config.kubernetes.io/path: 'f2.yaml'
namespace: foo namespace: foo
spec: spec:
replicas: 3 replicas: 3
@@ -389,6 +421,8 @@ metadata:
app: nginx2 app: nginx2
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'f1.yaml' config.kubernetes.io/path: 'f1.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'f1.yaml'
spec: spec:
replicas: 1 replicas: 1
--- ---
@@ -399,6 +433,8 @@ metadata:
app: nginx app: nginx
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
config.kubernetes.io/path: 'f1.yaml' config.kubernetes.io/path: 'f1.yaml'
internal.config.kubernetes.io/index: '1'
internal.config.kubernetes.io/path: 'f1.yaml'
spec: spec:
selector: selector:
app: nginx app: nginx
@@ -414,6 +450,8 @@ metadata:
config.kubernetes.io/local-config: "true" config.kubernetes.io/local-config: "true"
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'f2.yaml' config.kubernetes.io/path: 'f2.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'f2.yaml'
namespace: bar namespace: bar
spec: spec:
replicas: 3 replicas: 3
@@ -429,6 +467,8 @@ metadata:
a: 'b' a: 'b'
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
config.kubernetes.io/path: 'f2.yaml' config.kubernetes.io/path: 'f2.yaml'
internal.config.kubernetes.io/index: '1'
internal.config.kubernetes.io/path: 'f2.yaml'
namespace: foo namespace: foo
spec: spec:
replicas: 3 replicas: 3
@@ -443,6 +483,8 @@ metadata:
app: nginx2 app: nginx2
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'f1.yaml' config.kubernetes.io/path: 'f1.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'f1.yaml'
spec: spec:
replicas: 1 replicas: 1
--- ---
@@ -453,6 +495,8 @@ metadata:
app: nginx app: nginx
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
config.kubernetes.io/path: 'f1.yaml' config.kubernetes.io/path: 'f1.yaml'
internal.config.kubernetes.io/index: '1'
internal.config.kubernetes.io/path: 'f1.yaml'
spec: spec:
selector: selector:
app: nginx app: nginx
@@ -469,6 +513,8 @@ metadata:
a: 'b' a: 'b'
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'f2.yaml' config.kubernetes.io/path: 'f2.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'f2.yaml'
namespace: bar namespace: bar
spec: spec:
replicas: 3 replicas: 3
@@ -483,6 +529,8 @@ metadata:
app: nginx app: nginx
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
config.kubernetes.io/path: 'f2.yaml' config.kubernetes.io/path: 'f2.yaml'
internal.config.kubernetes.io/index: '1'
internal.config.kubernetes.io/path: 'f2.yaml'
namespace: foo namespace: foo
spec: spec:
replicas: 3 replicas: 3

View File

@@ -17,6 +17,7 @@ import (
"sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/kio/filters" "sigs.k8s.io/kustomize/kyaml/kio/filters"
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
"sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml"
) )
@@ -165,6 +166,7 @@ func (r *CatRunner) catFilters() []kio.Filter {
return fltrs return fltrs
} }
// nolint
func (r *CatRunner) out(w io.Writer) ([]kio.Writer, error) { func (r *CatRunner) out(w io.Writer) ([]kio.Writer, error) {
var outputs []kio.Writer var outputs []kio.Writer
var functionConfig *yaml.RNode var functionConfig *yaml.RNode
@@ -182,7 +184,7 @@ func (r *CatRunner) out(w io.Writer) ([]kio.Writer, error) {
// remove this annotation explicitly, the ByteWriter won't clear it by // remove this annotation explicitly, the ByteWriter won't clear it by
// default because it doesn't set it // default because it doesn't set it
clear := []string{"config.kubernetes.io/path"} clear := []string{kioutil.LegacyPathAnnotation, kioutil.PathAnnotation}
if r.KeepAnnotations { if r.KeepAnnotations {
clear = nil clear = nil
} }

View File

@@ -5,6 +5,7 @@ package commands
import ( import (
"bytes" "bytes"
"fmt"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
@@ -47,6 +48,7 @@ Environment Variables:
`, `,
RunE: r.runE, RunE: r.runE,
PreRunE: r.preRunE,
SilenceUsage: true, SilenceUsage: true,
FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true}, FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true},
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
@@ -78,6 +80,12 @@ func WrapCommand() *cobra.Command {
return GetWrapRunner().Command return GetWrapRunner().Command
} }
func (r *WrapRunner) preRunE(_ *cobra.Command, _ []string) error {
_, err := fmt.Fprintln(os.Stderr, `Command "wrap" is deprecated, this will no longer be available in kustomize v5.
See discussion in https://github.com/kubernetes-sigs/kustomize/issues/3953.`)
return err
}
func (r *WrapRunner) runE(c *cobra.Command, args []string) error { func (r *WrapRunner) runE(c *cobra.Command, args []string) error {
if r.getEnv == nil { if r.getEnv == nil {
r.getEnv = os.Getenv r.getEnv = os.Getenv

View File

@@ -14,7 +14,7 @@ import (
) )
const ( const (
input = `apiVersion: config.kubernetes.io/v1alpha1 input = `apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
functionConfig: functionConfig:
metadata: metadata:
@@ -68,7 +68,7 @@ items:
name: test name: test
` `
output = `apiVersion: config.kubernetes.io/v1alpha1 output = `apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- apiVersion: apps/v1 - apiVersion: apps/v1
@@ -81,6 +81,8 @@ items:
annotations: annotations:
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'config/test_deployment.yaml' config.kubernetes.io/path: 'config/test_deployment.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'config/test_deployment.yaml'
spec: spec:
replicas: 11 replicas: 11
selector: selector:
@@ -112,6 +114,8 @@ items:
annotations: annotations:
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'config/test_service.yaml' config.kubernetes.io/path: 'config/test_service.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'config/test_service.yaml'
spec: spec:
selector: selector:
name: test name: test
@@ -123,7 +127,7 @@ items:
targetPort: 8080 targetPort: 8080
` `
outputNoMerge = `apiVersion: config.kubernetes.io/v1alpha1 outputNoMerge = `apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- apiVersion: apps/v1 - apiVersion: apps/v1
@@ -136,6 +140,8 @@ items:
annotations: annotations:
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'config/test_deployment.yaml' config.kubernetes.io/path: 'config/test_deployment.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'config/test_deployment.yaml'
spec: spec:
replicas: 11 replicas: 11
selector: selector:
@@ -164,6 +170,8 @@ items:
annotations: annotations:
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'config/test_service.yaml' config.kubernetes.io/path: 'config/test_service.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'config/test_service.yaml'
spec: spec:
selector: selector:
name: test name: test
@@ -175,7 +183,7 @@ items:
targetPort: 8080 targetPort: 8080
` `
outputOverride = `apiVersion: config.kubernetes.io/v1alpha1 outputOverride = `apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- apiVersion: apps/v1 - apiVersion: apps/v1
@@ -186,6 +194,8 @@ items:
annotations: annotations:
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'config/mysql-deployment_deployment.yaml' config.kubernetes.io/path: 'config/mysql-deployment_deployment.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'config/mysql-deployment_deployment.yaml'
spec: spec:
replicas: 3 replicas: 3
template: template:
@@ -201,6 +211,8 @@ items:
annotations: annotations:
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'config/nosetters-deployment_deployment.yaml' config.kubernetes.io/path: 'config/nosetters-deployment_deployment.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'config/nosetters-deployment_deployment.yaml'
spec: spec:
replicas: 4 replicas: 4
template: template:
@@ -216,6 +228,8 @@ items:
annotations: annotations:
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'config/storage-deployment_deployment.yaml' config.kubernetes.io/path: 'config/storage-deployment_deployment.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'config/storage-deployment_deployment.yaml'
spec: spec:
replicas: 4 replicas: 4
template: template:
@@ -233,6 +247,8 @@ items:
annotations: annotations:
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'config/test_deployment.yaml' config.kubernetes.io/path: 'config/test_deployment.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'config/test_deployment.yaml'
spec: spec:
replicas: 11 replicas: 11
selector: selector:
@@ -264,6 +280,8 @@ items:
annotations: annotations:
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'config/test_service.yaml' config.kubernetes.io/path: 'config/test_service.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'config/test_service.yaml'
spec: spec:
selector: selector:
name: test name: test

View File

@@ -60,6 +60,7 @@ $ kyaml cat pkg/ --function-config config.yaml --wrap-kind ResourceList | kyaml
`, `,
RunE: r.runE, RunE: r.runE,
PreRunE: r.preRunE,
SilenceUsage: true, SilenceUsage: true,
FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true}, FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true},
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
@@ -84,6 +85,12 @@ func XArgsCommand() *cobra.Command {
return GetXArgsRunner().Command return GetXArgsRunner().Command
} }
func (r *XArgsRunner) preRunE(_ *cobra.Command, _ []string) error {
_, err := fmt.Fprintln(os.Stderr, `Command "xargs" is deprecated, this will no longer be available in kustomize v5.
See discussion in https://github.com/kubernetes-sigs/kustomize/issues/3953.`)
return err
}
func (r *XArgsRunner) runE(c *cobra.Command, _ []string) error { func (r *XArgsRunner) runE(c *cobra.Command, _ []string) error {
if len(r.Args) == 0 { if len(r.Args) == 0 {
r.Args = os.Args r.Args = os.Args

View File

@@ -39,7 +39,7 @@ functionConfig:
- 4 - 4
` `
resourceInput = `apiVersion: config.kubernetes.io/v1alpha1 resourceInput = `apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- apiVersion: apps/v1 - apiVersion: apps/v1

View File

@@ -79,6 +79,8 @@ metadata:
app: nginx2 app: nginx2
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'f1.yaml' config.kubernetes.io/path: 'f1.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'f1.yaml'
spec: spec:
replicas: 1 replicas: 1
--- ---
@@ -89,6 +91,8 @@ metadata:
app: nginx app: nginx
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
config.kubernetes.io/path: 'f1.yaml' config.kubernetes.io/path: 'f1.yaml'
internal.config.kubernetes.io/index: '1'
internal.config.kubernetes.io/path: 'f1.yaml'
spec: spec:
selector: selector:
app: nginx app: nginx
@@ -146,6 +150,7 @@ metadata:
annotations: annotations:
app: nginx2 app: nginx2
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
internal.config.kubernetes.io/index: '0'
spec: spec:
replicas: 1 replicas: 1
--- ---
@@ -155,6 +160,7 @@ metadata:
annotations: annotations:
app: nginx app: nginx
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
internal.config.kubernetes.io/index: '1'
spec: spec:
selector: selector:
app: nginx app: nginx
@@ -295,6 +301,8 @@ metadata:
annotations: annotations:
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'deployment.yaml' config.kubernetes.io/path: 'deployment.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'deployment.yaml'
spec: spec:
replicas: 3 replicas: 3
template: template:
@@ -314,6 +322,8 @@ metadata:
annotations: annotations:
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'deployment.yaml' config.kubernetes.io/path: 'deployment.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'deployment.yaml'
spec: spec:
replicas: 4 replicas: 4
template: template:
@@ -339,6 +349,8 @@ metadata:
annotations: annotations:
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'deployment.yaml' config.kubernetes.io/path: 'deployment.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'deployment.yaml'
spec: spec:
replicas: 3 replicas: 3
template: template:
@@ -364,6 +376,8 @@ metadata:
annotations: annotations:
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'deployment.yaml' config.kubernetes.io/path: 'deployment.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'deployment.yaml'
spec: spec:
replicas: 4 replicas: 4
template: template:

View File

@@ -4,6 +4,9 @@
package commands package commands
import ( import (
"fmt"
"os"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner" "sigs.k8s.io/kustomize/cmd/config/runner"
@@ -20,6 +23,7 @@ func GetSinkRunner(name string) *SinkRunner {
Long: commands.SinkLong, Long: commands.SinkLong,
Example: commands.SinkExamples, Example: commands.SinkExamples,
RunE: r.runE, RunE: r.runE,
PreRunE: r.preRunE,
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
} }
runner.FixDocs(name, c) runner.FixDocs(name, c)
@@ -36,6 +40,13 @@ type SinkRunner struct {
Command *cobra.Command Command *cobra.Command
} }
func (r *SinkRunner) preRunE(c *cobra.Command, args []string) error {
_, err := fmt.Fprintln(os.Stderr, `Command "sink" is deprecated, this will no longer be available in kustomize v5.
See discussion in https://github.com/kubernetes-sigs/kustomize/issues/3953.`)
return err
}
// nolint
func (r *SinkRunner) runE(c *cobra.Command, args []string) error { func (r *SinkRunner) runE(c *cobra.Command, args []string) error {
var outputs []kio.Writer var outputs []kio.Writer
if len(args) == 1 { if len(args) == 1 {
@@ -43,7 +54,7 @@ func (r *SinkRunner) runE(c *cobra.Command, args []string) error {
} else { } else {
outputs = []kio.Writer{&kio.ByteWriter{ outputs = []kio.Writer{&kio.ByteWriter{
Writer: c.OutOrStdout(), Writer: c.OutOrStdout(),
ClearAnnotations: []string{kioutil.PathAnnotation}}, ClearAnnotations: []string{kioutil.PathAnnotation, kioutil.LegacyPathAnnotation}},
} }
} }

View File

@@ -22,7 +22,7 @@ func TestSinkCommand(t *testing.T) {
defer os.RemoveAll(d) defer os.RemoveAll(d)
r := commands.GetSinkRunner("") r := commands.GetSinkRunner("")
r.Command.SetIn(bytes.NewBufferString(`apiVersion: config.kubernetes.io/v1alpha1 r.Command.SetIn(bytes.NewBufferString(`apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- kind: Deployment - kind: Deployment
@@ -144,7 +144,7 @@ func TestSinkCommandJSON(t *testing.T) {
defer os.RemoveAll(d) defer os.RemoveAll(d)
r := commands.GetSinkRunner("") r := commands.GetSinkRunner("")
r.Command.SetIn(bytes.NewBufferString(`apiVersion: config.kubernetes.io/v1alpha1 r.Command.SetIn(bytes.NewBufferString(`apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- {"kind": "Deployment", "metadata": {"labels": {"app": "nginx2"}, "name": "foo", - {"kind": "Deployment", "metadata": {"labels": {"app": "nginx2"}, "name": "foo",
@@ -191,7 +191,7 @@ func TestSinkCommand_Stdout(t *testing.T) {
// fmt the files // fmt the files
out := &bytes.Buffer{} out := &bytes.Buffer{}
r := commands.GetSinkRunner("") r := commands.GetSinkRunner("")
r.Command.SetIn(bytes.NewBufferString(`apiVersion: config.kubernetes.io/v1alpha1 r.Command.SetIn(bytes.NewBufferString(`apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- kind: Deployment - kind: Deployment
@@ -305,7 +305,7 @@ func TestSinkCommandJSON_Stdout(t *testing.T) {
// fmt the files // fmt the files
out := &bytes.Buffer{} out := &bytes.Buffer{}
r := commands.GetSinkRunner("") r := commands.GetSinkRunner("")
r.Command.SetIn(bytes.NewBufferString(`apiVersion: config.kubernetes.io/v1alpha1 r.Command.SetIn(bytes.NewBufferString(`apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- {"kind": "Deployment", "metadata": {"labels": {"app": "nginx2"}, "name": "foo", - {"kind": "Deployment", "metadata": {"labels": {"app": "nginx2"}, "name": "foo",

View File

@@ -5,6 +5,7 @@ package commands
import ( import (
"fmt" "fmt"
"os"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
@@ -22,6 +23,7 @@ func GetSourceRunner(name string) *SourceRunner {
Long: commands.SourceLong, Long: commands.SourceLong,
Example: commands.SourceExamples, Example: commands.SourceExamples,
RunE: r.runE, RunE: r.runE,
PreRunE: r.preRunE,
} }
runner.FixDocs(name, c) runner.FixDocs(name, c)
c.Flags().StringVar(&r.WrapKind, "wrap-kind", kio.ResourceListKind, c.Flags().StringVar(&r.WrapKind, "wrap-kind", kio.ResourceListKind,
@@ -47,6 +49,12 @@ type SourceRunner struct {
Command *cobra.Command Command *cobra.Command
} }
func (r *SourceRunner) preRunE(c *cobra.Command, args []string) error {
_, err := fmt.Fprintln(os.Stderr, `Command "source" is deprecated, this will no longer be available in kustomize v5.
See discussion in https://github.com/kubernetes-sigs/kustomize/issues/3953.`)
return err
}
func (r *SourceRunner) runE(c *cobra.Command, args []string) error { func (r *SourceRunner) runE(c *cobra.Command, args []string) error {
// if there is a function-config specified, emit it // if there is a function-config specified, emit it
var functionConfig *yaml.RNode var functionConfig *yaml.RNode

View File

@@ -81,7 +81,7 @@ spec:
return return
} }
if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1 if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- kind: Deployment - kind: Deployment
@@ -93,6 +93,8 @@ items:
app: nginx2 app: nginx2
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'f1.yaml' config.kubernetes.io/path: 'f1.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'f1.yaml'
spec: spec:
replicas: 1 replicas: 1
- kind: Service - kind: Service
@@ -102,6 +104,8 @@ items:
app: nginx app: nginx
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
config.kubernetes.io/path: 'f1.yaml' config.kubernetes.io/path: 'f1.yaml'
internal.config.kubernetes.io/index: '1'
internal.config.kubernetes.io/path: 'f1.yaml'
spec: spec:
selector: selector:
app: nginx app: nginx
@@ -116,6 +120,8 @@ items:
config.kubernetes.io/local-config: "true" config.kubernetes.io/local-config: "true"
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'f2.yaml' config.kubernetes.io/path: 'f2.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'f2.yaml'
spec: spec:
replicas: 3 replicas: 3
- apiVersion: apps/v1 - apiVersion: apps/v1
@@ -128,6 +134,8 @@ items:
app: nginx app: nginx
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
config.kubernetes.io/path: 'f2.yaml' config.kubernetes.io/path: 'f2.yaml'
internal.config.kubernetes.io/index: '1'
internal.config.kubernetes.io/path: 'f2.yaml'
spec: spec:
replicas: 3 replicas: 3
`, b.String()) { `, b.String()) {
@@ -191,11 +199,11 @@ func TestSourceCommandJSON(t *testing.T) {
return return
} }
if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1 if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- {"kind": "Deployment", "metadata": {"labels": {"app": "nginx2"}, "name": "foo", "annotations": {"app": "nginx2", config.kubernetes.io/index: '0', config.kubernetes.io/path: 'f1.json'}}, "spec": {"replicas": 1}} - {"kind": "Deployment", "metadata": {"labels": {"app": "nginx2"}, "name": "foo", "annotations": {"app": "nginx2", config.kubernetes.io/index: '0', config.kubernetes.io/path: 'f1.json', internal.config.kubernetes.io/index: '0', internal.config.kubernetes.io/path: 'f1.json'}}, "spec": {"replicas": 1}}
- {"apiVersion": "v1", "kind": "Abstraction", "metadata": {"name": "foo", "annotations": {"config.kubernetes.io/function": "container:\n image: gcr.io/example/reconciler:v1\n", "config.kubernetes.io/local-config": "true", config.kubernetes.io/index: '0', config.kubernetes.io/path: 'f2.json'}}, "spec": {"replicas": 3}} - {"apiVersion": "v1", "kind": "Abstraction", "metadata": {"name": "foo", "annotations": {"config.kubernetes.io/function": "container:\n image: gcr.io/example/reconciler:v1\n", "config.kubernetes.io/local-config": "true", config.kubernetes.io/index: '0', config.kubernetes.io/path: 'f2.json', internal.config.kubernetes.io/index: '0', internal.config.kubernetes.io/path: 'f2.json'}}, "spec": {"replicas": 3}}
`, b.String()) { `, b.String()) {
return return
} }
@@ -238,7 +246,7 @@ spec:
return return
} }
if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1 if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- kind: Deployment - kind: Deployment
@@ -249,6 +257,7 @@ items:
annotations: annotations:
app: nginx2 app: nginx2
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
internal.config.kubernetes.io/index: '0'
spec: spec:
replicas: 1 replicas: 1
- kind: Service - kind: Service
@@ -257,6 +266,7 @@ items:
annotations: annotations:
app: nginx app: nginx
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
internal.config.kubernetes.io/index: '1'
spec: spec:
selector: selector:
app: nginx app: nginx
@@ -299,10 +309,10 @@ func TestSourceCommandJSON_Stdin(t *testing.T) {
return return
} }
if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1 if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- {"kind": "Deployment", "metadata": {"labels": {"app": "nginx2"}, "name": "foo", "annotations": {"app": "nginx2", config.kubernetes.io/index: '0'}}, "spec": {"replicas": 1}} - {"kind": "Deployment", "metadata": {"labels": {"app": "nginx2"}, "name": "foo", "annotations": {"app": "nginx2", config.kubernetes.io/index: '0', internal.config.kubernetes.io/index: '0'}}, "spec": {"replicas": 1}}
`, out.String()) { `, out.String()) {
return return
} }

View File

@@ -61,15 +61,16 @@ Example:
annotations: annotations:
config.kubernetes.io/local-config: "true"` config.kubernetes.io/local-config: "true"`
var FunctionsImplShort = `Following is an example for implementing an nginx abstraction using a configuration` var (
var FunctionsImplLong = `# Running Configuration Functions using kustomize CLI FunctionsImplShort = `Following is an example for implementing an nginx abstraction using a configuration`
FunctionsImplLong = `# Running Configuration Functions using kustomize CLI
Configuration functions can be implemented using any toolchain and invoked using any Configuration functions can be implemented using any toolchain and invoked using any
container workflow orchestrator including Tekton, Cloud Build, or run directly using ` + "`" + `docker run` + "`" + `. container workflow orchestrator including Tekton, Cloud Build, or run directly using ` + "`" + `docker run` + "`" + `.
Run ` + "`" + `config help docs-fn-spec` + "`" + ` to see the Configuration Functions Specification. Run ` + "`" + `config help docs-fn-spec` + "`" + ` to see the Configuration Functions Specification.
` + "`" + `kustomize config run` + "`" + ` is an example orchestrator for invoking Configuration Functions. This ` + "`" + `kustomize fn run` + "`" + ` is an example orchestrator for invoking Configuration Functions. This
document describes how to implement and invoke an example function. document describes how to implement and invoke an example function.
function. function.
@@ -88,7 +89,7 @@ The script wraps itself using ` + "`" + `config run wrap -- $0` + "`" + ` which
4. Format the output 4. Format the output
#!/bin/bash #!/bin/bash
# script must run wrapped by "kustomize config run wrap" # script must run wrapped by "kustomize fn run wrap"
# for parsing input the functionConfig into env vars # for parsing input the functionConfig into env vars
if [ -z ${WRAPPED} ]; then if [ -z ${WRAPPED} ]; then
export WRAPPED=true export WRAPPED=true
@@ -141,7 +142,7 @@ The script wraps itself using ` + "`" + `config run wrap -- $0` + "`" + ` which
### Dockerfile ### Dockerfile
` + "`" + `Dockerfile` + "`" + ` installs ` + "`" + `kustomize config` + "`" + ` and copies the script into the container image. ` + "`" + `Dockerfile` + "`" + ` installs ` + "`" + `kustomize fn` + "`" + ` and copies the script into the container image.
FROM golang:1.13-stretch FROM golang:1.13-stretch
RUN go get sigs.k8s.io/kustomize/cmd/config RUN go get sigs.k8s.io/kustomize/cmd/config
@@ -151,9 +152,9 @@ The script wraps itself using ` + "`" + `config run wrap -- $0` + "`" + ` which
## Example Function Usage ## Example Function Usage
Following is an example of running the ` + "`" + `kustomize config run` + "`" + ` using the preceding API. Following is an example of running the ` + "`" + `kustomize fn run` + "`" + ` using the preceding API.
When run by ` + "`" + `kustomize config run` + "`" + `, functions are run in containers with the When run by ` + "`" + `kustomize fn run` + "`" + `, functions are run in containers with the
following environment: following environment:
- Network: ` + "`" + `none` + "`" + ` - Network: ` + "`" + `none` + "`" + `
@@ -184,7 +185,7 @@ are passed to the Function through the ` + "`" + `ResourceList.functionConfig` +
### Output ### Output
The function is invoked using byrunning ` + "`" + `kustomize config run dir/` + "`" + `. The function is invoked using byrunning ` + "`" + `kustomize fn run dir/` + "`" + `.
` + "`" + `dir/my-instance_deployment.yaml` + "`" + ` contains the Deployment: ` + "`" + `dir/my-instance_deployment.yaml` + "`" + ` contains the Deployment:
@@ -230,9 +231,11 @@ The function is invoked using byrunning ` + "`" + `kustomize config run dir/` +
selector: selector:
app: nginx app: nginx
instance: my-instance` instance: my-instance`
)
var FunctionsSpecShort = `_Configuration functions_ enable shift-left practices (client-side) through:` var (
var FunctionsSpecLong = `# Configuration Functions Specification FunctionsSpecShort = `_Configuration functions_ enable shift-left practices (client-side) through:`
FunctionsSpecLong = `# Configuration Functions Specification
This document specifies a standard for client-side functions that operate on This document specifies a standard for client-side functions that operate on
Kubernetes declarative configurations. This standard enables creating Kubernetes declarative configurations. This standard enables creating
@@ -408,6 +411,7 @@ A non-zero exit code indicates a failure.
[1]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md [1]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md
[2]: https://tools.ietf.org/html/rfc2119 [2]: https://tools.ietf.org/html/rfc2119
[3]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds` [3]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds`
)
var Merge2Long = `# Merge (2-way) var Merge2Long = `# Merge (2-way)

View File

@@ -2,6 +2,7 @@
package tutorials package tutorials
var ConfigurationBasicsShort = `### Synopsis` var ConfigurationBasicsShort = `### Synopsis`
var ConfigurationBasicsLong = ` var ConfigurationBasicsLong = `
` + "`" + `kustomize cfg` + "`" + ` provides tools for working with local configuration directories. ` + "`" + `kustomize cfg` + "`" + ` provides tools for working with local configuration directories.
@@ -274,9 +275,10 @@ var ConfigurationBasicsLong = `
│   └── image: <YOUR-CONTAINER> │   └── image: <YOUR-CONTAINER>
...` ...`
var FunctionBasicsShort = `### Synopsis` var (
var FunctionBasicsLong = ` FunctionBasicsShort = `### Synopsis`
` + "`" + `kustomize config` + "`" + ` enables encapsulating function for manipulating Resource FunctionBasicsLong = `
` + "`" + `kustomize fn` + "`" + ` enables encapsulating function for manipulating Resource
configuration inside containers, which are run using ` + "`" + `run` + "`" + `. configuration inside containers, which are run using ` + "`" + `run` + "`" + `.
First fetch the kustomize repository, which contains a collection of example First fetch the kustomize repository, which contains a collection of example
@@ -288,7 +290,7 @@ var FunctionBasicsLong = `
### Templating -- CockroachDB ### Templating -- CockroachDB
This section demonstrates how to leverage templating based solutions from This section demonstrates how to leverage templating based solutions from
` + "`" + `kustomize config` + "`" + `. The templating function is implemented as a ` + "`" + `bash` + "`" + ` script ` + "`" + `kustomize fn` + "`" + `. The templating function is implemented as a ` + "`" + `bash` + "`" + ` script
using a ` + "`" + `heredoc` + "`" + `. using a ` + "`" + `heredoc` + "`" + `.
#### 1: Generate the Resources #### 1: Generate the Resources
@@ -455,3 +457,4 @@ Functions may be composed together. Try putting the Injection (tshirt-size) and
Validation functions together in the same .yaml file (separated by ` + "`" + `---` + "`" + `). Run Validation functions together in the same .yaml file (separated by ` + "`" + `---` + "`" + `). Run
` + "`" + `run` + "`" + ` and observe that the first function in the file is applied to the Resources, ` + "`" + `run` + "`" + ` and observe that the first function in the file is applied to the Resources,
and then the second function in the file is applied.` and then the second function in the file is applied.`
)

View File

@@ -129,7 +129,7 @@ var ExitOnError bool
// StackOnError if true, will print a stack trace on failure. // StackOnError if true, will print a stack trace on failure.
var StackOnError bool var StackOnError bool
const cmdName = "kustomize config" const cmdName = "kustomize fn"
// FixDocs replaces instances of old with new in the docs for c // FixDocs replaces instances of old with new in the docs for c
func FixDocs(new string, c *cobra.Command) { func FixDocs(new string, c *cobra.Command) {

View File

@@ -278,12 +278,13 @@ func (gr *Runner) CheckoutReleaseBranch(
return nil return nil
} }
gr.comment("creating branch") gr.comment("creating branch")
// The branch doesn't exist. Create it. // The branch doesn't exist remotely. Create or reset it locally.
out, err := gr.run(noHarmDone, "checkout", "-b", branch) out, err := gr.run(noHarmDone, "checkout", "-B", branch)
if err != nil { if err != nil {
return err return err
} }
if !strings.Contains(out, "Switched to a new branch ") { // Expected strings: "Switched to a new branch" or "Switched to and reset branch"
if !strings.Contains(out, "Switched to") {
return fmt.Errorf("unexpected branch creation output: %q", out) return fmt.Errorf("unexpected branch creation output: %q", out)
} }
return nil return nil

View File

@@ -6,8 +6,8 @@ require (
github.com/rakyll/statik v0.1.7 github.com/rakyll/statik v0.1.7
github.com/spf13/cobra v1.0.0 github.com/spf13/cobra v1.0.0
github.com/stretchr/testify v1.5.1 github.com/stretchr/testify v1.5.1
sigs.k8s.io/kustomize/api v0.8.11 sigs.k8s.io/kustomize/api v0.10.0
sigs.k8s.io/kustomize/kyaml v0.11.1 sigs.k8s.io/kustomize/kyaml v0.13.0
) )
replace sigs.k8s.io/kustomize/api => ../../api replace sigs.k8s.io/kustomize/api => ../../api

View File

@@ -228,8 +228,8 @@ k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
sigs.k8s.io/kustomize/kyaml v0.11.1 h1:MWihd9syKG7VQnAzr/OpKb94FvH+cw96nEV1u3it7pI= sigs.k8s.io/kustomize/kyaml v0.13.0 h1:9c+ETyNfSrVhxvphs+K2dzT3dh5oVPPEqPOE/cUpScY=
sigs.k8s.io/kustomize/kyaml v0.11.1/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E= sigs.k8s.io/kustomize/kyaml v0.13.0/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

View File

@@ -74,7 +74,7 @@ func (p *plugin) Transform(rm resmap.ResMap) error {
func getTransformerInputResource() []byte { func getTransformerInputResource() []byte {
return []byte(` return []byte(`
apiVersion: config.kubernetes.io/v1beta1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
functionConfig: functionConfig:
apiVersion: foo-corp.com/v1 apiVersion: foo-corp.com/v1
@@ -128,7 +128,7 @@ func TestTransformerConverter(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
output := runKrmFunction(t, getTransformerInputResource(), filepath.Join(dir, "output")) output := runKrmFunction(t, getTransformerInputResource(), filepath.Join(dir, "output"))
assert.Equal(t, `apiVersion: config.kubernetes.io/v1beta1 assert.Equal(t, `apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- apiVersion: apps/v1 - apiVersion: apps/v1
@@ -193,7 +193,7 @@ func (p *plugin) Generate() (resmap.ResMap, error) {
func getGeneratorInputResource() []byte { func getGeneratorInputResource() []byte {
return []byte(` return []byte(`
apiVersion: config.kubernetes.io/v1beta1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
functionConfig: functionConfig:
apiVersion: foo-corp.com/v1 apiVersion: foo-corp.com/v1
@@ -224,7 +224,7 @@ func TestGeneratorConverter(t *testing.T) {
err := c.Convert() err := c.Convert()
assert.NoError(t, err) assert.NoError(t, err)
output := runKrmFunction(t, getGeneratorInputResource(), filepath.Join(dir, "output")) output := runKrmFunction(t, getGeneratorInputResource(), filepath.Join(dir, "output"))
assert.Equal(t, `apiVersion: config.kubernetes.io/v1beta1 assert.Equal(t, `apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- apiVersion: v1 - apiVersion: v1

View File

@@ -23,14 +23,12 @@ Kustomize provides two ways of adding ConfigMap in one `kustomization`, either b
The ConfigMaps declared as [resource] are treated the same way as other resources. Kustomize doesn't append any hash to the ConfigMap name. The ConfigMap declared from a ConfigMapGenerator is treated differently. A hash is appended to the name and any change in the ConfigMap will trigger a rolling update. The ConfigMaps declared as [resource] are treated the same way as other resources. Kustomize doesn't append any hash to the ConfigMap name. The ConfigMap declared from a ConfigMapGenerator is treated differently. A hash is appended to the name and any change in the ConfigMap will trigger a rolling update.
In this demo, the same [hello_world](helloWorld/README.md) is used while the ConfigMap declared as [resources] is replaced by a ConfigMap declared from a ConfigmapGenerator. The change in this ConfigMap will result in a hash change and a rolling update. In this demo, the same [hello_world](helloWorld/README.md) is used while the ConfigMap declared as [resources] is replaced by a ConfigMap declared from a ConfigMapGenerator. The change in this ConfigMap will result in a hash change and a rolling update.
### Establish base and staging ### Establish base and staging
Establish the base with a configMapGenerator Establish the base with a `configMapGenerator`:
<!-- @establishBase @testAgainstLatestRelease --> <!-- @establishBase @testAgainstLatestRelease -->
``` ```
DEMO_HOME=$(mktemp -d) DEMO_HOME=$(mktemp -d)
@@ -92,7 +90,7 @@ EOF
### Review ### Review
The _hello-world_ deployment running in this cluster is The _hello-world_ deployment running in this cluster is
configured with data from a configMap. configured with data from a ConfigMap.
The deployment refers to this map by name: The deployment refers to this map by name:
@@ -102,26 +100,26 @@ The deployment refers to this map by name:
grep -C 2 configMapKeyRef $BASE/deployment.yaml grep -C 2 configMapKeyRef $BASE/deployment.yaml
``` ```
Changing the data held by a live configMap in a cluster Changing the data held by a live ConfigMap in a cluster
is considered bad practice. Deployments have no means is considered bad practice. Deployments have no means
to know that the configMaps they refer to have to know that the ConfigMaps they refer to have
changed, so such updates have no effect. changed, so such updates have no effect.
The recommended way to change a deployment's The recommended way to change a deployment's
configuration is to configuration is to
1. create a new configMap with a new name, 1. create a new ConfigMap with a new name,
1. patch the _deployment_, modifying the name value of 1. patch the _deployment_, modifying the name value of
the appropriate `configMapKeyRef` field. the appropriate `configMapKeyRef` field.
This latter change initiates rolling update to the pods This latter change initiates rolling update to the pods
in the deployment. The older configMap, when no longer in the deployment. The older ConfigMap, when no longer
referenced by any other resource, is eventually [garbage referenced by any other resource, is eventually [garbage
collected](/../../issues/242). collected](/../../issues/242).
### How this works with kustomize ### How this works with kustomize
The _staging_ [variant] here has a configMap [patch]: The _staging_ [variant] here has a ConfigMap [patch]:
<!-- @showMapPatch @testAgainstLatestRelease --> <!-- @showMapPatch @testAgainstLatestRelease -->
@@ -133,7 +131,7 @@ This patch is by definition a named but not necessarily
complete resource spec intended to modify a complete complete resource spec intended to modify a complete
resource spec. resource spec.
The ConfigMap it modifies is declared from a configMapGenerator. The ConfigMap it modifies is declared from a `configMapGenerator`.
<!-- @showMapBase @testAgainstLatestRelease --> <!-- @showMapBase @testAgainstLatestRelease -->
@@ -156,15 +154,15 @@ kustomize build $OVERLAYS/staging |\
grep -B 8 -A 1 staging-the-map grep -B 8 -A 1 staging-the-map
``` ```
The configMap name is prefixed by _staging-_, per the The ConfigMap name is prefixed by _staging-_, per the
`namePrefix` field in `namePrefix` field in
`$OVERLAYS/staging/kustomization.yaml`. `$OVERLAYS/staging/kustomization.yaml`.
The configMap name is suffixed by _-v1_, per the The ConfigMap name is suffixed by _-v1_, per the
`nameSuffix` field in `nameSuffix` field in
`$OVERLAYS/staging/kustomization.yaml`. `$OVERLAYS/staging/kustomization.yaml`.
The suffix to the configMap name is generated from a The suffix to the ConfigMap name is generated from a
hash of the maps content - in this case the name suffix hash of the maps content - in this case the name suffix
is _5276h4th55_: is _5276h4th55_:
@@ -190,7 +188,7 @@ kustomize build $OVERLAYS/staging |\
grep -B 2 -A 3 kiwi grep -B 2 -A 3 kiwi
``` ```
Run kustomize again to see the new configMap names: Run kustomize again to see the new ConfigMap names:
<!-- @grepStagingName @testAgainstLatestRelease --> <!-- @grepStagingName @testAgainstLatestRelease -->
@@ -199,9 +197,9 @@ kustomize build $OVERLAYS/staging |\
grep -B 8 -A 1 staging-the-map grep -B 8 -A 1 staging-the-map
``` ```
Confirm that the change in configMap content resulted Confirm that the change in ConfigMap content resulted
in three new names ending in _c2g8fcbf88_ - one in the in three new names ending in _c2g8fcbf88_ - one in the
configMap name itself, and two in the deployment that ConfigMap name itself, and two in the deployment that
uses the map: uses the map:
<!-- @countHashes @testAgainstLatestRelease --> <!-- @countHashes @testAgainstLatestRelease -->

View File

@@ -148,7 +148,7 @@ commonLabels:
org: acmeCorporation org: acmeCorporation
commonAnnotations: commonAnnotations:
note: Hello, I am staging! note: Hello, I am staging!
bases: resources:
- ../../base - ../../base
patchesStrategicMerge: patchesStrategicMerge:
- map.yaml - map.yaml
@@ -189,7 +189,7 @@ commonLabels:
org: acmeCorporation org: acmeCorporation
commonAnnotations: commonAnnotations:
note: Hello, I am production! note: Hello, I am production!
bases: resources:
- ../../base - ../../base
patchesStrategicMerge: patchesStrategicMerge:
- deployment.yaml - deployment.yaml

View File

@@ -22,17 +22,17 @@ a _target selector_:
> group: <optional group> > group: <optional group>
> version: <optional version> > version: <optional version>
> kind: <optional kind> > kind: <optional kind>
> name: <optional name> > name: <optional name or regex pattern>
> namespace: <optional namespace> > namespace: <optional namespace>
> labelSelector: <optional label selector> > labelSelector: <optional label selector>
> annotationSelector: <optional annotation selector> > annotationSelector: <optional annotation selector>
> ``` > ```
E.g. select resources with _name_ matching `foo*`: E.g. select resources with _name_ matching the regular expression `foo.*`:
> ```yaml > ```yaml
> target: > target:
> name: foo* > name: foo.*
> ``` > ```
Select all resources of _kind_ `Deployment`: Select all resources of _kind_ `Deployment`:

View File

@@ -17,7 +17,7 @@ Resource configuration, and looks for invalid configuration.
The function is invoked by authoring a [local Resource](local-resource) The function is invoked by authoring a [local Resource](local-resource)
with `metadata.annotations.[config.kubernetes.io/function]` and running: with `metadata.annotations.[config.kubernetes.io/function]` and running:
kustomize config run local-resource/ --fn-path config/ kustomize fn run local-resource/ --fn-path config/
This exits non-zero if there is an error. This exits non-zero if there is an error.
@@ -25,6 +25,6 @@ This exits non-zero if there is an error.
Run the validator with: Run the validator with:
kustomize config run local-resource/ --fn-path config/ kustomize fn run local-resource/ --fn-path config/
This will append an Application CR. This will append an Application CR.

View File

@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Package main implements adding an Application CR to a group of resources and // Package main implements adding an Application CR to a group of resources and
// is run with `kustomize config run -- DIR/`. // is run with `kustomize fn run -- DIR/`.
package main package main
import ( import (
@@ -82,7 +82,6 @@ func (f appCRFilter) Filter(in []*yaml.RNode) ([]*yaml.RNode, error) {
return append(in, app), nil return append(in, app), nil
} }
return in, nil return in, nil
} }
// parseAPI parses the functionConfig into an API struct. // parseAPI parses the functionConfig into an API struct.

View File

@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Package main implements adding an Application CR to a group of resources and // Package main implements adding an Application CR to a group of resources and
// is run with `kustomize config run -- DIR/`. // is run with `kustomize fn run -- DIR/`.
package main package main
import ( import (
@@ -13,7 +13,7 @@ import (
"testing" "testing"
) )
var input = `apiVersion: config.kubernetes.io/v1alpha1 var input = `apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- apiVersion: v1 - apiVersion: v1
@@ -89,7 +89,7 @@ functionConfig:
url: https://metrics/internal/worldpress-01/web-app url: https://metrics/internal/worldpress-01/web-app
` `
var output = `apiVersion: config.kubernetes.io/v1alpha1 var output = `apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- apiVersion: v1 - apiVersion: v1

View File

@@ -17,7 +17,7 @@ Resource configuration, and looks for invalid configuration.
The function is invoked by authoring a [local Resource](local-resource) The function is invoked by authoring a [local Resource](local-resource)
with `metadata.annotations.[config.kubernetes.io/function]` and running: with `metadata.annotations.[config.kubernetes.io/function]` and running:
kustomize config run local-resource/ kustomize fn run local-resource/
This exits non-zero if there is an error. This exits non-zero if there is an error.
@@ -25,11 +25,11 @@ This exits non-zero if there is an error.
Run the validator with: Run the validator with:
kustomize config run local-resource/ kustomize fn run local-resource/
This will add resource reservations to the Deployment. Change the `tshirt-size` This will add resource reservations to the Deployment. Change the `tshirt-size`
annotation from `medium` to `small` and rerun: annotation from `medium` to `small` and rerun:
kustomize config run local-resource/ kustomize fn run local-resource/
Observe that the reservations have changed. Observe that the reservations have changed.

View File

@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Package main implements an injection function for resource reservations and // Package main implements an injection function for resource reservations and
// is run with `kustomize config run -- DIR/`. // is run with `kustomize fn run -- DIR/`.
package main package main
import ( import (

View File

@@ -27,7 +27,7 @@ function input, and writing the function output.
The function is invoked by authoring a [local Resource](local-resource) The function is invoked by authoring a [local Resource](local-resource)
with `metadata.annotations.[config.kubernetes.io/function]` and running: with `metadata.annotations.[config.kubernetes.io/function]` and running:
kustomize config run local-resource/ kustomize fn run local-resource/
This generates the `local-resource/config` directory containing the template output. This generates the `local-resource/config` directory containing the template output.
@@ -41,7 +41,7 @@ This generates the `local-resource/config` directory containing the template out
Run the config with: Run the config with:
kustomize config run local-resource/ kustomize fn run local-resource/
This will create the directory This will create the directory
@@ -50,6 +50,6 @@ This will create the directory
Add an annotation to the Deployment Resource and change the replica count of the Add an annotation to the Deployment Resource and change the replica count of the
`kind: Nginx` Resource in `example-use.yaml`. Rerun the template: `kind: Nginx` Resource in `example-use.yaml`. Rerun the template:
kustomize config run local-resource/ kustomize fn run local-resource/
The replica count should be updated, but your annotation should remain. The replica count should be updated, but your annotation should remain.

View File

@@ -1,7 +1,7 @@
# Copyright 2019 The Kubernetes Authors. # Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
apiVersion: examples.config.kubernetes.io/v1beta1 # call `kustomize config run` on a directory containing this file apiVersion: examples.config.kubernetes.io/v1beta1 # call `kustomize fn run` on a directory containing this file
kind: Nginx kind: Nginx
metadata: metadata:
name: demo name: demo

View File

@@ -11,7 +11,7 @@ The function is implemented as an [image](image), and built using `make image`.
The template is implemented as a heredoc, which substitutes environment variables The template is implemented as a heredoc, which substitutes environment variables
into a static string. into a static string.
This simple implementation uses `kustomize config run wrap --` to perform the This simple implementation uses `kustomize fn run wrap --` to perform the
heavy lifting of implementing the function interface. heavy lifting of implementing the function interface.
- parse functionConfig from stdin into environment variables - parse functionConfig from stdin into environment variables
@@ -22,7 +22,7 @@ heavy lifting of implementing the function interface.
The function is invoked by authoring a [local Resource](local-resource) The function is invoked by authoring a [local Resource](local-resource)
with `metadata.annotations.[config.kubernetes.io/function]` and running: with `metadata.annotations.[config.kubernetes.io/function]` and running:
kustomize config run local-resource/ kustomize fn run local-resource/
This generates the `local-resource/config` directory containing the template output. This generates the `local-resource/config` directory containing the template output.
@@ -36,7 +36,7 @@ This generates the `local-resource/config` directory containing the template out
Run the config with: Run the config with:
kustomize config run local-resource/ kustomize fn run local-resource/
This will create the directory This will create the directory
@@ -45,6 +45,6 @@ This will create the directory
Add an annotation to the StatefulSet Resource and change the replica count of the Add an annotation to the StatefulSet Resource and change the replica count of the
`kind: CockroachDB` Resource in `example-use.yaml`. Rerun the template: `kind: CockroachDB` Resource in `example-use.yaml`. Rerun the template:
kustomize config run local-resource/ kustomize fn run local-resource/
The replica count should be updated, but your annotation should remain. The replica count should be updated, but your annotation should remain.

View File

@@ -3,18 +3,18 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# use `kustomize config run wrap` to parse the container stdin into # use `kustomize fn run wrap` to parse the container stdin into
# environment variables, and to merge the template output into the # environment variables, and to merge the template output into the
# input Resources. # input Resources.
if [ -z ${WRAPPED} ]; then if [ -z ${WRAPPED} ]; then
export WRAPPED=true export WRAPPED=true
kustomize config run wrap -- $0 kustomize fn run wrap -- $0
exit $? exit $?
fi fi
# this is the template for a cockroachdb instance # this is the template for a cockroachdb instance
# environment variables are parsed from the input functionConfig by # environment variables are parsed from the input functionConfig by
# `kustomize config run wrap` # `kustomize fn run wrap`
cat <<End-of-message cat <<End-of-message
apiVersion: v1 apiVersion: v1
kind: Service kind: Service

View File

@@ -1,7 +1,7 @@
# Copyright 2019 The Kubernetes Authors. # Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# call `kustomize config run` on a directory containing this file # call `kustomize fn run` on a directory containing this file
apiVersion: examples.config.kubernetes.io/v1beta1 apiVersion: examples.config.kubernetes.io/v1beta1
kind: CockroachDB kind: CockroachDB
metadata: metadata:

View File

@@ -20,7 +20,7 @@ the `API` struct definition in [main.go](image/main.go) for documentation.
The function is invoked by authoring a [local Resource](local-resource) The function is invoked by authoring a [local Resource](local-resource)
with `metadata.annotations.[config.kubernetes.io/function]` and running: with `metadata.annotations.[config.kubernetes.io/function]` and running:
kustomize config run local-resource/ kustomize fn run local-resource/
This exists non-zero if kubeval detects an invalid Resource. This exists non-zero if kubeval detects an invalid Resource.
@@ -28,7 +28,7 @@ This exists non-zero if kubeval detects an invalid Resource.
Run the validator with: Run the validator with:
kustomize config run local-resource/ kustomize fn run local-resource/
This will return an error: This will return an error:
@@ -39,6 +39,6 @@ This will return an error:
Now fix the typo in [example-use.yaml](local-resource/example-use.yaml) and Now fix the typo in [example-use.yaml](local-resource/example-use.yaml) and
run: run:
kustomize config run local-resource/ kustomize fn run local-resource/
This will return success (no output). This will return success (no output).

View File

@@ -1,7 +1,7 @@
// Copyright 2019 The Kubernetes Authors. // Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Package main implements a validator function run by `kustomize config run` // Package main implements a validator function run by `kustomize fn run`
package main package main
import ( import (

View File

@@ -17,7 +17,7 @@ Resource configuration, and looks for invalid configuration.
The function is invoked by authoring a [local Resource](local-resource) The function is invoked by authoring a [local Resource](local-resource)
with `metadata.annotations.[config.kubernetes.io/function]` and running: with `metadata.annotations.[config.kubernetes.io/function]` and running:
kustomize config run local-resource/ kustomize fn run local-resource/
This exists non-zero if there is an error. This exists non-zero if there is an error.
@@ -25,7 +25,7 @@ This exists non-zero if there is an error.
Run the validator with: Run the validator with:
kustomize config run local-resource/ kustomize fn run local-resource/
This will return an error: This will return an error:
@@ -33,6 +33,6 @@ This will return an error:
Now uncomment the resource reservations and run again: Now uncomment the resource reservations and run again:
kustomize config run local-resource/ kustomize fn run local-resource/
This will return success This will return success

View File

@@ -1,7 +1,7 @@
// Copyright 2019 The Kubernetes Authors. // Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Package main implements a validator function run by `kustomize config run` // Package main implements a validator function run by `kustomize fn run`
package main package main
import ( import (
@@ -18,7 +18,8 @@ func main() {
p := kio.Pipeline{ p := kio.Pipeline{
Inputs: []kio.Reader{rw}, // read the inputs into a slice Inputs: []kio.Reader{rw}, // read the inputs into a slice
Filters: []kio.Filter{filter{}}, // run the filter against the inputs Filters: []kio.Filter{filter{}}, // run the filter against the inputs
Outputs: []kio.Writer{rw}} // copy the inputs to the output Outputs: []kio.Writer{rw}, // copy the inputs to the output
}
if err := p.Execute(); err != nil { if err := p.Execute(); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err) fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1) os.Exit(1)
@@ -59,7 +60,6 @@ func validate(r *yaml.RNode) error {
// visit each container in the list and validate // visit each container in the list and validate
return containers.VisitElements(func(node *yaml.RNode) error { return containers.VisitElements(func(node *yaml.RNode) error {
// check cpu is non-nil // check cpu is non-nil
f, err := node.Pipe(yaml.Lookup("resources", "requests", "cpu")) f, err := node.Pipe(yaml.Lookup("resources", "requests", "cpu"))
if err != nil { if err != nil {

View File

@@ -102,7 +102,14 @@ elif [[ "$OSTYPE" == darwin* ]]; then
opsys=darwin opsys=darwin
fi fi
RELEASE_URL=$(curl -s $release_url |\ releases=$(curl -s $release_url)
if [[ $releases == *"API rate limit exceeded"* ]]; then
echo "Github rate-limiter failed the request. Either authenticate or wait a couple of minutes."
exit 1
fi
RELEASE_URL=$(echo "${releases}" |\
grep browser_download.*${opsys}_${arch} |\ grep browser_download.*${opsys}_${arch} |\
cut -d '"' -f 4 |\ cut -d '"' -f 4 |\
sort -V | tail -n 1) sort -V | tail -n 1)

View File

@@ -33,8 +33,27 @@ func TestAddResourceHappyPath(t *testing.T) {
assert.NoError(t, cmd.RunE(cmd, args)) assert.NoError(t, cmd.RunE(cmd, args))
content, err := testutils_test.ReadTestKustomization(fSys) content, err := testutils_test.ReadTestKustomization(fSys)
assert.NoError(t, err) assert.NoError(t, err)
assert.Contains(t, string(content), resourceFileName) assert.Equal(t, string(content), `apiVersion: kustomize.config.k8s.io/v1beta1
assert.Contains(t, string(content), resourceFileName+"another") kind: Kustomization
namePrefix: some-prefix
nameSuffix: some-suffix
# Labels to add to all objects and selectors.
# These labels would also be used to form the selector for apply --prune
# Named differently than “labels” to avoid confusion with metadata for this object
commonLabels:
app: helloworld
commonAnnotations:
note: This is an example annotation
resources:
- myWonderfulResource.yaml
- myWonderfulResource.yamlanother
#- service.yaml
#- ../some-dir/
# There could also be configmaps in Base, which would make these overlays
# There could be secrets in Base, if just using a fork/rebase workflow
replacements:
- path: replacement.yaml
`)
} }
func TestAddResourceAlreadyThere(t *testing.T) { func TestAddResourceAlreadyThere(t *testing.T) {

View File

@@ -212,7 +212,7 @@ func (mf *kustomizationFile) parseCommentedFields(content []byte) error {
if matched { if matched {
mf.originalFields = append(mf.originalFields, &commentedField{field: field, comment: squash(comments)}) mf.originalFields = append(mf.originalFields, &commentedField{field: field, comment: squash(comments)})
comments = [][]byte{} comments = [][]byte{}
} else if len(comments) > 0 { } else if len(comments) > 0 && len(mf.originalFields) > 0 {
mf.originalFields[len(mf.originalFields)-1].appendComment(squash(comments)) mf.originalFields[len(mf.originalFields)-1].appendComment(squash(comments))
comments = [][]byte{} comments = [][]byte{}
} }

View File

@@ -356,6 +356,53 @@ kind: Kustomization
} }
} }
func TestCommentsWithDocumentSeperatorAtBeginning(t *testing.T) {
kustomizationContentWithComments := []byte(`
# Some comments
# This is some comment we should preserve
# don't delete it
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: mynamespace
`)
expected := []byte(`
# Some comments
# This is some comment we should preserve
# don't delete it
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: mynamespace
`)
fSys := filesys.MakeFsInMemory()
testutils_test.WriteTestKustomizationWith(
fSys, kustomizationContentWithComments)
mf, err := NewKustomizationFile(fSys)
if err != nil {
t.Fatalf("Unexpected Error: %v", err)
}
kustomization, err := mf.Read()
if err != nil {
t.Fatalf("Unexpected Error: %v", err)
}
if err = mf.Write(kustomization); err != nil {
t.Fatalf("Unexpected Error: %v", err)
}
bytes, _ := fSys.ReadFile(mf.path)
if diff := cmp.Diff(expected, bytes); diff != "" {
t.Errorf("Mismatch (-expected, +actual):\n%s", diff)
}
}
func TestUnknownFieldInKustomization(t *testing.T) { func TestUnknownFieldInKustomization(t *testing.T) {
kContent := []byte(` kContent := []byte(`
foo: foo:

View File

@@ -28,6 +28,8 @@ resources: []
configMapGenerator: [] configMapGenerator: []
# There could be secrets in Base, if just using a fork/rebase workflow # There could be secrets in Base, if just using a fork/rebase workflow
secretGenerator: [] secretGenerator: []
replacements:
- path: replacement.yaml
` `
) )

View File

@@ -8,9 +8,9 @@ require (
github.com/spf13/cobra v1.0.0 github.com/spf13/cobra v1.0.0
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
sigs.k8s.io/kustomize/api v0.8.11 sigs.k8s.io/kustomize/api v0.10.0
sigs.k8s.io/kustomize/cmd/config v0.10.0 sigs.k8s.io/kustomize/cmd/config v0.10.2
sigs.k8s.io/kustomize/kyaml v0.11.1 sigs.k8s.io/kustomize/kyaml v0.13.0
sigs.k8s.io/yaml v1.2.0 sigs.k8s.io/yaml v1.2.0
) )

View File

@@ -253,10 +253,10 @@ k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
sigs.k8s.io/kustomize/cmd/config v0.10.0 h1:6XPkaOu9eFdvrcqHpfmYAKoBvE01JdvsTVvtDuAFM+8= sigs.k8s.io/kustomize/cmd/config v0.10.2 h1:2GD3+knDaqZo6rSibkc4kKGp8auNBJrGPZQCTWN4Rtc=
sigs.k8s.io/kustomize/cmd/config v0.10.0/go.mod h1:XS4NFKucjk0/+nPKJwSMoZYCjey2PB0ipNoZabXUFPU= sigs.k8s.io/kustomize/cmd/config v0.10.2/go.mod h1:K2aW7nXJ0AaT+VA/eO0/dzFLxmpFcTzudmAgDwPY1HQ=
sigs.k8s.io/kustomize/kyaml v0.11.1 h1:MWihd9syKG7VQnAzr/OpKb94FvH+cw96nEV1u3it7pI= sigs.k8s.io/kustomize/kyaml v0.13.0 h1:9c+ETyNfSrVhxvphs+K2dzT3dh5oVPPEqPOE/cUpScY=
sigs.k8s.io/kustomize/kyaml v0.11.1/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E= sigs.k8s.io/kustomize/kyaml v0.13.0/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

6
kyaml/OWNERS Normal file
View File

@@ -0,0 +1,6 @@
# See https://github.com/kubernetes/community/blob/master/community-membership.md
approvers:
- kyaml-approvers
reviewers:
- kyaml-reviewers

View File

@@ -11,10 +11,12 @@ import (
// CopyComments recursively copies the comments on fields in from to fields in to // CopyComments recursively copies the comments on fields in from to fields in to
func CopyComments(from, to *yaml.RNode) error { func CopyComments(from, to *yaml.RNode) error {
copy(from, to) // from node should not be modified, it should be just used as a reference
fromCopy := from.Copy()
copyFieldComments(fromCopy, to)
// walk the fields copying comments // walk the fields copying comments
_, err := walk.Walker{ _, err := walk.Walker{
Sources: []*yaml.RNode{from, to}, Sources: []*yaml.RNode{fromCopy, to},
Visitor: &copier{}, Visitor: &copier{},
VisitKeysAsScalars: true}.Walk() VisitKeysAsScalars: true}.Walk()
return err return err
@@ -25,7 +27,7 @@ func CopyComments(from, to *yaml.RNode) error {
type copier struct{} type copier struct{}
func (c *copier) VisitMap(s walk.Sources, _ *openapi.ResourceSchema) (*yaml.RNode, error) { func (c *copier) VisitMap(s walk.Sources, _ *openapi.ResourceSchema) (*yaml.RNode, error) {
copy(s.Dest(), s.Origin()) copyFieldComments(s.Dest(), s.Origin())
return s.Dest(), nil return s.Dest(), nil
} }
@@ -39,13 +41,13 @@ func (c *copier) VisitScalar(s walk.Sources, _ *openapi.ResourceSchema) (*yaml.R
to.Document().Style = yaml.DoubleQuotedStyle to.Document().Style = yaml.DoubleQuotedStyle
} }
copy(s.Dest(), to) copyFieldComments(s.Dest(), to)
return s.Dest(), nil return s.Dest(), nil
} }
func (c *copier) VisitList(s walk.Sources, _ *openapi.ResourceSchema, _ walk.ListKind) ( func (c *copier) VisitList(s walk.Sources, _ *openapi.ResourceSchema, _ walk.ListKind) (
*yaml.RNode, error) { *yaml.RNode, error) {
copy(s.Dest(), s.Origin()) copyFieldComments(s.Dest(), s.Origin())
destItems := s.Dest().Content() destItems := s.Dest().Content()
originItems := s.Origin().Content() originItems := s.Origin().Content()
@@ -64,8 +66,8 @@ func (c *copier) VisitList(s walk.Sources, _ *openapi.ResourceSchema, _ walk.Lis
return s.Dest(), nil return s.Dest(), nil
} }
// copy copies the comment from one field to another // copyFieldComments copies the comment from one field to another
func copy(from, to *yaml.RNode) { func copyFieldComments(from, to *yaml.RNode) {
if from == nil || to == nil { if from == nil || to == nil {
return return
} }

View File

@@ -351,6 +351,30 @@ apiVersion: v1
kind: ConfigMap kind: ConfigMap
data: data:
somekey: "012345678901234567890123456789012345678901234567890123456789012345678901234" # x somekey: "012345678901234567890123456789012345678901234567890123456789012345678901234" # x
`,
},
{
name: "sort fields with null value",
from: `apiVersion: v1
kind: ConfigMap
metadata:
name: workspaces.app.terraform.io
creationTimestamp: null # this field is null
namespace: staging
`,
to: `apiVersion: v1
kind: ConfigMap
metadata:
name: workspaces.app.terraform.io
creationTimestamp: null
namespace: staging
`,
expected: `apiVersion: v1
kind: ConfigMap
metadata:
name: workspaces.app.terraform.io
creationTimestamp: null # this field is null
namespace: staging
`, `,
}, },
} }
@@ -378,9 +402,18 @@ data:
t.FailNow() t.FailNow()
} }
actualFrom, err := from.String()
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Equal(t, strings.TrimSpace(tc.expected), strings.TrimSpace(actual)) { if !assert.Equal(t, strings.TrimSpace(tc.expected), strings.TrimSpace(actual)) {
t.FailNow() t.FailNow()
} }
if !assert.Equal(t, strings.TrimSpace(tc.from), strings.TrimSpace(actualFrom)) {
t.FailNow()
}
}) })
} }
} }

View File

@@ -1,6 +1,7 @@
// Copyright 2019 The Kubernetes Authors. // Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
//go:build !windows
// +build !windows // +build !windows
package filesys package filesys

View File

@@ -612,6 +612,7 @@ func (n *fsNode) RegExpGlob(pattern string) ([]string, error) {
// This is how /bin/ls behaves. // This is how /bin/ls behaves.
func (n *fsNode) Glob(pattern string) ([]string, error) { func (n *fsNode) Glob(pattern string) ([]string, error) {
var result []string var result []string
var allFiles []string
err := n.WalkMe(func(path string, info os.FileInfo, err error) error { err := n.WalkMe(func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
@@ -622,7 +623,7 @@ func (n *fsNode) Glob(pattern string) ([]string, error) {
return err return err
} }
if match { if match {
result = append(result, path) allFiles = append(allFiles, path)
} }
} }
return nil return nil
@@ -630,6 +631,11 @@ func (n *fsNode) Glob(pattern string) ([]string, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if IsHiddenFilePath(pattern) {
result = allFiles
} else {
result = RemoveHiddenFiles(allFiles)
}
sort.Strings(result) sort.Strings(result)
return result, nil return result, nil
} }

View File

@@ -1,6 +1,7 @@
// Copyright 2019 The Kubernetes Authors. // Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
//go:build !windows
// +build !windows // +build !windows
package filesys package filesys
@@ -463,6 +464,13 @@ var bunchOfFiles = []struct {
{ {
path: filepath.Join("b", "d", "a", "c", "u"), path: filepath.Join("b", "d", "a", "c", "u"),
}, },
{
path: filepath.Join("b", "d", ".hidden_file"),
},
{
path: filepath.Join("b", "d", ".hidden_dir"),
addAsDir: true,
},
} }
func makeLoadedFileTree(t *testing.T) *fsNode { func makeLoadedFileTree(t *testing.T) *fsNode {
@@ -579,6 +587,7 @@ func TestExists(t *testing.T) {
func TestRegExpGlob(t *testing.T) { func TestRegExpGlob(t *testing.T) {
n := makeLoadedFileTree(t) n := makeLoadedFileTree(t)
expected := []string{ expected := []string{
filepath.Join("b", "d", ".hidden_file"),
filepath.Join("b", "d", "a", "c", "i", "beans"), filepath.Join("b", "d", "a", "c", "i", "beans"),
filepath.Join("b", "d", "a", "c", "m"), filepath.Join("b", "d", "a", "c", "m"),
filepath.Join("b", "d", "a", "c", "u"), filepath.Join("b", "d", "a", "c", "u"),
@@ -598,16 +607,36 @@ func TestRegExpGlob(t *testing.T) {
func TestGlob(t *testing.T) { func TestGlob(t *testing.T) {
n := makeLoadedFileTree(t) n := makeLoadedFileTree(t)
expected := []string{
filepath.Join("b", "d", "x"), tests := map[string]struct {
filepath.Join("b", "d", "y"), globPattern string
filepath.Join("b", "d", "z"), expectedFiles []string
}{
"VisibleFiles": {
globPattern: "b/d/*",
expectedFiles: []string{
filepath.Join("b", "d", "x"),
filepath.Join("b", "d", "y"),
filepath.Join("b", "d", "z"),
},
},
"HiddenFiles": {
globPattern: "b/d/.*",
expectedFiles: []string{
filepath.Join("b", "d", ".hidden_file"),
},
},
} }
paths, err := n.Glob("b/d/*")
if err != nil { for test, c := range tests {
t.Fatalf("glob error: %v", err) t.Run(test, func(t *testing.T) {
paths, err := n.Glob(c.globPattern)
if err != nil {
t.Fatalf("glob error: %v", err)
}
assertEqualStringSlices(t, c.expectedFiles, paths, "glob test")
})
} }
assertEqualStringSlices(t, expected, paths, "glob test")
} }
func assertEqualStringSlices(t *testing.T, expected, actual []string, message string) { func assertEqualStringSlices(t *testing.T, expected, actual []string, message string) {

View File

@@ -88,7 +88,17 @@ func (fsOnDisk) Exists(name string) bool {
// Glob returns the list of matching files // Glob returns the list of matching files
func (fsOnDisk) Glob(pattern string) ([]string, error) { func (fsOnDisk) Glob(pattern string) ([]string, error) {
return filepath.Glob(pattern) var result []string
allFilePaths, err := filepath.Glob(pattern)
if err != nil {
return nil, err
}
if IsHiddenFilePath(pattern) {
result = allFilePaths
} else {
result = RemoveHiddenFiles(allFilePaths)
}
return result, nil
} }
// IsDir delegates to os.Stat and FileInfo.IsDir // IsDir delegates to os.Stat and FileInfo.IsDir

View File

@@ -1,6 +1,7 @@
// Copyright 2019 The Kubernetes Authors. // Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
//go:build !windows
// +build !windows // +build !windows
package filesys package filesys
@@ -11,6 +12,7 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"reflect" "reflect"
"sort"
"testing" "testing"
) )
@@ -135,31 +137,113 @@ func TestReadFilesRealFS(t *testing.T) {
fSys, testDir := makeTestDir(t) fSys, testDir := makeTestDir(t)
defer os.RemoveAll(testDir) defer os.RemoveAll(testDir)
err := fSys.WriteFile(path.Join(testDir, "foo"), []byte(`foo`)) dir := path.Join(testDir, "dir")
if err != nil { nestedDir := path.Join(dir, "nestedDir")
t.Fatalf("unexpected error %s", err) hiddenDir := path.Join(testDir, ".hiddenDir")
dirs := []string{
testDir,
dir,
nestedDir,
hiddenDir,
} }
if !fSys.Exists(path.Join(testDir, "foo")) { // all directories will have all these files
t.Fatalf("expected foo") files := []string{
} "bar",
if fSys.IsDir(path.Join(testDir, "foo")) { "foo",
t.Fatalf("expected foo not to be a directory") "file-1.xtn",
".file-2.xtn",
".some-file-3.xtn",
".some-file-4.xtn",
} }
err = fSys.WriteFile(path.Join(testDir, "bar"), []byte(`bar`)) err := fSys.MkdirAll(nestedDir)
if err != nil { if err != nil {
t.Fatalf("unexpected error %s", err) t.Fatalf("Unexpected Error %v\n", err)
}
err = fSys.MkdirAll(hiddenDir)
if err != nil {
t.Fatalf("Unexpected Error %v\n", err)
} }
files, err := fSys.Glob(path.Join("testDir", "*")) // adding all files in every directory that we had defined
expected := []string{ for _, d := range dirs {
path.Join(testDir, "bar"), if !fSys.IsDir(d) {
path.Join(testDir, "foo"), t.Fatalf("Expected %s to be a dir\n", d)
}
for _, f := range files {
err = fSys.WriteFile(path.Join(d, f), []byte(f))
if err != nil {
t.Fatalf("unexpected error %s", err)
}
if !fSys.Exists(path.Join(d, f)) {
t.Fatalf("expected %s", f)
}
}
} }
if err != nil {
t.Fatalf("expected no error") tests := map[string]struct {
globPattern string
expectedFiles []string
expectedDirs map[string][]string // glob returns directories as well, so we need to add those to expected files
}{
"AllVisibleFiles": {
globPattern: "*",
expectedFiles: []string{
"bar",
"foo",
"file-1.xtn",
},
expectedDirs: map[string][]string{
testDir: []string{dir},
dir: []string{nestedDir},
},
},
"AllHiddenFiles": {
globPattern: ".*",
expectedFiles: []string{
".file-2.xtn",
".some-file-3.xtn",
".some-file-4.xtn",
},
expectedDirs: map[string][]string{
testDir: []string{hiddenDir},
},
},
"foo_File": {
globPattern: "foo",
expectedFiles: []string{
"foo",
},
},
"dotsome-file_PrefixedFiles": {
globPattern: ".some-file*",
expectedFiles: []string{
".some-file-3.xtn",
".some-file-4.xtn",
},
},
} }
if reflect.DeepEqual(files, expected) {
t.Fatalf("incorrect files found by glob: %v", files) for n, c := range tests {
t.Run(n, func(t *testing.T) {
for _, d := range dirs {
var expectedPaths []string
for _, f := range c.expectedFiles {
expectedPaths = append(expectedPaths, path.Join(d, f))
}
if c.expectedDirs != nil {
expectedPaths = append(expectedPaths, c.expectedDirs[d]...)
}
actualPaths, globErr := fSys.Glob(path.Join(d, c.globPattern))
if globErr != nil {
t.Fatalf("Unexpected Error : %v\n", globErr)
}
sort.Strings(actualPaths)
sort.Strings(expectedPaths)
if !reflect.DeepEqual(actualPaths, expectedPaths) {
t.Fatalf("incorrect files found by glob: expected=%v, actual=%v", expectedPaths, actualPaths)
}
}
})
} }
} }

View File

@@ -123,3 +123,21 @@ func InsertPathPart(path string, pos int, part string) string {
result[pos] = part result[pos] = part
return PathJoin(append(result, parts[pos:]...)) return PathJoin(append(result, parts[pos:]...))
} }
func IsHiddenFilePath(pattern string) bool {
return strings.HasPrefix(filepath.Base(pattern), ".")
}
// Removes paths containing hidden files/folders from a list of paths
func RemoveHiddenFiles(paths []string) []string {
if len(paths) == 0 {
return paths
}
var result []string
for _, path := range paths {
if !IsHiddenFilePath(path) {
result = append(result, path)
}
}
return result
}

View File

@@ -1,6 +1,7 @@
// Copyright 2021 The Kubernetes Authors. // Copyright 2021 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
//go:build !windows
// +build !windows // +build !windows
package filesys package filesys
@@ -8,6 +9,7 @@ package filesys
import ( import (
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"testing" "testing"
) )
@@ -375,3 +377,90 @@ func TestStripLeadingSeps(t *testing.T) {
} }
} }
} }
func TestIsHiddenFilePath(t *testing.T) {
tests := map[string]struct {
paths []string
expectHidden bool
}{
"hiddenGlobs": {
expectHidden: true,
paths: []string{
".*",
"/.*",
"dir/.*",
"dir1/dir2/dir3/.*",
"../../.*",
"../../dir/.*",
},
},
"visibleGlobes": {
expectHidden: false,
paths: []string{
"*",
"/*",
"dir/*",
"dir1/dir2/dir3/*",
"../../*",
"../../dir/*",
},
},
"hiddenFiles": {
expectHidden: true,
paths: []string{
".root_file.xtn",
"/.file_1.xtn",
"dir/.file_2.xtn",
"dir1/dir2/dir3/.file_3.xtn",
"../../.file_4.xtn",
"../../dir/.file_5.xtn",
},
},
"visibleFiles": {
expectHidden: false,
paths: []string{
"root_file.xtn",
"/file_1.xtn",
"dir/file_2.xtn",
"dir1/dir2/dir3/file_3.xtn",
"../../file_4.xtn",
"../../dir/file_5.xtn",
},
},
}
for n, c := range tests {
t.Run(n, func(t *testing.T) {
for _, path := range c.paths {
actual := IsHiddenFilePath(path)
if actual != c.expectHidden {
t.Fatalf("For file path %q, expected hidden: %v, got hidden: %v", path, c.expectHidden, actual)
}
}
})
}
}
func TestRemoveHiddenFiles(t *testing.T) {
paths := []string{
"file1.xtn",
".file2.xtn",
"dir/fa1",
"dir/fa2",
"dir/.fa3",
"../../.fa4",
"../../fa5",
"../../dir/fa6",
"../../dir/.fa7",
}
result := RemoveHiddenFiles(paths)
expected := []string{
"file1.xtn",
"dir/fa1",
"dir/fa2",
"../../fa5",
"../../dir/fa6",
}
if !reflect.DeepEqual(result, expected) {
t.Fatalf("Hidden dirs not correctly removed, expected %v but got %v\n", expected, result)
}
}

View File

@@ -122,15 +122,17 @@ func AddGenerateDockerfile(cmd *cobra.Command) {
Use: "gen [DIR]", Use: "gen [DIR]",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return ioutil.WriteFile(filepath.Join(args[0], "Dockerfile"), []byte(`FROM golang:1.15-alpine as builder return ioutil.WriteFile(filepath.Join(args[0], "Dockerfile"), []byte(`FROM golang:1.16-alpine as builder
ENV CGO_ENABLED=0 ENV CGO_ENABLED=0
WORKDIR /go/src/ WORKDIR /go/src/
COPY go.mod go.sum ./
RUN go mod download
COPY . . COPY . .
RUN go build -tags netgo -ldflags '-w' -v -o /usr/local/bin/function ./ RUN go build -ldflags '-w -s' -v -o /usr/local/bin/function ./
FROM alpine:latest FROM alpine:latest
COPY --from=builder /usr/local/bin/function /usr/local/bin/function COPY --from=builder /usr/local/bin/function /usr/local/bin/function
CMD ["function"] ENTRYPOINT ["function"]
`), 0600) `), 0600)
}, },
} }

View File

@@ -45,15 +45,17 @@ func TestCommand_dockerfile(t *testing.T) {
t.FailNow() t.FailNow()
} }
expected := `FROM golang:1.15-alpine as builder expected := `FROM golang:1.16-alpine as builder
ENV CGO_ENABLED=0 ENV CGO_ENABLED=0
WORKDIR /go/src/ WORKDIR /go/src/
COPY go.mod go.sum ./
RUN go mod download
COPY . . COPY . .
RUN go build -tags netgo -ldflags '-w' -v -o /usr/local/bin/function ./ RUN go build -ldflags '-w -s' -v -o /usr/local/bin/function ./
FROM alpine:latest FROM alpine:latest
COPY --from=builder /usr/local/bin/function /usr/local/bin/function COPY --from=builder /usr/local/bin/function /usr/local/bin/function
CMD ["function"] ENTRYPOINT ["function"]
` `
if !assert.Equal(t, expected, string(b)) { if !assert.Equal(t, expected, string(b)) {
t.FailNow() t.FailNow()

View File

@@ -37,7 +37,7 @@ func ExampleBuild_modify() {
// for testing purposes only -- normally read from stdin when Executing // for testing purposes only -- normally read from stdin when Executing
cmd.SetIn(bytes.NewBufferString(` cmd.SetIn(bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
# items are provided as nodes # items are provided as nodes
items: items:
@@ -61,7 +61,7 @@ functionConfig:
} }
// Output: // Output:
// apiVersion: config.kubernetes.io/v1alpha1 // apiVersion: config.kubernetes.io/v1
// kind: ResourceList // kind: ResourceList
// items: // items:
// - apiVersion: apps/v1 // - apiVersion: apps/v1
@@ -133,7 +133,7 @@ metadata:
// for testing purposes only -- normally read from stdin when Executing // for testing purposes only -- normally read from stdin when Executing
cmd.SetIn(bytes.NewBufferString(` cmd.SetIn(bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
# items are provided as nodes # items are provided as nodes
items: items:
@@ -154,7 +154,7 @@ functionConfig:
} }
// Output: // Output:
// apiVersion: config.kubernetes.io/v1alpha1 // apiVersion: config.kubernetes.io/v1
// kind: ResourceList // kind: ResourceList
// items: // items:
// - apiVersion: apps/v1 // - apiVersion: apps/v1
@@ -241,7 +241,7 @@ metadata:
// for testing purposes only -- normally read from stdin when Executing // for testing purposes only -- normally read from stdin when Executing
cmd.SetIn(bytes.NewBufferString(` cmd.SetIn(bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
# items are provided as nodes # items are provided as nodes
items: items:
@@ -268,7 +268,7 @@ functionConfig:
} }
// Output: // Output:
// apiVersion: config.kubernetes.io/v1alpha1 // apiVersion: config.kubernetes.io/v1
// kind: ResourceList // kind: ResourceList
// items: // items:
// - apiVersion: apps/v1 // - apiVersion: apps/v1
@@ -296,7 +296,7 @@ functionConfig:
func ExampleBuild_validate() { func ExampleBuild_validate() {
fn := func(rl *framework.ResourceList) error { fn := func(rl *framework.ResourceList) error {
// validation results // validation results
var validationResults []framework.ResultItem var validationResults framework.Results
// validate that each Deployment resource has spec.replicas set // validate that each Deployment resource has spec.replicas set
for i := range rl.Items { for i := range rl.Items {
@@ -319,34 +319,31 @@ func ExampleBuild_validate() {
if r != nil { if r != nil {
continue continue
} }
validationResults = append(validationResults, framework.ResultItem{ validationResults = append(validationResults, &framework.Result{
Severity: framework.Error, Severity: framework.Error,
Message: "field is required", Message: "field is required",
ResourceRef: yaml.ResourceIdentifier{ ResourceRef: &yaml.ResourceIdentifier{
TypeMeta: meta.TypeMeta, TypeMeta: meta.TypeMeta,
NameMeta: meta.ObjectMeta.NameMeta, NameMeta: meta.ObjectMeta.NameMeta,
}, },
Field: framework.Field{ Field: &framework.Field{
Path: "spec.replicas", Path: "spec.replicas",
SuggestedValue: "1", ProposedValue: "1",
}, },
}) })
} }
if len(validationResults) > 0 { if len(validationResults) > 0 {
rl.Result = &framework.Result{ rl.Results = validationResults
Name: "replicas-validator",
Items: validationResults,
}
} }
return rl.Result return rl.Results
} }
cmd := command.Build(framework.ResourceListProcessorFunc(fn), command.StandaloneDisabled, true) cmd := command.Build(framework.ResourceListProcessorFunc(fn), command.StandaloneDisabled, true)
// for testing purposes only -- normally read from stdin when Executing // for testing purposes only -- normally read from stdin when Executing
cmd.SetIn(bytes.NewBufferString(` cmd.SetIn(bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
# items are provided as nodes # items are provided as nodes
items: items:
@@ -362,7 +359,7 @@ items:
} }
// Output: // Output:
// apiVersion: config.kubernetes.io/v1alpha1 // apiVersion: config.kubernetes.io/v1
// kind: ResourceList // kind: ResourceList
// items: // items:
// - apiVersion: apps/v1 // - apiVersion: apps/v1
@@ -370,15 +367,13 @@ items:
// metadata: // metadata:
// name: foo // name: foo
// results: // results:
// name: replicas-validator // - message: field is required
// items: // severity: error
// - message: field is required // resourceRef:
// severity: error // apiVersion: apps/v1
// resourceRef: // kind: Deployment
// apiVersion: apps/v1 // name: foo
// kind: Deployment // field:
// name: foo // path: spec.replicas
// field: // proposedValue: "1"
// path: spec.replicas
// suggestedValue: "1"
} }

View File

@@ -23,7 +23,7 @@ const service = "Service"
// ExampleSimpleProcessor_modify implements a function that sets an annotation on each resource. // ExampleSimpleProcessor_modify implements a function that sets an annotation on each resource.
func ExampleSimpleProcessor_modify() { func ExampleSimpleProcessor_modify() {
input := bytes.NewBufferString(` input := bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
# items are provided as nodes # items are provided as nodes
items: items:
@@ -60,7 +60,7 @@ functionConfig:
} }
// Output: // Output:
// apiVersion: config.kubernetes.io/v1alpha1 // apiVersion: config.kubernetes.io/v1
// kind: ResourceList // kind: ResourceList
// items: // items:
// - apiVersion: apps/v1 // - apiVersion: apps/v1
@@ -86,7 +86,7 @@ functionConfig:
// If the resource already exists, it replaces the resource with a new copy. // If the resource already exists, it replaces the resource with a new copy.
func ExampleSimpleProcessor_generateReplace() { func ExampleSimpleProcessor_generateReplace() {
input := bytes.NewBufferString(` input := bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
# items are provided as nodes # items are provided as nodes
items: items:
@@ -150,7 +150,7 @@ metadata:
} }
// Output: // Output:
// apiVersion: config.kubernetes.io/v1alpha1 // apiVersion: config.kubernetes.io/v1
// kind: ResourceList // kind: ResourceList
// items: // items:
// - apiVersion: apps/v1 // - apiVersion: apps/v1
@@ -471,7 +471,7 @@ spec:
// The second resource will be treated as a patch since its metadata matches the resource // The second resource will be treated as a patch since its metadata matches the resource
// generated by ResourceTemplates and MergeResources is true. // generated by ResourceTemplates and MergeResources is true.
rw := kio.ByteReadWriter{Reader: bytes.NewBufferString(` rw := kio.ByteReadWriter{Reader: bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- kind: Deployment - kind: Deployment
@@ -501,7 +501,7 @@ functionConfig:
} }
// Output: // Output:
// apiVersion: config.kubernetes.io/v1alpha1 // apiVersion: config.kubernetes.io/v1
// kind: ResourceList // kind: ResourceList
// items: // items:
// - apiVersion: apps/v1 // - apiVersion: apps/v1
@@ -543,7 +543,7 @@ func ExampleSelector_templatizeKinds() {
} }
rw := &kio.ByteReadWriter{ rw := &kio.ByteReadWriter{
Reader: bytes.NewBufferString(` Reader: bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1beta1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
functionConfig: functionConfig:
kindName: Deployment kindName: Deployment
@@ -575,7 +575,7 @@ items:
} }
// Output: // Output:
// apiVersion: config.kubernetes.io/v1beta1 // apiVersion: config.kubernetes.io/v1
// kind: ResourceList // kind: ResourceList
// items: // items:
// - apiVersion: apps/v1 // - apiVersion: apps/v1
@@ -595,7 +595,7 @@ func ExampleSelector_templatizeAnnotations() {
Value string `yaml:"value"` Value string `yaml:"value"`
} }
rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(` rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1beta1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
functionConfig: functionConfig:
value: bar value: bar
@@ -629,7 +629,7 @@ items:
} }
// Output: // Output:
// apiVersion: config.kubernetes.io/v1beta1 // apiVersion: config.kubernetes.io/v1
// kind: ResourceList // kind: ResourceList
// items: // items:
// - apiVersion: apps/v1 // - apiVersion: apps/v1
@@ -995,7 +995,7 @@ func ExampleVersionedAPIProcessor() {
}}} }}}
source := &kio.ByteReadWriter{Reader: bytes.NewBufferString(` source := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1beta1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
functionConfig: functionConfig:
apiVersion: example.com/v1alpha1 apiVersion: example.com/v1alpha1
@@ -1011,7 +1011,7 @@ functionConfig:
} }
// Output: // Output:
// apiVersion: config.kubernetes.io/v1beta1 // apiVersion: config.kubernetes.io/v1
// kind: ResourceList // kind: ResourceList
// items: // items:
// - apiVersion: apps/v1 // - apiVersion: apps/v1

View File

@@ -17,6 +17,22 @@ import (
// This framework facilitates building functions that receive and emit ResourceLists, // This framework facilitates building functions that receive and emit ResourceLists,
// as required by the specification. // as required by the specification.
type ResourceList struct { type ResourceList struct {
// Items is the ResourceList.items input and output value.
//
// e.g. given the function input:
//
// kind: ResourceList
// items:
// - kind: Deployment
// ...
// - kind: Service
// ...
//
// Items will be a slice containing the Deployment and Service resources
// Mutating functions will alter this field during processing.
// This field is required.
Items []*yaml.RNode `yaml:"items" json:"items"`
// FunctionConfig is the ResourceList.functionConfig input value. // FunctionConfig is the ResourceList.functionConfig input value.
// //
// e.g. given the input: // e.g. given the input:
@@ -31,27 +47,12 @@ type ResourceList struct {
// kind: Example // kind: Example
// spec: // spec:
// foo: var // foo: var
FunctionConfig *yaml.RNode `yaml:"functionConfig" json:"functionConfig"` FunctionConfig *yaml.RNode `yaml:"functionConfig,omitempty" json:"functionConfig,omitempty"`
// Items is the ResourceList.items input and output value. // Results is ResourceList.results output value.
//
// e.g. given the function input:
//
// kind: ResourceList
// items:
// - kind: Deployment
// ...
// - kind: Service
// ...
//
// Items will be a slice containing the Deployment and Service resources
// Mutating functions will alter this field during processing.
Items []*yaml.RNode `yaml:"items" json:"items"`
// Result is ResourceList.result output value.
// Validating functions can optionally use this field to communicate structured // Validating functions can optionally use this field to communicate structured
// validation error data to downstream functions. // validation error data to downstream functions.
Result *Result `yaml:"results" json:"results"` Results Results `yaml:"results,omitempty" json:"results,omitempty"`
} }
// ResourceListProcessor is implemented by configuration functions built with this framework // ResourceListProcessor is implemented by configuration functions built with this framework
@@ -119,8 +120,8 @@ func Execute(p ResourceListProcessor, rlSource *kio.ByteReadWriter) error {
// Write the results // Write the results
// Set the ResourceList.results for validating functions // Set the ResourceList.results for validating functions
if rl.Result != nil && len(rl.Result.Items) > 0 { if len(rl.Results) > 0 {
b, err := yaml.Marshal(rl.Result) b, err := yaml.Marshal(rl.Results)
if err != nil { if err != nil {
return errors.Wrap(err) return errors.Wrap(err)
} }

View File

@@ -16,39 +16,37 @@ import (
func TestExecute_Result(t *testing.T) { func TestExecute_Result(t *testing.T) {
p := framework.ResourceListProcessorFunc(func(rl *framework.ResourceList) error { p := framework.ResourceListProcessorFunc(func(rl *framework.ResourceList) error {
err := &framework.Result{ err := &framework.Results{
Name: "Incompatible config", {
Items: []framework.ResultItem{ Message: "bad value for replicas",
{ Severity: framework.Error,
Message: "bad value for replicas", ResourceRef: &yaml.ResourceIdentifier{
Severity: framework.Error, TypeMeta: yaml.TypeMeta{APIVersion: "v1", Kind: "Deployment"},
ResourceRef: yaml.ResourceIdentifier{ NameMeta: yaml.NameMeta{Name: "tester", Namespace: "default"},
TypeMeta: yaml.TypeMeta{APIVersion: "v1", Kind: "Deployment"},
NameMeta: yaml.NameMeta{Name: "tester", Namespace: "default"},
},
Field: framework.Field{
Path: ".spec.Replicas",
CurrentValue: "0",
SuggestedValue: "3",
},
File: framework.File{
Path: "/path/to/deployment.yaml",
Index: 0,
},
}, },
{ Field: &framework.Field{
Message: "some error", Path: ".spec.Replicas",
Severity: framework.Error, CurrentValue: "0",
ProposedValue: "3",
},
File: &framework.File{
Path: "/path/to/deployment.yaml",
Index: 0,
}, },
}, },
{
Message: "some error",
Severity: framework.Error,
Tags: map[string]string{"foo": "bar"},
},
} }
rl.Result = err rl.Results = *err
return err return err
}) })
out := new(bytes.Buffer) out := new(bytes.Buffer)
source := &kio.ByteReadWriter{Reader: bytes.NewBufferString(` source := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
kind: ResourceList kind: ResourceList
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
items: items:
- kind: Deployment - kind: Deployment
apiVersion: v1 apiVersion: v1
@@ -61,9 +59,9 @@ items:
err := framework.Execute(p, source) err := framework.Execute(p, source)
assert.EqualError(t, err, `[error] v1/Deployment/default/tester .spec.Replicas: bad value for replicas assert.EqualError(t, err, `[error] v1/Deployment/default/tester .spec.Replicas: bad value for replicas
[error] : some error`) [error]: some error`)
assert.Equal(t, 1, err.(*framework.Result).ExitCode()) assert.Equal(t, 1, err.(*framework.Results).ExitCode())
assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1 assert.Equal(t, `apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- kind: Deployment - kind: Deployment
@@ -74,21 +72,21 @@ items:
spec: spec:
replicas: 0 replicas: 0
results: results:
name: Incompatible config - message: bad value for replicas
items: severity: error
- message: bad value for replicas resourceRef:
severity: error apiVersion: v1
resourceRef: kind: Deployment
apiVersion: v1 name: tester
kind: Deployment namespace: default
name: tester field:
namespace: default path: .spec.Replicas
field: currentValue: "0"
path: .spec.Replicas proposedValue: "3"
currentValue: "0" file:
suggestedValue: "3" path: /path/to/deployment.yaml
file: - message: some error
path: /path/to/deployment.yaml severity: error
- message: some error tags:
severity: error`, strings.TrimSpace(out.String())) foo: bar`, strings.TrimSpace(out.String()))
} }

View File

@@ -35,7 +35,7 @@ func TestTemplateProcessor_ResourceTemplates(t *testing.T) {
out := new(bytes.Buffer) out := new(bytes.Buffer)
rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(` rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- apiVersion: v1 - apiVersion: v1
@@ -47,7 +47,7 @@ functionConfig:
require.NoError(t, framework.Execute(p, rw)) require.NoError(t, framework.Execute(p, rw))
require.Equal(t, strings.TrimSpace(` require.Equal(t, strings.TrimSpace(`
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- apiVersion: v1 - apiVersion: v1
@@ -98,7 +98,7 @@ metadata:
out := new(bytes.Buffer) out := new(bytes.Buffer)
rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(` rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- apiVersion: apps/v1 - apiVersion: apps/v1
@@ -130,7 +130,7 @@ functionConfig:
require.NoError(t, framework.Execute(p, rw)) require.NoError(t, framework.Execute(p, rw))
require.Equal(t, strings.TrimSpace(` require.Equal(t, strings.TrimSpace(`
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- apiVersion: apps/v1 - apiVersion: apps/v1
@@ -194,7 +194,7 @@ env:
out := new(bytes.Buffer) out := new(bytes.Buffer)
rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(` rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- apiVersion: apps/v1 - apiVersion: apps/v1
@@ -231,7 +231,7 @@ functionConfig:
require.NoError(t, framework.Execute(p, rw)) require.NoError(t, framework.Execute(p, rw))
require.Equal(t, strings.TrimSpace(` require.Equal(t, strings.TrimSpace(`
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- apiVersion: apps/v1 - apiVersion: apps/v1
@@ -300,7 +300,7 @@ func TestTemplateProcessor_ContainerPatchTemplates_MultipleWorkloadKinds(t *test
out := new(bytes.Buffer) out := new(bytes.Buffer)
rw := &kio.ByteReadWriter{Writer: out, Reader: bytes.NewBufferString(` rw := &kio.ByteReadWriter{Writer: out, Reader: bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: [] items: []
functionConfig: functionConfig:
@@ -591,7 +591,7 @@ func TestTemplateProcessor_AdditionalSchemas(t *testing.T) {
out := new(bytes.Buffer) out := new(bytes.Buffer)
rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(` rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- apiVersion: example.com/v1 - apiVersion: example.com/v1
@@ -606,7 +606,7 @@ items:
Writer: out} Writer: out}
require.NoError(t, framework.Execute(p, rw)) require.NoError(t, framework.Execute(p, rw))
require.Equal(t, strings.TrimSpace(` require.Equal(t, strings.TrimSpace(`
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
kind: ResourceList kind: ResourceList
items: items:
- apiVersion: example.com/v1 - apiVersion: example.com/v1

View File

@@ -23,89 +23,98 @@ const (
) )
// ResultItem defines a validation result // ResultItem defines a validation result
type ResultItem struct { type Result struct {
// Message is a human readable message // Message is a human readable message. This field is required.
Message string `yaml:"message,omitempty"` Message string `yaml:"message,omitempty" json:"message,omitempty"`
// Severity is the severity of this result // Severity is the severity of this result
Severity Severity `yaml:"severity,omitempty"` Severity Severity `yaml:"severity,omitempty" json:"severity,omitempty"`
// ResourceRef is a reference to a resource // ResourceRef is a reference to a resource.
ResourceRef yaml.ResourceIdentifier `yaml:"resourceRef,omitempty"` // Required fields: apiVersion, kind, name.
ResourceRef *yaml.ResourceIdentifier `yaml:"resourceRef,omitempty" json:"resourceRef,omitempty"`
// Field is a reference to the field in a resource this result refers to // Field is a reference to the field in a resource this result refers to
Field Field `yaml:"field,omitempty"` Field *Field `yaml:"field,omitempty" json:"field,omitempty"`
// File references a file containing the resource this result refers to // File references a file containing the resource this result refers to
File File `yaml:"file,omitempty"` File *File `yaml:"file,omitempty" json:"file,omitempty"`
// Tags is an unstructured key value map stored with a result that may be set
// by external tools to store and retrieve arbitrary metadata
Tags map[string]string `yaml:"tags,omitempty" json:"tags,omitempty"`
} }
// String provides a human-readable message for the result item // String provides a human-readable message for the result item
func (i ResultItem) String() string { func (i Result) String() string {
identifier := i.ResourceRef identifier := i.ResourceRef
var idStringList []string var idStringList []string
if identifier.APIVersion != "" { if identifier != nil {
idStringList = append(idStringList, identifier.APIVersion) if identifier.APIVersion != "" {
} idStringList = append(idStringList, identifier.APIVersion)
if identifier.Kind != "" { }
idStringList = append(idStringList, identifier.Kind) if identifier.Kind != "" {
} idStringList = append(idStringList, identifier.Kind)
if identifier.Namespace != "" { }
idStringList = append(idStringList, identifier.Namespace) if identifier.Namespace != "" {
} idStringList = append(idStringList, identifier.Namespace)
if identifier.Name != "" { }
idStringList = append(idStringList, identifier.Name) if identifier.Name != "" {
idStringList = append(idStringList, identifier.Name)
}
} }
formatString := "[%s]"
list := []interface{}{i.Severity}
if len(idStringList) > 0 { if len(idStringList) > 0 {
idString := strings.Join(idStringList, "/") formatString += " %s"
return fmt.Sprintf("[%s] %s %s: %s", i.Severity, idString, i.Field.Path, i.Message) list = append(list, strings.Join(idStringList, "/"))
} }
return fmt.Sprintf("[%s] %s: %s", i.Severity, i.Field.Path, i.Message) if i.Field != nil {
formatString += " %s"
list = append(list, i.Field.Path)
}
formatString += ": %s"
list = append(list, i.Message)
return fmt.Sprintf(formatString, list...)
} }
// File references a file containing a resource // File references a file containing a resource
type File struct { type File struct {
// Path is relative path to the file containing the resource // Path is relative path to the file containing the resource.
Path string `yaml:"path,omitempty"` // This field is required.
Path string `yaml:"path,omitempty" json:"path,omitempty"`
// Index is the index into the file containing the resource // Index is the index into the file containing the resource
// (i.e. if there are multiple resources in a single file) // (i.e. if there are multiple resources in a single file)
Index int `yaml:"index,omitempty"` Index int `yaml:"index,omitempty" json:"index,omitempty"`
} }
// Field references a field in a resource // Field references a field in a resource
type Field struct { type Field struct {
// Path is the field path // Path is the field path. This field is required.
Path string `yaml:"path,omitempty"` Path string `yaml:"path,omitempty" json:"path,omitempty"`
// CurrentValue is the current field value // CurrentValue is the current field value
CurrentValue string `yaml:"currentValue,omitempty"` CurrentValue interface{} `yaml:"currentValue,omitempty" json:"currentValue,omitempty"`
// SuggestedValue is the suggested field value // ProposedValue is the proposed value of the field to fix an issue.
SuggestedValue string `yaml:"suggestedValue,omitempty"` ProposedValue interface{} `yaml:"proposedValue,omitempty" json:"proposedValue,omitempty"`
} }
// Result defines a function result which will be set on the emitted ResourceList type Results []*Result
type Result struct {
// Name is the name of the function creating the result
Name string `yaml:"name,omitempty"`
// Items are the individual results // Error enables Results to be returned as an error
Items []ResultItem `yaml:"items,omitempty"` func (e Results) Error() string {
}
// Error enables a Result to be returned as an error
func (e Result) Error() string {
var msgs []string var msgs []string
for _, i := range e.Items { for _, i := range e {
msgs = append(msgs, i.String()) msgs = append(msgs, i.String())
} }
return strings.Join(msgs, "\n\n") return strings.Join(msgs, "\n\n")
} }
// ExitCode provides the exit code based on the result's severity // ExitCode provides the exit code based on the result's severity
func (e Result) ExitCode() int { func (e Results) ExitCode() int {
for _, i := range e.Items { for _, i := range e {
if i.Severity == Error { if i.Severity == Error {
return 1 return 1
} }

View File

@@ -128,6 +128,7 @@ metadata:
annotations: annotations:
key: foo-a key: foo-a
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
internal.config.kubernetes.io/index: '0'
labels: labels:
key: foo-l key: foo-l
` `
@@ -141,6 +142,7 @@ metadata:
annotations: annotations:
key: bar-a key: bar-a
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
internal.config.kubernetes.io/index: '1'
labels: labels:
key: bar-l key: bar-l
` `

View File

@@ -2,7 +2,7 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
kind: ResourceList kind: ResourceList
apiVersion: config.kubernetes.io/v1alpha1 apiVersion: config.kubernetes.io/v1
functionConfig: functionConfig:
apiVersion: example.com/v1alpha1 apiVersion: example.com/v1alpha1
kind: JavaSpringBoot kind: JavaSpringBoot

View File

@@ -194,6 +194,8 @@ metadata:
name: deployment-foo name: deployment-foo
annotations: annotations:
config.kubernetes.io/index: '0' config.kubernetes.io/index: '0'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'statefulset_deployment-foo.yaml'
config.kubernetes.io/path: 'statefulset_deployment-foo.yaml' config.kubernetes.io/path: 'statefulset_deployment-foo.yaml'
--- ---
apiVersion: v1 apiVersion: v1
@@ -202,6 +204,8 @@ metadata:
name: service-foo name: service-foo
annotations: annotations:
config.kubernetes.io/index: '1' config.kubernetes.io/index: '1'
internal.config.kubernetes.io/index: '1'
internal.config.kubernetes.io/path: 'service_service-foo.yaml'
config.kubernetes.io/path: 'service_service-foo.yaml' config.kubernetes.io/path: 'service_service-foo.yaml'
`, b.String()) { `, b.String()) {
t.FailNow() t.FailNow()

View File

@@ -43,6 +43,7 @@ kind: StatefulSet
metadata: metadata:
name: deployment-foo name: deployment-foo
annotations: annotations:
internal.config.kubernetes.io/path: 'statefulset_deployment-foo.yaml'
config.kubernetes.io/path: 'statefulset_deployment-foo.yaml' config.kubernetes.io/path: 'statefulset_deployment-foo.yaml'
`, `,
`apiVersion: v1 `apiVersion: v1
@@ -50,6 +51,7 @@ kind: Service
metadata: metadata:
name: service-foo name: service-foo
annotations: annotations:
internal.config.kubernetes.io/path: 'service_service-foo.yaml'
config.kubernetes.io/path: 'service_service-foo.yaml' config.kubernetes.io/path: 'service_service-foo.yaml'
`, `,
}, },

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