mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-12 01:14:22 +00:00
add replacement filter to support replacmenttransformer
This commit is contained in:
4
api/filters/replacement/doc.go
Normal file
4
api/filters/replacement/doc.go
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
// Package replacement contains a kio.Filter implementation of the kustomize
|
||||||
|
// replacement transformer (accepts sources and looks for targets to replace
|
||||||
|
// their values with values from the sources).
|
||||||
|
package replacement
|
||||||
68
api/filters/replacement/example_test.go
Normal file
68
api/filters/replacement/example_test.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2021 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package replacement
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleFilter() {
|
||||||
|
f := Filter{}
|
||||||
|
err := yaml.Unmarshal([]byte(`
|
||||||
|
replacements:
|
||||||
|
- source:
|
||||||
|
kind: Foo2
|
||||||
|
fieldPath: spec.replicas
|
||||||
|
targets:
|
||||||
|
- select:
|
||||||
|
kind: Foo1
|
||||||
|
fieldPaths:
|
||||||
|
- spec.replicas`), &f)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = kio.Pipeline{
|
||||||
|
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo1
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
replicas: 3
|
||||||
|
---
|
||||||
|
apiVersion: example.com/v1
|
||||||
|
kind: Foo2
|
||||||
|
metadata:
|
||||||
|
name: instance
|
||||||
|
spec:
|
||||||
|
replicas: 99
|
||||||
|
`)}},
|
||||||
|
Filters: []kio.Filter{f},
|
||||||
|
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
|
||||||
|
}.Execute()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// apiVersion: example.com/v1
|
||||||
|
// kind: Foo1
|
||||||
|
// metadata:
|
||||||
|
// name: instance
|
||||||
|
// spec:
|
||||||
|
// replicas: 99
|
||||||
|
// ---
|
||||||
|
// apiVersion: example.com/v1
|
||||||
|
// kind: Foo2
|
||||||
|
// metadata:
|
||||||
|
// name: instance
|
||||||
|
// spec:
|
||||||
|
// replicas: 99
|
||||||
|
}
|
||||||
123
api/filters/replacement/replacement.go
Normal file
123
api/filters/replacement/replacement.go
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
// Copyright 2021 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package replacement
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/api/resid"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Filter struct {
|
||||||
|
Replacements []types.Replacement
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter replaces values of targets with values from sources
|
||||||
|
// TODO (#3492): Connect this to a replacement transformer plugin
|
||||||
|
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||||
|
for _, r := range f.Replacements {
|
||||||
|
if r.Source == nil || r.Targets == nil {
|
||||||
|
return nil, fmt.Errorf("replacements must specify a source and at least one target")
|
||||||
|
}
|
||||||
|
value, err := getReplacement(nodes, &r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nodes, err = applyReplacement(nodes, value, r.Targets)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyReplacement(nodes []*yaml.RNode, value *yaml.RNode, targets []*types.TargetSelector) ([]*yaml.RNode, error) {
|
||||||
|
for _, t := range targets {
|
||||||
|
if len(t.FieldPaths) == 0 {
|
||||||
|
t.FieldPaths = []string{types.DefaultReplacementFieldPath}
|
||||||
|
}
|
||||||
|
for _, n := range nodes {
|
||||||
|
// TODO (#3492): Don't include matches listed in the `reject` field
|
||||||
|
if t.Select.KrmId.Match(getKrmId(n)) {
|
||||||
|
err := applyToNode(n, value, t)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyToNode(node *yaml.RNode, value *yaml.RNode, target *types.TargetSelector) error {
|
||||||
|
if target.Select == nil {
|
||||||
|
return fmt.Errorf("target must specify resources to select")
|
||||||
|
}
|
||||||
|
for _, fp := range target.FieldPaths {
|
||||||
|
fieldPath := strings.Split(fp, ".")
|
||||||
|
// TODO (#3492): Add tests for map keys in the fieldPath (e.g. .spec.containers[name=nginx])
|
||||||
|
t, err := node.Pipe(yaml.Lookup(fieldPath...))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if t != nil {
|
||||||
|
// TODO (#3492): Use the field options to refine interpretation of the field
|
||||||
|
t.SetYNode(value.YNode())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getReplacement(nodes []*yaml.RNode, r *types.Replacement) (*yaml.RNode, error) {
|
||||||
|
source, err := selectSourceNode(nodes, r.Source)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Source.FieldPath == "" {
|
||||||
|
r.Source.FieldPath = types.DefaultReplacementFieldPath
|
||||||
|
}
|
||||||
|
fieldPath := strings.Split(r.Source.FieldPath, ".")
|
||||||
|
|
||||||
|
// TODO (#3492): Add tests for map keys in the fieldPath (e.g. .spec.containers[name=nginx])
|
||||||
|
rn, err := source.Pipe(yaml.Lookup(fieldPath...))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// TODO (#3492): Use the field options to refine interpretation of the field
|
||||||
|
return rn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// selectSourceNode finds the node that matches the selector, returning
|
||||||
|
// an error if multiple or none are found
|
||||||
|
func selectSourceNode(nodes []*yaml.RNode, selector *types.SourceSelector) (*yaml.RNode, error) {
|
||||||
|
var matches []*yaml.RNode
|
||||||
|
for _, n := range nodes {
|
||||||
|
if selector.KrmId.Match(getKrmId(n)) {
|
||||||
|
if len(matches) > 0 {
|
||||||
|
return nil, fmt.Errorf("more than one match for source %v", selector)
|
||||||
|
}
|
||||||
|
matches = append(matches, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(matches) == 0 {
|
||||||
|
return nil, fmt.Errorf("found no matches for source %v", selector)
|
||||||
|
}
|
||||||
|
return matches[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getKrmId(n *yaml.RNode) *types.KrmId {
|
||||||
|
ns, _ := n.GetNamespace()
|
||||||
|
apiVersion := yaml.GetValue(n.Field(yaml.APIVersionField).Value)
|
||||||
|
group, version := resid.ParseGroupVersion(apiVersion)
|
||||||
|
|
||||||
|
return &types.KrmId{
|
||||||
|
Gvk: resid.Gvk{Group: group, Version: version, Kind: n.GetKind()},
|
||||||
|
Name: n.GetName(),
|
||||||
|
Namespace: ns,
|
||||||
|
}
|
||||||
|
}
|
||||||
336
api/filters/replacement/replacement_test.go
Normal file
336
api/filters/replacement/replacement_test.go
Normal file
@@ -0,0 +1,336 @@
|
|||||||
|
// Copyright 2021 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package replacement
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
filtertest "sigs.k8s.io/kustomize/api/testutils/filtertest"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFilter(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
input string
|
||||||
|
replacements string
|
||||||
|
expected string
|
||||||
|
expectedErr bool
|
||||||
|
}{
|
||||||
|
"simple": {
|
||||||
|
input: `apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy2
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
`,
|
||||||
|
replacements: `replacements:
|
||||||
|
- source:
|
||||||
|
kind: Deployment
|
||||||
|
name: deploy2
|
||||||
|
fieldPath: spec.template.spec.containers.0.image
|
||||||
|
targets:
|
||||||
|
- select:
|
||||||
|
kind: Deployment
|
||||||
|
name: deploy1
|
||||||
|
fieldPaths:
|
||||||
|
- spec.template.spec.containers.1.image
|
||||||
|
`,
|
||||||
|
expected: `apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: postgresdb
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy2
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"complex type": {
|
||||||
|
input: `apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: pod
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: busybox
|
||||||
|
name: myapp-container
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy2
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers: {}
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy3
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers: {}
|
||||||
|
`,
|
||||||
|
replacements: `replacements:
|
||||||
|
- source:
|
||||||
|
kind: Pod
|
||||||
|
name: pod
|
||||||
|
fieldPath: spec.containers
|
||||||
|
targets:
|
||||||
|
- select:
|
||||||
|
kind: Deployment
|
||||||
|
fieldPaths:
|
||||||
|
- spec.template.spec.containers
|
||||||
|
`,
|
||||||
|
expected: `apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: pod
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: busybox
|
||||||
|
name: myapp-container
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy2
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: busybox
|
||||||
|
name: myapp-container
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy3
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: busybox
|
||||||
|
name: myapp-container
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"from ConfigMap": {
|
||||||
|
input: `apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy
|
||||||
|
labels:
|
||||||
|
foo: bar
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
foo: bar
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: command-demo-container
|
||||||
|
image: debian
|
||||||
|
command: ["printenv"]
|
||||||
|
args:
|
||||||
|
- HOSTNAME
|
||||||
|
- PORT
|
||||||
|
- name: busybox
|
||||||
|
image: busybox:latest
|
||||||
|
args:
|
||||||
|
- echo
|
||||||
|
- HOSTNAME
|
||||||
|
- PORT
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: cm
|
||||||
|
data:
|
||||||
|
HOSTNAME: example.com
|
||||||
|
PORT: 8080
|
||||||
|
`,
|
||||||
|
replacements: `replacements:
|
||||||
|
- source:
|
||||||
|
kind: ConfigMap
|
||||||
|
name: cm
|
||||||
|
fieldPath: data.HOSTNAME
|
||||||
|
targets:
|
||||||
|
- select:
|
||||||
|
kind: Deployment
|
||||||
|
fieldPaths:
|
||||||
|
- spec.template.spec.containers.0.args.0
|
||||||
|
- spec.template.spec.containers.1.args.1
|
||||||
|
- source:
|
||||||
|
kind: ConfigMap
|
||||||
|
name: cm
|
||||||
|
fieldPath: data.PORT
|
||||||
|
targets:
|
||||||
|
- select:
|
||||||
|
kind: Deployment
|
||||||
|
fieldPaths:
|
||||||
|
- spec.template.spec.containers.0.args.1
|
||||||
|
- spec.template.spec.containers.1.args.2
|
||||||
|
`,
|
||||||
|
expected: `apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy
|
||||||
|
labels:
|
||||||
|
foo: bar
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
foo: bar
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: command-demo-container
|
||||||
|
image: debian
|
||||||
|
command: ["printenv"]
|
||||||
|
args:
|
||||||
|
- example.com
|
||||||
|
- 8080
|
||||||
|
- name: busybox
|
||||||
|
image: busybox:latest
|
||||||
|
args:
|
||||||
|
- echo
|
||||||
|
- example.com
|
||||||
|
- 8080
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: cm
|
||||||
|
data:
|
||||||
|
HOSTNAME: example.com
|
||||||
|
PORT: 8080
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"multiple matches for source select": {
|
||||||
|
input: `apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy2
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy3
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
`,
|
||||||
|
replacements: `replacements:
|
||||||
|
- source:
|
||||||
|
kind: Deployment
|
||||||
|
targets:
|
||||||
|
- select:
|
||||||
|
kind: Deployment
|
||||||
|
`,
|
||||||
|
expectedErr: true,
|
||||||
|
},
|
||||||
|
"replacement has no source": {
|
||||||
|
input: `apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
`,
|
||||||
|
replacements: `replacements:
|
||||||
|
- targets:
|
||||||
|
- select:
|
||||||
|
kind: Deployment
|
||||||
|
`,
|
||||||
|
expectedErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tn, tc := range testCases {
|
||||||
|
t.Run(tn, func(t *testing.T) {
|
||||||
|
f := Filter{}
|
||||||
|
err := yaml.Unmarshal([]byte(tc.replacements), &f)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
actual, err := filtertest.RunFilterE(t, tc.input, f)
|
||||||
|
assert.Equal(t, tc.expectedErr, err != nil)
|
||||||
|
if !tc.expectedErr &&
|
||||||
|
!assert.Equal(t, strings.TrimSpace(tc.expected), strings.TrimSpace(actual)) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,8 +4,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
server "sigs.k8s.io/kustomize/api/internal/crawl/backend"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
server "sigs.k8s.io/kustomize/api/internal/crawl/backend"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ func (gc githubCrawler) Crawl(ctx context.Context,
|
|||||||
output chan<- crawler.CrawledDocument, seen utils.SeenMap) error {
|
output chan<- crawler.CrawledDocument, seen utils.SeenMap) error {
|
||||||
|
|
||||||
ranges := []RangeWithin{
|
ranges := []RangeWithin{
|
||||||
RangeWithin{
|
{
|
||||||
start: uint64(0),
|
start: uint64(0),
|
||||||
end: githubMaxFileSize,
|
end: githubMaxFileSize,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -96,6 +96,6 @@ func TestRangeSizes(t *testing.T) {
|
|||||||
returnedResult := RangeSizes(s)
|
returnedResult := RangeSizes(s)
|
||||||
expectedResult := RangeWithin{uint64(2365), uint64(10000)}
|
expectedResult := RangeWithin{uint64(2365), uint64(10000)}
|
||||||
if !reflect.DeepEqual(returnedResult, expectedResult) {
|
if !reflect.DeepEqual(returnedResult, expectedResult) {
|
||||||
t.Errorf("RangeSizes expected (%v), got (%v)",expectedResult, returnedResult)
|
t.Errorf("RangeSizes expected (%v), got (%v)", expectedResult, returnedResult)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,13 +61,13 @@ func TestFindPatchTargets(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
"select_01": {
|
"select_01": {
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Name: "name.*",
|
KrmId: types.KrmId{Name: "name.*"},
|
||||||
},
|
},
|
||||||
count: 3,
|
count: 3,
|
||||||
},
|
},
|
||||||
"select_02": {
|
"select_02": {
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Name: "name.*",
|
KrmId: types.KrmId{Name: "name.*"},
|
||||||
AnnotationSelector: "foo=bar",
|
AnnotationSelector: "foo=bar",
|
||||||
},
|
},
|
||||||
count: 2,
|
count: 2,
|
||||||
@@ -80,98 +80,102 @@ func TestFindPatchTargets(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"select_04": {
|
"select_04": {
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Gvk: resid.Gvk{
|
KrmId: types.KrmId{
|
||||||
Kind: "Kind1",
|
Gvk: resid.Gvk{
|
||||||
|
Kind: "Kind1",
|
||||||
|
},
|
||||||
|
Name: "name.*",
|
||||||
},
|
},
|
||||||
Name: "name.*",
|
|
||||||
},
|
},
|
||||||
count: 2,
|
count: 2,
|
||||||
},
|
},
|
||||||
"select_05": {
|
"select_05": {
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Name: "NotMatched",
|
KrmId: types.KrmId{Name: "NotMatched"},
|
||||||
},
|
},
|
||||||
count: 0,
|
count: 0,
|
||||||
},
|
},
|
||||||
"select_06": {
|
"select_06": {
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Name: "",
|
KrmId: types.KrmId{Name: ""},
|
||||||
},
|
},
|
||||||
count: 4,
|
count: 4,
|
||||||
},
|
},
|
||||||
"select_07": {
|
"select_07": {
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Namespace: "default",
|
KrmId: types.KrmId{Namespace: "default"},
|
||||||
},
|
},
|
||||||
count: 2,
|
count: 2,
|
||||||
},
|
},
|
||||||
"select_08": {
|
"select_08": {
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Namespace: "",
|
KrmId: types.KrmId{Namespace: ""},
|
||||||
},
|
},
|
||||||
count: 4,
|
count: 4,
|
||||||
},
|
},
|
||||||
"select_09": {
|
"select_09": {
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Namespace: "default",
|
KrmId: types.KrmId{
|
||||||
Name: "name.*",
|
Namespace: "default",
|
||||||
Gvk: resid.Gvk{
|
Name: "name.*",
|
||||||
Kind: "Kind1",
|
Gvk: resid.Gvk{
|
||||||
|
Kind: "Kind1",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
count: 1,
|
count: 1,
|
||||||
},
|
},
|
||||||
"select_10": {
|
"select_10": {
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Name: "^name.*",
|
KrmId: types.KrmId{Name: "^name.*"},
|
||||||
},
|
},
|
||||||
count: 3,
|
count: 3,
|
||||||
},
|
},
|
||||||
"select_11": {
|
"select_11": {
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Name: "name.*$",
|
KrmId: types.KrmId{Name: "name.*$"},
|
||||||
},
|
},
|
||||||
count: 3,
|
count: 3,
|
||||||
},
|
},
|
||||||
"select_12": {
|
"select_12": {
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Name: "^name.*$",
|
KrmId: types.KrmId{Name: "^name.*$"},
|
||||||
},
|
},
|
||||||
count: 3,
|
count: 3,
|
||||||
},
|
},
|
||||||
"select_13": {
|
"select_13": {
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Namespace: "^def.*",
|
KrmId: types.KrmId{Namespace: "^def.*"},
|
||||||
},
|
},
|
||||||
count: 2,
|
count: 2,
|
||||||
},
|
},
|
||||||
"select_14": {
|
"select_14": {
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Namespace: "def.*$",
|
KrmId: types.KrmId{Namespace: "def.*$"},
|
||||||
},
|
},
|
||||||
count: 2,
|
count: 2,
|
||||||
},
|
},
|
||||||
"select_15": {
|
"select_15": {
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Namespace: "^def.*$",
|
KrmId: types.KrmId{Namespace: "^def.*$"},
|
||||||
},
|
},
|
||||||
count: 2,
|
count: 2,
|
||||||
},
|
},
|
||||||
"select_16": {
|
"select_16": {
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Namespace: "default",
|
KrmId: types.KrmId{Namespace: "default"},
|
||||||
},
|
},
|
||||||
count: 2,
|
count: 2,
|
||||||
},
|
},
|
||||||
"select_17": {
|
"select_17": {
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Namespace: "NotMatched",
|
KrmId: types.KrmId{Namespace: "NotMatched"},
|
||||||
},
|
},
|
||||||
count: 0,
|
count: 0,
|
||||||
},
|
},
|
||||||
"select_18": {
|
"select_18": {
|
||||||
target: types.Selector{
|
target: types.Selector{
|
||||||
Namespace: "ns1",
|
KrmId: types.KrmId{Namespace: "ns1"},
|
||||||
},
|
},
|
||||||
count: 1,
|
count: 1,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -9,13 +9,15 @@ import (
|
|||||||
|
|
||||||
func TestPatchEquals(t *testing.T) {
|
func TestPatchEquals(t *testing.T) {
|
||||||
selector := Selector{
|
selector := Selector{
|
||||||
Gvk: resid.Gvk{
|
KrmId: KrmId{
|
||||||
Group: "group",
|
Gvk: resid.Gvk{
|
||||||
Version: "version",
|
Group: "group",
|
||||||
Kind: "kind",
|
Version: "version",
|
||||||
|
Kind: "kind",
|
||||||
|
},
|
||||||
|
Name: "name",
|
||||||
|
Namespace: "namespace",
|
||||||
},
|
},
|
||||||
Name: "name",
|
|
||||||
Namespace: "namespace",
|
|
||||||
LabelSelector: "selector",
|
LabelSelector: "selector",
|
||||||
AnnotationSelector: "selector",
|
AnnotationSelector: "selector",
|
||||||
}
|
}
|
||||||
@@ -38,13 +40,15 @@ func TestPatchEquals(t *testing.T) {
|
|||||||
Path: "foo",
|
Path: "foo",
|
||||||
Patch: "bar",
|
Patch: "bar",
|
||||||
Target: &Selector{
|
Target: &Selector{
|
||||||
Gvk: resid.Gvk{
|
KrmId: KrmId{
|
||||||
Group: "group",
|
Gvk: resid.Gvk{
|
||||||
Version: "version",
|
Group: "group",
|
||||||
Kind: "kind",
|
Version: "version",
|
||||||
|
Kind: "kind",
|
||||||
|
},
|
||||||
|
Name: "name",
|
||||||
|
Namespace: "namespace",
|
||||||
},
|
},
|
||||||
Name: "name",
|
|
||||||
Namespace: "namespace",
|
|
||||||
LabelSelector: "selector",
|
LabelSelector: "selector",
|
||||||
AnnotationSelector: "selector",
|
AnnotationSelector: "selector",
|
||||||
},
|
},
|
||||||
@@ -53,13 +57,15 @@ func TestPatchEquals(t *testing.T) {
|
|||||||
Path: "foo",
|
Path: "foo",
|
||||||
Patch: "bar",
|
Patch: "bar",
|
||||||
Target: &Selector{
|
Target: &Selector{
|
||||||
Gvk: resid.Gvk{
|
KrmId: KrmId{
|
||||||
Group: "group",
|
Gvk: resid.Gvk{
|
||||||
Version: "version",
|
Group: "group",
|
||||||
Kind: "kind",
|
Version: "version",
|
||||||
|
Kind: "kind",
|
||||||
|
},
|
||||||
|
Name: "name",
|
||||||
|
Namespace: "namespace",
|
||||||
},
|
},
|
||||||
Name: "name",
|
|
||||||
Namespace: "namespace",
|
|
||||||
LabelSelector: "selector",
|
LabelSelector: "selector",
|
||||||
AnnotationSelector: "selector",
|
AnnotationSelector: "selector",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,27 +1,62 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
// Copyright 2021 The Kubernetes Authors.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package types
|
package types
|
||||||
|
|
||||||
|
const DefaultReplacementFieldPath = "metadata.name"
|
||||||
|
|
||||||
// Replacement defines how to perform a substitution
|
// Replacement defines how to perform a substitution
|
||||||
// where it is from and where it is to.
|
// where it is from and where it is to.
|
||||||
type Replacement struct {
|
type Replacement struct {
|
||||||
Source *ReplSource `json:"source" yaml:"source"`
|
// The source of the value.
|
||||||
Target *ReplTarget `json:"target" yaml:"target"`
|
Source *SourceSelector `json:"source" yaml:"source"`
|
||||||
|
|
||||||
|
// The N fields to write the value to.
|
||||||
|
Targets []*TargetSelector `json:"targets" yaml:"targets"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReplSource defines where a substitution is from
|
// SourceSelector is the source of the replacement transformer.
|
||||||
// It can from two different kinds of sources
|
type SourceSelector struct {
|
||||||
// - from a field of one resource
|
// A specific object to read it from.
|
||||||
// - from a string
|
KrmId `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||||
type ReplSource struct {
|
|
||||||
ObjRef *Target `json:"objref,omitempty" yaml:"objref,omitempty"`
|
// Structured field path expected in the allowed object.
|
||||||
FieldRef string `json:"fieldref,omitempty" yaml:"fiedldref,omitempty"`
|
FieldPath string `json:"fieldPath" yaml:"fieldPath"`
|
||||||
Value string `json:"value,omitempty" yaml:"value,omitempty"`
|
|
||||||
|
// Used to refine the interpretation of the field
|
||||||
|
Options *FieldOptions `json:"options" yaml:"options"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReplTarget defines where a substitution is to.
|
// TargetSelector specifies fields in one or more objects.
|
||||||
type ReplTarget struct {
|
type TargetSelector struct {
|
||||||
ObjRef *Selector `json:"objref,omitempty" yaml:"objref,omitempty"`
|
// Include objects that match this.
|
||||||
FieldRefs []string `json:"fieldrefs,omitempty" yaml:"fieldrefs,omitempty"`
|
Select *Selector `json:"select" yaml:"select"`
|
||||||
|
|
||||||
|
// From the allowed set, remove objects that match this.
|
||||||
|
// TODO (#3492): Remove matches listed in the exclude field
|
||||||
|
// Currently this field is unused
|
||||||
|
Reject *Selector `json:"reject" yaml:"reject"`
|
||||||
|
|
||||||
|
// Structured field paths expected in each allowed object.
|
||||||
|
FieldPaths []string `json:"fieldPaths" yaml:"fieldPaths"`
|
||||||
|
|
||||||
|
// Used to refine the interpretation of the field
|
||||||
|
Options *FieldOptions `json:"options" yaml:"options"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FieldPath is a structured field path to the desired object
|
||||||
|
// TODO (#3492): Implement use of these options, they are
|
||||||
|
// currently used
|
||||||
|
type FieldOptions struct {
|
||||||
|
// Used to split/join the field.
|
||||||
|
Delimiter string `json:"delimiter" yaml:"delimiter"`
|
||||||
|
|
||||||
|
// Which position in the split to consider.
|
||||||
|
Index int `json:"index" yaml:"index"`
|
||||||
|
|
||||||
|
// None, Base64, URL, Hex, etc
|
||||||
|
Encoding string `json:"encoding" yaml:"index"`
|
||||||
|
|
||||||
|
// If field missing, add it
|
||||||
|
Create bool `json:"create" yaml:"create"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,8 @@ import (
|
|||||||
// Any resource that matches intersection of all conditions
|
// Any resource that matches intersection of all conditions
|
||||||
// is included in this set.
|
// is included in this set.
|
||||||
type Selector struct {
|
type Selector struct {
|
||||||
resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
|
// KrmId refers to a GVKN/Ns of a resource.
|
||||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
KrmId `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
|
||||||
|
|
||||||
// AnnotationSelector is a string that follows the label selection expression
|
// AnnotationSelector is a string that follows the label selection expression
|
||||||
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
|
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
|
||||||
@@ -28,6 +27,23 @@ type Selector struct {
|
|||||||
LabelSelector string `json:"labelSelector,omitempty" yaml:"labelSelector,omitempty"`
|
LabelSelector string `json:"labelSelector,omitempty" yaml:"labelSelector,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KrmId refers to a GVKN/Ns of a resource.
|
||||||
|
type KrmId struct {
|
||||||
|
resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||||
|
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||||
|
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match returns true if id selects other, i.e. id's fields
|
||||||
|
// either match other's or are empty
|
||||||
|
func (id *KrmId) Match(other *KrmId) bool {
|
||||||
|
return (id.Group == "" || id.Group == other.Group) &&
|
||||||
|
(id.Version == "" || id.Version == other.Version) &&
|
||||||
|
(id.Kind == "" || id.Kind == other.Kind) &&
|
||||||
|
(id.Name == "" || id.Name == other.Name) &&
|
||||||
|
(id.Namespace == "" || id.Namespace == other.Namespace)
|
||||||
|
}
|
||||||
|
|
||||||
// SelectorRegex is a Selector with regex in GVK
|
// SelectorRegex is a Selector with regex in GVK
|
||||||
// Any resource that matches intersection of all conditions
|
// Any resource that matches intersection of all conditions
|
||||||
// is included in this set.
|
// is included in this set.
|
||||||
|
|||||||
@@ -15,10 +15,12 @@ func TestSelectorRegexMatchGvk(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
S: Selector{
|
S: Selector{
|
||||||
Gvk: resid.Gvk{
|
KrmId: KrmId{
|
||||||
Group: "group",
|
Gvk: resid.Gvk{
|
||||||
Version: "version",
|
Group: "group",
|
||||||
Kind: "kind",
|
Version: "version",
|
||||||
|
Kind: "kind",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
G: resid.Gvk{
|
G: resid.Gvk{
|
||||||
@@ -30,10 +32,12 @@ func TestSelectorRegexMatchGvk(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
S: Selector{
|
S: Selector{
|
||||||
Gvk: resid.Gvk{
|
KrmId: KrmId{
|
||||||
Group: "group",
|
Gvk: resid.Gvk{
|
||||||
Version: "",
|
Group: "group",
|
||||||
Kind: "",
|
Version: "",
|
||||||
|
Kind: "",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
G: resid.Gvk{
|
G: resid.Gvk{
|
||||||
@@ -45,10 +49,12 @@ func TestSelectorRegexMatchGvk(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
S: Selector{
|
S: Selector{
|
||||||
Gvk: resid.Gvk{
|
KrmId: KrmId{
|
||||||
Group: "group",
|
Gvk: resid.Gvk{
|
||||||
Version: "version",
|
Group: "group",
|
||||||
Kind: "kind",
|
Version: "version",
|
||||||
|
Kind: "kind",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
G: resid.Gvk{
|
G: resid.Gvk{
|
||||||
@@ -60,10 +66,12 @@ func TestSelectorRegexMatchGvk(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
S: Selector{
|
S: Selector{
|
||||||
Gvk: resid.Gvk{
|
KrmId: KrmId{
|
||||||
Group: "group",
|
Gvk: resid.Gvk{
|
||||||
Version: "version",
|
Group: "group",
|
||||||
Kind: "kind",
|
Version: "version",
|
||||||
|
Kind: "kind",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
G: resid.Gvk{
|
G: resid.Gvk{
|
||||||
@@ -75,10 +83,12 @@ func TestSelectorRegexMatchGvk(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
S: Selector{
|
S: Selector{
|
||||||
Gvk: resid.Gvk{
|
KrmId: KrmId{
|
||||||
Group: "g.*",
|
Gvk: resid.Gvk{
|
||||||
Version: "\\d+",
|
Group: "g.*",
|
||||||
Kind: ".{4}",
|
Version: "\\d+",
|
||||||
|
Kind: ".{4}",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
G: resid.Gvk{
|
G: resid.Gvk{
|
||||||
@@ -90,10 +100,12 @@ func TestSelectorRegexMatchGvk(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
S: Selector{
|
S: Selector{
|
||||||
Gvk: resid.Gvk{
|
KrmId: KrmId{
|
||||||
Group: "g.*",
|
Gvk: resid.Gvk{
|
||||||
Version: "\\d+",
|
Group: "g.*",
|
||||||
Kind: ".{4}",
|
Version: "\\d+",
|
||||||
|
Kind: ".{4}",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
G: resid.Gvk{
|
G: resid.Gvk{
|
||||||
@@ -125,30 +137,38 @@ func TestSelectorRegexMatchName(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
S: Selector{
|
S: Selector{
|
||||||
Name: "foo",
|
KrmId: KrmId{
|
||||||
Namespace: "bar",
|
Name: "foo",
|
||||||
|
Namespace: "bar",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Expected: true,
|
Expected: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
S: Selector{
|
S: Selector{
|
||||||
Name: "foo",
|
KrmId: KrmId{
|
||||||
Namespace: "bar",
|
Name: "foo",
|
||||||
|
Namespace: "bar",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
Expected: false,
|
Expected: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
S: Selector{
|
S: Selector{
|
||||||
Name: "f.*",
|
KrmId: KrmId{
|
||||||
|
Name: "f.*",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Expected: true,
|
Expected: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
S: Selector{
|
S: Selector{
|
||||||
Name: "b.*",
|
KrmId: KrmId{
|
||||||
|
Name: "b.*",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Expected: false,
|
Expected: false,
|
||||||
@@ -174,30 +194,38 @@ func TestSelectorRegexMatchNamespace(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
S: Selector{
|
S: Selector{
|
||||||
Name: "bar",
|
KrmId: KrmId{
|
||||||
Namespace: "foo",
|
Name: "bar",
|
||||||
|
Namespace: "foo",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Namespace: "foo",
|
Namespace: "foo",
|
||||||
Expected: true,
|
Expected: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
S: Selector{
|
S: Selector{
|
||||||
Name: "foo",
|
KrmId: KrmId{
|
||||||
Namespace: "bar",
|
Name: "foo",
|
||||||
|
Namespace: "bar",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Namespace: "foo",
|
Namespace: "foo",
|
||||||
Expected: false,
|
Expected: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
S: Selector{
|
S: Selector{
|
||||||
Namespace: "f.*",
|
KrmId: KrmId{
|
||||||
|
Namespace: "f.*",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Namespace: "foo",
|
Namespace: "foo",
|
||||||
Expected: true,
|
Expected: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
S: Selector{
|
S: Selector{
|
||||||
Namespace: "b.*",
|
KrmId: KrmId{
|
||||||
|
Namespace: "b.*",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Namespace: "foo",
|
Namespace: "foo",
|
||||||
Expected: false,
|
Expected: false,
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/api/resid"
|
"sigs.k8s.io/kustomize/api/resid"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultFieldPath = "metadata.name"
|
|
||||||
|
|
||||||
// Var represents a variable whose value will be sourced
|
// Var represents a variable whose value will be sourced
|
||||||
// from a field in a Kubernetes object.
|
// from a field in a Kubernetes object.
|
||||||
type Var struct {
|
type Var struct {
|
||||||
@@ -71,7 +69,7 @@ type FieldSelector struct {
|
|||||||
// defaulting sets reference to field used by default.
|
// defaulting sets reference to field used by default.
|
||||||
func (v *Var) Defaulting() {
|
func (v *Var) Defaulting() {
|
||||||
if v.FieldRef.FieldPath == "" {
|
if v.FieldRef.FieldPath == "" {
|
||||||
v.FieldRef.FieldPath = defaultFieldPath
|
v.FieldRef.FieldPath = DefaultReplacementFieldPath
|
||||||
}
|
}
|
||||||
v.ObjRef.GVK()
|
v.ObjRef.GVK()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,9 +69,9 @@ func TestDefaulting(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
v.Defaulting()
|
v.Defaulting()
|
||||||
if v.FieldRef.FieldPath != defaultFieldPath {
|
if v.FieldRef.FieldPath != DefaultReplacementFieldPath {
|
||||||
t.Fatalf("expected %s, got %v",
|
t.Fatalf("expected %s, got %v",
|
||||||
defaultFieldPath, v.FieldRef.FieldPath)
|
DefaultReplacementFieldPath, v.FieldRef.FieldPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ func TestVarSet(t *testing.T) {
|
|||||||
t.Fatalf("expected var")
|
t.Fatalf("expected var")
|
||||||
}
|
}
|
||||||
// Confirm defaulting.
|
// Confirm defaulting.
|
||||||
if v.FieldRef.FieldPath != defaultFieldPath {
|
if v.FieldRef.FieldPath != DefaultReplacementFieldPath {
|
||||||
t.Fatalf("unexpected field path: %v", v.FieldRef.FieldPath)
|
t.Fatalf("unexpected field path: %v", v.FieldRef.FieldPath)
|
||||||
}
|
}
|
||||||
// Confirm sorting.
|
// Confirm sorting.
|
||||||
|
|||||||
Reference in New Issue
Block a user