Compare commits

...

72 Commits

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

* fixed behaviour of fsondisk with test updated

* glob behaviour fixed in fsnode

* removed commented code
2021-11-10 08:51:26 -08:00
Kubernetes Prow Robot
86fb408b2c Merge pull request #4276 from natasha41575/fixFunctionSpec
fix function spec example
2021-11-09 21:05:26 -08:00
natasha41575
ca5d691199 fix function spec example 2021-11-09 20:56:36 -08:00
Kubernetes Prow Robot
394567079d Merge pull request #4272 from mengqiy/pointer
Make ResourceList follow k8s api conventions
2021-11-09 15:41:26 -08:00
Kubernetes Prow Robot
e0c8ebc41f Merge pull request #4235 from Goodwine/kyaml-wrap-bug
Fix kyaml readwriter inconsistencies when wrapping resources
2021-11-09 12:37:48 -08:00
Kubernetes Prow Robot
8668691ade Merge pull request #4271 from natasha41575/ReplacementsEdit
Fix: replacements entries get source and targets with null value appended
2021-11-09 10:49:47 -08:00
Mengqi Yu
374d790a21 Make ResourceList follow k8s api conventions
Make optional fields as pointers.
Add omitempty for optional fields.
2021-11-08 21:35:49 -08:00
natasha41575
d8f406d06f add omitempty tag to replacement sources and targets 2021-11-08 12:33:30 -08:00
natasha41575
46b3cd2109 modify edit test for null replacements fields 2021-11-08 12:21:45 -08:00
Carlos Ortiz García
20c608989a Move kio.ByteRW tests from framework_test to byteio_readwriter_test 2021-11-08 11:55:02 -08:00
Carlos Ortiz García
ba4d83f75f only override wrapping kind if it wasn't set already 2021-11-08 11:29:57 -08:00
Carlos Ortiz García
067559127d test cases for framework wrapping/unwrapping bug 2021-11-08 10:13:00 -08:00
Kubernetes Prow Robot
37ab5579f0 Merge pull request #4229 from natasha41575/annotationAndLabelSelectionInReplacements
Annotation and label selection in replacement targets
2021-11-04 13:08:23 -07:00
natasha41575
ef5f1d347d support label and annotation selection in replacement targets 2021-11-04 12:25:15 -07:00
Kubernetes Prow Robot
2c4b195516 Merge pull request #4259 from MikaelSmith/fix-patch-example
docs: Update example for patching multiple objects
2021-11-01 16:01:54 -07:00
Kubernetes Prow Robot
04396ab4e6 Merge pull request #4203 from timofurrer/config-map-consistency
Add consistency to ConfigMap spelling
2021-11-01 15:47:54 -07:00
Kubernetes Prow Robot
4fd77b3a6e Merge pull request #4248 from natasha41575/resourceListResults
[breaking] update results field of ResourceList to implement function spec v1
2021-10-29 14:51:09 -07:00
natasha41575
3ea8b79925 update results field of ResourceList to implement function spec v1 2021-10-29 14:28:50 -07:00
Natasha Sarkar
71b978da1a Merge pull request #4253 from natasha41575/resourceListSDKHelpers
provide utility helpers for preserving internal annotations
2021-10-29 14:25:06 -07:00
Natasha Sarkar
7110298c52 Merge pull request #4249 from natasha41575/resourceListV1
bump ResourceList from v1alpha1 to v1
2021-10-29 14:24:10 -07:00
natasha41575
b4a69f08c0 provide utility helpers for preserving internal annotations 2021-10-29 12:30:55 -07:00
Michael Smith
572d5841c6 docs: Update example for patching multiple objects
Updates the example for patching multiple objects to match the
implementation in #1355, which supports name as a regular expression
(not wildcard pattern).
2021-10-26 12:28:42 -07:00
Kubernetes Prow Robot
984a2dab3d Merge pull request #4242 from natasha41575/configmapissue
fix issue with quotations being dropped in configmap generation
2021-10-24 18:54:22 -07:00
natasha41575
c3c02887ec bump ResourceList from v1alpha1 to v1 2021-10-19 16:15:27 -07:00
natasha41575
ba051c863b fix issue with quote being dropped in configmap generation 2021-10-14 18:30:28 -07:00
natasha41575
4d59146e48 test for dropped quote in configmap generation 2021-10-14 18:13:49 -07:00
Kubernetes Prow Robot
5765ab4dbc Merge pull request #4236 from Goodwine/docs-fn
Update documents from 'kustomize configuration' to 'kustomize fn'
2021-10-13 18:35:28 -07:00
Kubernetes Prow Robot
4769751943 Merge pull request #4160 from osherdp/fix/github-rate-limiter-output
Return a meaningful message if we hit the rate-limiter of GitHub
2021-10-13 18:23:28 -07:00
Kubernetes Prow Robot
e506ce021e Merge pull request #4230 from yutachaos/feature/update_unified_go_version
Update go version 1.16 for CI
2021-10-13 18:09:28 -07:00
Kubernetes Prow Robot
ed763991de Merge pull request #4227 from natasha41575/MigrateIndexPathIdAnnotations
fix bug with migrating kyaml reader path, index, and id annotations
2021-10-12 18:37:48 -07:00
natasha41575
55ac9ca88d fix bug with migrating annotations 2021-10-12 15:42:54 -07:00
Carlos Ortiz García
548f5ffca9 Update documents from 'configuration' to 'fn' 2021-10-11 12:35:22 -05:00
yutachaos
dd3377b1a0 Update CI go version 1.16
Signed-off-by: yutachaos <18604471+yutachaos@users.noreply.github.com>
2021-10-08 14:02:50 +09:00
natasha41575
605239a1e5 test to demonstrate broken annotation selection 2021-10-07 15:40:23 -07:00
Kubernetes Prow Robot
67c58ad4f4 Merge pull request #4210 from natasha41575/openapiFromComponent
fix issue with getting openapi schema from components
2021-10-04 19:27:49 -07:00
natasha41575
11e19a3d0f separate custom openapi test from the others 2021-10-04 18:48:54 -07:00
Kubernetes Prow Robot
6fffcb9203 Merge pull request #4202 from cedarkuo/update-helloworld-example-readme
Updated README to use 'resources' instead of 'bases' in overlays example.
2021-10-04 14:26:41 -07:00
Kubernetes Prow Robot
68790e00a9 Merge pull request #4216 from mengqiy/updatedockerfilegen
update the dockerfile gen command
2021-09-29 13:51:22 -07:00
Mengqi Yu
6cf06fac12 update the dockerfile gen command 2021-09-29 13:34:11 -07:00
natasha41575
0d8c107362 fix issue with openapi schema from components 2021-09-27 17:00:14 -07:00
natasha41575
f30e45c549 test to demonstrate issue with openapi from components (#4179) 2021-09-27 16:29:08 -07:00
Kubernetes Prow Robot
250ea13767 Merge pull request #4208 from KnVerey/release_instructions
Small improvements to release instructions
2021-09-27 11:41:45 -07:00
Katrina Verey
608128738d Small improvements to release instructions 2021-09-27 10:44:02 -07:00
Kubernetes Prow Robot
7153f33466 Merge pull request #4207 from KnVerey/updateProwExamplesTarget
Test examples against latest release
2021-09-27 10:11:36 -07:00
Kubernetes Prow Robot
274b12318d Merge pull request #4205 from natasha41575/releasing
add link to k8s-staging-kustomize project to releasing instructions
2021-09-27 10:01:37 -07:00
Katrina Verey
94c82f61a3 Test examples against latest release 2021-09-27 09:51:01 -07:00
Kubernetes Prow Robot
d260f50573 Merge pull request #4206 from KnVerey/unpinEverything
Back to development mode; unpin the modules
2021-09-27 09:47:37 -07:00
Katrina Verey
40c014a991 Back to development mode; unpin the modules 2021-09-27 09:37:38 -07:00
natasha41575
75c8aec29d add link to k8s-staging-kustomize project to releasing instructions 2021-09-27 09:35:40 -07:00
Kubernetes Prow Robot
fcb9c0065e Merge pull request #4200 from KnVerey/go1.17_build_tags
Add go 1.17 build tags, which go fmt auto-synchronizes
2021-09-27 09:27:36 -07:00
Katrina Verey
63ec6bdb3d Merge pull request #4199 from KnVerey/pinToApi
Pin to api v0.10.0
2021-09-27 09:13:36 -07:00
Kubernetes Prow Robot
25bfe6f306 Merge pull request #4204 from KnVerey/release_updates
Use keyring from kustomize GCP project with new token
2021-09-27 09:01:35 -07:00
Timo Furrer
635c4fd43b Merge branch 'master' into config-map-consistency 2021-09-27 09:16:42 +02:00
Timo Furrer
c455215f55 Add consistency to ConfigMap spelling 2021-09-27 09:11:56 +02:00
cedarkuo
8f56f51307 Updated README to use 'resources' instead of 'bases' in overlays example.
Kubernetes v1.21 upgrade kustomize-in-kubectl to v4.0.5. https://github.com/kubernetes/kubernetes/pull/98946
So I think this example could update back to use resources instead of bases?
2021-09-27 12:40:36 +08:00
Katrina Verey
70a8ed6ed3 Add go 1.17 build tags, which go fmt auto-synchronizes 2021-09-24 17:28:21 -07:00
Katrina Verey
febfaf16dc Use keyring from kustomize GCP project with new token 2021-09-24 20:24:10 -04:00
Katrina Verey
8268b17700 Pin to api v0.10.0 2021-09-24 16:58:20 -07:00
Osher De Paz
f7cd553044 return a meaningful message if we hit the rate-limiter of GitHub 2021-08-31 23:26:49 +03:00
93 changed files with 2142 additions and 469 deletions

View File

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

View File

@@ -12,7 +12,7 @@ MYGOBIN = $(shell go env GOPATH)/bin
endif
export PATH := $(MYGOBIN):$(PATH)
MODULES := '"cmd/config" "api/" "kustomize/" "kyaml/"'
LATEST_V4_RELEASE=v4.3.0
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.
@@ -229,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:

View File

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

View File

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

View File

@@ -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
}
}

