mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-11 00:52:55 +00:00
Remove starlark support
Signed-off-by: Davanum Srinivas <davanum@gmail.com>
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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"}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user