mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-16 03:18:16 +00:00
Compare commits
72 Commits
api/v0.10.
...
release-ap
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
326a57a9cc | ||
|
|
9dfdebc6c7 | ||
|
|
b896e04c20 | ||
|
|
6ecae1ad50 | ||
|
|
9abb72e4d6 | ||
|
|
6365b3d0cf | ||
|
|
33c2ea01c4 | ||
|
|
863ff0ef1b | ||
|
|
a5117083ec | ||
|
|
a143688a1d | ||
|
|
0676d0bd11 | ||
|
|
b6cb6c8ae9 | ||
|
|
b16e4ec566 | ||
|
|
cb1cbbe044 | ||
|
|
86fb408b2c | ||
|
|
ca5d691199 | ||
|
|
394567079d | ||
|
|
e0c8ebc41f | ||
|
|
8668691ade | ||
|
|
374d790a21 | ||
|
|
d8f406d06f | ||
|
|
46b3cd2109 | ||
|
|
20c608989a | ||
|
|
ba4d83f75f | ||
|
|
067559127d | ||
|
|
37ab5579f0 | ||
|
|
ef5f1d347d | ||
|
|
2c4b195516 | ||
|
|
04396ab4e6 | ||
|
|
4fd77b3a6e | ||
|
|
3ea8b79925 | ||
|
|
71b978da1a | ||
|
|
7110298c52 | ||
|
|
b4a69f08c0 | ||
|
|
572d5841c6 | ||
|
|
984a2dab3d | ||
|
|
c3c02887ec | ||
|
|
ba051c863b | ||
|
|
4d59146e48 | ||
|
|
5765ab4dbc | ||
|
|
4769751943 | ||
|
|
e506ce021e | ||
|
|
ed763991de | ||
|
|
55ac9ca88d | ||
|
|
548f5ffca9 | ||
|
|
dd3377b1a0 | ||
|
|
605239a1e5 | ||
|
|
67c58ad4f4 | ||
|
|
11e19a3d0f | ||
|
|
6fffcb9203 | ||
|
|
68790e00a9 | ||
|
|
6cf06fac12 | ||
|
|
0d8c107362 | ||
|
|
f30e45c549 | ||
|
|
250ea13767 | ||
|
|
608128738d | ||
|
|
7153f33466 | ||
|
|
274b12318d | ||
|
|
94c82f61a3 | ||
|
|
d260f50573 | ||
|
|
40c014a991 | ||
|
|
75c8aec29d | ||
|
|
fcb9c0065e | ||
|
|
63ec6bdb3d | ||
|
|
25bfe6f306 | ||
|
|
635c4fd43b | ||
|
|
c455215f55 | ||
|
|
8f56f51307 | ||
|
|
70a8ed6ed3 | ||
|
|
febfaf16dc | ||
|
|
8268b17700 | ||
|
|
f7cd553044 |
8
.github/workflows/go.yml
vendored
8
.github/workflows/go.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ^1.13
|
||||
go-version: ^1.16
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ^1.13
|
||||
go-version: ^1.16
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ^1.13
|
||||
go-version: ^1.16
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
@@ -91,7 +91,7 @@ jobs:
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ^1.13
|
||||
go-version: ^1.16
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
|
||||
5
Makefile
5
Makefile
@@ -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:
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
@@ -78,12 +79,23 @@ func (p *PatchJson6902TransformerPlugin) Transform(m resmap.ResMap) error {
|
||||
return err
|
||||
}
|
||||
for _, res := range resources {
|
||||
internalAnnotations := kioutil.GetInternalAnnotations(&res.RNode)
|
||||
|
||||
err = res.ApplyFilter(patchjson6902.Filter{
|
||||
Patch: p.JsonOp,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
annotations := res.GetAnnotations()
|
||||
for key, value := range internalAnnotations {
|
||||
annotations[key] = value
|
||||
}
|
||||
err = res.SetAnnotations(annotations)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
@@ -111,12 +112,19 @@ func (p *PatchTransformerPlugin) transformJson6902(m resmap.ResMap, patch jsonpa
|
||||
}
|
||||
for _, res := range resources {
|
||||
res.StorePreviousId()
|
||||
internalAnnotations := kioutil.GetInternalAnnotations(&res.RNode)
|
||||
err = res.ApplyFilter(patchjson6902.Filter{
|
||||
Patch: p.Patch,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
annotations := res.GetAnnotations()
|
||||
for key, value := range internalAnnotations {
|
||||
annotations[key] = value
|
||||
}
|
||||
err = res.SetAnnotations(annotations)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -1646,3 +1646,64 @@ spec:
|
||||
type: NodePort
|
||||
`)
|
||||
}
|
||||
|
||||
// test for #4111
|
||||
func TestPatchPreservesInternalAnnotations(t *testing.T) {
|
||||
th := kusttest_test.MakeHarness(t)
|
||||
th.WriteK(".", `
|
||||
nameSuffix: -abc
|
||||
resources:
|
||||
- fluentd.yaml
|
||||
patchesJson6902:
|
||||
- path: patch.yaml
|
||||
target:
|
||||
name: fluentd-sa
|
||||
kind: ServiceAccount
|
||||
version: v1
|
||||
`)
|
||||
th.WriteF("fluentd.yaml", `
|
||||
apiVersion: v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: fluentd
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: fluentd:latest
|
||||
name: fluentd
|
||||
serviceAccountName: fluentd-sa
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: fluentd-sa
|
||||
`)
|
||||
th.WriteF("patch.yaml", `
|
||||
- op: add
|
||||
path: /metadata/annotations
|
||||
value:
|
||||
note: this is a test annotation
|
||||
`)
|
||||
m := th.Run(".", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: fluentd-abc
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: fluentd:latest
|
||||
name: fluentd
|
||||
serviceAccountName: fluentd-sa-abc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
annotations:
|
||||
note: this is a test annotation
|
||||
name: fluentd-sa-abc
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ package krusty_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -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
|
||||
`)
|
||||
}
|
||||
|
||||
76
api/krusty/testdata/openshiftschema.json
vendored
Normal file
76
api/krusty/testdata/openshiftschema.json
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"definitions": {
|
||||
"com.github.openshift.api.apps.v1.DeploymentConfig": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"spec"
|
||||
],
|
||||
"properties": {
|
||||
"apiVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta"
|
||||
},
|
||||
"spec": {
|
||||
"$ref": "#/definitions/com.github.openshift.api.apps.v1.DeploymentConfigSpec"
|
||||
}
|
||||
},
|
||||
"x-kubernetes-group-version-kind": [
|
||||
{
|
||||
"group": "apps.openshift.io",
|
||||
"kind": "DeploymentConfig",
|
||||
"version": "v1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"com.github.openshift.api.apps.v1.DeploymentConfigSpec": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"template": {
|
||||
"$ref": "#/definitions/io.k8s.api.core.v1.PodTemplateSpec"
|
||||
}
|
||||
}
|
||||
},
|
||||
"io.k8s.api.core.v1.Volume": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"configMap": {
|
||||
"$ref": "#/definitions/io.k8s.api.core.v1.ConfigMapVolumeSource"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"io.k8s.api.core.v1.VolumeMount": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"mountPath"
|
||||
],
|
||||
"properties": {
|
||||
"mountPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
14
api/kv/kv.go
14
api/kv/kv.go
@@ -209,5 +209,17 @@ func parseLiteralSource(source string) (keyName, value string, err error) {
|
||||
if len(items) != 2 {
|
||||
return "", "", fmt.Errorf("invalid literal source %v, expected key=value", source)
|
||||
}
|
||||
return items[0], strings.Trim(items[1], "\"'"), nil
|
||||
return items[0], removeQuotes(items[1]), nil
|
||||
}
|
||||
|
||||
// removeQuotes removes the surrounding quotes from the provided string only if it is surrounded on both sides
|
||||
// rather than blindly trimming all quotation marks on either side.
|
||||
func removeQuotes(str string) string {
|
||||
if len(str) == 0 || str[0] != str[len(str)-1] {
|
||||
return str
|
||||
}
|
||||
if str[0] == '"' || str[0] == '\'' {
|
||||
return str[1 : len(str)-1]
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ type Resource struct {
|
||||
refVarNames []string
|
||||
}
|
||||
|
||||
// nolint
|
||||
var BuildAnnotations = []string{
|
||||
utils.BuildAnnotationPreviousKinds,
|
||||
utils.BuildAnnotationPreviousNames,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -5,7 +5,7 @@ container workflow orchestrator including Tekton, Cloud Build, or run directly u
|
||||
|
||||
Run `config help docs-fn-spec` to see the Configuration Functions Specification.
|
||||
|
||||
`kustomize config run` is an example orchestrator for invoking Configuration Functions. This
|
||||
`kustomize fn run` is an example orchestrator for invoking Configuration Functions. This
|
||||
document describes how to implement and invoke an example function.
|
||||
|
||||
## Example Function Implementation
|
||||
@@ -28,7 +28,7 @@ The script wraps itself using `config run wrap -- $0` which will:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# script must run wrapped by "kustomize config run wrap"
|
||||
# script must run wrapped by "kustomize fn run wrap"
|
||||
# for parsing input the functionConfig into env vars
|
||||
if [ -z ${WRAPPED} ]; then
|
||||
export WRAPPED=true
|
||||
@@ -82,7 +82,7 @@ End-of-message
|
||||
|
||||
### Dockerfile
|
||||
|
||||
`Dockerfile` installs `kustomize config` and copies the script into the container image.
|
||||
`Dockerfile` installs `kustomize fn` and copies the script into the container image.
|
||||
|
||||
```
|
||||
FROM golang:1.13-stretch
|
||||
@@ -94,9 +94,9 @@ CMD ["nginx-template.sh]
|
||||
|
||||
## Example Function Usage
|
||||
|
||||
Following is an example of running the `kustomize config run` using the preceding API.
|
||||
Following is an example of running the `kustomize fn run` using the preceding API.
|
||||
|
||||
When run by `kustomize config run`, functions are run in containers with the
|
||||
When run by `kustomize fn run`, functions are run in containers with the
|
||||
following environment:
|
||||
|
||||
- Network: `none`
|
||||
@@ -129,7 +129,7 @@ spec:
|
||||
|
||||
### Output
|
||||
|
||||
The function is invoked using byrunning `kustomize config run dir/`.
|
||||
The function is invoked using byrunning `kustomize fn run dir/`.
|
||||
|
||||
`dir/my-instance_deployment.yaml` contains the Deployment:
|
||||
|
||||
|
||||
@@ -245,8 +245,8 @@ items:
|
||||
labels:
|
||||
app: wordpress
|
||||
annotations:
|
||||
config.kubernetes.io/index: "0"
|
||||
config.kubernetes.io/path: "service.yaml"
|
||||
internal.config.kubernetes.io/index: "0"
|
||||
internal.config.kubernetes.io/path: "service.yaml"
|
||||
spec: # Example comment
|
||||
type: LoadBalancer
|
||||
selector:
|
||||
@@ -271,8 +271,8 @@ items:
|
||||
labels:
|
||||
app: wordpress
|
||||
annotations:
|
||||
config.kubernetes.io/index: "0"
|
||||
config.kubernetes.io/path: "service.yaml"
|
||||
internal.config.kubernetes.io/index: "0"
|
||||
internal.config.kubernetes.io/path: "service.yaml"
|
||||
spec: # Example comment
|
||||
type: LoadBalancer
|
||||
selector:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
### Synopsis
|
||||
|
||||
`kustomize config` enables encapsulating function for manipulating Resource
|
||||
`kustomize fn` enables encapsulating function for manipulating Resource
|
||||
configuration inside containers, which are run using `run`.
|
||||
|
||||
First fetch the kustomize repository, which contains a collection of example
|
||||
@@ -14,7 +14,7 @@
|
||||
### Templating -- CockroachDB
|
||||
|
||||
This section demonstrates how to leverage templating based solutions from
|
||||
`kustomize config`. The templating function is implemented as a `bash` script
|
||||
`kustomize fn`. The templating function is implemented as a `bash` script
|
||||
using a `heredoc`.
|
||||
|
||||
#### 1: Generate the Resources
|
||||
|
||||
@@ -16,5 +16,5 @@ require (
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
gopkg.in/inf.v0 v0.9.1
|
||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e
|
||||
sigs.k8s.io/kustomize/kyaml v0.12.0
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.0
|
||||
)
|
||||
|
||||
@@ -245,8 +245,8 @@ k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM=
|
||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
||||
sigs.k8s.io/kustomize/kyaml v0.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=
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -39,7 +39,7 @@ functionConfig:
|
||||
- 4
|
||||
`
|
||||
|
||||
resourceInput = `apiVersion: config.kubernetes.io/v1alpha1
|
||||
resourceInput = `apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: apps/v1
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -61,15 +61,16 @@ Example:
|
||||
annotations:
|
||||
config.kubernetes.io/local-config: "true"`
|
||||
|
||||
var FunctionsImplShort = `Following is an example for implementing an nginx abstraction using a configuration`
|
||||
var FunctionsImplLong = `# Running Configuration Functions using kustomize CLI
|
||||
var (
|
||||
FunctionsImplShort = `Following is an example for implementing an nginx abstraction using a configuration`
|
||||
FunctionsImplLong = `# Running Configuration Functions using kustomize CLI
|
||||
|
||||
Configuration functions can be implemented using any toolchain and invoked using any
|
||||
container workflow orchestrator including Tekton, Cloud Build, or run directly using ` + "`" + `docker run` + "`" + `.
|
||||
|
||||
Run ` + "`" + `config help docs-fn-spec` + "`" + ` to see the Configuration Functions Specification.
|
||||
|
||||
` + "`" + `kustomize config run` + "`" + ` is an example orchestrator for invoking Configuration Functions. This
|
||||
` + "`" + `kustomize fn run` + "`" + ` is an example orchestrator for invoking Configuration Functions. This
|
||||
document describes how to implement and invoke an example function.
|
||||
|
||||
function.
|
||||
@@ -88,7 +89,7 @@ The script wraps itself using ` + "`" + `config run wrap -- $0` + "`" + ` which
|
||||
4. Format the output
|
||||
|
||||
#!/bin/bash
|
||||
# script must run wrapped by "kustomize config run wrap"
|
||||
# script must run wrapped by "kustomize fn run wrap"
|
||||
# for parsing input the functionConfig into env vars
|
||||
if [ -z ${WRAPPED} ]; then
|
||||
export WRAPPED=true
|
||||
@@ -141,7 +142,7 @@ The script wraps itself using ` + "`" + `config run wrap -- $0` + "`" + ` which
|
||||
|
||||
### Dockerfile
|
||||
|
||||
` + "`" + `Dockerfile` + "`" + ` installs ` + "`" + `kustomize config` + "`" + ` and copies the script into the container image.
|
||||
` + "`" + `Dockerfile` + "`" + ` installs ` + "`" + `kustomize fn` + "`" + ` and copies the script into the container image.
|
||||
|
||||
FROM golang:1.13-stretch
|
||||
RUN go get sigs.k8s.io/kustomize/cmd/config
|
||||
@@ -151,9 +152,9 @@ The script wraps itself using ` + "`" + `config run wrap -- $0` + "`" + ` which
|
||||
|
||||
## Example Function Usage
|
||||
|
||||
Following is an example of running the ` + "`" + `kustomize config run` + "`" + ` using the preceding API.
|
||||
Following is an example of running the ` + "`" + `kustomize fn run` + "`" + ` using the preceding API.
|
||||
|
||||
When run by ` + "`" + `kustomize config run` + "`" + `, functions are run in containers with the
|
||||
When run by ` + "`" + `kustomize fn run` + "`" + `, functions are run in containers with the
|
||||
following environment:
|
||||
|
||||
- Network: ` + "`" + `none` + "`" + `
|
||||
@@ -184,7 +185,7 @@ are passed to the Function through the ` + "`" + `ResourceList.functionConfig` +
|
||||
|
||||
### Output
|
||||
|
||||
The function is invoked using byrunning ` + "`" + `kustomize config run dir/` + "`" + `.
|
||||
The function is invoked using byrunning ` + "`" + `kustomize fn run dir/` + "`" + `.
|
||||
|
||||
` + "`" + `dir/my-instance_deployment.yaml` + "`" + ` contains the Deployment:
|
||||
|
||||
@@ -230,9 +231,11 @@ The function is invoked using byrunning ` + "`" + `kustomize config run dir/` +
|
||||
selector:
|
||||
app: nginx
|
||||
instance: my-instance`
|
||||
)
|
||||
|
||||
var FunctionsSpecShort = `_Configuration functions_ enable shift-left practices (client-side) through:`
|
||||
var FunctionsSpecLong = `# Configuration Functions Specification
|
||||
var (
|
||||
FunctionsSpecShort = `_Configuration functions_ enable shift-left practices (client-side) through:`
|
||||
FunctionsSpecLong = `# Configuration Functions Specification
|
||||
|
||||
This document specifies a standard for client-side functions that operate on
|
||||
Kubernetes declarative configurations. This standard enables creating
|
||||
@@ -408,6 +411,7 @@ A non-zero exit code indicates a failure.
|
||||
[1]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md
|
||||
[2]: https://tools.ietf.org/html/rfc2119
|
||||
[3]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds`
|
||||
)
|
||||
|
||||
var Merge2Long = `# Merge (2-way)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package tutorials
|
||||
|
||||
var ConfigurationBasicsShort = `### Synopsis`
|
||||
|
||||
var ConfigurationBasicsLong = `
|
||||
` + "`" + `kustomize cfg` + "`" + ` provides tools for working with local configuration directories.
|
||||
|
||||
@@ -274,9 +275,10 @@ var ConfigurationBasicsLong = `
|
||||
│ └── image: <YOUR-CONTAINER>
|
||||
...`
|
||||
|
||||
var FunctionBasicsShort = `### Synopsis`
|
||||
var FunctionBasicsLong = `
|
||||
` + "`" + `kustomize config` + "`" + ` enables encapsulating function for manipulating Resource
|
||||
var (
|
||||
FunctionBasicsShort = `### Synopsis`
|
||||
FunctionBasicsLong = `
|
||||
` + "`" + `kustomize fn` + "`" + ` enables encapsulating function for manipulating Resource
|
||||
configuration inside containers, which are run using ` + "`" + `run` + "`" + `.
|
||||
|
||||
First fetch the kustomize repository, which contains a collection of example
|
||||
@@ -288,7 +290,7 @@ var FunctionBasicsLong = `
|
||||
### Templating -- CockroachDB
|
||||
|
||||
This section demonstrates how to leverage templating based solutions from
|
||||
` + "`" + `kustomize config` + "`" + `. The templating function is implemented as a ` + "`" + `bash` + "`" + ` script
|
||||
` + "`" + `kustomize fn` + "`" + `. The templating function is implemented as a ` + "`" + `bash` + "`" + ` script
|
||||
using a ` + "`" + `heredoc` + "`" + `.
|
||||
|
||||
#### 1: Generate the Resources
|
||||
@@ -455,3 +457,4 @@ Functions may be composed together. Try putting the Injection (tshirt-size) and
|
||||
Validation functions together in the same .yaml file (separated by ` + "`" + `---` + "`" + `). Run
|
||||
` + "`" + `run` + "`" + ` and observe that the first function in the file is applied to the Resources,
|
||||
and then the second function in the file is applied.`
|
||||
)
|
||||
|
||||
@@ -129,7 +129,7 @@ var ExitOnError bool
|
||||
// StackOnError if true, will print a stack trace on failure.
|
||||
var StackOnError bool
|
||||
|
||||
const cmdName = "kustomize config"
|
||||
const cmdName = "kustomize fn"
|
||||
|
||||
// FixDocs replaces instances of old with new in the docs for c
|
||||
func FixDocs(new string, c *cobra.Command) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -74,7 +74,7 @@ func (p *plugin) Transform(rm resmap.ResMap) error {
|
||||
|
||||
func getTransformerInputResource() []byte {
|
||||
return []byte(`
|
||||
apiVersion: config.kubernetes.io/v1beta1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
functionConfig:
|
||||
apiVersion: foo-corp.com/v1
|
||||
@@ -128,7 +128,7 @@ func TestTransformerConverter(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
|
||||
output := runKrmFunction(t, getTransformerInputResource(), filepath.Join(dir, "output"))
|
||||
assert.Equal(t, `apiVersion: config.kubernetes.io/v1beta1
|
||||
assert.Equal(t, `apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: apps/v1
|
||||
@@ -193,7 +193,7 @@ func (p *plugin) Generate() (resmap.ResMap, error) {
|
||||
|
||||
func getGeneratorInputResource() []byte {
|
||||
return []byte(`
|
||||
apiVersion: config.kubernetes.io/v1beta1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
functionConfig:
|
||||
apiVersion: foo-corp.com/v1
|
||||
@@ -224,7 +224,7 @@ func TestGeneratorConverter(t *testing.T) {
|
||||
err := c.Convert()
|
||||
assert.NoError(t, err)
|
||||
output := runKrmFunction(t, getGeneratorInputResource(), filepath.Join(dir, "output"))
|
||||
assert.Equal(t, `apiVersion: config.kubernetes.io/v1beta1
|
||||
assert.Equal(t, `apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: v1
|
||||
|
||||
@@ -23,14 +23,12 @@ Kustomize provides two ways of adding ConfigMap in one `kustomization`, either b
|
||||
|
||||
The ConfigMaps declared as [resource] are treated the same way as other resources. Kustomize doesn't append any hash to the ConfigMap name. The ConfigMap declared from a ConfigMapGenerator is treated differently. A hash is appended to the name and any change in the ConfigMap will trigger a rolling update.
|
||||
|
||||
In this demo, the same [hello_world](helloWorld/README.md) is used while the ConfigMap declared as [resources] is replaced by a ConfigMap declared from a ConfigmapGenerator. The change in this ConfigMap will result in a hash change and a rolling update.
|
||||
In this demo, the same [hello_world](helloWorld/README.md) is used while the ConfigMap declared as [resources] is replaced by a ConfigMap declared from a ConfigMapGenerator. The change in this ConfigMap will result in a hash change and a rolling update.
|
||||
|
||||
### Establish base and staging
|
||||
|
||||
Establish the base with a configMapGenerator
|
||||
|
||||
Establish the base with a `configMapGenerator`:
|
||||
<!-- @establishBase @testAgainstLatestRelease -->
|
||||
|
||||
```
|
||||
DEMO_HOME=$(mktemp -d)
|
||||
|
||||
@@ -92,7 +90,7 @@ EOF
|
||||
### Review
|
||||
|
||||
The _hello-world_ deployment running in this cluster is
|
||||
configured with data from a configMap.
|
||||
configured with data from a ConfigMap.
|
||||
|
||||
The deployment refers to this map by name:
|
||||
|
||||
@@ -102,26 +100,26 @@ The deployment refers to this map by name:
|
||||
grep -C 2 configMapKeyRef $BASE/deployment.yaml
|
||||
```
|
||||
|
||||
Changing the data held by a live configMap in a cluster
|
||||
Changing the data held by a live ConfigMap in a cluster
|
||||
is considered bad practice. Deployments have no means
|
||||
to know that the configMaps they refer to have
|
||||
to know that the ConfigMaps they refer to have
|
||||
changed, so such updates have no effect.
|
||||
|
||||
The recommended way to change a deployment's
|
||||
configuration is to
|
||||
|
||||
1. create a new configMap with a new name,
|
||||
1. create a new ConfigMap with a new name,
|
||||
1. patch the _deployment_, modifying the name value of
|
||||
the appropriate `configMapKeyRef` field.
|
||||
|
||||
This latter change initiates rolling update to the pods
|
||||
in the deployment. The older configMap, when no longer
|
||||
in the deployment. The older ConfigMap, when no longer
|
||||
referenced by any other resource, is eventually [garbage
|
||||
collected](/../../issues/242).
|
||||
|
||||
### How this works with kustomize
|
||||
|
||||
The _staging_ [variant] here has a configMap [patch]:
|
||||
The _staging_ [variant] here has a ConfigMap [patch]:
|
||||
|
||||
<!-- @showMapPatch @testAgainstLatestRelease -->
|
||||
|
||||
@@ -133,7 +131,7 @@ This patch is by definition a named but not necessarily
|
||||
complete resource spec intended to modify a complete
|
||||
resource spec.
|
||||
|
||||
The ConfigMap it modifies is declared from a configMapGenerator.
|
||||
The ConfigMap it modifies is declared from a `configMapGenerator`.
|
||||
|
||||
<!-- @showMapBase @testAgainstLatestRelease -->
|
||||
|
||||
@@ -156,15 +154,15 @@ kustomize build $OVERLAYS/staging |\
|
||||
grep -B 8 -A 1 staging-the-map
|
||||
```
|
||||
|
||||
The configMap name is prefixed by _staging-_, per the
|
||||
The ConfigMap name is prefixed by _staging-_, per the
|
||||
`namePrefix` field in
|
||||
`$OVERLAYS/staging/kustomization.yaml`.
|
||||
|
||||
The configMap name is suffixed by _-v1_, per the
|
||||
The ConfigMap name is suffixed by _-v1_, per the
|
||||
`nameSuffix` field in
|
||||
`$OVERLAYS/staging/kustomization.yaml`.
|
||||
|
||||
The suffix to the configMap name is generated from a
|
||||
The suffix to the ConfigMap name is generated from a
|
||||
hash of the maps content - in this case the name suffix
|
||||
is _5276h4th55_:
|
||||
|
||||
@@ -190,7 +188,7 @@ kustomize build $OVERLAYS/staging |\
|
||||
grep -B 2 -A 3 kiwi
|
||||
```
|
||||
|
||||
Run kustomize again to see the new configMap names:
|
||||
Run kustomize again to see the new ConfigMap names:
|
||||
|
||||
<!-- @grepStagingName @testAgainstLatestRelease -->
|
||||
|
||||
@@ -199,9 +197,9 @@ kustomize build $OVERLAYS/staging |\
|
||||
grep -B 8 -A 1 staging-the-map
|
||||
```
|
||||
|
||||
Confirm that the change in configMap content resulted
|
||||
Confirm that the change in ConfigMap content resulted
|
||||
in three new names ending in _c2g8fcbf88_ - one in the
|
||||
configMap name itself, and two in the deployment that
|
||||
ConfigMap name itself, and two in the deployment that
|
||||
uses the map:
|
||||
|
||||
<!-- @countHashes @testAgainstLatestRelease -->
|
||||
|
||||
@@ -148,7 +148,7 @@ commonLabels:
|
||||
org: acmeCorporation
|
||||
commonAnnotations:
|
||||
note: Hello, I am staging!
|
||||
bases:
|
||||
resources:
|
||||
- ../../base
|
||||
patchesStrategicMerge:
|
||||
- map.yaml
|
||||
@@ -189,7 +189,7 @@ commonLabels:
|
||||
org: acmeCorporation
|
||||
commonAnnotations:
|
||||
note: Hello, I am production!
|
||||
bases:
|
||||
resources:
|
||||
- ../../base
|
||||
patchesStrategicMerge:
|
||||
- deployment.yaml
|
||||
|
||||
@@ -22,17 +22,17 @@ a _target selector_:
|
||||
> group: <optional group>
|
||||
> version: <optional version>
|
||||
> kind: <optional kind>
|
||||
> name: <optional name>
|
||||
> name: <optional name or regex pattern>
|
||||
> namespace: <optional namespace>
|
||||
> labelSelector: <optional label selector>
|
||||
> annotationSelector: <optional annotation selector>
|
||||
> ```
|
||||
|
||||
E.g. select resources with _name_ matching `foo*`:
|
||||
E.g. select resources with _name_ matching the regular expression `foo.*`:
|
||||
|
||||
> ```yaml
|
||||
> target:
|
||||
> name: foo*
|
||||
> name: foo.*
|
||||
> ```
|
||||
|
||||
Select all resources of _kind_ `Deployment`:
|
||||
|
||||
@@ -17,7 +17,7 @@ Resource configuration, and looks for invalid configuration.
|
||||
The function is invoked by authoring a [local Resource](local-resource)
|
||||
with `metadata.annotations.[config.kubernetes.io/function]` and running:
|
||||
|
||||
kustomize config run local-resource/ --fn-path config/
|
||||
kustomize fn run local-resource/ --fn-path config/
|
||||
|
||||
This exits non-zero if there is an error.
|
||||
|
||||
@@ -25,6 +25,6 @@ This exits non-zero if there is an error.
|
||||
|
||||
Run the validator with:
|
||||
|
||||
kustomize config run local-resource/ --fn-path config/
|
||||
kustomize fn run local-resource/ --fn-path config/
|
||||
|
||||
This will append an Application CR.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package main implements adding an Application CR to a group of resources and
|
||||
// is run with `kustomize config run -- DIR/`.
|
||||
// is run with `kustomize fn run -- DIR/`.
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -82,7 +82,6 @@ func (f appCRFilter) Filter(in []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
return append(in, app), nil
|
||||
}
|
||||
return in, nil
|
||||
|
||||
}
|
||||
|
||||
// parseAPI parses the functionConfig into an API struct.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package main implements adding an Application CR to a group of resources and
|
||||
// is run with `kustomize config run -- DIR/`.
|
||||
// is run with `kustomize fn run -- DIR/`.
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var input = `apiVersion: config.kubernetes.io/v1alpha1
|
||||
var input = `apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: v1
|
||||
@@ -89,7 +89,7 @@ functionConfig:
|
||||
url: https://metrics/internal/worldpress-01/web-app
|
||||
`
|
||||
|
||||
var output = `apiVersion: config.kubernetes.io/v1alpha1
|
||||
var output = `apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: v1
|
||||
|
||||
@@ -17,7 +17,7 @@ Resource configuration, and looks for invalid configuration.
|
||||
The function is invoked by authoring a [local Resource](local-resource)
|
||||
with `metadata.annotations.[config.kubernetes.io/function]` and running:
|
||||
|
||||
kustomize config run local-resource/
|
||||
kustomize fn run local-resource/
|
||||
|
||||
This exits non-zero if there is an error.
|
||||
|
||||
@@ -25,11 +25,11 @@ This exits non-zero if there is an error.
|
||||
|
||||
Run the validator with:
|
||||
|
||||
kustomize config run local-resource/
|
||||
kustomize fn run local-resource/
|
||||
|
||||
This will add resource reservations to the Deployment. Change the `tshirt-size`
|
||||
annotation from `medium` to `small` and rerun:
|
||||
|
||||
kustomize config run local-resource/
|
||||
kustomize fn run local-resource/
|
||||
|
||||
Observe that the reservations have changed.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package main implements an injection function for resource reservations and
|
||||
// is run with `kustomize config run -- DIR/`.
|
||||
// is run with `kustomize fn run -- DIR/`.
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@@ -27,7 +27,7 @@ function input, and writing the function output.
|
||||
The function is invoked by authoring a [local Resource](local-resource)
|
||||
with `metadata.annotations.[config.kubernetes.io/function]` and running:
|
||||
|
||||
kustomize config run local-resource/
|
||||
kustomize fn run local-resource/
|
||||
|
||||
This generates the `local-resource/config` directory containing the template output.
|
||||
|
||||
@@ -41,7 +41,7 @@ This generates the `local-resource/config` directory containing the template out
|
||||
|
||||
Run the config with:
|
||||
|
||||
kustomize config run local-resource/
|
||||
kustomize fn run local-resource/
|
||||
|
||||
This will create the directory
|
||||
|
||||
@@ -50,6 +50,6 @@ This will create the directory
|
||||
Add an annotation to the Deployment Resource and change the replica count of the
|
||||
`kind: Nginx` Resource in `example-use.yaml`. Rerun the template:
|
||||
|
||||
kustomize config run local-resource/
|
||||
kustomize fn run local-resource/
|
||||
|
||||
The replica count should be updated, but your annotation should remain.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright 2019 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: examples.config.kubernetes.io/v1beta1 # call `kustomize config run` on a directory containing this file
|
||||
apiVersion: examples.config.kubernetes.io/v1beta1 # call `kustomize fn run` on a directory containing this file
|
||||
kind: Nginx
|
||||
metadata:
|
||||
name: demo
|
||||
|
||||
@@ -11,7 +11,7 @@ The function is implemented as an [image](image), and built using `make image`.
|
||||
The template is implemented as a heredoc, which substitutes environment variables
|
||||
into a static string.
|
||||
|
||||
This simple implementation uses `kustomize config run wrap --` to perform the
|
||||
This simple implementation uses `kustomize fn run wrap --` to perform the
|
||||
heavy lifting of implementing the function interface.
|
||||
|
||||
- parse functionConfig from stdin into environment variables
|
||||
@@ -22,7 +22,7 @@ heavy lifting of implementing the function interface.
|
||||
The function is invoked by authoring a [local Resource](local-resource)
|
||||
with `metadata.annotations.[config.kubernetes.io/function]` and running:
|
||||
|
||||
kustomize config run local-resource/
|
||||
kustomize fn run local-resource/
|
||||
|
||||
This generates the `local-resource/config` directory containing the template output.
|
||||
|
||||
@@ -36,7 +36,7 @@ This generates the `local-resource/config` directory containing the template out
|
||||
|
||||
Run the config with:
|
||||
|
||||
kustomize config run local-resource/
|
||||
kustomize fn run local-resource/
|
||||
|
||||
This will create the directory
|
||||
|
||||
@@ -45,6 +45,6 @@ This will create the directory
|
||||
Add an annotation to the StatefulSet Resource and change the replica count of the
|
||||
`kind: CockroachDB` Resource in `example-use.yaml`. Rerun the template:
|
||||
|
||||
kustomize config run local-resource/
|
||||
kustomize fn run local-resource/
|
||||
|
||||
The replica count should be updated, but your annotation should remain.
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
# use `kustomize config run wrap` to parse the container stdin into
|
||||
# use `kustomize fn run wrap` to parse the container stdin into
|
||||
# environment variables, and to merge the template output into the
|
||||
# input Resources.
|
||||
if [ -z ${WRAPPED} ]; then
|
||||
export WRAPPED=true
|
||||
kustomize config run wrap -- $0
|
||||
kustomize fn run wrap -- $0
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# this is the template for a cockroachdb instance
|
||||
# environment variables are parsed from the input functionConfig by
|
||||
# `kustomize config run wrap`
|
||||
# `kustomize fn run wrap`
|
||||
cat <<End-of-message
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright 2019 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# call `kustomize config run` on a directory containing this file
|
||||
# call `kustomize fn run` on a directory containing this file
|
||||
apiVersion: examples.config.kubernetes.io/v1beta1
|
||||
kind: CockroachDB
|
||||
metadata:
|
||||
|
||||
@@ -20,7 +20,7 @@ the `API` struct definition in [main.go](image/main.go) for documentation.
|
||||
The function is invoked by authoring a [local Resource](local-resource)
|
||||
with `metadata.annotations.[config.kubernetes.io/function]` and running:
|
||||
|
||||
kustomize config run local-resource/
|
||||
kustomize fn run local-resource/
|
||||
|
||||
This exists non-zero if kubeval detects an invalid Resource.
|
||||
|
||||
@@ -28,7 +28,7 @@ This exists non-zero if kubeval detects an invalid Resource.
|
||||
|
||||
Run the validator with:
|
||||
|
||||
kustomize config run local-resource/
|
||||
kustomize fn run local-resource/
|
||||
|
||||
This will return an error:
|
||||
|
||||
@@ -39,6 +39,6 @@ This will return an error:
|
||||
Now fix the typo in [example-use.yaml](local-resource/example-use.yaml) and
|
||||
run:
|
||||
|
||||
kustomize config run local-resource/
|
||||
kustomize fn run local-resource/
|
||||
|
||||
This will return success (no output).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package main implements a validator function run by `kustomize config run`
|
||||
// Package main implements a validator function run by `kustomize fn run`
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@@ -17,7 +17,7 @@ Resource configuration, and looks for invalid configuration.
|
||||
The function is invoked by authoring a [local Resource](local-resource)
|
||||
with `metadata.annotations.[config.kubernetes.io/function]` and running:
|
||||
|
||||
kustomize config run local-resource/
|
||||
kustomize fn run local-resource/
|
||||
|
||||
This exists non-zero if there is an error.
|
||||
|
||||
@@ -25,7 +25,7 @@ This exists non-zero if there is an error.
|
||||
|
||||
Run the validator with:
|
||||
|
||||
kustomize config run local-resource/
|
||||
kustomize fn run local-resource/
|
||||
|
||||
This will return an error:
|
||||
|
||||
@@ -33,6 +33,6 @@ This will return an error:
|
||||
|
||||
Now uncomment the resource reservations and run again:
|
||||
|
||||
kustomize config run local-resource/
|
||||
kustomize fn run local-resource/
|
||||
|
||||
This will return success
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package main implements a validator function run by `kustomize config run`
|
||||
// Package main implements a validator function run by `kustomize fn run`
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -18,7 +18,8 @@ func main() {
|
||||
p := kio.Pipeline{
|
||||
Inputs: []kio.Reader{rw}, // read the inputs into a slice
|
||||
Filters: []kio.Filter{filter{}}, // run the filter against the inputs
|
||||
Outputs: []kio.Writer{rw}} // copy the inputs to the output
|
||||
Outputs: []kio.Writer{rw}, // copy the inputs to the output
|
||||
}
|
||||
if err := p.Execute(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
os.Exit(1)
|
||||
@@ -59,7 +60,6 @@ func validate(r *yaml.RNode) error {
|
||||
|
||||
// visit each container in the list and validate
|
||||
return containers.VisitElements(func(node *yaml.RNode) error {
|
||||
|
||||
// check cpu is non-nil
|
||||
f, err := node.Pipe(yaml.Lookup("resources", "requests", "cpu"))
|
||||
if err != nil {
|
||||
|
||||
@@ -102,7 +102,14 @@ elif [[ "$OSTYPE" == darwin* ]]; then
|
||||
opsys=darwin
|
||||
fi
|
||||
|
||||
RELEASE_URL=$(curl -s $release_url |\
|
||||
releases=$(curl -s $release_url)
|
||||
|
||||
if [[ $releases == *"API rate limit exceeded"* ]]; then
|
||||
echo "Github rate-limiter failed the request. Either authenticate or wait a couple of minutes."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RELEASE_URL=$(echo "${releases}" |\
|
||||
grep browser_download.*${opsys}_${arch} |\
|
||||
cut -d '"' -f 4 |\
|
||||
sort -V | tail -n 1)
|
||||
|
||||
@@ -33,8 +33,27 @@ func TestAddResourceHappyPath(t *testing.T) {
|
||||
assert.NoError(t, cmd.RunE(cmd, args))
|
||||
content, err := testutils_test.ReadTestKustomization(fSys)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, string(content), resourceFileName)
|
||||
assert.Contains(t, string(content), resourceFileName+"another")
|
||||
assert.Equal(t, string(content), `apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
namePrefix: some-prefix
|
||||
nameSuffix: some-suffix
|
||||
# Labels to add to all objects and selectors.
|
||||
# These labels would also be used to form the selector for apply --prune
|
||||
# Named differently than “labels” to avoid confusion with metadata for this object
|
||||
commonLabels:
|
||||
app: helloworld
|
||||
commonAnnotations:
|
||||
note: This is an example annotation
|
||||
resources:
|
||||
- myWonderfulResource.yaml
|
||||
- myWonderfulResource.yamlanother
|
||||
#- service.yaml
|
||||
#- ../some-dir/
|
||||
# There could also be configmaps in Base, which would make these overlays
|
||||
# There could be secrets in Base, if just using a fork/rebase workflow
|
||||
replacements:
|
||||
- path: replacement.yaml
|
||||
`)
|
||||
}
|
||||
|
||||
func TestAddResourceAlreadyThere(t *testing.T) {
|
||||
|
||||
@@ -28,6 +28,8 @@ resources: []
|
||||
configMapGenerator: []
|
||||
# There could be secrets in Base, if just using a fork/rebase workflow
|
||||
secretGenerator: []
|
||||
replacements:
|
||||
- path: replacement.yaml
|
||||
`
|
||||
)
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@ require (
|
||||
github.com/spf13/cobra v1.0.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.7.0
|
||||
sigs.k8s.io/kustomize/api v0.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
|
||||
)
|
||||
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package filesys
|
||||
|
||||
@@ -612,6 +612,7 @@ func (n *fsNode) RegExpGlob(pattern string) ([]string, error) {
|
||||
// This is how /bin/ls behaves.
|
||||
func (n *fsNode) Glob(pattern string) ([]string, error) {
|
||||
var result []string
|
||||
var allFiles []string
|
||||
err := n.WalkMe(func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -622,7 +623,7 @@ func (n *fsNode) Glob(pattern string) ([]string, error) {
|
||||
return err
|
||||
}
|
||||
if match {
|
||||
result = append(result, path)
|
||||
allFiles = append(allFiles, path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -630,6 +631,11 @@ func (n *fsNode) Glob(pattern string) ([]string, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if IsHiddenFilePath(pattern) {
|
||||
result = allFiles
|
||||
} else {
|
||||
result = RemoveHiddenFiles(allFiles)
|
||||
}
|
||||
sort.Strings(result)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package filesys
|
||||
@@ -463,6 +464,13 @@ var bunchOfFiles = []struct {
|
||||
{
|
||||
path: filepath.Join("b", "d", "a", "c", "u"),
|
||||
},
|
||||
{
|
||||
path: filepath.Join("b", "d", ".hidden_file"),
|
||||
},
|
||||
{
|
||||
path: filepath.Join("b", "d", ".hidden_dir"),
|
||||
addAsDir: true,
|
||||
},
|
||||
}
|
||||
|
||||
func makeLoadedFileTree(t *testing.T) *fsNode {
|
||||
@@ -579,6 +587,7 @@ func TestExists(t *testing.T) {
|
||||
func TestRegExpGlob(t *testing.T) {
|
||||
n := makeLoadedFileTree(t)
|
||||
expected := []string{
|
||||
filepath.Join("b", "d", ".hidden_file"),
|
||||
filepath.Join("b", "d", "a", "c", "i", "beans"),
|
||||
filepath.Join("b", "d", "a", "c", "m"),
|
||||
filepath.Join("b", "d", "a", "c", "u"),
|
||||
@@ -598,16 +607,36 @@ func TestRegExpGlob(t *testing.T) {
|
||||
|
||||
func TestGlob(t *testing.T) {
|
||||
n := makeLoadedFileTree(t)
|
||||
expected := []string{
|
||||
filepath.Join("b", "d", "x"),
|
||||
filepath.Join("b", "d", "y"),
|
||||
filepath.Join("b", "d", "z"),
|
||||
|
||||
tests := map[string]struct {
|
||||
globPattern string
|
||||
expectedFiles []string
|
||||
}{
|
||||
"VisibleFiles": {
|
||||
globPattern: "b/d/*",
|
||||
expectedFiles: []string{
|
||||
filepath.Join("b", "d", "x"),
|
||||
filepath.Join("b", "d", "y"),
|
||||
filepath.Join("b", "d", "z"),
|
||||
},
|
||||
},
|
||||
"HiddenFiles": {
|
||||
globPattern: "b/d/.*",
|
||||
expectedFiles: []string{
|
||||
filepath.Join("b", "d", ".hidden_file"),
|
||||
},
|
||||
},
|
||||
}
|
||||
paths, err := n.Glob("b/d/*")
|
||||
if err != nil {
|
||||
t.Fatalf("glob error: %v", err)
|
||||
|
||||
for test, c := range tests {
|
||||
t.Run(test, func(t *testing.T) {
|
||||
paths, err := n.Glob(c.globPattern)
|
||||
if err != nil {
|
||||
t.Fatalf("glob error: %v", err)
|
||||
}
|
||||
assertEqualStringSlices(t, c.expectedFiles, paths, "glob test")
|
||||
})
|
||||
}
|
||||
assertEqualStringSlices(t, expected, paths, "glob test")
|
||||
}
|
||||
|
||||
func assertEqualStringSlices(t *testing.T, expected, actual []string, message string) {
|
||||
|
||||
@@ -88,7 +88,17 @@ func (fsOnDisk) Exists(name string) bool {
|
||||
|
||||
// Glob returns the list of matching files
|
||||
func (fsOnDisk) Glob(pattern string) ([]string, error) {
|
||||
return filepath.Glob(pattern)
|
||||
var result []string
|
||||
allFilePaths, err := filepath.Glob(pattern)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if IsHiddenFilePath(pattern) {
|
||||
result = allFilePaths
|
||||
} else {
|
||||
result = RemoveHiddenFiles(allFilePaths)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// IsDir delegates to os.Stat and FileInfo.IsDir
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package filesys
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -135,31 +137,113 @@ func TestReadFilesRealFS(t *testing.T) {
|
||||
fSys, testDir := makeTestDir(t)
|
||||
defer os.RemoveAll(testDir)
|
||||
|
||||
err := fSys.WriteFile(path.Join(testDir, "foo"), []byte(`foo`))
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %s", err)
|
||||
dir := path.Join(testDir, "dir")
|
||||
nestedDir := path.Join(dir, "nestedDir")
|
||||
hiddenDir := path.Join(testDir, ".hiddenDir")
|
||||
dirs := []string{
|
||||
testDir,
|
||||
dir,
|
||||
nestedDir,
|
||||
hiddenDir,
|
||||
}
|
||||
if !fSys.Exists(path.Join(testDir, "foo")) {
|
||||
t.Fatalf("expected foo")
|
||||
}
|
||||
if fSys.IsDir(path.Join(testDir, "foo")) {
|
||||
t.Fatalf("expected foo not to be a directory")
|
||||
// all directories will have all these files
|
||||
files := []string{
|
||||
"bar",
|
||||
"foo",
|
||||
"file-1.xtn",
|
||||
".file-2.xtn",
|
||||
".some-file-3.xtn",
|
||||
".some-file-4.xtn",
|
||||
}
|
||||
|
||||
err = fSys.WriteFile(path.Join(testDir, "bar"), []byte(`bar`))
|
||||
err := fSys.MkdirAll(nestedDir)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %s", err)
|
||||
t.Fatalf("Unexpected Error %v\n", err)
|
||||
}
|
||||
err = fSys.MkdirAll(hiddenDir)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected Error %v\n", err)
|
||||
}
|
||||
|
||||
files, err := fSys.Glob(path.Join("testDir", "*"))
|
||||
expected := []string{
|
||||
path.Join(testDir, "bar"),
|
||||
path.Join(testDir, "foo"),
|
||||
// adding all files in every directory that we had defined
|
||||
for _, d := range dirs {
|
||||
if !fSys.IsDir(d) {
|
||||
t.Fatalf("Expected %s to be a dir\n", d)
|
||||
}
|
||||
for _, f := range files {
|
||||
err = fSys.WriteFile(path.Join(d, f), []byte(f))
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %s", err)
|
||||
}
|
||||
if !fSys.Exists(path.Join(d, f)) {
|
||||
t.Fatalf("expected %s", f)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error")
|
||||
|
||||
tests := map[string]struct {
|
||||
globPattern string
|
||||
expectedFiles []string
|
||||
expectedDirs map[string][]string // glob returns directories as well, so we need to add those to expected files
|
||||
}{
|
||||
"AllVisibleFiles": {
|
||||
globPattern: "*",
|
||||
expectedFiles: []string{
|
||||
"bar",
|
||||
"foo",
|
||||
"file-1.xtn",
|
||||
},
|
||||
expectedDirs: map[string][]string{
|
||||
testDir: []string{dir},
|
||||
dir: []string{nestedDir},
|
||||
},
|
||||
},
|
||||
"AllHiddenFiles": {
|
||||
globPattern: ".*",
|
||||
expectedFiles: []string{
|
||||
".file-2.xtn",
|
||||
".some-file-3.xtn",
|
||||
".some-file-4.xtn",
|
||||
},
|
||||
expectedDirs: map[string][]string{
|
||||
testDir: []string{hiddenDir},
|
||||
},
|
||||
},
|
||||
"foo_File": {
|
||||
globPattern: "foo",
|
||||
expectedFiles: []string{
|
||||
"foo",
|
||||
},
|
||||
},
|
||||
"dotsome-file_PrefixedFiles": {
|
||||
globPattern: ".some-file*",
|
||||
expectedFiles: []string{
|
||||
".some-file-3.xtn",
|
||||
".some-file-4.xtn",
|
||||
},
|
||||
},
|
||||
}
|
||||
if reflect.DeepEqual(files, expected) {
|
||||
t.Fatalf("incorrect files found by glob: %v", files)
|
||||
|
||||
for n, c := range tests {
|
||||
t.Run(n, func(t *testing.T) {
|
||||
for _, d := range dirs {
|
||||
var expectedPaths []string
|
||||
for _, f := range c.expectedFiles {
|
||||
expectedPaths = append(expectedPaths, path.Join(d, f))
|
||||
}
|
||||
if c.expectedDirs != nil {
|
||||
expectedPaths = append(expectedPaths, c.expectedDirs[d]...)
|
||||
}
|
||||
actualPaths, globErr := fSys.Glob(path.Join(d, c.globPattern))
|
||||
if globErr != nil {
|
||||
t.Fatalf("Unexpected Error : %v\n", globErr)
|
||||
}
|
||||
sort.Strings(actualPaths)
|
||||
sort.Strings(expectedPaths)
|
||||
if !reflect.DeepEqual(actualPaths, expectedPaths) {
|
||||
t.Fatalf("incorrect files found by glob: expected=%v, actual=%v", expectedPaths, actualPaths)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,3 +123,21 @@ func InsertPathPart(path string, pos int, part string) string {
|
||||
result[pos] = part
|
||||
return PathJoin(append(result, parts[pos:]...))
|
||||
}
|
||||
|
||||
func IsHiddenFilePath(pattern string) bool {
|
||||
return strings.HasPrefix(filepath.Base(pattern), ".")
|
||||
}
|
||||
|
||||
// Removes paths containing hidden files/folders from a list of paths
|
||||
func RemoveHiddenFiles(paths []string) []string {
|
||||
if len(paths) == 0 {
|
||||
return paths
|
||||
}
|
||||
var result []string
|
||||
for _, path := range paths {
|
||||
if !IsHiddenFilePath(path) {
|
||||
result = append(result, path)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2021 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package filesys
|
||||
@@ -8,6 +9,7 @@ package filesys
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -375,3 +377,90 @@ func TestStripLeadingSeps(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsHiddenFilePath(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
paths []string
|
||||
expectHidden bool
|
||||
}{
|
||||
"hiddenGlobs": {
|
||||
expectHidden: true,
|
||||
paths: []string{
|
||||
".*",
|
||||
"/.*",
|
||||
"dir/.*",
|
||||
"dir1/dir2/dir3/.*",
|
||||
"../../.*",
|
||||
"../../dir/.*",
|
||||
},
|
||||
},
|
||||
"visibleGlobes": {
|
||||
expectHidden: false,
|
||||
paths: []string{
|
||||
"*",
|
||||
"/*",
|
||||
"dir/*",
|
||||
"dir1/dir2/dir3/*",
|
||||
"../../*",
|
||||
"../../dir/*",
|
||||
},
|
||||
},
|
||||
"hiddenFiles": {
|
||||
expectHidden: true,
|
||||
paths: []string{
|
||||
".root_file.xtn",
|
||||
"/.file_1.xtn",
|
||||
"dir/.file_2.xtn",
|
||||
"dir1/dir2/dir3/.file_3.xtn",
|
||||
"../../.file_4.xtn",
|
||||
"../../dir/.file_5.xtn",
|
||||
},
|
||||
},
|
||||
"visibleFiles": {
|
||||
expectHidden: false,
|
||||
paths: []string{
|
||||
"root_file.xtn",
|
||||
"/file_1.xtn",
|
||||
"dir/file_2.xtn",
|
||||
"dir1/dir2/dir3/file_3.xtn",
|
||||
"../../file_4.xtn",
|
||||
"../../dir/file_5.xtn",
|
||||
},
|
||||
},
|
||||
}
|
||||
for n, c := range tests {
|
||||
t.Run(n, func(t *testing.T) {
|
||||
for _, path := range c.paths {
|
||||
actual := IsHiddenFilePath(path)
|
||||
if actual != c.expectHidden {
|
||||
t.Fatalf("For file path %q, expected hidden: %v, got hidden: %v", path, c.expectHidden, actual)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveHiddenFiles(t *testing.T) {
|
||||
paths := []string{
|
||||
"file1.xtn",
|
||||
".file2.xtn",
|
||||
"dir/fa1",
|
||||
"dir/fa2",
|
||||
"dir/.fa3",
|
||||
"../../.fa4",
|
||||
"../../fa5",
|
||||
"../../dir/fa6",
|
||||
"../../dir/.fa7",
|
||||
}
|
||||
result := RemoveHiddenFiles(paths)
|
||||
expected := []string{
|
||||
"file1.xtn",
|
||||
"dir/fa1",
|
||||
"dir/fa2",
|
||||
"../../fa5",
|
||||
"../../dir/fa6",
|
||||
}
|
||||
if !reflect.DeepEqual(result, expected) {
|
||||
t.Fatalf("Hidden dirs not correctly removed, expected %v but got %v\n", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,15 +122,17 @@ func AddGenerateDockerfile(cmd *cobra.Command) {
|
||||
Use: "gen [DIR]",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return ioutil.WriteFile(filepath.Join(args[0], "Dockerfile"), []byte(`FROM golang:1.15-alpine as builder
|
||||
return ioutil.WriteFile(filepath.Join(args[0], "Dockerfile"), []byte(`FROM golang:1.16-alpine as builder
|
||||
ENV CGO_ENABLED=0
|
||||
WORKDIR /go/src/
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
COPY . .
|
||||
RUN go build -tags netgo -ldflags '-w' -v -o /usr/local/bin/function ./
|
||||
RUN go build -ldflags '-w -s' -v -o /usr/local/bin/function ./
|
||||
|
||||
FROM alpine:latest
|
||||
COPY --from=builder /usr/local/bin/function /usr/local/bin/function
|
||||
CMD ["function"]
|
||||
ENTRYPOINT ["function"]
|
||||
`), 0600)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -45,15 +45,17 @@ func TestCommand_dockerfile(t *testing.T) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
expected := `FROM golang:1.15-alpine as builder
|
||||
expected := `FROM golang:1.16-alpine as builder
|
||||
ENV CGO_ENABLED=0
|
||||
WORKDIR /go/src/
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
COPY . .
|
||||
RUN go build -tags netgo -ldflags '-w' -v -o /usr/local/bin/function ./
|
||||
RUN go build -ldflags '-w -s' -v -o /usr/local/bin/function ./
|
||||
|
||||
FROM alpine:latest
|
||||
COPY --from=builder /usr/local/bin/function /usr/local/bin/function
|
||||
CMD ["function"]
|
||||
ENTRYPOINT ["function"]
|
||||
`
|
||||
if !assert.Equal(t, expected, string(b)) {
|
||||
t.FailNow()
|
||||
|
||||
@@ -37,7 +37,7 @@ func ExampleBuild_modify() {
|
||||
|
||||
// for testing purposes only -- normally read from stdin when Executing
|
||||
cmd.SetIn(bytes.NewBufferString(`
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
# items are provided as nodes
|
||||
items:
|
||||
@@ -61,7 +61,7 @@ functionConfig:
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: config.kubernetes.io/v1alpha1
|
||||
// apiVersion: config.kubernetes.io/v1
|
||||
// kind: ResourceList
|
||||
// items:
|
||||
// - apiVersion: apps/v1
|
||||
@@ -133,7 +133,7 @@ metadata:
|
||||
|
||||
// for testing purposes only -- normally read from stdin when Executing
|
||||
cmd.SetIn(bytes.NewBufferString(`
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
# items are provided as nodes
|
||||
items:
|
||||
@@ -154,7 +154,7 @@ functionConfig:
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: config.kubernetes.io/v1alpha1
|
||||
// apiVersion: config.kubernetes.io/v1
|
||||
// kind: ResourceList
|
||||
// items:
|
||||
// - apiVersion: apps/v1
|
||||
@@ -241,7 +241,7 @@ metadata:
|
||||
|
||||
// for testing purposes only -- normally read from stdin when Executing
|
||||
cmd.SetIn(bytes.NewBufferString(`
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
# items are provided as nodes
|
||||
items:
|
||||
@@ -268,7 +268,7 @@ functionConfig:
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: config.kubernetes.io/v1alpha1
|
||||
// apiVersion: config.kubernetes.io/v1
|
||||
// kind: ResourceList
|
||||
// items:
|
||||
// - apiVersion: apps/v1
|
||||
@@ -296,7 +296,7 @@ functionConfig:
|
||||
func ExampleBuild_validate() {
|
||||
fn := func(rl *framework.ResourceList) error {
|
||||
// validation results
|
||||
var validationResults []framework.ResultItem
|
||||
var validationResults framework.Results
|
||||
|
||||
// validate that each Deployment resource has spec.replicas set
|
||||
for i := range rl.Items {
|
||||
@@ -319,34 +319,31 @@ func ExampleBuild_validate() {
|
||||
if r != nil {
|
||||
continue
|
||||
}
|
||||
validationResults = append(validationResults, framework.ResultItem{
|
||||
validationResults = append(validationResults, &framework.Result{
|
||||
Severity: framework.Error,
|
||||
Message: "field is required",
|
||||
ResourceRef: yaml.ResourceIdentifier{
|
||||
ResourceRef: &yaml.ResourceIdentifier{
|
||||
TypeMeta: meta.TypeMeta,
|
||||
NameMeta: meta.ObjectMeta.NameMeta,
|
||||
},
|
||||
Field: framework.Field{
|
||||
Path: "spec.replicas",
|
||||
SuggestedValue: "1",
|
||||
Field: &framework.Field{
|
||||
Path: "spec.replicas",
|
||||
ProposedValue: "1",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if len(validationResults) > 0 {
|
||||
rl.Result = &framework.Result{
|
||||
Name: "replicas-validator",
|
||||
Items: validationResults,
|
||||
}
|
||||
rl.Results = validationResults
|
||||
}
|
||||
|
||||
return rl.Result
|
||||
return rl.Results
|
||||
}
|
||||
|
||||
cmd := command.Build(framework.ResourceListProcessorFunc(fn), command.StandaloneDisabled, true)
|
||||
// for testing purposes only -- normally read from stdin when Executing
|
||||
cmd.SetIn(bytes.NewBufferString(`
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
# items are provided as nodes
|
||||
items:
|
||||
@@ -362,7 +359,7 @@ items:
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: config.kubernetes.io/v1alpha1
|
||||
// apiVersion: config.kubernetes.io/v1
|
||||
// kind: ResourceList
|
||||
// items:
|
||||
// - apiVersion: apps/v1
|
||||
@@ -370,15 +367,13 @@ items:
|
||||
// metadata:
|
||||
// name: foo
|
||||
// results:
|
||||
// name: replicas-validator
|
||||
// items:
|
||||
// - message: field is required
|
||||
// severity: error
|
||||
// resourceRef:
|
||||
// apiVersion: apps/v1
|
||||
// kind: Deployment
|
||||
// name: foo
|
||||
// field:
|
||||
// path: spec.replicas
|
||||
// suggestedValue: "1"
|
||||
// - message: field is required
|
||||
// severity: error
|
||||
// resourceRef:
|
||||
// apiVersion: apps/v1
|
||||
// kind: Deployment
|
||||
// name: foo
|
||||
// field:
|
||||
// path: spec.replicas
|
||||
// proposedValue: "1"
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ const service = "Service"
|
||||
// ExampleSimpleProcessor_modify implements a function that sets an annotation on each resource.
|
||||
func ExampleSimpleProcessor_modify() {
|
||||
input := bytes.NewBufferString(`
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
# items are provided as nodes
|
||||
items:
|
||||
@@ -60,7 +60,7 @@ functionConfig:
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: config.kubernetes.io/v1alpha1
|
||||
// apiVersion: config.kubernetes.io/v1
|
||||
// kind: ResourceList
|
||||
// items:
|
||||
// - apiVersion: apps/v1
|
||||
@@ -86,7 +86,7 @@ functionConfig:
|
||||
// If the resource already exists, it replaces the resource with a new copy.
|
||||
func ExampleSimpleProcessor_generateReplace() {
|
||||
input := bytes.NewBufferString(`
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
# items are provided as nodes
|
||||
items:
|
||||
@@ -150,7 +150,7 @@ metadata:
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: config.kubernetes.io/v1alpha1
|
||||
// apiVersion: config.kubernetes.io/v1
|
||||
// kind: ResourceList
|
||||
// items:
|
||||
// - apiVersion: apps/v1
|
||||
@@ -471,7 +471,7 @@ spec:
|
||||
// The second resource will be treated as a patch since its metadata matches the resource
|
||||
// generated by ResourceTemplates and MergeResources is true.
|
||||
rw := kio.ByteReadWriter{Reader: bytes.NewBufferString(`
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- kind: Deployment
|
||||
@@ -501,7 +501,7 @@ functionConfig:
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: config.kubernetes.io/v1alpha1
|
||||
// apiVersion: config.kubernetes.io/v1
|
||||
// kind: ResourceList
|
||||
// items:
|
||||
// - apiVersion: apps/v1
|
||||
@@ -543,7 +543,7 @@ func ExampleSelector_templatizeKinds() {
|
||||
}
|
||||
rw := &kio.ByteReadWriter{
|
||||
Reader: bytes.NewBufferString(`
|
||||
apiVersion: config.kubernetes.io/v1beta1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
functionConfig:
|
||||
kindName: Deployment
|
||||
@@ -575,7 +575,7 @@ items:
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: config.kubernetes.io/v1beta1
|
||||
// apiVersion: config.kubernetes.io/v1
|
||||
// kind: ResourceList
|
||||
// items:
|
||||
// - apiVersion: apps/v1
|
||||
@@ -595,7 +595,7 @@ func ExampleSelector_templatizeAnnotations() {
|
||||
Value string `yaml:"value"`
|
||||
}
|
||||
rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
|
||||
apiVersion: config.kubernetes.io/v1beta1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
functionConfig:
|
||||
value: bar
|
||||
@@ -629,7 +629,7 @@ items:
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: config.kubernetes.io/v1beta1
|
||||
// apiVersion: config.kubernetes.io/v1
|
||||
// kind: ResourceList
|
||||
// items:
|
||||
// - apiVersion: apps/v1
|
||||
@@ -995,7 +995,7 @@ func ExampleVersionedAPIProcessor() {
|
||||
}}}
|
||||
|
||||
source := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
|
||||
apiVersion: config.kubernetes.io/v1beta1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
functionConfig:
|
||||
apiVersion: example.com/v1alpha1
|
||||
@@ -1011,7 +1011,7 @@ functionConfig:
|
||||
}
|
||||
|
||||
// Output:
|
||||
// apiVersion: config.kubernetes.io/v1beta1
|
||||
// apiVersion: config.kubernetes.io/v1
|
||||
// kind: ResourceList
|
||||
// items:
|
||||
// - apiVersion: apps/v1
|
||||
|
||||
@@ -17,6 +17,22 @@ import (
|
||||
// This framework facilitates building functions that receive and emit ResourceLists,
|
||||
// as required by the specification.
|
||||
type ResourceList struct {
|
||||
// Items is the ResourceList.items input and output value.
|
||||
//
|
||||
// e.g. given the function input:
|
||||
//
|
||||
// kind: ResourceList
|
||||
// items:
|
||||
// - kind: Deployment
|
||||
// ...
|
||||
// - kind: Service
|
||||
// ...
|
||||
//
|
||||
// Items will be a slice containing the Deployment and Service resources
|
||||
// Mutating functions will alter this field during processing.
|
||||
// This field is required.
|
||||
Items []*yaml.RNode `yaml:"items" json:"items"`
|
||||
|
||||
// FunctionConfig is the ResourceList.functionConfig input value.
|
||||
//
|
||||
// e.g. given the input:
|
||||
@@ -31,27 +47,12 @@ type ResourceList struct {
|
||||
// kind: Example
|
||||
// spec:
|
||||
// foo: var
|
||||
FunctionConfig *yaml.RNode `yaml:"functionConfig" json:"functionConfig"`
|
||||
FunctionConfig *yaml.RNode `yaml:"functionConfig,omitempty" json:"functionConfig,omitempty"`
|
||||
|
||||
// Items is the ResourceList.items input and output value.
|
||||
//
|
||||
// e.g. given the function input:
|
||||
//
|
||||
// kind: ResourceList
|
||||
// items:
|
||||
// - kind: Deployment
|
||||
// ...
|
||||
// - kind: Service
|
||||
// ...
|
||||
//
|
||||
// Items will be a slice containing the Deployment and Service resources
|
||||
// Mutating functions will alter this field during processing.
|
||||
Items []*yaml.RNode `yaml:"items" json:"items"`
|
||||
|
||||
// Result is ResourceList.result output value.
|
||||
// Results is ResourceList.results output value.
|
||||
// Validating functions can optionally use this field to communicate structured
|
||||
// validation error data to downstream functions.
|
||||
Result *Result `yaml:"results" json:"results"`
|
||||
Results Results `yaml:"results,omitempty" json:"results,omitempty"`
|
||||
}
|
||||
|
||||
// ResourceListProcessor is implemented by configuration functions built with this framework
|
||||
@@ -119,8 +120,8 @@ func Execute(p ResourceListProcessor, rlSource *kio.ByteReadWriter) error {
|
||||
|
||||
// Write the results
|
||||
// Set the ResourceList.results for validating functions
|
||||
if rl.Result != nil && len(rl.Result.Items) > 0 {
|
||||
b, err := yaml.Marshal(rl.Result)
|
||||
if len(rl.Results) > 0 {
|
||||
b, err := yaml.Marshal(rl.Results)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
|
||||
@@ -16,39 +16,37 @@ import (
|
||||
|
||||
func TestExecute_Result(t *testing.T) {
|
||||
p := framework.ResourceListProcessorFunc(func(rl *framework.ResourceList) error {
|
||||
err := &framework.Result{
|
||||
Name: "Incompatible config",
|
||||
Items: []framework.ResultItem{
|
||||
{
|
||||
Message: "bad value for replicas",
|
||||
Severity: framework.Error,
|
||||
ResourceRef: yaml.ResourceIdentifier{
|
||||
TypeMeta: yaml.TypeMeta{APIVersion: "v1", Kind: "Deployment"},
|
||||
NameMeta: yaml.NameMeta{Name: "tester", Namespace: "default"},
|
||||
},
|
||||
Field: framework.Field{
|
||||
Path: ".spec.Replicas",
|
||||
CurrentValue: "0",
|
||||
SuggestedValue: "3",
|
||||
},
|
||||
File: framework.File{
|
||||
Path: "/path/to/deployment.yaml",
|
||||
Index: 0,
|
||||
},
|
||||
err := &framework.Results{
|
||||
{
|
||||
Message: "bad value for replicas",
|
||||
Severity: framework.Error,
|
||||
ResourceRef: &yaml.ResourceIdentifier{
|
||||
TypeMeta: yaml.TypeMeta{APIVersion: "v1", Kind: "Deployment"},
|
||||
NameMeta: yaml.NameMeta{Name: "tester", Namespace: "default"},
|
||||
},
|
||||
{
|
||||
Message: "some error",
|
||||
Severity: framework.Error,
|
||||
Field: &framework.Field{
|
||||
Path: ".spec.Replicas",
|
||||
CurrentValue: "0",
|
||||
ProposedValue: "3",
|
||||
},
|
||||
File: &framework.File{
|
||||
Path: "/path/to/deployment.yaml",
|
||||
Index: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
Message: "some error",
|
||||
Severity: framework.Error,
|
||||
Tags: map[string]string{"foo": "bar"},
|
||||
},
|
||||
}
|
||||
rl.Result = err
|
||||
rl.Results = *err
|
||||
return err
|
||||
})
|
||||
out := new(bytes.Buffer)
|
||||
source := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
|
||||
kind: ResourceList
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
items:
|
||||
- kind: Deployment
|
||||
apiVersion: v1
|
||||
@@ -61,9 +59,9 @@ items:
|
||||
err := framework.Execute(p, source)
|
||||
assert.EqualError(t, err, `[error] v1/Deployment/default/tester .spec.Replicas: bad value for replicas
|
||||
|
||||
[error] : some error`)
|
||||
assert.Equal(t, 1, err.(*framework.Result).ExitCode())
|
||||
assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1
|
||||
[error]: some error`)
|
||||
assert.Equal(t, 1, err.(*framework.Results).ExitCode())
|
||||
assert.Equal(t, `apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- kind: Deployment
|
||||
@@ -74,21 +72,21 @@ items:
|
||||
spec:
|
||||
replicas: 0
|
||||
results:
|
||||
name: Incompatible config
|
||||
items:
|
||||
- message: bad value for replicas
|
||||
severity: error
|
||||
resourceRef:
|
||||
apiVersion: v1
|
||||
kind: Deployment
|
||||
name: tester
|
||||
namespace: default
|
||||
field:
|
||||
path: .spec.Replicas
|
||||
currentValue: "0"
|
||||
suggestedValue: "3"
|
||||
file:
|
||||
path: /path/to/deployment.yaml
|
||||
- message: some error
|
||||
severity: error`, strings.TrimSpace(out.String()))
|
||||
- message: bad value for replicas
|
||||
severity: error
|
||||
resourceRef:
|
||||
apiVersion: v1
|
||||
kind: Deployment
|
||||
name: tester
|
||||
namespace: default
|
||||
field:
|
||||
path: .spec.Replicas
|
||||
currentValue: "0"
|
||||
proposedValue: "3"
|
||||
file:
|
||||
path: /path/to/deployment.yaml
|
||||
- message: some error
|
||||
severity: error
|
||||
tags:
|
||||
foo: bar`, strings.TrimSpace(out.String()))
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestTemplateProcessor_ResourceTemplates(t *testing.T) {
|
||||
|
||||
out := new(bytes.Buffer)
|
||||
rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: v1
|
||||
@@ -47,7 +47,7 @@ functionConfig:
|
||||
|
||||
require.NoError(t, framework.Execute(p, rw))
|
||||
require.Equal(t, strings.TrimSpace(`
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: v1
|
||||
@@ -98,7 +98,7 @@ metadata:
|
||||
out := new(bytes.Buffer)
|
||||
|
||||
rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: apps/v1
|
||||
@@ -130,7 +130,7 @@ functionConfig:
|
||||
|
||||
require.NoError(t, framework.Execute(p, rw))
|
||||
require.Equal(t, strings.TrimSpace(`
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: apps/v1
|
||||
@@ -194,7 +194,7 @@ env:
|
||||
|
||||
out := new(bytes.Buffer)
|
||||
rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: apps/v1
|
||||
@@ -231,7 +231,7 @@ functionConfig:
|
||||
|
||||
require.NoError(t, framework.Execute(p, rw))
|
||||
require.Equal(t, strings.TrimSpace(`
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: apps/v1
|
||||
@@ -300,7 +300,7 @@ func TestTemplateProcessor_ContainerPatchTemplates_MultipleWorkloadKinds(t *test
|
||||
|
||||
out := new(bytes.Buffer)
|
||||
rw := &kio.ByteReadWriter{Writer: out, Reader: bytes.NewBufferString(`
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items: []
|
||||
functionConfig:
|
||||
@@ -591,7 +591,7 @@ func TestTemplateProcessor_AdditionalSchemas(t *testing.T) {
|
||||
out := new(bytes.Buffer)
|
||||
|
||||
rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: example.com/v1
|
||||
@@ -606,7 +606,7 @@ items:
|
||||
Writer: out}
|
||||
require.NoError(t, framework.Execute(p, rw))
|
||||
require.Equal(t, strings.TrimSpace(`
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: example.com/v1
|
||||
|
||||
@@ -23,89 +23,98 @@ const (
|
||||
)
|
||||
|
||||
// ResultItem defines a validation result
|
||||
type ResultItem struct {
|
||||
// Message is a human readable message
|
||||
Message string `yaml:"message,omitempty"`
|
||||
type Result struct {
|
||||
// Message is a human readable message. This field is required.
|
||||
Message string `yaml:"message,omitempty" json:"message,omitempty"`
|
||||
|
||||
// Severity is the severity of this result
|
||||
Severity Severity `yaml:"severity,omitempty"`
|
||||
Severity Severity `yaml:"severity,omitempty" json:"severity,omitempty"`
|
||||
|
||||
// ResourceRef is a reference to a resource
|
||||
ResourceRef yaml.ResourceIdentifier `yaml:"resourceRef,omitempty"`
|
||||
// ResourceRef is a reference to a resource.
|
||||
// Required fields: apiVersion, kind, name.
|
||||
ResourceRef *yaml.ResourceIdentifier `yaml:"resourceRef,omitempty" json:"resourceRef,omitempty"`
|
||||
|
||||
// Field is a reference to the field in a resource this result refers to
|
||||
Field Field `yaml:"field,omitempty"`
|
||||
Field *Field `yaml:"field,omitempty" json:"field,omitempty"`
|
||||
|
||||
// File references a file containing the resource this result refers to
|
||||
File File `yaml:"file,omitempty"`
|
||||
File *File `yaml:"file,omitempty" json:"file,omitempty"`
|
||||
|
||||
// Tags is an unstructured key value map stored with a result that may be set
|
||||
// by external tools to store and retrieve arbitrary metadata
|
||||
Tags map[string]string `yaml:"tags,omitempty" json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
// String provides a human-readable message for the result item
|
||||
func (i ResultItem) String() string {
|
||||
func (i Result) String() string {
|
||||
identifier := i.ResourceRef
|
||||
var idStringList []string
|
||||
if identifier.APIVersion != "" {
|
||||
idStringList = append(idStringList, identifier.APIVersion)
|
||||
}
|
||||
if identifier.Kind != "" {
|
||||
idStringList = append(idStringList, identifier.Kind)
|
||||
}
|
||||
if identifier.Namespace != "" {
|
||||
idStringList = append(idStringList, identifier.Namespace)
|
||||
}
|
||||
if identifier.Name != "" {
|
||||
idStringList = append(idStringList, identifier.Name)
|
||||
if identifier != nil {
|
||||
if identifier.APIVersion != "" {
|
||||
idStringList = append(idStringList, identifier.APIVersion)
|
||||
}
|
||||
if identifier.Kind != "" {
|
||||
idStringList = append(idStringList, identifier.Kind)
|
||||
}
|
||||
if identifier.Namespace != "" {
|
||||
idStringList = append(idStringList, identifier.Namespace)
|
||||
}
|
||||
if identifier.Name != "" {
|
||||
idStringList = append(idStringList, identifier.Name)
|
||||
}
|
||||
}
|
||||
formatString := "[%s]"
|
||||
list := []interface{}{i.Severity}
|
||||
if len(idStringList) > 0 {
|
||||
idString := strings.Join(idStringList, "/")
|
||||
return fmt.Sprintf("[%s] %s %s: %s", i.Severity, idString, i.Field.Path, i.Message)
|
||||
formatString += " %s"
|
||||
list = append(list, strings.Join(idStringList, "/"))
|
||||
}
|
||||
return fmt.Sprintf("[%s] %s: %s", i.Severity, i.Field.Path, i.Message)
|
||||
if i.Field != nil {
|
||||
formatString += " %s"
|
||||
list = append(list, i.Field.Path)
|
||||
}
|
||||
formatString += ": %s"
|
||||
list = append(list, i.Message)
|
||||
return fmt.Sprintf(formatString, list...)
|
||||
}
|
||||
|
||||
// File references a file containing a resource
|
||||
type File struct {
|
||||
// Path is relative path to the file containing the resource
|
||||
Path string `yaml:"path,omitempty"`
|
||||
// Path is relative path to the file containing the resource.
|
||||
// This field is required.
|
||||
Path string `yaml:"path,omitempty" json:"path,omitempty"`
|
||||
|
||||
// Index is the index into the file containing the resource
|
||||
// (i.e. if there are multiple resources in a single file)
|
||||
Index int `yaml:"index,omitempty"`
|
||||
Index int `yaml:"index,omitempty" json:"index,omitempty"`
|
||||
}
|
||||
|
||||
// Field references a field in a resource
|
||||
type Field struct {
|
||||
// Path is the field path
|
||||
Path string `yaml:"path,omitempty"`
|
||||
// Path is the field path. This field is required.
|
||||
Path string `yaml:"path,omitempty" json:"path,omitempty"`
|
||||
|
||||
// CurrentValue is the current field value
|
||||
CurrentValue string `yaml:"currentValue,omitempty"`
|
||||
CurrentValue interface{} `yaml:"currentValue,omitempty" json:"currentValue,omitempty"`
|
||||
|
||||
// SuggestedValue is the suggested field value
|
||||
SuggestedValue string `yaml:"suggestedValue,omitempty"`
|
||||
// ProposedValue is the proposed value of the field to fix an issue.
|
||||
ProposedValue interface{} `yaml:"proposedValue,omitempty" json:"proposedValue,omitempty"`
|
||||
}
|
||||
|
||||
// Result defines a function result which will be set on the emitted ResourceList
|
||||
type Result struct {
|
||||
// Name is the name of the function creating the result
|
||||
Name string `yaml:"name,omitempty"`
|
||||
type Results []*Result
|
||||
|
||||
// Items are the individual results
|
||||
Items []ResultItem `yaml:"items,omitempty"`
|
||||
}
|
||||
|
||||
// Error enables a Result to be returned as an error
|
||||
func (e Result) Error() string {
|
||||
// Error enables Results to be returned as an error
|
||||
func (e Results) Error() string {
|
||||
var msgs []string
|
||||
for _, i := range e.Items {
|
||||
for _, i := range e {
|
||||
msgs = append(msgs, i.String())
|
||||
}
|
||||
return strings.Join(msgs, "\n\n")
|
||||
}
|
||||
|
||||
// ExitCode provides the exit code based on the result's severity
|
||||
func (e Result) ExitCode() int {
|
||||
for _, i := range e.Items {
|
||||
func (e Results) ExitCode() int {
|
||||
for _, i := range e {
|
||||
if i.Severity == Error {
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"}}}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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]))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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{})
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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
54
releasing/cloudbuild-local.sh
Executable 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 "##########################################"
|
||||
@@ -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 \
|
||||
|
||||
@@ -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==
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user