mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-11 17:12:51 +00:00
Add kyaml command for invoking container filters
This commit is contained in:
@@ -17,7 +17,7 @@ import (
|
||||
|
||||
const (
|
||||
ResourceListKind = "ResourceList"
|
||||
ResourceListApiVersion = "kyaml.kustomize.dev/v1alpha1"
|
||||
ResourceListApiVersion = "config.kubernetes.io/v1alpha1"
|
||||
)
|
||||
|
||||
// ByteReadWriter reads from an input and writes to an output.
|
||||
|
||||
@@ -34,7 +34,7 @@ i: j
|
||||
}
|
||||
|
||||
func TestByteReader_Read_wrappedResourceßßList(t *testing.T) {
|
||||
r := &ByteReader{Reader: bytes.NewBufferString(`apiVersion: kyaml.kustomize.dev/v1alpha1
|
||||
r := &ByteReader{Reader: bytes.NewBufferString(`apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
functionConfig:
|
||||
foo: bar
|
||||
|
||||
@@ -45,7 +45,7 @@ g:
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, `apiVersion: kyaml.kustomize.dev/v1alpha1
|
||||
assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- c: d # second
|
||||
|
||||
@@ -5,12 +5,13 @@ package filters
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
@@ -24,6 +25,8 @@ import (
|
||||
// The full set of environment variables from the parent process
|
||||
// are passed to the container.
|
||||
type ContainerFilter struct {
|
||||
mountPath string
|
||||
|
||||
// Image is the container image to use to create a container.
|
||||
Image string `yaml:"image,omitempty"`
|
||||
|
||||
@@ -38,6 +41,10 @@ type ContainerFilter struct {
|
||||
checkInput func(string)
|
||||
}
|
||||
|
||||
func (c *ContainerFilter) SetMountPath(path string) {
|
||||
c.mountPath = path
|
||||
}
|
||||
|
||||
// GrepFilter implements kio.GrepFilter
|
||||
func (c *ContainerFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
// get the command to filter the Resources
|
||||
@@ -89,6 +96,10 @@ func (c *ContainerFilter) getArgs() []string {
|
||||
// don't make fs readonly because things like heredoc rely on writing tmp files
|
||||
"--security-opt=no-new-privileges", // don't allow the user to escalate privileges
|
||||
}
|
||||
// mount the directory containing the function as read-only
|
||||
if c.mountPath != "" {
|
||||
args = append(args, "-v", fmt.Sprintf("%s:/local/:ro", c.mountPath))
|
||||
}
|
||||
|
||||
// export the local environment vars to the container
|
||||
for _, pair := range os.Environ() {
|
||||
@@ -141,7 +152,8 @@ type IsReconcilerFilter struct {
|
||||
func (c *IsReconcilerFilter) Filter(inputs []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
var out []*yaml.RNode
|
||||
for i := range inputs {
|
||||
isContainerResource := GetContainerName(inputs[i]) != ""
|
||||
img, _ := GetContainerName(inputs[i])
|
||||
isContainerResource := img != ""
|
||||
if isContainerResource && !c.ExcludeReconcilers {
|
||||
out = append(out, inputs[i])
|
||||
}
|
||||
@@ -153,19 +165,20 @@ func (c *IsReconcilerFilter) Filter(inputs []*yaml.RNode) ([]*yaml.RNode, error)
|
||||
}
|
||||
|
||||
// GetContainerName returns the container image for an API if one exists
|
||||
func GetContainerName(n *yaml.RNode) string {
|
||||
func GetContainerName(n *yaml.RNode) (string, string) {
|
||||
meta, _ := n.GetMeta()
|
||||
container := meta.Annotations["kyaml.kustomize.dev/container"]
|
||||
|
||||
// path to the function, this will be mounted into the container
|
||||
path := meta.Annotations[kioutil.PathAnnotation]
|
||||
|
||||
container := meta.Annotations["config.kubernetes.io/container"]
|
||||
if container != "" {
|
||||
return container
|
||||
return container, path
|
||||
}
|
||||
|
||||
if match.MatchString(meta.ApiVersion) {
|
||||
return meta.ApiVersion
|
||||
image, err := n.Pipe(yaml.Lookup("metadata", "configFn", "container", "image"))
|
||||
if err != nil || yaml.IsMissingOrNull(image) {
|
||||
return "", path
|
||||
}
|
||||
|
||||
return ""
|
||||
return image.YNode().Value, path
|
||||
}
|
||||
|
||||
// match specifies the set of apiVersions to recognize as being container images
|
||||
var match = regexp.MustCompile(`(docker\.io|.*\.?gcr\.io)/.*(:.*)?`)
|
||||
|
||||
@@ -5,7 +5,9 @@ package filters
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -60,6 +62,54 @@ metadata:
|
||||
assert.True(t, foundKyaml)
|
||||
}
|
||||
|
||||
func TestFilter_commandMountPath(t *testing.T) {
|
||||
cfg, err := yaml.Parse(`apiversion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: foo
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
instance := &ContainerFilter{
|
||||
Image: "example.com:version",
|
||||
Config: cfg,
|
||||
mountPath: filepath.Join("mount", "path"),
|
||||
}
|
||||
os.Setenv("KYAML_TEST", "FOO")
|
||||
cmd, err := instance.getCommand()
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
expected := []string{
|
||||
"docker", "run",
|
||||
"--rm",
|
||||
"-i", "-a", "STDIN", "-a", "STDOUT", "-a", "STDERR",
|
||||
"--network", "none",
|
||||
"--user", "nobody",
|
||||
"--security-opt=no-new-privileges",
|
||||
"-v", fmt.Sprintf("%s:/local/:ro", filepath.Join("mount", "path")),
|
||||
}
|
||||
for _, e := range os.Environ() {
|
||||
// the process env
|
||||
expected = append(expected, "-e", strings.Split(e, "=")[0])
|
||||
}
|
||||
expected = append(expected, "example.com:version")
|
||||
assert.Equal(t, expected, cmd.Args)
|
||||
|
||||
foundKyaml := false
|
||||
for _, e := range cmd.Env {
|
||||
// verify the command has the right environment variables to pass to the container
|
||||
split := strings.Split(e, "=")
|
||||
if split[0] == "KYAML_TEST" {
|
||||
assert.Equal(t, "FOO", split[1])
|
||||
foundKyaml = true
|
||||
}
|
||||
}
|
||||
assert.True(t, foundKyaml)
|
||||
}
|
||||
|
||||
func TestFilter_Filter(t *testing.T) {
|
||||
cfg, err := yaml.Parse(`apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -92,7 +142,7 @@ metadata:
|
||||
args: []string{"sed", "s/Deployment/StatefulSet/g"},
|
||||
checkInput: func(s string) {
|
||||
called = true
|
||||
if !assert.Equal(t, `apiVersion: kyaml.kustomize.dev/v1alpha1
|
||||
if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: apps/v1
|
||||
@@ -174,7 +224,7 @@ metadata:
|
||||
args: []string{"sh", "-c", "cat <&0"},
|
||||
checkInput: func(s string) {
|
||||
called = true
|
||||
if !assert.Equal(t, `apiVersion: kyaml.kustomize.dev/v1alpha1
|
||||
if !assert.Equal(t, `apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiversion: apps/v1
|
||||
@@ -226,36 +276,30 @@ metadata:
|
||||
|
||||
func Test_GetContainerName(t *testing.T) {
|
||||
// make sure gcr.io works
|
||||
n, err := yaml.Parse(`apiVersion: gcr.io/foo/bar:something
|
||||
n, err := yaml.Parse(`apiVersion: v1beta1
|
||||
kind: MyThing
|
||||
metadata:
|
||||
configFn:
|
||||
container:
|
||||
image: gcr.io/foo/bar:something
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
c := GetContainerName(n)
|
||||
c, _ := GetContainerName(n)
|
||||
assert.Equal(t, "gcr.io/foo/bar:something", c)
|
||||
|
||||
// make sure regional gcr.io works
|
||||
n, err = yaml.Parse(`apiVersion: us.gcr.io/foo/bar:something
|
||||
kind: MyThing
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
c = GetContainerName(n)
|
||||
assert.Equal(t, "us.gcr.io/foo/bar:something", c)
|
||||
|
||||
// container from annotation
|
||||
n, err = yaml.Parse(`apiVersion: v1
|
||||
kind: MyThing
|
||||
metadata:
|
||||
annotations:
|
||||
kyaml.kustomize.dev/container: gcr.io/foo/bar:something
|
||||
config.kubernetes.io/container: gcr.io/foo/bar:something
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
c = GetContainerName(n)
|
||||
c, _ = GetContainerName(n)
|
||||
assert.Equal(t, "gcr.io/foo/bar:something", c)
|
||||
|
||||
// doesn't have a container
|
||||
@@ -266,16 +310,6 @@ metadata:
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
c = GetContainerName(n)
|
||||
c, _ = GetContainerName(n)
|
||||
assert.Equal(t, "", c)
|
||||
|
||||
// make sure docker.io works
|
||||
n, err = yaml.Parse(`apiVersion: docker.io/foo/bar:something
|
||||
kind: MyThing
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
c = GetContainerName(n)
|
||||
assert.Equal(t, "docker.io/foo/bar:something", c)
|
||||
}
|
||||
|
||||
38
kyaml/kio/filters/local.go
Normal file
38
kyaml/kio/filters/local.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package filters
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
const LocalConfigAnnotation = "config.kubernetes.io/local-config"
|
||||
|
||||
// IsLocalConfig filters Resources using the config.kubernetes.io/local-config annotation
|
||||
type IsLocalConfig struct {
|
||||
// IncludeLocalConfig will include local-config if set to true
|
||||
IncludeLocalConfig bool `yaml:"includeLocalConfig,omitempty"`
|
||||
|
||||
// ExcludeNonLocalConfig will exclude non local-config if set to true
|
||||
ExcludeNonLocalConfig bool `yaml:"excludeNonLocalConfig,omitempty"`
|
||||
}
|
||||
|
||||
// Filter implements kio.Filter
|
||||
func (c *IsLocalConfig) Filter(inputs []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
var out []*yaml.RNode
|
||||
for i := range inputs {
|
||||
meta, err := inputs[i].GetMeta()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, local := meta.Annotations[LocalConfigAnnotation]
|
||||
|
||||
if local && c.IncludeLocalConfig {
|
||||
out = append(out, inputs[i])
|
||||
} else if !local && !c.ExcludeNonLocalConfig {
|
||||
out = append(out, inputs[i])
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
mergeSourceAnnotation = "kyaml.kustomize.dev/merge-source"
|
||||
mergeSourceAnnotation = "config.kubernetes.io/merge-source"
|
||||
mergeSourceOriginal = "original"
|
||||
mergeSourceUpdated = "updated"
|
||||
mergeSourceDest = "dest"
|
||||
|
||||
Reference in New Issue
Block a user