framework

package
v0.18.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 27, 2024 License: Apache-2.0 Imports: 22 Imported by: 126

Documentation

Overview

Package framework contains a framework for writing functions in Go. The function specification is defined at: https://github.com/kubernetes-sigs/kustomize/blob/master/cmd/config/docs/api-conventions/functions-spec.md

Functions are executables that generate, modify, delete or validate Kubernetes resources. They are often used used to implement abstractions ("kind: JavaSpringBoot") and cross-cutting logic ("kind: SidecarInjector").

Functions may be run as standalone executables or invoked as part of an orchestrated pipeline (e.g. kustomize).

Example function implementation using framework.SimpleProcessor with a struct input

import (
	"sigs.k8s.io/kustomize/kyaml/errors"
	"sigs.k8s.io/kustomize/kyaml/fn/framework"
	"sigs.k8s.io/kustomize/kyaml/kio"
	"sigs.k8s.io/kustomize/kyaml/yaml"
)

type Spec struct {
	Value string `yaml:"value,omitempty"`
}
type Example struct {
	Spec Spec `yaml:"spec,omitempty"`
}

func runFunction(rlSource *kio.ByteReadWriter) error {
	functionConfig := &Example{}

	fn := func(items []*yaml.RNode) ([]*yaml.RNode, error) {
		for i := range items {
			// modify the items...
		}
		return items, nil
	}

	p := framework.SimpleProcessor{Config: functionConfig, Filter: kio.FilterFunc(fn)}
	err := framework.Execute(p, rlSource)
	return errors.Wrap(err)
}

Architecture

Functions modify a slice of resources (ResourceList.Items) which are read as input and written as output. The function itself may be configured through a functionConfig (ResourceList.FunctionConfig).

Example function input:

kind: ResourceList
items:
- kind: Deployment
  ...
- kind: Service
  ....
functionConfig:
  kind: Example
  spec:
    value: foo

The functionConfig may be specified declaratively and run with

kustomize fn run DIR/

Declarative function declaration:

kind: Example
metadata:
  annotations:
    # run the function by creating this container and providing this
    # Example as the functionConfig
    config.kubernetes.io/function: |
      container:
        image: image/containing/function:impl
spec:
  value: foo

The framework takes care of serializing and deserializing the ResourceList.

Generated ResourceList.functionConfig -- ConfigMaps Functions may also be specified imperatively and run using:

kustomize fn run DIR/ --image image/containing/function:impl -- value=foo

When run imperatively, a ConfigMap is generated for the functionConfig, and the command arguments are set as ConfigMap data entries.

kind: ConfigMap
data:
  value: foo

To write a function that can be run imperatively on the commandline, have it take a ConfigMap as its functionConfig.

Mutator and Generator Functions

Functions may add, delete or modify resources by modifying the ResourceList.Items slice.

Validator Functions

A function may emit validation results by setting the ResourceList.Result

Configuring Functions

Functions may be configured through a functionConfig (i.e. a client-side custom resource), or through flags (which the framework parses from a ConfigMap provided as input).

Functions may also access environment variables set by the caller.

Building a container image for the function

The go program may be built into a container and run as a function. The framework can be used to generate a Dockerfile to build the function container.

# create the ./Dockerfile for the container
$ go run ./main.go gen ./

# build the function's container
$ docker build . -t gcr.io/my-project/my-image:my-version

Index

Examples

Constants

View Source
const FunctionDefinitionGroupVersion = "config.kubernetes.io/v1alpha1"
View Source
const FunctionDefinitionKind = "KRMFunctionDefinition"

Variables

This section is empty.

Functions

func ContainerNameMatcher added in v0.10.14

func ContainerNameMatcher(names ...string) func(node *yaml.RNode) bool

ContainerNameMatcher returns a function that returns true if the "name" field of the provided container node matches one of the given container names. If no names are provided, the function always returns true. Note that this is not a ResourceMatcher, since the node it matches against must be container-level (e.g. "name", "env" and "image" would be top level fields).

func Execute added in v0.10.14

func Execute(p ResourceListProcessor, rlSource *kio.ByteReadWriter) error

Execute is the entrypoint for invoking configuration functions built with this framework from code. See framework/command#Build for a Cobra-based command-line equivalent. Execute reads a ResourceList from the given source, passes it to a ResourceListProcessor, and then writes the result to the target. STDIN and STDOUT will be used if no reader or writer respectively is provided.

func LoadFunctionConfig added in v0.10.14

func LoadFunctionConfig(src *yaml.RNode, api interface{}) error

LoadFunctionConfig reads a configuration resource from YAML into the provided data structure and then prepares it for use by running defaulting and validation on it, if supported. ResourceListProcessors should use this function to load ResourceList.functionConfig.

func SchemaFromFunctionDefinition added in v0.13.4

func SchemaFromFunctionDefinition(gvk resid.Gvk, data string) (*spec.Schema, error)

SchemaFromFunctionDefinition extracts the schema for a particular GVK from the provided KRMFunctionDefinition Since the relevant fields of KRMFunctionDefinition exactly match the ones in CustomResourceDefinition, this helper can also load CRDs (e.g. produced by KubeBuilder) transparently.

Types

type AndSelector added in v0.10.14

type AndSelector struct {
	// Matchers is the list of ResourceMatchers to try on the input resources.
	Matchers []ResourceMatcher
	// TemplateData, if present, is used to initialize any matchers that implement
	// ResourceTemplateMatcher.
	TemplateData interface{}
	// FailOnEmptyMatch makes the selector return an error when no items are selected.
	FailOnEmptyMatch bool
}

AndSelector is a kio.Filter that selects resources when that match all of its embedded matchers.

func MatchAll added in v0.10.14

func MatchAll(matchers ...ResourceMatcher) *AndSelector

MatchAll is a shorthand for building an AndSelector from a list of ResourceMatchers.

func (*AndSelector) DefaultTemplateData added in v0.10.14

func (s *AndSelector) DefaultTemplateData(data interface{})

DefaultTemplateData makes AndSelector a ResourceTemplateMatcher. Although it does not contain templates itself, this allows it to support ResourceTemplateMatchers when being used as a matcher itself.

func (*AndSelector) Filter added in v0.10.14

func (s *AndSelector) Filter(items []*yaml.RNode) ([]*yaml.RNode, error)

Filter implements kio.Filter, returning only those items from the list that the selector matches.

func (*AndSelector) InitTemplates added in v0.10.14

func (s *AndSelector) InitTemplates() error

func (*AndSelector) Match added in v0.10.14

func (s *AndSelector) Match(item *yaml.RNode) bool

Match implements ResourceMatcher so that AndSelectors can be composed

type ContainerPatchTemplate added in v0.10.1

type ContainerPatchTemplate struct {
	// Templates provides a list of templates to render into one or more patches that apply at the container level.
	// For example, "name", "env" and "image" would be top-level fields in container patches.
	Templates TemplateParser

	// Selector targets the rendered patches to containers within specific resources.
	// If no Selector is provided, all resources with containers will be patched (subject to
	// ContainerMatcher, if provided).
	//
	// Although any Filter can be used, this framework provides several especially for Selector use:
	// framework.Selector, framework.AndSelector, framework.OrSelector. You can also use any of the
	// framework's ResourceMatchers here directly.
	Selector kio.Filter

	// TemplateData is the data to use when rendering the templates provided by the Templates field.
	TemplateData interface{}

	// ContainerMatcher targets the rendered patch to only those containers it matches.
	// For example, it can be used with ContainerNameMatcher to patch only containers with
	// specific names. If no ContainerMatcher is provided, all containers will be patched.
	//
	// The node passed to ContainerMatcher will be container-level, not a full resource node.
	// For example, "name", "env" and "image" would be top level fields.
	// To filter based on resource-level context, use the Selector field.
	ContainerMatcher func(node *yaml.RNode) bool
}

ContainerPatchTemplate defines a patch to be applied to containers

func (*ContainerPatchTemplate) DefaultTemplateData added in v0.10.14

func (cpt *ContainerPatchTemplate) DefaultTemplateData(data interface{})

DefaultTemplateData sets TemplateData to the provided default values if it has not already been set.

func (ContainerPatchTemplate) Filter added in v0.10.14

func (cpt ContainerPatchTemplate) Filter(items []*yaml.RNode) ([]*yaml.RNode, error)

