...

Package starlark

import "sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark"
Overview
Index
Examples

Overview ▾

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

type Context

type Context struct {
    // contains filtered or unexported fields
}

type Filter

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 (*Filter) Filter

func (sf *Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error)

Example

Code:

// 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"}

Example (File)

ExampleFilter_Filter_file applies a starlark program in a local file to a collection of resource configuration read from a directory.

Code:

// 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"}

Example (FunctionConfig)

Code:

// 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"}

func (*Filter) Run

func (sf *Filter) Run(reader io.Reader, writer io.Writer) error

func (*Filter) String

func (sf *Filter) String() string