View File

@@ -1588,6 +1588,230 @@ data:
`,
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
`,
},
}
for tn, tc := range testCases {

View File

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

View File

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

View File

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

View File

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

View File

@@ -5,6 +5,7 @@ package krusty_test
import (
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/assert"
@@ -346,3 +347,109 @@ func TestCustomOpenAPIFieldFromComponent(t *testing.T) {
th.Run("prod", th.MakeDefaultOptions())
assert.Equal(t, "using custom schema from file provided", openapi.GetSchemaVersion())
}
// test for https://github.com/kubernetes-sigs/kustomize/issues/4179
// kustomize is not seeing the openapi field from the component defined in the overlay
func TestCustomOpenAPIFieldFromComponentWithOverlays(t *testing.T) {
if val, ok := os.LookupEnv("OPENAPI_TEST"); !ok || val != "true" {
t.SkipNow()
}
th := kusttest_test.MakeHarness(t)
// overlay declaring the component
th.WriteK("overlays/overlay-component-openapi", `resources:
- ../base/
components:
- ../../components/dc-openapi
`)
// base kustomization
th.WriteK("overlays/base", `resources:
- dc.yml
`)
// resource declared in the base kustomization
th.WriteF("overlays/base/dc.yml", `apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
name: my-dc
spec:
template:
spec:
initContainers:
- name: init
containers:
- name: container
env:
- name: foo
value: bar
volumeMounts:
- name: cm
mountPath: /opt/cm
volumes:
- name: cm
configMap:
name: cm
`)
// openapi schema referred to by the component
bytes, _ := ioutil.ReadFile("testdata/openshiftschema.json")
th.WriteF("components/dc-openapi/openapi.json", string(bytes))
// patch referred to by the component
th.WriteF("components/dc-openapi/patch.yml", `apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
name: my-dc
spec:
template:
spec:
containers:
- name: container
volumeMounts:
- name: additional-cm
mountPath: /mnt
volumes:
- name: additional-cm
configMap:
name: additional-cm
`)
// component declared in overlay with custom schema and patch
th.WriteC("components/dc-openapi", `patches:
- patch.yml
openapi:
path: openapi.json
`)
openapi.ResetOpenAPI()
m := th.Run("overlays/overlay-component-openapi", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
name: my-dc
spec:
template:
spec:
containers:
- env:
- name: foo
value: bar
name: container
volumeMounts:
- mountPath: /mnt
name: additional-cm
- mountPath: /opt/cm
name: cm
initContainers:
- name: init
volumes:
- configMap:
name: additional-cm
name: additional-cm
- configMap:
name: cm
name: cm
`)
}

View File

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

View File

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

View File

@@ -26,6 +26,7 @@ type Resource struct {
refVarNames []string
}
// nolint
var BuildAnnotations = []string{
utils.BuildAnnotationPreviousKinds,
utils.BuildAnnotationPreviousNames,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -166,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

View File

@@ -14,7 +14,7 @@ import (
)
const (
input = `apiVersion: config.kubernetes.io/v1alpha1
input = `apiVersion: config.kubernetes.io/v1
kind: ResourceList
functionConfig:
metadata:
@@ -68,7 +68,7 @@ items:
name: test
`
output = `apiVersion: config.kubernetes.io/v1alpha1
output = `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1
@@ -127,7 +127,7 @@ items:
targetPort: 8080
`
outputNoMerge = `apiVersion: config.kubernetes.io/v1alpha1
outputNoMerge = `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1
@@ -183,7 +183,7 @@ items:
targetPort: 8080
`
outputOverride = `apiVersion: config.kubernetes.io/v1alpha1
outputOverride = `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1

View File

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

View File

@@ -46,6 +46,7 @@ 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 {

View File

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

View File

@@ -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
@@ -199,7 +199,7 @@ 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', internal.config.kubernetes.io/index: '0', internal.config.kubernetes.io/path: 'f1.json'}}, "spec": {"replicas": 1}}
@@ -246,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
@@ -309,7 +309,7 @@ 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', internal.config.kubernetes.io/index: '0'}}, "spec": {"replicas": 1}}

View File

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

View File

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

View File

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

View File

@@ -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.9.0
sigs.k8s.io/kustomize/kyaml v0.12.0
sigs.k8s.io/kustomize/api v0.10.0
sigs.k8s.io/kustomize/kyaml v0.13.0
)
replace sigs.k8s.io/kustomize/api => ../../api

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -8,9 +8,9 @@ require (
github.com/spf13/cobra v1.0.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.7.0
sigs.k8s.io/kustomize/api v0.9.0
sigs.k8s.io/kustomize/cmd/config v0.10.1
sigs.k8s.io/kustomize/kyaml v0.12.0
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
)

View File

@@ -253,10 +253,10 @@ k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/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.1 h1:eqpN9eUSn3XIfvPabit8lpIqUbWKS7f4lOB4D2cr5CQ=
sigs.k8s.io/kustomize/cmd/config v0.10.1/go.mod h1:9W5pDv3cgDfMjOXEga4yC9lUpkgAaecW+lZmHOMeX2I=
sigs.k8s.io/kustomize/kyaml v0.12.0 h1:k08l8SLwnKa/eXXB5GW2/OnEc/4gJF90VDFebsOwqw4=
sigs.k8s.io/kustomize/kyaml v0.12.0/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=

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -62,7 +62,7 @@ func TestFunctionFilter_Filter(t *testing.T) {
name: "default_file_path_annotation",
run: testRun{
output: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1
@@ -103,7 +103,7 @@ metadata:
name: "no_default_file_path_annotation",
run: testRun{
output: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1
@@ -146,7 +146,7 @@ metadata:
name: "write_read",
run: testRun{
output: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: v1
@@ -203,7 +203,7 @@ metadata:
{
name: "write_results_file",
run: testRun{
output: `apiVersion: config.kubernetes.io/v1alpha1
output: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1
@@ -283,7 +283,7 @@ metadata:
run: testRun{
err: fmt.Errorf("failed"),
output: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1
@@ -363,7 +363,7 @@ metadata:
run: testRun{
err: fmt.Errorf("failed"),
output: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1
@@ -440,7 +440,7 @@ metadata:
noMakeResultsFile: true,
run: testRun{
output: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1
@@ -487,7 +487,7 @@ metadata:
{
name: "scope_resources_by_directory",
run: testRun{
expectedInput: `apiVersion: config.kubernetes.io/v1alpha1
expectedInput: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: v1
@@ -506,7 +506,7 @@ functionConfig:
annotations:
config.kubernetes.io/path: 'foo/bar.yaml'
`,
output: `apiVersion: config.kubernetes.io/v1alpha1
output: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: v1
@@ -578,7 +578,7 @@ metadata:
{
name: "scope_resources_by_directory_resources_missing_path",
run: testRun{
expectedInput: `apiVersion: config.kubernetes.io/v1alpha1
expectedInput: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: v1
@@ -597,7 +597,7 @@ functionConfig:
annotations:
config.kubernetes.io/path: 'foo/bar.yaml'
`,
output: `apiVersion: config.kubernetes.io/v1alpha1
output: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: v1
@@ -666,7 +666,7 @@ metadata:
name: "scope_resources_global",
instance: FunctionFilter{GlobalScope: true},
run: testRun{
expectedInput: `apiVersion: config.kubernetes.io/v1alpha1
expectedInput: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1
@@ -693,7 +693,7 @@ functionConfig:
annotations:
config.kubernetes.io/path: 'foo/bar.yaml'
`,
output: `apiVersion: config.kubernetes.io/v1alpha1
output: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1
@@ -770,7 +770,7 @@ metadata:
{
name: "scope_no_resources",
run: testRun{
expectedInput: `apiVersion: config.kubernetes.io/v1alpha1
expectedInput: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items: []
functionConfig:
@@ -781,7 +781,7 @@ functionConfig:
annotations:
config.kubernetes.io/path: 'foo/bar.yaml'
`,
output: `apiVersion: config.kubernetes.io/v1alpha1
output: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items: []
functionConfig:
@@ -840,7 +840,7 @@ metadata:
{
name: "scope_functions_dir",
run: testRun{
expectedInput: `apiVersion: config.kubernetes.io/v1alpha1
expectedInput: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: v1
@@ -859,7 +859,7 @@ functionConfig:
annotations:
config.kubernetes.io/path: 'foo/functions/bar.yaml'
`,
output: `apiVersion: config.kubernetes.io/v1alpha1
output: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: v1
@@ -931,7 +931,7 @@ metadata:
{
name: "copy_comments",
run: testRun{
expectedInput: `apiVersion: config.kubernetes.io/v1alpha1
expectedInput: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1
@@ -959,7 +959,7 @@ functionConfig:
config.kubernetes.io/path: 'foo/f.yaml'
`,
// delete the comment
output: `apiVersion: config.kubernetes.io/v1alpha1
output: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1

View File

@@ -18,7 +18,7 @@ import (
const (
ResourceListKind = "ResourceList"
ResourceListAPIVersion = "config.kubernetes.io/v1alpha1"
ResourceListAPIVersion = "config.kubernetes.io/v1"
)
// ByteReadWriter reads from an input and writes to an output.
@@ -67,12 +67,12 @@ func (rw *ByteReadWriter) Read() ([]*yaml.RNode, error) {
WrapBareSeqNode: rw.WrapBareSeqNode,
}
val, err := b.Read()
rw.Results = b.Results
if rw.FunctionConfig == nil {
rw.FunctionConfig = b.FunctionConfig
}
rw.Results = b.Results
if !rw.NoWrap {
if !rw.NoWrap && rw.WrappingKind == "" {
rw.WrappingAPIVersion = b.WrappingAPIVersion
rw.WrappingKind = b.WrappingKind
}
@@ -80,15 +80,18 @@ func (rw *ByteReadWriter) Read() ([]*yaml.RNode, error) {
}
func (rw *ByteReadWriter) Write(nodes []*yaml.RNode) error {
return ByteWriter{
w := ByteWriter{
Writer: rw.Writer,
KeepReaderAnnotations: rw.KeepReaderAnnotations,
Style: rw.Style,
FunctionConfig: rw.FunctionConfig,
Results: rw.Results,
WrappingAPIVersion: rw.WrappingAPIVersion,
WrappingKind: rw.WrappingKind,
}.Write(nodes)
}
if !rw.NoWrap {
w.WrappingAPIVersion = rw.WrappingAPIVersion
w.WrappingKind = rw.WrappingKind
}
return w.Write(nodes)
}
// ParseAll reads all of the inputs into resources
@@ -316,6 +319,10 @@ func (r *ByteReader) decode(originalYAML string, index int, decoder *yaml.Decode
r.SetAnnotations = map[string]string{}
}
if !r.OmitReaderAnnotations {
err := kioutil.CopyLegacyAnnotations(n)
if err != nil {
return nil, err
}
r.SetAnnotations[kioutil.IndexAnnotation] = fmt.Sprintf("%d", index)
r.SetAnnotations[kioutil.LegacyIndexAnnotation] = fmt.Sprintf("%d", index)

View File

@@ -33,7 +33,7 @@ func TestByteReader(t *testing.T) {
//
{
name: "wrapped_resource_list",
input: `apiVersion: config.kubernetes.io/v1alpha1
input: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- kind: Deployment
@@ -64,7 +64,7 @@ spec:
//
{
name: "wrapped_resource_list_function_config",
input: `apiVersion: config.kubernetes.io/v1alpha1
input: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
functionConfig:
foo: bar
@@ -105,7 +105,7 @@ elems:
//
{
name: "wrapped_resource_list_function_config_without_items",
input: `apiVersion: config.kubernetes.io/v1alpha1
input: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
functionConfig:
foo: bar

View File

@@ -26,7 +26,7 @@ func TestByteReadWriter(t *testing.T) {
{
name: "round_trip",
input: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- kind: Deployment
@@ -38,7 +38,7 @@ items:
foo: bar
`,
expectedOutput: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- kind: Deployment
@@ -54,7 +54,7 @@ items:
{
name: "function_config",
input: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- kind: Deployment
@@ -68,7 +68,7 @@ functionConfig:
a: b # something
`,
expectedOutput: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- kind: Deployment
@@ -86,7 +86,7 @@ functionConfig:
{
name: "results",
input: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- kind: Deployment
@@ -100,7 +100,7 @@ results:
a: b # something
`,
expectedOutput: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- kind: Deployment
@@ -118,7 +118,7 @@ results:
{
name: "drop_invalid_resource_list_field",
input: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- kind: Deployment
@@ -132,7 +132,7 @@ foo:
a: b # something
`,
expectedOutput: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- kind: Deployment
@@ -233,7 +233,7 @@ metadata:
{
name: "manual_override_wrap",
input: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- kind: Deployment
@@ -262,7 +262,7 @@ spec:
{
name: "manual_override_function_config",
input: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- kind: Deployment
@@ -276,7 +276,7 @@ functionConfig:
a: b # something
`,
expectedOutput: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- kind: Deployment
@@ -499,7 +499,7 @@ env:
{
name: "unwrap ResourceList with annotations",
input: `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- kind: Deployment
@@ -747,3 +747,122 @@ func TestByteReadWriter_WrapBareSeqNode(t *testing.T) {
})
}
}
func TestByteReadWriter_ResourceListWrapping(t *testing.T) {
singleDeployment := `kind: Deployment
apiVersion: v1
metadata:
name: tester
namespace: default
spec:
replicas: 0`
resourceList := `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- kind: Deployment
apiVersion: v1
metadata:
name: tester
namespace: default
spec:
replicas: 0`
resourceListWithError := `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- kind: Deployment
apiVersion: v1
metadata:
name: tester
namespace: default
spec:
replicas: 0
results:
- message: some error
severity: error`
resourceListDifferentWrapper := strings.NewReplacer(
"kind: ResourceList", "kind: SomethingElse",
"apiVersion: config.kubernetes.io/v1", "apiVersion: fakeVersion",
).Replace(resourceList)
testCases := []struct {
desc string
noWrap bool
wrapKind string
wrapAPIVersion string
input string
want string
}{
{
desc: "resource list",
input: resourceList,
want: resourceList,
},
{
desc: "individual resources",
input: singleDeployment,
want: singleDeployment,
},
{
desc: "no nested wrapping",
wrapKind: kio.ResourceListKind,
wrapAPIVersion: kio.ResourceListAPIVersion,
input: resourceList,
want: resourceList,
},
{
desc: "unwrap resource list",
noWrap: true,
input: resourceList,
want: singleDeployment,
},
{
desc: "wrap individual resources",
wrapKind: kio.ResourceListKind,
wrapAPIVersion: kio.ResourceListAPIVersion,
input: singleDeployment,
want: resourceList,
},
{
desc: "NoWrap has precedence",
noWrap: true,
wrapKind: kio.ResourceListKind,
wrapAPIVersion: kio.ResourceListAPIVersion,
input: singleDeployment,
want: singleDeployment,
},
{
desc: "honor specified wrapping kind",
wrapKind: "SomethingElse",
wrapAPIVersion: "fakeVersion",
input: resourceList,
want: resourceListDifferentWrapper,
},
{
desc: "passthrough results",
input: resourceListWithError,
want: resourceListWithError,
},
}
for i := range testCases {
tc := testCases[i]
t.Run(tc.desc, func(t *testing.T) {
var got bytes.Buffer
rw := kio.ByteReadWriter{
Reader: strings.NewReader(tc.input),
Writer: &got,
NoWrap: tc.noWrap,
WrappingAPIVersion: tc.wrapAPIVersion,
WrappingKind: tc.wrapKind,
}
rnodes, err := rw.Read()
assert.NoError(t, err)
err = rw.Write(rnodes)
assert.NoError(t, err)
assert.Equal(t, tc.want, strings.TrimSpace(got.String()))
})
}
}

View File

@@ -45,7 +45,7 @@ g:
h:
- i # has a list
- j`,
expectedOutput: `apiVersion: config.kubernetes.io/v1alpha1
expectedOutput: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- a: b #first
@@ -299,7 +299,13 @@ g:
`,
},
expectedOutput: `a: b #first
expectedOutput: `e: f
g:
h:
- i # has a list
- j
---
a: b #first
metadata:
annotations:
internal.config.kubernetes.io/path: "a/b/a_test.yaml"
@@ -310,12 +316,6 @@ metadata:
annotations:
internal.config.kubernetes.io/path: "a/b/a_test.yaml"
config.kubernetes.io/path: 'a/b/a_test.yaml'
---
e: f
g:
h:
- i # has a list
- j
`,
},
@@ -477,7 +477,7 @@ metadata:
}`,
},
expectedOutput: `apiVersion: config.kubernetes.io/v1alpha1
expectedOutput: `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- {"a": "b", "metadata": {"annotations": {"internal.config.kubernetes.io/path": "test.json"}}}

View File

@@ -181,6 +181,10 @@ func storeInternalAnnotations(result []*yaml.RNode) (map[string]map[string]strin
if err != nil {
return nil, err
}
if err := checkMismatchedAnnos(meta); err != nil {
return nil, err
}
path := meta.Annotations[kioutil.PathAnnotation]
index := meta.Annotations[kioutil.IndexAnnotation]
id := meta.Annotations[kioutil.IdAnnotation]
@@ -193,6 +197,29 @@ func storeInternalAnnotations(result []*yaml.RNode) (map[string]map[string]strin
return nodeAnnosMap, nil
}
func checkMismatchedAnnos(meta yaml.ResourceMeta) error {
path := meta.Annotations[kioutil.PathAnnotation]
index := meta.Annotations[kioutil.IndexAnnotation]
id := meta.Annotations[kioutil.IdAnnotation]
legacyPath := meta.Annotations[kioutil.LegacyPathAnnotation]
legacyIndex := meta.Annotations[kioutil.LegacyIndexAnnotation]
legacyId := meta.Annotations[kioutil.LegacyIdAnnotation]
// if prior to running the functions, the legacy and internal annotations differ,
// throw an error as we cannot infer the user's intent.
if path != legacyPath {
return fmt.Errorf("resource input to function has mismatched legacy and internal path annotations")
}
if index != legacyIndex {
return fmt.Errorf("resource input to function has mismatched legacy and internal index annotations")
}
if id != legacyId {
return fmt.Errorf("resource input to function has mismatched legacy and internal id annotations")
}
return nil
}
type nodeAnnotations struct {
path string
index string
@@ -217,9 +244,12 @@ func reconcileInternalAnnotations(result []*yaml.RNode, nodeAnnosMap map[string]
if err != nil {
return err
}
// if the annotations are still somehow out of sync, prefer the internal annotations
// and copy them to the legacy ones
err = kioutil.CopyLegacyAnnotations(node)
// if the annotations are still somehow out of sync, throw an error
meta, err = node.GetMeta()
if err != nil {
return err
}
err = checkMismatchedAnnos(meta)
if err != nil {
return err
}

View File

@@ -97,7 +97,7 @@ func TestEmptyInput(t *testing.T) {
}
expected := `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items: []
`
@@ -138,7 +138,7 @@ func TestEmptyInputWithFilter(t *testing.T) {
}
expected := `
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- foo: bar
@@ -233,6 +233,17 @@ func TestLegacyAnnotationReconciliation(t *testing.T) {
}
return nodes, nil
}
changeBothPathAnnos := func(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
for _, rn := range nodes {
if err := rn.PipeE(yaml.SetAnnotation(kioutil.LegacyPathAnnotation, "legacy")); err != nil {
return nil, err
}
if err := rn.PipeE(yaml.SetAnnotation(kioutil.PathAnnotation, "new")); err != nil {
return nil, err
}
}
return nodes, nil
}
noops := []Filter{
FilterFunc(noopFilter1),
@@ -242,11 +253,13 @@ func TestLegacyAnnotationReconciliation(t *testing.T) {
legacy := []Filter{FilterFunc(changeLegacyAnnos)}
legacyId := []Filter{FilterFunc(changeLegacyId)}
internalId := []Filter{FilterFunc(changeInternalId)}
changeBoth := []Filter{FilterFunc(changeBothPathAnnos), FilterFunc(noopFilter1)}
testCases := map[string]struct {
input string
filters []Filter
expected string
input string
filters []Filter
expected string
expectedErr string
}{
// the orchestrator should copy the legacy annotations to the new
// annotations
@@ -510,6 +523,32 @@ data:
grpcPort: 8080
`,
},
// the function changes both the legacy and new path annotation,
// so we should get an error
"change both": {
input: `apiVersion: v1
kind: ConfigMap
metadata:
name: ports-from
annotations:
config.kubernetes.io/path: 'configmap.yaml'
internal.kubernetes.io/path: 'configmap.yaml'
data:
grpcPort: 8080
---
apiVersion: v1
kind: ConfigMap
metadata:
name: ports-to
annotations:
config.kubernetes.io/path: "configmap.yaml"
config.kubernetes.io/index: '1'
data:
grpcPort: 8081
`,
filters: changeBoth,
expectedErr: "resource input to function has mismatched legacy and internal path annotations",
},
}
for tn, tc := range testCases {
@@ -526,8 +565,16 @@ data:
Filters: tc.filters,
Outputs: []Writer{&input},
}
assert.NoError(t, p.Execute())
assert.Equal(t, tc.expected, out.String())
err := p.Execute()
if tc.expectedErr == "" {
assert.NoError(t, err)
assert.Equal(t, tc.expected, out.String())
} else {
assert.Error(t, err)
assert.Equal(t, tc.expectedErr, err.Error())
}
})
}
}

View File

@@ -17,25 +17,29 @@ import (
type AnnotationKey = string
const (
// internalPrefix is the prefix given to internal annotations that are used
// internally by the orchestrator
internalPrefix string = "internal.config.kubernetes.io/"
// IndexAnnotation records the index of a specific resource in a file or input stream.
IndexAnnotation AnnotationKey = "internal.config.kubernetes.io/index"
IndexAnnotation AnnotationKey = internalPrefix + "index"
// PathAnnotation records the path to the file the Resource was read from
PathAnnotation AnnotationKey = "internal.config.kubernetes.io/path"
PathAnnotation AnnotationKey = internalPrefix + "path"
// SeqIndentAnnotation records the sequence nodes indentation of the input resource
SeqIndentAnnotation AnnotationKey = "internal.config.kubernetes.io/seqindent"
SeqIndentAnnotation AnnotationKey = internalPrefix + "seqindent"
// IdAnnotation records the id of the resource to map inputs to outputs
IdAnnotation = "internal.config.kubernetes.io/id"
IdAnnotation AnnotationKey = internalPrefix + "id"
// LegacyIndexAnnotation is the deprecated annotation key for resource index
// Deprecated: Use IndexAnnotation instead.
LegacyIndexAnnotation AnnotationKey = "config.kubernetes.io/index"
// LegacyPathAnnotation is the deprecated annotation key for resource path
// Deprecated: use PathAnnotation instead.
LegacyPathAnnotation AnnotationKey = "config.kubernetes.io/path"
// LegacyIdAnnotation is the deprecated annotation key for resource ids
// Deprecated: use IdAnnotation instead.
LegacyIdAnnotation = "config.k8s.io/id"
)
@@ -55,6 +59,10 @@ func GetFileAnnotations(rn *yaml.RNode) (string, string, error) {
func CopyLegacyAnnotations(rn *yaml.RNode) error {
meta, err := rn.GetMeta()
if err != nil {
if err == yaml.ErrMissingMetadata {
// resource has no metadata, this should be a no-op
return nil
}
return err
}
if err := copyAnnotations(meta, rn, LegacyPathAnnotation, PathAnnotation); err != nil {
@@ -71,12 +79,14 @@ func CopyLegacyAnnotations(rn *yaml.RNode) error {
func copyAnnotations(meta yaml.ResourceMeta, rn *yaml.RNode, legacyKey string, newKey string) error {
newValue := meta.Annotations[newKey]
legacyValue := meta.Annotations[legacyKey]
if newValue != "" {
if err := rn.PipeE(yaml.SetAnnotation(legacyKey, newValue)); err != nil {
return err
if legacyValue == "" {
if err := rn.PipeE(yaml.SetAnnotation(legacyKey, newValue)); err != nil {
return err
}
}
} else {
legacyValue := meta.Annotations[legacyKey]
if legacyValue != "" {
if err := rn.PipeE(yaml.SetAnnotation(newKey, legacyValue)); err != nil {
return err
@@ -305,3 +315,87 @@ func SortNodes(nodes []*yaml.RNode) error {
})
return errors.Wrap(err)
}
// CopyInternalAnnotations copies the annotations that begin with the prefix
// `internal.config.kubernetes.io` from the source RNode to the destination RNode.
// It takes a parameter exclusions, which is a list of annotation keys to ignore.
func CopyInternalAnnotations(src *yaml.RNode, dst *yaml.RNode, exclusions ...AnnotationKey) error {
srcAnnotations := GetInternalAnnotations(src)
for k, v := range srcAnnotations {
if stringSliceContains(exclusions, k) {
continue
}
if err := dst.PipeE(yaml.SetAnnotation(k, v)); err != nil {
return err
}
}
return nil
}
// ConfirmInternalAnnotationUnchanged compares the annotations of the RNodes that begin with the prefix
// `internal.config.kubernetes.io`, throwing an error if they differ. It takes a parameter exclusions,
// which is a list of annotation keys to ignore.
func ConfirmInternalAnnotationUnchanged(r1 *yaml.RNode, r2 *yaml.RNode, exclusions ...AnnotationKey) error {
r1Annotations := GetInternalAnnotations(r1)
r2Annotations := GetInternalAnnotations(r2)
// this is a map to prevent duplicates
diffAnnos := make(map[string]bool)
for k, v1 := range r1Annotations {
if stringSliceContains(exclusions, k) {
continue
}
if v2, ok := r2Annotations[k]; !ok || v1 != v2 {
diffAnnos[k] = true
}
}
for k, v2 := range r2Annotations {
if stringSliceContains(exclusions, k) {
continue
}
if v1, ok := r1Annotations[k]; !ok || v2 != v1 {
diffAnnos[k] = true
}
}
if len(diffAnnos) > 0 {
keys := make([]string, 0, len(diffAnnos))
for k := range diffAnnos {
keys = append(keys, k)
}
sort.Strings(keys)
errorString := "internal annotations differ: "
for _, key := range keys {
errorString = errorString + key + ", "
}
return errors.Errorf(errorString[0 : len(errorString)-2])
}
return nil
}
// GetInternalAnnotations returns a map of all the annotations of the provided RNode that begin
// with the prefix `internal.config.kubernetes.io`
func GetInternalAnnotations(rn *yaml.RNode) map[string]string {
annotations := rn.GetAnnotations()
result := make(map[string]string)
for k, v := range annotations {
if strings.HasPrefix(k, internalPrefix) {
result[k] = v
}
}
return result
}
// stringSliceContains returns true if the slice has the string.
func stringSliceContains(slice []string, str string) bool {
for _, s := range slice {
if s == str {
return true
}
}
return false
}

View File

@@ -374,3 +374,330 @@ func TestCreatePathAnnotationValue(t *testing.T) {
}
}
}
func TestCopyLegacyAnnotations(t *testing.T) {
var tests = []struct {
input string
expected string
}{
{
input: `apiVersion: v1
kind: Foo
metadata:
name: foobar
annotations:
config.kubernetes.io/path: 'a/b.yaml'
config.kubernetes.io/index: '5'
`,
expected: `apiVersion: v1
kind: Foo
metadata:
name: foobar
annotations:
config.kubernetes.io/path: 'a/b.yaml'
config.kubernetes.io/index: '5'
internal.config.kubernetes.io/path: 'a/b.yaml'
internal.config.kubernetes.io/index: '5'
`,
},
{
input: `apiVersion: v1
kind: Foo
metadata:
name: foobar
annotations:
internal.config.kubernetes.io/path: 'a/b.yaml'
internal.config.kubernetes.io/index: '5'
`,
expected: `apiVersion: v1
kind: Foo
metadata:
name: foobar
annotations:
internal.config.kubernetes.io/path: 'a/b.yaml'
internal.config.kubernetes.io/index: '5'
config.kubernetes.io/path: 'a/b.yaml'
config.kubernetes.io/index: '5'
`,
},
{
input: `apiVersion: v1
kind: Foo
metadata:
name: foobar
annotations:
internal.config.kubernetes.io/path: 'a/b.yaml'
config.kubernetes.io/path: 'c/d.yaml'
`,
expected: `apiVersion: v1
kind: Foo
metadata:
name: foobar
annotations:
internal.config.kubernetes.io/path: 'a/b.yaml'
config.kubernetes.io/path: 'c/d.yaml'
`,
},
}
for _, tc := range tests {
rw := kio.ByteReadWriter{
Reader: bytes.NewBufferString(tc.input),
OmitReaderAnnotations: true,
}
nodes, err := rw.Read()
assert.NoError(t, err)
assert.NoError(t, kioutil.CopyLegacyAnnotations(nodes[0]))
assert.Equal(t, tc.expected, nodes[0].MustString())
}
}
func TestCopyInternalAnnotations(t *testing.T) {
var tests = []struct {
input string
exclusions []kioutil.AnnotationKey
expected string
}{
{
input: `apiVersion: v1
kind: Foo
metadata:
name: src
annotations:
internal.config.kubernetes.io/path: 'a/b.yaml'
internal.config.kubernetes.io/index: '5'
internal.config.kubernetes.io/foo: 'bar'
---
apiVersion: v1
kind: Foo
metadata:
name: dst
annotations:
internal.config.kubernetes.io/path: 'c/d.yaml'
internal.config.kubernetes.io/index: '10'
`,
expected: `apiVersion: v1
kind: Foo
metadata:
name: dst
annotations:
internal.config.kubernetes.io/path: 'a/b.yaml'
internal.config.kubernetes.io/index: '5'
internal.config.kubernetes.io/foo: 'bar'
`,
},
{
input: `apiVersion: v1
kind: Foo
metadata:
name: src
annotations:
internal.config.kubernetes.io/path: 'a/b.yaml'
internal.config.kubernetes.io/index: '5'
internal.config.kubernetes.io/foo: 'bar-src'
---
apiVersion: v1
kind: Foo
metadata:
name: dst
annotations:
internal.config.kubernetes.io/path: 'c/d.yaml'
internal.config.kubernetes.io/index: '10'
internal.config.kubernetes.io/foo: 'bar-dst'
`,
exclusions: []kioutil.AnnotationKey{
kioutil.PathAnnotation,
kioutil.IndexAnnotation,
},
expected: `apiVersion: v1
kind: Foo
metadata:
name: dst
annotations:
internal.config.kubernetes.io/path: 'c/d.yaml'
internal.config.kubernetes.io/index: '10'
internal.config.kubernetes.io/foo: 'bar-src'
`,
},
}
for _, tc := range tests {
rw := kio.ByteReadWriter{
Reader: bytes.NewBufferString(tc.input),
OmitReaderAnnotations: true,
}
nodes, err := rw.Read()
assert.NoError(t, err)
assert.NoError(t, kioutil.CopyInternalAnnotations(nodes[0], nodes[1], tc.exclusions...))
assert.Equal(t, tc.expected, nodes[1].MustString())
}
}
func TestConfirmInternalAnnotationUnchanged(t *testing.T) {
var tests = []struct {
input string
exclusions []kioutil.AnnotationKey
expectedErr string
}{
{
input: `apiVersion: v1
kind: Foo
metadata:
name: foo-1
annotations:
internal.config.kubernetes.io/path: 'a/b.yaml'
internal.config.kubernetes.io/index: '5'
---
apiVersion: v1
kind: Foo
metadata:
name: foo-2
annotations:
internal.config.kubernetes.io/path: 'c/d.yaml'
internal.config.kubernetes.io/index: '10'
`,
expectedErr: `internal annotations differ: internal.config.kubernetes.io/index, internal.config.kubernetes.io/path`,
},
{
input: `apiVersion: v1
kind: Foo
metadata:
name: foo-1
annotations:
internal.config.kubernetes.io/path: 'a/b.yaml'
internal.config.kubernetes.io/index: '5'
---
apiVersion: v1
kind: Foo
metadata:
name: foo-2
annotations:
internal.config.kubernetes.io/path: 'c/d.yaml'
internal.config.kubernetes.io/index: '10'
`,
exclusions: []kioutil.AnnotationKey{
kioutil.PathAnnotation,
kioutil.IndexAnnotation,
},
expectedErr: ``,
},
{
input: `apiVersion: v1
kind: Foo
metadata:
name: foo-1
annotations:
internal.config.kubernetes.io/path: 'a/b.yaml'
internal.config.kubernetes.io/index: '5'
internal.config.kubernetes.io/foo: 'bar-1'
---
apiVersion: v1
kind: Foo
metadata:
name: foo-2
annotations:
internal.config.kubernetes.io/path: 'c/d.yaml'
internal.config.kubernetes.io/index: '10'
internal.config.kubernetes.io/foo: 'bar-2'
`,
exclusions: []kioutil.AnnotationKey{
kioutil.PathAnnotation,
kioutil.IndexAnnotation,
},
expectedErr: `internal annotations differ: internal.config.kubernetes.io/foo`,
},
{
input: `apiVersion: v1
kind: Foo
metadata:
name: foo-1
annotations:
internal.config.kubernetes.io/path: 'a/b.yaml'
internal.config.kubernetes.io/index: '5'
internal.config.kubernetes.io/foo: 'bar-1'
---
apiVersion: v1
kind: Foo
metadata:
name: foo-2
annotations:
internal.config.kubernetes.io/path: 'c/d.yaml'
internal.config.kubernetes.io/index: '10'
internal.config.kubernetes.io/foo: 'bar-1'
`,
expectedErr: `internal annotations differ: internal.config.kubernetes.io/index, internal.config.kubernetes.io/path`,
},
{
input: `apiVersion: v1
kind: Foo
metadata:
name: foo-1
annotations:
internal.config.kubernetes.io/a: 'b'
internal.config.kubernetes.io/c: 'd'
---
apiVersion: v1
kind: Foo
metadata:
name: foo-2
annotations:
internal.config.kubernetes.io/e: 'f'
internal.config.kubernetes.io/g: 'h'
`,
expectedErr: `internal annotations differ: internal.config.kubernetes.io/a, internal.config.kubernetes.io/c, internal.config.kubernetes.io/e, internal.config.kubernetes.io/g`,
},
}
for _, tc := range tests {
rw := kio.ByteReadWriter{
Reader: bytes.NewBufferString(tc.input),
OmitReaderAnnotations: true,
}
nodes, err := rw.Read()
assert.NoError(t, err)
err = kioutil.ConfirmInternalAnnotationUnchanged(nodes[0], nodes[1], tc.exclusions...)
if tc.expectedErr == "" {
assert.NoError(t, err)
} else {
if err == nil {
t.Fatalf("expected error: %s\n", tc.expectedErr)
}
assert.Equal(t, tc.expectedErr, err.Error())
}
}
}
func TestGetInternalAnnotations(t *testing.T) {
var tests = []struct {
input string
expected map[string]string
}{
{
input: `apiVersion: v1
kind: Foo
metadata:
name: foobar
annotations:
foo: bar
internal.config.kubernetes.io/path: 'a/b.yaml'
internal.config.kubernetes.io/index: '5'
internal.config.kubernetes.io/foo: 'bar'
`,
expected: map[string]string{
"internal.config.kubernetes.io/path": "a/b.yaml",
"internal.config.kubernetes.io/index": "5",
"internal.config.kubernetes.io/foo": "bar",
},
},
}
for _, tc := range tests {
rw := kio.ByteReadWriter{
Reader: bytes.NewBufferString(tc.input),
OmitReaderAnnotations: true,
}
nodes, err := rw.Read()
assert.NoError(t, err)
assert.Equal(t, tc.expected, kioutil.GetInternalAnnotations(nodes[0]))
}
}

View File

@@ -555,6 +555,8 @@ func SetSchema(openAPIField map[string]string, schema []byte, reset bool) error
if schema != nil { // use custom schema
customSchema = schema
kubernetesOpenAPIVersion = "custom"
// if the schema is changed, initSchema should parse the new schema
globalSchema.schemaInit = false
return nil
}
@@ -567,6 +569,8 @@ func SetSchema(openAPIField map[string]string, schema []byte, reset bool) error
return fmt.Errorf("the specified OpenAPI version is not built in")
}
customSchema = nil
// if the schema is changed, initSchema should parse the new schema
globalSchema.schemaInit = false
return nil
}

View File

@@ -4,6 +4,7 @@
package resid
import (
"reflect"
"strings"
)
@@ -129,3 +130,9 @@ func (id ResId) EffectiveNamespace() string {
}
return id.Namespace
}
// IsEmpty returns true of all of the id's fields are
// empty strings
func (id ResId) IsEmpty() bool {
return reflect.DeepEqual(id, ResId{})
}

View File

@@ -1,6 +1,7 @@
// Code generated by k8scopy from k8s.io/apimachinery@v0.19.8; DO NOT EDIT.
// File content copied from k8s.io/apimachinery@v0.19.8/pkg/labels/zz_generated.deepcopy.go
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*

View File

@@ -13,6 +13,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"
)
@@ -82,12 +83,23 @@ func (p *plugin) Transform(m resmap.ResMap) error {
return err
}
for _, res := range resources {
internalAnnotations := kioutil.GetInternalAnnotations(&res.RNode)
err = res.ApplyFilter(patchjson6902.Filter{
Patch: p.JsonOp,
})
if err != nil {
return err
}
annotations := res.GetAnnotations()
for key, value := range internalAnnotations {
annotations[key] = value
}
err = res.SetAnnotations(annotations)
if err != nil {
return err
}
}
return nil
}

View File

@@ -6,6 +6,7 @@ require (
github.com/evanphx/json-patch v4.11.0+incompatible
github.com/pkg/errors v0.9.1
sigs.k8s.io/kustomize/api v0.8.9
sigs.k8s.io/kustomize/kyaml v0.13.0
sigs.k8s.io/yaml v1.2.0
)

View File

@@ -13,6 +13,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"
)
@@ -115,12 +116,19 @@ func (p *plugin) transformJson6902(m resmap.ResMap, patch jsonpatch.Patch) error
}
for _, res := range resources {
res.StorePreviousId()
internalAnnotations := kioutil.GetInternalAnnotations(&res.RNode)
err = res.ApplyFilter(patchjson6902.Filter{
Patch: p.Patch,
})
if err != nil {
return err
}
annotations := res.GetAnnotations()
for key, value := range internalAnnotations {
annotations[key] = value
}
err = res.SetAnnotations(annotations)
}
return nil
}

View File

@@ -5,6 +5,7 @@ go 1.16
require (
github.com/evanphx/json-patch v4.11.0+incompatible
sigs.k8s.io/kustomize/api v0.8.9
sigs.k8s.io/kustomize/kyaml v0.13.0
sigs.k8s.io/yaml v1.2.0
)

View File

@@ -4,7 +4,7 @@ go 1.16
require (
sigs.k8s.io/kustomize/api v0.8.9
sigs.k8s.io/kustomize/kyaml v0.12.0
sigs.k8s.io/kustomize/kyaml v0.13.0
sigs.k8s.io/yaml v1.2.0
)

View File

@@ -4,7 +4,7 @@ go 1.16
require (
sigs.k8s.io/kustomize/api v0.8.9
sigs.k8s.io/kustomize/kyaml v0.12.0
sigs.k8s.io/kustomize/kyaml v0.13.0
sigs.k8s.io/yaml v1.2.0
)

View File

@@ -11,6 +11,7 @@
[`cloudbuild.yaml`]: cloudbuild.yaml
[kustomize repo release page]: https://github.com/kubernetes-sigs/kustomize/releases
[OpenAPI Readme]: ../kyaml/openapi/README.md
[project cloud build history page]: https://console.cloud.google.com/cloud-build/builds?project=k8s-staging-kustomize
This document describes how to perform a [semver release]
of one of the several [Go modules] in this repository.
@@ -86,7 +87,7 @@ echo $GITHUB_TOKEN | gh auth login --scopes repo --with-token
#### Establish clean state
```
refreshMaster
refreshMaster &&
testKustomizeRepo
```
@@ -108,6 +109,9 @@ Note the version:
versionKyaml=v0.10.20 # EDIT THIS!
```
See the process of the cloud build job
on the [project cloud build history page].
Undraft the release on the [kustomize repo release page]:
* Make sure the version number is what you expect.
* Remove references to commits that aren't relevant to end users of this module (e.g. test commits, refactors).
@@ -119,16 +123,18 @@ Undraft the release on the [kustomize repo release page]:
#### Pin to the most recent kyaml
```
gorepomod pin kyaml --doIt
go mod edit -require=sigs.k8s.io/kustomize/kyaml@$versionKyaml plugin/builtin/prefixsuffixtransformer/go.mod
go mod edit -require=sigs.k8s.io/kustomize/kyaml@$versionKyaml plugin/builtin/replicacounttransformer/go.mod
gorepomod pin kyaml --doIt &&
go mod edit -require=sigs.k8s.io/kustomize/kyaml@$versionKyaml plugin/builtin/prefixsuffixtransformer/go.mod &&
go mod edit -require=sigs.k8s.io/kustomize/kyaml@$versionKyaml plugin/builtin/replicacounttransformer/go.mod &&
go mod edit -require=sigs.k8s.io/kustomize/kyaml@$versionKyaml plugin/builtin/patchtransformer/go.mod &&
go mod edit -require=sigs.k8s.io/kustomize/kyaml@$versionKyaml plugin/builtin/patchjson6902transformer/go.mod
```
Create the PR:
```
title="Pin to kyaml $versionKyaml"
createBranch pinToKyaml $title
createBranch pinToKyaml "Pin to kyaml $versionKyaml"
```
```
createPr
```
@@ -140,12 +146,14 @@ testKustomizeRepo
Wait for tests to pass, then merge the PR:
```
gh pr status
```
```
gh pr merge -m
```
Get back on master and do paranoia test:
```
refreshMaster
refreshMaster &&
testKustomizeRepo
```
@@ -162,6 +170,9 @@ Note the version:
versionCmdConfig=v0.9.12 # EDIT THIS!
```
See the process of the cloud build job
on the [project cloud build history page].
Undraft the release on the [kustomize repo release page]:
* Make sure the version number is what you expect.
* Remove references to commits that aren't relevant to end users of this module (e.g. test commits, refactors).
@@ -181,8 +192,7 @@ gorepomod pin cmd/config --doIt
Create the PR:
```
title="Pin to cmd/config $versionCmdConfig"
createBranch pinToCmdConfig $title
createBranch pinToCmdConfig "Pin to cmd/config $versionCmdConfig" &&
createPr
```
@@ -194,12 +204,14 @@ testKustomizeRepo
Wait for tests to pass, then merge the PR:
```
gh pr status # rinse, repeat
```
```
gh pr merge -m
```
Get back on master and do paranoia test:
```
refreshMaster
refreshMaster &&
testKustomizeRepo
```
@@ -216,6 +228,9 @@ Note the version:
versionApi=v0.8.10 # EDIT THIS!
```
See the process of the cloud build job
on the [project cloud build history page].
Undraft the release on the [kustomize repo release page]:
* Make sure the version number is what you expect.
* Remove references to commits that aren't relevant to end users of this module (e.g. test commits, refactors).
@@ -232,8 +247,7 @@ gorepomod pin api --doIt
Create the PR:
```
title="Pin to api $versionApi"
createBranch pinToApi $title
createBranch pinToApi "Pin to api $versionApi" &&
createPr
```
@@ -245,12 +259,14 @@ testKustomizeRepo
Wait for tests to pass, then merge the PR:
```
gh pr status # rinse, repeat
```
```
gh pr merge -m
```
Get back on master and do paranoia test:
```
refreshMaster
refreshMaster &&
testKustomizeRepo
```
@@ -262,6 +278,9 @@ While you're waiting for the tests, review the commit log. Based on the changes
gorepomod release kustomize [patch|minor|major] --doIt
```
See the process of the cloud build job
on the [project cloud build history page].
Undraft the release on the [kustomize repo release page]:
* Make sure the version number is what you expect.
* Remove references to commits that aren't relevant to end users of the CLI (e.g. test commits, refactors, changes that only surface in Go).
@@ -269,14 +288,14 @@ Undraft the release on the [kustomize repo release page]:
## Confirm the kustomize binary is correct
> [installation instructions]: https://kubectl.docs.kubernetes.io/installation/kustomize/binaries/
>
> * Follow the [installation instructions] to install your new
> release and make sure it reports the expected version number.
>
> If not, something is very wrong.
>
> * Visit the [release page] and edit the release notes as desired.
[installation instructions]: https://kubectl.docs.kubernetes.io/installation/kustomize/binaries/
* Follow the [installation instructions] to install your new
release and make sure it reports the expected version number.
If not, something is very wrong.
* Visit the [release page] and edit the release notes as desired.
## Unpin everything
@@ -285,15 +304,14 @@ Undraft the release on the [kustomize repo release page]:
Go back into development mode, where all modules depend on in-repo code:
```
gorepomod unpin api --doIt
gorepomod unpin cmd/config --doIt
gorepomod unpin api --doIt &&
gorepomod unpin cmd/config --doIt &&
gorepomod unpin kyaml --doIt
```
Create the PR:
```
title="Back to development mode; unpin the modules"
createBranch unpinEverything
createBranch unpinEverything "Back to development mode; unpin the modules" &&
createPr
```
@@ -305,12 +323,14 @@ testKustomizeRepo
Wait for tests to pass, then merge the PR:
```
gh pr status # rinse, repeat
```
```
gh pr merge -m
```
Get back on master and do paranoia test:
```
refreshMaster
refreshMaster &&
testKustomizeRepo
```
@@ -323,14 +343,17 @@ to test examples against your new release.
```
sed -i "" "s/LATEST_V4_RELEASE=.*/LATEST_V4_RELEASE=v4.3.0/" Makefile
title="Test examples against latest release"
createBranch updateProwExamplesTarget $title
```
```
createBranch updateProwExamplesTarget "Test examples against latest release" &&
createPr
```
Wait for tests to pass, then merge the PR:
```
gh pr status # rinse, repeat
```
```
gh pr merge -m
```
@@ -574,14 +597,32 @@ git push upstream :latest_kustomize
git tag -a latest_kustomize
```
### Optionally build a release locally
### Optionally build locally
[localbuild.sh]: localbuild.sh
Install [`cloud-build-local`], then run [localbuild.sh]:
Load the same version of `goreleaser` referenced in `cloudbuild.yaml` via docker and run [localbuild.sh] from the container's command line:
```
./releasing/localbuild.sh $module
# Get goreleaser image from cloudbuild.yaml
export GORELEASER_IMAGE=goreleaser/goreleaser:v0.172.1
# Drop into a shell
docker run -it --entrypoint=/bin/bash -v $(pwd):/go/src/github.com/kubernetes-sigs/kustomize -w /go/src/github.com/kubernetes-sigs/kustomize $GORELEASER_IMAGE
# Run build
./releasing/localbuild.sh TAG [--snapshot]
```
### Optionally build and release locally
[cloudbuild-local.sh]: cloudbuild-local.sh
Install [`cloud-build-local`], then run [cloudbuild-local.sh]:
```
./releasing/cloudbuild-local.sh $module
```
This should create release artifacts in a local directory.

54
releasing/cloudbuild-local.sh Executable file
View File

@@ -0,0 +1,54 @@
#!/bin/bash
#
# To test the release process, this script attempts
# to use a Google cloudbuild configuration to create
# release artifacts locally.
#
# See https://cloud.google.com/cloud-build/docs/build-debug-locally
#
# Usage: from the repo root, enter:
#
# ./releasing/cloudbuild-local.sh kustomize/v1.2.3
#
# or some other valid tag value.
#
# IMPORTANT:
# The process clones the repo at the given tag,
# so the repo must have the tag applied upstream.
# Either use an old tag, or disable the cloud build
# trigger so that a new testing tag can be applied
# without setting off a cloud build.
set -e
config=$(mktemp)
cp releasing/cloudbuild.yaml $config
# Add the --snapshot flag to suppress the
# github release and leave the build output
# in the kustomize/dist directory.
sed -i "s|# - '--snapshot|- '--snapshot|" $config
echo "Executing cloud-build-local with config file $config :"
echo "========================="
cat $config
echo "========================="
workspace=~/cloud-build-local-workspace
cloud-build-local \
--config=$config \
--substitutions=TAG_NAME=$1 \
--write-workspace=$workspace \
--dryrun=false \
.
# --bind-mount-source \
echo " "
echo "Result of local build:"
echo "##########################################"
tree ./$module/dist
echo "##########################################"
tree ./$workspace
echo "##########################################"

View File

@@ -92,10 +92,13 @@ builds:
goos:
- linux
- darwin
- windows
goarch:
- amd64
- arm64
- s390x
- ppc64le
checksum:
name_template: 'checksums.txt'
@@ -117,8 +120,9 @@ cat $goReleaserConfigFile
date
time /usr/local/bin/goreleaser release \
--debug \
--timeout 10m \
--parallelism 4 \
--parallelism 7 \
--config=$goReleaserConfigFile \
--release-notes=$changeLogFile \
--rm-dist \

View File

@@ -57,6 +57,6 @@ timeout: 14m
# The base64 of that is shown below. It's decrypted by cloud build
# and provided back to goreleaser.
secrets:
- kmsKeyName: projects/jregan-corp-gke-dev/locations/global/keyRings/kust-cloud-key-ring/cryptoKeys/kust-cloud-key-name
- kmsKeyName: projects/k8s-staging-kustomize/locations/global/keyRings/kust-cloud-key-ring/cryptoKeys/kust-cloud-key-name
secretEnv:
GITHUB_TOKEN: CiQAwfbOkSP4tJf3ZJZMjzHaRPZ2RxiQhORZ3xxlVtpoy8631uQSUACk6WMKjtkpsRkRl+uxWUVvN29M5qveyXjaDDO094/qwsSc8RiYlHYt7Ii1bWkkz3P1kG0nHfG7Fd46A+GJ6R5NhmNfingd/nu9iKrNwLXK
GITHUB_TOKEN: CiQAJ+XRL07Aror04bf6N0PpMDxRpxzs1PXVVDztB+HNu3fW7FESUQA2EggaBGI1cpFJC1YT93h9r50WzyLMD28LDDBTO8QJxZsU6UEToBfpVDr0ohnSazBTbvCcy5NJK0ooKyDifFsKzkT5ym3LPyHzPIXiejCmAg==

View File

@@ -1,54 +1,127 @@
#!/bin/bash
#
# To test the release process, this script attempts
# to use a Google cloudbuild configuration to create
# release artifacts locally.
# Works exactly like cloudbuild.sh but doesn't perform a release.
#
# See https://cloud.google.com/cloud-build/docs/build-debug-locally
# Usage (from top of repo):
#
# Usage: from the repo root, enter:
# releasing/localbuild.sh TAG [--snapshot]
#
# ./releasing/localbuild.sh kustomize/v1.2.3
# Where TAG is in the form
#
# or some other valid tag value.
# api/v1.2.3
# kustomize/v1.2.3
# cmd/config/v1.2.3
# ... etc.
#
# This script runs a build through goreleaser (http://goreleaser.com) but nothing else.
#
# IMPORTANT:
# The process clones the repo at the given tag,
# so the repo must have the tag applied upstream.
# Either use an old tag, or disable the cloud build
# trigger so that a new testing tag can be applied
# without setting off a cloud build.
set -e
set -x
config=$(mktemp)
cp releasing/cloudbuild.yaml $config
fullTag=$1
shift
echo "fullTag=$fullTag"
# Add the --snapshot flag to suppress the
# github release and leave the build output
# in the kustomize/dist directory.
sed -i "s|# - '--snapshot|- '--snapshot|" $config
remainingArgs="$@"
echo "Remaining args: $remainingArgs"
echo "Executing cloud-build-local with config file $config :"
echo "========================="
cat $config
echo "========================="
# Take everything before the last slash.
# This is expected to match $module.
module=${fullTag%/*}
echo "module=$module"
workspace=~/cloud-build-local-workspace
# Find previous tag that matches the tags module
prevTag=$(git tag -l "$module*" --sort=-version:refname --no-contains=$fullTag | head -n 1)
cloud-build-local \
--config=$config \
--substitutions=TAG_NAME=$1 \
--write-workspace=$workspace \
--dryrun=false \
.
# Generate the changelog for this release
# using the last two tags for the module
changeLogFile=$(mktemp)
git log $prevTag..$fullTag \
--pretty=oneline \
--abbrev-commit --no-decorate --no-color --no-merges \
-- $module > $changeLogFile
echo "Release notes:"
cat $changeLogFile
# --bind-mount-source \
# Take everything after the last slash.
# This should be something like "v1.2.3".
semVer=`echo $fullTag | sed "s|$module/||"`
echo "semVer=$semVer"
echo " "
echo "Result of local build:"
echo "##########################################"
tree ./$module/dist
echo "##########################################"
tree ./$workspace
echo "##########################################"
# This is probably a directory called /workspace
echo "pwd = $PWD"
# Sanity check
echo "### ls -las . ################################"
ls -las .
echo "###################################"
# CD into the module directory.
# This directory expected to contain a main.go, so there's
# no need for extra details in the `build` stanza below.
cd $module
skipBuild=true
if [[ "$module" == "kustomize" || "$module" == "pluginator" ]]; then
# If releasing a main program, don't skip the build.
skipBuild=false
fi
goReleaserConfigFile=$(mktemp)
cat <<EOF >$goReleaserConfigFile
project_name: $module
archives:
- name_template: "${module}_${semVer}_{{ .Os }}_{{ .Arch }}"
builds:
- skip: $skipBuild
ldflags: >
-s
-X sigs.k8s.io/kustomize/api/provenance.version={{.Version}}
-X sigs.k8s.io/kustomize/api/provenance.gitCommit={{.Commit}}
-X sigs.k8s.io/kustomize/api/provenance.buildDate={{.Date}}
goos:
- linux
- darwin
- windows
goarch:
- amd64
- arm64
- s390x
- ppc64le
checksum:
name_template: 'checksums.txt'
env:
- CGO_ENABLED=0
- GO111MODULE=on
release:
github:
owner: kubernetes-sigs
name: kustomize
draft: true
EOF
cat $goReleaserConfigFile
date
time /usr/local/bin/goreleaser build \
--debug \
--timeout 10m \
--parallelism 7 \
--config=$goReleaserConfigFile \
--rm-dist \
--skip-validate $remainingArgs
date