Filter applies the ContainerPatchTemplate to the appropriate resources in the input. First, it applies the Selector to identify target resources. Then, it renders the Templates into patches using TemplateData. Finally, it identifies target containers and applies the patches.

type Defaulter added in v0.10.2

type Defaulter interface {
	Default() error
}

Defaulter is implemented by APIs to have Default invoked. The standard application is to create a type to hold your FunctionConfig data, and implement Defaulter on that type. All of the framework's processors will invoke Default() on your type after unmarshalling the FunctionConfig data into it.

type Field

type Field struct {
	// Path is the field path. This field is required.
	Path string `yaml:"path,omitempty" json:"path,omitempty"`

	// CurrentValue is the current field value
	CurrentValue interface{} `yaml:"currentValue,omitempty" json:"currentValue,omitempty"`

	// ProposedValue is the proposed value of the field to fix an issue.
	ProposedValue interface{} `yaml:"proposedValue,omitempty" json:"proposedValue,omitempty"`
}

Field references a field in a resource

type File

type File struct {
	// Path is relative path to the file containing the resource.
	// This field is required.
	Path string `yaml:"path,omitempty" json:"path,omitempty"`

	// Index is the index into the file containing the resource
	// (i.e. if there are multiple resources in a single file)
	Index int `yaml:"index,omitempty" json:"index,omitempty"`
}

File references a file containing a resource

type FilterProvider added in v0.10.14

type FilterProvider interface {
	// ProviderFor returns the appropriate filter for the given APIVersion and Kind.
	ProviderFor(apiVersion, kind string) (kio.Filter, error)
}

FilterProvider is implemented by types that provide a way to look up which Filter should be used to process a ResourceList based on the ApiVersion and Kind of the ResourceList.functionConfig in the input. FilterProviders are intended to be used as part of VersionedAPIProcessor.

type FilterProviderFunc added in v0.10.14

type FilterProviderFunc func(apiVersion, kind string) (kio.Filter, error)

FilterProviderFunc converts a compatible function to a FilterProvider.

func (FilterProviderFunc) ProviderFor added in v0.10.14

func (f FilterProviderFunc) ProviderFor(apiVersion, kind string) (kio.Filter, error)

ProviderFor makes FilterProviderFunc implement FilterProvider.

type GVKFilterMap added in v0.10.14

type GVKFilterMap map[string]map[string]kio.Filter

GVKFilterMap is a FilterProvider that resolves Filters through a simple lookup in a map. It is intended for use in VersionedAPIProcessor.

func (GVKFilterMap) ProviderFor added in v0.10.14

func (m GVKFilterMap) ProviderFor(apiVersion, kind string) (kio.Filter, error)

ProviderFor makes GVKFilterMap implement the FilterProvider interface. It uses the given apiVersion and kind to do a simple lookup in the map and returns an error if no exact match is found.

type KRMFunctionDefinition added in v0.13.4

type KRMFunctionDefinition struct {
	// APIVersion and Kind of the object. Must be config.kubernetes.io/v1alpha1 and KRMFunctionDefinition respectively.
	yaml.TypeMeta `yaml:",inline" json:",inline"`
	// Standard KRM object metadata
	yaml.ObjectMeta `yaml:"metadata,omitempty" json:"metadata,omitempty"`
	// Spec contains the properties of the KRM function this object defines.
	Spec KrmFunctionDefinitionSpec `yaml:"spec" json:"spec"`
}

KRMFunctionDefinition is metadata that defines a KRM function the same way a CRD defines a custom resource. https://github.com/kubernetes/enhancements/tree/master/keps/sig-cli/2906-kustomize-function-catalog#function-metadata-schema

type KRMFunctionNames added in v0.13.4

type KRMFunctionNames struct {
	// Kind is the kind of the defined KRM Function. It is normally CamelCase and singular.
	Kind string `yaml:"kind" json:"kind"`
}

type KRMFunctionValidation added in v0.13.4

type KRMFunctionValidation struct {
	// OpenAPIV3Schema is the OpenAPI v3 schema for an instance of the KRM function.
	OpenAPIV3Schema *spec.Schema `yaml:"openAPIV3Schema,omitempty" json:"openAPIV3Schema,omitempty"` //nolint: tagliatelle
}

type KRMFunctionVersion added in v0.13.4

type KRMFunctionVersion struct {
	//
	// The following fields are shared with CustomResourceDefinition.
	//
	// Name is the version name, e.g. “v1”, “v2beta1”, etc.
	Name string `yaml:"name" json:"name"`
	// Schema describes the schema of this version of the KRM function.
	// This can be used for validation, pruning, and/or defaulting.
	Schema *KRMFunctionValidation `yaml:"schema,omitempty" json:"schema,omitempty"`

	//
	// The following fields are custom to KRMFunctionDefinition
	//
	// Idempotent indicates whether the function can be re-run multiple times without changing the result.
	Idempotent bool `yaml:"idempotent,omitempty" json:"idempotent,omitempty"`
	// Usage is URI pointing to a README.md that describe the details of how to use the KRM function.
	// It should at least cover what the function does and should give a detailed explanation about each
	// field used to configure it.
	Usage string `yaml:"usage,omitempty" json:"usage,omitempty"`
	// A list of URIs that point to README.md files. Each README.md should cover an example.
	// It should at least cover how to get input resources, how to run it and what is the expected
	// output.
	Examples []string `yaml:"examples,omitempty" json:"examples,omitempty"`
	// License is the name of the license covering the function.
	License string `yaml:"license,omitempty" json:"license,omitempty"`
	// The maintainers for this version of the function, if different from the primary maintainers.
	Maintainers []string `yaml:"maintainers,omitempty" json:"maintainers,omitempty"`
	// The runtime information describing how to execute this function.
	Runtime runtimeutil.FunctionSpec `yaml:"runtime" json:"runtime"`
}

type KrmFunctionDefinitionSpec added in v0.13.4

type KrmFunctionDefinitionSpec struct {
	//
	// The following fields are shared with CustomResourceDefinition.
	//
	// Group is the API group of the defined KRM function.
	Group string `yaml:"group" json:"group"`
	// Names specify the resource and kind names for the KRM function.
	Names KRMFunctionNames `yaml:"names" json:"names"`
	// Versions is the list of all API versions of the defined KRM function.
	Versions []KRMFunctionVersion `yaml:"versions" json:"versions"`

	//
	// The following fields are custom to KRMFunctionDefinition
	//
	// Description briefly describes the KRM function.
	Description string `yaml:"description,omitempty" json:"description,omitempty"`
	// Publisher is the entity (e.g. organization) that produced and owns this KRM function.
	Publisher string `yaml:"publisher,omitempty" json:"publisher,omitempty"`
	// Home is a URI pointing the home page of the KRM function.
	Home string `yaml:"home,omitempty" json:"home,omitempty"`
	// Maintainers lists the individual maintainers of the KRM function.
	Maintainers []string `yaml:"maintainers,omitempty" json:"maintainers,omitempty"`
	// Tags are keywords describing the function. e.g. mutator, validator, generator, prefix, GCP.
	Tags []string `yaml:"tags,omitempty" json:"tags,omitempty"`
}

type OrSelector added in v0.10.14

type OrSelector struct {
	// Matchers is the list of ResourceMatchers to try on the input resources.
	Matchers []ResourceMatcher
	// TemplateData, if present, is used to initialize any matchers that implement
	// ResourceTemplateMatcher.
	TemplateData interface{}
	// FailOnEmptyMatch makes the selector return an error when no items are selected.
	FailOnEmptyMatch bool
}

OrSelector is a kio.Filter that selects resources when that match at least one of its embedded matchers.

func MatchAny added in v0.10.14

func MatchAny(matchers ...ResourceMatcher) *OrSelector

MatchAny is a shorthand for building an OrSelector from a list of ResourceMatchers.

func (*OrSelector) DefaultTemplateData added in v0.10.14

func (s *OrSelector) DefaultTemplateData(data interface{})

DefaultTemplateData makes OrSelector a ResourceTemplateMatcher. Although it does not contain templates itself, this allows it to support ResourceTemplateMatchers when being used as a matcher itself.

func (*OrSelector) Filter added in v0.10.14

func (s *OrSelector) Filter(items []*yaml.RNode) ([]*yaml.RNode, error)

Filter implements kio.Filter, returning only those items from the list that the selector matches.

func (*OrSelector) InitTemplates added in v0.10.14

func (s *OrSelector) InitTemplates() error

func (*OrSelector) Match added in v0.10.14

func (s *OrSelector) Match(item *yaml.RNode) bool

Match implements ResourceMatcher so that OrSelectors can be composed

type PatchTemplate added in v0.10.0

type PatchTemplate interface {
	// Filter is a kio.Filter-compliant function that applies PatchTemplate's templates as patches
	// on the given resource nodes.
	Filter(items []*yaml.RNode) ([]*yaml.RNode, error)
	// DefaultTemplateData accepts default data to be used in template rendering when no template
	// data was explicitly provided to the PatchTemplate.
	DefaultTemplateData(interface{})
}

PatchTemplate is implemented by kio.Filters that work by rendering patches and applying them to the given resource nodes.

type ResourceList

type ResourceList struct {
	// Items is the ResourceList.items input and output value.
	//
	// e.g. given the function input:
	//
	//    kind: ResourceList
	//    items:
	//    - kind: Deployment
	//      ...
	//    - kind: Service
	//      ...
	//
	// Items will be a slice containing the Deployment and Service resources
	// Mutating functions will alter this field during processing.
	// This field is required.
	Items []*yaml.RNode `yaml:"items" json:"items"`

	// FunctionConfig is the ResourceList.functionConfig input value.
	//
	// e.g. given the input:
	//
	//    kind: ResourceList
	//    functionConfig:
	//      kind: Example
	//      spec:
	//        foo: var
	//
	// FunctionConfig will contain the RNodes for the Example:
	//      kind: Example
	//      spec:
	//        foo: var
	FunctionConfig *yaml.RNode `yaml:"functionConfig,omitempty" json:"functionConfig,omitempty"`

	// Results is ResourceList.results output value.
	// Validating functions can optionally use this field to communicate structured
	// validation error data to downstream functions.
	Results Results `yaml:"results,omitempty" json:"results,omitempty"`
}

ResourceList is a Kubernetes list type used as the primary data interchange format in the Configuration Functions Specification: https://github.com/kubernetes-sigs/kustomize/blob/master/cmd/config/docs/api-conventions/functions-spec.md This framework facilitates building functions that receive and emit ResourceLists, as required by the specification.

func (*ResourceList) Filter added in v0.10.14

func (rl *ResourceList) Filter(api kio.Filter) error

Filter executes the given kio.Filter and replaces the ResourceList's items with the result. This can be used to help implement ResourceListProcessors. See SimpleProcessor for example.

Filters that return a Result as error will store the result in the ResourceList and continue processing instead of erroring out.

type ResourceListProcessor added in v0.10.14

type ResourceListProcessor interface {
	Process(rl *ResourceList) error
}

ResourceListProcessor is implemented by configuration functions built with this framework to conform to the Configuration Functions Specification: https://github.com/kubernetes-sigs/kustomize/blob/master/cmd/config/docs/api-conventions/functions-spec.md To invoke a processor, pass it to framework.Execute, which will also handle ResourceList IO.

This framework provides several ready-to-use ResourceListProcessors, including SimpleProcessor, VersionedAPIProcessor and TemplateProcessor. You can also build your own by implementing this interface.

type ResourceListProcessorFunc added in v0.10.14

type ResourceListProcessorFunc func(rl *ResourceList) error

ResourceListProcessorFunc converts a compatible function to a ResourceListProcessor.

func (ResourceListProcessorFunc) Process added in v0.10.14

Process makes ResourceListProcessorFunc implement the ResourceListProcessor interface.

type ResourceMatcher added in v0.10.14

type ResourceMatcher interface {
	// kio.Filter applies the matcher to multiple resources.
	// This makes individual matchers usable as selectors directly.
	kio.Filter
	// Match returns true if the given resource matches the matcher's configuration.
	Match(node *yaml.RNode) bool
}

ResourceMatcher is implemented by types designed for use in or as selectors.

type ResourceMatcherFunc added in v0.10.14

type ResourceMatcherFunc func(node *yaml.RNode) bool

ResourceMatcherFunc converts a compliant function into a ResourceMatcher

func (ResourceMatcherFunc) Filter added in v0.10.14

func (m ResourceMatcherFunc) Filter(items []*yaml.RNode) ([]*yaml.RNode, error)

Filter applies ResourceMatcherFunc to a list of items, returning only those that match.

func (ResourceMatcherFunc) Match added in v0.10.14

func (m ResourceMatcherFunc) Match(node *yaml.RNode) bool

Match runs the ResourceMatcherFunc on the given node.

type ResourcePatchTemplate added in v0.10.14

type ResourcePatchTemplate struct {
	// Templates provides a list of templates to render into one or more patches.
	Templates TemplateParser

	// Selector targets the rendered patches to specific resources. If no Selector is provided,
	// all resources will be patched.
	//
	// Although any Filter can be used, this framework provides several especially for Selector use:
	// framework.Selector, framework.AndSelector, framework.OrSelector. You can also use any of the
	// framework's ResourceMatchers here directly.
	Selector kio.Filter

	// TemplateData is the data to use when rendering the templates provided by the Templates field.
	TemplateData interface{}
}

ResourcePatchTemplate applies a patch to a collection of resources

func (*ResourcePatchTemplate) DefaultTemplateData added in v0.10.14

func (t *ResourcePatchTemplate) DefaultTemplateData(data interface{})

DefaultTemplateData sets TemplateData to the provided default values if it has not already been set.

func (ResourcePatchTemplate) Filter added in v0.10.14

func (t ResourcePatchTemplate) Filter(items []*yaml.RNode) ([]*yaml.RNode, error)

Filter applies the ResourcePatchTemplate to the appropriate resources in the input. First, it applies the Selector to identify target resources. Then, it renders the Templates into patches using TemplateData. Finally, it identifies applies the patch to each resource.

type ResourceTemplate added in v0.10.14

type ResourceTemplate struct {
	// Templates provides a list of templates to render into one or more resources.
	Templates TemplateParser

	// TemplateData is the data to use when rendering the templates provided by the Templates field.
	TemplateData interface{}
}

ResourceTemplate generates resources from templates.

func (*ResourceTemplate) DefaultTemplateData added in v0.10.14

func (rt *ResourceTemplate) DefaultTemplateData(data interface{})

DefaultTemplateData sets TemplateData to the provided default values if it has not already been set.

func (*ResourceTemplate) Render added in v0.10.14

func (rt *ResourceTemplate) Render() ([]*yaml.RNode, error)

Render renders the Templates into resource nodes using TemplateData.

type ResourceTemplateMatcher added in v0.10.14

type ResourceTemplateMatcher interface {
	// ResourceMatcher makes matchers usable in or as selectors.
	ResourceMatcher
	// DefaultTemplateData is used to pass default template values down a chain of matchers.
	DefaultTemplateData(interface{})
	// InitTemplates is used to render the templates in selectors that support
	// ResourceTemplateMatcher. The selector should call this exactly once per filter
	// operation, before beginning match comparisons.
	InitTemplates() error
}

ResourceTemplateMatcher is implemented by ResourceMatcher types that accept text templates as part of their configuration.

func APIVersionMatcher added in v0.10.14

func APIVersionMatcher(names ...string) ResourceTemplateMatcher

APIVersionMatcher matches resources whose kind is equal to one of the provided values. e.g. `APIVersionMatcher("foo/v1", "bar/v1")` matches if `apiVersion` is either "foo/v1" or "bar/v1".

APIVersionMatcher supports templating. e.g. `APIVersionMatcher("{{.TargetAPI}}")` will match `apiVersion` "foo/v1" if TemplateData is `struct{ TargetAPI string }{ TargetAPI: "foo/v1" }`

func AnnotationMatcher added in v0.10.14

func AnnotationMatcher(ann map[string]string) ResourceTemplateMatcher

AnnotationMatcher matches resources that are annotated with all of the provided key-value pairs. e.g. `AnnotationMatcher(map[string]string{"app": "foo", "env": "prod"})` matches resources annotated app=foo AND env=prod.

AnnotationMatcher supports templating. e.g. `AnnotationMatcher(map[string]string{"app": "{{ .AppName}}"})` will match label app=foo if TemplateData is `struct{ AppName string }{ AppName: "foo" }`

func GVKMatcher added in v0.10.14

func GVKMatcher(names ...string) ResourceTemplateMatcher

GVKMatcher matches resources whose API group, version and kind match one of the provided values. e.g. `GVKMatcher("foo/v1/Widget", "bar/v1/App")` matches if `apiVersion` concatenated with `kind` is either "foo/v1/Widget" or "bar/v1/App".

GVKMatcher supports templating. e.g. `GVKMatcher("{{.TargetAPI}}")` will match "foo/v1/Widget" if TemplateData is `struct{ TargetAPI string }{ TargetAPI: "foo/v1/Widget" }`

func KindMatcher added in v0.10.14

func KindMatcher(names ...string) ResourceTemplateMatcher

KindMatcher matches resources whose kind is equal to one of the provided values. e.g. `KindMatcher("foo", "bar")` matches if `kind` is either "foo" or "bar".

KindMatcher supports templating. e.g. `KindMatcher("{{.TargetKind}}")` will match `kind` "foo" if TemplateData is `struct{ TargetKind string }{ TargetKind: "foo" }`

func LabelMatcher added in v0.10.14

func LabelMatcher(labels map[string]string) ResourceTemplateMatcher

LabelMatcher matches resources that are labelled with all of the provided key-value pairs. e.g. `LabelMatcher(map[string]string{"app": "foo", "env": "prod"})` matches resources labelled app=foo AND env=prod.

LabelMatcher supports templating. e.g. `LabelMatcher(map[string]string{"app": "{{ .AppName}}"})` will match label app=foo if TemplateData is `struct{ AppName string }{ AppName: "foo" }`

func NameMatcher added in v0.10.14

func NameMatcher(names ...string) ResourceTemplateMatcher

NameMatcher matches resources whose metadata.name is equal to one of the provided values. e.g. `NameMatcher("foo", "bar")` matches if `metadata.name` is either "foo" or "bar".

NameMatcher supports templating. e.g. `NameMatcher("{{.AppName}}")` will match `metadata.name` "foo" if TemplateData is `struct{ AppName string }{ AppName: "foo" }`

func NamespaceMatcher added in v0.10.14

func NamespaceMatcher(names ...string) ResourceTemplateMatcher

NamespaceMatcher matches resources whose metadata.namespace is equal to one of the provided values. e.g. `NamespaceMatcher("foo", "bar")` matches if `metadata.namespace` is either "foo" or "bar".

NamespaceMatcher supports templating. e.g. `NamespaceMatcher("{{.AppName}}")` will match `metadata.namespace` "foo" if TemplateData is `struct{ AppName string }{ AppName: "foo" }`

type Result

type Result struct {
	// Message is a human readable message. This field is required.
	Message string `yaml:"message,omitempty" json:"message,omitempty"`

	// Severity is the severity of this result
	Severity Severity `yaml:"severity,omitempty" json:"severity,omitempty"`

	// ResourceRef is a reference to a resource.
	// Required fields: apiVersion, kind, name.
	ResourceRef *yaml.ResourceIdentifier `yaml:"resourceRef,omitempty" json:"resourceRef,omitempty"`

	// Field is a reference to the field in a resource this result refers to
	Field *Field `yaml:"field,omitempty" json:"field,omitempty"`

	// File references a file containing the resource this result refers to
	File *File `yaml:"file,omitempty" json:"file,omitempty"`

	// Tags is an unstructured key value map stored with a result that may be set
	// by external tools to store and retrieve arbitrary metadata
	Tags map[string]string `yaml:"tags,omitempty" json:"tags,omitempty"`
}

ResultItem defines a validation result

func (Result) String added in v0.13.0

func (i Result) String() string

String provides a human-readable message for the result item

type Results added in v0.13.0

type Results []*Result

func (Results) Error added in v0.13.0

func (e Results) Error() string

Error enables Results to be returned as an error

func (Results) ExitCode added in v0.13.0

func (e Results) ExitCode() int

ExitCode provides the exit code based on the result's severity

func (Results) Sort added in v0.13.1

func (e Results) Sort()

Sort performs an in place stable sort of Results

type SchemaParser added in v0.10.20

type SchemaParser interface {
	Parse() ([]*spec.Definitions, error)
}

type SchemaParserFunc added in v0.10.20

type SchemaParserFunc func() ([]*spec.Definitions, error)

func (SchemaParserFunc) Parse added in v0.10.20

func (s SchemaParserFunc) Parse() ([]*spec.Definitions, error)

type Selector added in v0.10.0

type Selector struct {
	// Names is a list of metadata.names to match.  If empty match all names.
	// e.g. Names: ["foo", "bar"] matches if `metadata.name` is either "foo" or "bar".
	Names []string `json:"names" yaml:"names"`

	// Namespaces is a list of metadata.namespaces to match.  If empty match all namespaces.
	// e.g. Namespaces: ["foo", "bar"] matches if `metadata.namespace` is either "foo" or "bar".
	Namespaces []string `json:"namespaces" yaml:"namespaces"`

	// Kinds is a list of kinds to match.  If empty match all kinds.
	// e.g. Kinds: ["foo", "bar"] matches if `kind` is either "foo" or "bar".
	Kinds []string `json:"kinds" yaml:"kinds"`

	// APIVersions is a list of apiVersions to match.  If empty apply match all apiVersions.
	// e.g. APIVersions: ["foo/v1", "bar/v1"] matches if `apiVersion` is either "foo/v1" or "bar/v1".
	APIVersions []string `json:"apiVersions" yaml:"apiVersions"`

	// Labels is a collection of labels to match.  All labels must match exactly.
	// e.g. Labels: {"foo": "bar", "baz": "buz"] matches if BOTH "foo" and "baz" labels match.
	Labels map[string]string `json:"labels" yaml:"labels"`

	// Annotations is a collection of annotations to match.  All annotations must match exactly.
	// e.g. Annotations: {"foo": "bar", "baz": "buz"] matches if BOTH "foo" and "baz" annotations match.
	Annotations map[string]string `json:"annotations" yaml:"annotations"`

	// ResourceMatcher is an arbitrary function used to match resources.
	// Selector matches if the function returns true.
	ResourceMatcher func(*yaml.RNode) bool

	// TemplateData if present will cause the selector values to be parsed as templates
	// and rendered using TemplateData before they are used.
	TemplateData interface{}

	// FailOnEmptyMatch makes the selector return an error when no items are selected.
	FailOnEmptyMatch bool
}

Selector matches resources. A resource matches if and only if ALL of the Selector fields match the resource. An empty Selector matches all resources.

Example (TemplatizeAnnotations)

ExampleSelector_templatizeKinds provides an example of using a template as a selector value, to dynamically match resources based on the functionConfig input. It also shows how Selector can be used with SimpleProcessor to implement a ResourceListProcessor the filters the input.

package main

import (
	"bytes"

	"sigs.k8s.io/kustomize/kyaml/fn/framework"
	"sigs.k8s.io/kustomize/kyaml/kio"
)

func main() {
	type api struct {
		Value string `yaml:"value"`
	}
	rw := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1
kind: ResourceList
functionConfig:
  value: bar
items:
- apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: foo
    namespace: default
    annotations:
      key: foo
- apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: bar
    namespace: default
    annotations:
      key: bar
`)}
	config := &api{}
	p := framework.SimpleProcessor{
		Config: config,
		Filter: &framework.Selector{
			TemplateData: config,
			Annotations:  map[string]string{"key": "{{ .Value }}"},
		},
	}

	if err := framework.Execute(p, rw); err != nil {
		panic(err)
	}

}
Output:

apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: bar
    namespace: default
    annotations:
      key: bar
functionConfig:
  value: bar
Example (TemplatizeKinds)

ExampleSelector_templatizeKinds provides an example of using a template as a selector value, to dynamically match resources based on the functionConfig input. It also shows how Selector can be used with SimpleProcessor to implement a ResourceListProcessor the filters the input.

package main

import (
	"bytes"

	"sigs.k8s.io/kustomize/kyaml/fn/framework"
	"sigs.k8s.io/kustomize/kyaml/kio"
)

func main() {
	type api struct {
		KindName string `yaml:"kindName"`
	}
	rw := &kio.ByteReadWriter{
		Reader: bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1
kind: ResourceList
functionConfig:
  kindName: Deployment
items:
- apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: foo
    namespace: default
- apiVersion: apps/v1
  kind: StatefulSet
  metadata:
    name: bar
    namespace: default
`),
	}
	config := &api{}
	p := framework.SimpleProcessor{
		Config: config,
		Filter: &framework.Selector{
			TemplateData: config,
			Kinds:        []string{"{{ .KindName }}"},
		},
	}

	err := framework.Execute(p, rw)
	if err != nil {
		panic(err)
	}

}
Output:

apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: foo
    namespace: default
functionConfig:
  kindName: Deployment

func (*Selector) Filter added in v0.10.0

func (s *Selector) Filter(items []*yaml.RNode) ([]*yaml.RNode, error)

Filter implements kio.Filter, returning only those items from the list that the selector matches.

type Severity

type Severity string

Severity indicates the severity of the Result

const (
	// Error indicates the result is an error.  Will cause the function to exit non-0.
	Error Severity = "error"
	// Warning indicates the result is a warning
	Warning Severity = "warning"
	// Info indicates the result is an informative message
	Info Severity = "info"
)

type SimpleProcessor added in v0.10.14

type SimpleProcessor struct {
	// Filter is the kio.Filter that will be used to process the ResourceList's items.
	// Note that kio.FilterFunc is available to transform a compatible func into a kio.Filter.
	Filter kio.Filter
	// Config must be a struct capable of receiving the data from ResourceList.functionConfig.
	// Filter functions may close over this struct to access its data.
	Config interface{}
}

SimpleProcessor processes a ResourceList by loading the FunctionConfig into the given Config type and then running the provided Filter on the ResourceList. The provided Config MAY implement Defaulter and Validator to have Default and Validate respectively called between unmarshalling and filter execution.

Typical uses include functions that do not actually require config, and simple functions built with a filter that closes over the Config instance to access ResourceList.functionConfig values.

Example (GenerateReplace)

ExampleSimpleProcessor_generateReplace generates a resource from a FunctionConfig. If the resource already exists, it replaces the resource with a new copy.

package main

import (
	"bytes"
	"fmt"

	"sigs.k8s.io/kustomize/kyaml/fn/framework"
	"sigs.k8s.io/kustomize/kyaml/kio"
	"sigs.k8s.io/kustomize/kyaml/yaml"
)

const service = "Service"

func main() {
	input := bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1
kind: ResourceList
# items are provided as nodes
items:
- apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: foo
functionConfig:
  apiVersion: example.com/v1alpha1
  kind: ExampleServiceGenerator
  spec:
    name: bar
`)

	// function API definition which will be parsed from the ResourceList.FunctionConfig
	// read from stdin
	type Spec struct {
		Name string `yaml:"name,omitempty"`
	}
	type ExampleServiceGenerator struct {
		Spec Spec `yaml:"spec,omitempty"`
	}

	functionConfig := &ExampleServiceGenerator{}

	fn := func(items []*yaml.RNode) ([]*yaml.RNode, error) {
		// remove the last generated resource
		var newNodes []*yaml.RNode
		for i := range items {
			meta, err := items[i].GetMeta()
			if err != nil {
				return nil, err
			}
			// something we already generated, remove it from the list so we regenerate it
			if meta.Name == functionConfig.Spec.Name &&
				meta.Kind == service &&
				meta.APIVersion == "v1" {
				continue
			}
			newNodes = append(newNodes, items[i])
		}
		items = newNodes

		// generate the resource again
		n, err := yaml.Parse(fmt.Sprintf(`apiVersion: v1
kind: Service
metadata:
 name: %s
`, functionConfig.Spec.Name))
		if err != nil {
			return nil, err
		}
		items = append(items, n)
		return items, nil
	}

	p := framework.SimpleProcessor{Config: functionConfig, Filter: kio.FilterFunc(fn)}
	err := framework.Execute(p, &kio.ByteReadWriter{Reader: input})
	if err != nil {
		panic(err)
	}

}
Output:

apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: foo
- apiVersion: v1
  kind: Service
  metadata:
    name: bar
functionConfig:
  apiVersion: example.com/v1alpha1
  kind: ExampleServiceGenerator
  spec:
    name: bar
Example (Modify)

ExampleSimpleProcessor_modify implements a function that sets an annotation on each resource.

package main

import (
	"bytes"

	"sigs.k8s.io/kustomize/kyaml/fn/framework"
	"sigs.k8s.io/kustomize/kyaml/kio"
	"sigs.k8s.io/kustomize/kyaml/yaml"
)

func main() {
	input := bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1
kind: ResourceList
# items are provided as nodes
items:
- apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: foo
- apiVersion: v1
  kind: Service
  metadata:
    name: foo
functionConfig:
  apiVersion: v1
  kind: ConfigMap
  data:
    value: baz
`)
	config := new(struct {
		Data map[string]string `yaml:"data" json:"data"`
	})
	fn := func(items []*yaml.RNode) ([]*yaml.RNode, error) {
		for i := range items {
			// set the annotation on each resource item
			if err := items[i].PipeE(yaml.SetAnnotation("value", config.Data["value"])); err != nil {
				return nil, err
			}
		}
		return items, nil
	}

	err := framework.Execute(framework.SimpleProcessor{Config: config, Filter: kio.FilterFunc(fn)}, &kio.ByteReadWriter{Reader: input})
	if err != nil {
		panic(err)
	}

}
Output:

apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: foo
    annotations:
      value: 'baz'
- apiVersion: v1
  kind: Service
  metadata:
    name: foo
    annotations:
      value: 'baz'
functionConfig:
  apiVersion: v1
  kind: ConfigMap
  data:
    value: baz

func (SimpleProcessor) Process added in v0.10.14

func (p SimpleProcessor) Process(rl *ResourceList) error

Process makes SimpleProcessor implement the ResourceListProcessor interface. It loads the ResourceList.functionConfig into the provided Config type, applying defaulting and validation if supported by Config. It then executes the processor's filter.

type TemplateParser added in v0.10.20

type TemplateParser interface {
	Parse() ([]*template.Template, error)
}

type TemplateParserFunc added in v0.10.20

type TemplateParserFunc func() ([]*template.Template, error)

func (TemplateParserFunc) Parse added in v0.10.20

func (s TemplateParserFunc) Parse() ([]*template.Template, error)

type TemplateProcessor added in v0.10.14

type TemplateProcessor struct {
	// TemplateData will will be exposed to all the templates in the processor (unless explicitly
	// overridden for a template).
	// If TemplateProcessor is used directly as a ResourceListProcessor, TemplateData will contain the
	// value of ResourceList.functionConfig.
	TemplateData interface{}

	// ResourceTemplates returns a list of templates to render into resources.
	// If MergeResources is set, any matching resources in ResourceList.items will be used as patches
	// modifying the rendered templates. Otherwise, the rendered resources will be appended to
	// the input resources as-is.
	ResourceTemplates []ResourceTemplate

	// PatchTemplates is a list of templates to render into patches that apply to ResourceList.items.
	// ResourcePatchTemplate can be used here to patch entire resources.
	// ContainerPatchTemplate can be used here to patch specific containers within resources.
	PatchTemplates []PatchTemplate

	// MergeResources, if set to true, will cause the resources in ResourceList.items to be
	// applied as patches on any matching resources generated by ResourceTemplates.
	MergeResources bool

	// PreProcessFilters provides a hook to manipulate the ResourceList's items or config after
	// TemplateData has been populated but before template-based filters are applied.
	PreProcessFilters []kio.Filter

	// PostProcessFilters provides a hook to manipulate the ResourceList's items after template
	// filters are applied.
	PostProcessFilters []kio.Filter

	// AdditionalSchemas is a function that returns a list of schema definitions to add to openapi.
	// This enables correct merging of custom resource fields.
	AdditionalSchemas SchemaParser
}

TemplateProcessor is a ResourceListProcessor based on rendering templates with the data in ResourceList.functionConfig. It works as follows: - loads ResourceList.functionConfig into TemplateData - runs PreProcessFilters - renders ResourceTemplates and adds them to ResourceList.items - renders PatchTemplates and applies them to ResourceList.items - executes a merge on ResourceList.items if configured to - runs PostProcessFilters The TemplateData struct MAY implement Defaulter and Validator to have Default and Validate respectively called between unmarshalling and filter execution.

TemplateProcessor also implements kio.Filter directly and can be used in the construction of higher-level processors. For example, you might use TemplateProcessors as the filters for each API supported by a VersionedAPIProcessor (see VersionedAPIProcessor examples).

Example (Container_patch)

ExampleTemplateProcessor_container_patch provides an example for using TemplateProcessor to patch all of the containers in the input.

package main

