cmd/config: Add examples and tutorials for config functions

- Add examples under `functions`
- Add built-in tutorial for functions
This commit is contained in:
Phillip Wittrock
2019-11-26 20:08:23 -08:00
parent 5876a8cce0
commit dc66de6bf3
34 changed files with 1524 additions and 2 deletions

View File

@@ -0,0 +1,2 @@
Copyright {{.Year}} {{.Holder}}
SPDX-License-Identifier: Apache-2.0

View File

@@ -0,0 +1,42 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
.PHONY: generate license fix vet fmt test build tidy image
GOBIN := $(shell go env GOPATH)/bin
build:
(cd image && go build -v -o $(GOBIN)/config-function .)
all: generate license build fix vet fmt test lint tidy
fix:
(cd image && go fix ./...)
fmt:
(cd image && go fmt ./...)
generate:
(which $(GOBIN)/mdtogo || go get sigs.k8s.io/kustomize/cmd/mdtogo)
(cd image && GOBIN=$(GOBIN) go generate ./...)
license:
(which $(GOPATH)/bin/addlicense || go get github.com/google/addlicense)
$(GOPATH)/bin/addlicense -y 2019 -c "The Kubernetes Authors." -f LICENSE_TEMPLATE .
tidy:
(cd image && go mod tidy)
lint:
(which $(GOBIN)/golangci-lint || go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.19.1)
(cd image && $(GOBIN)/golangci-lint run ./...)
test:
(cd image && go test -cover ./...)
vet:
(cd image && go vet ./...)
image:
docker build image -t gcr.io/kustomize-functions/example-tshirt:v0.1.0
docker push gcr.io/kustomize-functions/example-tshirt:v0.1.0

View File

@@ -0,0 +1,35 @@
# Injection
This is an example of implementing an injection function.
This example is written in `go` and uses the `kyaml` libraries for parsing the
input and writing the output. Writing in `go` is not a requirement.
## Function implementation
The function is implemented as an [image](image), and built using `make image`.
The template is implemented as a go program, which reads a collection of input
Resource configuration, and looks for invalid configuration.
## Function invocation
The function is invoked by authoring a [local Resource](local-resource)
with `metadata.configFn` and running:
kustomize config run-fns local-resources/
This exists non-zero if there is an error.
## Running the Example
Run the validator with:
kustomize config run-fns local-resource/
This will add resource reservations to the Deployment. Change the `tshirt-size`
annotation from `medium` to `small` and rerun:
kustomize config run-fns local-resource/
Observe that the reservations have changed.

View File

@@ -0,0 +1,15 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
FROM golang:1.13-stretch
ENV CGO_ENABLED=0
WORKDIR /go/src/
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY main.go .
RUN go build -v -o /usr/local/bin/config-function ./
FROM alpine:latest
COPY --from=0 /usr/local/bin/config-function /usr/local/bin/config-function
CMD ["config-function"]

View File

@@ -0,0 +1,5 @@
module sigs.k8s.io/kustomize/functions/examples/injection-tshirt-sizes
go 1.13
require sigs.k8s.io/kustomize/kyaml v0.0.0-20191126155111-73fb32c85ad4

View File

@@ -0,0 +1,27 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d h1:LCPbGQ34PMrwad11aMZ+dbz5SAsq/0ySjRwQ8I9Qwd8=
gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
sigs.k8s.io/kustomize/kyaml v0.0.0-20191126155111-73fb32c85ad4 h1:QfQuib3Xi0uyHUi/R5MgWmDScb5iy/+LjoaGIdpmMpE=
sigs.k8s.io/kustomize/kyaml v0.0.0-20191126155111-73fb32c85ad4/go.mod h1:rywm/rcR5LmCBghz9956tE45OdUPChFoXVVs+WmhMTI=

View File

@@ -0,0 +1,116 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package main implements an injection function for resource reservations and
// is run with `kustomize config run-fns -- DIR/`.
package main
import (
"fmt"
"os"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
func main() {
rw := &kio.ByteReadWriter{Reader: os.Stdin, Writer: os.Stdout, KeepReaderAnnotations: true}
p := kio.Pipeline{
Inputs: []kio.Reader{rw}, // read the inputs into a slice
Filters: []kio.Filter{filter{}}, // run the inject into the inputs
Outputs: []kio.Writer{rw}} // copy the inputs to the output
if err := p.Execute(); err != nil {
os.Exit(1)
}
}
// filter implements kio.Filter
type filter struct{}
// Filter injects cpu and memory resource reservations into containers for
// Resources containing the `tshirt-size` annotation.
func (filter) Filter(in []*yaml.RNode) ([]*yaml.RNode, error) {
// inject the resource reservations into each Resource
for _, r := range in {
if err := inject(r); err != nil {
return nil, err
}
}
return in, nil
}
// cpuSizes is the mapping from tshirt-size to cpu reservation quantity
var cpuSizes = map[string]string{
"small": "200m",
"medium": "4",
"large": "16",
}
// memorySizes is the mapping from tshirt-size to memory reservation quantity
var memorySizes = map[string]string{
"small": "50MiB",
"medium": "1GiB",
"large": "32GiB",
}
// inject sets the cpu and memory reservations on all containers for Resources annotated
// with `tshirt-size: small|medium|large`
func inject(r *yaml.RNode) error {
// lookup the containers field
containers, err := r.Pipe(yaml.Lookup("spec", "template", "spec", "containers"))
if err != nil {
s, _ := r.String()
return fmt.Errorf("%v: %s", err, s)
}
if containers == nil {
// doesn't have containers, skip the Resource
return nil
}
// check for the tshirt-size annotations
meta, err := r.GetMeta()
if err != nil {
return err
}
var memorySize, cpuSize string
if size, found := meta.Annotations["tshirt-size"]; !found {
// not a tshirt-sized Resource, ignore it
return nil
} else {
// lookup the memory and cpu quantities based on the tshirt size
memorySize = memorySizes[size]
cpuSize = cpuSizes[size]
if memorySize == "" || cpuSize == "" {
return fmt.Errorf("unsupported tshirt-size: " + size)
}
}
// visit each container and apply the cpu and memory reservations
return containers.VisitElements(func(node *yaml.RNode) error {
// set cpu
err := node.PipeE(
// lookup resources.requests.cpu, creating the field as a
// ScalarNode if it doesn't exist
yaml.LookupCreate(yaml.ScalarNode, "resources", "requests", "cpu"),
// set the field value to the cpuSize
yaml.Set(yaml.NewScalarRNode(cpuSize)))
if err != nil {
s, _ := r.String()
return fmt.Errorf("%v: %s", err, s)
}
// set memory
err = node.PipeE(
// lookup resources.requests.memory, creating the field as a
// ScalarNode if it doesn't exist
yaml.LookupCreate(yaml.ScalarNode, "resources", "requests", "memory"),
// set the field value to the memorySize
yaml.Set(yaml.NewScalarRNode(memorySize)))
if err != nil {
s, _ := r.String()
return fmt.Errorf("%v: %s", err, s)
}
return nil
})
}

View File

@@ -0,0 +1,30 @@
# Copyright 2019 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
apiVersion: examples.config.kubernetes.io/v1beta1
kind: Validator
metadata:
configFn:
container:
image: gcr.io/kustomize-functions/example-tshirt:v0.1.0
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
annotations:
tshirt-size: small # this injects the resource reservations
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx