Merge pull request #462 from monopole/fixTransformConfigNames

Fix names/doc in transformation config code.
This commit is contained in:
k8s-ci-robot
2018-10-12 13:41:49 -07:00
committed by GitHub
27 changed files with 475 additions and 305 deletions

View File

@@ -24,8 +24,6 @@ import (
"sigs.k8s.io/kustomize/pkg/transformers"
)
// nameHashTransformer contains the prefix and the path config for each field that
// the name prefix will be applied.
type nameHashTransformer struct{}
var _ transformers.Transformer = &nameHashTransformer{}

View File

@@ -102,7 +102,7 @@ func (o *saveOptions) Complete(fsys fs.FileSystem) error {
// RunSave saves the default transformer configurations local directory
func (o *saveOptions) RunSave(fsys fs.FileSystem) error {
m := defaultconfig.GetDefaultPathConfigStrings()
m := defaultconfig.GetDefaultFieldSpecsAsMap()
for tname, tcfg := range m {
filename := filepath.Join(o.saveDirectory, tname+".yaml")
err := fsys.WriteFile(filename, []byte(tcfg))

View File

@@ -132,8 +132,8 @@ func (kt *KustTarget) loadCustomizedResMap() (resmap.ResMap, error) {
if err != nil {
errs.Append(errors.Wrap(err, "loadResMapFromBasesAndResources"))
}
crdPathConfigs, err := config.NewFactory(kt.ldr).LoadCRDs(kt.kustomization.Crds)
kt.tcfg = kt.tcfg.Merge(crdPathConfigs)
crdTc, err := config.NewFactory(kt.ldr).LoadCRDs(kt.kustomization.Crds)
kt.tcfg = kt.tcfg.Merge(crdTc)
if err != nil {
errs.Append(errors.Wrap(err, "LoadCRDs"))
}

View File

@@ -16,7 +16,7 @@ limitations under the License.
package defaultconfig
const commonAnnotationPathConfigs = `
const commonAnnotationFieldSpecs = `
commonAnnotations:
- path: metadata/annotations
create: true

View File

@@ -16,7 +16,7 @@ limitations under the License.
package defaultconfig
const commonLabelPathConfigs = `
const commonLabelFieldSpecs = `
commonLabels:
- path: metadata/labels
create: true

View File

@@ -22,27 +22,28 @@ import (
"bytes"
)
// GetDefaultPathConfigs returns the default pathConfigs data
func GetDefaultPathConfigs() []byte {
// GetDefaultFieldSpecs returns default fieldSpecs.
func GetDefaultFieldSpecs() []byte {
configData := [][]byte{
[]byte(namePrefixPathConfigs),
[]byte(commonLabelPathConfigs),
[]byte(commonAnnotationPathConfigs),
[]byte(namespacePathConfigs),
[]byte(varReferencePathConfigs),
[]byte(nameReferencePathConfigs),
[]byte(namePrefixFieldSpecs),
[]byte(commonLabelFieldSpecs),
[]byte(commonAnnotationFieldSpecs),
[]byte(namespaceFieldSpecs),
[]byte(varReferenceFieldSpecs),
[]byte(nameReferenceFieldSpecs),
}
return bytes.Join(configData, []byte("\n"))
}
// GetDefaultPathConfigStrings returns the default pathConfigs in string format
func GetDefaultPathConfigStrings() map[string]string {
// GetDefaultFieldSpecsAsMap returns default fieldSpecs
// as a string->string map.
func GetDefaultFieldSpecsAsMap() map[string]string {
result := make(map[string]string)
result["nameprefix"] = namePrefixPathConfigs
result["commonlabels"] = commonLabelPathConfigs
result["commonannotations"] = commonAnnotationPathConfigs
result["namespace"] = namespacePathConfigs
result["varreference"] = varReferencePathConfigs
result["namereference"] = namespacePathConfigs
result["nameprefix"] = namePrefixFieldSpecs
result["commonlabels"] = commonLabelFieldSpecs
result["commonannotations"] = commonAnnotationFieldSpecs
result["namespace"] = namespaceFieldSpecs
result["varreference"] = varReferenceFieldSpecs
result["namereference"] = nameReferenceFieldSpecs
return result
}

View File

@@ -17,7 +17,7 @@ limitations under the License.
package defaultconfig
const (
namePrefixPathConfigs = `
namePrefixFieldSpecs = `
namePrefix:
- path: metadata/name
`

View File

@@ -17,26 +17,26 @@ limitations under the License.
package defaultconfig
const (
nameReferencePathConfigs = `
nameReferenceFieldSpecs = `
nameReference:
- kind: Deployment
pathConfigs:
fieldSpecs:
- path: spec/scaleTargetRef/name
kind: HorizontalPodAutoscaler
- kind: ReplicationController
pathConfigs:
fieldSpecs:
- path: spec/scaleTargetRef/name
kind: HorizontalPodAutoscaler
- kind: ReplicaSet
pathConfigs:
fieldSpecs:
- path: spec/scaleTargetRef/name
kind: HorizontalPodAutoscaler
- kind: ConfigMap
version: v1
pathConfigs:
fieldSpecs:
- path: spec/volumes/configMap/name
version: v1
kind: Pod
@@ -119,7 +119,7 @@ nameReference:
- kind: Secret
version: v1
pathConfigs:
fieldSpecs:
- path: spec/volumes/secret/secretName
version: v1
kind: Pod
@@ -229,7 +229,7 @@ nameReference:
- kind: Service
version: v1
pathConfigs:
fieldSpecs:
- path: spec/serviceName
kind: StatefulSet
group: apps
@@ -240,14 +240,14 @@ nameReference:
- kind: Role
group: rbac.authorization.k8s.io
pathConfigs:
fieldSpecs:
- path: roleRef/name
kind: RoleBinding
group: rbac.authorization.k8s.io
- kind: ClusterRole
group: rbac.authorization.k8s.io
pathConfigs:
fieldSpecs:
- path: roleRef/name
kind: RoleBinding
group: rbac.authorization.k8s.io
@@ -257,7 +257,7 @@ nameReference:
- kind: ServiceAccount
version: v1
pathConfigs:
fieldSpecs:
- path: subjects/name
kind: RoleBinding
group: rbac.authorization.k8s.io
@@ -281,7 +281,7 @@ nameReference:
- kind: PersistentVolumeClaim
version: v1
pathConfigs:
fieldSpecs:
- path: spec/volumes/persistentVolumeClaim/claimName
kind: Pod
- path: spec/template/spec/volumes/persistentVolumeClaim/claimName
@@ -299,7 +299,7 @@ nameReference:
- kind: PersistentVolume
version: v1
pathConfigs:
fieldSpecs:
- path: spec/volumeName
kind: PersistentVolumeClaim
`

View File

@@ -17,7 +17,7 @@ limitations under the License.
package defaultconfig
const (
namespacePathConfigs = `
namespaceFieldSpecs = `
namespace:
- path: metadata/namespace
create: true

View File

@@ -17,7 +17,7 @@ limitations under the License.
package defaultconfig
const (
varReferencePathConfigs = `
varReferenceFieldSpecs = `
varReference:
- path: spec/template/spec/initContainers/command
kind: StatefulSet

View File

@@ -78,7 +78,7 @@ func (tf *Factory) EmptyConfig() *TransformerConfig {
// This should never fail, hence the Fatal panic.
func (tf *Factory) DefaultConfig() *TransformerConfig {
c, err := makeTransformerConfigFromBytes(
defaultconfig.GetDefaultPathConfigs())
defaultconfig.GetDefaultFieldSpecs())
if err != nil {
log.Fatalf("Unable to make default transformconfig: %v", err)
}

View File

@@ -41,7 +41,7 @@ namePrefix:
fakeFS.WriteFile("transformerconfig/test/config.yaml", []byte(transformerConfig))
ldr := loader.NewFileLoader(fakeFS)
expected := &TransformerConfig{
NamePrefix: []PathConfig{
NamePrefix: []FieldSpec{
{
Gvk: gvk.Gvk{Kind: "SomeKind"},
Path: "nameprefix/path",

View File

@@ -27,15 +27,15 @@ import (
// LoadCRDs parse CRD schemas from paths into a TransformerConfig
func (tf *Factory) LoadCRDs(paths []string) (*TransformerConfig, error) {
pathConfigs := tf.EmptyConfig()
tc := tf.EmptyConfig()
for _, path := range paths {
pathConfig, err := tf.loadCRD(path)
otherTc, err := tf.loadCRD(path)
if err != nil {
return nil, err
}
pathConfigs = pathConfigs.Merge(pathConfig)
tc = tc.Merge(otherTc)
}
return pathConfigs, nil
return tc, nil
}
func (tf *Factory) loadCRD(path string) (*TransformerConfig, error) {
@@ -57,13 +57,13 @@ func (tf *Factory) loadCRD(path string) (*TransformerConfig, error) {
crds := getCRDs(types)
for crd, k := range crds {
crdPathConfigs := tf.EmptyConfig()
err = getCRDPathConfig(
types, crd, crd, k, []string{}, crdPathConfigs)
tc := tf.EmptyConfig()
err = loadCrdIntoConfig(
types, crd, crd, k, []string{}, tc)
if err != nil {
return result, err
}
result = result.Merge(crdPathConfigs)
result = result.Merge(tc)
}
return result, nil
@@ -88,10 +88,11 @@ func getCRDs(types map[string]common.OpenAPIDefinition) map[string]gvk.Gvk {
return crds
}
// getCRDPathConfig gets pathConfigs for one CRD recursively
func getCRDPathConfig(
types map[string]common.OpenAPIDefinition, atype string, crd string, in gvk.Gvk,
path []string, configs *TransformerConfig) error {
// loadCrdIntoConfig loads a CRD spec into a TransformerConfig
func loadCrdIntoConfig(
types map[string]common.OpenAPIDefinition,
atype string, crd string, in gvk.Gvk,
path []string, config *TransformerConfig) error {
if _, ok := types[crd]; !ok {
return nil
}
@@ -99,8 +100,8 @@ func getCRDPathConfig(
for propname, property := range types[atype].Schema.SchemaProps.Properties {
_, annotate := property.Extensions.GetString(Annotation)
if annotate {
configs.AddAnnotationPathConfig(
PathConfig{
config.AddAnnotationFieldSpec(
FieldSpec{
CreateIfNotPresent: false,
Gvk: in,
Path: strings.Join(append(path, propname), "/"),
@@ -109,8 +110,8 @@ func getCRDPathConfig(
}
_, label := property.Extensions.GetString(LabelSelector)
if label {
configs.AddLabelPathConfig(
PathConfig{
config.AddLabelFieldSpec(
FieldSpec{
CreateIfNotPresent: false,
Gvk: in,
Path: strings.Join(append(path, propname), "/"),
@@ -119,8 +120,8 @@ func getCRDPathConfig(
}
_, identity := property.Extensions.GetString(Identity)
if identity {
configs.AddPrefixPathConfig(
PathConfig{
config.AddPrefixFieldSpec(
FieldSpec{
CreateIfNotPresent: false,
Gvk: in,
Path: strings.Join(append(path, propname), "/"),
@@ -135,9 +136,9 @@ func getCRDPathConfig(
if !ok {
nameKey = "name"
}
configs.AddNamereferencePathConfig(ReferencePathConfig{
config.AddNamereferenceFieldSpec(NameBackReferences{
Gvk: gvk.Gvk{Kind: kind, Version: version},
PathConfigs: []PathConfig{
FieldSpecs: []FieldSpec{
{
CreateIfNotPresent: false,
Gvk: in,
@@ -149,7 +150,9 @@ func getCRDPathConfig(
}
if property.Ref.GetURL() != nil {
getCRDPathConfig(types, property.Ref.String(), crd, in, append(path, propname), configs)
loadCrdIntoConfig(
types, property.Ref.String(), crd, in,
append(path, propname), config)
}
}
return nil

View File

@@ -25,6 +25,12 @@ import (
"sigs.k8s.io/kustomize/pkg/internal/loadertest"
)
// This defines two CRD's: Bee and MyKind.
//
// Bee is boring, it's spec has no dependencies.
//
// MyKind, however, has a spec that contains
// a Bee and a (k8s native) Secret.
const (
crdContent = `
{
@@ -149,10 +155,10 @@ func makeLoader(t *testing.T) ifc.Loader {
}
func TestLoadCRDs(t *testing.T) {
refpathconfigs := []ReferencePathConfig{
nbrs := []NameBackReferences{
{
Gvk: gvk.Gvk{Kind: "Secret", Version: "v1"},
PathConfigs: []PathConfig{
FieldSpecs: []FieldSpec{
{
CreateIfNotPresent: false,
Gvk: gvk.Gvk{Kind: "MyKind"},
@@ -162,7 +168,7 @@ func TestLoadCRDs(t *testing.T) {
},
{
Gvk: gvk.Gvk{Kind: "Bee", Version: "v1beta1"},
PathConfigs: []PathConfig{
FieldSpecs: []FieldSpec{
{
CreateIfNotPresent: false,
Gvk: gvk.Gvk{Kind: "MyKind"},
@@ -172,14 +178,14 @@ func TestLoadCRDs(t *testing.T) {
},
}
expected := &TransformerConfig{
NameReference: refpathconfigs,
expectedTc := &TransformerConfig{
NameReference: nbrs,
}
pathconfig, _ := NewFactory(makeLoader(t)).LoadCRDs(
actualTc, _ := NewFactory(makeLoader(t)).LoadCRDs(
[]string{"/testpath/crd.json"})
if !reflect.DeepEqual(pathconfig, expected) {
t.Fatalf("expected\n %v\n but got\n %v\n", expected, pathconfig)
if !reflect.DeepEqual(actualTc, expectedTc) {
t.Fatalf("expected\n %v\n but got\n %v\n", expectedTc, actualTc)
}
}

View File

@@ -0,0 +1,87 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"fmt"
"strings"
"sigs.k8s.io/kustomize/pkg/gvk"
)
// FieldSpec completely specifies a kustomizable field in
// an unstructured representation of a k8s API object.
// It helps define the operands of transformations.
//
// For example, a directive to add a common label to objects
// will need to know that a 'Deployment' object (in API group
// 'apps', any version) can have labels at field path
// 'spec/template/metadata/labels', and further that it is OK
// (or not OK) to add that field path to the object if the
// field path doesn't exist already.
//
// This would look like
// {
// group: apps
// kind: Deployment
// path: spec/template/metadata/labels
// create: true
// }
type FieldSpec struct {
gvk.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
Path string `json:"path,omitempty" yaml:"path,omitempty"`
CreateIfNotPresent bool `json:"create,omitempty" yaml:"create,omitempty"`
}
const (
escapedForwardSlash = "\\/"
tempSlashReplacement = "???"
)
func (fs FieldSpec) String() string {
return fmt.Sprintf(
"%s:%v:%s", fs.Gvk.String(), fs.CreateIfNotPresent, fs.Path)
}
// PathSlice converts the path string to a slice of strings,
// separated by a '/'. Forward slash can be contained in a
// fieldname. such as ingress.kubernetes.io/auth-secret in
// Ingress annotations. To deal with this special case, the
// path to this field should be formatted as
//
// metadata/annotations/ingress.kubernetes.io\/auth-secret
//
// Then PathSlice will return
//
// []string{
// "metadata",
// "annotations",
// "ingress.auth-secretkubernetes.io/auth-secret"
// }
func (fs FieldSpec) PathSlice() []string {
if !strings.Contains(fs.Path, escapedForwardSlash) {
return strings.Split(fs.Path, "/")
}
s := strings.Replace(fs.Path, escapedForwardSlash, tempSlashReplacement, -1)
paths := strings.Split(s, "/")
var result []string
for _, path := range paths {
result = append(result, strings.Replace(path, tempSlashReplacement, "/", -1))
}
return result
}

View File

@@ -37,8 +37,8 @@ func TestPathSlice(t *testing.T) {
},
}
for _, p := range paths {
pathConfig := PathConfig{Path: p.input}
actual := pathConfig.PathSlice()
fs := FieldSpec{Path: p.input}
actual := fs.PathSlice()
if !reflect.DeepEqual(actual, p.parsed) {
t.Fatalf("expected %v, but got %v", p.parsed, actual)
}

View File

@@ -0,0 +1,91 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"sigs.k8s.io/kustomize/pkg/gvk"
"strings"
)
// NameBackReferences is an association between a gvk.GVK and a list
// of FieldSpec instances that could refer to it.
//
// It is used to handle name changes, and can be thought of as a
// a contact list. If you change your own contact info (name,
// phone number, etc.), you must tell your contacts or they won't
// know about the change.
//
// For example, ConfigMaps can be used by Pods and everything that
// contains a Pod; Deployment, Job, StatefulSet, etc. To change
// the name of a ConfigMap instance from 'alice' to 'bob', one
// must visit all objects that could refer to the ConfigMap, see if
// they mention 'alice', and if so, change the reference to 'bob'.
//
// The NameBackReferences instance to aid in this could look like
// {
// kind: ConfigMap
// version: v1
// FieldSpecs:
// - kind: Pod
// version: v1
// path: spec/volumes/configMap/name
// - kind: Deployment
// path: spec/template/spec/volumes/configMap/name
// - kind: Job
// path: spec/template/spec/volumes/configMap/name
// (etc.)
// }
type NameBackReferences struct {
gvk.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
FieldSpecs []FieldSpec `json:"FieldSpecs,omitempty" yaml:"FieldSpecs,omitempty"`
}
func (n NameBackReferences) String() string {
var r []string
for _, f := range n.FieldSpecs {
r = append(r, f.String())
}
return n.Gvk.String() + ": (\n" +
strings.Join(r, "\n") + "\n)"
}
func mergeNameBackReferences(
a, b []NameBackReferences) []NameBackReferences {
for _, r := range b {
a = merge(a, r)
}
return a
}
func merge(
backRefsSlice []NameBackReferences,
other NameBackReferences) []NameBackReferences {
var result []NameBackReferences
found := false
for _, c := range backRefsSlice {
if c.Equals(other.Gvk) {
c.FieldSpecs = append(c.FieldSpecs, other.FieldSpecs...)
found = true
}
result = append(result, c)
}
if !found {
result = append(result, other)
}
return result
}

View File

@@ -0,0 +1,106 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"reflect"
"sigs.k8s.io/kustomize/pkg/gvk"
"testing"
)
func TestFoo(t *testing.T) {
fsSlice1 := []FieldSpec{
{
Gvk: gvk.Gvk{
Kind: "Pod",
},
Path: "path/to/a/name",
CreateIfNotPresent: false,
},
{
Gvk: gvk.Gvk{
Kind: "Deployment",
},
Path: "another/path/to/some/name",
CreateIfNotPresent: false,
},
}
fsSlice2 := []FieldSpec{
{
Gvk: gvk.Gvk{
Kind: "Job",
},
Path: "morepath/to/name",
CreateIfNotPresent: false,
},
{
Gvk: gvk.Gvk{
Kind: "StatefulSet",
},
Path: "yet/another/path/to/a/name",
CreateIfNotPresent: false,
},
}
nbrsSlice1 := []NameBackReferences{
{
Gvk: gvk.Gvk{
Kind: "ConfigMap",
},
FieldSpecs: fsSlice1,
},
{
Gvk: gvk.Gvk{
Kind: "Secret",
},
FieldSpecs: fsSlice2,
},
}
nbrsSlice2 := []NameBackReferences{
{
Gvk: gvk.Gvk{
Kind: "ConfigMap",
},
FieldSpecs: fsSlice1,
},
{
Gvk: gvk.Gvk{
Kind: "Secret",
},
FieldSpecs: fsSlice2,
},
}
expected := []NameBackReferences{
{
Gvk: gvk.Gvk{
Kind: "ConfigMap",
},
// Current behavior allows repeats of FieldSpec
FieldSpecs: append(fsSlice1, fsSlice1...),
},
{
Gvk: gvk.Gvk{
Kind: "Secret",
},
FieldSpecs: append(fsSlice2, fsSlice2...),
},
}
actual := mergeNameBackReferences(nbrsSlice1, nbrsSlice2)
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("expected\n %v\n but got\n %v\n", expected, actual)
}
}

View File

@@ -1,60 +0,0 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"strings"
"sigs.k8s.io/kustomize/pkg/gvk"
)
// PathConfig contains the configuration of a field, including the gvk it ties to,
// path to the field, etc.
type PathConfig struct {
gvk.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
Path string `json:"path,omitempty" yaml:"path,omitempty"`
CreateIfNotPresent bool `json:"create,omitempty" yaml:"create,omitempty"`
}
const (
escapedForwardSlash = "\\/"
tempSlashReplacement = "???"
)
// PathSlice converts the path string to a slice of strings, separated by "/"
// "/" can be contained in a fieldname.
// such as ingress.kubernetes.io/auth-secret in Ingress annotations.
// To deal with this special case, the path to this field should be formatted as
//
// metadata/annotations/ingress.kubernetes.io\/auth-secret
//
// Then PathSlice will return
//
// []string{"metadata", "annotations", "ingress.auth-secretkubernetes.io/auth-secret"}
func (p PathConfig) PathSlice() []string {
if !strings.Contains(p.Path, escapedForwardSlash) {
return strings.Split(p.Path, "/")
}
s := strings.Replace(p.Path, escapedForwardSlash, tempSlashReplacement, -1)
paths := strings.Split(s, "/")
var result []string
for _, path := range paths {
result = append(result, strings.Replace(path, tempSlashReplacement, "/", -1))
}
return result
}

View File

@@ -1,64 +0,0 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"sigs.k8s.io/kustomize/pkg/gvk"
)
// ReferencePathConfig contains the configuration of a field that references
// the name of another resource whose GroupVersionKind is specified in referencedGVK.
// e.g. pod.spec.template.volumes.configMap.name references the name of a configmap
// Its corresponding referencePathConfig will look like:
//
// ReferencePathConfig{
// referencedGVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
// pathConfigs: []PathConfig{
// {
// GroupVersionKind: &schema.GroupVersionKind{Version: "v1", Kind: "Pod"},
// Path: []string{"spec", "volumes", "configMap", "name"},
// },
// }
type ReferencePathConfig struct {
gvk.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
// PathConfig is the gvk that is referencing the referencedGVK object's name.
PathConfigs []PathConfig `json:"pathConfigs,omitempty" yaml:"pathConfigs,omitempty"`
}
func merge(configs []ReferencePathConfig, config ReferencePathConfig) []ReferencePathConfig {
var result []ReferencePathConfig
found := false
for _, c := range configs {
if c.Equals(config.Gvk) {
c.PathConfigs = append(c.PathConfigs, config.PathConfigs...)
found = true
}
result = append(result, c)
}
if !found {
result = append(result, config)
}
return result
}
func mergeNameReferencePathConfigs(a, b []ReferencePathConfig) []ReferencePathConfig {
for _, r := range b {
a = merge(a, r)
}
return a
}

View File

@@ -22,30 +22,30 @@ import (
"sort"
)
type rpcSlice []ReferencePathConfig
type nbrSlice []NameBackReferences
func (s rpcSlice) Len() int { return len(s) }
func (s rpcSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s rpcSlice) Less(i, j int) bool {
func (s nbrSlice) Len() int { return len(s) }
func (s nbrSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s nbrSlice) Less(i, j int) bool {
return s[i].Gvk.IsLessThan(s[j].Gvk)
}
type pcSlice []PathConfig
type fsSlice []FieldSpec
func (s pcSlice) Len() int { return len(s) }
func (s pcSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s pcSlice) Less(i, j int) bool {
func (s fsSlice) Len() int { return len(s) }
func (s fsSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s fsSlice) Less(i, j int) bool {
return s[i].Gvk.IsLessThan(s[j].Gvk)
}
// TransformerConfig represents the path configurations for different transformations
// TransformerConfig holds the data needed to perform transformations.
type TransformerConfig struct {
NamePrefix pcSlice `json:"namePrefix,omitempty" yaml:"namePrefix,omitempty"`
NameSpace pcSlice `json:"namespace,omitempty" yaml:"namespace,omitempty"`
CommonLabels pcSlice `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"`
CommonAnnotations pcSlice `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"`
NameReference rpcSlice `json:"nameReference,omitempty" yaml:"nameReference,omitempty"`
VarReference pcSlice `json:"varReference,omitempty" yaml:"varReference,omitempty"`
NamePrefix fsSlice `json:"namePrefix,omitempty" yaml:"namePrefix,omitempty"`
NameSpace fsSlice `json:"namespace,omitempty" yaml:"namespace,omitempty"`
CommonLabels fsSlice `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"`
CommonAnnotations fsSlice `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"`
NameReference nbrSlice `json:"nameReference,omitempty" yaml:"nameReference,omitempty"`
VarReference fsSlice `json:"varReference,omitempty" yaml:"varReference,omitempty"`
}
// sortFields provides determinism in logging, tests, etc.
@@ -58,24 +58,24 @@ func (t *TransformerConfig) sortFields() {
sort.Sort(t.VarReference)
}
// AddPrefixPathConfig adds a PathConfig to NamePrefix
func (t *TransformerConfig) AddPrefixPathConfig(config PathConfig) {
t.NamePrefix = append(t.NamePrefix, config)
// AddPrefixFieldSpec adds a FieldSpec to NamePrefix
func (t *TransformerConfig) AddPrefixFieldSpec(fs FieldSpec) {
t.NamePrefix = append(t.NamePrefix, fs)
}
// AddLabelPathConfig adds a PathConfig to CommonLabels
func (t *TransformerConfig) AddLabelPathConfig(config PathConfig) {
t.CommonLabels = append(t.CommonLabels, config)
// AddLabelFieldSpec adds a FieldSpec to CommonLabels
func (t *TransformerConfig) AddLabelFieldSpec(fs FieldSpec) {
t.CommonLabels = append(t.CommonLabels, fs)
}
// AddAnnotationPathConfig adds a PathConfig to CommonAnnotations
func (t *TransformerConfig) AddAnnotationPathConfig(config PathConfig) {
t.CommonAnnotations = append(t.CommonAnnotations, config)
// AddAnnotationFieldSpec adds a FieldSpec to CommonAnnotations
func (t *TransformerConfig) AddAnnotationFieldSpec(fs FieldSpec) {
t.CommonAnnotations = append(t.CommonAnnotations, fs)
}
// AddNamereferencePathConfig adds a ReferencePathConfig to NameReference
func (t *TransformerConfig) AddNamereferencePathConfig(config ReferencePathConfig) {
t.NameReference = mergeNameReferencePathConfigs(t.NameReference, []ReferencePathConfig{config})
// AddNamereferenceFieldSpec adds a NameBackReferences to NameReference
func (t *TransformerConfig) AddNamereferenceFieldSpec(nbrs NameBackReferences) {
t.NameReference = mergeNameBackReferences(t.NameReference, []NameBackReferences{nbrs})
}
// Merge merges two TransformerConfigs objects into a new TransformerConfig object
@@ -86,7 +86,7 @@ func (t *TransformerConfig) Merge(input *TransformerConfig) *TransformerConfig {
merged.CommonAnnotations = append(t.CommonAnnotations, input.CommonAnnotations...)
merged.CommonLabels = append(t.CommonLabels, input.CommonLabels...)
merged.VarReference = append(t.VarReference, input.VarReference...)
merged.NameReference = mergeNameReferencePathConfigs(t.NameReference, input.NameReference)
merged.NameReference = mergeNameBackReferences(t.NameReference, input.NameReference)
merged.sortFields()
return merged
}

View File

@@ -24,14 +24,14 @@ import (
"sigs.k8s.io/kustomize/pkg/gvk"
)
func TestAddNameReferencePathConfigs(t *testing.T) {
func TestAddNamereferenceFieldSpec(t *testing.T) {
cfg := &TransformerConfig{}
pathConfig := ReferencePathConfig{
nbrs := NameBackReferences{
Gvk: gvk.Gvk{
Kind: "KindA",
},
PathConfigs: []PathConfig{
FieldSpecs: []FieldSpec{
{
Gvk: gvk.Gvk{
Kind: "KindB",
@@ -42,42 +42,42 @@ func TestAddNameReferencePathConfigs(t *testing.T) {
},
}
cfg.AddNamereferencePathConfig(pathConfig)
cfg.AddNamereferenceFieldSpec(nbrs)
if len(cfg.NameReference) != 1 {
t.Fatal("failed to add namerefence pathconfig")
t.Fatal("failed to add namerefence FieldSpec")
}
}
func TestAddPathConfigs(t *testing.T) {
func TestAddFieldSpecs(t *testing.T) {
cfg := &TransformerConfig{}
pathConfig := PathConfig{
fieldSpec := FieldSpec{
Gvk: gvk.Gvk{Group: "GroupA", Kind: "KindB"},
Path: "path/to/a/field",
CreateIfNotPresent: true,
}
cfg.AddPrefixPathConfig(pathConfig)
cfg.AddPrefixFieldSpec(fieldSpec)
if len(cfg.NamePrefix) != 1 {
t.Fatalf("failed to add nameprefix pathconfig")
t.Fatalf("failed to add nameprefix FieldSpec")
}
cfg.AddLabelPathConfig(pathConfig)
cfg.AddLabelFieldSpec(fieldSpec)
if len(cfg.CommonLabels) != 1 {
t.Fatalf("failed to add nameprefix pathconfig")
t.Fatalf("failed to add nameprefix FieldSpec")
}
cfg.AddAnnotationPathConfig(pathConfig)
cfg.AddAnnotationFieldSpec(fieldSpec)
if len(cfg.CommonAnnotations) != 1 {
t.Fatalf("failed to add nameprefix pathconfig")
t.Fatalf("failed to add nameprefix FieldSpec")
}
}
func TestMerge(t *testing.T) {
nameReference := []ReferencePathConfig{
nameReference := []NameBackReferences{
{
Gvk: gvk.Gvk{
Kind: "KindA",
},
PathConfigs: []PathConfig{
FieldSpecs: []FieldSpec{
{
Gvk: gvk.Gvk{
Kind: "KindB",
@@ -91,7 +91,7 @@ func TestMerge(t *testing.T) {
Gvk: gvk.Gvk{
Kind: "KindA",
},
PathConfigs: []PathConfig{
FieldSpecs: []FieldSpec{
{
Gvk: gvk.Gvk{
Kind: "KindC",
@@ -102,7 +102,7 @@ func TestMerge(t *testing.T) {
},
},
}
pathConfigs := []PathConfig{
fieldSpecs := []FieldSpec{
{
Gvk: gvk.Gvk{Group: "GroupA", Kind: "KindB"},
Path: "path/to/a/field",
@@ -115,28 +115,28 @@ func TestMerge(t *testing.T) {
},
}
cfga := &TransformerConfig{}
cfga.AddNamereferencePathConfig(nameReference[0])
cfga.AddPrefixPathConfig(pathConfigs[0])
cfga.AddNamereferenceFieldSpec(nameReference[0])
cfga.AddPrefixFieldSpec(fieldSpecs[0])
cfgb := &TransformerConfig{}
cfgb.AddNamereferencePathConfig(nameReference[1])
cfgb.AddPrefixPathConfig(pathConfigs[1])
cfgb.AddNamereferenceFieldSpec(nameReference[1])
cfgb.AddPrefixFieldSpec(fieldSpecs[1])
actual := cfga.Merge(cfgb)
if len(actual.NamePrefix) != 2 {
t.Fatal("merge failed for namePrefix pathconfig")
t.Fatal("merge failed for namePrefix FieldSpec")
}
if len(actual.NameReference) != 1 {
t.Fatal("merge failed for namereference pathconfig")
t.Fatal("merge failed for namereference FieldSpec")
}
expected := &TransformerConfig{}
expected.AddNamereferencePathConfig(nameReference[0])
expected.AddNamereferencePathConfig(nameReference[1])
expected.AddPrefixPathConfig(pathConfigs[0])
expected.AddPrefixPathConfig(pathConfigs[1])
expected.AddNamereferenceFieldSpec(nameReference[0])
expected.AddNamereferenceFieldSpec(nameReference[1])
expected.AddPrefixFieldSpec(fieldSpecs[0])
expected.AddPrefixFieldSpec(fieldSpecs[1])
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("expected: %v\n but got: %v\n", expected, actual)

View File

@@ -24,34 +24,36 @@ import (
"sigs.k8s.io/kustomize/pkg/transformers/config"
)
// mapTransformer contains a map string->string and path configs
// The map will be applied to the fields specified in path configs.
// mapTransformer applies a string->string map to fieldSpecs.
type mapTransformer struct {
m map[string]string
pathConfigs []config.PathConfig
m map[string]string
fieldSpecs []config.FieldSpec
}
var _ Transformer = &mapTransformer{}
// NewLabelsMapTransformer construct a mapTransformer with a given pathConfig slice
func NewLabelsMapTransformer(m map[string]string, p []config.PathConfig) (Transformer, error) {
return NewMapTransformer(p, m)
// NewLabelsMapTransformer constructs a mapTransformer.
func NewLabelsMapTransformer(
m map[string]string, fs []config.FieldSpec) (Transformer, error) {
return NewMapTransformer(fs, m)
}
// NewAnnotationsMapTransformer construct a mapTransformer with a given pathConfig slice
func NewAnnotationsMapTransformer(m map[string]string, p []config.PathConfig) (Transformer, error) {
return NewMapTransformer(p, m)
// NewAnnotationsMapTransformer construct a mapTransformer.
func NewAnnotationsMapTransformer(
m map[string]string, fs []config.FieldSpec) (Transformer, error) {
return NewMapTransformer(fs, m)
}
// NewMapTransformer construct a mapTransformer.
func NewMapTransformer(pc []config.PathConfig, m map[string]string) (Transformer, error) {
func NewMapTransformer(
pc []config.FieldSpec, m map[string]string) (Transformer, error) {
if m == nil {
return NewNoOpTransformer(), nil
}
if pc == nil {
return nil, errors.New("pathConfigs is not expected to be nil")
return nil, errors.New("fieldSpecs is not expected to be nil")
}
return &mapTransformer{pathConfigs: pc, m: m}, nil
return &mapTransformer{fieldSpecs: pc, m: m}, nil
}
// Transform apply each <key, value> pair in the mapTransformer to the
@@ -59,7 +61,7 @@ func NewMapTransformer(pc []config.PathConfig, m map[string]string) (Transformer
func (o *mapTransformer) Transform(m resmap.ResMap) error {
for id := range m {
objMap := m[id].Map()
for _, path := range o.pathConfigs {
for _, path := range o.fieldSpecs {
if !id.Gvk().IsSelected(&path.Gvk) {
continue
}

View File

@@ -26,36 +26,36 @@ import (
"sigs.k8s.io/kustomize/pkg/transformers/config"
)
// nameReferenceTransformer contains the referencing info between 2 GroupVersionKinds
type nameReferenceTransformer struct {
pathConfigs []config.ReferencePathConfig
backRefs []config.NameBackReferences
}
var _ Transformer = &nameReferenceTransformer{}
// NewNameReferenceTransformer constructs a nameReferenceTransformer
// with a given Reference PathConfig slice
func NewNameReferenceTransformer(pc []config.ReferencePathConfig) (Transformer, error) {
if pc == nil {
return nil, errors.New("pathConfigs is not expected to be nil")
// with a given slice of NameBackReferences.
func NewNameReferenceTransformer(
br []config.NameBackReferences) (Transformer, error) {
if br == nil {
return nil, errors.New("backrefs not expected to be nil")
}
return &nameReferenceTransformer{pathConfigs: pc}, nil
return &nameReferenceTransformer{backRefs: br}, nil
}
// Transform does the fields update according to pathConfigs.
// Transform does the fields update according to fieldSpecs.
// The old name is in the key in the map and the new name is in the object
// associated with the key. e.g. if <k, v> is one of the key-value pair in the map,
// then the old name is k.Name and the new name is v.GetName()
func (o *nameReferenceTransformer) Transform(m resmap.ResMap) error {
for id := range m {
objMap := m[id].Map()
for _, referencePathConfig := range o.pathConfigs {
for _, path := range referencePathConfig.PathConfigs {
for _, backRef := range o.backRefs {
for _, path := range backRef.FieldSpecs {
if !id.Gvk().IsSelected(&path.Gvk) {
continue
}
err := mutateField(objMap, path.PathSlice(), path.CreateIfNotPresent,
o.updateNameReference(referencePathConfig.Gvk, m.FilterBy(id)))
o.updateNameReference(backRef.Gvk, m.FilterBy(id)))
if err != nil {
return err
}

View File

@@ -23,12 +23,12 @@ import (
)
type namespaceTransformer struct {
namespace string
pathConfigs []config.PathConfig
skipPathConfigs []config.PathConfig
namespace string
fieldSpecsToUse []config.FieldSpec
fieldSpecsToSkip []config.FieldSpec
}
var skipNamespacePathConfigs = []config.PathConfig{
var namespaceFieldSpecsToSkip = []config.FieldSpec{
{
Gvk: gvk.Gvk{
Kind: "Namespace",
@@ -54,15 +54,15 @@ var skipNamespacePathConfigs = []config.PathConfig{
var _ Transformer = &namespaceTransformer{}
// NewNamespaceTransformer construct a namespaceTransformer.
func NewNamespaceTransformer(ns string, cf []config.PathConfig) Transformer {
func NewNamespaceTransformer(ns string, cf []config.FieldSpec) Transformer {
if len(ns) == 0 {
return NewNoOpTransformer()
}
return &namespaceTransformer{
namespace: ns,
pathConfigs: cf,
skipPathConfigs: skipNamespacePathConfigs,
namespace: ns,
fieldSpecsToUse: cf,
fieldSpecsToSkip: namespaceFieldSpecsToSkip,
}
}
@@ -72,7 +72,7 @@ func (o *namespaceTransformer) Transform(m resmap.ResMap) error {
for id := range m {
found := false
for _, path := range o.skipPathConfigs {
for _, path := range o.fieldSpecsToSkip {
if id.Gvk().IsSelected(&path.Gvk) {
found = true
break
@@ -86,7 +86,7 @@ func (o *namespaceTransformer) Transform(m resmap.ResMap) error {
for id := range mf {
objMap := mf[id].Map()
for _, path := range o.pathConfigs {
for _, path := range o.fieldSpecsToUse {
if !id.Gvk().IsSelected(&path.Gvk) {
continue
}

View File

@@ -26,36 +26,36 @@ import (
"sigs.k8s.io/kustomize/pkg/transformers/config"
)
// namePrefixTransformer contains the prefix and the path config for each field that
// the name prefix will be applied.
// namePrefixTransformer contains the prefix and the FieldSpecs
// for each field needing a name prefix.
type namePrefixTransformer struct {
prefix string
pathConfigs []config.PathConfig
skipPathConfigs []config.PathConfig
prefix string
fieldSpecsToUse []config.FieldSpec
fieldSpecsToSkip []config.FieldSpec
}
var _ Transformer = &namePrefixTransformer{}
var skipNamePrefixPathConfigs = []config.PathConfig{
var prefixFieldSpecsToSkip = []config.FieldSpec{
{
Gvk: gvk.Gvk{Kind: "CustomResourceDefinition"},
},
}
// deprecateNamePrefixPathConfig will be moved into skipNamePrefixPathConfigs in next release
var deprecateNamePrefixPathConfig = config.PathConfig{
// deprecateNamePrefixFieldSpec will be moved into prefixFieldSpecsToSkip in next release
var deprecateNamePrefixFieldSpec = config.FieldSpec{
Gvk: gvk.Gvk{Kind: "Namespace"},
}
// NewNamePrefixTransformer construct a namePrefixTransformer.
func NewNamePrefixTransformer(np string, pc []config.PathConfig) (Transformer, error) {
func NewNamePrefixTransformer(np string, pc []config.FieldSpec) (Transformer, error) {
if len(np) == 0 {
return NewNoOpTransformer(), nil
}
if pc == nil {
return nil, errors.New("pathConfigs is not expected to be nil")
return nil, errors.New("fieldSpecs is not expected to be nil")
}
return &namePrefixTransformer{pathConfigs: pc, prefix: np, skipPathConfigs: skipNamePrefixPathConfigs}, nil
return &namePrefixTransformer{fieldSpecsToUse: pc, prefix: np, fieldSpecsToSkip: prefixFieldSpecsToSkip}, nil
}
// Transform prepends the name prefix.
@@ -64,7 +64,7 @@ func (o *namePrefixTransformer) Transform(m resmap.ResMap) error {
for id := range m {
found := false
for _, path := range o.skipPathConfigs {
for _, path := range o.fieldSpecsToSkip {
if id.Gvk().IsSelected(&path.Gvk) {
found = true
break
@@ -77,11 +77,11 @@ func (o *namePrefixTransformer) Transform(m resmap.ResMap) error {
}
for id := range mf {
if id.Gvk().IsSelected(&deprecateNamePrefixPathConfig.Gvk) {
if id.Gvk().IsSelected(&deprecateNamePrefixFieldSpec.Gvk) {
log.Println("Adding nameprefix to Namespace resource will be deprecated in next release.")
}
objMap := mf[id].Map()
for _, path := range o.pathConfigs {
for _, path := range o.fieldSpecsToUse {
if !id.Gvk().IsSelected(&path.Gvk) {
continue
}

View File

@@ -9,15 +9,15 @@ import (
)
type refvarTransformer struct {
pathConfigs []config.PathConfig
vars map[string]string
fieldSpecs []config.FieldSpec
vars map[string]string
}
// NewRefVarTransformer returns a Trasformer that replaces $(VAR) style variables with values.
func NewRefVarTransformer(vars map[string]string, p []config.PathConfig) Transformer {
func NewRefVarTransformer(vars map[string]string, p []config.FieldSpec) Transformer {
return &refvarTransformer{
vars: vars,
pathConfigs: p,
vars: vars,
fieldSpecs: p,
}
}
@@ -33,7 +33,7 @@ func NewRefVarTransformer(vars map[string]string, p []config.PathConfig) Transfo
func (rv *refvarTransformer) Transform(resources resmap.ResMap) error {
for resId := range resources {
objMap := resources[resId].Map()
for _, pc := range rv.pathConfigs {
for _, pc := range rv.fieldSpecs {
if !resId.Gvk().IsSelected(&pc.Gvk) {
continue
}