import (
	"bytes"
	"log"

	"sigs.k8s.io/kustomize/kyaml/fn/framework"
	"sigs.k8s.io/kustomize/kyaml/fn/framework/parser"
	"sigs.k8s.io/kustomize/kyaml/kio"
)

func main() {
	input := `
apiVersion: apps/v1
kind: Deployment
metadata:
  name: foo
spec:
  template:
    spec:
      containers:
      - name: foo
        image: a
      - name: bar
        image: b
---
apiVersion: v1
kind: Service
metadata:
  name: foo
spec:
  selector:
    foo: bar
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bar
spec:
  template:
    spec:
      containers:
      - name: foo
        image: a
      - name: baz
        image: b
---
apiVersion: v1
kind: Service
metadata:
  name: bar
spec:
  selector:
    foo: bar
`
	p := framework.TemplateProcessor{
		PatchTemplates: []framework.PatchTemplate{
			&framework.ContainerPatchTemplate{
				Templates: parser.TemplateStrings(`
env:
- name: KEY
  value: {{ .Value }}
`),
				TemplateData: struct{ Value string }{Value: "new-value"},
			}},
	}
	err := framework.Execute(p, &kio.ByteReadWriter{Reader: bytes.NewBufferString(input)})
	if err != nil {
		log.Fatal(err)
	}

}
Output:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: foo
spec:
  template:
    spec:
      containers:
      - name: foo
        image: a
        env:
        - name: KEY
          value: new-value
      - name: bar
        image: b
        env:
        - name: KEY
          value: new-value
---
apiVersion: v1
kind: Service
metadata:
  name: foo
spec:
  selector:
    foo: bar
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bar
spec:
  template:
    spec:
      containers:
      - name: foo
        image: a
        env:
        - name: KEY
          value: new-value
      - name: baz
        image: b
        env:
        - name: KEY
          value: new-value
---
apiVersion: v1
kind: Service
metadata:
  name: bar
spec:
  selector:
    foo: bar
Example (Container_patch_by_name)

PatchTemplateContainersWithString patches containers matching a specific name.

package main

import (
	"bytes"
	"log"

	"sigs.k8s.io/kustomize/kyaml/fn/framework"
	"sigs.k8s.io/kustomize/kyaml/fn/framework/parser"
	"sigs.k8s.io/kustomize/kyaml/kio"
)

func main() {
	input := `
apiVersion: apps/v1
kind: Deployment
metadata:
  name: foo
spec:
  template:
    spec:
      containers:
      - name: foo
        image: a
        env:
        - name: EXISTING
          value: variable
      - name: bar
        image: b
---
apiVersion: v1
kind: Service
metadata:
  name: foo
spec:
  selector:
    foo: bar
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bar
spec:
  template:
    spec:
      containers:
      - name: foo
        image: a
      - name: baz
        image: b
---
apiVersion: v1
kind: Service
metadata:
  name: bar
spec:
  selector:
    foo: bar
`
	p := framework.TemplateProcessor{
		TemplateData: struct{ Value string }{Value: "new-value"},
		PatchTemplates: []framework.PatchTemplate{
			&framework.ContainerPatchTemplate{
				// Only patch containers named "foo"
				ContainerMatcher: framework.ContainerNameMatcher("foo"),
				Templates: parser.TemplateStrings(`
env:
- name: KEY
  value: {{ .Value }}
`),
			}},
	}

	err := framework.Execute(p, &kio.ByteReadWriter{Reader: bytes.NewBufferString(input)})
	if err != nil {
		log.Fatal(err)
	}

}
Output:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: foo
spec:
  template:
    spec:
      containers:
      - name: foo
        image: a
        env:
        - name: EXISTING
          value: variable
        - name: KEY
          value: new-value
      - name: bar
        image: b
---
apiVersion: v1
kind: Service
metadata:
  name: foo
spec:
  selector:
    foo: bar
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bar
spec:
  template:
    spec:
      containers:
      - name: foo
        image: a
        env:
        - name: KEY
          value: new-value
      - name: baz
        image: b
---
apiVersion: v1
kind: Service
metadata:
  name: bar
spec:
  selector:
    foo: bar
Example (Generate_files)

ExampleTemplateProcessor_files provides an example for using the TemplateProcessor to add resources from templates defined in files.

package main

import (
	"fmt"
	"path/filepath"

	"sigs.k8s.io/kustomize/kyaml/fn/framework"
	"sigs.k8s.io/kustomize/kyaml/fn/framework/command"
	"sigs.k8s.io/kustomize/kyaml/fn/framework/parser"
)

func main() {
	api := new(struct {
		Key   string `json:"key" yaml:"key"`
		Value string `json:"value" yaml:"value"`
	})
	// create the template
	templateFn := framework.TemplateProcessor{
		// Templates input
		TemplateData: api,
		// Templates
		ResourceTemplates: []framework.ResourceTemplate{{
			Templates: parser.TemplateFiles("testdata/example/templatefiles/deployment.template.yaml"),
		}},
	}
	cmd := command.Build(templateFn, command.StandaloneEnabled, false)
	// mimic standalone mode: testdata/template/config.yaml will be parsed into `api`
	cmd.SetArgs([]string{filepath.Join("testdata", "example", "templatefiles", "config.yaml")})
	if err := cmd.Execute(); err != nil {
		_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "%v\n", err)
	}

}
Output:

# Copyright 2021 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0

apiVersion: apps/v1
kind: Deployment
metadata:
  name: foo
  namespace: default
  annotations:
    a: b
Example (Generate_inline)

ExampleTemplateProcessor provides an example for using the TemplateProcessor to add resources from templates defined inline

package main

import (
	"fmt"
	"path/filepath"

	"sigs.k8s.io/kustomize/kyaml/fn/framework"
	"sigs.k8s.io/kustomize/kyaml/fn/framework/command"
	"sigs.k8s.io/kustomize/kyaml/fn/framework/parser"
)

func main() {
	api := new(struct {
		Key   string `json:"key" yaml:"key"`
		Value string `json:"value" yaml:"value"`
	})
	// create the template
	fn := framework.TemplateProcessor{
		// Templates input
		TemplateData: api,
		// Templates
		ResourceTemplates: []framework.ResourceTemplate{{
			Templates: parser.TemplateStrings(`
apiVersion: apps/v1
kind: Deployment
metadata:
 name: foo
 namespace: default
 annotations:
   {{ .Key }}: {{ .Value }}
`)}},
	}
	cmd := command.Build(fn, command.StandaloneEnabled, false)

	// mimic standalone mode: testdata/template/config.yaml will be parsed into `api`
	cmd.SetArgs([]string{filepath.Join("testdata", "example", "template", "config.yaml")})
	if err := cmd.Execute(); err != nil {
		_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "%v\n", err)
	}

}
Output:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: foo
  namespace: default
  annotations:
    a: b
Example (Patch)

ExampleTemplateProcessor_patch provides an example for using the TemplateProcessor to create a function that patches resources.

package main

import (
	"fmt"
	"path/filepath"

	"sigs.k8s.io/kustomize/kyaml/fn/framework"
	"sigs.k8s.io/kustomize/kyaml/fn/framework/command"
	"sigs.k8s.io/kustomize/kyaml/fn/framework/parser"
)

func main() {
	fn := framework.TemplateProcessor{
		TemplateData: new(struct {
			Key   string `json:"key" yaml:"key"`
			Value string `json:"value" yaml:"value"`
		}),
		ResourceTemplates: []framework.ResourceTemplate{{
			Templates: parser.TemplateStrings(`
apiVersion: apps/v1
kind: Deployment
metadata:
  name: foo
  namespace: default
  annotations:
    {{ .Key }}: {{ .Value }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bar
  namespace: default
  annotations:
    {{ .Key }}: {{ .Value }}
`),
		}},
		// PatchTemplates are applied to BOTH ResourceList input resources AND templated resources
		PatchTemplates: []framework.PatchTemplate{
			&framework.ResourcePatchTemplate{
				// patch the foo resource only
				Selector: &framework.Selector{Names: []string{"foo"}},
				Templates: parser.TemplateStrings(`
metadata:
  annotations:
    patched: 'true'
`),
			}},
	}
	cmd := command.Build(fn, command.StandaloneEnabled, false)

	cmd.SetArgs([]string{filepath.Join("testdata", "example", "template", "config.yaml")})
	if err := cmd.Execute(); err != nil {
		_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "%v\n", err)
	}

}
Output:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: foo
  namespace: default
  annotations:
    a: b
    patched: 'true'
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bar
  namespace: default
  annotations:
    a: b
