mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-12 01:14:22 +00:00
cmd/config run scoping and path defaulting
- default the path and index for Resources generated by functions - scope functions to only operate against resources in subdirectories
This commit is contained in:
@@ -8,8 +8,10 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
|
||||
|
||||
@@ -24,6 +26,106 @@ import (
|
||||
// non-zero.
|
||||
// The full set of environment variables from the parent process
|
||||
// are passed to the container.
|
||||
//
|
||||
// Function Scoping:
|
||||
// ContainerFilter applies the function only to Resources to which it is scoped.
|
||||
//
|
||||
// Resources are scoped to a function if any of the following are true:
|
||||
// - the Resource were read from the same directory as the function config
|
||||
// - the Resource were read from a subdirectory of the function config directory
|
||||
// - the function config is in a directory named "functions" and
|
||||
// they were read from a subdirectory of "functions" parent
|
||||
// - the function config doesn't have a path annotation (considered globally scoped)
|
||||
// - the ContainerFilter has GlobalScope == true
|
||||
//
|
||||
// In Scope Examples:
|
||||
//
|
||||
// Example 1: deployment.yaml and service.yaml in function.yaml scope
|
||||
// same directory as the function config directory
|
||||
// .
|
||||
// ├── function.yaml
|
||||
// ├── deployment.yaml
|
||||
// └── service.yaml
|
||||
//
|
||||
// Example 2: apps/deployment.yaml and apps/service.yaml in function.yaml scope
|
||||
// subdirectory of the function config directory
|
||||
// .
|
||||
// ├── function.yaml
|
||||
// └── apps
|
||||
// ├── deployment.yaml
|
||||
// └── service.yaml
|
||||
//
|
||||
// Example 3: apps/deployment.yaml and apps/service.yaml in functions/function.yaml scope
|
||||
// function config is in a directory named "functions"
|
||||
// .
|
||||
// ├── functions
|
||||
// │ └── function.yaml
|
||||
// └── apps
|
||||
// ├── deployment.yaml
|
||||
// └── service.yaml
|
||||
//
|
||||
// Out of Scope Examples:
|
||||
//
|
||||
// Example 1: apps/deployment.yaml and apps/service.yaml NOT in stuff/function.yaml scope
|
||||
// .
|
||||
// ├── stuff
|
||||
// │ └── function.yaml
|
||||
// └── apps
|
||||
// ├── deployment.yaml
|
||||
// └── service.yaml
|
||||
//
|
||||
// Example 2: apps/deployment.yaml and apps/service.yaml NOT in stuff/functions/function.yaml scope
|
||||
// .
|
||||
// ├── stuff
|
||||
// │ └── functions
|
||||
// │ └── function.yaml
|
||||
// └── apps
|
||||
// ├── deployment.yaml
|
||||
// └── service.yaml
|
||||
//
|
||||
// Default Paths:
|
||||
// Resources emitted by functions will have default path applied as annotations
|
||||
// if none is present.
|
||||
// The default path will be the function-dir/ (or parent directory in the case of "functions")
|
||||
// + function-file-name/ + namespace/ + kind_name.yaml
|
||||
//
|
||||
// Example 1: Given a function in fn.yaml that produces a Deployment name foo and a Service named bar
|
||||
// dir
|
||||
// └── fn.yaml
|
||||
//
|
||||
// Would default newly generated Resources to:
|
||||
//
|
||||
// dir
|
||||
// ├── fn.yaml
|
||||
// └── fn
|
||||
// ├── deployment_foo.yaml
|
||||
// └── service_bar.yaml
|
||||
//
|
||||
// Example 2: Given a function in functions/fn.yaml that produces a Deployment name foo and a Service named bar
|
||||
// dir
|
||||
// └── fn.yaml
|
||||
//
|
||||
// Would default newly generated Resources to:
|
||||
//
|
||||
// dir
|
||||
// ├── functions
|
||||
// │ └── fn.yaml
|
||||
// └── fn
|
||||
// ├── deployment_foo.yaml
|
||||
// └── service_bar.yaml
|
||||
//
|
||||
// Example 3: Given a function in fn.yaml that produces a Deployment name foo, namespace baz and a Service named bar namespace baz
|
||||
// dir
|
||||
// └── fn.yaml
|
||||
//
|
||||
// Would default newly generated Resources to:
|
||||
//
|
||||
// dir
|
||||
// ├── fn.yaml
|
||||
// └── fn
|
||||
// └── baz
|
||||
// ├── deployment_foo.yaml
|
||||
// └── service_bar.yaml
|
||||
type ContainerFilter struct {
|
||||
|
||||
// Image is the container image to use to create a container.
|
||||
@@ -40,6 +142,10 @@ type ContainerFilter struct {
|
||||
// Typically a Kubernetes style Resource Config.
|
||||
Config *yaml.RNode `yaml:"config,omitempty"`
|
||||
|
||||
// GlobalScope will cause the function to be run against all input
|
||||
// nodes instead of only nodes scoped under the function.
|
||||
GlobalScope bool
|
||||
|
||||
// args may be specified by tests to override how a container is spawned
|
||||
args []string
|
||||
|
||||
@@ -65,8 +171,76 @@ func (s *StorageMount) String() string {
|
||||
return fmt.Sprintf("type=%s,src=%s,dst=%s:ro", s.MountType, s.Src, s.DstPath)
|
||||
}
|
||||
|
||||
// functionsDirectoryName is keyword directory name for functions scoped 1 directory higher
|
||||
const functionsDirectoryName = "functions"
|
||||
|
||||
// getFunctionScope returns the path of the directory containing the function config,
|
||||
// or its parent directory if the base directory is named "functions"
|
||||
func (c *ContainerFilter) getFunctionScope() (string, error) {
|
||||
m, err := c.Config.GetMeta()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err)
|
||||
}
|
||||
p, found := m.Annotations[kioutil.PathAnnotation]
|
||||
if !found {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
functionDir := path.Clean(path.Dir(p))
|
||||
|
||||
if path.Base(functionDir) == functionsDirectoryName {
|
||||
// the scope of functions in a directory called "functions" is 1 level higher
|
||||
// this is similar to how the golang "internal" directory scoping works
|
||||
functionDir = path.Dir(functionDir)
|
||||
}
|
||||
return functionDir, nil
|
||||
}
|
||||
|
||||
// scope partitions the input nodes into 2 slices. The first slice contains only Resources
|
||||
// which are scoped under dir, and the second slice contains the Resources which are not.
|
||||
func (c *ContainerFilter) scope(dir string, nodes []*yaml.RNode) ([]*yaml.RNode, []*yaml.RNode, error) {
|
||||
// scope container filtered Resources to Resources under that directory
|
||||
var input, saved []*yaml.RNode
|
||||
if c.GlobalScope {
|
||||
return nodes, nil, nil
|
||||
}
|
||||
|
||||
if dir == "" {
|
||||
// global function
|
||||
return nodes, nil, nil
|
||||
}
|
||||
|
||||
// identify Resources read from directories under the function configuration
|
||||
for i := range nodes {
|
||||
m, err := nodes[i].GetMeta()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
p, found := m.Annotations[kioutil.PathAnnotation]
|
||||
if !found {
|
||||
// this Resource isn't scoped under the function -- don't know where it came from
|
||||
// consider it out of scope
|
||||
saved = append(saved, nodes[i])
|
||||
continue
|
||||
}
|
||||
|
||||
resourceDir := path.Clean(path.Dir(p))
|
||||
if !strings.HasPrefix(resourceDir, dir) {
|
||||
// this Resource doesn't fall under the function scope if it
|
||||
// isn't in a subdirectory of where the function lives
|
||||
saved = append(saved, nodes[i])
|
||||
continue
|
||||
}
|
||||
|
||||
// this input is scoped under the function
|
||||
input = append(input, nodes[i])
|
||||
}
|
||||
|
||||
return input, saved, nil
|
||||
}
|
||||
|
||||
// GrepFilter implements kio.GrepFilter
|
||||
func (c *ContainerFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
func (c *ContainerFilter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
// get the command to filter the Resources
|
||||
cmd, err := c.getCommand()
|
||||
if err != nil {
|
||||
@@ -76,11 +250,23 @@ func (c *ContainerFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
in := &bytes.Buffer{}
|
||||
out := &bytes.Buffer{}
|
||||
|
||||
// only process Resources scoped to this function, save the others
|
||||
functionDir, err := c.getFunctionScope()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
input, saved, err := c.scope(functionDir, nodes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// write the input
|
||||
err = kio.ByteWriter{
|
||||
WrappingAPIVersion: kio.ResourceListAPIVersion,
|
||||
WrappingKind: kio.ResourceListKind,
|
||||
Writer: in, KeepReaderAnnotations: true, FunctionConfig: c.Config}.Write(input)
|
||||
WrappingAPIVersion: kio.ResourceListAPIVersion,
|
||||
WrappingKind: kio.ResourceListKind,
|
||||
Writer: in,
|
||||
KeepReaderAnnotations: true,
|
||||
FunctionConfig: c.Config}.Write(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -98,7 +284,19 @@ func (c *ContainerFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r.Read()
|
||||
output, err := r.Read()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// annotate any generated Resources with a path and index if they don't already have one
|
||||
if err := kioutil.DefaultPathAnnotation(functionDir, output); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// emit both the Resources output from the function, and the out-of-scope Resources
|
||||
// which were not provided to the function
|
||||
return append(output, saved...), nil
|
||||
}
|
||||
|
||||
// getArgs returns the command + args to run to spawn the container
|
||||
@@ -139,7 +337,7 @@ func (c *ContainerFilter) getArgs() []string {
|
||||
return append(args, c.Image)
|
||||
}
|
||||
|
||||
// getCommand returns a command which will apply the GrepFilter using the container image
|
||||
// getCommand returns a command which will apply the Filter using the container image
|
||||
func (c *ContainerFilter) getCommand() (*exec.Cmd, error) {
|
||||
// encode the filter command API configuration
|
||||
cfg := &bytes.Buffer{}
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
)
|
||||
|
||||
func TestFilter_command(t *testing.T) {
|
||||
cfg, err := yaml.Parse(`apiversion: apps/v1
|
||||
cfg, err := yaml.Parse(`apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: foo
|
||||
@@ -62,7 +62,7 @@ metadata:
|
||||
}
|
||||
|
||||
func TestFilter_command_StorageMount(t *testing.T) {
|
||||
cfg, err := yaml.Parse(`apiversion: apps/v1
|
||||
cfg, err := yaml.Parse(`apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: foo
|
||||
@@ -103,7 +103,7 @@ metadata:
|
||||
}
|
||||
|
||||
func TestFilter_command_network(t *testing.T) {
|
||||
cfg, err := yaml.Parse(`apiversion: apps/v1
|
||||
cfg, err := yaml.Parse(`apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: foo
|
||||
@@ -213,6 +213,7 @@ metadata:
|
||||
name: deployment-foo
|
||||
annotations:
|
||||
config.kubernetes.io/index: '0'
|
||||
config.kubernetes.io/path: 'statefulset_deployment-foo.yaml'
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
@@ -220,11 +221,12 @@ metadata:
|
||||
name: service-foo
|
||||
annotations:
|
||||
config.kubernetes.io/index: '1'
|
||||
config.kubernetes.io/path: 'service_service-foo.yaml'
|
||||
`, b.String())
|
||||
}
|
||||
|
||||
func TestFilter_Filter_noChange(t *testing.T) {
|
||||
cfg, err := yaml.Parse(`apiversion: apps/v1
|
||||
cfg, err := yaml.Parse(`apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: foo
|
||||
@@ -234,7 +236,7 @@ metadata:
|
||||
}
|
||||
|
||||
input, err := (&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||
apiversion: apps/v1
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
@@ -258,7 +260,7 @@ metadata:
|
||||
if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiversion: apps/v1
|
||||
- apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
@@ -270,7 +272,7 @@ items:
|
||||
name: service-foo
|
||||
annotations:
|
||||
config.kubernetes.io/index: '1'
|
||||
functionConfig: {apiversion: apps/v1, kind: Deployment, metadata: {name: foo}}
|
||||
functionConfig: {apiVersion: apps/v1, kind: Deployment, metadata: {name: foo}}
|
||||
`, s) {
|
||||
t.FailNow()
|
||||
}
|
||||
@@ -289,12 +291,13 @@ functionConfig: {apiversion: apps/v1, kind: Deployment, metadata: {name: foo}}
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, `apiversion: apps/v1
|
||||
assert.Equal(t, `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
annotations:
|
||||
config.kubernetes.io/index: '0'
|
||||
config.kubernetes.io/path: 'deployment_deployment-foo.yaml'
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
@@ -302,6 +305,7 @@ metadata:
|
||||
name: service-foo
|
||||
annotations:
|
||||
config.kubernetes.io/index: '1'
|
||||
config.kubernetes.io/path: 'service_service-foo.yaml'
|
||||
`, b.String())
|
||||
}
|
||||
|
||||
@@ -359,3 +363,418 @@ metadata:
|
||||
c, _ = GetContainerName(n)
|
||||
assert.Equal(t, "", c)
|
||||
}
|
||||
|
||||
func TestFilter_Filter_defaultNaming(t *testing.T) {
|
||||
cfg, err := yaml.Parse(`apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'foo/bar.yaml'
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
input, err := (&kio.ByteReader{Reader: bytes.NewBufferString(``)}).Read()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
called := false
|
||||
result, err := (&ContainerFilter{
|
||||
Image: "example.com:version",
|
||||
Config: cfg,
|
||||
args: []string{"echo", `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: service-foo
|
||||
`},
|
||||
checkInput: func(s string) {
|
||||
called = true
|
||||
if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items: []
|
||||
functionConfig: {apiVersion: apps/v1, kind: Deployment, metadata: {name: foo, annotations: {
|
||||
config.kubernetes.io/path: 'foo/bar.yaml'}}}
|
||||
`, s) {
|
||||
t.FailNow()
|
||||
}
|
||||
},
|
||||
}).Filter(input)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
if !assert.True(t, called) {
|
||||
return
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
err = kio.ByteWriter{Writer: b, KeepReaderAnnotations: true}.Write(result)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
annotations:
|
||||
config.kubernetes.io/index: '0'
|
||||
config.kubernetes.io/path: 'foo/deployment_deployment-foo.yaml'
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: service-foo
|
||||
annotations:
|
||||
config.kubernetes.io/index: '1'
|
||||
config.kubernetes.io/path: 'foo/service_service-foo.yaml'
|
||||
`, b.String())
|
||||
}
|
||||
|
||||
func TestFilter_Filter_defaultNamingFunctions(t *testing.T) {
|
||||
cfg, err := yaml.Parse(`apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'foo/functions/bar.yaml'
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
input, err := (&kio.ByteReader{Reader: bytes.NewBufferString(``)}).Read()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
called := false
|
||||
result, err := (&ContainerFilter{
|
||||
Image: "example.com:version",
|
||||
Config: cfg,
|
||||
args: []string{"echo", `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: service-foo
|
||||
`},
|
||||
checkInput: func(s string) {
|
||||
called = true
|
||||
if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items: []
|
||||
functionConfig: {apiVersion: apps/v1, kind: Deployment, metadata: {name: foo, annotations: {
|
||||
config.kubernetes.io/path: 'foo/functions/bar.yaml'}}}
|
||||
`, s) {
|
||||
t.FailNow()
|
||||
}
|
||||
},
|
||||
}).Filter(input)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
if !assert.True(t, called) {
|
||||
return
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
err = kio.ByteWriter{Writer: b, KeepReaderAnnotations: true}.Write(result)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
annotations:
|
||||
config.kubernetes.io/index: '0'
|
||||
config.kubernetes.io/path: 'foo/deployment_deployment-foo.yaml'
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: service-foo
|
||||
annotations:
|
||||
config.kubernetes.io/index: '1'
|
||||
config.kubernetes.io/path: 'foo/service_service-foo.yaml'
|
||||
`, b.String())
|
||||
}
|
||||
|
||||
func TestFilter_Filter_scopeMissingFromResource(t *testing.T) {
|
||||
cfg, err := yaml.Parse(`apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'foo/bar.yaml'
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
input, err := (&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: service-foo
|
||||
`)}).Read()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// no resources match the scope
|
||||
called := false
|
||||
result, err := (&ContainerFilter{
|
||||
Image: "example.com:version",
|
||||
Config: cfg,
|
||||
args: []string{"sed", "s/Deployment/StatefulSet/g"},
|
||||
checkInput: func(s string) {
|
||||
called = true
|
||||
if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items: []
|
||||
functionConfig: {apiVersion: apps/v1, kind: Deployment, metadata: {name: foo, annotations: {
|
||||
config.kubernetes.io/path: 'foo/bar.yaml'}}}
|
||||
`, s) {
|
||||
t.FailNow()
|
||||
}
|
||||
},
|
||||
}).Filter(input)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
if !assert.True(t, called) {
|
||||
return
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
err = kio.ByteWriter{Writer: b, KeepReaderAnnotations: true}.Write(result)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// Resources should be preserved -- paths shouldn't be set by container
|
||||
assert.Equal(t, `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
annotations:
|
||||
config.kubernetes.io/index: '0'
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: service-foo
|
||||
annotations:
|
||||
config.kubernetes.io/index: '1'
|
||||
`, b.String())
|
||||
}
|
||||
|
||||
func TestFilter_Filter_scopeFunctionsDir(t *testing.T) {
|
||||
// functions under "functions/" dir should be scoped to parent dir
|
||||
cfg, err := yaml.Parse(`apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'foo/functions/bar.yaml'
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
input, err := (&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'foo/bar/d.yaml'
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: service-foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'foo/bar/s.yaml'
|
||||
`)}).Read()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// no resources match the scope
|
||||
called := false
|
||||
result, err := (&ContainerFilter{
|
||||
Image: "example.com:version",
|
||||
Config: cfg,
|
||||
args: []string{"sed", "s/Deployment/StatefulSet/g"},
|
||||
checkInput: func(s string) {
|
||||
called = true
|
||||
if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'foo/bar/d.yaml'
|
||||
config.kubernetes.io/index: '0'
|
||||
- apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: service-foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'foo/bar/s.yaml'
|
||||
config.kubernetes.io/index: '1'
|
||||
functionConfig: {apiVersion: apps/v1, kind: Deployment, metadata: {name: foo, annotations: {
|
||||
config.kubernetes.io/path: 'foo/functions/bar.yaml'}}}
|
||||
`, s) {
|
||||
t.FailNow()
|
||||
}
|
||||
},
|
||||
}).Filter(input)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
if !assert.True(t, called) {
|
||||
return
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
err = kio.ByteWriter{Writer: b, KeepReaderAnnotations: true}.Write(result)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// Resources should be modified
|
||||
assert.Equal(t, `apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'foo/bar/d.yaml'
|
||||
config.kubernetes.io/index: '0'
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: service-foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'foo/bar/s.yaml'
|
||||
config.kubernetes.io/index: '1'
|
||||
`, b.String())
|
||||
}
|
||||
|
||||
func TestFilter_Filter_scopeDir(t *testing.T) {
|
||||
// functions under "functions/" dir should be scoped to parent dir
|
||||
cfg, err := yaml.Parse(`apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'foo/bar.yaml'
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
input, err := (&kio.ByteReader{Reader: bytes.NewBufferString(`
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'foo/bar/d.yaml'
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: service-foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'foo/bar/s.yaml'
|
||||
`)}).Read()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// no resources match the scope
|
||||
called := false
|
||||
result, err := (&ContainerFilter{
|
||||
Image: "example.com:version",
|
||||
Config: cfg,
|
||||
args: []string{"sed", "s/Deployment/StatefulSet/g"},
|
||||
checkInput: func(s string) {
|
||||
called = true
|
||||
if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'foo/bar/d.yaml'
|
||||
config.kubernetes.io/index: '0'
|
||||
- apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: service-foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'foo/bar/s.yaml'
|
||||
config.kubernetes.io/index: '1'
|
||||
functionConfig: {apiVersion: apps/v1, kind: Deployment, metadata: {name: foo, annotations: {
|
||||
config.kubernetes.io/path: 'foo/bar.yaml'}}}
|
||||
`, s) {
|
||||
t.FailNow()
|
||||
}
|
||||
},
|
||||
}).Filter(input)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
if !assert.True(t, called) {
|
||||
return
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
err = kio.ByteWriter{Writer: b, KeepReaderAnnotations: true}.Write(result)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// Resources should be preserved
|
||||
assert.Equal(t, `apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'foo/bar/d.yaml'
|
||||
config.kubernetes.io/index: '0'
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: service-foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'foo/bar/s.yaml'
|
||||
config.kubernetes.io/index: '1'
|
||||
`, b.String())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user