mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-21 13:58:18 +00:00
Compare commits
38 Commits
release-ky
...
updateRele
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f59f12947b | ||
|
|
90bc96d9d8 | ||
|
|
2be59aefec | ||
|
|
91b779269f | ||
|
|
e6ea4ad260 | ||
|
|
f5cab0f6e1 | ||
|
|
e39afc9f68 | ||
|
|
3801a29d9b | ||
|
|
39cf4af638 | ||
|
|
9d65dd0786 | ||
|
|
3dced70850 | ||
|
|
4356043582 | ||
|
|
c202be0338 | ||
|
|
9359155418 | ||
|
|
ba22bbe19e | ||
|
|
3e5989ae18 | ||
|
|
fbebd990a4 | ||
|
|
646e0b4f61 | ||
|
|
0f67692265 | ||
|
|
6a7afd8694 | ||
|
|
46194b3385 | ||
|
|
904a9dea08 | ||
|
|
30b58e90a3 | ||
|
|
5bdd8657a5 | ||
|
|
893c99da1c | ||
|
|
43980f8586 | ||
|
|
0c8e033c96 | ||
|
|
fa15242719 | ||
|
|
a2e080bf6c | ||
|
|
e91cdb5eba | ||
|
|
ef54f9be5a | ||
|
|
f051acb83c | ||
|
|
bbb046081b | ||
|
|
77b28a986f | ||
|
|
97bc34eb37 | ||
|
|
719380f523 | ||
|
|
640ae9521b | ||
|
|
1dffc7577b |
@@ -86,6 +86,18 @@ func (f Filter) setScalar(node *yaml.RNode) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func filterReferralCandidates(
|
||||
referrer *resource.Resource,
|
||||
matches []*resource.Resource) []*resource.Resource {
|
||||
var ret []*resource.Resource
|
||||
for _, m := range matches {
|
||||
if referrer.PrefixesSuffixesEquals(m) {
|
||||
ret = append(ret, m)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// selectReferral picks the referral among a subset of candidates.
|
||||
// It returns the current name and namespace of the selected candidate.
|
||||
// Note that the content of the referricalCandidateSubset slice is most of the time
|
||||
@@ -103,12 +115,19 @@ func selectReferral(
|
||||
id := res.OrgId()
|
||||
if id.IsSelected(&target) && res.GetOriginalName() == oldName {
|
||||
matches := referralCandidates.GetMatchingResourcesByOriginalId(id.Equals)
|
||||
// If there's more than one match, there's no way
|
||||
// to know which one to pick, so emit error.
|
||||
// If there's more than one match,
|
||||
// filter the matches by prefix and suffix
|
||||
if len(matches) > 1 {
|
||||
return "", "", fmt.Errorf(
|
||||
"multiple matches for %s:\n %v",
|
||||
id, getIds(matches))
|
||||
filteredMatches := filterReferralCandidates(referrer, matches)
|
||||
if len(filteredMatches) > 1 {
|
||||
return "", "", fmt.Errorf(
|
||||
"multiple matches for %s:\n %v",
|
||||
id, getIds(filteredMatches))
|
||||
}
|
||||
// Check is the match the resource we are working on
|
||||
if len(filteredMatches) == 0 || res != filteredMatches[0] {
|
||||
continue
|
||||
}
|
||||
}
|
||||
// In the resource, note that it is referenced
|
||||
// by the referrer.
|
||||
|
||||
@@ -331,3 +331,434 @@ metadata:
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCandidatesWithDifferentPrefixSuffix(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
input string
|
||||
candidates string
|
||||
expected string
|
||||
filter Filter
|
||||
originalNames []string
|
||||
prefix []string
|
||||
suffix []string
|
||||
inputPrefix string
|
||||
inputSuffix string
|
||||
err bool
|
||||
}{
|
||||
"prefix match": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dep
|
||||
ref:
|
||||
name: oldName
|
||||
`,
|
||||
candidates: `
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName2
|
||||
`,
|
||||
originalNames: []string{"oldName", "oldName"},
|
||||
prefix: []string{"prefix1", "prefix2"},
|
||||
suffix: []string{"", "suffix2"},
|
||||
inputPrefix: "prefix1",
|
||||
inputSuffix: "",
|
||||
expected: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dep
|
||||
ref:
|
||||
name: newName
|
||||
`,
|
||||
filter: Filter{
|
||||
FieldSpec: types.FieldSpec{Path: "ref/name"},
|
||||
Target: resid.Gvk{
|
||||
Group: "apps",
|
||||
Version: "v1",
|
||||
Kind: "Secret",
|
||||
},
|
||||
},
|
||||
err: false,
|
||||
},
|
||||
"suffix match": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dep
|
||||
ref:
|
||||
name: oldName
|
||||
`,
|
||||
candidates: `
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName2
|
||||
`,
|
||||
originalNames: []string{"oldName", "oldName"},
|
||||
prefix: []string{"", "prefix2"},
|
||||
suffix: []string{"suffix1", "suffix2"},
|
||||
inputPrefix: "",
|
||||
inputSuffix: "suffix1",
|
||||
expected: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dep
|
||||
ref:
|
||||
name: newName
|
||||
`,
|
||||
filter: Filter{
|
||||
FieldSpec: types.FieldSpec{Path: "ref/name"},
|
||||
Target: resid.Gvk{
|
||||
Group: "apps",
|
||||
Version: "v1",
|
||||
Kind: "Secret",
|
||||
},
|
||||
},
|
||||
err: false,
|
||||
},
|
||||
"prefix suffix both match": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dep
|
||||
ref:
|
||||
name: oldName
|
||||
`,
|
||||
candidates: `
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName2
|
||||
`,
|
||||
originalNames: []string{"oldName", "oldName"},
|
||||
prefix: []string{"prefix1", "prefix2"},
|
||||
suffix: []string{"suffix1", "suffix2"},
|
||||
inputPrefix: "prefix1",
|
||||
inputSuffix: "suffix1",
|
||||
expected: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dep
|
||||
ref:
|
||||
name: newName
|
||||
`,
|
||||
filter: Filter{
|
||||
FieldSpec: types.FieldSpec{Path: "ref/name"},
|
||||
Target: resid.Gvk{
|
||||
Group: "apps",
|
||||
Version: "v1",
|
||||
Kind: "Secret",
|
||||
},
|
||||
},
|
||||
err: false,
|
||||
},
|
||||
"multiple match: both": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dep
|
||||
ref:
|
||||
name: oldName
|
||||
`,
|
||||
candidates: `
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName2
|
||||
`,
|
||||
originalNames: []string{"oldName", "oldName"},
|
||||
prefix: []string{"prefix", "prefix"},
|
||||
suffix: []string{"suffix", "suffix"},
|
||||
inputPrefix: "prefix",
|
||||
inputSuffix: "suffix",
|
||||
expected: "",
|
||||
filter: Filter{
|
||||
FieldSpec: types.FieldSpec{Path: "ref/name"},
|
||||
Target: resid.Gvk{
|
||||
Group: "apps",
|
||||
Version: "v1",
|
||||
Kind: "Secret",
|
||||
},
|
||||
},
|
||||
err: true,
|
||||
},
|
||||
"multiple match: only prefix": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dep
|
||||
ref:
|
||||
name: oldName
|
||||
`,
|
||||
candidates: `
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName2
|
||||
`,
|
||||
originalNames: []string{"oldName", "oldName"},
|
||||
prefix: []string{"prefix", "prefix"},
|
||||
suffix: []string{"", ""},
|
||||
inputPrefix: "prefix",
|
||||
inputSuffix: "",
|
||||
expected: "",
|
||||
filter: Filter{
|
||||
FieldSpec: types.FieldSpec{Path: "ref/name"},
|
||||
Target: resid.Gvk{
|
||||
Group: "apps",
|
||||
Version: "v1",
|
||||
Kind: "Secret",
|
||||
},
|
||||
},
|
||||
err: true,
|
||||
},
|
||||
"multiple match: only suffix": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dep
|
||||
ref:
|
||||
name: oldName
|
||||
`,
|
||||
candidates: `
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName2
|
||||
`,
|
||||
originalNames: []string{"oldName", "oldName"},
|
||||
prefix: []string{"", ""},
|
||||
suffix: []string{"suffix", "suffix"},
|
||||
inputPrefix: "",
|
||||
inputSuffix: "suffix",
|
||||
expected: "",
|
||||
filter: Filter{
|
||||
FieldSpec: types.FieldSpec{Path: "ref/name"},
|
||||
Target: resid.Gvk{
|
||||
Group: "apps",
|
||||
Version: "v1",
|
||||
Kind: "Secret",
|
||||
},
|
||||
},
|
||||
err: true,
|
||||
},
|
||||
"no match: neither match": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dep
|
||||
ref:
|
||||
name: oldName
|
||||
`,
|
||||
candidates: `
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName2
|
||||
`,
|
||||
originalNames: []string{"oldName", "oldName"},
|
||||
prefix: []string{"prefix1", "prefix2"},
|
||||
suffix: []string{"suffix1", "suffix2"},
|
||||
inputPrefix: "prefix",
|
||||
inputSuffix: "suffix",
|
||||
expected: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dep
|
||||
ref:
|
||||
name: oldName
|
||||
`,
|
||||
filter: Filter{
|
||||
FieldSpec: types.FieldSpec{Path: "ref/name"},
|
||||
Target: resid.Gvk{
|
||||
Group: "apps",
|
||||
Version: "v1",
|
||||
Kind: "Secret",
|
||||
},
|
||||
},
|
||||
err: false,
|
||||
},
|
||||
"no match: prefix doesn't match": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dep
|
||||
ref:
|
||||
name: oldName
|
||||
`,
|
||||
candidates: `
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName2
|
||||
`,
|
||||
originalNames: []string{"oldName", "oldName"},
|
||||
prefix: []string{"prefix1", "prefix2"},
|
||||
suffix: []string{"suffix", "suffix"},
|
||||
inputPrefix: "prefix",
|
||||
inputSuffix: "suffix",
|
||||
expected: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dep
|
||||
ref:
|
||||
name: oldName
|
||||
`,
|
||||
filter: Filter{
|
||||
FieldSpec: types.FieldSpec{Path: "ref/name"},
|
||||
Target: resid.Gvk{
|
||||
Group: "apps",
|
||||
Version: "v1",
|
||||
Kind: "Secret",
|
||||
},
|
||||
},
|
||||
err: false,
|
||||
},
|
||||
"no match: suffix doesn't match": {
|
||||
input: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dep
|
||||
ref:
|
||||
name: oldName
|
||||
`,
|
||||
candidates: `
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: newName2
|
||||
`,
|
||||
originalNames: []string{"oldName", "oldName"},
|
||||
prefix: []string{"prefix", "prefix"},
|
||||
suffix: []string{"suffix1", "suffix2"},
|
||||
inputPrefix: "prefix",
|
||||
inputSuffix: "suffix",
|
||||
expected: `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dep
|
||||
ref:
|
||||
name: oldName
|
||||
`,
|
||||
filter: Filter{
|
||||
FieldSpec: types.FieldSpec{Path: "ref/name"},
|
||||
Target: resid.Gvk{
|
||||
Group: "apps",
|
||||
Version: "v1",
|
||||
Kind: "Secret",
|
||||
},
|
||||
},
|
||||
err: false,
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range testCases {
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
factory := resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl())
|
||||
referrer, err := factory.FromBytes([]byte(tc.input))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if tc.inputPrefix != "" {
|
||||
referrer.AddNamePrefix(tc.inputPrefix)
|
||||
}
|
||||
if tc.inputSuffix != "" {
|
||||
referrer.AddNameSuffix(tc.inputSuffix)
|
||||
}
|
||||
tc.filter.Referrer = referrer
|
||||
|
||||
resMapFactory := resmap.NewFactory(factory, nil)
|
||||
candidatesRes, err := factory.SliceFromBytesWithNames(
|
||||
tc.originalNames, []byte(tc.candidates))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := range candidatesRes {
|
||||
if tc.prefix[i] != "" {
|
||||
candidatesRes[i].AddNamePrefix(tc.prefix[i])
|
||||
}
|
||||
if tc.suffix[i] != "" {
|
||||
candidatesRes[i].AddNameSuffix(tc.suffix[i])
|
||||
}
|
||||
}
|
||||
|
||||
candidates := resMapFactory.FromResourceSlice(candidatesRes)
|
||||
tc.filter.ReferralCandidates = candidates
|
||||
|
||||
if !tc.err {
|
||||
if !assert.Equal(t,
|
||||
strings.TrimSpace(tc.expected),
|
||||
strings.TrimSpace(
|
||||
filtertest_test.RunFilter(t, tc.input, tc.filter))) {
|
||||
t.FailNow()
|
||||
}
|
||||
} else {
|
||||
_, err := filtertest_test.RunFilterE(t, tc.input, tc.filter)
|
||||
if err == nil {
|
||||
t.Fatalf("an error is expected")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,13 @@ require (
|
||||
github.com/yujunz/go-getter v1.4.1-lite
|
||||
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71
|
||||
k8s.io/api v0.17.0
|
||||
k8s.io/apimachinery v0.17.0
|
||||
k8s.io/client-go v0.17.0
|
||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
|
||||
sigs.k8s.io/kustomize/kyaml v0.5.0
|
||||
sigs.k8s.io/kustomize/kyaml v0.6.1
|
||||
sigs.k8s.io/yaml v1.2.0
|
||||
)
|
||||
|
||||
replace sigs.k8s.io/kustomize/kyaml v0.5.0 => ../kyaml
|
||||
replace sigs.k8s.io/kustomize/kyaml v0.6.1 => ../kyaml
|
||||
|
||||
@@ -38,8 +38,7 @@ type Loader interface {
|
||||
Cleanup() error
|
||||
}
|
||||
|
||||
// Kunstructured allows manipulation of k8s objects
|
||||
// that do not have Golang structs.
|
||||
// Kunstructured represents a Kubernetes Resource Model object.
|
||||
type Kunstructured interface {
|
||||
// Several uses.
|
||||
Copy() Kunstructured
|
||||
|
||||
@@ -338,6 +338,7 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
@@ -523,8 +524,8 @@ k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl
|
||||
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
|
||||
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
|
||||
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
|
||||
sigs.k8s.io/kustomize/kyaml v0.5.0 h1:xufpSxgpugQxtd0aN1ZsWnr3Kj0fpAi7GN4dnEs4oPg=
|
||||
sigs.k8s.io/kustomize/kyaml v0.5.0/go.mod h1:bEzbO5pN9OvlEeCLvFHo8Pu7SA26Herc2m60UeWZBdI=
|
||||
sigs.k8s.io/kustomize/kyaml v0.6.1 h1:mwffj5vt3MPdbWV3fZnnwol8SO7sUoGdgejBlvseyak=
|
||||
sigs.k8s.io/kustomize/kyaml v0.6.1/go.mod h1:bEzbO5pN9OvlEeCLvFHo8Pu7SA26Herc2m60UeWZBdI=
|
||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
|
||||
25
api/internal/merge/merginator.go
Normal file
25
api/internal/merge/merginator.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package merge
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
)
|
||||
|
||||
// Merginator implements resmap.Merginator using kyaml libs.
|
||||
type Merginator struct {
|
||||
}
|
||||
|
||||
var _ resmap.Merginator = (*Merginator)(nil)
|
||||
|
||||
func NewMerginator(_ *resource.Factory) *Merginator {
|
||||
return &Merginator{}
|
||||
}
|
||||
|
||||
// Merge implements resmap.Merginator
|
||||
func (m Merginator) Merge(
|
||||
resources []*resource.Resource) (resmap.ResMap, error) {
|
||||
panic("TODO(#Merginator): implement Merge")
|
||||
}
|
||||
4
api/internal/merge/merginator_test.go
Normal file
4
api/internal/merge/merginator_test.go
Normal file
@@ -0,0 +1,4 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package merge_test
|
||||
64
api/internal/validate/fieldvalidator.go
Normal file
64
api/internal/validate/fieldvalidator.go
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package validate
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
)
|
||||
|
||||
// FieldValidator implements ifc.Validator to check
|
||||
// the values of various KRM string fields,
|
||||
// e.g. labels, annotations, names, namespaces.
|
||||
type FieldValidator struct {
|
||||
}
|
||||
|
||||
var _ ifc.Validator = (*FieldValidator)(nil)
|
||||
|
||||
func NewFieldValidator() *FieldValidator {
|
||||
return &FieldValidator{}
|
||||
}
|
||||
|
||||
// TODO(#FieldValidator): implement MakeAnnotationValidator
|
||||
func (f FieldValidator) MakeAnnotationValidator() func(map[string]string) error {
|
||||
return func(x map[string]string) error {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(#FieldValidator): implement MakeAnnotationNameValidator
|
||||
func (f FieldValidator) MakeAnnotationNameValidator() func([]string) error {
|
||||
return func(x []string) error {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(#FieldValidator): implement MakeLabelValidator
|
||||
func (f FieldValidator) MakeLabelValidator() func(map[string]string) error {
|
||||
return func(x map[string]string) error {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(#FieldValidator): implement MakeLabelNameValidator
|
||||
func (f FieldValidator) MakeLabelNameValidator() func([]string) error {
|
||||
return func(x []string) error {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(#FieldValidator): implement ValidateNamespace
|
||||
func (f FieldValidator) ValidateNamespace(s string) []string {
|
||||
var errs []string
|
||||
return errs
|
||||
}
|
||||
|
||||
// TODO(#FieldValidator): implement ErrIfInvalidKey
|
||||
func (f FieldValidator) ErrIfInvalidKey(s string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO(#FieldValidator): implement IsEnvVarName
|
||||
func (f FieldValidator) IsEnvVarName(k string) error {
|
||||
return nil
|
||||
}
|
||||
4
api/internal/validate/fieldvalidator_test.go
Normal file
4
api/internal/validate/fieldvalidator_test.go
Normal file
@@ -0,0 +1,4 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package validate_test
|
||||
41
api/internal/wrappy/factory.go
Normal file
41
api/internal/wrappy/factory.go
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package wrappy
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
// WNodeFactory makes instances of WNode.
|
||||
// These instances in turn adapt
|
||||
// sigs.k8s.io/kustomize/kyaml/yaml.RNode
|
||||
// to implement ifc.Unstructured.
|
||||
// This factory is meant to implement ifc.KunstructuredFactory.
|
||||
type WNodeFactory struct {
|
||||
}
|
||||
|
||||
var _ ifc.KunstructuredFactory = (*WNodeFactory)(nil)
|
||||
|
||||
func (k *WNodeFactory) SliceFromBytes(bs []byte) ([]ifc.Kunstructured, error) {
|
||||
panic("TODO(#WNodeFactory): implement SliceFromBytes")
|
||||
}
|
||||
|
||||
func (k *WNodeFactory) FromMap(m map[string]interface{}) ifc.Kunstructured {
|
||||
panic("TODO(#WNodeFactory): implement FromMap")
|
||||
}
|
||||
|
||||
func (k *WNodeFactory) Hasher() ifc.KunstructuredHasher {
|
||||
panic("TODO(#WNodeFactory): implement Hasher")
|
||||
}
|
||||
|
||||
func (k *WNodeFactory) MakeConfigMap(
|
||||
kvLdr ifc.KvLoader, args *types.ConfigMapArgs) (ifc.Kunstructured, error) {
|
||||
panic("TODO(#WNodeFactory): implement MakeConfigMap")
|
||||
}
|
||||
|
||||
func (k *WNodeFactory) MakeSecret(
|
||||
kvLdr ifc.KvLoader, args *types.SecretArgs) (ifc.Kunstructured, error) {
|
||||
panic("TODO(#WNodeFactory): implement MakeSecret")
|
||||
}
|
||||
4
api/internal/wrappy/factory_test.go
Normal file
4
api/internal/wrappy/factory_test.go
Normal file
@@ -0,0 +1,4 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package wrappy_test
|
||||
143
api/internal/wrappy/wnode.go
Normal file
143
api/internal/wrappy/wnode.go
Normal file
@@ -0,0 +1,143 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package wrappy
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// WNode implements ifc.Kunstructured using yaml.RNode.
|
||||
//
|
||||
// It exists only to help manage a switch from
|
||||
// kunstruct.UnstructAdapter to yaml.RNode as the core
|
||||
// representation of KRM objects in kustomize.
|
||||
//
|
||||
// It's got a silly name because we don't want it around for long,
|
||||
// and want its use to be obvious.
|
||||
type WNode struct {
|
||||
node *yaml.RNode
|
||||
}
|
||||
|
||||
var _ ifc.Kunstructured = (*WNode)(nil)
|
||||
|
||||
func NewWNode() *WNode {
|
||||
return FromRNode(yaml.NewRNode(nil))
|
||||
}
|
||||
|
||||
func FromRNode(node *yaml.RNode) *WNode {
|
||||
return &WNode{node: node}
|
||||
}
|
||||
|
||||
func (wn *WNode) demandMetaData(label string) yaml.ResourceMeta {
|
||||
meta, err := wn.node.GetMeta()
|
||||
if err != nil {
|
||||
// Log and die since interface doesn't allow error.
|
||||
log.Fatalf("for %s', expected valid resource: %v", label, err)
|
||||
}
|
||||
return meta
|
||||
}
|
||||
|
||||
// Copy implements ifc.Kunstructured.
|
||||
func (wn *WNode) Copy() ifc.Kunstructured {
|
||||
return &WNode{node: wn.node.Copy()}
|
||||
}
|
||||
|
||||
// GetAnnotations implements ifc.Kunstructured.
|
||||
func (wn *WNode) GetAnnotations() map[string]string {
|
||||
return wn.demandMetaData("GetAnnotations").Annotations
|
||||
}
|
||||
|
||||
// GetFieldValue implements ifc.Kunstructured.
|
||||
func (wn *WNode) GetFieldValue(path string) (interface{}, error) {
|
||||
// The argument is a json path, e.g. "metadata.name"
|
||||
// fields := strings.Split(path, ".")
|
||||
// return wn.node.Pipe(yaml.Lookup(fields...))
|
||||
panic("TODO(#WNode): GetFieldValue; implement or drop from API")
|
||||
}
|
||||
|
||||
// GetGvk implements ifc.Kunstructured.
|
||||
func (wn *WNode) GetGvk() resid.Gvk {
|
||||
meta := wn.demandMetaData("GetGvk")
|
||||
g, v := resid.ParseGroupVersion(meta.APIVersion)
|
||||
return resid.Gvk{Group: g, Version: v, Kind: meta.Kind}
|
||||
}
|
||||
|
||||
// GetKind implements ifc.Kunstructured.
|
||||
func (wn *WNode) GetKind() string {
|
||||
return wn.demandMetaData("GetKind").Kind
|
||||
}
|
||||
|
||||
// GetLabels implements ifc.Kunstructured.
|
||||
func (wn *WNode) GetLabels() map[string]string {
|
||||
return wn.demandMetaData("GetLabels").Labels
|
||||
}
|
||||
|
||||
// GetName implements ifc.Kunstructured.
|
||||
func (wn *WNode) GetName() string {
|
||||
return wn.demandMetaData("GetName").Name
|
||||
}
|
||||
|
||||
// GetSlice implements ifc.Kunstructured.
|
||||
func (wn *WNode) GetSlice(string) ([]interface{}, error) {
|
||||
panic("TODO(#WNode) GetSlice; implement or drop from API")
|
||||
}
|
||||
|
||||
// GetSlice implements ifc.Kunstructured.
|
||||
func (wn *WNode) GetString(string) (string, error) {
|
||||
panic("TODO(#WNode) GetString; implement or drop from API")
|
||||
}
|
||||
|
||||
// Map implements ifc.Kunstructured.
|
||||
func (wn *WNode) Map() map[string]interface{} {
|
||||
panic("TODO(#WNode) Map; implement or drop from API")
|
||||
}
|
||||
|
||||
// MarshalJSON implements ifc.Kunstructured.
|
||||
func (wn *WNode) MarshalJSON() ([]byte, error) {
|
||||
return wn.node.MarshalJSON()
|
||||
}
|
||||
|
||||
// MatchesAnnotationSelector implements ifc.Kunstructured.
|
||||
func (wn *WNode) MatchesAnnotationSelector(string) (bool, error) {
|
||||
panic("TODO(#WNode) MatchesAnnotationSelector; implement or drop from API")
|
||||
}
|
||||
|
||||
// MatchesLabelSelector implements ifc.Kunstructured.
|
||||
func (wn *WNode) MatchesLabelSelector(string) (bool, error) {
|
||||
panic("TODO(#WNode) MatchesLabelSelector; implement or drop from API")
|
||||
}
|
||||
|
||||
// SetAnnotations implements ifc.Kunstructured.
|
||||
func (wn *WNode) SetAnnotations(map[string]string) {
|
||||
panic("TODO(#WNode) SetAnnotations; implement or drop from API")
|
||||
}
|
||||
|
||||
// SetGvk implements ifc.Kunstructured.
|
||||
func (wn *WNode) SetGvk(resid.Gvk) {
|
||||
panic("TODO(#WNode) SetGvk; implement or drop from API")
|
||||
}
|
||||
|
||||
// SetLabels implements ifc.Kunstructured.
|
||||
func (wn *WNode) SetLabels(map[string]string) {
|
||||
panic("TODO(#WNode) SetLabels; implement or drop from API")
|
||||
}
|
||||
|
||||
// SetName implements ifc.Kunstructured.
|
||||
func (wn *WNode) SetName(string) {
|
||||
panic("TODO(#WNode) SetName; implement or drop from API")
|
||||
}
|
||||
|
||||
// SetNamespace implements ifc.Kunstructured.
|
||||
func (wn *WNode) SetNamespace(string) {
|
||||
panic("TODO(#WNode) SetNamespace; implement or drop from API")
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements ifc.Kunstructured.
|
||||
func (wn *WNode) UnmarshalJSON(data []byte) error {
|
||||
return wn.node.UnmarshalJSON(data)
|
||||
}
|
||||
339
api/internal/wrappy/wnode_test.go
Normal file
339
api/internal/wrappy/wnode_test.go
Normal file
@@ -0,0 +1,339 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package wrappy_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
. "sigs.k8s.io/kustomize/api/internal/wrappy"
|
||||
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
const (
|
||||
deploymentLittleJson = `{"apiVersion":"apps/v1","kind":"Deployment",` +
|
||||
`"metadata":{"name":"homer","namespace":"simpsons"}}`
|
||||
|
||||
deploymentBiggerJson = `
|
||||
{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": {
|
||||
"name": "homer",
|
||||
"namespace": "simpsons",
|
||||
"labels": {
|
||||
"fruit": "apple",
|
||||
"veggie": "carrot"
|
||||
},
|
||||
"annotations": {
|
||||
"area": "51",
|
||||
"greeting": "Take me to your leader."
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
bigMapYaml = `Kind: Service
|
||||
complextree:
|
||||
- field1:
|
||||
- boolfield: true
|
||||
floatsubfield: 1.01
|
||||
intsubfield: 1010
|
||||
stringsubfield: idx1010
|
||||
- boolfield: false
|
||||
floatsubfield: 1.011
|
||||
intsubfield: 1011
|
||||
stringsubfield: idx1011
|
||||
field2:
|
||||
- boolfield: true
|
||||
floatsubfield: 1.02
|
||||
intsubfield: 1020
|
||||
stringsubfield: idx1020
|
||||
- boolfield: false
|
||||
floatsubfield: 1.021
|
||||
intsubfield: 1021
|
||||
stringsubfield: idx1021
|
||||
- field1:
|
||||
- boolfield: true
|
||||
floatsubfield: 1.11
|
||||
intsubfield: 1110
|
||||
stringsubfield: idx1110
|
||||
- boolfield: false
|
||||
floatsubfield: 1.111
|
||||
intsubfield: 1111
|
||||
stringsubfield: idx1111
|
||||
field2:
|
||||
- boolfield: true
|
||||
floatsubfield: 1.112
|
||||
intsubfield: 1120
|
||||
stringsubfield: idx1120
|
||||
- boolfield: false
|
||||
floatsubfield: 1.1121
|
||||
intsubfield: 1121
|
||||
stringsubfield: idx1121
|
||||
metadata:
|
||||
labels:
|
||||
app: application-name
|
||||
name: service-name
|
||||
spec:
|
||||
ports:
|
||||
port: 80
|
||||
that:
|
||||
- idx0
|
||||
- idx1
|
||||
- idx2
|
||||
- idx3
|
||||
these:
|
||||
- field1:
|
||||
- idx010
|
||||
- idx011
|
||||
field2:
|
||||
- idx020
|
||||
- idx021
|
||||
- field1:
|
||||
- idx110
|
||||
- idx111
|
||||
field2:
|
||||
- idx120
|
||||
- idx121
|
||||
- field1:
|
||||
- idx210
|
||||
- idx211
|
||||
field2:
|
||||
- idx220
|
||||
- idx221
|
||||
this:
|
||||
is:
|
||||
aBool: true
|
||||
aFloat: 1.001
|
||||
aNilValue: null
|
||||
aNumber: 1000
|
||||
anEmptyMap: {}
|
||||
anEmptySlice: []
|
||||
those:
|
||||
- field1: idx0foo
|
||||
field2: idx0bar
|
||||
- field1: idx1foo
|
||||
field2: idx1bar
|
||||
- field1: idx2foo
|
||||
field2: idx2bar
|
||||
`
|
||||
)
|
||||
|
||||
func makeBigMap() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"Kind": "Service",
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]interface{}{
|
||||
"app": "application-name",
|
||||
},
|
||||
"name": "service-name",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"ports": map[string]interface{}{
|
||||
"port": int64(80),
|
||||
},
|
||||
},
|
||||
"this": map[string]interface{}{
|
||||
"is": map[string]interface{}{
|
||||
"aNumber": int64(1000),
|
||||
"aFloat": float64(1.001),
|
||||
"aNilValue": nil,
|
||||
"aBool": true,
|
||||
"anEmptyMap": map[string]interface{}{},
|
||||
"anEmptySlice": []interface{}{},
|
||||
/*
|
||||
TODO: test for unrecognizable (e.g. a function)
|
||||
"unrecognizable": testing.InternalExample{
|
||||
Name: "fooBar",
|
||||
},
|
||||
*/
|
||||
},
|
||||
},
|
||||
"that": []interface{}{
|
||||
"idx0",
|
||||
"idx1",
|
||||
"idx2",
|
||||
"idx3",
|
||||
},
|
||||
"those": []interface{}{
|
||||
map[string]interface{}{
|
||||
"field1": "idx0foo",
|
||||
"field2": "idx0bar",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"field1": "idx1foo",
|
||||
"field2": "idx1bar",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"field1": "idx2foo",
|
||||
"field2": "idx2bar",
|
||||
},
|
||||
},
|
||||
"these": []interface{}{
|
||||
map[string]interface{}{
|
||||
"field1": []interface{}{"idx010", "idx011"},
|
||||
"field2": []interface{}{"idx020", "idx021"},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"field1": []interface{}{"idx110", "idx111"},
|
||||
"field2": []interface{}{"idx120", "idx121"},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"field1": []interface{}{"idx210", "idx211"},
|
||||
"field2": []interface{}{"idx220", "idx221"},
|
||||
},
|
||||
},
|
||||
"complextree": []interface{}{
|
||||
map[string]interface{}{
|
||||
"field1": []interface{}{
|
||||
map[string]interface{}{
|
||||
"stringsubfield": "idx1010",
|
||||
"intsubfield": int64(1010),
|
||||
"floatsubfield": float64(1.010),
|
||||
"boolfield": true,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"stringsubfield": "idx1011",
|
||||
"intsubfield": int64(1011),
|
||||
"floatsubfield": float64(1.011),
|
||||
"boolfield": false,
|
||||
},
|
||||
},
|
||||
"field2": []interface{}{
|
||||
map[string]interface{}{
|
||||
"stringsubfield": "idx1020",
|
||||
"intsubfield": int64(1020),
|
||||
"floatsubfield": float64(1.020),
|
||||
"boolfield": true,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"stringsubfield": "idx1021",
|
||||
"intsubfield": int64(1021),
|
||||
"floatsubfield": float64(1.021),
|
||||
"boolfield": false,
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"field1": []interface{}{
|
||||
map[string]interface{}{
|
||||
"stringsubfield": "idx1110",
|
||||
"intsubfield": int64(1110),
|
||||
"floatsubfield": float64(1.110),
|
||||
"boolfield": true,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"stringsubfield": "idx1111",
|
||||
"intsubfield": int64(1111),
|
||||
"floatsubfield": float64(1.111),
|
||||
"boolfield": false,
|
||||
},
|
||||
},
|
||||
"field2": []interface{}{
|
||||
map[string]interface{}{
|
||||
"stringsubfield": "idx1120",
|
||||
"intsubfield": int64(1120),
|
||||
"floatsubfield": float64(1.1120),
|
||||
"boolfield": true,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"stringsubfield": "idx1121",
|
||||
"intsubfield": int64(1121),
|
||||
"floatsubfield": float64(1.1121),
|
||||
"boolfield": false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestBasicYamlOperationFromMap(t *testing.T) {
|
||||
bytes, err := yaml.Marshal(makeBigMap())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected yaml.Marshal err: %v", err)
|
||||
}
|
||||
if string(bytes) != bigMapYaml {
|
||||
t.Fatalf("unexpected string equality")
|
||||
}
|
||||
rNode, err := kyaml.Parse(string(bytes))
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected yaml.Marshal err: %v", err)
|
||||
}
|
||||
rNodeString := rNode.MustString()
|
||||
// The result from MustString has more indentation
|
||||
// than bigMapYaml.
|
||||
rNodeStrings := strings.Split(rNodeString, "\n")
|
||||
bigMapStrings := strings.Split(bigMapYaml, "\n")
|
||||
if len(rNodeStrings) != len(bigMapStrings) {
|
||||
t.Fatalf("line count mismatch")
|
||||
}
|
||||
for i := range rNodeStrings {
|
||||
s1 := strings.TrimSpace(rNodeStrings[i])
|
||||
s2 := strings.TrimSpace(bigMapStrings[i])
|
||||
if s1 != s2 {
|
||||
t.Fatalf("expected '%s'=='%s'", s1, s2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoundTripJSON(t *testing.T) {
|
||||
wn := NewWNode()
|
||||
err := wn.UnmarshalJSON([]byte(deploymentLittleJson))
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected UnmarshalJSON err: %v", err)
|
||||
}
|
||||
data, err := wn.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected MarshalJSON err: %v", err)
|
||||
}
|
||||
actual := string(data)
|
||||
if actual != deploymentLittleJson {
|
||||
t.Fatalf("expected %s, got %s", deploymentLittleJson, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGettingFields(t *testing.T) {
|
||||
wn := NewWNode()
|
||||
err := wn.UnmarshalJSON([]byte(deploymentBiggerJson))
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected unmarshaljson err: %v", err)
|
||||
}
|
||||
gvk := wn.GetGvk()
|
||||
expected := "apps"
|
||||
actual := gvk.Group
|
||||
if expected != actual {
|
||||
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
||||
}
|
||||
expected = "v1"
|
||||
actual = gvk.Version
|
||||
if expected != actual {
|
||||
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
||||
}
|
||||
expected = "Deployment"
|
||||
actual = gvk.Kind
|
||||
if expected != actual {
|
||||
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
||||
}
|
||||
actual = wn.GetKind()
|
||||
if expected != actual {
|
||||
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
||||
}
|
||||
expected = "homer"
|
||||
actual = wn.GetName()
|
||||
if expected != actual {
|
||||
t.Fatalf("expected '%s', got '%s'", expected, actual)
|
||||
}
|
||||
actualMap := wn.GetLabels()
|
||||
v, ok := actualMap["fruit"]
|
||||
if !ok || v != "apple" {
|
||||
t.Fatalf("unexpected labels '%v'", actualMap)
|
||||
}
|
||||
actualMap = wn.GetAnnotations()
|
||||
v, ok = actualMap["greeting"]
|
||||
if !ok || v != "Take me to your leader." {
|
||||
t.Fatalf("unexpected annotations '%v'", actualMap)
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,11 @@ import (
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
// KunstructuredFactoryImpl hides construction using apimachinery types.
|
||||
// KunstructuredFactoryImpl makes instances of UnstructAdapter.
|
||||
// These instances in turn adapt structs in
|
||||
// k8s.io/apimachinery/pkg/apis/meta/v1/unstructured
|
||||
// to implement ifc.Kunstructured.
|
||||
// This factory is meant to implement ifc.KunstructuredFactory.
|
||||
type KunstructuredFactoryImpl struct {
|
||||
hasher *kustHash
|
||||
}
|
||||
|
||||
@@ -14,11 +14,14 @@ import (
|
||||
v1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
)
|
||||
|
||||
// KustValidator validates Labels and annotations by apimachinery
|
||||
type KustValidator struct{}
|
||||
|
||||
var _ ifc.Validator = (*KustValidator)(nil)
|
||||
|
||||
// NewKustValidator returns a KustValidator object
|
||||
func NewKustValidator() *KustValidator {
|
||||
return &KustValidator{}
|
||||
183
api/krusty/internal/provider/depprovider.go
Normal file
183
api/krusty/internal/provider/depprovider.go
Normal file
@@ -0,0 +1,183 @@
|
||||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package provider
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/internal/k8sdeps/merge"
|
||||
kmerge "sigs.k8s.io/kustomize/api/internal/merge"
|
||||
"sigs.k8s.io/kustomize/api/internal/validate"
|
||||
"sigs.k8s.io/kustomize/api/internal/wrappy"
|
||||
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
|
||||
"sigs.k8s.io/kustomize/api/k8sdeps/validator"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
)
|
||||
|
||||
// DepProvider is a dependency provider.
|
||||
//
|
||||
// The instances it returns are either
|
||||
// - old implementations backed by k8sdeps code,
|
||||
// - new implementations backed by kyaml code.
|
||||
//
|
||||
// History:
|
||||
//
|
||||
// kubectl depends on k8s.io code, and at the time of writing, so
|
||||
// does kustomize. Code that imports k8s.io/api* cannot be imported
|
||||
// back into k8s.io/*, yet kustomize appears inside k8s.io/kubectl.
|
||||
//
|
||||
// To allow kustomize to appear inside kubectl, yet still be developed
|
||||
// outside kubectl, the kustomize code was divided into the following
|
||||
// packages
|
||||
//
|
||||
// api/
|
||||
// k8sdeps/ (and internal/ks8deps/)
|
||||
// ifc/
|
||||
// krusty/
|
||||
// everythingElse/
|
||||
//
|
||||
// with the following rules:
|
||||
//
|
||||
// - Only k8sdeps/ may import k8s.io/api*.
|
||||
//
|
||||
// - Only krusty/ (and its internals) may import k8sdeps/.
|
||||
// I.e., ifc/ and everythingElse/ must not
|
||||
// import k8sdeps/ or k8s.io/api*.
|
||||
//
|
||||
// - Code in krusty/ may use code in k8sdeps/ to create
|
||||
// objects then inject said objects into
|
||||
// everythingElse/ behind dependency neutral interfaces.
|
||||
//
|
||||
// The idea was to periodically copy, not import, the large k8sdeps/
|
||||
// tree (plus a snippet from krusty/kustomizer.go) into the kubectl
|
||||
// codebase via a large PR, and have kubectl depend on the rest via
|
||||
// normal importing.
|
||||
//
|
||||
// Over 2019, however, kubectl underwent large changes including
|
||||
// a switch to Go modules, and a concerted attempt to extract kubectl
|
||||
// from the k8s repo. This made large kustomize integration PRs too
|
||||
// intrusive to review.
|
||||
//
|
||||
// In 2020, kubectl is based on Go modules, and almost entirely
|
||||
// extracted from the k8s.io repositories, and further the kyaml
|
||||
// library has a appeared as a viable replacement to k8s.io/api*
|
||||
// KRM manipulation code.
|
||||
//
|
||||
// The new plan is to eliminate k8sdeps/ entirely, along with its
|
||||
// k8s.io/api* dependence, allowing kustomize code to be imported
|
||||
// into kubectl via normal Go module imports. Then the kustomize API
|
||||
// code can then move into the github.com/kubernetes-sigs/cli-utils
|
||||
// repo. The kustomize CLI in github.com/kubernetes-sigs/kustomize
|
||||
// and the kubectl CLI can then both depend on the kustomize API.
|
||||
//
|
||||
// So, all code that depends on k8sdeps must go behind interfaces,
|
||||
// and kustomize must be factored to choose the implementation.
|
||||
//
|
||||
// That problem has been reduced to three interfaces, each having
|
||||
// two implementations. (1) is k8sdeps-based, (2) is kyaml-based.
|
||||
//
|
||||
// - ifc.Kunstructured
|
||||
//
|
||||
// 1) api/k8sdeps/kunstruct.UnstructAdapter
|
||||
//
|
||||
// This adapts structs in
|
||||
// k8s.io/apimachinery/pkg/apis/meta/v1/unstructured
|
||||
// to ifc.Kunstructured.
|
||||
//
|
||||
// 2) api/wrappy.WNode
|
||||
//
|
||||
// This adapts sigs.k8s.io/kustomize/kyaml/yaml.RNode
|
||||
// to ifc.Unstructured.
|
||||
//
|
||||
// At time of writing, implementation started.
|
||||
// Further reducing the size of ifc.Kunstructed
|
||||
// would really reduce the work
|
||||
// (e.g. drop Vars, drop ReplacementTranformer).
|
||||
//
|
||||
// - resmap.Merginator
|
||||
//
|
||||
// 1) api/internal/k8sdeps/merge.Merginator
|
||||
//
|
||||
// Uses k8s.io/apimachinery/pkg/util/strategicpatch,
|
||||
// apimachinery/pkg/util/mergepatch, etc. to merge
|
||||
// resource.Resource instances.
|
||||
//
|
||||
// 2) api/internal/merge.Merginator
|
||||
//
|
||||
// At time of writing, this is unimplemented.
|
||||
//
|
||||
// - ifc.Validator
|
||||
//
|
||||
// 1) api/k8sdeps/validator.KustValidator
|
||||
//
|
||||
// Uses k8s.io/apimachinery/pkg/api/validation and
|
||||
// friends to validate strings.
|
||||
//
|
||||
// 2) api/internal/validate.FieldValidator
|
||||
//
|
||||
// At time of writing, this is a do-nothing
|
||||
// validator as it's not critical to kustomize function.
|
||||
//
|
||||
// Proposed plan:
|
||||
// [ ] Ship kustomize with the ability to switch from 1 to 2 via
|
||||
// an --enable_kyaml flag.
|
||||
// [ ] Make --enable_kyaml true by default.
|
||||
// [ ] When 2 is not noticeably more buggy than 1, delete 1.
|
||||
// I.e. delete k8sdeps/, transitively deleting all k8s.io/api* deps.
|
||||
// This DepProvider should be left in place to retain these
|
||||
// comments, but it will have only one choice.
|
||||
// [ ] The way is now clear to reintegrate into kubectl.
|
||||
// This should be done ASAP; the last step is cleanup.
|
||||
// [ ] With only one impl of Kunstructure remaining, that interface
|
||||
// and WNode can be deleted, along with this DepProvider.
|
||||
// The other two interfaces could be dropped too.
|
||||
//
|
||||
// When the above is done, kustomize will use yaml.RNode and/or
|
||||
// KRM Config Functions directly and exclusively.
|
||||
// If you're reading this, plan not done.
|
||||
//
|
||||
type DepProvider struct {
|
||||
resourceFactory *resource.Factory
|
||||
merginator resmap.Merginator
|
||||
fieldValidator ifc.Validator
|
||||
}
|
||||
|
||||
func makeK8sdepBasedInstances() *DepProvider {
|
||||
kf := kunstruct.NewKunstructuredFactoryImpl()
|
||||
rf := resource.NewFactory(kf)
|
||||
return &DepProvider{
|
||||
resourceFactory: rf,
|
||||
merginator: merge.NewMerginator(rf),
|
||||
fieldValidator: validator.NewKustValidator(),
|
||||
}
|
||||
}
|
||||
|
||||
func makeKyamlBasedInstances() *DepProvider {
|
||||
kf := &wrappy.WNodeFactory{}
|
||||
rf := resource.NewFactory(kf)
|
||||
return &DepProvider{
|
||||
resourceFactory: rf,
|
||||
merginator: kmerge.NewMerginator(rf),
|
||||
fieldValidator: validate.NewFieldValidator(),
|
||||
}
|
||||
}
|
||||
|
||||
func NewDepProvider(useKyaml bool) *DepProvider {
|
||||
if useKyaml {
|
||||
return makeKyamlBasedInstances()
|
||||
}
|
||||
return makeK8sdepBasedInstances()
|
||||
}
|
||||
|
||||
func (dp *DepProvider) GetResourceFactory() *resource.Factory {
|
||||
return dp.resourceFactory
|
||||
}
|
||||
|
||||
func (dp *DepProvider) GetMerginator() resmap.Merginator {
|
||||
return dp.merginator
|
||||
}
|
||||
|
||||
func (dp *DepProvider) GetFieldValidator() ifc.Validator {
|
||||
return dp.fieldValidator
|
||||
}
|
||||
@@ -8,16 +8,13 @@ import (
|
||||
|
||||
"sigs.k8s.io/kustomize/api/builtins"
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
"sigs.k8s.io/kustomize/api/internal/k8sdeps/merge"
|
||||
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||
"sigs.k8s.io/kustomize/api/internal/target"
|
||||
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
|
||||
"sigs.k8s.io/kustomize/api/k8sdeps/validator"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
"sigs.k8s.io/kustomize/api/krusty/internal/provider"
|
||||
fLdr "sigs.k8s.io/kustomize/api/loader"
|
||||
"sigs.k8s.io/kustomize/api/provenance"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
@@ -28,13 +25,18 @@ import (
|
||||
// number of overlays and bases), then make a Kustomizer
|
||||
// injected with the given fileystem, then call Run.
|
||||
type Kustomizer struct {
|
||||
fSys filesys.FileSystem
|
||||
options *Options
|
||||
fSys filesys.FileSystem
|
||||
options *Options
|
||||
depProvider *provider.DepProvider
|
||||
}
|
||||
|
||||
// MakeKustomizer returns an instance of Kustomizer.
|
||||
func MakeKustomizer(fSys filesys.FileSystem, o *Options) *Kustomizer {
|
||||
return &Kustomizer{fSys: fSys, options: o}
|
||||
return &Kustomizer{
|
||||
fSys: fSys,
|
||||
options: o,
|
||||
depProvider: provider.NewDepProvider(o.UseKyaml),
|
||||
}
|
||||
}
|
||||
|
||||
// Run performs a kustomization.
|
||||
@@ -49,11 +51,9 @@ func MakeKustomizer(fSys filesys.FileSystem, o *Options) *Kustomizer {
|
||||
// on any number of internal paths (e.g. the filesystem may contain
|
||||
// multiple overlays, and Run can be called on each of them).
|
||||
func (b *Kustomizer) Run(path string) (resmap.ResMap, error) {
|
||||
resourceFactory := resource.NewFactory(
|
||||
kunstruct.NewKunstructuredFactoryImpl())
|
||||
resmapFactory := resmap.NewFactory(
|
||||
resourceFactory,
|
||||
merge.NewMerginator(resourceFactory))
|
||||
b.depProvider.GetResourceFactory(),
|
||||
b.depProvider.GetMerginator())
|
||||
lr := fLdr.RestrictionNone
|
||||
if b.options.LoadRestrictions == types.LoadRestrictionsRootOnly {
|
||||
lr = fLdr.RestrictionRootOnly
|
||||
@@ -65,7 +65,7 @@ func (b *Kustomizer) Run(path string) (resmap.ResMap, error) {
|
||||
defer ldr.Cleanup()
|
||||
kt := target.NewKustTarget(
|
||||
ldr,
|
||||
validator.NewKustValidator(),
|
||||
b.depProvider.GetFieldValidator(),
|
||||
resmapFactory,
|
||||
pLdr.NewLoader(b.options.PluginConfig, resmapFactory),
|
||||
)
|
||||
|
||||
@@ -104,10 +104,10 @@ spec:
|
||||
- valueFrom:
|
||||
configMapKeyRef:
|
||||
key: MYSQL_DATABASE
|
||||
name: mysql
|
||||
name: mysql-9792mdchtg
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: mysql
|
||||
name: mysql-9792mdchtg
|
||||
name: handler
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -32,14 +32,20 @@ type Options struct {
|
||||
|
||||
// Options related to kustomize plugins.
|
||||
PluginConfig *types.PluginConfig
|
||||
|
||||
// When true, use kyaml/ packages to manipulate KRM yaml.
|
||||
// When false, use k8sdeps/ instead (uses k8s.io/api* packages).
|
||||
UseKyaml bool
|
||||
}
|
||||
|
||||
// MakeDefaultOptions returns a default instance of Options.
|
||||
func MakeDefaultOptions() *Options {
|
||||
return &Options{
|
||||
DoLegacyResourceSort: true,
|
||||
DoLegacyResourceSort: false,
|
||||
AddManagedbyLabel: false,
|
||||
LoadRestrictions: types.LoadRestrictionsRootOnly,
|
||||
DoPrune: false,
|
||||
PluginConfig: konfig.DisabledPluginConfig(),
|
||||
UseKyaml: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,19 @@ import (
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
// Merginator merges resources.
|
||||
type Merginator interface {
|
||||
// Merge creates a new ResMap by merging incoming resources.
|
||||
// Error if conflict found.
|
||||
Merge([]*resource.Resource) (ResMap, error)
|
||||
}
|
||||
|
||||
// Factory makes instances of ResMap.
|
||||
type Factory struct {
|
||||
// Makes resources.
|
||||
resF *resource.Factory
|
||||
pm Merginator
|
||||
// Makes ResMaps via merging.
|
||||
pm Merginator
|
||||
}
|
||||
|
||||
// NewFactory returns a new resmap.Factory.
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resmap
|
||||
|
||||
import "sigs.k8s.io/kustomize/api/resource"
|
||||
|
||||
// Merginator merges resources.
|
||||
type Merginator interface {
|
||||
// Merge creates a new ResMap by merging incoming resources.
|
||||
// Error if conflict found.
|
||||
Merge([]*resource.Resource) (ResMap, error)
|
||||
}
|
||||
@@ -6,16 +6,10 @@
|
||||
package resmap
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// A Transformer modifies an instance of ResMap.
|
||||
@@ -242,569 +236,3 @@ type ResMap interface {
|
||||
// are selected by a Selector
|
||||
Select(types.Selector) ([]*resource.Resource, error)
|
||||
}
|
||||
|
||||
// resWrangler holds the content manipulated by kustomize.
|
||||
type resWrangler struct {
|
||||
// Resource list maintained in load (append) order.
|
||||
// This is important for transformers, which must
|
||||
// be performed in a specific order, and for users
|
||||
// who for whatever reasons wish the order they
|
||||
// specify in kustomizations to be maintained and
|
||||
// available as an option for final YAML rendering.
|
||||
rList []*resource.Resource
|
||||
}
|
||||
|
||||
func newOne() *resWrangler {
|
||||
result := &resWrangler{}
|
||||
result.Clear()
|
||||
return result
|
||||
}
|
||||
|
||||
// Clear implements ResMap.
|
||||
func (m *resWrangler) Clear() {
|
||||
m.rList = nil
|
||||
}
|
||||
|
||||
// Size implements ResMap.
|
||||
func (m *resWrangler) Size() int {
|
||||
return len(m.rList)
|
||||
}
|
||||
|
||||
func (m *resWrangler) indexOfResource(other *resource.Resource) int {
|
||||
for i, r := range m.rList {
|
||||
if r == other {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Resources implements ResMap.
|
||||
func (m *resWrangler) Resources() []*resource.Resource {
|
||||
tmp := make([]*resource.Resource, len(m.rList))
|
||||
copy(tmp, m.rList)
|
||||
return tmp
|
||||
}
|
||||
|
||||
// Append implements ResMap.
|
||||
func (m *resWrangler) Append(res *resource.Resource) error {
|
||||
id := res.CurId()
|
||||
if r := m.GetMatchingResourcesByCurrentId(id.Equals); len(r) > 0 {
|
||||
return fmt.Errorf(
|
||||
"may not add resource with an already registered id: %s", id)
|
||||
}
|
||||
m.rList = append(m.rList, res)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove implements ResMap.
|
||||
func (m *resWrangler) Remove(adios resid.ResId) error {
|
||||
tmp := newOne()
|
||||
for _, r := range m.rList {
|
||||
if r.CurId() != adios {
|
||||
tmp.Append(r)
|
||||
}
|
||||
}
|
||||
if tmp.Size() != m.Size()-1 {
|
||||
return fmt.Errorf("id %s not found in removal", adios)
|
||||
}
|
||||
m.rList = tmp.rList
|
||||
return nil
|
||||
}
|
||||
|
||||
// Replace implements ResMap.
|
||||
func (m *resWrangler) Replace(res *resource.Resource) (int, error) {
|
||||
id := res.CurId()
|
||||
i, err := m.GetIndexOfCurrentId(id)
|
||||
if err != nil {
|
||||
return -1, errors.Wrap(err, "in Replace")
|
||||
}
|
||||
if i < 0 {
|
||||
return -1, fmt.Errorf("cannot find resource with id %s to replace", id)
|
||||
}
|
||||
m.rList[i] = res
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// AllIds implements ResMap.
|
||||
func (m *resWrangler) AllIds() (ids []resid.ResId) {
|
||||
ids = make([]resid.ResId, m.Size())
|
||||
for i, r := range m.rList {
|
||||
ids[i] = r.CurId()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Debug implements ResMap.
|
||||
func (m *resWrangler) Debug(title string) {
|
||||
fmt.Println("--------------------------- " + title)
|
||||
firstObj := true
|
||||
for i, r := range m.rList {
|
||||
if firstObj {
|
||||
firstObj = false
|
||||
} else {
|
||||
fmt.Println("---")
|
||||
}
|
||||
fmt.Printf("# %d %s\n", i, r.OrgId())
|
||||
blob, err := yaml.Marshal(r.Map())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(string(blob))
|
||||
}
|
||||
}
|
||||
|
||||
type IdMatcher func(resid.ResId) bool
|
||||
|
||||
// GetByIndex implements ResMap.
|
||||
func (m *resWrangler) GetByIndex(i int) *resource.Resource {
|
||||
if i < 0 || i >= m.Size() {
|
||||
return nil
|
||||
}
|
||||
return m.rList[i]
|
||||
}
|
||||
|
||||
// GetIndexOfCurrentId implements ResMap.
|
||||
func (m *resWrangler) GetIndexOfCurrentId(id resid.ResId) (int, error) {
|
||||
count := 0
|
||||
result := -1
|
||||
for i, r := range m.rList {
|
||||
if id.Equals(r.CurId()) {
|
||||
count++
|
||||
result = i
|
||||
}
|
||||
}
|
||||
if count > 1 {
|
||||
return -1, fmt.Errorf("id matched %d resources", count)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type IdFromResource func(r *resource.Resource) resid.ResId
|
||||
|
||||
func GetOriginalId(r *resource.Resource) resid.ResId { return r.OrgId() }
|
||||
func GetCurrentId(r *resource.Resource) resid.ResId { return r.CurId() }
|
||||
|
||||
// GetMatchingResourcesByCurrentId implements ResMap.
|
||||
func (m *resWrangler) GetMatchingResourcesByCurrentId(
|
||||
matches IdMatcher) []*resource.Resource {
|
||||
return m.filteredById(matches, GetCurrentId)
|
||||
}
|
||||
|
||||
// GetMatchingResourcesByOriginalId implements ResMap.
|
||||
func (m *resWrangler) GetMatchingResourcesByOriginalId(
|
||||
matches IdMatcher) []*resource.Resource {
|
||||
return m.filteredById(matches, GetOriginalId)
|
||||
}
|
||||
|
||||
func (m *resWrangler) filteredById(
|
||||
matches IdMatcher, idGetter IdFromResource) []*resource.Resource {
|
||||
var result []*resource.Resource
|
||||
for _, r := range m.rList {
|
||||
if matches(idGetter(r)) {
|
||||
result = append(result, r)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// GetByCurrentId implements ResMap.
|
||||
func (m *resWrangler) GetByCurrentId(
|
||||
id resid.ResId) (*resource.Resource, error) {
|
||||
return demandOneMatch(m.GetMatchingResourcesByCurrentId, id, "Current")
|
||||
}
|
||||
|
||||
// GetByOriginalId implements ResMap.
|
||||
func (m *resWrangler) GetByOriginalId(
|
||||
id resid.ResId) (*resource.Resource, error) {
|
||||
return demandOneMatch(m.GetMatchingResourcesByOriginalId, id, "Original")
|
||||
}
|
||||
|
||||
// GetById implements ResMap.
|
||||
func (m *resWrangler) GetById(
|
||||
id resid.ResId) (*resource.Resource, error) {
|
||||
match, err1 := m.GetByOriginalId(id)
|
||||
if err1 == nil {
|
||||
return match, nil
|
||||
}
|
||||
match, err2 := m.GetByCurrentId(id)
|
||||
if err2 == nil {
|
||||
return match, nil
|
||||
}
|
||||
return nil, fmt.Errorf(
|
||||
"%s; %s; failed to find unique target for patch %s",
|
||||
err1.Error(), err2.Error(), id.GvknString())
|
||||
}
|
||||
|
||||
type resFinder func(IdMatcher) []*resource.Resource
|
||||
|
||||
func demandOneMatch(
|
||||
f resFinder, id resid.ResId, s string) (*resource.Resource, error) {
|
||||
r := f(id.Equals)
|
||||
if len(r) == 1 {
|
||||
return r[0], nil
|
||||
}
|
||||
if len(r) > 1 {
|
||||
return nil, fmt.Errorf("multiple matches for %sId %s", s, id)
|
||||
}
|
||||
return nil, fmt.Errorf("no matches for %sId %s", s, id)
|
||||
}
|
||||
|
||||
// GroupedByCurrentNamespace implements ResMap.GroupByCurrentNamespace
|
||||
func (m *resWrangler) GroupedByCurrentNamespace() map[string][]*resource.Resource {
|
||||
items := m.groupedByCurrentNamespace()
|
||||
delete(items, resid.TotallyNotANamespace)
|
||||
return items
|
||||
}
|
||||
|
||||
// NonNamespaceable implements ResMap.NonNamespaceable
|
||||
func (m *resWrangler) NonNamespaceable() []*resource.Resource {
|
||||
return m.groupedByCurrentNamespace()[resid.TotallyNotANamespace]
|
||||
}
|
||||
|
||||
func (m *resWrangler) groupedByCurrentNamespace() map[string][]*resource.Resource {
|
||||
byNamespace := make(map[string][]*resource.Resource)
|
||||
for _, res := range m.rList {
|
||||
namespace := res.CurId().EffectiveNamespace()
|
||||
if _, found := byNamespace[namespace]; !found {
|
||||
byNamespace[namespace] = []*resource.Resource{}
|
||||
}
|
||||
byNamespace[namespace] = append(byNamespace[namespace], res)
|
||||
}
|
||||
return byNamespace
|
||||
}
|
||||
|
||||
// GroupedByNamespace implements ResMap.GroupByOrginalNamespace
|
||||
func (m *resWrangler) GroupedByOriginalNamespace() map[string][]*resource.Resource {
|
||||
items := m.groupedByOriginalNamespace()
|
||||
delete(items, resid.TotallyNotANamespace)
|
||||
return items
|
||||
}
|
||||
|
||||
func (m *resWrangler) groupedByOriginalNamespace() map[string][]*resource.Resource {
|
||||
byNamespace := make(map[string][]*resource.Resource)
|
||||
for _, res := range m.rList {
|
||||
namespace := res.OrgId().EffectiveNamespace()
|
||||
if _, found := byNamespace[namespace]; !found {
|
||||
byNamespace[namespace] = []*resource.Resource{}
|
||||
}
|
||||
byNamespace[namespace] = append(byNamespace[namespace], res)
|
||||
}
|
||||
return byNamespace
|
||||
}
|
||||
|
||||
// AsYaml implements ResMap.
|
||||
func (m *resWrangler) AsYaml() ([]byte, error) {
|
||||
firstObj := true
|
||||
var b []byte
|
||||
buf := bytes.NewBuffer(b)
|
||||
for _, res := range m.Resources() {
|
||||
out, err := yaml.Marshal(res.Map())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if firstObj {
|
||||
firstObj = false
|
||||
} else {
|
||||
if _, err = buf.WriteString("---\n"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if _, err = buf.Write(out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// ErrorIfNotEqualSets implements ResMap.
|
||||
func (m *resWrangler) ErrorIfNotEqualSets(other ResMap) error {
|
||||
m2, ok := other.(*resWrangler)
|
||||
if !ok {
|
||||
panic("bad cast")
|
||||
}
|
||||
if m.Size() != m2.Size() {
|
||||
return fmt.Errorf(
|
||||
"lists have different number of entries: %#v doesn't equal %#v",
|
||||
m.rList, m2.rList)
|
||||
}
|
||||
seen := make(map[int]bool)
|
||||
for _, r1 := range m.rList {
|
||||
id := r1.CurId()
|
||||
others := m2.GetMatchingResourcesByCurrentId(id.Equals)
|
||||
if len(others) == 0 {
|
||||
return fmt.Errorf(
|
||||
"id in self missing from other; id: %s", id)
|
||||
}
|
||||
if len(others) > 1 {
|
||||
return fmt.Errorf(
|
||||
"id in self matches %d in other; id: %s", len(others), id)
|
||||
}
|
||||
r2 := others[0]
|
||||
if !r1.KunstructEqual(r2) {
|
||||
return fmt.Errorf(
|
||||
"kunstruct not equal: \n -- %s,\n -- %s\n\n--\n%#v\n------\n%#v\n",
|
||||
r1, r2, r1, r2)
|
||||
}
|
||||
seen[m2.indexOfResource(r2)] = true
|
||||
}
|
||||
if len(seen) != m.Size() {
|
||||
return fmt.Errorf("counting problem %d != %d", len(seen), m.Size())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ErrorIfNotEqualList implements ResMap.
|
||||
func (m *resWrangler) ErrorIfNotEqualLists(other ResMap) error {
|
||||
m2, ok := other.(*resWrangler)
|
||||
if !ok {
|
||||
panic("bad cast")
|
||||
}
|
||||
if m.Size() != m2.Size() {
|
||||
return fmt.Errorf(
|
||||
"lists have different number of entries: %#v doesn't equal %#v",
|
||||
m.rList, m2.rList)
|
||||
}
|
||||
for i, r1 := range m.rList {
|
||||
r2 := m2.rList[i]
|
||||
if !r1.Equals(r2) {
|
||||
return fmt.Errorf(
|
||||
"Item i=%d differs:\n n1 = %s\n n2 = %s\n o1 = %s\n o2 = %s\n",
|
||||
i, r1.OrgId(), r2.OrgId(), r1, r2)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type resCopier func(r *resource.Resource) *resource.Resource
|
||||
|
||||
// ShallowCopy implements ResMap.
|
||||
func (m *resWrangler) ShallowCopy() ResMap {
|
||||
return m.makeCopy(
|
||||
func(r *resource.Resource) *resource.Resource {
|
||||
return r
|
||||
})
|
||||
}
|
||||
|
||||
// DeepCopy implements ResMap.
|
||||
func (m *resWrangler) DeepCopy() ResMap {
|
||||
return m.makeCopy(
|
||||
func(r *resource.Resource) *resource.Resource {
|
||||
return r.DeepCopy()
|
||||
})
|
||||
}
|
||||
|
||||
// makeCopy copies the ResMap.
|
||||
func (m *resWrangler) makeCopy(copier resCopier) ResMap {
|
||||
result := &resWrangler{}
|
||||
result.rList = make([]*resource.Resource, m.Size())
|
||||
for i, r := range m.rList {
|
||||
result.rList[i] = copier(r)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// SubsetThatCouldBeReferencedByResource implements ResMap.
|
||||
func (m *resWrangler) SubsetThatCouldBeReferencedByResource(
|
||||
inputRes *resource.Resource) ResMap {
|
||||
result := newOne()
|
||||
inputId := inputRes.CurId()
|
||||
isInputIdNamespaceable := inputId.IsNamespaceableKind()
|
||||
rctxm := inputRes.PrefixesSuffixesEquals
|
||||
subjectNamespaces := getNamespacesForRoleBinding(inputRes)
|
||||
for _, r := range m.Resources() {
|
||||
// Need to match more accuratly both at the time of selection and transformation.
|
||||
// OutmostPrefixSuffixEquals is not accurate enough since it is only using
|
||||
// the outer most suffix and the last prefix. Use PrefixedSuffixesEquals instead.
|
||||
resId := r.CurId()
|
||||
if (!isInputIdNamespaceable || !resId.IsNamespaceableKind() || resId.IsNsEquals(inputId) ||
|
||||
isRoleBindingNamespace(&subjectNamespaces, r.GetNamespace())) && r.InSameKustomizeCtx(rctxm) {
|
||||
result.append(r)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// isRoleBindingNamespace returns true is the namespace `ns` is in role binding
|
||||
// namespaces `m`
|
||||
func isRoleBindingNamespace(m *map[string]bool, ns string) bool {
|
||||
return (*m)[ns]
|
||||
}
|
||||
|
||||
// getNamespacesForRoleBinding returns referenced ServiceAccount namespaces if the inputRes is
|
||||
// a RoleBinding
|
||||
func getNamespacesForRoleBinding(inputRes *resource.Resource) map[string]bool {
|
||||
res := make(map[string]bool)
|
||||
if inputRes.GetKind() != "RoleBinding" {
|
||||
return res
|
||||
}
|
||||
subjects, err := inputRes.GetSlice("subjects")
|
||||
if err != nil || subjects == nil {
|
||||
return res
|
||||
}
|
||||
|
||||
for _, s := range subjects {
|
||||
subject := s.(map[string]interface{})
|
||||
if subject["namespace"] == nil || subject["kind"] == nil ||
|
||||
subject["kind"].(string) != "ServiceAccount" {
|
||||
continue
|
||||
}
|
||||
res[subject["namespace"].(string)] = true
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (m *resWrangler) append(res *resource.Resource) {
|
||||
m.rList = append(m.rList, res)
|
||||
}
|
||||
|
||||
// AppendAll implements ResMap.
|
||||
func (m *resWrangler) AppendAll(other ResMap) error {
|
||||
if other == nil {
|
||||
return nil
|
||||
}
|
||||
for _, res := range other.Resources() {
|
||||
if err := m.Append(res); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AbsorbAll implements ResMap.
|
||||
func (m *resWrangler) AbsorbAll(other ResMap) error {
|
||||
if other == nil {
|
||||
return nil
|
||||
}
|
||||
for _, r := range other.Resources() {
|
||||
err := m.appendReplaceOrMerge(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *resWrangler) appendReplaceOrMerge(
|
||||
res *resource.Resource) error {
|
||||
id := res.CurId()
|
||||
matches := m.GetMatchingResourcesByOriginalId(id.Equals)
|
||||
if len(matches) == 0 {
|
||||
matches = m.GetMatchingResourcesByCurrentId(id.Equals)
|
||||
}
|
||||
switch len(matches) {
|
||||
case 0:
|
||||
switch res.Behavior() {
|
||||
case types.BehaviorMerge, types.BehaviorReplace:
|
||||
return fmt.Errorf(
|
||||
"id %#v does not exist; cannot merge or replace", id)
|
||||
default:
|
||||
// presumably types.BehaviorCreate
|
||||
err := m.Append(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
old := matches[0]
|
||||
if old == nil {
|
||||
return fmt.Errorf("id lookup failure")
|
||||
}
|
||||
index := m.indexOfResource(old)
|
||||
if index < 0 {
|
||||
return fmt.Errorf("indexing problem")
|
||||
}
|
||||
switch res.Behavior() {
|
||||
case types.BehaviorReplace:
|
||||
res.Replace(old)
|
||||
case types.BehaviorMerge:
|
||||
res.Merge(old)
|
||||
default:
|
||||
return fmt.Errorf(
|
||||
"id %#v exists; behavior must be merge or replace", id)
|
||||
}
|
||||
i, err := m.Replace(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i != index {
|
||||
return fmt.Errorf("unexpected index in replacement")
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf(
|
||||
"found multiple objects %v that could accept merge of %v",
|
||||
matches, id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func anchorRegex(pattern string) string {
|
||||
if pattern == "" {
|
||||
return pattern
|
||||
}
|
||||
return "^" + pattern + "$"
|
||||
}
|
||||
|
||||
// Select returns a list of resources that
|
||||
// are selected by a Selector
|
||||
func (m *resWrangler) Select(s types.Selector) ([]*resource.Resource, error) {
|
||||
ns := regexp.MustCompile(anchorRegex(s.Namespace))
|
||||
nm := regexp.MustCompile(anchorRegex(s.Name))
|
||||
var result []*resource.Resource
|
||||
for _, r := range m.Resources() {
|
||||
curId := r.CurId()
|
||||
orgId := r.OrgId()
|
||||
|
||||
// matches the namespace when namespace is not empty in the selector
|
||||
// It first tries to match with the original namespace
|
||||
// then matches with the current namespace
|
||||
if r.GetNamespace() != "" {
|
||||
matched := ns.MatchString(orgId.EffectiveNamespace())
|
||||
if !matched {
|
||||
matched = ns.MatchString(curId.EffectiveNamespace())
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// matches the name when name is not empty in the selector
|
||||
// It first tries to match with the original name
|
||||
// then matches with the current name
|
||||
if r.GetName() != "" {
|
||||
matched := nm.MatchString(orgId.Name)
|
||||
if !matched {
|
||||
matched = nm.MatchString(curId.Name)
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// matches the GVK
|
||||
if !r.GetGvk().IsSelected(&s.Gvk) {
|
||||
continue
|
||||
}
|
||||
|
||||
// matches the label selector
|
||||
matched, err := r.MatchesLabelSelector(s.LabelSelector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
|
||||
// matches the annotation selector
|
||||
matched, err = r.MatchesAnnotationSelector(s.AnnotationSelector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
result = append(result, r)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -3,899 +3,4 @@
|
||||
|
||||
package resmap_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
. "sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
resmaptest_test "sigs.k8s.io/kustomize/api/testutils/resmaptest"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
var rf = resource.NewFactory(
|
||||
kunstruct.NewKunstructuredFactoryImpl())
|
||||
var rmF = NewFactory(rf, nil)
|
||||
|
||||
func doAppend(t *testing.T, w ResMap, r *resource.Resource) {
|
||||
err := w.Append(r)
|
||||
if err != nil {
|
||||
t.Fatalf("append error: %v", err)
|
||||
}
|
||||
}
|
||||
func doRemove(t *testing.T, w ResMap, id resid.ResId) {
|
||||
err := w.Remove(id)
|
||||
if err != nil {
|
||||
t.Fatalf("remove error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Make a resource with a predictable name.
|
||||
func makeCm(i int) *resource.Resource {
|
||||
return rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": fmt.Sprintf("cm%03d", i),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Maintain the class invariant that no two
|
||||
// resources can have the same CurId().
|
||||
func TestAppendRejectsDuplicateResId(t *testing.T) {
|
||||
w := New()
|
||||
if err := w.Append(makeCm(1)); err != nil {
|
||||
t.Fatalf("append error: %v", err)
|
||||
}
|
||||
err := w.Append(makeCm(1))
|
||||
if err == nil {
|
||||
t.Fatalf("expected append error")
|
||||
}
|
||||
if !strings.Contains(
|
||||
err.Error(),
|
||||
"may not add resource with an already registered id") {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendRemove(t *testing.T) {
|
||||
w1 := New()
|
||||
doAppend(t, w1, makeCm(1))
|
||||
doAppend(t, w1, makeCm(2))
|
||||
doAppend(t, w1, makeCm(3))
|
||||
doAppend(t, w1, makeCm(4))
|
||||
doAppend(t, w1, makeCm(5))
|
||||
doAppend(t, w1, makeCm(6))
|
||||
doAppend(t, w1, makeCm(7))
|
||||
doRemove(t, w1, makeCm(1).OrgId())
|
||||
doRemove(t, w1, makeCm(3).OrgId())
|
||||
doRemove(t, w1, makeCm(5).OrgId())
|
||||
doRemove(t, w1, makeCm(7).OrgId())
|
||||
|
||||
w2 := New()
|
||||
doAppend(t, w2, makeCm(2))
|
||||
doAppend(t, w2, makeCm(4))
|
||||
doAppend(t, w2, makeCm(6))
|
||||
if !reflect.DeepEqual(w1, w1) {
|
||||
w1.Debug("w1")
|
||||
w2.Debug("w2")
|
||||
t.Fatalf("mismatch")
|
||||
}
|
||||
|
||||
err := w2.Append(makeCm(6))
|
||||
if err == nil {
|
||||
t.Fatalf("expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemove(t *testing.T) {
|
||||
w := New()
|
||||
r := makeCm(1)
|
||||
err := w.Remove(r.OrgId())
|
||||
if err == nil {
|
||||
t.Fatalf("expected error")
|
||||
}
|
||||
err = w.Append(r)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
err = w.Remove(r.OrgId())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
err = w.Remove(r.OrgId())
|
||||
if err == nil {
|
||||
t.Fatalf("expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplace(t *testing.T) {
|
||||
cm5 := makeCm(5)
|
||||
cm700 := makeCm(700)
|
||||
otherCm5 := makeCm(5)
|
||||
|
||||
w := New()
|
||||
doAppend(t, w, makeCm(1))
|
||||
doAppend(t, w, makeCm(2))
|
||||
doAppend(t, w, makeCm(3))
|
||||
doAppend(t, w, makeCm(4))
|
||||
doAppend(t, w, cm5)
|
||||
doAppend(t, w, makeCm(6))
|
||||
doAppend(t, w, makeCm(7))
|
||||
|
||||
oldSize := w.Size()
|
||||
_, err := w.Replace(otherCm5)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if w.Size() != oldSize {
|
||||
t.Fatalf("unexpected size %d", w.Size())
|
||||
}
|
||||
if r, err := w.GetByCurrentId(cm5.OrgId()); err != nil || r != otherCm5 {
|
||||
t.Fatalf("unexpected result r=%s, err=%v", r.CurId(), err)
|
||||
}
|
||||
if err := w.Append(cm5); err == nil {
|
||||
t.Fatalf("expected id already there error")
|
||||
}
|
||||
if err := w.Remove(cm5.OrgId()); err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
if err := w.Append(cm700); err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
if err := w.Append(cm5); err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeAsYaml(t *testing.T) {
|
||||
encoded := []byte(`apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm2
|
||||
`)
|
||||
input := resmaptest_test.NewRmBuilder(t, rf).Add(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
},
|
||||
}).Add(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm2",
|
||||
},
|
||||
}).ResMap()
|
||||
out, err := input.AsYaml()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(out, encoded) {
|
||||
t.Fatalf("%s doesn't match expected %s", out, encoded)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMatchingResourcesByCurrentId(t *testing.T) {
|
||||
r1 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "alice",
|
||||
},
|
||||
})
|
||||
r2 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "bob",
|
||||
},
|
||||
})
|
||||
r3 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "bob",
|
||||
"namespace": "happy",
|
||||
},
|
||||
})
|
||||
r4 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "charlie",
|
||||
"namespace": "happy",
|
||||
},
|
||||
})
|
||||
r5 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "charlie",
|
||||
"namespace": "happy",
|
||||
},
|
||||
})
|
||||
|
||||
m := resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(r1).AddR(r2).AddR(r3).AddR(r4).AddR(r5).ResMap()
|
||||
|
||||
result := m.GetMatchingResourcesByCurrentId(
|
||||
resid.NewResId(cmap, "alice").GvknEquals)
|
||||
if len(result) != 1 {
|
||||
t.Fatalf("Expected single map entry but got %v", result)
|
||||
}
|
||||
result = m.GetMatchingResourcesByCurrentId(
|
||||
resid.NewResId(cmap, "bob").GvknEquals)
|
||||
if len(result) != 2 {
|
||||
t.Fatalf("Expected two, got %v", result)
|
||||
}
|
||||
result = m.GetMatchingResourcesByCurrentId(
|
||||
resid.NewResIdWithNamespace(cmap, "bob", "system").GvknEquals)
|
||||
if len(result) != 2 {
|
||||
t.Fatalf("Expected two but got %v", result)
|
||||
}
|
||||
result = m.GetMatchingResourcesByCurrentId(
|
||||
resid.NewResIdWithNamespace(cmap, "bob", "happy").Equals)
|
||||
if len(result) != 1 {
|
||||
t.Fatalf("Expected single map entry but got %v", result)
|
||||
}
|
||||
result = m.GetMatchingResourcesByCurrentId(
|
||||
resid.NewResId(cmap, "charlie").GvknEquals)
|
||||
if len(result) != 1 {
|
||||
t.Fatalf("Expected single map entry but got %v", result)
|
||||
}
|
||||
|
||||
// nolint:goconst
|
||||
tests := []struct {
|
||||
name string
|
||||
matcher IdMatcher
|
||||
count int
|
||||
}{
|
||||
{
|
||||
"match everything",
|
||||
func(resid.ResId) bool { return true },
|
||||
5,
|
||||
},
|
||||
{
|
||||
"match nothing",
|
||||
func(resid.ResId) bool { return false },
|
||||
0,
|
||||
},
|
||||
{
|
||||
"name is alice",
|
||||
func(x resid.ResId) bool { return x.Name == "alice" },
|
||||
1,
|
||||
},
|
||||
{
|
||||
"name is charlie",
|
||||
func(x resid.ResId) bool { return x.Name == "charlie" },
|
||||
2,
|
||||
},
|
||||
{
|
||||
"name is bob",
|
||||
func(x resid.ResId) bool { return x.Name == "bob" },
|
||||
2,
|
||||
},
|
||||
{
|
||||
"happy namespace",
|
||||
func(x resid.ResId) bool {
|
||||
return x.Namespace == "happy"
|
||||
},
|
||||
3,
|
||||
},
|
||||
{
|
||||
"happy deployment",
|
||||
func(x resid.ResId) bool {
|
||||
return x.Namespace == "happy" &&
|
||||
x.Gvk.Kind == "Deployment"
|
||||
},
|
||||
1,
|
||||
},
|
||||
{
|
||||
"happy ConfigMap",
|
||||
func(x resid.ResId) bool {
|
||||
return x.Namespace == "happy" &&
|
||||
x.Gvk.Kind == "ConfigMap"
|
||||
},
|
||||
2,
|
||||
},
|
||||
}
|
||||
for _, tst := range tests {
|
||||
result := m.GetMatchingResourcesByCurrentId(tst.matcher)
|
||||
if len(result) != tst.count {
|
||||
t.Fatalf("test '%s'; actual: %d, expected: %d",
|
||||
tst.name, len(result), tst.count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubsetThatCouldBeReferencedByResource(t *testing.T) {
|
||||
r1 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "alice",
|
||||
},
|
||||
})
|
||||
r2 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "bob",
|
||||
},
|
||||
})
|
||||
r3 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "bob",
|
||||
"namespace": "happy",
|
||||
},
|
||||
})
|
||||
r4 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "charlie",
|
||||
"namespace": "happy",
|
||||
},
|
||||
})
|
||||
r5 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "charlie",
|
||||
"namespace": "happy",
|
||||
},
|
||||
})
|
||||
r5.AddNamePrefix("little-")
|
||||
r6 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "domino",
|
||||
"namespace": "happy",
|
||||
},
|
||||
})
|
||||
r6.AddNamePrefix("little-")
|
||||
r7 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ClusterRoleBinding",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "meh",
|
||||
},
|
||||
})
|
||||
|
||||
tests := map[string]struct {
|
||||
filter *resource.Resource
|
||||
expected ResMap
|
||||
}{
|
||||
"default namespace 1": {
|
||||
filter: r2,
|
||||
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(r1).AddR(r2).AddR(r7).ResMap(),
|
||||
},
|
||||
"default namespace 2": {
|
||||
filter: r1,
|
||||
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(r1).AddR(r2).AddR(r7).ResMap(),
|
||||
},
|
||||
"happy namespace no prefix": {
|
||||
filter: r3,
|
||||
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(r3).AddR(r4).AddR(r5).AddR(r6).AddR(r7).ResMap(),
|
||||
},
|
||||
"happy namespace with prefix": {
|
||||
filter: r5,
|
||||
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(r3).AddR(r4).AddR(r5).AddR(r6).AddR(r7).ResMap(),
|
||||
},
|
||||
"cluster level": {
|
||||
filter: r7,
|
||||
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(r1).AddR(r2).AddR(r3).AddR(r4).AddR(r5).AddR(r6).AddR(r7).ResMap(),
|
||||
},
|
||||
}
|
||||
m := resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(r1).AddR(r2).AddR(r3).AddR(r4).AddR(r5).AddR(r6).AddR(r7).ResMap()
|
||||
for name, test := range tests {
|
||||
test := test
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got := m.SubsetThatCouldBeReferencedByResource(test.filter)
|
||||
err := test.expected.ErrorIfNotEqualLists(got)
|
||||
if err != nil {
|
||||
test.expected.Debug("expected")
|
||||
got.Debug("actual")
|
||||
t.Fatalf("Expected match")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func addPfxSfx(r *resource.Resource, prefixes []string, suffixes []string) {
|
||||
for _, pfx := range prefixes {
|
||||
r.AddNamePrefix(pfx)
|
||||
}
|
||||
|
||||
for _, sfx := range suffixes {
|
||||
r.AddNameSuffix(sfx)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubsetThatCouldBeReferencedByResourceMultiLevel(t *testing.T) {
|
||||
// Simulates ConfigMap and Deployment defined at level 1
|
||||
// No prefix nor suffix added at that level
|
||||
cm1 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "level1",
|
||||
},
|
||||
})
|
||||
addPfxSfx(cm1, []string{""}, []string{""})
|
||||
dep1 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "level1",
|
||||
},
|
||||
})
|
||||
addPfxSfx(dep1, []string{""}, []string{""})
|
||||
|
||||
// Simulates ConfigMap and Deployment defined at level 1
|
||||
// and prefix added in level 2 of kustomization
|
||||
cm2p := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "level2p",
|
||||
},
|
||||
})
|
||||
addPfxSfx(cm2p, []string{"", "level2p-"}, []string{"", ""})
|
||||
|
||||
dep2p := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "level2p",
|
||||
},
|
||||
})
|
||||
addPfxSfx(dep2p, []string{"", "level2p-"}, []string{"", ""})
|
||||
|
||||
// Simulates ConfigMap and Deployment defined at level 1
|
||||
// and suffix added in level 2 of kustomization
|
||||
cm2s := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "level2s",
|
||||
},
|
||||
})
|
||||
addPfxSfx(cm2s, []string{"", ""}, []string{"", "-level2s"})
|
||||
|
||||
dep2s := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "level2s",
|
||||
},
|
||||
})
|
||||
addPfxSfx(dep2s, []string{"", ""}, []string{"", "-level2s"})
|
||||
|
||||
// Simulates ConfigMap and Deployment defined at level 1,
|
||||
// prefix added in levels 2 and 3 of kustomization.
|
||||
cm3e := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "level3e",
|
||||
},
|
||||
})
|
||||
addPfxSfx(cm3e, []string{"", "level2p-", "level3e-"}, []string{"", "", ""})
|
||||
|
||||
dep3e := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "level3e",
|
||||
},
|
||||
})
|
||||
addPfxSfx(dep3e, []string{"", "level2p-", "level3e-"}, []string{"", "", ""})
|
||||
|
||||
// Simulates Deployment defined at level 1, ConfigMap defined at level 2,
|
||||
// prefix added in levels 2 and 3 of kustomization.
|
||||
// This reproduce issue 1440.
|
||||
cm3i := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "level3i",
|
||||
},
|
||||
})
|
||||
addPfxSfx(cm3i, []string{"level2p-", "level3i-"}, []string{"", ""})
|
||||
|
||||
dep3i := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "level3i",
|
||||
},
|
||||
})
|
||||
addPfxSfx(dep3i, []string{"", "level2p-", "level3i-"}, []string{"", "", ""})
|
||||
|
||||
tests := map[string]struct {
|
||||
filter *resource.Resource
|
||||
expected ResMap
|
||||
}{
|
||||
"level1": {
|
||||
filter: dep1,
|
||||
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(cm1).AddR(dep1).ResMap(),
|
||||
},
|
||||
"level2p": {
|
||||
filter: dep2p,
|
||||
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(cm2p).AddR(dep2p).ResMap(),
|
||||
},
|
||||
"level2s": {
|
||||
filter: dep2s,
|
||||
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(cm2s).AddR(dep2s).ResMap(),
|
||||
},
|
||||
"level3p": {
|
||||
filter: dep3e,
|
||||
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(cm3e).AddR(dep3e).ResMap(),
|
||||
},
|
||||
"level3i": {
|
||||
filter: dep3i,
|
||||
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(cm3i).AddR(dep3i).ResMap(),
|
||||
},
|
||||
}
|
||||
m := resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(cm1).AddR(dep1).AddR(cm2s).AddR(dep2s).AddR(cm2p).AddR(dep2p).AddR(cm3e).AddR(dep3e).AddR(cm3i).AddR(dep3i).ResMap()
|
||||
for name, test := range tests {
|
||||
test := test
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got := m.SubsetThatCouldBeReferencedByResource(test.filter)
|
||||
err := test.expected.ErrorIfNotEqualLists(got)
|
||||
if err != nil {
|
||||
test.expected.Debug("expected")
|
||||
got.Debug("actual")
|
||||
t.Fatalf("Expected match")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeepCopy(t *testing.T) {
|
||||
rm1 := resmaptest_test.NewRmBuilder(t, rf).Add(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
},
|
||||
}).Add(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm2",
|
||||
},
|
||||
}).ResMap()
|
||||
|
||||
rm2 := rm1.DeepCopy()
|
||||
|
||||
if &rm1 == &rm2 {
|
||||
t.Fatal("DeepCopy returned a reference to itself instead of a copy")
|
||||
}
|
||||
err := rm1.ErrorIfNotEqualLists(rm1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorIfNotEqualSets(t *testing.T) {
|
||||
r1 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
},
|
||||
})
|
||||
r2 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm2",
|
||||
},
|
||||
})
|
||||
r3 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm2",
|
||||
"namespace": "system",
|
||||
},
|
||||
})
|
||||
|
||||
m1 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).AddR(r2).AddR(r3).ResMap()
|
||||
if err := m1.ErrorIfNotEqualSets(m1); err != nil {
|
||||
t.Fatalf("object should equal itself %v", err)
|
||||
}
|
||||
|
||||
m2 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).ResMap()
|
||||
if err := m1.ErrorIfNotEqualSets(m2); err == nil {
|
||||
t.Fatalf("%v should not equal %v %v", m1, m2, err)
|
||||
}
|
||||
|
||||
m3 := resmaptest_test.NewRmBuilder(t, rf).AddR(r2).ResMap()
|
||||
if err := m2.ErrorIfNotEqualSets(m3); err == nil {
|
||||
t.Fatalf("%v should not equal %v %v", m2, m3, err)
|
||||
}
|
||||
|
||||
m3 = resmaptest_test.NewRmBuilder(t, rf).Add(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
}}).ResMap()
|
||||
if err := m2.ErrorIfNotEqualSets(m3); err != nil {
|
||||
t.Fatalf("%v should equal %v %v", m2, m3, err)
|
||||
}
|
||||
|
||||
m4 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).AddR(r2).AddR(r3).ResMap()
|
||||
if err := m1.ErrorIfNotEqualSets(m4); err != nil {
|
||||
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||
}
|
||||
|
||||
m4 = resmaptest_test.NewRmBuilder(t, rf).AddR(r3).AddR(r1).AddR(r2).ResMap()
|
||||
if err := m1.ErrorIfNotEqualSets(m4); err != nil {
|
||||
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||
}
|
||||
|
||||
m4 = m1.ShallowCopy()
|
||||
if err := m1.ErrorIfNotEqualSets(m4); err != nil {
|
||||
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||
}
|
||||
m4 = m1.DeepCopy()
|
||||
if err := m1.ErrorIfNotEqualSets(m4); err != nil {
|
||||
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorIfNotEqualLists(t *testing.T) {
|
||||
r1 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
},
|
||||
})
|
||||
r2 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm2",
|
||||
},
|
||||
})
|
||||
r3 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm2",
|
||||
"namespace": "system",
|
||||
},
|
||||
})
|
||||
|
||||
m1 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).AddR(r2).AddR(r3).ResMap()
|
||||
if err := m1.ErrorIfNotEqualLists(m1); err != nil {
|
||||
t.Fatalf("object should equal itself %v", err)
|
||||
}
|
||||
|
||||
m2 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).ResMap()
|
||||
if err := m1.ErrorIfNotEqualLists(m2); err == nil {
|
||||
t.Fatalf("%v should not equal %v %v", m1, m2, err)
|
||||
}
|
||||
|
||||
m3 := resmaptest_test.NewRmBuilder(t, rf).Add(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
}}).ResMap()
|
||||
if err := m2.ErrorIfNotEqualLists(m3); err != nil {
|
||||
t.Fatalf("%v should equal %v %v", m2, m3, err)
|
||||
}
|
||||
|
||||
m4 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).AddR(r2).AddR(r3).ResMap()
|
||||
if err := m1.ErrorIfNotEqualLists(m4); err != nil {
|
||||
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||
}
|
||||
|
||||
m4 = resmaptest_test.NewRmBuilder(t, rf).AddR(r3).AddR(r1).AddR(r2).ResMap()
|
||||
if err := m1.ErrorIfNotEqualLists(m4); err == nil {
|
||||
t.Fatalf("expected inequality between %v and %v, %v", m1, m4, err)
|
||||
}
|
||||
|
||||
m4 = m1.ShallowCopy()
|
||||
if err := m1.ErrorIfNotEqualLists(m4); err != nil {
|
||||
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||
}
|
||||
m4 = m1.DeepCopy()
|
||||
if err := m1.ErrorIfNotEqualLists(m4); err != nil {
|
||||
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendAll(t *testing.T) {
|
||||
r1 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "foo-deploy1",
|
||||
},
|
||||
})
|
||||
input1 := rmF.FromResource(r1)
|
||||
r2 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "StatefulSet",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "bar-stateful",
|
||||
},
|
||||
})
|
||||
input2 := rmF.FromResource(r2)
|
||||
|
||||
expected := New()
|
||||
if err := expected.Append(r1); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := expected.Append(r2); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if err := input1.AppendAll(input2); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := expected.ErrorIfNotEqualLists(input1); err != nil {
|
||||
input1.Debug("1")
|
||||
expected.Debug("ex")
|
||||
t.Fatalf("%#v doesn't equal expected %#v", input1, expected)
|
||||
}
|
||||
if err := input1.AppendAll(nil); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := expected.ErrorIfNotEqualLists(input1); err != nil {
|
||||
t.Fatalf("%#v doesn't equal expected %#v", input1, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func makeMap1() ResMap {
|
||||
return rmF.FromResource(rf.FromMapAndOption(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cmap",
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
"a": "x",
|
||||
"b": "y",
|
||||
},
|
||||
}, &types.GeneratorArgs{
|
||||
Behavior: "create",
|
||||
}))
|
||||
}
|
||||
|
||||
func makeMap2(b types.GenerationBehavior) ResMap {
|
||||
return rmF.FromResource(rf.FromMapAndOption(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cmap",
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
"a": "u",
|
||||
"b": "v",
|
||||
"c": "w",
|
||||
},
|
||||
}, &types.GeneratorArgs{
|
||||
Behavior: b.String(),
|
||||
}))
|
||||
}
|
||||
|
||||
func TestAbsorbAll(t *testing.T) {
|
||||
expected := rmF.FromResource(rf.FromMapAndOption(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"annotations": map[string]interface{}{},
|
||||
"labels": map[string]interface{}{},
|
||||
"name": "cmap",
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
"a": "u",
|
||||
"b": "v",
|
||||
"c": "w",
|
||||
},
|
||||
}, &types.GeneratorArgs{
|
||||
Behavior: "create",
|
||||
}))
|
||||
w := makeMap1()
|
||||
if err := w.AbsorbAll(makeMap2(types.BehaviorMerge)); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := expected.ErrorIfNotEqualLists(w); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
w = makeMap1()
|
||||
if err := w.AbsorbAll(nil); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := w.ErrorIfNotEqualLists(makeMap1()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
w = makeMap1()
|
||||
w2 := makeMap2(types.BehaviorReplace)
|
||||
if err := w.AbsorbAll(w2); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := w2.ErrorIfNotEqualLists(w); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
w = makeMap1()
|
||||
w2 = makeMap2(types.BehaviorUnspecified)
|
||||
err := w.AbsorbAll(w2)
|
||||
if err == nil {
|
||||
t.Fatalf("expected error with unspecified behavior")
|
||||
}
|
||||
}
|
||||
// See reswrangler_test.go
|
||||
|
||||
581
api/resmap/reswrangler.go
Normal file
581
api/resmap/reswrangler.go
Normal file
@@ -0,0 +1,581 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resmap
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// resWrangler implements ResMap.
|
||||
type resWrangler struct {
|
||||
// Resource list maintained in load (append) order.
|
||||
// This is important for transformers, which must
|
||||
// be performed in a specific order, and for users
|
||||
// who for whatever reasons wish the order they
|
||||
// specify in kustomizations to be maintained and
|
||||
// available as an option for final YAML rendering.
|
||||
rList []*resource.Resource
|
||||
}
|
||||
|
||||
func newOne() *resWrangler {
|
||||
result := &resWrangler{}
|
||||
result.Clear()
|
||||
return result
|
||||
}
|
||||
|
||||
// Clear implements ResMap.
|
||||
func (m *resWrangler) Clear() {
|
||||
m.rList = nil
|
||||
}
|
||||
|
||||
// Size implements ResMap.
|
||||
func (m *resWrangler) Size() int {
|
||||
return len(m.rList)
|
||||
}
|
||||
|
||||
func (m *resWrangler) indexOfResource(other *resource.Resource) int {
|
||||
for i, r := range m.rList {
|
||||
if r == other {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Resources implements ResMap.
|
||||
func (m *resWrangler) Resources() []*resource.Resource {
|
||||
tmp := make([]*resource.Resource, len(m.rList))
|
||||
copy(tmp, m.rList)
|
||||
return tmp
|
||||
}
|
||||
|
||||
// Append implements ResMap.
|
||||
func (m *resWrangler) Append(res *resource.Resource) error {
|
||||
id := res.CurId()
|
||||
if r := m.GetMatchingResourcesByCurrentId(id.Equals); len(r) > 0 {
|
||||
return fmt.Errorf(
|
||||
"may not add resource with an already registered id: %s", id)
|
||||
}
|
||||
m.rList = append(m.rList, res)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove implements ResMap.
|
||||
func (m *resWrangler) Remove(adios resid.ResId) error {
|
||||
tmp := newOne()
|
||||
for _, r := range m.rList {
|
||||
if r.CurId() != adios {
|
||||
tmp.Append(r)
|
||||
}
|
||||
}
|
||||
if tmp.Size() != m.Size()-1 {
|
||||
return fmt.Errorf("id %s not found in removal", adios)
|
||||
}
|
||||
m.rList = tmp.rList
|
||||
return nil
|
||||
}
|
||||
|
||||
// Replace implements ResMap.
|
||||
func (m *resWrangler) Replace(res *resource.Resource) (int, error) {
|
||||
id := res.CurId()
|
||||
i, err := m.GetIndexOfCurrentId(id)
|
||||
if err != nil {
|
||||
return -1, errors.Wrap(err, "in Replace")
|
||||
}
|
||||
if i < 0 {
|
||||
return -1, fmt.Errorf("cannot find resource with id %s to replace", id)
|
||||
}
|
||||
m.rList[i] = res
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// AllIds implements ResMap.
|
||||
func (m *resWrangler) AllIds() (ids []resid.ResId) {
|
||||
ids = make([]resid.ResId, m.Size())
|
||||
for i, r := range m.rList {
|
||||
ids[i] = r.CurId()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Debug implements ResMap.
|
||||
func (m *resWrangler) Debug(title string) {
|
||||
fmt.Println("--------------------------- " + title)
|
||||
firstObj := true
|
||||
for i, r := range m.rList {
|
||||
if firstObj {
|
||||
firstObj = false
|
||||
} else {
|
||||
fmt.Println("---")
|
||||
}
|
||||
fmt.Printf("# %d %s\n", i, r.OrgId())
|
||||
blob, err := yaml.Marshal(r.Map())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(string(blob))
|
||||
}
|
||||
}
|
||||
|
||||
type IdMatcher func(resid.ResId) bool
|
||||
|
||||
// GetByIndex implements ResMap.
|
||||
func (m *resWrangler) GetByIndex(i int) *resource.Resource {
|
||||
if i < 0 || i >= m.Size() {
|
||||
return nil
|
||||
}
|
||||
return m.rList[i]
|
||||
}
|
||||
|
||||
// GetIndexOfCurrentId implements ResMap.
|
||||
func (m *resWrangler) GetIndexOfCurrentId(id resid.ResId) (int, error) {
|
||||
count := 0
|
||||
result := -1
|
||||
for i, r := range m.rList {
|
||||
if id.Equals(r.CurId()) {
|
||||
count++
|
||||
result = i
|
||||
}
|
||||
}
|
||||
if count > 1 {
|
||||
return -1, fmt.Errorf("id matched %d resources", count)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type IdFromResource func(r *resource.Resource) resid.ResId
|
||||
|
||||
func GetOriginalId(r *resource.Resource) resid.ResId { return r.OrgId() }
|
||||
func GetCurrentId(r *resource.Resource) resid.ResId { return r.CurId() }
|
||||
|
||||
// GetMatchingResourcesByCurrentId implements ResMap.
|
||||
func (m *resWrangler) GetMatchingResourcesByCurrentId(
|
||||
matches IdMatcher) []*resource.Resource {
|
||||
return m.filteredById(matches, GetCurrentId)
|
||||
}
|
||||
|
||||
// GetMatchingResourcesByOriginalId implements ResMap.
|
||||
func (m *resWrangler) GetMatchingResourcesByOriginalId(
|
||||
matches IdMatcher) []*resource.Resource {
|
||||
return m.filteredById(matches, GetOriginalId)
|
||||
}
|
||||
|
||||
func (m *resWrangler) filteredById(
|
||||
matches IdMatcher, idGetter IdFromResource) []*resource.Resource {
|
||||
var result []*resource.Resource
|
||||
for _, r := range m.rList {
|
||||
if matches(idGetter(r)) {
|
||||
result = append(result, r)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// GetByCurrentId implements ResMap.
|
||||
func (m *resWrangler) GetByCurrentId(
|
||||
id resid.ResId) (*resource.Resource, error) {
|
||||
return demandOneMatch(m.GetMatchingResourcesByCurrentId, id, "Current")
|
||||
}
|
||||
|
||||
// GetByOriginalId implements ResMap.
|
||||
func (m *resWrangler) GetByOriginalId(
|
||||
id resid.ResId) (*resource.Resource, error) {
|
||||
return demandOneMatch(m.GetMatchingResourcesByOriginalId, id, "Original")
|
||||
}
|
||||
|
||||
// GetById implements ResMap.
|
||||
func (m *resWrangler) GetById(
|
||||
id resid.ResId) (*resource.Resource, error) {
|
||||
match, err1 := m.GetByOriginalId(id)
|
||||
if err1 == nil {
|
||||
return match, nil
|
||||
}
|
||||
match, err2 := m.GetByCurrentId(id)
|
||||
if err2 == nil {
|
||||
return match, nil
|
||||
}
|
||||
return nil, fmt.Errorf(
|
||||
"%s; %s; failed to find unique target for patch %s",
|
||||
err1.Error(), err2.Error(), id.GvknString())
|
||||
}
|
||||
|
||||
type resFinder func(IdMatcher) []*resource.Resource
|
||||
|
||||
func demandOneMatch(
|
||||
f resFinder, id resid.ResId, s string) (*resource.Resource, error) {
|
||||
r := f(id.Equals)
|
||||
if len(r) == 1 {
|
||||
return r[0], nil
|
||||
}
|
||||
if len(r) > 1 {
|
||||
return nil, fmt.Errorf("multiple matches for %sId %s", s, id)
|
||||
}
|
||||
return nil, fmt.Errorf("no matches for %sId %s", s, id)
|
||||
}
|
||||
|
||||
// GroupedByCurrentNamespace implements ResMap.GroupByCurrentNamespace
|
||||
func (m *resWrangler) GroupedByCurrentNamespace() map[string][]*resource.Resource {
|
||||
items := m.groupedByCurrentNamespace()
|
||||
delete(items, resid.TotallyNotANamespace)
|
||||
return items
|
||||
}
|
||||
|
||||
// NonNamespaceable implements ResMap.NonNamespaceable
|
||||
func (m *resWrangler) NonNamespaceable() []*resource.Resource {
|
||||
return m.groupedByCurrentNamespace()[resid.TotallyNotANamespace]
|
||||
}
|
||||
|
||||
func (m *resWrangler) groupedByCurrentNamespace() map[string][]*resource.Resource {
|
||||
byNamespace := make(map[string][]*resource.Resource)
|
||||
for _, res := range m.rList {
|
||||
namespace := res.CurId().EffectiveNamespace()
|
||||
if _, found := byNamespace[namespace]; !found {
|
||||
byNamespace[namespace] = []*resource.Resource{}
|
||||
}
|
||||
byNamespace[namespace] = append(byNamespace[namespace], res)
|
||||
}
|
||||
return byNamespace
|
||||
}
|
||||
|
||||
// GroupedByNamespace implements ResMap.GroupByOrginalNamespace
|
||||
func (m *resWrangler) GroupedByOriginalNamespace() map[string][]*resource.Resource {
|
||||
items := m.groupedByOriginalNamespace()
|
||||
delete(items, resid.TotallyNotANamespace)
|
||||
return items
|
||||
}
|
||||
|
||||
func (m *resWrangler) groupedByOriginalNamespace() map[string][]*resource.Resource {
|
||||
byNamespace := make(map[string][]*resource.Resource)
|
||||
for _, res := range m.rList {
|
||||
namespace := res.OrgId().EffectiveNamespace()
|
||||
if _, found := byNamespace[namespace]; !found {
|
||||
byNamespace[namespace] = []*resource.Resource{}
|
||||
}
|
||||
byNamespace[namespace] = append(byNamespace[namespace], res)
|
||||
}
|
||||
return byNamespace
|
||||
}
|
||||
|
||||
// AsYaml implements ResMap.
|
||||
func (m *resWrangler) AsYaml() ([]byte, error) {
|
||||
firstObj := true
|
||||
var b []byte
|
||||
buf := bytes.NewBuffer(b)
|
||||
for _, res := range m.Resources() {
|
||||
out, err := yaml.Marshal(res.Map())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if firstObj {
|
||||
firstObj = false
|
||||
} else {
|
||||
if _, err = buf.WriteString("---\n"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if _, err = buf.Write(out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// ErrorIfNotEqualSets implements ResMap.
|
||||
func (m *resWrangler) ErrorIfNotEqualSets(other ResMap) error {
|
||||
m2, ok := other.(*resWrangler)
|
||||
if !ok {
|
||||
panic("bad cast")
|
||||
}
|
||||
if m.Size() != m2.Size() {
|
||||
return fmt.Errorf(
|
||||
"lists have different number of entries: %#v doesn't equal %#v",
|
||||
m.rList, m2.rList)
|
||||
}
|
||||
seen := make(map[int]bool)
|
||||
for _, r1 := range m.rList {
|
||||
id := r1.CurId()
|
||||
others := m2.GetMatchingResourcesByCurrentId(id.Equals)
|
||||
if len(others) == 0 {
|
||||
return fmt.Errorf(
|
||||
"id in self missing from other; id: %s", id)
|
||||
}
|
||||
if len(others) > 1 {
|
||||
return fmt.Errorf(
|
||||
"id in self matches %d in other; id: %s", len(others), id)
|
||||
}
|
||||
r2 := others[0]
|
||||
if !r1.KunstructEqual(r2) {
|
||||
return fmt.Errorf(
|
||||
"kunstruct not equal: \n -- %s,\n -- %s\n\n--\n%#v\n------\n%#v\n",
|
||||
r1, r2, r1, r2)
|
||||
}
|
||||
seen[m2.indexOfResource(r2)] = true
|
||||
}
|
||||
if len(seen) != m.Size() {
|
||||
return fmt.Errorf("counting problem %d != %d", len(seen), m.Size())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ErrorIfNotEqualList implements ResMap.
|
||||
func (m *resWrangler) ErrorIfNotEqualLists(other ResMap) error {
|
||||
m2, ok := other.(*resWrangler)
|
||||
if !ok {
|
||||
panic("bad cast")
|
||||
}
|
||||
if m.Size() != m2.Size() {
|
||||
return fmt.Errorf(
|
||||
"lists have different number of entries: %#v doesn't equal %#v",
|
||||
m.rList, m2.rList)
|
||||
}
|
||||
for i, r1 := range m.rList {
|
||||
r2 := m2.rList[i]
|
||||
if !r1.Equals(r2) {
|
||||
return fmt.Errorf(
|
||||
"Item i=%d differs:\n n1 = %s\n n2 = %s\n o1 = %s\n o2 = %s\n",
|
||||
i, r1.OrgId(), r2.OrgId(), r1, r2)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type resCopier func(r *resource.Resource) *resource.Resource
|
||||
|
||||
// ShallowCopy implements ResMap.
|
||||
func (m *resWrangler) ShallowCopy() ResMap {
|
||||
return m.makeCopy(
|
||||
func(r *resource.Resource) *resource.Resource {
|
||||
return r
|
||||
})
|
||||
}
|
||||
|
||||
// DeepCopy implements ResMap.
|
||||
func (m *resWrangler) DeepCopy() ResMap {
|
||||
return m.makeCopy(
|
||||
func(r *resource.Resource) *resource.Resource {
|
||||
return r.DeepCopy()
|
||||
})
|
||||
}
|
||||
|
||||
// makeCopy copies the ResMap.
|
||||
func (m *resWrangler) makeCopy(copier resCopier) ResMap {
|
||||
result := &resWrangler{}
|
||||
result.rList = make([]*resource.Resource, m.Size())
|
||||
for i, r := range m.rList {
|
||||
result.rList[i] = copier(r)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// SubsetThatCouldBeReferencedByResource implements ResMap.
|
||||
func (m *resWrangler) SubsetThatCouldBeReferencedByResource(
|
||||
inputRes *resource.Resource) ResMap {
|
||||
result := newOne()
|
||||
inputId := inputRes.CurId()
|
||||
isInputIdNamespaceable := inputId.IsNamespaceableKind()
|
||||
subjectNamespaces := getNamespacesForRoleBinding(inputRes)
|
||||
for _, r := range m.Resources() {
|
||||
// Need to match more accuratly both at the time of selection and transformation.
|
||||
// OutmostPrefixSuffixEquals is not accurate enough since it is only using
|
||||
// the outer most suffix and the last prefix. Use PrefixedSuffixesEquals instead.
|
||||
resId := r.CurId()
|
||||
if !isInputIdNamespaceable || !resId.IsNamespaceableKind() || resId.IsNsEquals(inputId) ||
|
||||
isRoleBindingNamespace(&subjectNamespaces, r.GetNamespace()) {
|
||||
result.append(r)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// isRoleBindingNamespace returns true is the namespace `ns` is in role binding
|
||||
// namespaces `m`
|
||||
func isRoleBindingNamespace(m *map[string]bool, ns string) bool {
|
||||
return (*m)[ns]
|
||||
}
|
||||
|
||||
// getNamespacesForRoleBinding returns referenced ServiceAccount namespaces if the inputRes is
|
||||
// a RoleBinding
|
||||
func getNamespacesForRoleBinding(inputRes *resource.Resource) map[string]bool {
|
||||
res := make(map[string]bool)
|
||||
if inputRes.GetKind() != "RoleBinding" {
|
||||
return res
|
||||
}
|
||||
subjects, err := inputRes.GetSlice("subjects")
|
||||
if err != nil || subjects == nil {
|
||||
return res
|
||||
}
|
||||
|
||||
for _, s := range subjects {
|
||||
subject := s.(map[string]interface{})
|
||||
if subject["namespace"] == nil || subject["kind"] == nil ||
|
||||
subject["kind"].(string) != "ServiceAccount" {
|
||||
continue
|
||||
}
|
||||
res[subject["namespace"].(string)] = true
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (m *resWrangler) append(res *resource.Resource) {
|
||||
m.rList = append(m.rList, res)
|
||||
}
|
||||
|
||||
// AppendAll implements ResMap.
|
||||
func (m *resWrangler) AppendAll(other ResMap) error {
|
||||
if other == nil {
|
||||
return nil
|
||||
}
|
||||
for _, res := range other.Resources() {
|
||||
if err := m.Append(res); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AbsorbAll implements ResMap.
|
||||
func (m *resWrangler) AbsorbAll(other ResMap) error {
|
||||
if other == nil {
|
||||
return nil
|
||||
}
|
||||
for _, r := range other.Resources() {
|
||||
err := m.appendReplaceOrMerge(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *resWrangler) appendReplaceOrMerge(
|
||||
res *resource.Resource) error {
|
||||
id := res.CurId()
|
||||
matches := m.GetMatchingResourcesByOriginalId(id.Equals)
|
||||
if len(matches) == 0 {
|
||||
matches = m.GetMatchingResourcesByCurrentId(id.Equals)
|
||||
}
|
||||
switch len(matches) {
|
||||
case 0:
|
||||
switch res.Behavior() {
|
||||
case types.BehaviorMerge, types.BehaviorReplace:
|
||||
return fmt.Errorf(
|
||||
"id %#v does not exist; cannot merge or replace", id)
|
||||
default:
|
||||
// presumably types.BehaviorCreate
|
||||
err := m.Append(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
old := matches[0]
|
||||
if old == nil {
|
||||
return fmt.Errorf("id lookup failure")
|
||||
}
|
||||
index := m.indexOfResource(old)
|
||||
if index < 0 {
|
||||
return fmt.Errorf("indexing problem")
|
||||
}
|
||||
switch res.Behavior() {
|
||||
case types.BehaviorReplace:
|
||||
res.Replace(old)
|
||||
case types.BehaviorMerge:
|
||||
res.Merge(old)
|
||||
default:
|
||||
return fmt.Errorf(
|
||||
"id %#v exists; behavior must be merge or replace", id)
|
||||
}
|
||||
i, err := m.Replace(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i != index {
|
||||
return fmt.Errorf("unexpected index in replacement")
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf(
|
||||
"found multiple objects %v that could accept merge of %v",
|
||||
matches, id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func anchorRegex(pattern string) string {
|
||||
if pattern == "" {
|
||||
return pattern
|
||||
}
|
||||
return "^" + pattern + "$"
|
||||
}
|
||||
|
||||
// Select returns a list of resources that
|
||||
// are selected by a Selector
|
||||
func (m *resWrangler) Select(s types.Selector) ([]*resource.Resource, error) {
|
||||
ns := regexp.MustCompile(anchorRegex(s.Namespace))
|
||||
nm := regexp.MustCompile(anchorRegex(s.Name))
|
||||
var result []*resource.Resource
|
||||
for _, r := range m.Resources() {
|
||||
curId := r.CurId()
|
||||
orgId := r.OrgId()
|
||||
|
||||
// matches the namespace when namespace is not empty in the selector
|
||||
// It first tries to match with the original namespace
|
||||
// then matches with the current namespace
|
||||
if r.GetNamespace() != "" {
|
||||
matched := ns.MatchString(orgId.EffectiveNamespace())
|
||||
if !matched {
|
||||
matched = ns.MatchString(curId.EffectiveNamespace())
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// matches the name when name is not empty in the selector
|
||||
// It first tries to match with the original name
|
||||
// then matches with the current name
|
||||
if r.GetName() != "" {
|
||||
matched := nm.MatchString(orgId.Name)
|
||||
if !matched {
|
||||
matched = nm.MatchString(curId.Name)
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// matches the GVK
|
||||
if !r.GetGvk().IsSelected(&s.Gvk) {
|
||||
continue
|
||||
}
|
||||
|
||||
// matches the label selector
|
||||
matched, err := r.MatchesLabelSelector(s.LabelSelector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
|
||||
// matches the annotation selector
|
||||
matched, err = r.MatchesAnnotationSelector(s.AnnotationSelector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
result = append(result, r)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
734
api/resmap/reswrangler_test.go
Normal file
734
api/resmap/reswrangler_test.go
Normal file
@@ -0,0 +1,734 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resmap_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/k8sdeps/kunstruct"
|
||||
"sigs.k8s.io/kustomize/api/resid"
|
||||
. "sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
resmaptest_test "sigs.k8s.io/kustomize/api/testutils/resmaptest"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
var rf = resource.NewFactory(
|
||||
kunstruct.NewKunstructuredFactoryImpl())
|
||||
var rmF = NewFactory(rf, nil)
|
||||
|
||||
func doAppend(t *testing.T, w ResMap, r *resource.Resource) {
|
||||
err := w.Append(r)
|
||||
if err != nil {
|
||||
t.Fatalf("append error: %v", err)
|
||||
}
|
||||
}
|
||||
func doRemove(t *testing.T, w ResMap, id resid.ResId) {
|
||||
err := w.Remove(id)
|
||||
if err != nil {
|
||||
t.Fatalf("remove error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Make a resource with a predictable name.
|
||||
func makeCm(i int) *resource.Resource {
|
||||
return rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": fmt.Sprintf("cm%03d", i),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Maintain the class invariant that no two
|
||||
// resources can have the same CurId().
|
||||
func TestAppendRejectsDuplicateResId(t *testing.T) {
|
||||
w := New()
|
||||
if err := w.Append(makeCm(1)); err != nil {
|
||||
t.Fatalf("append error: %v", err)
|
||||
}
|
||||
err := w.Append(makeCm(1))
|
||||
if err == nil {
|
||||
t.Fatalf("expected append error")
|
||||
}
|
||||
if !strings.Contains(
|
||||
err.Error(),
|
||||
"may not add resource with an already registered id") {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendRemove(t *testing.T) {
|
||||
w1 := New()
|
||||
doAppend(t, w1, makeCm(1))
|
||||
doAppend(t, w1, makeCm(2))
|
||||
doAppend(t, w1, makeCm(3))
|
||||
doAppend(t, w1, makeCm(4))
|
||||
doAppend(t, w1, makeCm(5))
|
||||
doAppend(t, w1, makeCm(6))
|
||||
doAppend(t, w1, makeCm(7))
|
||||
doRemove(t, w1, makeCm(1).OrgId())
|
||||
doRemove(t, w1, makeCm(3).OrgId())
|
||||
doRemove(t, w1, makeCm(5).OrgId())
|
||||
doRemove(t, w1, makeCm(7).OrgId())
|
||||
|
||||
w2 := New()
|
||||
doAppend(t, w2, makeCm(2))
|
||||
doAppend(t, w2, makeCm(4))
|
||||
doAppend(t, w2, makeCm(6))
|
||||
if !reflect.DeepEqual(w1, w1) {
|
||||
w1.Debug("w1")
|
||||
w2.Debug("w2")
|
||||
t.Fatalf("mismatch")
|
||||
}
|
||||
|
||||
err := w2.Append(makeCm(6))
|
||||
if err == nil {
|
||||
t.Fatalf("expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemove(t *testing.T) {
|
||||
w := New()
|
||||
r := makeCm(1)
|
||||
err := w.Remove(r.OrgId())
|
||||
if err == nil {
|
||||
t.Fatalf("expected error")
|
||||
}
|
||||
err = w.Append(r)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
err = w.Remove(r.OrgId())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
err = w.Remove(r.OrgId())
|
||||
if err == nil {
|
||||
t.Fatalf("expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplace(t *testing.T) {
|
||||
cm5 := makeCm(5)
|
||||
cm700 := makeCm(700)
|
||||
otherCm5 := makeCm(5)
|
||||
|
||||
w := New()
|
||||
doAppend(t, w, makeCm(1))
|
||||
doAppend(t, w, makeCm(2))
|
||||
doAppend(t, w, makeCm(3))
|
||||
doAppend(t, w, makeCm(4))
|
||||
doAppend(t, w, cm5)
|
||||
doAppend(t, w, makeCm(6))
|
||||
doAppend(t, w, makeCm(7))
|
||||
|
||||
oldSize := w.Size()
|
||||
_, err := w.Replace(otherCm5)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if w.Size() != oldSize {
|
||||
t.Fatalf("unexpected size %d", w.Size())
|
||||
}
|
||||
if r, err := w.GetByCurrentId(cm5.OrgId()); err != nil || r != otherCm5 {
|
||||
t.Fatalf("unexpected result r=%s, err=%v", r.CurId(), err)
|
||||
}
|
||||
if err := w.Append(cm5); err == nil {
|
||||
t.Fatalf("expected id already there error")
|
||||
}
|
||||
if err := w.Remove(cm5.OrgId()); err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
if err := w.Append(cm700); err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
if err := w.Append(cm5); err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeAsYaml(t *testing.T) {
|
||||
encoded := []byte(`apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm2
|
||||
`)
|
||||
input := resmaptest_test.NewRmBuilder(t, rf).Add(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
},
|
||||
}).Add(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm2",
|
||||
},
|
||||
}).ResMap()
|
||||
out, err := input.AsYaml()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(out, encoded) {
|
||||
t.Fatalf("%s doesn't match expected %s", out, encoded)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMatchingResourcesByCurrentId(t *testing.T) {
|
||||
r1 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "alice",
|
||||
},
|
||||
})
|
||||
r2 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "bob",
|
||||
},
|
||||
})
|
||||
r3 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "bob",
|
||||
"namespace": "happy",
|
||||
},
|
||||
})
|
||||
r4 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "charlie",
|
||||
"namespace": "happy",
|
||||
},
|
||||
})
|
||||
r5 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "charlie",
|
||||
"namespace": "happy",
|
||||
},
|
||||
})
|
||||
|
||||
m := resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(r1).AddR(r2).AddR(r3).AddR(r4).AddR(r5).ResMap()
|
||||
|
||||
result := m.GetMatchingResourcesByCurrentId(
|
||||
resid.NewResId(cmap, "alice").GvknEquals)
|
||||
if len(result) != 1 {
|
||||
t.Fatalf("Expected single map entry but got %v", result)
|
||||
}
|
||||
result = m.GetMatchingResourcesByCurrentId(
|
||||
resid.NewResId(cmap, "bob").GvknEquals)
|
||||
if len(result) != 2 {
|
||||
t.Fatalf("Expected two, got %v", result)
|
||||
}
|
||||
result = m.GetMatchingResourcesByCurrentId(
|
||||
resid.NewResIdWithNamespace(cmap, "bob", "system").GvknEquals)
|
||||
if len(result) != 2 {
|
||||
t.Fatalf("Expected two but got %v", result)
|
||||
}
|
||||
result = m.GetMatchingResourcesByCurrentId(
|
||||
resid.NewResIdWithNamespace(cmap, "bob", "happy").Equals)
|
||||
if len(result) != 1 {
|
||||
t.Fatalf("Expected single map entry but got %v", result)
|
||||
}
|
||||
result = m.GetMatchingResourcesByCurrentId(
|
||||
resid.NewResId(cmap, "charlie").GvknEquals)
|
||||
if len(result) != 1 {
|
||||
t.Fatalf("Expected single map entry but got %v", result)
|
||||
}
|
||||
|
||||
// nolint:goconst
|
||||
tests := []struct {
|
||||
name string
|
||||
matcher IdMatcher
|
||||
count int
|
||||
}{
|
||||
{
|
||||
"match everything",
|
||||
func(resid.ResId) bool { return true },
|
||||
5,
|
||||
},
|
||||
{
|
||||
"match nothing",
|
||||
func(resid.ResId) bool { return false },
|
||||
0,
|
||||
},
|
||||
{
|
||||
"name is alice",
|
||||
func(x resid.ResId) bool { return x.Name == "alice" },
|
||||
1,
|
||||
},
|
||||
{
|
||||
"name is charlie",
|
||||
func(x resid.ResId) bool { return x.Name == "charlie" },
|
||||
2,
|
||||
},
|
||||
{
|
||||
"name is bob",
|
||||
func(x resid.ResId) bool { return x.Name == "bob" },
|
||||
2,
|
||||
},
|
||||
{
|
||||
"happy namespace",
|
||||
func(x resid.ResId) bool {
|
||||
return x.Namespace == "happy"
|
||||
},
|
||||
3,
|
||||
},
|
||||
{
|
||||
"happy deployment",
|
||||
func(x resid.ResId) bool {
|
||||
return x.Namespace == "happy" &&
|
||||
x.Gvk.Kind == "Deployment"
|
||||
},
|
||||
1,
|
||||
},
|
||||
{
|
||||
"happy ConfigMap",
|
||||
func(x resid.ResId) bool {
|
||||
return x.Namespace == "happy" &&
|
||||
x.Gvk.Kind == "ConfigMap"
|
||||
},
|
||||
2,
|
||||
},
|
||||
}
|
||||
for _, tst := range tests {
|
||||
result := m.GetMatchingResourcesByCurrentId(tst.matcher)
|
||||
if len(result) != tst.count {
|
||||
t.Fatalf("test '%s'; actual: %d, expected: %d",
|
||||
tst.name, len(result), tst.count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubsetThatCouldBeReferencedByResource(t *testing.T) {
|
||||
r1 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "alice",
|
||||
},
|
||||
})
|
||||
r2 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "bob",
|
||||
},
|
||||
})
|
||||
r3 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "bob",
|
||||
"namespace": "happy",
|
||||
},
|
||||
})
|
||||
r4 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "charlie",
|
||||
"namespace": "happy",
|
||||
},
|
||||
})
|
||||
r5 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "charlie",
|
||||
"namespace": "happy",
|
||||
},
|
||||
})
|
||||
r5.AddNamePrefix("little-")
|
||||
r6 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "domino",
|
||||
"namespace": "happy",
|
||||
},
|
||||
})
|
||||
r6.AddNamePrefix("little-")
|
||||
r7 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ClusterRoleBinding",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "meh",
|
||||
},
|
||||
})
|
||||
|
||||
tests := map[string]struct {
|
||||
filter *resource.Resource
|
||||
expected ResMap
|
||||
}{
|
||||
"default namespace 1": {
|
||||
filter: r2,
|
||||
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(r1).AddR(r2).AddR(r7).ResMap(),
|
||||
},
|
||||
"default namespace 2": {
|
||||
filter: r1,
|
||||
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(r1).AddR(r2).AddR(r7).ResMap(),
|
||||
},
|
||||
"happy namespace no prefix": {
|
||||
filter: r3,
|
||||
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(r3).AddR(r4).AddR(r5).AddR(r6).AddR(r7).ResMap(),
|
||||
},
|
||||
"happy namespace with prefix": {
|
||||
filter: r5,
|
||||
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(r3).AddR(r4).AddR(r5).AddR(r6).AddR(r7).ResMap(),
|
||||
},
|
||||
"cluster level": {
|
||||
filter: r7,
|
||||
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(r1).AddR(r2).AddR(r3).AddR(r4).AddR(r5).AddR(r6).AddR(r7).ResMap(),
|
||||
},
|
||||
}
|
||||
m := resmaptest_test.NewRmBuilder(t, rf).
|
||||
AddR(r1).AddR(r2).AddR(r3).AddR(r4).AddR(r5).AddR(r6).AddR(r7).ResMap()
|
||||
for name, test := range tests {
|
||||
test := test
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got := m.SubsetThatCouldBeReferencedByResource(test.filter)
|
||||
err := test.expected.ErrorIfNotEqualLists(got)
|
||||
if err != nil {
|
||||
test.expected.Debug("expected")
|
||||
got.Debug("actual")
|
||||
t.Fatalf("Expected match")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeepCopy(t *testing.T) {
|
||||
rm1 := resmaptest_test.NewRmBuilder(t, rf).Add(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
},
|
||||
}).Add(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm2",
|
||||
},
|
||||
}).ResMap()
|
||||
|
||||
rm2 := rm1.DeepCopy()
|
||||
|
||||
if &rm1 == &rm2 {
|
||||
t.Fatal("DeepCopy returned a reference to itself instead of a copy")
|
||||
}
|
||||
err := rm1.ErrorIfNotEqualLists(rm1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorIfNotEqualSets(t *testing.T) {
|
||||
r1 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
},
|
||||
})
|
||||
r2 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm2",
|
||||
},
|
||||
})
|
||||
r3 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm2",
|
||||
"namespace": "system",
|
||||
},
|
||||
})
|
||||
|
||||
m1 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).AddR(r2).AddR(r3).ResMap()
|
||||
if err := m1.ErrorIfNotEqualSets(m1); err != nil {
|
||||
t.Fatalf("object should equal itself %v", err)
|
||||
}
|
||||
|
||||
m2 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).ResMap()
|
||||
if err := m1.ErrorIfNotEqualSets(m2); err == nil {
|
||||
t.Fatalf("%v should not equal %v %v", m1, m2, err)
|
||||
}
|
||||
|
||||
m3 := resmaptest_test.NewRmBuilder(t, rf).AddR(r2).ResMap()
|
||||
if err := m2.ErrorIfNotEqualSets(m3); err == nil {
|
||||
t.Fatalf("%v should not equal %v %v", m2, m3, err)
|
||||
}
|
||||
|
||||
m3 = resmaptest_test.NewRmBuilder(t, rf).Add(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
}}).ResMap()
|
||||
if err := m2.ErrorIfNotEqualSets(m3); err != nil {
|
||||
t.Fatalf("%v should equal %v %v", m2, m3, err)
|
||||
}
|
||||
|
||||
m4 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).AddR(r2).AddR(r3).ResMap()
|
||||
if err := m1.ErrorIfNotEqualSets(m4); err != nil {
|
||||
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||
}
|
||||
|
||||
m4 = resmaptest_test.NewRmBuilder(t, rf).AddR(r3).AddR(r1).AddR(r2).ResMap()
|
||||
if err := m1.ErrorIfNotEqualSets(m4); err != nil {
|
||||
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||
}
|
||||
|
||||
m4 = m1.ShallowCopy()
|
||||
if err := m1.ErrorIfNotEqualSets(m4); err != nil {
|
||||
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||
}
|
||||
m4 = m1.DeepCopy()
|
||||
if err := m1.ErrorIfNotEqualSets(m4); err != nil {
|
||||
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorIfNotEqualLists(t *testing.T) {
|
||||
r1 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
},
|
||||
})
|
||||
r2 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm2",
|
||||
},
|
||||
})
|
||||
r3 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm2",
|
||||
"namespace": "system",
|
||||
},
|
||||
})
|
||||
|
||||
m1 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).AddR(r2).AddR(r3).ResMap()
|
||||
if err := m1.ErrorIfNotEqualLists(m1); err != nil {
|
||||
t.Fatalf("object should equal itself %v", err)
|
||||
}
|
||||
|
||||
m2 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).ResMap()
|
||||
if err := m1.ErrorIfNotEqualLists(m2); err == nil {
|
||||
t.Fatalf("%v should not equal %v %v", m1, m2, err)
|
||||
}
|
||||
|
||||
m3 := resmaptest_test.NewRmBuilder(t, rf).Add(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cm1",
|
||||
}}).ResMap()
|
||||
if err := m2.ErrorIfNotEqualLists(m3); err != nil {
|
||||
t.Fatalf("%v should equal %v %v", m2, m3, err)
|
||||
}
|
||||
|
||||
m4 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).AddR(r2).AddR(r3).ResMap()
|
||||
if err := m1.ErrorIfNotEqualLists(m4); err != nil {
|
||||
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||
}
|
||||
|
||||
m4 = resmaptest_test.NewRmBuilder(t, rf).AddR(r3).AddR(r1).AddR(r2).ResMap()
|
||||
if err := m1.ErrorIfNotEqualLists(m4); err == nil {
|
||||
t.Fatalf("expected inequality between %v and %v, %v", m1, m4, err)
|
||||
}
|
||||
|
||||
m4 = m1.ShallowCopy()
|
||||
if err := m1.ErrorIfNotEqualLists(m4); err != nil {
|
||||
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||
}
|
||||
m4 = m1.DeepCopy()
|
||||
if err := m1.ErrorIfNotEqualLists(m4); err != nil {
|
||||
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendAll(t *testing.T) {
|
||||
r1 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "foo-deploy1",
|
||||
},
|
||||
})
|
||||
input1 := rmF.FromResource(r1)
|
||||
r2 := rf.FromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "StatefulSet",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "bar-stateful",
|
||||
},
|
||||
})
|
||||
input2 := rmF.FromResource(r2)
|
||||
|
||||
expected := New()
|
||||
if err := expected.Append(r1); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := expected.Append(r2); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if err := input1.AppendAll(input2); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := expected.ErrorIfNotEqualLists(input1); err != nil {
|
||||
input1.Debug("1")
|
||||
expected.Debug("ex")
|
||||
t.Fatalf("%#v doesn't equal expected %#v", input1, expected)
|
||||
}
|
||||
if err := input1.AppendAll(nil); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := expected.ErrorIfNotEqualLists(input1); err != nil {
|
||||
t.Fatalf("%#v doesn't equal expected %#v", input1, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func makeMap1() ResMap {
|
||||
return rmF.FromResource(rf.FromMapAndOption(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cmap",
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
"a": "x",
|
||||
"b": "y",
|
||||
},
|
||||
}, &types.GeneratorArgs{
|
||||
Behavior: "create",
|
||||
}))
|
||||
}
|
||||
|
||||
func makeMap2(b types.GenerationBehavior) ResMap {
|
||||
return rmF.FromResource(rf.FromMapAndOption(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "cmap",
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
"a": "u",
|
||||
"b": "v",
|
||||
"c": "w",
|
||||
},
|
||||
}, &types.GeneratorArgs{
|
||||
Behavior: b.String(),
|
||||
}))
|
||||
}
|
||||
|
||||
func TestAbsorbAll(t *testing.T) {
|
||||
expected := rmF.FromResource(rf.FromMapAndOption(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "ConfigMap",
|
||||
"metadata": map[string]interface{}{
|
||||
"annotations": map[string]interface{}{},
|
||||
"labels": map[string]interface{}{},
|
||||
"name": "cmap",
|
||||
},
|
||||
"data": map[string]interface{}{
|
||||
"a": "u",
|
||||
"b": "v",
|
||||
"c": "w",
|
||||
},
|
||||
}, &types.GeneratorArgs{
|
||||
Behavior: "create",
|
||||
}))
|
||||
w := makeMap1()
|
||||
if err := w.AbsorbAll(makeMap2(types.BehaviorMerge)); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := expected.ErrorIfNotEqualLists(w); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
w = makeMap1()
|
||||
if err := w.AbsorbAll(nil); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := w.ErrorIfNotEqualLists(makeMap1()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
w = makeMap1()
|
||||
w2 := makeMap2(types.BehaviorReplace)
|
||||
if err := w.AbsorbAll(w2); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := w2.ErrorIfNotEqualLists(w); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
w = makeMap1()
|
||||
w2 = makeMap2(types.BehaviorUnspecified)
|
||||
err := w.AbsorbAll(w2)
|
||||
if err == nil {
|
||||
t.Fatalf("expected error with unspecified behavior")
|
||||
}
|
||||
}
|
||||
@@ -277,12 +277,6 @@ func (r *Resource) PrefixesSuffixesEquals(o ResCtx) bool {
|
||||
return sameEndingSubarray(r.GetNamePrefixes(), o.GetNamePrefixes()) && sameEndingSubarray(r.GetNameSuffixes(), o.GetNameSuffixes())
|
||||
}
|
||||
|
||||
// This is used to compute if a referrer could potentially be impacted
|
||||
// by the change of name of a referral.
|
||||
func (r *Resource) InSameKustomizeCtx(rctxm ResCtxMatcher) bool {
|
||||
return rctxm(r)
|
||||
}
|
||||
|
||||
func (r *Resource) GetOriginalName() string {
|
||||
return r.originalName
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
)
|
||||
|
||||
// Harness manages a kustomize environment for tests.
|
||||
// Harness manages a test environment.
|
||||
type Harness struct {
|
||||
t *testing.T
|
||||
fSys filesys.FileSystem
|
||||
@@ -72,15 +72,12 @@ func (th Harness) MakeDefaultOptions() krusty.Options {
|
||||
|
||||
// This has no impact on Builtin plugins, as they are always enabled.
|
||||
func (th Harness) MakeOptionsPluginsDisabled() krusty.Options {
|
||||
return krusty.Options{
|
||||
LoadRestrictions: types.LoadRestrictionsRootOnly,
|
||||
PluginConfig: konfig.DisabledPluginConfig(),
|
||||
}
|
||||
return *krusty.MakeDefaultOptions()
|
||||
}
|
||||
|
||||
// Enables use of non-builtin plugins.
|
||||
func (th Harness) MakeOptionsPluginsEnabled() krusty.Options {
|
||||
c, err := konfig.EnabledPluginConfig(types.BploLoadFromFileSys)
|
||||
pc, err := konfig.EnabledPluginConfig(types.BploLoadFromFileSys)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "unable to find plugin root") {
|
||||
th.t.Log(
|
||||
@@ -89,10 +86,9 @@ func (th Harness) MakeOptionsPluginsEnabled() krusty.Options {
|
||||
}
|
||||
th.t.Fatal(err)
|
||||
}
|
||||
return krusty.Options{
|
||||
LoadRestrictions: types.LoadRestrictionsRootOnly,
|
||||
PluginConfig: c,
|
||||
}
|
||||
o := *krusty.MakeDefaultOptions()
|
||||
o.PluginConfig = pc
|
||||
return o
|
||||
}
|
||||
|
||||
// Run, failing on error.
|
||||
|
||||
@@ -12,3 +12,13 @@ import (
|
||||
var GetOpenAPIFile = func(args []string) (string, error) {
|
||||
return filepath.Join(args[0], "Krmfile"), nil
|
||||
}
|
||||
|
||||
// OpenAPIFileName returns the name of the file with openAPI definitions
|
||||
// uses OpenAPIFile function to derive it
|
||||
func OpenAPIFileName() (string, error) {
|
||||
openAPIFileName, err := GetOpenAPIFile([]string{"."})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return openAPIFileName, nil
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ require (
|
||||
k8s.io/client-go v0.17.3
|
||||
k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd
|
||||
sigs.k8s.io/cli-utils v0.19.0
|
||||
sigs.k8s.io/kustomize/kyaml v0.6.0
|
||||
sigs.k8s.io/kustomize/kyaml v0.6.1
|
||||
)
|
||||
|
||||
replace sigs.k8s.io/kustomize/kyaml => ../../kyaml
|
||||
|
||||
@@ -13,7 +13,9 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/ext"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
|
||||
"sigs.k8s.io/kustomize/kyaml/pathutil"
|
||||
"sigs.k8s.io/kustomize/kyaml/setters"
|
||||
"sigs.k8s.io/kustomize/kyaml/setters2"
|
||||
)
|
||||
@@ -63,11 +65,35 @@ func (r *ListSettersRunner) preRunE(c *cobra.Command, args []string) error {
|
||||
|
||||
func (r *ListSettersRunner) runE(c *cobra.Command, args []string) error {
|
||||
if setterVersion == "v2" {
|
||||
if err := r.ListSetters(c, args); err != nil {
|
||||
openAPIFileName, err := ext.OpenAPIFileName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if r.IncludeSubst {
|
||||
return r.ListSubstitutions(c, args)
|
||||
|
||||
openAPIPaths, err := pathutil.SubDirsWithFile(args[0], openAPIFileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(openAPIPaths) == 0 {
|
||||
return errors.Errorf("unable to find %s in %s", openAPIFileName, args[0])
|
||||
}
|
||||
|
||||
// list setters for all the subpackages with openAPI file paths
|
||||
for _, openAPIPath := range openAPIPaths {
|
||||
r.List = setters2.List{
|
||||
Name: r.List.Name,
|
||||
OpenAPIFileName: openAPIFileName,
|
||||
}
|
||||
resourcePath := strings.TrimSuffix(openAPIPath, openAPIFileName)
|
||||
fmt.Fprintf(c.OutOrStdout(), "%s\n", resourcePath)
|
||||
if err := r.ListSetters(c, openAPIPath, resourcePath); err != nil {
|
||||
return err
|
||||
}
|
||||
if r.IncludeSubst {
|
||||
if err := r.ListSubstitutions(c, openAPIPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -75,13 +101,9 @@ func (r *ListSettersRunner) runE(c *cobra.Command, args []string) error {
|
||||
return handleError(c, lookup(r.Lookup, c, args))
|
||||
}
|
||||
|
||||
func (r *ListSettersRunner) ListSetters(c *cobra.Command, args []string) error {
|
||||
func (r *ListSettersRunner) ListSetters(c *cobra.Command, openAPIPath, resourcePath string) error {
|
||||
// use setters v2
|
||||
path, err := ext.GetOpenAPIFile(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.List.ListSetters(path, args[0]); err != nil {
|
||||
if err := r.List.ListSetters(openAPIPath, resourcePath); err != nil {
|
||||
return err
|
||||
}
|
||||
table := newTable(c.OutOrStdout(), r.Markdown)
|
||||
@@ -115,13 +137,9 @@ func (r *ListSettersRunner) ListSetters(c *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ListSettersRunner) ListSubstitutions(c *cobra.Command, args []string) error {
|
||||
func (r *ListSettersRunner) ListSubstitutions(c *cobra.Command, openAPIPath string) error {
|
||||
// use setters v2
|
||||
path, err := ext.GetOpenAPIFile(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.List.ListSubst(path); err != nil {
|
||||
if err := r.List.ListSubst(openAPIPath); err != nil {
|
||||
return err
|
||||
}
|
||||
table := newTable(c.OutOrStdout(), r.Markdown)
|
||||
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/cmd/config/ext"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
|
||||
"sigs.k8s.io/kustomize/kyaml/openapi"
|
||||
)
|
||||
@@ -408,27 +408,19 @@ openAPI:
|
||||
openapi.ResetOpenAPI()
|
||||
defer openapi.ResetOpenAPI()
|
||||
|
||||
f, err := ioutil.TempFile("", "k8s-cli-")
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
defer os.Remove(f.Name())
|
||||
old := ext.GetOpenAPIFile
|
||||
defer func() { ext.GetOpenAPIFile = old }()
|
||||
ext.GetOpenAPIFile = func(args []string) (s string, err error) {
|
||||
err = ioutil.WriteFile(f.Name(), []byte(test.openapi), 0600)
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
return f.Name(), nil
|
||||
}
|
||||
|
||||
r, err := ioutil.TempFile("", "k8s-cli-*.yaml")
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(dir, "Krmfile"), []byte(test.openapi), 0600)
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
defer os.Remove(r.Name())
|
||||
err = ioutil.WriteFile(r.Name(), []byte(test.input), 0600)
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(dir, "deployment.yaml"), []byte(test.input), 0600)
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
@@ -436,18 +428,18 @@ openAPI:
|
||||
runner := commands.NewListSettersRunner("")
|
||||
actual := &bytes.Buffer{}
|
||||
runner.Command.SetOut(actual)
|
||||
runner.Command.SetArgs(append([]string{r.Name()}, test.args...))
|
||||
runner.Command.SetArgs(append([]string{dir}, test.args...))
|
||||
err = runner.Command.Execute()
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !assert.Equal(t, test.expected, actual.String()) {
|
||||
if !assert.Contains(t, actual.String(), test.expected) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// make sure that the resources are not altered
|
||||
actualResources, err := ioutil.ReadFile(r.Name())
|
||||
actualResources, err := ioutil.ReadFile(filepath.Join(dir, "deployment.yaml"))
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
@@ -457,7 +449,7 @@ openAPI:
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
actualOpenAPI, err := ioutil.ReadFile(f.Name())
|
||||
actualOpenAPI, err := ioutil.ReadFile(filepath.Join(dir, "Krmfile"))
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
@@ -469,3 +461,57 @@ openAPI:
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListSettersSubPackages(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
dataset string
|
||||
args []string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "list-replicas",
|
||||
dataset: "dataset1",
|
||||
args: []string{"--include-subst"},
|
||||
expected: `test/testdata/dataset1/mysql/
|
||||
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||
image mysql 1 No
|
||||
namespace myspace 1 No
|
||||
tag 1.7.9 1 No
|
||||
--------------- ----------------- --------------
|
||||
SUBSTITUTION PATTERN REFERENCES
|
||||
image-tag ${image}:${tag} [image,tag]
|
||||
test/testdata/dataset1/mysql/nosetters/
|
||||
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||
test/testdata/dataset1/mysql/storage/
|
||||
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||
namespace myspace 1 No
|
||||
`,
|
||||
},
|
||||
}
|
||||
for i := range tests {
|
||||
test := tests[i]
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
// reset the openAPI afterward
|
||||
openapi.ResetOpenAPI()
|
||||
defer openapi.ResetOpenAPI()
|
||||
dir := filepath.Join("test", "testdata", test.dataset)
|
||||
|
||||
runner := commands.NewListSettersRunner("")
|
||||
actual := &bytes.Buffer{}
|
||||
runner.Command.SetOut(actual)
|
||||
runner.Command.SetArgs(append([]string{dir}, test.args...))
|
||||
err := runner.Command.Execute()
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// normalize path format for windows
|
||||
actualNormalized := strings.Replace(actual.String(), "\\", "/", -1)
|
||||
|
||||
if !assert.Equal(t, test.expected, actualNormalized) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,6 +178,51 @@ items:
|
||||
outputOverride = `apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: mysql-deployment
|
||||
namespace: myspace # {"$openapi":"namespace"}
|
||||
annotations:
|
||||
config.kubernetes.io/index: '0'
|
||||
config.kubernetes.io/path: 'config/mysql-deployment_deployment.yaml'
|
||||
spec:
|
||||
replicas: 3
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: mysql
|
||||
image: mysql:1.7.9 # {"$openapi":"image-tag"}
|
||||
- apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nosetters-deployment
|
||||
namespace: myspace
|
||||
annotations:
|
||||
config.kubernetes.io/index: '0'
|
||||
config.kubernetes.io/path: 'config/nosetters-deployment_deployment.yaml'
|
||||
spec:
|
||||
replicas: 4
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: nosetters
|
||||
image: nosetters:1.7.7
|
||||
- apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: storage-deployment
|
||||
namespace: myspace # {"$openapi":"namespace"}
|
||||
annotations:
|
||||
config.kubernetes.io/index: '0'
|
||||
config.kubernetes.io/path: 'config/storage-deployment_deployment.yaml'
|
||||
spec:
|
||||
replicas: 4
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: storage
|
||||
image: storage:1.7.7
|
||||
- apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
|
||||
@@ -34,7 +34,8 @@ openAPI:
|
||||
`,
|
||||
},
|
||||
expectedStdOut: `
|
||||
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||
./
|
||||
NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
|
||||
replicas 3 1 No
|
||||
`,
|
||||
},
|
||||
|
||||
33
cmd/config/internal/commands/test/testdata/dataset1/mysql/Krmfile
vendored
Normal file
33
cmd/config/internal/commands/test/testdata/dataset1/mysql/Krmfile
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
apiVersion: krm.dev/v1alpha1
|
||||
kind: Krmfile
|
||||
metadata:
|
||||
name: mysql
|
||||
packageMetadata:
|
||||
shortDescription: sample description
|
||||
openAPI:
|
||||
definitions:
|
||||
io.k8s.cli.setters.namespace:
|
||||
x-k8s-cli:
|
||||
setter:
|
||||
name: namespace
|
||||
value: myspace
|
||||
io.k8s.cli.substitutions.image-tag:
|
||||
x-k8s-cli:
|
||||
substitution:
|
||||
name: image-tag
|
||||
pattern: ${image}:${tag}
|
||||
values:
|
||||
- marker: ${image}
|
||||
ref: '#/definitions/io.k8s.cli.setters.image'
|
||||
- marker: ${tag}
|
||||
ref: '#/definitions/io.k8s.cli.setters.tag'
|
||||
io.k8s.cli.setters.image:
|
||||
x-k8s-cli:
|
||||
setter:
|
||||
name: image
|
||||
value: mysql
|
||||
io.k8s.cli.setters.tag:
|
||||
x-k8s-cli:
|
||||
setter:
|
||||
name: tag
|
||||
value: 1.7.9
|
||||
15
cmd/config/internal/commands/test/testdata/dataset1/mysql/deployment.yaml
vendored
Normal file
15
cmd/config/internal/commands/test/testdata/dataset1/mysql/deployment.yaml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# Copyright 2019 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
namespace: myspace # {"$openapi":"namespace"}
|
||||
name: mysql-deployment
|
||||
spec:
|
||||
replicas: 3
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: mysql
|
||||
image: mysql:1.7.9 # {"$openapi":"image-tag"}
|
||||
6
cmd/config/internal/commands/test/testdata/dataset1/mysql/nosetters/Krmfile
vendored
Normal file
6
cmd/config/internal/commands/test/testdata/dataset1/mysql/nosetters/Krmfile
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
apiVersion: krm.dev/v1alpha1
|
||||
kind: Krmfile
|
||||
metadata:
|
||||
name: storage
|
||||
packageMetadata:
|
||||
shortDescription: sample description
|
||||
15
cmd/config/internal/commands/test/testdata/dataset1/mysql/nosetters/deployment.yaml
vendored
Normal file
15
cmd/config/internal/commands/test/testdata/dataset1/mysql/nosetters/deployment.yaml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# Copyright 2019 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
namespace: myspace
|
||||
name: nosetters-deployment
|
||||
spec:
|
||||
replicas: 4
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: nosetters
|
||||
image: nosetters:1.7.7
|
||||
13
cmd/config/internal/commands/test/testdata/dataset1/mysql/storage/Krmfile
vendored
Normal file
13
cmd/config/internal/commands/test/testdata/dataset1/mysql/storage/Krmfile
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
apiVersion: krm.dev/v1alpha1
|
||||
kind: Krmfile
|
||||
metadata:
|
||||
name: storage
|
||||
packageMetadata:
|
||||
shortDescription: sample description
|
||||
openAPI:
|
||||
definitions:
|
||||
io.k8s.cli.setters.namespace:
|
||||
x-k8s-cli:
|
||||
setter:
|
||||
name: namespace
|
||||
value: myspace
|
||||
15
cmd/config/internal/commands/test/testdata/dataset1/mysql/storage/deployment.yaml
vendored
Normal file
15
cmd/config/internal/commands/test/testdata/dataset1/mysql/storage/deployment.yaml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# Copyright 2019 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
namespace: myspace # {"$openapi":"namespace"}
|
||||
name: storage-deployment
|
||||
spec:
|
||||
replicas: 4
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: storage
|
||||
image: storage:1.7.7
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Glossary">
|
||||
<meta itemprop="description" content="Glossary of terms
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Glossary"/>
|
||||
<meta name="twitter:description" content="Glossary of terms
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="API Reference">
|
||||
<meta itemprop="description" content="Reference for Kustomize client-side APIs
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="API Reference"/>
|
||||
<meta name="twitter:description" content="Reference for Kustomize client-side APIs
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="bases">
|
||||
<meta itemprop="description" content="Add resources from a kustomization dir.
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="bases"/>
|
||||
<meta name="twitter:description" content="Add resources from a kustomization dir.
|
||||
"/>
|
||||
@@ -755,7 +756,7 @@
|
||||
|
||||
<p>Move entries into the <a href="/kustomize/api-reference/kustomization/resources">resources</a>
|
||||
field. This allows bases - which are still a
|
||||
<a href="/kustomize/api-reference/kustomization/glossary#base">central concept</a> - to be
|
||||
<a href="/kustomize/api-reference/glossary#base">central concept</a> - to be
|
||||
ordered relative to other input resources.</p>
|
||||
|
||||
<div class="section-index">
|
||||
@@ -812,7 +813,7 @@ ordered relative to other input resources.</p>
|
||||
|
||||
|
||||
|
||||
<div class="text-muted mt-5 pt-3 border-top">Last modified July 16, 2020: <a href="https://github.com/kubernetes-sigs/kustomize/commit/f9ee578aed600136133c3232fff03029cdfc526e">Docs: Auto-fix markdownlint issues (f9ee578a)</a>
|
||||
<div class="text-muted mt-5 pt-3 border-top">Last modified August 20, 2020: <a href="https://github.com/kubernetes-sigs/kustomize/commit/b450b624e8ff259bc52ce85d439b7f58dd548f27">Update dead URL to base in glossary. (b450b624)</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="commonAnnotations">
|
||||
<meta itemprop="description" content="Add annotations to add all resources.
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="commonAnnotations"/>
|
||||
<meta name="twitter:description" content="Add annotations to add all resources.
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="commonLabels">
|
||||
<meta itemprop="description" content="Add labels and selectors to add all resources.
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="commonLabels"/>
|
||||
<meta name="twitter:description" content="Add labels and selectors to add all resources.
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="components">
|
||||
<meta itemprop="description" content="Compose kustomizations.
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="components"/>
|
||||
<meta name="twitter:description" content="Compose kustomizations.
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="configMapGenerator">
|
||||
<meta itemprop="description" content="Generate ConfigMap resources.
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="configMapGenerator"/>
|
||||
<meta name="twitter:description" content="Generate ConfigMap resources.
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="crds">
|
||||
<meta itemprop="description" content="Adding CRD support
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="crds"/>
|
||||
<meta name="twitter:description" content="Adding CRD support
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="generatorOptions">
|
||||
<meta itemprop="description" content="Control behavior of [ConfigMap](/kustomize/api-reference/kustomization/configmapgenerator) and [Secret](/kustomize/api-reference/kustomization/secretgenerator) generators.
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="generatorOptions"/>
|
||||
<meta name="twitter:description" content="Control behavior of [ConfigMap](/kustomize/api-reference/kustomization/configmapgenerator) and [Secret](/kustomize/api-reference/kustomization/secretgenerator) generators.
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="images">
|
||||
<meta itemprop="description" content="Modify the name, tags and/or digest for images.
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="images"/>
|
||||
<meta name="twitter:description" content="Modify the name, tags and/or digest for images.
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="kustomization.yaml">
|
||||
<meta itemprop="description" content="kustomization.yaml fields and API
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="kustomization.yaml"/>
|
||||
<meta name="twitter:description" content="kustomization.yaml fields and API
|
||||
"/>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
<p>Move entries into the <a href="https://kubernetes-sigs.github.io/kustomize/kustomize/api-reference/kustomization/resources">resources</a>
|
||||
field. This allows bases - which are still a
|
||||
<a href="https://kubernetes-sigs.github.io/kustomize/kustomize/api-reference/kustomization/glossary#base">central concept</a> - to be
|
||||
<a href="https://kubernetes-sigs.github.io/kustomize/kustomize/api-reference/glossary#base">central concept</a> - to be
|
||||
ordered relative to other input resources.</p>
|
||||
|
||||
</description>
|
||||
@@ -492,7 +492,80 @@ to it (regular expressions).</p>
|
||||
</span></code></pre></div><p>The <code>name</code> and <code>namespace</code> fields of the patch target selector are
|
||||
automatically anchored regular expressions. This means that the value <code>myapp</code>
|
||||
is equivalent to <code>^myapp$</code>.</p>
|
||||
|
||||
<p>Consider the following <code>deployment.yaml</code> common for both the examples:</p>
|
||||
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#204a87;font-weight:bold">apiVersion</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>apps/v1<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">kind</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>Deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">metadata</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">spec</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">replicas</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#0000cf;font-weight:bold">5</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">template</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">containers</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>- <span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-container<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">image</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>registry/conatiner<span style="color:#000;font-weight:bold">:</span>latest<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span></code></pre></div><h2 id="example-i">Example I</h2>
|
||||
<h3 id="intent">Intent</h3>
|
||||
<p>To Make the container image point to a specific version and not to the latest container in the
|
||||
registry.</p>
|
||||
<h3 id="file-input">File Input</h3>
|
||||
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#8f5902;font-style:italic"># kustomization.yaml</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">resources</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span>- deployment.yaml<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">patches</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span>- <span style="color:#204a87;font-weight:bold">path</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>patch.yaml<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span></code></pre></div><div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#8f5902;font-style:italic"># patch.yaml</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">apiVersion</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>apps/v1<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">kind</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>Deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">metadata</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">spec</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">template</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">containers</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>- <span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-container<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">image</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>registry/conatiner<span style="color:#000;font-weight:bold">:</span><span style="color:#0000cf;font-weight:bold">1.0.0</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span></code></pre></div><h3 id="build-output">Build Output</h3>
|
||||
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#204a87;font-weight:bold">apiVersion</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>apps/v1<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">kind</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>Deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">metadata</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">spec</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">replicas</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#0000cf;font-weight:bold">5</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">template</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">containers</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>- <span style="color:#204a87;font-weight:bold">image</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>registry/conatiner<span style="color:#000;font-weight:bold">:</span><span style="color:#0000cf;font-weight:bold">1.0.0</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-container<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span></code></pre></div><h2 id="example-ii">Example II</h2>
|
||||
<h3 id="intent-1">Intent</h3>
|
||||
<p>To Make the container image point to a specific version and not to the latest container in the
|
||||
registry.</p>
|
||||
<h3 id="file-input-1">File Input</h3>
|
||||
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#8f5902;font-style:italic"># kustomization.yaml</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">resources</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span>- deployment.yaml<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">patches</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span>- <span style="color:#204a87;font-weight:bold">target</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">kind</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>Deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">path</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>patch.json<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span></code></pre></div><div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#8f5902;font-style:italic"># patch.json</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#000;font-weight:bold">[</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>{<span style="color:#204a87;font-weight:bold">&#34;op&#34;: &#34;replace&#34;, &#34;path&#34;: &#34;/spec/template/containers/0/image&#34;, &#34;value&#34;: </span><span style="color:#4e9a06">&#34;registry/conatiner:1.0.0&#34;</span>}<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#000;font-weight:bold">]</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span></code></pre></div><h3 id="build-output-1">Build Output</h3>
|
||||
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#204a87;font-weight:bold">apiVersion</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>apps/v1<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">kind</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>Deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">metadata</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">spec</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">replicas</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#0000cf;font-weight:bold">5</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">template</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">containers</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>- <span style="color:#204a87;font-weight:bold">image</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>registry/conatiner<span style="color:#000;font-weight:bold">:</span><span style="color:#0000cf;font-weight:bold">1.0.0</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-container<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span></code></pre></div>
|
||||
</description>
|
||||
</item>
|
||||
|
||||
@@ -786,7 +859,7 @@ container number 2 of some pod template.</p>
|
||||
can only be placed in particular fields of
|
||||
particular objects as specified by kustomize&rsquo;s
|
||||
configuration data.</p>
|
||||
<p>The default config data for vars is at <a href="https://kubernetes-sigs.github.io/kustomize/konfig/builtinpluginconsts/varreference.go">/api/konfig/builtinpluginconsts/varreference.go</a>
|
||||
<p>The default config data for vars is at <a href="https://github.com/kubernetes-sigs/kustomize/blob/master/api/konfig/builtinpluginconsts/varreference.go">/api/konfig/builtinpluginconsts/varreference.go</a>
|
||||
Long story short, the default targets are all
|
||||
container command args and env value fields.</p>
|
||||
<p>Vars should <em>not</em> be used for inserting names in
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="namePrefix">
|
||||
<meta itemprop="description" content="Prepends the value to the names of all resources and references.
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="namePrefix"/>
|
||||
<meta name="twitter:description" content="Prepends the value to the names of all resources and references.
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="namespace">
|
||||
<meta itemprop="description" content="Adds namespace to all resources.
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="namespace"/>
|
||||
<meta name="twitter:description" content="Adds namespace to all resources.
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="nameSuffix">
|
||||
<meta itemprop="description" content="Appends the value to the names of all resources and references.
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="nameSuffix"/>
|
||||
<meta name="twitter:description" content="Appends the value to the names of all resources and references.
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="patches">
|
||||
<meta itemprop="description" content="Patch resources
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="patches"/>
|
||||
<meta name="twitter:description" content="Patch resources
|
||||
"/>
|
||||
@@ -701,6 +702,25 @@
|
||||
|
||||
|
||||
|
||||
<nav id="TableOfContents">
|
||||
<ul>
|
||||
<li><a href="#example-i">Example I</a>
|
||||
<ul>
|
||||
<li><a href="#intent">Intent</a></li>
|
||||
<li><a href="#file-input">File Input</a></li>
|
||||
<li><a href="#build-output">Build Output</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#example-ii">Example II</a>
|
||||
<ul>
|
||||
<li><a href="#intent-1">Intent</a></li>
|
||||
<li><a href="#file-input-1">File Input</a></li>
|
||||
<li><a href="#build-output-1">Build Output</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
@@ -780,7 +800,80 @@ to it (regular expressions).</p>
|
||||
</span></code></pre></div><p>The <code>name</code> and <code>namespace</code> fields of the patch target selector are
|
||||
automatically anchored regular expressions. This means that the value <code>myapp</code>
|
||||
is equivalent to <code>^myapp$</code>.</p>
|
||||
|
||||
<p>Consider the following <code>deployment.yaml</code> common for both the examples:</p>
|
||||
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#204a87;font-weight:bold">apiVersion</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>apps/v1<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">kind</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>Deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">metadata</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">spec</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">replicas</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#0000cf;font-weight:bold">5</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">template</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">containers</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>- <span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-container<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">image</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>registry/conatiner<span style="color:#000;font-weight:bold">:</span>latest<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span></code></pre></div><h2 id="example-i">Example I</h2>
|
||||
<h3 id="intent">Intent</h3>
|
||||
<p>To Make the container image point to a specific version and not to the latest container in the
|
||||
registry.</p>
|
||||
<h3 id="file-input">File Input</h3>
|
||||
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#8f5902;font-style:italic"># kustomization.yaml</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">resources</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span>- deployment.yaml<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">patches</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span>- <span style="color:#204a87;font-weight:bold">path</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>patch.yaml<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span></code></pre></div><div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#8f5902;font-style:italic"># patch.yaml</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">apiVersion</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>apps/v1<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">kind</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>Deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">metadata</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">spec</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">template</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">containers</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>- <span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-container<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">image</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>registry/conatiner<span style="color:#000;font-weight:bold">:</span><span style="color:#0000cf;font-weight:bold">1.0.0</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span></code></pre></div><h3 id="build-output">Build Output</h3>
|
||||
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#204a87;font-weight:bold">apiVersion</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>apps/v1<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">kind</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>Deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">metadata</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">spec</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">replicas</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#0000cf;font-weight:bold">5</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">template</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">containers</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>- <span style="color:#204a87;font-weight:bold">image</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>registry/conatiner<span style="color:#000;font-weight:bold">:</span><span style="color:#0000cf;font-weight:bold">1.0.0</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-container<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span></code></pre></div><h2 id="example-ii">Example II</h2>
|
||||
<h3 id="intent-1">Intent</h3>
|
||||
<p>To Make the container image point to a specific version and not to the latest container in the
|
||||
registry.</p>
|
||||
<h3 id="file-input-1">File Input</h3>
|
||||
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#8f5902;font-style:italic"># kustomization.yaml</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">resources</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span>- deployment.yaml<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">patches</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span>- <span style="color:#204a87;font-weight:bold">target</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">kind</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>Deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">path</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>patch.json<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span></code></pre></div><div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#8f5902;font-style:italic"># patch.json</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#000;font-weight:bold">[</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>{<span style="color:#204a87;font-weight:bold">"op": "replace", "path": "/spec/template/containers/0/image", "value": </span><span style="color:#4e9a06">"registry/conatiner:1.0.0"</span>}<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#000;font-weight:bold">]</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span></code></pre></div><h3 id="build-output-1">Build Output</h3>
|
||||
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#204a87;font-weight:bold">apiVersion</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>apps/v1<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">kind</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>Deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">metadata</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-deployment<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">spec</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">replicas</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#0000cf;font-weight:bold">5</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">template</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">containers</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span>- <span style="color:#204a87;font-weight:bold">image</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>registry/conatiner<span style="color:#000;font-weight:bold">:</span><span style="color:#0000cf;font-weight:bold">1.0.0</span><span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">name</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>the-container<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span></code></pre></div>
|
||||
<div class="section-index">
|
||||
|
||||
|
||||
@@ -835,7 +928,7 @@ is equivalent to <code>^myapp$</code>.</p>
|
||||
|
||||
|
||||
|
||||
<div class="text-muted mt-5 pt-3 border-top">Last modified July 16, 2020: <a href="https://github.com/kubernetes-sigs/kustomize/commit/f9ee578aed600136133c3232fff03029cdfc526e">Docs: Auto-fix markdownlint issues (f9ee578a)</a>
|
||||
<div class="text-muted mt-5 pt-3 border-top">Last modified August 26, 2020: <a href="https://github.com/kubernetes-sigs/kustomize/commit/fbebd990a4086c967f741ae2d7fd29a24b59845e">Docs update - Patch Examples (fbebd990)</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="patchesJson6902">
|
||||
<meta itemprop="description" content="Patch resources using the [json 6902 standard](https://tools.ietf.org/html/rfc6902)
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="patchesJson6902"/>
|
||||
<meta name="twitter:description" content="Patch resources using the [json 6902 standard](https://tools.ietf.org/html/rfc6902)
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="patchesStrategicMerge">
|
||||
<meta itemprop="description" content="Patch resources using the strategic merge patch standard.
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="patchesStrategicMerge"/>
|
||||
<meta name="twitter:description" content="Patch resources using the strategic merge patch standard.
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="replicas">
|
||||
<meta itemprop="description" content="Change the number of replicas for a resource.
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="replicas"/>
|
||||
<meta name="twitter:description" content="Change the number of replicas for a resource.
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="resources">
|
||||
<meta itemprop="description" content="Resources to include.
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="resources"/>
|
||||
<meta name="twitter:description" content="Resources to include.
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="secretGenerator">
|
||||
<meta itemprop="description" content="Generate Secret resources.
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="secretGenerator"/>
|
||||
<meta name="twitter:description" content="Generate Secret resources.
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="vars">
|
||||
<meta itemprop="description" content="Substitute name references.
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="vars"/>
|
||||
<meta name="twitter:description" content="Substitute name references.
|
||||
"/>
|
||||
@@ -798,7 +799,7 @@ container number 2 of some pod template.</p>
|
||||
can only be placed in particular fields of
|
||||
particular objects as specified by kustomize’s
|
||||
configuration data.</p>
|
||||
<p>The default config data for vars is at <a href="/konfig/builtinpluginconsts/varreference.go">/api/konfig/builtinpluginconsts/varreference.go</a>
|
||||
<p>The default config data for vars is at <a href="https://github.com/kubernetes-sigs/kustomize/blob/master/api/konfig/builtinpluginconsts/varreference.go">/api/konfig/builtinpluginconsts/varreference.go</a>
|
||||
Long story short, the default targets are all
|
||||
container command args and env value fields.</p>
|
||||
<p>Vars should <em>not</em> be used for inserting names in
|
||||
@@ -862,7 +863,7 @@ in the Deployment.</p>
|
||||
|
||||
|
||||
|
||||
<div class="text-muted mt-5 pt-3 border-top">Last modified July 16, 2020: <a href="https://github.com/kubernetes-sigs/kustomize/commit/f9ee578aed600136133c3232fff03029cdfc526e">Docs: Auto-fix markdownlint issues (f9ee578a)</a>
|
||||
<div class="text-muted mt-5 pt-3 border-top">Last modified August 7, 2020: <a href="https://github.com/kubernetes-sigs/kustomize/commit/ca807019f093ebff3c29480f308c54121af58f1a">Add full github link to varreference.go (ca807019)</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -30,13 +30,14 @@
|
||||
<meta itemprop="name" content="v1.0.1">
|
||||
<meta itemprop="description" content="Kustomize v1.0.1
|
||||
">
|
||||
<meta itemprop="datePublished" content="2018-05-21T00:00:00+00:00" />
|
||||
<meta itemprop="datePublished" content="2018-05-21T00:00:00+00:00" />
|
||||
<meta itemprop="dateModified" content="2020-07-16T12:57:18-07:00" />
|
||||
<meta itemprop="wordCount" content="45">
|
||||
|
||||
|
||||
|
||||
<meta itemprop="keywords" content="" /><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="keywords" content="" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="v1.0.1"/>
|
||||
<meta name="twitter:description" content="Kustomize v1.0.1
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -30,13 +30,14 @@
|
||||
<meta itemprop="name" content="v2.0.0">
|
||||
<meta itemprop="description" content="Kustomize v2.0.0
|
||||
">
|
||||
<meta itemprop="datePublished" content="2019-02-05T00:00:00+00:00" />
|
||||
<meta itemprop="datePublished" content="2019-02-05T00:00:00+00:00" />
|
||||
<meta itemprop="dateModified" content="2020-06-07T21:07:46-07:00" />
|
||||
<meta itemprop="wordCount" content="458">
|
||||
|
||||
|
||||
|
||||
<meta itemprop="keywords" content="" /><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="keywords" content="" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="v2.0.0"/>
|
||||
<meta name="twitter:description" content="Kustomize v2.0.0
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -30,13 +30,14 @@
|
||||
<meta itemprop="name" content="v2.1.0">
|
||||
<meta itemprop="description" content="Kustomize v2.1.0
|
||||
">
|
||||
<meta itemprop="datePublished" content="2019-06-18T00:00:00+00:00" />
|
||||
<meta itemprop="datePublished" content="2019-06-18T00:00:00+00:00" />
|
||||
<meta itemprop="dateModified" content="2020-07-16T12:57:18-07:00" />
|
||||
<meta itemprop="wordCount" content="920">
|
||||
|
||||
|
||||
|
||||
<meta itemprop="keywords" content="" /><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="keywords" content="" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="v2.1.0"/>
|
||||
<meta name="twitter:description" content="Kustomize v2.1.0
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -30,13 +30,14 @@
|
||||
<meta itemprop="name" content="v3.0.0">
|
||||
<meta itemprop="description" content="Kustomize v3.0.0
|
||||
">
|
||||
<meta itemprop="datePublished" content="2019-07-03T00:00:00+00:00" />
|
||||
<meta itemprop="datePublished" content="2019-07-03T00:00:00+00:00" />
|
||||
<meta itemprop="dateModified" content="2020-07-16T12:57:18-07:00" />
|
||||
<meta itemprop="wordCount" content="324">
|
||||
|
||||
|
||||
|
||||
<meta itemprop="keywords" content="" /><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="keywords" content="" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="v3.0.0"/>
|
||||
<meta name="twitter:description" content="Kustomize v3.0.0
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -30,13 +30,14 @@
|
||||
<meta itemprop="name" content="v3.1.0">
|
||||
<meta itemprop="description" content="Kustomize v3.1.0
|
||||
">
|
||||
<meta itemprop="datePublished" content="2019-07-26T00:00:00+00:00" />
|
||||
<meta itemprop="datePublished" content="2019-07-26T00:00:00+00:00" />
|
||||
<meta itemprop="dateModified" content="2020-07-16T12:57:18-07:00" />
|
||||
<meta itemprop="wordCount" content="362">
|
||||
|
||||
|
||||
|
||||
<meta itemprop="keywords" content="" /><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="keywords" content="" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="v3.1.0"/>
|
||||
<meta name="twitter:description" content="Kustomize v3.1.0
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -30,13 +30,14 @@
|
||||
<meta itemprop="name" content="v3.2.0">
|
||||
<meta itemprop="description" content="Kustomize v3.2.0
|
||||
">
|
||||
<meta itemprop="datePublished" content="2019-09-17T00:00:00+00:00" />
|
||||
<meta itemprop="datePublished" content="2019-09-17T00:00:00+00:00" />
|
||||
<meta itemprop="dateModified" content="2020-07-16T12:57:18-07:00" />
|
||||
<meta itemprop="wordCount" content="103">
|
||||
|
||||
|
||||
|
||||
<meta itemprop="keywords" content="" /><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="keywords" content="" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="v3.2.0"/>
|
||||
<meta name="twitter:description" content="Kustomize v3.2.0
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -30,13 +30,14 @@
|
||||
<meta itemprop="name" content="v3.2.1">
|
||||
<meta itemprop="description" content="Kustomize v3.2.1
|
||||
">
|
||||
<meta itemprop="datePublished" content="2019-09-26T00:00:00+00:00" />
|
||||
<meta itemprop="datePublished" content="2019-09-26T00:00:00+00:00" />
|
||||
<meta itemprop="dateModified" content="2020-06-07T21:07:46-07:00" />
|
||||
<meta itemprop="wordCount" content="63">
|
||||
|
||||
|
||||
|
||||
<meta itemprop="keywords" content="" /><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="keywords" content="" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="v3.2.1"/>
|
||||
<meta name="twitter:description" content="Kustomize v3.2.1
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -30,13 +30,14 @@
|
||||
<meta itemprop="name" content="v3.3.0">
|
||||
<meta itemprop="description" content="Kustomize v3.3.0
|
||||
">
|
||||
<meta itemprop="datePublished" content="2019-10-24T00:00:00+00:00" />
|
||||
<meta itemprop="datePublished" content="2019-10-24T00:00:00+00:00" />
|
||||
<meta itemprop="dateModified" content="2020-07-16T12:57:18-07:00" />
|
||||
<meta itemprop="wordCount" content="863">
|
||||
|
||||
|
||||
|
||||
<meta itemprop="keywords" content="" /><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="keywords" content="" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="v3.3.0"/>
|
||||
<meta name="twitter:description" content="Kustomize v3.3.0
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
<meta property="og:url" content="https://kubernetes-sigs.github.io/kustomize/blog/" />
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Kustomize Blog">
|
||||
<meta itemprop="description" content="Kubernetes Configuration Customization"><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="description" content="Kubernetes Configuration Customization">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Kustomize Blog"/>
|
||||
<meta name="twitter:description" content="Kubernetes Configuration Customization"/>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
<meta property="og:url" content="https://kubernetes-sigs.github.io/kustomize/blog/releases/" />
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="New Releases">
|
||||
<meta itemprop="description" content="Kubernetes Configuration Customization"><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="description" content="Kubernetes Configuration Customization">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="New Releases"/>
|
||||
<meta name="twitter:description" content="Kubernetes Configuration Customization"/>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Filing Bugs">
|
||||
<meta itemprop="description" content="How to file bugs and fix Kustomize bugs
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Filing Bugs"/>
|
||||
<meta name="twitter:description" content="How to file bugs and fix Kustomize bugs
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Community Engagment">
|
||||
<meta itemprop="description" content="Joining SIG-CLI and the Kubernetes community
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Community Engagment"/>
|
||||
<meta name="twitter:description" content="Joining SIG-CLI and the Kubernetes community
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Writing Docs">
|
||||
<meta itemprop="description" content="How to make Kustomize docs contributions
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Writing Docs"/>
|
||||
<meta name="twitter:description" content="How to make Kustomize docs contributions
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Contributing Features">
|
||||
<meta itemprop="description" content="How to contribute features
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Contributing Features"/>
|
||||
<meta name="twitter:description" content="How to contribute features
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Writing Code">
|
||||
<meta itemprop="description" content="How to modify Kustomize
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Writing Code"/>
|
||||
<meta name="twitter:description" content="How to modify Kustomize
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
<meta property="og:url" content="https://kubernetes-sigs.github.io/kustomize/contributing/" />
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Contributing">
|
||||
<meta itemprop="description" content="Kubernetes Configuration Customization"><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="description" content="Kubernetes Configuration Customization">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Contributing"/>
|
||||
<meta name="twitter:description" content="Kubernetes Configuration Customization"/>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="MacOS Dev Guide">
|
||||
<meta itemprop="description" content="How to develop on MacOS
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="MacOS Dev Guide"/>
|
||||
<meta name="twitter:description" content="How to develop on MacOS
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Windows Dev Guide">
|
||||
<meta itemprop="description" content="How to develop on Windows
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Windows Dev Guide"/>
|
||||
<meta name="twitter:description" content="How to develop on Windows
|
||||
"/>
|
||||
|
||||
@@ -274,7 +274,7 @@
|
||||
|
||||
<url>
|
||||
<loc>https://kubernetes-sigs.github.io/kustomize/guides/plugins/</loc>
|
||||
<lastmod>2020-07-17T12:03:19-07:00</lastmod>
|
||||
<lastmod>2020-07-19T19:52:54+01:00</lastmod>
|
||||
<xhtml:link
|
||||
rel="alternate"
|
||||
hreflang="zh"
|
||||
@@ -469,7 +469,7 @@
|
||||
|
||||
<url>
|
||||
<loc>https://kubernetes-sigs.github.io/kustomize/api-reference/kustomization/bases/</loc>
|
||||
<lastmod>2020-07-16T12:57:18-07:00</lastmod>
|
||||
<lastmod>2020-08-20T08:18:47+05:45</lastmod>
|
||||
<xhtml:link
|
||||
rel="alternate"
|
||||
hreflang="zh"
|
||||
@@ -619,7 +619,7 @@
|
||||
|
||||
<url>
|
||||
<loc>https://kubernetes-sigs.github.io/kustomize/faq/</loc>
|
||||
<lastmod>2020-07-16T12:57:18-07:00</lastmod>
|
||||
<lastmod>2020-07-22T09:27:07-07:00</lastmod>
|
||||
<xhtml:link
|
||||
rel="alternate"
|
||||
hreflang="zh"
|
||||
@@ -759,7 +759,7 @@
|
||||
|
||||
<url>
|
||||
<loc>https://kubernetes-sigs.github.io/kustomize/api-reference/kustomization/patches/</loc>
|
||||
<lastmod>2020-07-16T12:57:18-07:00</lastmod>
|
||||
<lastmod>2020-08-26T17:46:29+05:30</lastmod>
|
||||
<xhtml:link
|
||||
rel="alternate"
|
||||
hreflang="zh"
|
||||
@@ -864,7 +864,7 @@
|
||||
|
||||
<url>
|
||||
<loc>https://kubernetes-sigs.github.io/kustomize/api-reference/kustomization/vars/</loc>
|
||||
<lastmod>2020-07-16T12:57:18-07:00</lastmod>
|
||||
<lastmod>2020-08-07T22:23:18+02:00</lastmod>
|
||||
<xhtml:link
|
||||
rel="alternate"
|
||||
hreflang="zh"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Eschewed Features">
|
||||
<meta itemprop="description" content="Eschewed Features
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Eschewed Features"/>
|
||||
<meta name="twitter:description" content="Eschewed Features
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
<meta property="og:url" content="https://kubernetes-sigs.github.io/kustomize/faq/" />
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="FAQ">
|
||||
<meta itemprop="description" content="Kubernetes Configuration Customization"><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="description" content="Kubernetes Configuration Customization">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="FAQ"/>
|
||||
<meta name="twitter:description" content="Kubernetes Configuration Customization"/>
|
||||
|
||||
@@ -386,7 +387,7 @@ relocatability.</p>
|
||||
|
||||
|
||||
|
||||
<div class="text-muted mt-5 pt-3 border-top">Last modified July 16, 2020: <a href="https://github.com/kubernetes-sigs/kustomize/commit/f9ee578aed600136133c3232fff03029cdfc526e">Docs: Auto-fix markdownlint issues (f9ee578a)</a>
|
||||
<div class="text-muted mt-5 pt-3 border-top">Last modified July 22, 2020: <a href="https://github.com/kubernetes-sigs/kustomize/commit/c6524f984cfeb7b173cdc005ad2d900044bc6033">Docs: Update FAQ with why kubectl has kustomize 2 (c6524f98)</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
|
||||
|
||||
|
||||
<meta itemprop="keywords" content="" /><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="keywords" content="" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Versioning Policy"/>
|
||||
<meta name="twitter:description" content="Running kustomize means one is running a particular version of a program (a CLI), using a particular version of underlying packages (a Go API), and reading a particular version of a kustomization file.
|
||||
If you’re having trouble with go get, please read Go API Versioning and be patient.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Bespoke Application">
|
||||
<meta itemprop="description" content="Workflow for bespoke applications
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Bespoke Application"/>
|
||||
<meta name="twitter:description" content="Workflow for bespoke applications
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Kustomize Components">
|
||||
<meta itemprop="description" content="Kustomize components guide
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Kustomize Components"/>
|
||||
<meta name="twitter:description" content="Kustomize components guide
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Guides">
|
||||
<meta itemprop="description" content="Reference for Kustomize CLI commands
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Guides"/>
|
||||
<meta name="twitter:description" content="Reference for Kustomize CLI commands
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Off The Shelf Application">
|
||||
<meta itemprop="description" content="Workflow for off the shelf applications
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Off The Shelf Application"/>
|
||||
<meta name="twitter:description" content="Workflow for off the shelf applications
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
|
||||
|
||||
|
||||
<meta itemprop="keywords" content="" /><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="keywords" content="" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Builtin Plugins"/>
|
||||
<meta name="twitter:description" content="Builtin Plugins
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
|
||||
|
||||
|
||||
<meta itemprop="keywords" content="" /><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="keywords" content="" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Exec plugin on linux"/>
|
||||
<meta name="twitter:description" content="Exec plugin on linux in 60 seconds
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
|
||||
|
||||
|
||||
<meta itemprop="keywords" content="" /><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="keywords" content="" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Go plugin Caveats"/>
|
||||
<meta name="twitter:description" content="Go plugin Caveats
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
|
||||
|
||||
|
||||
<meta itemprop="keywords" content="" /><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="keywords" content="" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Go plugin example"/>
|
||||
<meta name="twitter:description" content="Go plugin example
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Kustomize Plugins">
|
||||
<meta itemprop="description" content="Kustomize plugins guide
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Kustomize Plugins"/>
|
||||
<meta name="twitter:description" content="Kustomize plugins guide
|
||||
"/>
|
||||
@@ -586,7 +587,12 @@ marshalled resources on <code>stdin</code> and capture
|
||||
</blockquote>
|
||||
<p><strong><code>kustomize.config.k8s.io/needs-hash</code></strong></p>
|
||||
<p>Resources can be marked as needing to be processed by the internal hash transformer by including the <code>needs-hash</code> annotation. When set valid values for the annotation are <code>"true"</code> and <code>"false"</code> which respectively enable or disable hash suffixing for the resource. Omitting the annotation is equivalent to setting the value <code>"false"</code>.</p>
|
||||
<p>If this annotation is set on a resource not supported by the hash transformer the build will fail.</p>
|
||||
<p>Hashes are determined as follows:</p>
|
||||
<ul>
|
||||
<li>For <code>ConfigMap</code> resources, hashes are based on the values of the <code>name</code>, <code>data</code>, and <code>binaryData</code> fields.</li>
|
||||
<li>For <code>Secret</code> resources, hashes are based on the values of the <code>name</code>, <code>type</code>, <code>data</code>, and <code>stringData</code> fields.</li>
|
||||
<li>For any other object type, hashes are based on the entire object content (i.e. all fields).</li>
|
||||
</ul>
|
||||
<p>Example:</p>
|
||||
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#204a87;font-weight:bold">apiVersion</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>v1<span style="color:#f8f8f8;text-decoration:underline">
|
||||
</span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#204a87;font-weight:bold">kind</span><span style="color:#000;font-weight:bold">:</span><span style="color:#f8f8f8;text-decoration:underline"> </span>ConfigMap<span style="color:#f8f8f8;text-decoration:underline">
|
||||
@@ -732,7 +738,7 @@ go build -buildmode plugin \
|
||||
|
||||
|
||||
|
||||
<div class="text-muted mt-5 pt-3 border-top">Last modified July 17, 2020: <a href="https://github.com/kubernetes-sigs/kustomize/commit/bc581b70bf74e42fc2845c1cfc18e8fc6fbd8956">Fix go plugins caveats link (bc581b70)</a>
|
||||
<div class="text-muted mt-5 pt-3 border-top">Last modified July 19, 2020: <a href="https://github.com/kubernetes-sigs/kustomize/commit/4fbe565b369267585e2dbfb3613fde57edb07db2">Allow hash suffixing of arbitrary types (4fbe565b)</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
<meta property="og:url" content="https://kubernetes-sigs.github.io/kustomize/" />
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Kustomize">
|
||||
<meta itemprop="description" content="Kubernetes Configuration Customization"><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="description" content="Kubernetes Configuration Customization">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Kustomize"/>
|
||||
<meta name="twitter:description" content="Kubernetes Configuration Customization"/>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
|
||||
|
||||
|
||||
<meta itemprop="keywords" content="" /><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="keywords" content="" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content=""/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Binaries">
|
||||
<meta itemprop="description" content="Install Kustomize by downloading precompiled binaries.
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Binaries"/>
|
||||
<meta name="twitter:description" content="Install Kustomize by downloading precompiled binaries.
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Chocolatey">
|
||||
<meta itemprop="description" content="Install Kustomize for Windows using Chocolatey
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Chocolatey"/>
|
||||
<meta name="twitter:description" content="Install Kustomize for Windows using Chocolatey
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Homebrew / MacPorts">
|
||||
<meta itemprop="description" content="Install Kustomize for MacOS using Homebrew or MacPorts
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Homebrew / MacPorts"/>
|
||||
<meta name="twitter:description" content="Install Kustomize for MacOS using Homebrew or MacPorts
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
<meta property="og:url" content="https://kubernetes-sigs.github.io/kustomize/installation/" />
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Installation">
|
||||
<meta itemprop="description" content="Kubernetes Configuration Customization"><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="description" content="Kubernetes Configuration Customization">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Installation"/>
|
||||
<meta name="twitter:description" content="Kubernetes Configuration Customization"/>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
<meta property="og:site_name" content="Kustomize" />
|
||||
<meta itemprop="name" content="Go Source">
|
||||
<meta itemprop="description" content="Install Kustomize from the Go source code
|
||||
"><meta name="twitter:card" content="summary"/>
|
||||
">
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Go Source"/>
|
||||
<meta name="twitter:description" content="Install Kustomize from the Go source code
|
||||
"/>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="generator" content="Hugo 0.73.0-DEV" />
|
||||
<meta name="generator" content="Hugo 0.74.3" />
|
||||
|
||||
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
|
||||
|
||||
|
||||
<meta itemprop="keywords" content="" /><meta name="twitter:card" content="summary"/>
|
||||
<meta itemprop="keywords" content="" />
|
||||
<meta name="twitter:card" content="summary"/>
|
||||
<meta name="twitter:title" content="Search Results"/>
|
||||
<meta name="twitter:description" content=""/>
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user