Example (Postprocess)

ExampleTemplateProcessor_postprocess provides an example for using the TemplateProcessor with PostProcess to modify the results.

package main

import (
	"fmt"
	"path/filepath"

	"sigs.k8s.io/kustomize/kyaml/fn/framework"
	"sigs.k8s.io/kustomize/kyaml/fn/framework/command"
	"sigs.k8s.io/kustomize/kyaml/fn/framework/parser"
	"sigs.k8s.io/kustomize/kyaml/kio"
	"sigs.k8s.io/kustomize/kyaml/yaml"
)

func main() {
	config := new(struct {
		Key   string `json:"key" yaml:"key"`
		Value string `json:"value" yaml:"value"`
	})

	// create the template
	fn := framework.TemplateProcessor{
		// Templates input
		TemplateData: config,
		ResourceTemplates: []framework.ResourceTemplate{{
			Templates: parser.TemplateStrings(`
apiVersion: apps/v1
kind: Deployment
metadata:
  name: foo
  namespace: default
  annotations:
    {{ .Key }}: {{ .Value }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bar
  namespace: default
  annotations:
    {{ .Key }}: {{ .Value }}
`),
		}},
		PostProcessFilters: []kio.Filter{
			kio.FilterFunc(func(items []*yaml.RNode) ([]*yaml.RNode, error) {
				items = items[1:]
				return items, nil
			}),
		},
	}
	cmd := command.Build(fn, command.StandaloneEnabled, false)

	cmd.SetArgs([]string{filepath.Join("testdata", "example", "template", "config.yaml")})
	if err := cmd.Execute(); err != nil {
		_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "%v\n", err)
	}

}
Output:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: bar
  namespace: default
  annotations:
    a: b
Example (Preprocess)

ExampleTemplateProcessor_preprocess provides an example for using the TemplateProcessor with PreProcess to configure the template based on the input resources observed.

package main

import (
	"fmt"
	"path/filepath"

	"sigs.k8s.io/kustomize/kyaml/fn/framework"
	"sigs.k8s.io/kustomize/kyaml/fn/framework/command"
	"sigs.k8s.io/kustomize/kyaml/fn/framework/parser"
	"sigs.k8s.io/kustomize/kyaml/kio"
	"sigs.k8s.io/kustomize/kyaml/yaml"
)

func main() {
	config := new(struct {
		Key   string `json:"key" yaml:"key"`
		Value string `json:"value" yaml:"value"`
		Short bool
	})

	// create the template
	fn := framework.TemplateProcessor{
		// Templates input
		TemplateData: config,
		PreProcessFilters: []kio.Filter{
			kio.FilterFunc(func(items []*yaml.RNode) ([]*yaml.RNode, error) {
				config.Short = len(items) < 3
				return items, nil
			}),
		},
		// Templates
		ResourceTemplates: []framework.ResourceTemplate{{
			Templates: parser.TemplateStrings(`
apiVersion: apps/v1
kind: Deployment
metadata:
 name: foo
 namespace: default
 annotations:
   {{ .Key }}: {{ .Value }}
{{- if .Short }}
   short: 'true'
{{- end }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
 name: bar
 namespace: default
 annotations:
   {{ .Key }}: {{ .Value }}
{{- if .Short }}
   short: 'true'
{{- end }}
`),
		}},
	}

	cmd := command.Build(fn, command.StandaloneEnabled, false)
	// mimic standalone mode: testdata/template/config.yaml will be parsed into `api`
	cmd.SetArgs([]string{filepath.Join("testdata", "example", "template", "config.yaml")})
	if err := cmd.Execute(); err != nil {
		_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "%v\n", err)
	}

}
Output:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: foo
  namespace: default
  annotations:
    a: b
    short: 'true'
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bar
  namespace: default
  annotations:
    a: b
    short: 'true'

func (TemplateProcessor) Filter added in v0.10.14

func (tp TemplateProcessor) Filter(items []*yaml.RNode) ([]*yaml.RNode, error)

Filter implements the kio.Filter interface, enabling you to use TemplateProcessor as part of a higher-level ResourceListProcessor like VersionedAPIProcessor. It sets up all the features of TemplateProcessors as a pipeline of filters and executes them.

func (TemplateProcessor) Process added in v0.10.14

func (tp TemplateProcessor) Process(rl *ResourceList) error

Process implements the ResourceListProcessor interface, enabling you to use TemplateProcessor directly as a processor. As a Processor, it loads the ResourceList.functionConfig into the TemplateData field, exposing it to all templates by default.

type TemplatedMetaMapMatcher added in v0.10.14

type TemplatedMetaMapMatcher struct {
	// Templates is the list of possibly templated strings to compare to.
	Templates map[string]string

	// TemplateData is the data to use in template rendering.
	// Rendering will not take place if it is nil when InitTemplates is called.
	TemplateData interface{}
	// MetaMatcher is a function that returns true if the given resource metadata matches at
	// least one of the given names.
	// The matcher implemented using TemplatedMetaSliceMatcher can compare names to any meta field.
	MetaMatcher func(names map[string]string, meta yaml.ResourceMeta) bool
	// contains filtered or unexported fields
}

TemplatedMetaMapMatcher is a utility type for constructing matchers that compare resource metadata to a map of (possibly templated) key-value pairs.

func (*TemplatedMetaMapMatcher) DefaultTemplateData added in v0.10.14

func (m *TemplatedMetaMapMatcher) DefaultTemplateData(data interface{})

DefaultTemplateData sets TemplateData to the provided default values if it has not already been set.

func (*TemplatedMetaMapMatcher) Filter added in v0.10.14

func (m *TemplatedMetaMapMatcher) Filter(items []*yaml.RNode) ([]*yaml.RNode, error)

Filter applies the matcher to a list of items, returning only those that match.

func (*TemplatedMetaMapMatcher) InitTemplates added in v0.10.14

func (m *TemplatedMetaMapMatcher) InitTemplates() error

InitTemplates is used to render any templates the selector's key-value pairs may contain before the selector is applied. It should be called exactly once per filter operation, before beginning match comparisons.

func (*TemplatedMetaMapMatcher) Match added in v0.10.14

func (m *TemplatedMetaMapMatcher) Match(node *yaml.RNode) bool

Match parses the resource node's metadata and delegates matching logic to the provided MetaMatcher func. This allows ResourceMatchers build with TemplatedMetaMapMatcher to match against any field in resource metadata.

type TemplatedMetaSliceMatcher added in v0.10.14

type TemplatedMetaSliceMatcher struct {
	// Templates is the list of possibly templated strings to compare to.
	Templates []string

	// TemplateData is the data to use in template rendering.
	// Rendering will not take place if it is nil when InitTemplates is called.
	TemplateData interface{}
	// MetaMatcher is a function that returns true if the given resource metadata matches at
	// least one of the given names.
	// The matcher implemented using TemplatedMetaSliceMatcher can compare names to any meta field.
	MetaMatcher func(names sets.String, meta yaml.ResourceMeta) bool
	// contains filtered or unexported fields
}

TemplatedMetaSliceMatcher is a utility type for constructing matchers that compare resource metadata to a slice of (possibly templated) strings.

func (*TemplatedMetaSliceMatcher) DefaultTemplateData added in v0.10.14

func (m *TemplatedMetaSliceMatcher) DefaultTemplateData(data interface{})

DefaultTemplateData sets TemplateData to the provided default values if it has not already been set.

func (*TemplatedMetaSliceMatcher) Filter added in v0.10.14

func (m *TemplatedMetaSliceMatcher) Filter(items []*yaml.RNode) ([]*yaml.RNode, error)

Filter applies the matcher to a list of items, returning only those that match.

func (*TemplatedMetaSliceMatcher) InitTemplates added in v0.10.14

func (m *TemplatedMetaSliceMatcher) InitTemplates() error

InitTemplates is used to render any templates the selector's list of strings may contain before the selector is applied. It should be called exactly once per filter operation, before beginning match comparisons.

func (*TemplatedMetaSliceMatcher) Match added in v0.10.14

func (m *TemplatedMetaSliceMatcher) Match(node *yaml.RNode) bool

Match parses the resource node's metadata and delegates matching logic to the provided MetaMatcher func. This allows ResourceMatchers build with TemplatedMetaSliceMatcher to match against any field in resource metadata.

