mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-14 18:40:55 +00:00
Compare commits
125 Commits
api/v0.9.0
...
release-ap
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
326a57a9cc | ||
|
|
9dfdebc6c7 | ||
|
|
b896e04c20 | ||
|
|
6ecae1ad50 | ||
|
|
9abb72e4d6 | ||
|
|
6365b3d0cf | ||
|
|
33c2ea01c4 | ||
|
|
863ff0ef1b | ||
|
|
a5117083ec | ||
|
|
a143688a1d | ||
|
|
0676d0bd11 | ||
|
|
b6cb6c8ae9 | ||
|
|
b16e4ec566 | ||
|
|
cb1cbbe044 | ||
|
|
86fb408b2c | ||
|
|
ca5d691199 | ||
|
|
394567079d | ||
|
|
e0c8ebc41f | ||
|
|
8668691ade | ||
|
|
374d790a21 | ||
|
|
d8f406d06f | ||
|
|
46b3cd2109 | ||
|
|
20c608989a | ||
|
|
ba4d83f75f | ||
|
|
067559127d | ||
|
|
37ab5579f0 | ||
|
|
ef5f1d347d | ||
|
|
2c4b195516 | ||
|
|
04396ab4e6 | ||
|
|
4fd77b3a6e | ||
|
|
3ea8b79925 | ||
|
|
71b978da1a | ||
|
|
7110298c52 | ||
|
|
b4a69f08c0 | ||
|
|
572d5841c6 | ||
|
|
984a2dab3d | ||
|
|
c3c02887ec | ||
|
|
ba051c863b | ||
|
|
4d59146e48 | ||
|
|
5765ab4dbc | ||
|
|
4769751943 | ||
|
|
e506ce021e | ||
|
|
ed763991de | ||
|
|
55ac9ca88d | ||
|
|
548f5ffca9 | ||
|
|
dd3377b1a0 | ||
|
|
605239a1e5 | ||
|
|
67c58ad4f4 | ||
|
|
11e19a3d0f | ||
|
|
6fffcb9203 | ||
|
|
68790e00a9 | ||
|
|
6cf06fac12 | ||
|
|
0d8c107362 | ||
|
|
f30e45c549 | ||
|
|
250ea13767 | ||
|
|
608128738d | ||
|
|
7153f33466 | ||
|
|
274b12318d | ||
|
|
94c82f61a3 | ||
|
|
d260f50573 | ||
|
|
40c014a991 | ||
|
|
75c8aec29d | ||
|
|
fcb9c0065e | ||
|
|
63ec6bdb3d | ||
|
|
25bfe6f306 | ||
|
|
635c4fd43b | ||
|
|
c455215f55 | ||
|
|
8f56f51307 | ||
|
|
70a8ed6ed3 | ||
|
|
febfaf16dc | ||
|
|
8268b17700 | ||
|
|
0889995a61 | ||
|
|
4e476ae574 | ||
|
|
7efd7d23fe | ||
|
|
6fb944815b | ||
|
|
5e3432fbbe | ||
|
|
f0c6bd7773 | ||
|
|
dd579c905d | ||
|
|
22b735885a | ||
|
|
b7c5058e37 | ||
|
|
baff5f4359 | ||
|
|
dce4ea5846 | ||
|
|
c47fc48607 | ||
|
|
1d9b6cbe57 | ||
|
|
1cb93123fc | ||
|
|
c6cb42ec27 | ||
|
|
67a5f6d68f | ||
|
|
e997cc5486 | ||
|
|
53577a5190 | ||
|
|
c1ae234a64 | ||
|
|
02cb395ec2 | ||
|
|
65e7529ca0 | ||
|
|
f70743b267 | ||
|
|
f4382738ab | ||
|
|
a100dca303 | ||
|
|
50414208d1 | ||
|
|
e17a007719 | ||
|
|
dd3c5f5c0a | ||
|
|
fb3f560e0c | ||
|
|
12c177a365 | ||
|
|
402f6ca72b | ||
|
|
2b8a39373e | ||
|
|
17f18604e4 | ||
|
|
99e404cb61 | ||
|
|
d4e3b4f832 | ||
|
|
6552b90657 | ||
|
|
bf57d698b1 | ||
|
|
4d002af735 | ||
|
|
2bfc7cc1b0 | ||
|
|
0244f0919e | ||
|
|
f122fb12f3 | ||
|
|
f7cd553044 | ||
|
|
7d0b7e2113 | ||
|
|
c3a67cfdca | ||
|
|
4315e982be | ||
|
|
634464353f | ||
|
|
9c36004493 | ||
|
|
1b1034442c | ||
|
|
a89863c84c | ||
|
|
f7340e0615 | ||
|
|
bf6b207cc9 | ||
|
|
f93b4877f7 | ||
|
|
cd17338759 | ||
|
|
c46867c3a7 | ||
|
|
3e7246690f |
8
.github/workflows/go.yml
vendored
8
.github/workflows/go.yml
vendored
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
14
Makefile
14
Makefile
@@ -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
6
OWNERS
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 + `'`,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
70
api/krusty/localconfig_test.go
Normal file
70
api/krusty/localconfig_test.go
Normal 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
|
||||
`)
|
||||
}
|
||||
@@ -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
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
`)
|
||||
}
|
||||
|
||||
5
api/krusty/testdata/customschema.json
vendored
5
api/krusty/testdata/customschema.json
vendored
@@ -34,6 +34,11 @@
|
||||
"group": "example.com",
|
||||
"kind": "MyCRD",
|
||||
"version": "v1alpha1"
|
||||
},
|
||||
{
|
||||
"group": "",
|
||||
"kind": "MyCRD",
|
||||
"version": "v1alpha1"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
3
api/krusty/testdata/customschema.yaml
vendored
3
api/krusty/testdata/customschema.yaml
vendored
@@ -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:
|
||||
|
||||
76
api/krusty/testdata/openshiftschema.json
vendored
Normal file
76
api/krusty/testdata/openshiftschema.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
14
api/kv/kv.go
14
api/kv/kv.go
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
6
cmd/config/OWNERS
Normal file
@@ -0,0 +1,6 @@
|
||||
# See https://github.com/kubernetes/community/blob/master/community-membership.md
|
||||
approvers:
|
||||
- kyaml-approvers
|
||||
|
||||
reviewers:
|
||||
- kyaml-reviewers
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -39,7 +39,7 @@ functionConfig:
|
||||
- 4
|
||||
`
|
||||
|
||||
resourceInput = `apiVersion: config.kubernetes.io/v1alpha1
|
||||
resourceInput = `apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: apps/v1
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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}},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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.`
|
||||
)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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{}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -28,6 +28,8 @@ resources: []
|
||||
configMapGenerator: []
|
||||
# There could be secrets in Base, if just using a fork/rebase workflow
|
||||
secretGenerator: []
|
||||
replacements:
|
||||
- path: replacement.yaml
|
||||
`
|
||||
)
|
||||
|
||||
|
||||
@@ -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.2
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.0
|
||||
sigs.k8s.io/yaml v1.2.0
|
||||
)
|
||||
|
||||
|
||||
@@ -253,10 +253,10 @@ k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/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/cmd/config v0.10.2 h1:2GD3+knDaqZo6rSibkc4kKGp8auNBJrGPZQCTWN4Rtc=
|
||||
sigs.k8s.io/kustomize/cmd/config v0.10.2/go.mod h1:K2aW7nXJ0AaT+VA/eO0/dzFLxmpFcTzudmAgDwPY1HQ=
|
||||
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
6
kyaml/OWNERS
Normal file
@@ -0,0 +1,6 @@
|
||||
# See https://github.com/kubernetes/community/blob/master/community-membership.md
|
||||
approvers:
|
||||
- kyaml-approvers
|
||||
|
||||
reviewers:
|
||||
- kyaml-reviewers
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package filesys
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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()))
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user