mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-07-17 09:49:13 +00:00
Merge pull request #4113 from KnVerey/kyaml_container_patch_kinds
Enable fn framework container patches to work with more kinds
This commit is contained in:
@@ -168,8 +168,7 @@ func (cpt ContainerPatchTemplate) apply(matches []*yaml.RNode) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := range matches {
|
for i := range matches {
|
||||||
// TODO(knverey): Make this work for more Kinds and expose the helper for doing so.
|
containers, err := matches[i].Pipe(yaml.LookupFirstMatch(yaml.ConventionalContainerPaths))
|
||||||
containers, err := matches[i].Pipe(yaml.Lookup("spec", "template", "spec", "containers"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err)
|
return errors.Wrap(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package framework_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -276,6 +277,57 @@ functionConfig:
|
|||||||
`), strings.TrimSpace(out.String()))
|
`), strings.TrimSpace(out.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTemplateProcessor_ContainerPatchTemplates_MultipleWorkloadKinds(t *testing.T) {
|
||||||
|
type API struct {
|
||||||
|
Spec struct {
|
||||||
|
Key string `json:"key" yaml:"key"`
|
||||||
|
Value string `json:"value" yaml:"value"`
|
||||||
|
A string `json:"a" yaml:"a"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config := &API{}
|
||||||
|
p := framework.TemplateProcessor{
|
||||||
|
TemplateData: config,
|
||||||
|
ResourceTemplates: []framework.ResourceTemplate{{
|
||||||
|
Templates: parser.TemplateFiles("testdata/template-processor/templates/container-sources"),
|
||||||
|
}},
|
||||||
|
PatchTemplates: []framework.PatchTemplate{
|
||||||
|
&framework.ContainerPatchTemplate{
|
||||||
|
Templates: parser.TemplateFiles("testdata/template-processor/container-patches"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
out := new(bytes.Buffer)
|
||||||
|
rw := &kio.ByteReadWriter{Writer: out, Reader: bytes.NewBufferString(`
|
||||||
|
apiVersion: config.kubernetes.io/v1alpha1
|
||||||
|
kind: ResourceList
|
||||||
|
items: []
|
||||||
|
functionConfig:
|
||||||
|
spec:
|
||||||
|
key: Hello
|
||||||
|
value: World
|
||||||
|
a: bar
|
||||||
|
`)}
|
||||||
|
|
||||||
|
require.NoError(t, framework.Execute(p, rw))
|
||||||
|
resources, err := (&kio.ByteReader{Reader: out}).Read()
|
||||||
|
require.NoError(t, err)
|
||||||
|
envRegex := regexp.MustCompile(strings.TrimSpace(`
|
||||||
|
\s+ env:
|
||||||
|
\s+ - name: EXISTING
|
||||||
|
\s+ value: variable
|
||||||
|
\s+ - name: Hello
|
||||||
|
\s+ value: World
|
||||||
|
`))
|
||||||
|
require.Equal(t, 9, len(resources))
|
||||||
|
for i, r := range resources {
|
||||||
|
t.Run(r.GetKind(), func(t *testing.T) {
|
||||||
|
assert.Regexp(t, envRegex, resources[i].MustString())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSimpleProcessor_Process_loads_config(t *testing.T) {
|
func TestSimpleProcessor_Process_loads_config(t *testing.T) {
|
||||||
cfg := new(struct {
|
cfg := new(struct {
|
||||||
Value string `yaml:"value"`
|
Value string `yaml:"value"`
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Copyright 2021 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: hello
|
||||||
|
spec:
|
||||||
|
schedule: "*/1 * * * *"
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: hello
|
||||||
|
image: nginx
|
||||||
|
env:
|
||||||
|
- name: EXISTING
|
||||||
|
value: variable
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Copyright 2021 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: DaemonSet
|
||||||
|
metadata:
|
||||||
|
name: hello
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
name: hello
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
name: hello
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: hello
|
||||||
|
image: nginx
|
||||||
|
env:
|
||||||
|
- name: EXISTING
|
||||||
|
value: variable
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Copyright 2021 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: hello
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: hello
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: hello
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: hello
|
||||||
|
image: nginx
|
||||||
|
env:
|
||||||
|
- name: EXISTING
|
||||||
|
value: variable
|
||||||
16
kyaml/fn/framework/testdata/template-processor/templates/container-sources/job.template.yaml
vendored
Normal file
16
kyaml/fn/framework/testdata/template-processor/templates/container-sources/job.template.yaml
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Copyright 2021 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: hello
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: hello
|
||||||
|
image: nginx
|
||||||
|
env:
|
||||||
|
- name: EXISTING
|
||||||
|
value: variable
|
||||||
14
kyaml/fn/framework/testdata/template-processor/templates/container-sources/pod.template.yaml
vendored
Normal file
14
kyaml/fn/framework/testdata/template-processor/templates/container-sources/pod.template.yaml
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Copyright 2021 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: hello
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: hello
|
||||||
|
image: nginx
|
||||||
|
env:
|
||||||
|
- name: EXISTING
|
||||||
|
value: variable
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Copyright 2021 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PodTemplate
|
||||||
|
metadata:
|
||||||
|
name: hello
|
||||||
|
labels:
|
||||||
|
tier: hello
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: hello
|
||||||
|
image: nginx
|
||||||
|
env:
|
||||||
|
- name: EXISTING
|
||||||
|
value: variable
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Copyright 2021 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: ReplicaSet
|
||||||
|
metadata:
|
||||||
|
name: hello
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: hello
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: hello
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: hello
|
||||||
|
image: nginx
|
||||||
|
env:
|
||||||
|
- name: EXISTING
|
||||||
|
value: variable
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Copyright 2021 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ReplicationController
|
||||||
|
metadata:
|
||||||
|
name: hello
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: hello
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
name: hello
|
||||||
|
labels:
|
||||||
|
app: hello
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: hello
|
||||||
|
image: nginx
|
||||||
|
env:
|
||||||
|
- name: EXISTING
|
||||||
|
value: variable
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Copyright 2021 The Kubernetes Authors.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: hello
|
||||||
|
spec:
|
||||||
|
serviceName: "nginx"
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: hello
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: hello
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: hello
|
||||||
|
image: nginx
|
||||||
|
env:
|
||||||
|
- name: EXISTING
|
||||||
|
value: variable
|
||||||
|
|
||||||
@@ -6,13 +6,13 @@
|
|||||||
package kubernetesapi
|
package kubernetesapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi/v1212"
|
"sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi/v1212"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Info = "{title:Kubernetes,version:v1.21.2}"
|
const Info = "{title:Kubernetes,version:v1.21.2}"
|
||||||
|
|
||||||
var OpenAPIMustAsset = map[string]func(string)[]byte{
|
var OpenAPIMustAsset = map[string]func(string) []byte{
|
||||||
"v1212": v1212.MustAsset,
|
"v1212": v1212.MustAsset,
|
||||||
}
|
}
|
||||||
|
|
||||||
const DefaultOpenAPI = "v1212"
|
const DefaultOpenAPI = "v1212"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||||
|
|
||||||
//Package v1212 generated by go-bindata.// sources:
|
//Package v1212 generated by go-bindata.// sources:
|
||||||
// kubernetesapi/v1212/swagger.json
|
// kubernetesapi/v1212/swagger.json
|
||||||
package v1212
|
package v1212
|
||||||
|
|
||||||
|
|||||||
@@ -424,12 +424,46 @@ func Lookup(path ...string) PathGetter {
|
|||||||
return PathGetter{Path: path}
|
return PathGetter{Path: path}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup returns a PathGetter to lookup a field by its path and create it if it doesn't already
|
// LookupCreate returns a PathGetter to lookup a field by its path and create it if it doesn't already
|
||||||
// exist.
|
// exist.
|
||||||
func LookupCreate(kind yaml.Kind, path ...string) PathGetter {
|
func LookupCreate(kind yaml.Kind, path ...string) PathGetter {
|
||||||
return PathGetter{Path: path, Create: kind}
|
return PathGetter{Path: path, Create: kind}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConventionalContainerPaths is a list of paths at which containers typically appear in workload APIs.
|
||||||
|
// It is intended for use with LookupFirstMatch.
|
||||||
|
var ConventionalContainerPaths = [][]string{
|
||||||
|
// e.g. Deployment, ReplicaSet, DaemonSet, Job, StatefulSet
|
||||||
|
{"spec", "template", "spec", "containers"},
|
||||||
|
// e.g. CronJob
|
||||||
|
{"spec", "jobTemplate", "spec", "template", "spec", "containers"},
|
||||||
|
// e.g. Pod
|
||||||
|
{"spec", "containers"},
|
||||||
|
// e.g. PodTemplate
|
||||||
|
{"template", "spec", "containers"},
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupFirstMatch returns a Filter for locating a value that may exist at one of several possible paths.
|
||||||
|
// For example, it can be used with ConventionalContainerPaths to find the containers field in a standard workload resource.
|
||||||
|
// If more than one of the paths exists in the resource, the first will be returned. If none exist,
|
||||||
|
// nil will be returned. If an error is encountered during lookup, it will be returned.
|
||||||
|
func LookupFirstMatch(paths [][]string) Filter {
|
||||||
|
return FilterFunc(func(object *RNode) (*RNode, error) {
|
||||||
|
var result *RNode
|
||||||
|
var err error
|
||||||
|
for _, path := range paths {
|
||||||
|
result, err = object.Pipe(PathGetter{Path: path})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err)
|
||||||
|
}
|
||||||
|
if result != nil {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// PathGetter returns the RNode under Path.
|
// PathGetter returns the RNode under Path.
|
||||||
type PathGetter struct {
|
type PathGetter struct {
|
||||||
Kind string `yaml:"kind,omitempty"`
|
Kind string `yaml:"kind,omitempty"`
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml"
|
"sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/go-yaml/yaml"
|
||||||
. "sigs.k8s.io/kustomize/kyaml/yaml"
|
. "sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
)
|
)
|
||||||
@@ -724,6 +725,72 @@ j: k
|
|||||||
assert.Nil(t, rn)
|
assert.Nil(t, rn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLookupFirstMatch(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
paths [][]string
|
||||||
|
wantPath []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "finds path that exists",
|
||||||
|
paths: [][]string{{"spec", "jobTemplate", "spec", "template", "spec", "containers"}},
|
||||||
|
wantPath: []string{"spec", "jobTemplate", "spec", "template", "spec", "containers"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "chooses first path when multiple exist: containers example",
|
||||||
|
paths: ConventionalContainerPaths,
|
||||||
|
wantPath: []string{"spec", "template", "spec", "containers"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "chooses first path when multiple exist: annotations example",
|
||||||
|
paths: [][]string{
|
||||||
|
{"metadata", "annotations", "example.kustomize.io/new"},
|
||||||
|
{"metadata", "annotations", "example.kustomize.io/deprecated"},
|
||||||
|
},
|
||||||
|
wantPath: []string{"metadata", "annotations", "example.kustomize.io/new"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "returns nil when path does not exist",
|
||||||
|
paths: [][]string{
|
||||||
|
{"metadata", "annotations", "example.kustomize.io/does-not-exist"},
|
||||||
|
{"metadata", "annotations", "example.kustomize.io/also-not-exist"},
|
||||||
|
},
|
||||||
|
wantPath: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
s := `
|
||||||
|
apiVersion: example.kustomize.io/v1
|
||||||
|
kind: Custom
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
example.kustomize.io/deprecated: foo
|
||||||
|
example.kustomize.io/new: foo
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: foo
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: foo
|
||||||
|
`
|
||||||
|
resource := MustParse(s)
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
result, err := LookupFirstMatch(tt.paths).Filter(resource)
|
||||||
|
require.NoError(t, err)
|
||||||
|
if tt.wantPath != nil {
|
||||||
|
assert.Equal(t, tt.wantPath, result.FieldPath())
|
||||||
|
} else {
|
||||||
|
assert.Nil(t, result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestFieldSetter(t *testing.T) {
|
func TestFieldSetter(t *testing.T) {
|
||||||
// Change field
|
// Change field
|
||||||
node, err := Parse(`
|
node, err := Parse(`
|
||||||
|
|||||||
Reference in New Issue
Block a user