type ValidationSchemaProvider added in v0.13.4

type ValidationSchemaProvider interface {
	Schema() (*spec.Schema, error)
}

ValidationSchemaProvider is implemented by APIs to have the openapi schema provided by Schema() used to validate the input functionConfig before it is parsed into the API's struct. Use this with framework.SchemaFromFunctionDefinition to load the schema out of a KRMFunctionDefinition or CRD (e.g. one generated with KubeBuilder).

func (t MyType) Schema() (*spec.Schema, error) {
	 schema, err := framework.SchemaFromFunctionDefinition(resid.NewGvk("example.com", "v1", "MyType"), MyTypeDef)
	 return schema, errors.WrapPrefixf(err, "parsing MyType schema")
}

type Validator added in v0.10.7

type Validator interface {
	Validate() error
}

Validator is implemented by APIs to have Validate invoked. The standard application is to create a type to hold your FunctionConfig data, and implement Validator on that type. All of the framework's processors will invoke Validate() on your type after unmarshalling the FunctionConfig data into it.

type VersionedAPIProcessor added in v0.10.14

type VersionedAPIProcessor struct {
	// FilterProvider resolves a kio.Filter for each supported API, based on its APIVersion and Kind.
	// GVKFilterMap is a simple FilterProvider implementation for use here.
	FilterProvider FilterProvider
}

VersionedAPIProcessor selects the appropriate kio.Filter based on the ApiVersion and Kind of the ResourceList.functionConfig in the input. It can be used to implement configuration function APIs that evolve over time, or create processors that support multiple configuration APIs with a single entrypoint. All provided Filters MUST be structs capable of receiving ResourceList.functionConfig data. Provided Filters MAY implement Defaulter and Validator to have Default and Validate respectively called between unmarshalling and filter execution.

Example

ExampleVersionedAPIProcessor shows how to use the VersionedAPIProcessor and TemplateProcessor to build functions that implement complex multi-version APIs that require defaulting and validation.

package main

import (
	"bytes"
	"log"
	"strings"

	validationErrors "k8s.io/kube-openapi/pkg/validation/errors"
	"k8s.io/kube-openapi/pkg/validation/spec"
	"sigs.k8s.io/kustomize/kyaml/errors"
	"sigs.k8s.io/kustomize/kyaml/fn/framework"
	"sigs.k8s.io/kustomize/kyaml/fn/framework/parser"
	"sigs.k8s.io/kustomize/kyaml/kio"
	"sigs.k8s.io/kustomize/kyaml/resid"
	"sigs.k8s.io/kustomize/kyaml/yaml"
)

type v1alpha1JavaSpringBoot struct {
	Metadata Metadata                   `yaml:"metadata" json:"metadata"`
	Spec     v1alpha1JavaSpringBootSpec `yaml:"spec" json:"spec"`
}

type Metadata struct {
	Name string `yaml:"name" json:"name"`
}

type v1alpha1JavaSpringBootSpec struct {
	Replicas int    `yaml:"replicas" json:"replicas"`
	Domain   string `yaml:"domain" json:"domain"`
	Image    string `yaml:"image" json:"image"`
}

func (a v1alpha1JavaSpringBoot) Filter(items []*yaml.RNode) ([]*yaml.RNode, error) {
	filter := framework.TemplateProcessor{
		ResourceTemplates: []framework.ResourceTemplate{{
			TemplateData: &a,
			Templates: parser.TemplateStrings(`
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Metadata.Name }}
  selector:
    app: {{ .Metadata.Name }}
spec:
  replicas: {{ .Spec.Replicas }}
  template:
    spec:
      containers:
      - name: app
        image: {{ .Spec.Image }}
        {{ if .Spec.Domain }}
        ports:
          - containerPort: 80
            name: http
        {{ end }}

{{ if .Spec.Domain }}
---
apiVersion: v1
kind: Service
metadata:
  name: {{ .Metadata.Name }}-svc
spec:
  selector:
    app:  {{ .Metadata.Name }}
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name:  {{ .Metadata.Name }}-ingress
spec:
  tls:
  - hosts:
      - {{ .Spec.Domain }}
    secretName: secret-tls
  defaultBackend:
    service:
      name: {{ .Metadata.Name }}
      port:
        number: 80
{{ end }}
`),
		}},
	}
	return filter.Filter(items)
}

func (a *v1alpha1JavaSpringBoot) Default() error {
	if a.Spec.Replicas == 0 {
		a.Spec.Replicas = 3
	}
	return nil
}

var javaSpringBootDefinition = `
apiVersion: config.kubernetes.io/v1alpha1
kind: KRMFunctionDefinition
metadata:
  name: javaspringboot.example.com
spec:
  group: example.com
  names:
    kind: JavaSpringBoot
  versions:
  - name: v1alpha1
    schema:
      openAPIV3Schema:
        properties:
          apiVersion:
            type: string
          kind:
            type: string
          metadata:
            type: object
            properties:
              name:
                type: string
                minLength: 1
            required:
            - name
          spec:
            properties:
              domain:
                pattern: example\.com$
                type: string
              image:
                type: string
              replicas:
                maximum: 9
                minimum: 0
                type: integer
            type: object
        type: object
`

func (a v1alpha1JavaSpringBoot) Schema() (*spec.Schema, error) {
	schema, err := framework.SchemaFromFunctionDefinition(resid.NewGvk("example.com", "v1alpha1", "JavaSpringBoot"), javaSpringBootDefinition)
	return schema, errors.WrapPrefixf(err, "parsing JavaSpringBoot schema")
}

func (a *v1alpha1JavaSpringBoot) Validate() error {
	var errs []error
	if strings.HasSuffix(a.Spec.Image, ":latest") {
		errs = append(errs, errors.Errorf("spec.image should not have latest tag"))
	}
	if len(errs) > 0 {
		return validationErrors.CompositeValidationError(errs...)
	}
	return nil
}

func main() {
	p := &framework.VersionedAPIProcessor{FilterProvider: framework.GVKFilterMap{
		"JavaSpringBoot": {
			"example.com/v1alpha1": &v1alpha1JavaSpringBoot{},
		}}}

	source := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
apiVersion: config.kubernetes.io/v1
kind: ResourceList
functionConfig:
  apiVersion: example.com/v1alpha1
  kind: JavaSpringBoot
  metadata:
    name: my-app
  spec:
    image: example.docker.com/team/app:1.0
    domain: demo.example.com
`)}
	if err := framework.Execute(p, source); err != nil {
		log.Fatal(err)
	}

}
Output:

apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: my-app
    selector:
      app: my-app
  spec:
    replicas: 3
    template:
      spec:
        containers:
        - name: app
          image: example.docker.com/team/app:1.0
          ports:
          - containerPort: 80
            name: http
- apiVersion: v1
  kind: Service
  metadata:
    name: my-app-svc
  spec:
    selector:
      app: my-app
    ports:
    - protocol: TCP
      port: 80
      targetPort: 80
- apiVersion: networking.k8s.io/v1
  kind: Ingress
  metadata:
    name: my-app-ingress
  spec:
    tls:
    - hosts:
      - demo.example.com
      secretName: secret-tls
    defaultBackend:
      service:
        name: my-app
        port:
          number: 80
functionConfig:
  apiVersion: example.com/v1alpha1
  kind: JavaSpringBoot
  metadata:
    name: my-app
  spec:
    image: example.docker.com/team/app:1.0
    domain: demo.example.com

func (*VersionedAPIProcessor) Process added in v0.10.14

func (p *VersionedAPIProcessor) Process(rl *ResourceList) error

Process makes VersionedAPIProcessor implement the ResourceListProcessor interface. It looks up the configuration object to use based on the ApiVersion and Kind of the input ResourceList.functionConfig, loads ResourceList.functionConfig into that object, invokes Validate and Default if supported, and finally invokes Filter.

Directories

Path Synopsis
Package command contains a builder for creating cobra.Commands based on configuration functions written using the kyaml function framework.
Package command contains a builder for creating cobra.Commands based on configuration functions written using the kyaml function framework.
Package main contains an example using the framework.
Package main contains an example using the framework.
Package frameworktestutil contains utilities for testing functions written using the framework.
Package frameworktestutil contains utilities for testing functions written using the framework.
Package parser contains implementations of the framework.TemplateParser and framework.SchemaParser interfaces.
Package parser contains implementations of the framework.TemplateParser and framework.SchemaParser interfaces.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL