mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-30 09:51:23 +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()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ require (
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/xlab/treeprint v1.2.0
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5
|
||||
golang.org/x/sys v0.21.0
|
||||
google.golang.org/protobuf v1.33.0
|
||||
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -75,9 +72,6 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
|
||||
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc=
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
|
||||
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# kyaml internal forks
|
||||
|
||||
## qri-io/starlib
|
||||
|
||||
This code is used by the starlark runtime. We copied it in to reduce the dependencies being brought over to kubectl by the kustomize integration. Should it need updating, do so via manual copy-paste.
|
||||
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 QRI, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -1,25 +0,0 @@
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2018 QRI, Inc.
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package util is forked from https://github.com/qri-io/starlib in order to prune
|
||||
// excessive transitive dependencies from pulling in that library.
|
||||
package util
|
||||
@@ -1,275 +0,0 @@
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2018 QRI, Inc.
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"go.starlark.net/starlark"
|
||||
"go.starlark.net/starlarkstruct"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
)
|
||||
|
||||
// // asString unquotes a starlark string value
|
||||
// func asString(x starlark.Value) (string, error) {
|
||||
// return strconv.Unquote(x.String())
|
||||
// }
|
||||
|
||||
// IsEmptyString checks is a starlark string is empty ("" for a go string)
|
||||
// starlark.String.String performs repr-style quotation, which is necessary
|
||||
// for the starlark.Value contract but a frequent source of errors in API
|
||||
// clients. This helper method makes sure it'll work properly
|
||||
func IsEmptyString(s starlark.String) bool {
|
||||
return s.String() == `""`
|
||||
}
|
||||
|
||||
// Unmarshal decodes a starlark.Value into it's golang counterpart
|
||||
//
|
||||
//nolint:nakedret
|
||||
func Unmarshal(x starlark.Value) (val interface{}, err error) {
|
||||
switch v := x.(type) {
|
||||
case starlark.NoneType:
|
||||
val = nil
|
||||
case starlark.Bool:
|
||||
val = v.Truth() == starlark.True
|
||||
case starlark.Int:
|
||||
val, err = starlark.AsInt32(x)
|
||||
case starlark.Float:
|
||||
if f, ok := starlark.AsFloat(x); !ok {
|
||||
err = fmt.Errorf("couldn't parse float")
|
||||
} else {
|
||||
val = f
|
||||
}
|
||||
case starlark.String:
|
||||
val = v.GoString()
|
||||
// case starlibtime.Time:
|
||||
// val = time.Time(v)
|
||||
case *starlark.Dict:
|
||||
var (
|
||||
dictVal starlark.Value
|
||||
pval interface{}
|
||||
kval interface{}
|
||||
keys []interface{}
|
||||
vals []interface{}
|
||||
// key as interface if found one key is not a string
|
||||
ki bool
|
||||
)
|
||||
|
||||
for _, k := range v.Keys() {
|
||||
dictVal, _, err = v.Get(k)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pval, err = Unmarshal(dictVal)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unmarshaling starlark value: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
kval, err = Unmarshal(k)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unmarshaling starlark key: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := kval.(string); !ok {
|
||||
// found key as not a string
|
||||
ki = true
|
||||
}
|
||||
|
||||
keys = append(keys, kval)
|
||||
vals = append(vals, pval)
|
||||
}
|
||||
|
||||
// prepare result
|
||||
|
||||
rs := map[string]interface{}{}
|
||||
ri := map[interface{}]interface{}{}
|
||||
|
||||
for i, key := range keys {
|
||||
// key as interface
|
||||
if ki {
|
||||
ri[key] = vals[i]
|
||||
} else {
|
||||
rs[key.(string)] = vals[i]
|
||||
}
|
||||
}
|
||||
|
||||
if ki {
|
||||
val = ri // map[interface{}]interface{}
|
||||
} else {
|
||||
val = rs // map[string]interface{}
|
||||
}
|
||||
case *starlark.List:
|
||||
var (
|
||||
i int
|
||||
listVal starlark.Value
|
||||
iter = v.Iterate()
|
||||
value = make([]interface{}, v.Len())
|
||||
)
|
||||
|
||||
defer iter.Done()
|
||||
for iter.Next(&listVal) {
|
||||
value[i], err = Unmarshal(listVal)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
i++
|
||||
}
|
||||
val = value
|
||||
case starlark.Tuple:
|
||||
var (
|
||||
i int
|
||||
tupleVal starlark.Value
|
||||
iter = v.Iterate()
|
||||
value = make([]interface{}, v.Len())
|
||||
)
|
||||
|
||||
defer iter.Done()
|
||||
for iter.Next(&tupleVal) {
|
||||
value[i], err = Unmarshal(tupleVal)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
i++
|
||||
}
|
||||
val = value
|
||||
case *starlark.Set:
|
||||
fmt.Println("errnotdone: SET")
|
||||
err = fmt.Errorf("sets aren't yet supported")
|
||||
case *starlarkstruct.Struct:
|
||||
if _var, ok := v.Constructor().(Unmarshaler); ok {
|
||||
err = _var.UnmarshalStarlark(x)
|
||||
if err != nil {
|
||||
err = errors.WrapPrefixf(err, "failed marshal %q to Starlark object", v.Constructor().Type())
|
||||
return
|
||||
}
|
||||
val = _var
|
||||
} else {
|
||||
err = fmt.Errorf("constructor object from *starlarkstruct.Struct not supported Marshaler to starlark object: %s", v.Constructor().Type())
|
||||
}
|
||||
default:
|
||||
fmt.Println("errbadtype:", x.Type())
|
||||
err = fmt.Errorf("unrecognized starlark type: %s", x.Type())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Marshal turns go values into starlark types
|
||||
//
|
||||
//nolint:nakedret
|
||||
func Marshal(data interface{}) (v starlark.Value, err error) {
|
||||
switch x := data.(type) {
|
||||
case nil:
|
||||
v = starlark.None
|
||||
case bool:
|
||||
v = starlark.Bool(x)
|
||||
case string:
|
||||
v = starlark.String(x)
|
||||
case int:
|
||||
v = starlark.MakeInt(x)
|
||||
case int8:
|
||||
v = starlark.MakeInt(int(x))
|
||||
case int16:
|
||||
v = starlark.MakeInt(int(x))
|
||||
case int32:
|
||||
v = starlark.MakeInt(int(x))
|
||||
case int64:
|
||||
v = starlark.MakeInt64(x)
|
||||
case uint:
|
||||
v = starlark.MakeUint(x)
|
||||
case uint8:
|
||||
v = starlark.MakeUint(uint(x))
|
||||
case uint16:
|
||||
v = starlark.MakeUint(uint(x))
|
||||
case uint32:
|
||||
v = starlark.MakeUint(uint(x))
|
||||
case uint64:
|
||||
v = starlark.MakeUint64(x)
|
||||
case float32:
|
||||
v = starlark.Float(float64(x))
|
||||
case float64:
|
||||
v = starlark.Float(x)
|
||||
// case time.Time:
|
||||
// v = starlibtime.Time(x)
|
||||
case []interface{}:
|
||||
var elems = make([]starlark.Value, len(x))
|
||||
for i, val := range x {
|
||||
elems[i], err = Marshal(val)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
v = starlark.NewList(elems)
|
||||
case map[interface{}]interface{}:
|
||||
dict := &starlark.Dict{}
|
||||
var elem starlark.Value
|
||||
for ki, val := range x {
|
||||
var key starlark.Value
|
||||
key, err = Marshal(ki)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
elem, err = Marshal(val)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = dict.SetKey(key, elem); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
v = dict
|
||||
case map[string]interface{}:
|
||||
dict := &starlark.Dict{}
|
||||
var elem starlark.Value
|
||||
for key, val := range x {
|
||||
elem, err = Marshal(val)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = dict.SetKey(starlark.String(key), elem); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
v = dict
|
||||
case Marshaler:
|
||||
v, err = x.MarshalStarlark()
|
||||
default:
|
||||
return starlark.None, fmt.Errorf("unrecognized type: %#v", x)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Unmarshaler is the interface use to unmarshal starlark custom types.
|
||||
type Unmarshaler interface {
|
||||
// UnmarshalStarlark unmarshal a starlark object to custom type.
|
||||
UnmarshalStarlark(starlark.Value) error
|
||||
}
|
||||
|
||||
// Marshaler is the interface use to marshal starlark custom types.
|
||||
type Marshaler interface {
|
||||
// MarshalStarlark marshal a custom type to starlark object.
|
||||
MarshalStarlark() (starlark.Value, error)
|
||||
}
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"sigs.k8s.io/kustomize/kyaml/fn/runtime/container"
|
||||
"sigs.k8s.io/kustomize/kyaml/fn/runtime/exec"
|
||||
"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"
|
||||
@@ -61,9 +60,6 @@ type RunFns struct {
|
||||
// and only use explicit sources
|
||||
NoFunctionsFromInput *bool
|
||||
|
||||
// EnableStarlark will enable functions run as starlark scripts
|
||||
EnableStarlark bool
|
||||
|
||||
// EnableExec will enable exec functions
|
||||
EnableExec bool
|
||||
|
||||
@@ -209,8 +205,6 @@ func (r RunFns) runFunctions(
|
||||
identifier = filter.Image
|
||||
case *exec.Filter:
|
||||
identifier = filter.Path
|
||||
case *starlark.Filter:
|
||||
identifier = filter.String()
|
||||
default:
|
||||
identifier = "unknown-type function"
|
||||
}
|
||||
@@ -496,41 +490,6 @@ func (r *RunFns) ffp(spec runtimeutil.FunctionSpec, api *yaml.RNode, currentUser
|
||||
cf.Exec.DeferFailure = spec.DeferFailure
|
||||
return cf, nil
|
||||
}
|
||||
if r.EnableStarlark && (spec.Starlark.Path != "" || spec.Starlark.URL != "") {
|
||||
// the script path is relative to the function config file
|
||||
m, err := api.GetMeta()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err)
|
||||
}
|
||||
|
||||
var p string
|
||||
if spec.Starlark.Path != "" {
|
||||
pathAnno := m.Annotations[kioutil.PathAnnotation]
|
||||
if pathAnno == "" {
|
||||
pathAnno = m.Annotations[kioutil.LegacyPathAnnotation]
|
||||
}
|
||||
p = filepath.ToSlash(path.Clean(pathAnno))
|
||||
|
||||
spec.Starlark.Path = filepath.ToSlash(path.Clean(spec.Starlark.Path))
|
||||
if filepath.IsAbs(spec.Starlark.Path) || path.IsAbs(spec.Starlark.Path) {
|
||||
return nil, errors.Errorf(
|
||||
"absolute function path %s not allowed", spec.Starlark.Path)
|
||||
}
|
||||
if strings.HasPrefix(spec.Starlark.Path, "..") {
|
||||
return nil, errors.Errorf(
|
||||
"function path %s not allowed to start with ../", spec.Starlark.Path)
|
||||
}
|
||||
p = filepath.ToSlash(filepath.Join(r.Path, filepath.Dir(p), spec.Starlark.Path))
|
||||
}
|
||||
|
||||
sf := &starlark.Filter{Name: spec.Starlark.Name, Path: p, URL: spec.Starlark.URL}
|
||||
|
||||
sf.FunctionConfig = api
|
||||
sf.GlobalScope = r.GlobalScope
|
||||
sf.ResultsFile = resultsFile
|
||||
sf.DeferFailure = spec.DeferFailure
|
||||
return sf, nil
|
||||
}
|
||||
|
||||
if r.EnableExec && spec.Exec.Path != "" {
|
||||
ef := &exec.Filter{
|
||||
|
||||
@@ -255,8 +255,6 @@ func TestRunFns_getFilters(t *testing.T) {
|
||||
// value to set for NoFunctionsFromInput
|
||||
noFunctionsFromInput *bool
|
||||
|
||||
enableStarlark bool
|
||||
|
||||
disableContainers bool
|
||||
}{
|
||||
// Test
|
||||
@@ -589,92 +587,6 @@ metadata:
|
||||
},
|
||||
out: []string{"b", "a", "c"},
|
||||
},
|
||||
|
||||
// Test
|
||||
//
|
||||
//
|
||||
{name: "starlark-function",
|
||||
in: []f{
|
||||
{
|
||||
path: filepath.Join("foo", "bar.yaml"),
|
||||
value: `
|
||||
apiVersion: example.com/v1alpha1
|
||||
kind: ExampleFunction
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/function: |
|
||||
starlark:
|
||||
path: a/b/c
|
||||
`,
|
||||
},
|
||||
},
|
||||
enableStarlark: true,
|
||||
outFn: func(path string) []string {
|
||||
return []string{
|
||||
fmt.Sprintf("name: path: %s/foo/a/b/c url: program:", filepath.ToSlash(path))}
|
||||
},
|
||||
},
|
||||
|
||||
// Test
|
||||
//
|
||||
//
|
||||
{name: "starlark-function-absolute",
|
||||
in: []f{
|
||||
{
|
||||
path: filepath.Join("foo", "bar.yaml"),
|
||||
value: `
|
||||
apiVersion: example.com/v1alpha1
|
||||
kind: ExampleFunction
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/function: |
|
||||
starlark:
|
||||
path: /a/b/c
|
||||
`,
|
||||
},
|
||||
},
|
||||
enableStarlark: true,
|
||||
error: "absolute function path /a/b/c not allowed",
|
||||
},
|
||||
|
||||
// Test
|
||||
//
|
||||
//
|
||||
{name: "starlark-function-escape-parent",
|
||||
in: []f{
|
||||
{
|
||||
path: filepath.Join("foo", "bar.yaml"),
|
||||
value: `
|
||||
apiVersion: example.com/v1alpha1
|
||||
kind: ExampleFunction
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/function: |
|
||||
starlark:
|
||||
path: ../a/b/c
|
||||
`,
|
||||
},
|
||||
},
|
||||
enableStarlark: true,
|
||||
error: "function path ../a/b/c not allowed to start with ../",
|
||||
},
|
||||
|
||||
{name: "starlark-function-disabled",
|
||||
in: []f{
|
||||
{
|
||||
path: filepath.Join("foo", "bar.yaml"),
|
||||
value: `
|
||||
apiVersion: example.com/v1alpha1
|
||||
kind: ExampleFunction
|
||||
metadata:
|
||||
annotations:
|
||||
config.kubernetes.io/function: |
|
||||
starlark:
|
||||
path: a/b/c
|
||||
`,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i := range tests {
|
||||
@@ -722,7 +634,6 @@ metadata:
|
||||
|
||||
// init the instance
|
||||
r := &RunFns{
|
||||
EnableStarlark: tt.enableStarlark,
|
||||
DisableContainers: tt.disableContainers,
|
||||
FunctionPaths: fnPaths,
|
||||
Functions: parsedFns,
|
||||
|
||||
Reference in New Issue
Block a user