Compare commits

...

123 Commits

Author SHA1 Message Date
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
uses: actions/setup-go@v2
with:
go-version: ^1.13
go-version: ^1.16
id: go
- name: Check out code into the Go module directory
@@ -35,7 +35,7 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.13
go-version: ^1.16
id: go
- name: Check out code into the Go module directory
@@ -63,7 +63,7 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.13
go-version: ^1.16
id: go
- name: Check out code into the Go module directory
@@ -91,7 +91,7 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.13
go-version: ^1.16
id: go
- 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
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._
@@ -8,13 +27,22 @@ _As contributors and maintainers of this project, and in the interest of fosteri
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
- [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)
- [Contributor Cheat Sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet/README.md) - Common resources for existing developers
- [Contributor License Agreement] - Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests.
- [Kubernetes Contributor Guide] - Main contributor documentation.
- [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
@@ -22,19 +50,22 @@ We have full documentation on how to get started contributing here:
## 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. 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. 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. 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. Contributor: Anyone who actively contributes code, issues or reviews to the project. All contributors must sign the [Contributor License Agreement].
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. 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. 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:
- 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
- [Slack channel](https://kubernetes.slack.com/messages/sig-cli)
- [Mailing list](https://groups.google.com/forum/#!forum/kubernetes-sig-cli)
- [Slack channel]
- [Mailing list]

View File

@@ -12,6 +12,7 @@ MYGOBIN = $(shell go env GOPATH)/bin
endif
export PATH := $(MYGOBIN):$(PATH)
MODULES := '"cmd/config" "api/" "kustomize/" "kyaml/"'
LATEST_V4_RELEASE=v4.4.0
# Provide defaults for REPO_OWNER and REPO_NAME if not present.
# Typically these values would be provided by Prow.
@@ -31,7 +32,7 @@ verify-kustomize: \
lint-kustomize \
test-unit-kustomize-all \
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
# 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-go-mod \
test-examples-kustomize-against-HEAD \
test-examples-kustomize-against-4.1
test-examples-kustomize-against-v4-release
.PHONY: verify-kustomize-e2e
verify-kustomize-e2e: test-examples-e2e-kustomize
@@ -228,7 +229,8 @@ generate-kustomize-api: $(MYGOBIN)/k8scopy
.PHONY: test-unit-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
test-unit-kustomize-plugins:
@@ -278,8 +280,8 @@ test-examples-kustomize-against-HEAD: $(MYGOBIN)/kustomize $(MYGOBIN)/mdrip
./hack/testExamplesAgainstKustomize.sh HEAD
.PHONY:
test-examples-kustomize-against-4.1: $(MYGOBIN)/mdrip
./hack/testExamplesAgainstKustomize.sh v4@v4.1.2
test-examples-kustomize-against-v4-release: $(MYGOBIN)/mdrip
./hack/testExamplesAgainstKustomize.sh v4@$(LATEST_V4_RELEASE)
# linux only.
# This is for testing an example plugin that
@@ -319,7 +321,7 @@ $(MYGOBIN)/helmV3:
( \
set -e; \
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; \
tar -xvzf $$tgzFile; \
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
approvers:
- kustomize-admins
- kustomize-maintainers
- kustomize-approvers
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
aliases:
kustomize-admins:
kustomize-owners:
- knverey
- monopole
- pwittrock
kustomize-maintainers:
kustomize-approvers:
- justinsb
- mortent
- knverey
- monopole
- natasha41575
- phanimarupaka
- Shell32-Natsu
emeritus-maintainers:
- liujingfang1
- pwittrock
kustomize-reviewers:
- knverey
- monopole
- natasha41575
kyaml-approvers:
- 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/resmap"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
"sigs.k8s.io/yaml"
)
@@ -78,12 +79,23 @@ func (p *PatchJson6902TransformerPlugin) Transform(m resmap.ResMap) error {
return err
}
for _, res := range resources {
internalAnnotations := kioutil.GetInternalAnnotations(&res.RNode)
err = res.ApplyFilter(patchjson6902.Filter{
Patch: p.JsonOp,
})
if err != nil {
return err
}
annotations := res.GetAnnotations()
for key, value := range internalAnnotations {
annotations[key] = value
}
err = res.SetAnnotations(annotations)
if err != nil {
return err
}
}
return nil
}

View File

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

View File

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

View File

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

View File

@@ -8,6 +8,7 @@ import (
"strings"
"sigs.k8s.io/kustomize/api/internal/utils"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/resid"
"sigs.k8s.io/kustomize/kyaml/yaml"
@@ -48,6 +49,17 @@ func applyReplacement(nodes []*yaml.RNode, value *yaml.RNode, targets []*types.T
if err != nil {
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 {
if id.IsSelectedBy(t.Select.ResId) && !rejectId(t.Reject, &id) {
err := applyToNode(n, value, t)
@@ -62,9 +74,37 @@ func applyReplacement(nodes []*yaml.RNode, value *yaml.RNode, targets []*types.T
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 {
for _, r := range rejects {
if id.IsSelectedBy(r.ResId) {
if !r.ResId.IsEmpty() && id.IsSelectedBy(r.ResId) {
return true
}
}
@@ -131,10 +171,11 @@ func getReplacement(nodes []*yaml.RNode, r *types.Replacement) (*yaml.RNode, err
if err != nil {
return nil, err
}
if !rn.IsNilOrEmpty() {
return getRefinedValue(r.Source.Options, rn)
if rn.IsNilOrEmpty() {
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) {

View File

@@ -1554,6 +1554,262 @@ spec:
name: nginx-tagged
- image: nginx:1.7.9
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
gopkg.in/yaml.v2 v2.4.0
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
)

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/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM=
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.11.1/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E=
sigs.k8s.io/kustomize/kyaml v0.13.0 h1:9c+ETyNfSrVhxvphs+K2dzT3dh5oVPPEqPOE/cUpScY=
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/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
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/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/kyaml/resid"
)
type nameReferenceTransformer struct {
@@ -109,11 +110,18 @@ func debug(fMap filterMap) {
// 'spec/scaleTargetRef/name' field. Return a filter that can do that.
func (t *nameReferenceTransformer) determineFilters(
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)
for _, backReference := range t.backRefs {
for _, referrerSpec := range backReference.Referrers {
for _, res := range resources {
if res.OrgId().IsSelected(&referrerSpec.Gvk) {
for i, res := range resources {
if resourceOrgIds[i].IsSelected(&referrerSpec.Gvk) {
// If this is true, the res might be a referrer, and if
// so, the name reference it holds might need an update.
if resHasField(res, referrerSpec.Path) {

View File

@@ -168,3 +168,23 @@ func (ra *ResAccumulator) FixBackReferences() (err error) {
return ra.Transform(
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"
"github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/builtins"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/internal/accumulator"
@@ -218,9 +219,26 @@ func (kt *KustTarget) accumulateTarget(ra *accumulator.ResAccumulator, origin *r
return nil, errors.Wrapf(
err, "merging vars %v", kt.kustomization.Vars)
}
err = kt.IgnoreLocal(ra)
if err != nil {
return nil, err
}
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(
ra *accumulator.ResAccumulator) error {
var generators []resmap.Generator

View File

@@ -549,3 +549,26 @@ metadata:
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
`)
}
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.
// To use, load a filesystem with kustomization files (any
// 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 {
options *Options
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
`)
}
// 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 (
"io/ioutil"
"os"
"testing"
"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) {
writeTestSchema(th, "comp/")
openapi.ResetOpenAPI()
@@ -74,6 +95,32 @@ patchesStrategicMerge:
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 = `
apiVersion: example.com/v1alpha1
kind: MyCRD
@@ -108,6 +155,54 @@ openapi:
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) {
th := kusttest_test.MakeHarness(t)
th.WriteK(".", `
@@ -252,3 +347,109 @@ func TestCustomOpenAPIFieldFromComponent(t *testing.T) {
th.Run("prod", th.MakeDefaultOptions())
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",
"kind": "MyCRD",
"version": "v1alpha1"
},
{
"group": "",
"kind": "MyCRD",
"version": "v1alpha1"
}
]
},

View File

@@ -22,6 +22,9 @@ definitions:
- group: example.com
kind: MyCRD
version: v1alpha1
- group: ""
kind: MyCRD
version: v1alpha1
io.k8s.api.core.v1.PodTemplateSpec:
properties:
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 {
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
}
// 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.
func (rf *Factory) ResourcesFromRNodes(
nodes []*yaml.RNode) (result []*Resource, err error) {
nodes, err = rf.dropBadNodes(nodes)
if err != nil {
return nil, err
}
return rf.resourcesFromRNodes(nodes), nil
return rf.DropLocalNodes(nodes)
}
// resourcesFromRNode assumes all nodes are good.
@@ -143,7 +163,7 @@ func (rf *Factory) resourcesFromRNodes(
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)
if err != nil {
return nil, err
@@ -152,9 +172,17 @@ func (rf *Factory) RNodesFromBytes(b []byte) (result []*yaml.RNode, err error) {
if err != nil {
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 {
n0 := nodes[0]
nodes = nodes[1:]
n0, nodes = nodes[0], nodes[1:]
kind := n0.GetKind()
if !strings.HasSuffix(kind, "List") {
result = append(result, n0)
@@ -164,7 +192,7 @@ func (rf *Factory) RNodesFromBytes(b []byte) (result []*yaml.RNode, err error) {
var m map[string]interface{}
m, err = n0.Map()
if err != nil {
return nil, err
return nil, fmt.Errorf("trouble expanding list of %s; %w", kind, err)
}
items, ok := m["items"]
if !ok {
@@ -216,38 +244,20 @@ func (rf *Factory) convertObjectSliceToNodeSlice(
func (rf *Factory) dropBadNodes(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
var result []*yaml.RNode
for _, n := range nodes {
ignore, err := rf.shouldIgnore(n)
if err != nil {
if n.IsNilOrEmpty() {
continue
}
if _, err := n.GetValidatedMetadata(); err != nil {
return nil, err
}
if !ignore {
result = append(result, n)
if foundNil, path := n.HasNilEntryInList(); foundNil {
return nil, fmt.Errorf("empty item at %v in object %v", path, n)
}
result = append(result, n)
}
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
// name.
func (rf *Factory) SliceFromBytesWithNames(names []string, in []byte) ([]*Resource, error) {

View File

@@ -5,7 +5,7 @@ package resource_test
import (
"fmt"
"reflect"
"strings"
"testing"
"github.com/stretchr/testify/assert"
@@ -13,9 +13,10 @@ import (
. "sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/api/types"
"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 {
input string
expected []string
@@ -399,60 +400,11 @@ binaryData:
}
}
func TestSliceFromBytesMore(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,
},
}
func TestMoreRNodesFromBytes(t *testing.T) {
type expected struct {
out []map[string]interface{}
out []string
isErr bool
}
testCases := map[string]struct {
input []byte
exp expected
@@ -465,16 +417,16 @@ func TestSliceFromBytesMore(t *testing.T) {
},
"noBytes": {
input: []byte{},
exp: expected{
out: []map[string]interface{}{},
},
exp: expected{},
},
"goodJson": {
input: []byte(`
{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"winnie"}}
`),
exp: expected{
out: []map[string]interface{}{testConfigMap},
out: []string{
`{"apiVersion": "v1", "kind": "ConfigMap", "metadata": {"name": "winnie"}}`,
},
},
},
"goodYaml1": {
@@ -485,7 +437,12 @@ metadata:
name: winnie
`),
exp: expected{
out: []map[string]interface{}{testConfigMap},
out: []string{`
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`},
},
},
"goodYaml2": {
@@ -501,26 +458,17 @@ metadata:
name: winnie
`),
exp: expected{
out: []map[string]interface{}{testConfigMap, testConfigMap},
},
},
"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: ""
---
out: []string{`
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`),
exp: expected{
out: []map[string]interface{}{testConfigMap},
`, `
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`},
},
},
"garbageInOneOfTwoObjects": {
@@ -545,7 +493,7 @@ WOOOOOOOOOOOOOOOOOOOOOOOOT: woot
`),
exp: expected{
out: []map[string]interface{}{},
out: []string{},
},
},
"Missing .metadata.name in object": {
@@ -591,9 +539,18 @@ items:
name: winnie
`),
exp: expected{
out: []map[string]interface{}{
testConfigMap,
testConfigMap},
out: []string{`
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`, `
apiVersion: v1
kind: ConfigMap
metadata:
name: winnie
`,
},
},
},
"ConfigMapList": {
@@ -611,9 +568,9 @@ items:
name: winnie
`),
exp: expected{
out: []map[string]interface{}{
testConfigMap,
testConfigMap,
out: []string{
`{"apiVersion": "v1", "kind": "ConfigMap", "metadata": {"name": "winnie"}}`,
`{"apiVersion": "v1", "kind": "ConfigMap", "metadata": {"name": "winnie"}}`,
},
},
},
@@ -626,7 +583,7 @@ items:
kind: Deployment
metadata:
name: deployment-a
spec: &hostAliases
spec: &foo
template:
spec:
hostAliases:
@@ -638,23 +595,39 @@ items:
metadata:
name: deployment-b
spec:
<<: *hostAliases
*foo
`),
exp: expected{
// TODO(3271): This should work.
// https://github.com/kubernetes-sigs/kustomize/issues/3271
// json.Marshal(obj) fails on the 2nd list item.
// The value of the 1st list item's first spec field is
// map[string]interface{}
// The value of the 2nd list item's first spec field is
// map[interface{}]interface{}
// which causes a encoding/json.UnsupportedTypeError.
isErr: true,
out: []map[string]interface{}{testDeploymentList},
out: []string{
`{"apiVersion": "apps/v1", "kind": "Deployment", "metadata": {"name": "deployment-a"}, ` +
`"spec": {"template": {"spec": {"hostAliases": [{"hostnames": ["a.example.com"], "ip": "8.8.8.8"}]}}}}`,
`{"apiVersion": "apps/v1", "kind": "Deployment", "metadata": {"name": "deployment-b"}, ` +
`"spec": {"template": {"spec": {"hostAliases": [{"hostnames": ["a.example.com"], "ip": "8.8.8.8"}]}}}}`},
},
},
"simpleAnchor": {
input: []byte(`
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 {
tc := testCases[n]
t.Run(n, func(t *testing.T) {
@@ -666,15 +639,100 @@ items:
assert.False(t, tc.exp.isErr)
assert.Equal(t, len(tc.exp.out), len(rs))
for i := range rs {
rsMap, err := rs[i].Map()
actual, err := rs[i].String()
assert.NoError(t, err)
assert.Equal(
t, fmt.Sprintf("%v", tc.exp.out[i]), fmt.Sprintf("%v", rsMap))
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)
}
t, strings.TrimSpace(tc.exp.out[i]), strings.TrimSpace(actual))
}
})
}
}
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
}
// nolint
var BuildAnnotations = []string{
utils.BuildAnnotationPreviousKinds,
utils.BuildAnnotationPreviousNames,
@@ -41,6 +42,9 @@ var BuildAnnotations = []string{
kioutil.PathAnnotation,
kioutil.IndexAnnotation,
kioutil.SeqIndentAnnotation,
kioutil.LegacyPathAnnotation,
kioutil.LegacyIndexAnnotation,
}
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.
type Replacement struct {
// 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.
Targets []*TargetSelector `json:"targets" yaml:"targets"`
Targets []*TargetSelector `json:"targets,omitempty" yaml:"targets,omitempty"`
}
// 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.
`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.
## Example Function Implementation
@@ -28,7 +28,7 @@ The script wraps itself using `config run wrap -- $0` which will:
```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
if [ -z ${WRAPPED} ]; then
export WRAPPED=true
@@ -82,7 +82,7 @@ End-of-message
### 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
@@ -94,9 +94,9 @@ CMD ["nginx-template.sh]
## 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:
- Network: `none`
@@ -129,7 +129,7 @@ spec:
### 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:

View File

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

View File

@@ -2,7 +2,7 @@
### 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`.
First fetch the kustomize repository, which contains a collection of example
@@ -14,7 +14,7 @@
### Templating -- CockroachDB
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`.
#### 1: Generate the Resources

View File

@@ -16,5 +16,5 @@ require (
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/inf.v0 v0.9.1
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/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM=
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.11.1/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E=
sigs.k8s.io/kustomize/kyaml v0.13.0 h1:9c+ETyNfSrVhxvphs+K2dzT3dh5oVPPEqPOE/cUpScY=
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/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

View File

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

View File

@@ -17,6 +17,7 @@ import (
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/kio/filters"
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
@@ -165,6 +166,7 @@ func (r *CatRunner) catFilters() []kio.Filter {
return fltrs
}
// nolint
func (r *CatRunner) out(w io.Writer) ([]kio.Writer, error) {
var outputs []kio.Writer
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
// default because it doesn't set it
clear := []string{"config.kubernetes.io/path"}
clear := []string{kioutil.LegacyPathAnnotation, kioutil.PathAnnotation}
if r.KeepAnnotations {
clear = nil
}

View File

@@ -5,6 +5,7 @@ package commands
import (
"bytes"
"fmt"
"io"
"os"
"path/filepath"
@@ -47,6 +48,7 @@ Environment Variables:
`,
RunE: r.runE,
PreRunE: r.preRunE,
SilenceUsage: true,
FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true},
Args: cobra.MinimumNArgs(1),
@@ -78,6 +80,12 @@ func WrapCommand() *cobra.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 {
if r.getEnv == nil {
r.getEnv = os.Getenv

View File

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

View File

@@ -60,6 +60,7 @@ $ kyaml cat pkg/ --function-config config.yaml --wrap-kind ResourceList | kyaml
`,
RunE: r.runE,
PreRunE: r.preRunE,
SilenceUsage: true,
FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true},
Args: cobra.MinimumNArgs(1),
@@ -84,6 +85,12 @@ func XArgsCommand() *cobra.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 {
if len(r.Args) == 0 {
r.Args = os.Args

View File

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

View File

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

View File

@@ -4,6 +4,9 @@
package commands
import (
"fmt"
"os"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/runner"
@@ -20,6 +23,7 @@ func GetSinkRunner(name string) *SinkRunner {
Long: commands.SinkLong,
Example: commands.SinkExamples,
RunE: r.runE,
PreRunE: r.preRunE,
Args: cobra.MaximumNArgs(1),
}
runner.FixDocs(name, c)
@@ -36,6 +40,13 @@ type SinkRunner struct {
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 {
var outputs []kio.Writer
if len(args) == 1 {
@@ -43,7 +54,7 @@ func (r *SinkRunner) runE(c *cobra.Command, args []string) error {
} else {
outputs = []kio.Writer{&kio.ByteWriter{
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)
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
items:
- kind: Deployment
@@ -144,7 +144,7 @@ func TestSinkCommandJSON(t *testing.T) {
defer os.RemoveAll(d)
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
items:
- {"kind": "Deployment", "metadata": {"labels": {"app": "nginx2"}, "name": "foo",
@@ -191,7 +191,7 @@ func TestSinkCommand_Stdout(t *testing.T) {
// fmt the files
out := &bytes.Buffer{}
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
items:
- kind: Deployment
@@ -305,7 +305,7 @@ func TestSinkCommandJSON_Stdout(t *testing.T) {
// fmt the files
out := &bytes.Buffer{}
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
items:
- {"kind": "Deployment", "metadata": {"labels": {"app": "nginx2"}, "name": "foo",

View File

@@ -5,6 +5,7 @@ package commands
import (
"fmt"
"os"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
@@ -22,6 +23,7 @@ func GetSourceRunner(name string) *SourceRunner {
Long: commands.SourceLong,
Example: commands.SourceExamples,
RunE: r.runE,
PreRunE: r.preRunE,
}
runner.FixDocs(name, c)
c.Flags().StringVar(&r.WrapKind, "wrap-kind", kio.ResourceListKind,
@@ -47,6 +49,12 @@ type SourceRunner struct {
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 {
// if there is a function-config specified, emit it
var functionConfig *yaml.RNode

View File

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

View File

@@ -61,15 +61,16 @@ Example:
annotations:
config.kubernetes.io/local-config: "true"`
var FunctionsImplShort = `Following is an example for implementing an nginx abstraction using a configuration`
var FunctionsImplLong = `# Running Configuration Functions using kustomize CLI
var (
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
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.
` + "`" + `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.
function.
@@ -88,7 +89,7 @@ The script wraps itself using ` + "`" + `config run wrap -- $0` + "`" + ` which
4. Format the output
#!/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
if [ -z ${WRAPPED} ]; then
export WRAPPED=true
@@ -141,7 +142,7 @@ The script wraps itself using ` + "`" + `config run wrap -- $0` + "`" + ` which
### 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
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
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:
- Network: ` + "`" + `none` + "`" + `
@@ -184,7 +185,7 @@ are passed to the Function through the ` + "`" + `ResourceList.functionConfig` +
### 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:
@@ -230,9 +231,11 @@ The function is invoked using byrunning ` + "`" + `kustomize config run dir/` +
selector:
app: nginx
instance: my-instance`
)
var FunctionsSpecShort = `_Configuration functions_ enable shift-left practices (client-side) through:`
var FunctionsSpecLong = `# Configuration Functions Specification
var (
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
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
[2]: https://tools.ietf.org/html/rfc2119
[3]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds`
)
var Merge2Long = `# Merge (2-way)

View File

@@ -2,6 +2,7 @@
package tutorials
var ConfigurationBasicsShort = `### Synopsis`
var ConfigurationBasicsLong = `
` + "`" + `kustomize cfg` + "`" + ` provides tools for working with local configuration directories.
@@ -274,9 +275,10 @@ var ConfigurationBasicsLong = `
│   └── image: <YOUR-CONTAINER>
...`
var FunctionBasicsShort = `### Synopsis`
var FunctionBasicsLong = `
` + "`" + `kustomize config` + "`" + ` enables encapsulating function for manipulating Resource
var (
FunctionBasicsShort = `### Synopsis`
FunctionBasicsLong = `
` + "`" + `kustomize fn` + "`" + ` enables encapsulating function for manipulating Resource
configuration inside containers, which are run using ` + "`" + `run` + "`" + `.
First fetch the kustomize repository, which contains a collection of example
@@ -288,7 +290,7 @@ var FunctionBasicsLong = `
### Templating -- CockroachDB
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` + "`" + `.
#### 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
` + "`" + `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.`
)

View File

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

View File

@@ -278,12 +278,13 @@ func (gr *Runner) CheckoutReleaseBranch(
return nil
}
gr.comment("creating branch")
// The branch doesn't exist. Create it.
out, err := gr.run(noHarmDone, "checkout", "-b", branch)
// The branch doesn't exist remotely. Create or reset it locally.
out, err := gr.run(noHarmDone, "checkout", "-B", branch)
if err != nil {
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 nil

View File

@@ -6,8 +6,8 @@ require (
github.com/rakyll/statik v0.1.7
github.com/spf13/cobra v1.0.0
github.com/stretchr/testify v1.5.1
sigs.k8s.io/kustomize/api v0.8.11
sigs.k8s.io/kustomize/kyaml v0.11.1
sigs.k8s.io/kustomize/api v0.10.0
sigs.k8s.io/kustomize/kyaml v0.13.0
)
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/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM=
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.11.1/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E=
sigs.k8s.io/kustomize/kyaml v0.13.0 h1:9c+ETyNfSrVhxvphs+K2dzT3dh5oVPPEqPOE/cUpScY=
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/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
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 {
return []byte(`
apiVersion: config.kubernetes.io/v1beta1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
functionConfig:
apiVersion: foo-corp.com/v1
@@ -128,7 +128,7 @@ func TestTransformerConverter(t *testing.T) {
assert.NoError(t, err)
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
items:
- apiVersion: apps/v1
@@ -193,7 +193,7 @@ func (p *plugin) Generate() (resmap.ResMap, error) {
func getGeneratorInputResource() []byte {
return []byte(`
apiVersion: config.kubernetes.io/v1beta1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
functionConfig:
apiVersion: foo-corp.com/v1
@@ -224,7 +224,7 @@ func TestGeneratorConverter(t *testing.T) {
err := c.Convert()
assert.NoError(t, err)
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
items:
- 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.
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 the base with a configMapGenerator
Establish the base with a `configMapGenerator`:
<!-- @establishBase @testAgainstLatestRelease -->
```
DEMO_HOME=$(mktemp -d)
@@ -92,7 +90,7 @@ EOF
### Review
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:
@@ -102,26 +100,26 @@ The deployment refers to this map by name:
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
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.
The recommended way to change a deployment's
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
the appropriate `configMapKeyRef` field.
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
collected](/../../issues/242).
### How this works with kustomize
The _staging_ [variant] here has a configMap [patch]:
The _staging_ [variant] here has a ConfigMap [patch]:
<!-- @showMapPatch @testAgainstLatestRelease -->
@@ -133,7 +131,7 @@ This patch is by definition a named but not necessarily
complete resource spec intended to modify a complete
resource spec.
The ConfigMap it modifies is declared from a configMapGenerator.
The ConfigMap it modifies is declared from a `configMapGenerator`.
<!-- @showMapBase @testAgainstLatestRelease -->
@@ -156,15 +154,15 @@ kustomize build $OVERLAYS/staging |\
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
`$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
`$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
is _5276h4th55_:
@@ -190,7 +188,7 @@ kustomize build $OVERLAYS/staging |\
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 -->
@@ -199,9 +197,9 @@ kustomize build $OVERLAYS/staging |\
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
configMap name itself, and two in the deployment that
ConfigMap name itself, and two in the deployment that
uses the map:
<!-- @countHashes @testAgainstLatestRelease -->

View File

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

View File

@@ -22,17 +22,17 @@ a _target selector_:
> group: <optional group>
> version: <optional version>
> kind: <optional kind>
> name: <optional name>
> name: <optional name or regex pattern>
> namespace: <optional namespace>
> labelSelector: <optional label 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
> target:
> name: foo*
> name: foo.*
> ```
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)
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.
@@ -25,6 +25,6 @@ This exits non-zero if there is an error.
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.

View File

@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
// 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
import (
@@ -82,7 +82,6 @@ func (f appCRFilter) Filter(in []*yaml.RNode) ([]*yaml.RNode, error) {
return append(in, app), nil
}
return in, nil
}
// parseAPI parses the functionConfig into an API struct.

View File

@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
// 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
import (
@@ -13,7 +13,7 @@ import (
"testing"
)
var input = `apiVersion: config.kubernetes.io/v1alpha1
var input = `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: v1
@@ -89,7 +89,7 @@ functionConfig:
url: https://metrics/internal/worldpress-01/web-app
`
var output = `apiVersion: config.kubernetes.io/v1alpha1
var output = `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- 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)
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.
@@ -25,11 +25,11 @@ This exits non-zero if there is an error.
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`
annotation from `medium` to `small` and rerun:
kustomize config run local-resource/
kustomize fn run local-resource/
Observe that the reservations have changed.

View File

@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
// 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
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)
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.
@@ -41,7 +41,7 @@ This generates the `local-resource/config` directory containing the template out
Run the config with:
kustomize config run local-resource/
kustomize fn run local-resource/
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
`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.

View File

@@ -1,7 +1,7 @@
# Copyright 2019 The Kubernetes Authors.
# 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
metadata:
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
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.
- 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)
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.
@@ -36,7 +36,7 @@ This generates the `local-resource/config` directory containing the template out
Run the config with:
kustomize config run local-resource/
kustomize fn run local-resource/
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
`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.

View File

@@ -3,18 +3,18 @@
# 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
# input Resources.
if [ -z ${WRAPPED} ]; then
export WRAPPED=true
kustomize config run wrap -- $0
kustomize fn run wrap -- $0
exit $?
fi
# this is the template for a cockroachdb instance
# environment variables are parsed from the input functionConfig by
# `kustomize config run wrap`
# `kustomize fn run wrap`
cat <<End-of-message
apiVersion: v1
kind: Service

View File

@@ -1,7 +1,7 @@
# Copyright 2019 The Kubernetes Authors.
# 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
kind: CockroachDB
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)
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.
@@ -28,7 +28,7 @@ This exists non-zero if kubeval detects an invalid Resource.
Run the validator with:
kustomize config run local-resource/
kustomize fn run local-resource/
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
run:
kustomize config run local-resource/
kustomize fn run local-resource/
This will return success (no output).

View File

@@ -1,7 +1,7 @@
// Copyright 2019 The Kubernetes Authors.
// 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
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)
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.
@@ -25,7 +25,7 @@ This exists non-zero if there is an error.
Run the validator with:
kustomize config run local-resource/
kustomize fn run local-resource/
This will return an error:
@@ -33,6 +33,6 @@ This will return an error:
Now uncomment the resource reservations and run again:
kustomize config run local-resource/
kustomize fn run local-resource/
This will return success

View File

@@ -1,7 +1,7 @@
// Copyright 2019 The Kubernetes Authors.
// 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
import (
@@ -18,7 +18,8 @@ func main() {
p := kio.Pipeline{
Inputs: []kio.Reader{rw}, // read the inputs into a slice
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 {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
@@ -59,7 +60,6 @@ func validate(r *yaml.RNode) error {
// visit each container in the list and validate
return containers.VisitElements(func(node *yaml.RNode) error {
// check cpu is non-nil
f, err := node.Pipe(yaml.Lookup("resources", "requests", "cpu"))
if err != nil {

View File

@@ -102,7 +102,14 @@ elif [[ "$OSTYPE" == darwin* ]]; then
opsys=darwin
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} |\
cut -d '"' -f 4 |\
sort -V | tail -n 1)

View File

@@ -33,8 +33,27 @@ func TestAddResourceHappyPath(t *testing.T) {
assert.NoError(t, cmd.RunE(cmd, args))
content, err := testutils_test.ReadTestKustomization(fSys)
assert.NoError(t, err)
assert.Contains(t, string(content), resourceFileName)
assert.Contains(t, string(content), resourceFileName+"another")
assert.Equal(t, string(content), `apiVersion: kustomize.config.k8s.io/v1beta1
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) {

View File

@@ -212,7 +212,7 @@ func (mf *kustomizationFile) parseCommentedFields(content []byte) error {
if matched {
mf.originalFields = append(mf.originalFields, &commentedField{field: field, comment: squash(comments)})
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))
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) {
kContent := []byte(`
foo:

View File

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

View File

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

View File

@@ -253,10 +253,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/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM=
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.0/go.mod h1:XS4NFKucjk0/+nPKJwSMoZYCjey2PB0ipNoZabXUFPU=
sigs.k8s.io/kustomize/kyaml v0.11.1 h1:MWihd9syKG7VQnAzr/OpKb94FvH+cw96nEV1u3it7pI=
sigs.k8s.io/kustomize/kyaml v0.11.1/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E=
sigs.k8s.io/kustomize/kyaml v0.13.0 h1:9c+ETyNfSrVhxvphs+K2dzT3dh5oVPPEqPOE/cUpScY=
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/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
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
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
_, err := walk.Walker{
Sources: []*yaml.RNode{from, to},
Sources: []*yaml.RNode{fromCopy, to},
Visitor: &copier{},
VisitKeysAsScalars: true}.Walk()
return err
@@ -25,7 +27,7 @@ func CopyComments(from, to *yaml.RNode) error {
type copier struct{}
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
}
@@ -39,13 +41,13 @@ func (c *copier) VisitScalar(s walk.Sources, _ *openapi.ResourceSchema) (*yaml.R
to.Document().Style = yaml.DoubleQuotedStyle
}
copy(s.Dest(), to)
copyFieldComments(s.Dest(), to)
return s.Dest(), nil
}
func (c *copier) VisitList(s walk.Sources, _ *openapi.ResourceSchema, _ walk.ListKind) (
*yaml.RNode, error) {
copy(s.Dest(), s.Origin())
copyFieldComments(s.Dest(), s.Origin())
destItems := s.Dest().Content()
originItems := s.Origin().Content()
@@ -64,8 +66,8 @@ func (c *copier) VisitList(s walk.Sources, _ *openapi.ResourceSchema, _ walk.Lis
return s.Dest(), nil
}
// copy copies the comment from one field to another
func copy(from, to *yaml.RNode) {
// copyFieldComments copies the comment from one field to another
func copyFieldComments(from, to *yaml.RNode) {
if from == nil || to == nil {
return
}

View File

@@ -351,6 +351,30 @@ apiVersion: v1
kind: ConfigMap
data:
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()
}
actualFrom, err := from.String()
if !assert.NoError(t, err) {
t.FailNow()
}
if !assert.Equal(t, strings.TrimSpace(tc.expected), strings.TrimSpace(actual)) {
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.
// SPDX-License-Identifier: Apache-2.0
//go:build !windows
// +build !windows
package filesys

View File

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

View File

@@ -1,6 +1,7 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
//go:build !windows
// +build !windows
package filesys
@@ -463,6 +464,13 @@ var bunchOfFiles = []struct {
{
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 {
@@ -579,6 +587,7 @@ func TestExists(t *testing.T) {
func TestRegExpGlob(t *testing.T) {
n := makeLoadedFileTree(t)
expected := []string{
filepath.Join("b", "d", ".hidden_file"),
filepath.Join("b", "d", "a", "c", "i", "beans"),
filepath.Join("b", "d", "a", "c", "m"),
filepath.Join("b", "d", "a", "c", "u"),
@@ -598,16 +607,36 @@ func TestRegExpGlob(t *testing.T) {
func TestGlob(t *testing.T) {
n := makeLoadedFileTree(t)
expected := []string{
filepath.Join("b", "d", "x"),
filepath.Join("b", "d", "y"),
filepath.Join("b", "d", "z"),
tests := map[string]struct {
globPattern string
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 {
t.Fatalf("glob error: %v", err)
for test, c := range tests {
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) {

View File

@@ -88,7 +88,17 @@ func (fsOnDisk) Exists(name string) bool {
// Glob returns the list of matching files
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

View File

@@ -1,6 +1,7 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
//go:build !windows
// +build !windows
package filesys
@@ -11,6 +12,7 @@ import (
"path"
"path/filepath"
"reflect"
"sort"
"testing"
)
@@ -135,31 +137,113 @@ func TestReadFilesRealFS(t *testing.T) {
fSys, testDir := makeTestDir(t)
defer os.RemoveAll(testDir)
err := fSys.WriteFile(path.Join(testDir, "foo"), []byte(`foo`))
if err != nil {
t.Fatalf("unexpected error %s", err)
dir := path.Join(testDir, "dir")
nestedDir := path.Join(dir, "nestedDir")
hiddenDir := path.Join(testDir, ".hiddenDir")
dirs := []string{
testDir,
dir,
nestedDir,
hiddenDir,
}
if !fSys.Exists(path.Join(testDir, "foo")) {
t.Fatalf("expected foo")
}
if fSys.IsDir(path.Join(testDir, "foo")) {
t.Fatalf("expected foo not to be a directory")
// all directories will have all these files
files := []string{
"bar",
"foo",
"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 {
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", "*"))
expected := []string{
path.Join(testDir, "bar"),
path.Join(testDir, "foo"),
// adding all files in every directory that we had defined
for _, d := range dirs {
if !fSys.IsDir(d) {
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
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.
// SPDX-License-Identifier: Apache-2.0
//go:build !windows
// +build !windows
package filesys
@@ -8,6 +9,7 @@ package filesys
import (
"os"
"path/filepath"
"reflect"
"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]",
Args: cobra.ExactArgs(1),
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
WORKDIR /go/src/
COPY go.mod go.sum ./
RUN go mod download
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
COPY --from=builder /usr/local/bin/function /usr/local/bin/function
CMD ["function"]
ENTRYPOINT ["function"]
`), 0600)
},
}

View File

@@ -45,15 +45,17 @@ func TestCommand_dockerfile(t *testing.T) {
t.FailNow()
}
expected := `FROM golang:1.15-alpine as builder
expected := `FROM golang:1.16-alpine as builder
ENV CGO_ENABLED=0
WORKDIR /go/src/
COPY go.mod go.sum ./
RUN go mod download
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
COPY --from=builder /usr/local/bin/function /usr/local/bin/function
CMD ["function"]
ENTRYPOINT ["function"]
`
if !assert.Equal(t, expected, string(b)) {
t.FailNow()

View File

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

View File

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

View File

@@ -17,6 +17,22 @@ import (
// This framework facilitates building functions that receive and emit ResourceLists,
// as required by the specification.
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.
//
// e.g. given the input:
@@ -31,27 +47,12 @@ type ResourceList struct {
// kind: Example
// spec:
// 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.
//
// 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.
// Results is ResourceList.results output value.
// Validating functions can optionally use this field to communicate structured
// 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
@@ -119,8 +120,8 @@ func Execute(p ResourceListProcessor, rlSource *kio.ByteReadWriter) error {
// Write the results
// Set the ResourceList.results for validating functions
if rl.Result != nil && len(rl.Result.Items) > 0 {
b, err := yaml.Marshal(rl.Result)
if len(rl.Results) > 0 {
b, err := yaml.Marshal(rl.Results)
if err != nil {
return errors.Wrap(err)
}

View File

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

View File

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

View File

@@ -23,89 +23,98 @@ const (
)
// ResultItem defines a validation result
type ResultItem struct {
// Message is a human readable message
Message string `yaml:"message,omitempty"`
type Result struct {
// Message is a human readable message. This field is required.
Message string `yaml:"message,omitempty" json:"message,omitempty"`
// 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 yaml.ResourceIdentifier `yaml:"resourceRef,omitempty"`
// ResourceRef is a reference to a resource.
// 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 Field `yaml:"field,omitempty"`
Field *Field `yaml:"field,omitempty" json:"field,omitempty"`
// 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
func (i ResultItem) String() string {
func (i Result) String() string {
identifier := i.ResourceRef
var idStringList []string
if identifier.APIVersion != "" {
idStringList = append(idStringList, identifier.APIVersion)
}
if identifier.Kind != "" {
idStringList = append(idStringList, identifier.Kind)
}
if identifier.Namespace != "" {
idStringList = append(idStringList, identifier.Namespace)
}
if identifier.Name != "" {
idStringList = append(idStringList, identifier.Name)
if identifier != nil {
if identifier.APIVersion != "" {
idStringList = append(idStringList, identifier.APIVersion)
}
if identifier.Kind != "" {
idStringList = append(idStringList, identifier.Kind)
}
if identifier.Namespace != "" {
idStringList = append(idStringList, identifier.Namespace)
}
if identifier.Name != "" {
idStringList = append(idStringList, identifier.Name)
}
}
formatString := "[%s]"
list := []interface{}{i.Severity}
if len(idStringList) > 0 {
idString := strings.Join(idStringList, "/")
return fmt.Sprintf("[%s] %s %s: %s", i.Severity, idString, i.Field.Path, i.Message)
formatString += " %s"
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
type File struct {
// Path is relative path to the file containing the resource
Path string `yaml:"path,omitempty"`
// Path is relative path to the file containing the resource.
// This field is required.
Path string `yaml:"path,omitempty" json:"path,omitempty"`
// Index is the index into the file containing the resource
// (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
type Field struct {
// Path is the field path
Path string `yaml:"path,omitempty"`
// Path is the field path. This field is required.
Path string `yaml:"path,omitempty" json:"path,omitempty"`
// 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
SuggestedValue string `yaml:"suggestedValue,omitempty"`
// ProposedValue is the proposed value of the field to fix an issue.
ProposedValue interface{} `yaml:"proposedValue,omitempty" json:"proposedValue,omitempty"`
}
// Result defines a function result which will be set on the emitted ResourceList
type Result struct {
// Name is the name of the function creating the result
Name string `yaml:"name,omitempty"`
type Results []*Result
// Items are the individual results
Items []ResultItem `yaml:"items,omitempty"`
}
// Error enables a Result to be returned as an error
func (e Result) Error() string {
// Error enables Results to be returned as an error
func (e Results) Error() string {
var msgs []string
for _, i := range e.Items {
for _, i := range e {
msgs = append(msgs, i.String())
}
return strings.Join(msgs, "\n\n")
}
// ExitCode provides the exit code based on the result's severity
func (e Result) ExitCode() int {
for _, i := range e.Items {
func (e Results) ExitCode() int {
for _, i := range e {
if i.Severity == Error {
return 1
}

View File

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

View File

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

View File

@@ -194,6 +194,8 @@ metadata:
name: deployment-foo
annotations:
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'
---
apiVersion: v1
@@ -202,6 +204,8 @@ metadata:
name: service-foo
annotations:
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'
`, b.String()) {
t.FailNow()

View File

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