Remove starlark support

Signed-off-by: Davanum Srinivas <davanum@gmail.com>
This commit is contained in:
Davanum Srinivas
2024-09-23 16:52:05 -04:00
parent 88f19bffa9
commit d32eacf034
91 changed files with 285 additions and 2410 deletions

View File

@@ -132,9 +132,6 @@ type FunctionSpec struct {
// Container is the spec for running a function as a container
Container ContainerSpec `json:"container,omitempty" yaml:"container,omitempty"`
// Starlark is the spec for running a function as a starlark script
Starlark StarlarkSpec `json:"starlark,omitempty" yaml:"starlark,omitempty"`
// ExecSpec is the spec for running a function as an executable
Exec ExecSpec `json:"exec,omitempty" yaml:"exec,omitempty"`
}
@@ -158,17 +155,6 @@ type ContainerSpec struct {
Env []string `json:"envs,omitempty" yaml:"envs,omitempty"`
}
// StarlarkSpec defines how to run a function as a starlark program
type StarlarkSpec struct {
Name string `json:"name,omitempty" yaml:"name,omitempty"`
// Path specifies a path to a starlark script
Path string `json:"path,omitempty" yaml:"path,omitempty"`
// URL specifies a url containing a starlark script
URL string `json:"url,omitempty" yaml:"url,omitempty"`
}
// StorageMount represents a container's mounted storage option(s)
type StorageMount struct {
// Type of mount e.g. bind mount, local volume, etc.

View File

@@ -1,79 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package starlark
import (
"encoding/json"
"os"
"strings"
"go.starlark.net/starlark"
"go.starlark.net/starlarkstruct"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
type Context struct {
resourceList starlark.Value
}
func (c *Context) predeclared() (starlark.StringDict, error) {
e, err := env()
if err != nil {
return nil, err
}
oa, err := oa()
if err != nil {
return nil, err
}
dict := starlark.StringDict{
"resource_list": c.resourceList,
"open_api": oa,
"environment": e,
}
return starlark.StringDict{
"ctx": starlarkstruct.FromStringDict(starlarkstruct.Default, dict),
}, nil
}
func oa() (starlark.Value, error) {
return interfaceToValue(openapi.Schema())
}
func env() (starlark.Value, error) {
env := map[string]interface{}{}
for _, e := range os.Environ() {
pair := strings.SplitN(e, "=", 2)
if len(pair) < 2 {
continue
}
env[pair[0]] = pair[1]
}
value, err := util.Marshal(env)
if err != nil {
return nil, errors.Wrap(err)
}
return value, nil
}
func interfaceToValue(i interface{}) (starlark.Value, error) {
b, err := json.Marshal(i)
if err != nil {
return nil, err
}
var in map[string]interface{}
if err := yaml.Unmarshal(b, &in); err != nil {
return nil, errors.Wrap(err)
}
value, err := util.Marshal(in)
if err != nil {
return nil, errors.Wrap(err)
}
return value, nil
}

View File

@@ -1,36 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package starlark contains a kio.Filter which can be applied to resources to transform
// them through starlark program.
//
// Starlark has become a popular runtime embedding in go programs, especially for Kubernetes
// and data processing.
// Examples: https://github.com/cruise-automation/isopod, https://qri.io/docs/starlark/starlib,
// https://github.com/stripe/skycfg, https://github.com/k14s/ytt
//
// The resources are provided to the starlark program through the global variable "resourceList".
// "resourceList" is a dictionary containing an "items" field with a list of resources.
// The starlark modified "resourceList" is the Filter output.
//
// After being run through the starlark program, the filter will copy the comments from the input
// resources to restore them -- due to them being dropped as a result of serializing the resources
// as starlark values.
//
// "resourceList" may also contain a "functionConfig" entry to configure the starlark script itself.
// Changes made by the starlark program to the "functionConfig" will be reflected in the
// Filter.FunctionConfig value.
//
// The Filter will also format the output so that output has the preferred field ordering
// rather than an alphabetical field ordering.
//
// The resourceList variable adheres to the kustomize function spec as specified by:
// https://github.com/kubernetes-sigs/kustomize/blob/master/cmd/config/docs/api-conventions/functions-spec.md
//
// All items in the resourceList are resources represented as starlark dictionaries/
// The items in the resourceList respect the io spec specified by:
// https://github.com/kubernetes-sigs/kustomize/blob/master/cmd/config/docs/api-conventions/config-io.md
//
// The starlark language spec can be found here:
// https://github.com/google/starlark-go/blob/master/doc/spec.md
package starlark

View File

@@ -1,302 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package starlark_test
import (
"bytes"
"fmt"
"log"
"os"
"path/filepath"
"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
"sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
func ExampleFilter_Filter() {
// input contains the items that will provided to the starlark program
input := bytes.NewBufferString(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-1
spec:
template:
spec:
containers:
- name: nginx
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image-1"}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-2
spec:
template:
spec:
containers:
- name: nginx
image: nginx:1.7.9 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image-2"}
`)
// fltr transforms the input using a starlark program
fltr := &starlark.Filter{
Name: "annotate",
Program: `
def run(items):
for item in items:
item["metadata"]["annotations"]["foo"] = "bar"
run(ctx.resource_list["items"])
`,
}
// output contains the transformed resources
output := &bytes.Buffer{}
// run the fltr against the inputs using a kio.Pipeline
err := kio.Pipeline{
Inputs: []kio.Reader{&kio.ByteReader{Reader: input}},
Filters: []kio.Filter{fltr},
Outputs: []kio.Writer{&kio.ByteWriter{Writer: output}}}.Execute()
if err != nil {
log.Println(err)
}
fmt.Println(output.String())
// Output:
// apiVersion: apps/v1
// kind: Deployment
// metadata:
// name: deployment-1
// annotations:
// foo: bar
// internal.config.kubernetes.io/path: 'deployment_deployment-1.yaml'
// config.kubernetes.io/path: 'deployment_deployment-1.yaml'
// spec:
// template:
// spec:
// containers:
// - name: nginx
// image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image-1"}
//---
// apiVersion: apps/v1
// kind: Deployment
// metadata:
// name: deployment-2
// annotations:
// foo: bar
// internal.config.kubernetes.io/path: 'deployment_deployment-2.yaml'
// config.kubernetes.io/path: 'deployment_deployment-2.yaml'
// spec:
// template:
// spec:
// containers:
// - name: nginx
// image: nginx:1.7.9 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image-2"}
}
func ExampleFilter_Filter_functionConfig() {
// input contains the items that will provided to the starlark program
input := bytes.NewBufferString(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-1
spec:
template:
spec:
containers:
- name: nginx
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image-1"}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-2
spec:
template:
spec:
containers:
- name: nginx
image: nginx:1.7.9 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image-2"}
`)
fc, err := yaml.Parse(`
kind: AnnotationSetter
spec:
value: "hello world"
`)
if err != nil {
log.Println(err)
}
// fltr transforms the input using a starlark program
fltr := &starlark.Filter{
Name: "annotate",
Program: `
def run(items, value):
for item in items:
item["metadata"]["annotations"]["foo"] = value
run(ctx.resource_list["items"], ctx.resource_list["functionConfig"]["spec"]["value"])
`,
FunctionFilter: runtimeutil.FunctionFilter{FunctionConfig: fc},
}
// output contains the transformed resources
output := &bytes.Buffer{}
// run the fltr against the inputs using a kio.Pipeline
err = kio.Pipeline{
Inputs: []kio.Reader{&kio.ByteReader{Reader: input}},
Filters: []kio.Filter{fltr},
Outputs: []kio.Writer{&kio.ByteWriter{Writer: output}}}.Execute()
if err != nil {
log.Println(err)
}
fmt.Println(output.String())
// Output:
// apiVersion: apps/v1
// kind: Deployment
// metadata:
// name: deployment-1
// annotations:
// foo: hello world
// internal.config.kubernetes.io/path: 'deployment_deployment-1.yaml'
// config.kubernetes.io/path: 'deployment_deployment-1.yaml'
// spec:
// template:
// spec:
// containers:
// - name: nginx
// image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image-1"}
//---
// apiVersion: apps/v1
// kind: Deployment
// metadata:
// name: deployment-2
// annotations:
// foo: hello world
// internal.config.kubernetes.io/path: 'deployment_deployment-2.yaml'
// config.kubernetes.io/path: 'deployment_deployment-2.yaml'
// spec:
// template:
// spec:
// containers:
// - name: nginx
// image: nginx:1.7.9 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image-2"}
}
// ExampleFilter_Filter_file applies a starlark program in a local file to a collection of
// resource configuration read from a directory.
func ExampleFilter_Filter_file() {
// setup the configuration
d, err := os.MkdirTemp("", "")
if err != nil {
log.Println(err)
}
defer os.RemoveAll(d)
err = os.WriteFile(filepath.Join(d, "deploy1.yaml"), []byte(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-1
spec:
template:
spec:
containers:
- name: nginx
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image-1"}
`), 0600)
if err != nil {
log.Println(err)
}
err = os.WriteFile(filepath.Join(d, "deploy2.yaml"), []byte(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-2
spec:
template:
spec:
containers:
- name: nginx
image: nginx:1.7.9 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image-2"}
`), 0600)
if err != nil {
log.Println(err)
}
err = os.WriteFile(filepath.Join(d, "annotate.star"), []byte(`
def run(items):
for item in items:
item["metadata"]["annotations"]["foo"] = "bar"
run(ctx.resource_list["items"])
`), 0600)
if err != nil {
log.Println(err)
}
fltr := &starlark.Filter{
Name: "annotate",
Path: filepath.Join(d, "annotate.star"),
}
// output contains the transformed resources
output := &bytes.Buffer{}
// run the fltr against the inputs using a kio.Pipeline
err = kio.Pipeline{
Inputs: []kio.Reader{&kio.LocalPackageReader{PackagePath: d}},
Filters: []kio.Filter{fltr},
Outputs: []kio.Writer{&kio.ByteWriter{
Writer: output,
ClearAnnotations: []string{
kioutil.PathAnnotation,
kioutil.LegacyPathAnnotation,
},
}}}.Execute()
if err != nil {
log.Println(err)
}
fmt.Println(output.String())
// Output:
// apiVersion: apps/v1
// kind: Deployment
// metadata:
// name: deployment-1
// annotations:
// foo: bar
// spec:
// template:
// spec:
// containers:
// - name: nginx
// image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image-1"}
//---
// apiVersion: apps/v1
// kind: Deployment
// metadata:
// name: deployment-2
// annotations:
// foo: bar
// spec:
// template:
// spec:
// containers:
// - name: nginx
// image: nginx:1.7.9 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image-2"}
}

View File

@@ -1,180 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package starlark
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
"go.starlark.net/starlark"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
"sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util"
"sigs.k8s.io/kustomize/kyaml/kio/filters"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// Filter transforms a set of resources through the provided program
type Filter struct {
Name string
// Program is a starlark script which will be run against the resources
Program string
// URL is the url of a starlark program to fetch and run
URL string
// Path is the path to a starlark program to read and run
Path string
runtimeutil.FunctionFilter
}
func (sf *Filter) String() string {
return fmt.Sprintf(
"name: %v path: %v url: %v program: %v", sf.Name, sf.Path, sf.URL, sf.Program)
}
func (sf *Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
if err := sf.setup(); err != nil {
return nil, err
}
sf.FunctionFilter.Run = sf.Run
return sf.FunctionFilter.Filter(nodes)
}
func (sf *Filter) setup() error {
if (sf.URL != "" && sf.Path != "") ||
(sf.URL != "" && sf.Program != "") ||
(sf.Path != "" && sf.Program != "") {
return errors.Errorf("Filter Path, Program and URL are mutually exclusive")
}
// read the program from a file
if sf.Path != "" {
b, err := os.ReadFile(sf.Path)
if err != nil {
return err
}
sf.Program = string(b)
}
// read the program from a URL
if sf.URL != "" {
err := func() error {
resp, err := http.Get(sf.URL)
if err != nil {
return err
}
defer resp.Body.Close()
b, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
sf.Program = string(b)
return nil
}()
if err != nil {
return err
}
}
return nil
}
func (sf *Filter) Run(reader io.Reader, writer io.Writer) error {
// retain map of inputs to outputs by id so if the name is changed by the
// starlark program, we are able to match the same resources
value, err := sf.readResourceList(reader)
if err != nil {
return errors.Wrap(err)
}
// run the starlark as program as transformation function
thread := &starlark.Thread{Name: sf.Name}
ctx := &Context{resourceList: value}
pd, err := ctx.predeclared()
if err != nil {
return errors.Wrap(err)
}
_, err = starlark.ExecFile(thread, sf.Name, sf.Program, pd)
if err != nil {
return errors.Wrap(err)
}
return sf.writeResourceList(value, writer)
}
// inputToResourceList transforms input into a starlark.Value
func (sf *Filter) readResourceList(reader io.Reader) (starlark.Value, error) {
// read and parse the inputs
rl := bytes.Buffer{}
_, err := rl.ReadFrom(reader)
if err != nil {
return nil, errors.Wrap(err)
}
rn, err := yaml.Parse(rl.String())
if err != nil {
return nil, errors.Wrap(err)
}
// convert to a starlark value
b, err := yaml.Marshal(rn.Document()) // convert to bytes
if err != nil {
return nil, errors.Wrap(err)
}
var in map[string]interface{}
err = yaml.Unmarshal(b, &in) // convert to map[string]interface{}
if err != nil {
return nil, errors.Wrap(err)
}
return util.Marshal(in) // convert to starlark value
}
// resourceListToOutput converts the output of the starlark program to the filter output
func (sf *Filter) writeResourceList(value starlark.Value, writer io.Writer) error {
// convert the modified resourceList back into a slice of RNodes
// by first converting to a map[string]interface{}
out, err := util.Unmarshal(value)
if err != nil {
return errors.Wrap(err)
}
b, err := yaml.Marshal(out)
if err != nil {
return errors.Wrap(err)
}
rl, err := yaml.Parse(string(b))
if err != nil {
return errors.Wrap(err)
}
// preserve the comments from the input
items, err := rl.Pipe(yaml.Lookup("items"))
if err != nil {
return errors.Wrap(err)
}
err = items.VisitElements(func(node *yaml.RNode) error {
// starlark will serialize the resources sorting the fields alphabetically,
// format them to have a better ordering
_, err := filters.FormatFilter{}.Filter([]*yaml.RNode{node})
return err
})
if err != nil {
return errors.Wrap(err)
}
s, err := rl.String()
if err != nil {
return errors.Wrap(err)
}
_, err = writer.Write([]byte(s))
return err
}

View File

@@ -1,537 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package starlark
import (
"bytes"
"fmt"
"os"
"strings"
"testing"
"github.com/go-errors/errors"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
func TestFilter_Filter(t *testing.T) {
var tests = []struct {
name string
input string
functionConfig string
script string
expected string
expectedFunctionConfig string
env map[string]string
}{
{
name: "add_annotation",
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
script: `
# set the foo annotation on each resource
def run(r):
for resource in r:
resource["metadata"]["annotations"]["foo"] = "bar"
run(ctx.resource_list["items"])
`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
annotations:
foo: bar
internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
},
{
name: "add_annotation_from_env",
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
script: `
def run(r):
for resource in r:
resource["metadata"]["annotations"]["foo"] = ctx.environment["ANNOTATION"]
run(ctx.resource_list["items"])
`,
env: map[string]string{"ANNOTATION": "annotation-value"},
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
annotations:
foo: annotation-value
internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
},
{
name: "add_annotation_from_open_api",
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
script: `
def run(r):
for resource in r:
resource["metadata"]["annotations"]["foo"] = ctx.open_api["definitions"]["io.k8s.api.apps.v1.Deployment"]["description"]
run(ctx.resource_list["items"])
`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
annotations:
foo: Deployment enables declarative updates for Pods and ReplicaSets.
internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
},
{
name: "update_annotation",
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
annotations:
foo: baz
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
script: `
# set the foo annotation on each resource
def run(r):
for resource in r:
resource["metadata"]["annotations"]["foo"] = "bar"
run(ctx.resource_list["items"])
`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
annotations:
foo: bar
internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
},
{
name: "delete_annotation",
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
annotations:
foo: baz
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
script: `
# set the foo annotation on each resource
def run(r):
for resource in r:
resource["metadata"]["annotations"].pop("foo")
run(ctx.resource_list["items"])
`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
annotations:
internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
},
{
name: "update_annotation_multiple",
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-1
annotations:
foo: baz
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-2
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
script: `
# set the foo annotation on each resource
def run(r):
for resource in r:
resource["metadata"]["annotations"]["foo"] = "bar"
run(ctx.resource_list["items"])
`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-1
annotations:
foo: bar
internal.config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-2
annotations:
foo: bar
internal.config.kubernetes.io/path: 'deployment_nginx-deployment-2.yaml'
config.kubernetes.io/path: 'deployment_nginx-deployment-2.yaml'
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}`,
},
{
name: "add_resource",
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-1
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
script: `
def run(r):
d = {
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "nginx-deployment-2",
},
}
r.append(d)
run(ctx.resource_list["items"])
`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-1
annotations:
internal.config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-2
annotations:
internal.config.kubernetes.io/path: 'deployment_nginx-deployment-2.yaml'
config.kubernetes.io/path: 'deployment_nginx-deployment-2.yaml'
`,
},
{
name: "remove_resource",
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-2
`,
script: `
def run(r):
r.pop()
run(ctx.resource_list["items"])
`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-1
annotations:
internal.config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
`,
},
{
name: "functionConfig",
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
functionConfig: `
kind: Script
spec:
value: "hello world"
`,
script: `
# set the foo annotation on each resource
def run(r, an):
for resource in r:
resource["metadata"]["annotations"]["foo"] = an
an = ctx.resource_list["functionConfig"]["spec"]["value"]
run(ctx.resource_list["items"], an)
`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
annotations:
foo: hello world
internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
expectedFunctionConfig: `
kind: Script
spec:
value: "hello world"
`,
},
{
name: "functionConfig_update_functionConfig",
input: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
functionConfig: `
kind: Script
spec:
value: "hello world"
`,
script: `
# set the foo annotation on each resource
def run(r, an):
for resource in r:
resource["metadata"]["annotations"]["foo"] = an
an = ctx.resource_list["functionConfig"]["spec"]["value"]
run(ctx.resource_list["items"], an)
ctx.resource_list["functionConfig"]["spec"]["value"] = "updated"
`,
expected: `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
annotations:
foo: hello world
internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
spec:
template:
spec:
containers:
- name: nginx
# head comment
image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
`,
expectedFunctionConfig: `
kind: Script
spec:
value: "hello world"
`,
},
}
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
for k, v := range test.env {
os.Setenv(k, v)
}
f := &Filter{Name: test.name, Program: test.script}
if test.functionConfig != "" {
fc, err := yaml.Parse(test.functionConfig)
if !assert.NoError(t, err) {
t.FailNow()
}
f.FunctionConfig = fc
}
r := &kio.ByteReader{Reader: bytes.NewBufferString(test.input)}
o := &bytes.Buffer{}
w := &kio.ByteWriter{Writer: o}
p := kio.Pipeline{
Inputs: []kio.Reader{r},
Filters: []kio.Filter{f},
Outputs: []kio.Writer{w},
}
err := p.Execute()
if !assert.NoError(t, err) {
if e, ok := err.(*errors.Error); ok {
fmt.Fprintf(os.Stderr, "%s\n", e.Stack())
}
t.FailNow()
}
if !assert.Equal(t, strings.TrimSpace(test.expected), strings.TrimSpace(o.String())) {
t.FailNow()
}
if test.expectedFunctionConfig != "" {
if !assert.Equal(t,
strings.TrimSpace(test.expectedFunctionConfig),
strings.TrimSpace(f.FunctionConfig.MustString())) {
t.FailNow()
}
}
})
}
}