mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-18 07:45:23 +00:00
380 lines
9.0 KiB
Go
380 lines
9.0 KiB
Go
// Copyright 2021 The Kubernetes Authors.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package command_test
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
|
|
"sigs.k8s.io/kustomize/kyaml/fn/framework"
|
|
"sigs.k8s.io/kustomize/kyaml/fn/framework/command"
|
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
|
)
|
|
|
|
const service = "Service"
|
|
|
|
// ExampleBuild_modify implements a function that sets an annotation on each resource.
|
|
// The annotation value is configured via ResourceList.FunctionConfig.
|
|
func ExampleBuild_modify() {
|
|
// create a struct matching the structure of ResourceList.FunctionConfig to hold its data
|
|
var config struct {
|
|
Data map[string]string `yaml:"data"`
|
|
}
|
|
fn := func(items []*yaml.RNode) ([]*yaml.RNode, error) {
|
|
for i := range items {
|
|
// set the annotation on each resource item
|
|
err := items[i].PipeE(yaml.SetAnnotation("value", config.Data["value"]))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return items, nil
|
|
}
|
|
p := framework.SimpleProcessor{Filter: kio.FilterFunc(fn), Config: &config}
|
|
cmd := command.Build(p, command.StandaloneDisabled, false)
|
|
|
|
// for testing purposes only -- normally read from stdin when Executing
|
|
cmd.SetIn(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
|
|
`))
|
|
// run the command
|
|
if err := cmd.Execute(); 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
|
|
}
|
|
|
|
// ExampleBuild_generateReplace generates a resource from a FunctionConfig.
|
|
// If the resource already exists, it replaces the resource with a new copy.
|
|
func ExampleBuild_generateReplace() {
|
|
// 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{}
|
|
|
|
// function implementation -- generate a Service resource
|
|
p := &framework.SimpleProcessor{
|
|
Config: functionConfig,
|
|
Filter: kio.FilterFunc(func(items []*yaml.RNode) ([]*yaml.RNode, error) {
|
|
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])
|
|
}
|
|
|
|
// generate the resource
|
|
n, err := yaml.Parse(fmt.Sprintf(`apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: %s
|
|
`, functionConfig.Spec.Name))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
newNodes = append(newNodes, n)
|
|
return newNodes, nil
|
|
}),
|
|
}
|
|
cmd := command.Build(p, command.StandaloneDisabled, false)
|
|
|
|
// for testing purposes only -- normally read from stdin when Executing
|
|
cmd.SetIn(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
|
|
`))
|
|
|
|
// run the command
|
|
if err := cmd.Execute(); 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
|
|
}
|
|
|
|
// ExampleBuild_generateUpdate generates a resource, updating the previously generated
|
|
// copy rather than replacing it.
|
|
//
|
|
// Note: This will keep manual edits to the previously generated copy.
|
|
func ExampleBuild_generateUpdate() {
|
|
// function API definition which will be parsed from the ResourceList.FunctionConfig
|
|
// read from stdin
|
|
type Spec struct {
|
|
Name string `yaml:"name,omitempty"`
|
|
Annotations map[string]string `yaml:"annotations,omitempty"`
|
|
}
|
|
type ExampleServiceGenerator struct {
|
|
Spec Spec `yaml:"spec,omitempty"`
|
|
}
|
|
functionConfig := &ExampleServiceGenerator{}
|
|
|
|
// function implementation -- generate or update a Service resource
|
|
fn := func(items []*yaml.RNode) ([]*yaml.RNode, error) {
|
|
var found bool
|
|
for i := range items {
|
|
meta, err := items[i].GetMeta()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// something we already generated, reconcile it to make sure it matches what
|
|
// is specified by the FunctionConfig
|
|
if meta.Name == functionConfig.Spec.Name &&
|
|
meta.Kind == service &&
|
|
meta.APIVersion == "v1" {
|
|
// set some values
|
|
for k, v := range functionConfig.Spec.Annotations {
|
|
err := items[i].PipeE(yaml.SetAnnotation(k, v))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if found {
|
|
return items, nil
|
|
}
|
|
|
|
// generate the resource if not found
|
|
n, err := yaml.Parse(fmt.Sprintf(`apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: %s
|
|
`, functionConfig.Spec.Name))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for k, v := range functionConfig.Spec.Annotations {
|
|
err := n.PipeE(yaml.SetAnnotation(k, v))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
items = append(items, n)
|
|
return items, nil
|
|
}
|
|
|
|
p := &framework.SimpleProcessor{Config: functionConfig, Filter: kio.FilterFunc(fn)}
|
|
cmd := command.Build(p, command.StandaloneDisabled, false)
|
|
|
|
// for testing purposes only -- normally read from stdin when Executing
|
|
cmd.SetIn(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: bar
|
|
functionConfig:
|
|
apiVersion: example.com/v1alpha1
|
|
kind: ExampleServiceGenerator
|
|
spec:
|
|
name: bar
|
|
annotations:
|
|
a: b
|
|
`))
|
|
|
|
// run the command
|
|
if err := cmd.Execute(); 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
|
|
// annotations:
|
|
// a: 'b'
|
|
// functionConfig:
|
|
// apiVersion: example.com/v1alpha1
|
|
// kind: ExampleServiceGenerator
|
|
// spec:
|
|
// name: bar
|
|
// annotations:
|
|
// a: b
|
|
}
|
|
|
|
// ExampleBuild_validate validates that all Deployment resources have the replicas field set.
|
|
// If any Deployments do not contain spec.replicas, then the function will return results
|
|
// which will be set on ResourceList.results
|
|
func ExampleBuild_validate() {
|
|
fn := func(rl *framework.ResourceList) error {
|
|
// validation results
|
|
var validationResults framework.Results
|
|
|
|
// validate that each Deployment resource has spec.replicas set
|
|
for i := range rl.Items {
|
|
// only check Deployment resources
|
|
meta, err := rl.Items[i].GetMeta()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if meta.Kind != "Deployment" {
|
|
continue
|
|
}
|
|
|
|
// lookup replicas field
|
|
r, err := rl.Items[i].Pipe(yaml.Lookup("spec", "replicas"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// check replicas not specified
|
|
if r != nil {
|
|
continue
|
|
}
|
|
validationResults = append(validationResults, &framework.Result{
|
|
Severity: framework.Error,
|
|
Message: "field is required",
|
|
ResourceRef: &yaml.ResourceIdentifier{
|
|
TypeMeta: meta.TypeMeta,
|
|
NameMeta: meta.ObjectMeta.NameMeta,
|
|
},
|
|
Field: &framework.Field{
|
|
Path: "spec.replicas",
|
|
ProposedValue: "1",
|
|
},
|
|
})
|
|
}
|
|
|
|
if len(validationResults) > 0 {
|
|
rl.Results = validationResults
|
|
}
|
|
|
|
return rl.Results
|
|
}
|
|
|
|
cmd := command.Build(framework.ResourceListProcessorFunc(fn), command.StandaloneDisabled, true)
|
|
// for testing purposes only -- normally read from stdin when Executing
|
|
cmd.SetIn(bytes.NewBufferString(`
|
|
apiVersion: config.kubernetes.io/v1
|
|
kind: ResourceList
|
|
# items are provided as nodes
|
|
items:
|
|
- apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: foo
|
|
`))
|
|
|
|
// run the command
|
|
if err := cmd.Execute(); err != nil {
|
|
// normally exit 1 here
|
|
}
|
|
|
|
// Output:
|
|
// apiVersion: config.kubernetes.io/v1
|
|
// kind: ResourceList
|
|
// items:
|
|
// - apiVersion: apps/v1
|
|
// kind: Deployment
|
|
// metadata:
|
|
// name: foo
|
|
// results:
|
|
// - message: field is required
|
|
// severity: error
|
|
// resourceRef:
|
|
// apiVersion: apps/v1
|
|
// kind: Deployment
|
|
// name: foo
|
|
// field:
|
|
// path: spec.replicas
|
|
// proposedValue: "1"
|
|
}
|