producer

package
v0.38.0 Latest Latest
Warning

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

Go to latest
Published: Feb 10, 2021 License: Apache-2.0 Imports: 0 Imported by: 0

Documentation

Overview

Code generated by "mdtogo"; DO NOT EDIT.

Code generated by "mdtogo"; DO NOT EDIT.

Code generated by "mdtogo"; DO NOT EDIT.

Code generated by "mdtogo"; DO NOT EDIT.

Code generated by "mdtogo"; DO NOT EDIT.

Code generated by "mdtogo"; DO NOT EDIT.

Code generated by "mdtogo"; DO NOT EDIT.

Code generated by "mdtogo"; DO NOT EDIT.

Code generated by "mdtogo"; DO NOT EDIT.

Code generated by "mdtogo"; DO NOT EDIT.

Code generated by "mdtogo"; DO NOT EDIT.

Code generated by "mdtogo"; DO NOT EDIT.

Code generated by "mdtogo"; DO NOT EDIT.

Code generated by "mdtogo"; DO NOT EDIT.

Code generated by "mdtogo"; DO NOT EDIT.

Code generated by "mdtogo"; DO NOT EDIT.

Code generated by "mdtogo"; DO NOT EDIT.

Index

Constants

This section is empty.

Variables

View Source
var BlueprintGuide = `
{{% pageinfo color="warning" %}}

### Notice: Under Development

{{% /pageinfo %}}

*Reusable, customizable components can be built and shared as blueprints.*

## Overview

Blueprints are a **pattern for developing reusable, customizable
configuration**.  Blueprints are typically published and consumed by
different teams.

{{% pageinfo color="primary" %}}
Because packages can be updated to new versions, blueprint consumers
can pull in changes to a blueprint after fetching it.
{{% /pageinfo %}}

### Example use cases for blueprints

- **Languages**: Java / Node / Ruby / Python / Golang application
- **Frameworks**: Spring, Express, Rails, Django
- **Platforms**: Kubeflow, Spark
- **Applications / Stacks**:
  - Rails Backend + Node Frontend + Prometheus
  - Spring Cloud Microservices (discovery-server, config-server, api-gateway,
    admin-server, hystrix, various backends)
- **Infrastructure Stacks**: CloudSQL + Pubsub + GKE

{{< svg src="images/blueprint" >}}

  # Optional: copy the mysql-kustomize blueprint to follow along
  kpt pkg get https://github.com/GoogleContainerTools/kpt.git/package-examples/mysql-kustomize mysql

## Factor / denormalize the configuration data

Structuring blueprints into separate publisher and consumer focused pieces
provides a clean UX for consumers to modifys the package.

Example: provide separate directories with pieces consumers are expected to
edit (replicas) vs publisher implementation (health check command).

As a package publisher, it is important to think about **where and how you
want to promote customization.**

We will use [kustomize] to structure the package:

1. **Factoring out a common field value**
   - Example: ` + "`" + `namespace` + "`" + `, ` + "`" + `commonLabels` + "`" + `, ` + "`" + `commonAnnotations` + "`" + `
2. **Factoring a single resource into multiple files**
   - Example: ` + "`" + `resources` + "`" + ` + ` + "`" + `patches` + "`" + `

{{% pageinfo color="info" %}}
Remote kustomize bases may be used to reference the publisher focused pieces
directly from a git repository rather than including them in the package.

One disadvantage of this approach is that it creates a dependency on the
remote package being accessible in order to push -- if you can't fetch the
remote package, then you can't push changes.
{{% /pageinfo %}}

Example package structure:

  $ tree mysql/
  mysql/
  ├── Kptfile
  ├── README.md
  ├── instance
  │   ├── kustomization.yaml
  │   ├── service.yaml
  │   └── statefulset.yaml
  └── upstream
      ├── kustomization.yaml
      ├── service.yaml
      └── statefulset.yaml

The ` + "`" + `upstream` + "`" + ` directory acts as a kustomize base to the ` + "`" + `instance` + "`" + ` directory.
Upstream contains things most **consumers are unlikely to modify** --
e.g. the image (for off the shelf software), health check endpoints, etc.

The ` + "`" + `instance` + "`" + ` directory contains patches with fields populated for things
most **consumers are expected to modify** -- e.g. namespace, cpu, memory,
user, password, etc.

{{% pageinfo color="warning" %}}
While the package is structured into publisher and consumer focused pieces,
it is still possible for the package consumer to modify (via direct edits)
or override (via patches) any part of the package.

**Factoring is for UX, not for enforcement of specific configuration values.**
{{% /pageinfo %}}

## Commands, Args and Environment Variables

How do you configure applications in a way that can be extended or overridden --
how can consumers of a package specify new args, flags, environment variables
or configuration files and merge those with those defined by the package
publisher?

### Notes

- Commands and Args are non-associative arrays so it is not possible to
  target specific elements -- any changes replace the entire list of elements.
- Commands and Args are separate fields that are concatenated
- Commands and Args can use values from environment variables
- Environment variables are associative arrays, so it is possible to target
  specific elements within the list to be overridden or added.
- Environment variables can be pulled from ConfigMaps and Secrets
- Kustomize merges ConfigMaps and Secrets per-key (deep merges of the
  values is not supported).
- ConfigMaps and Secrets can be read from apps via environment variables or
  volumes.

Flags and arguments may be factored into publisher and consumer focused pieces
by **specifying the ` + "`" + `command` + "`" + ` in the ` + "`" + `upstream` + "`" + ` base dir and the ` + "`" + `args` + "`" + ` in the
` + "`" + `instance` + "`" + ` dir**.  This allows consumers to set and add flags using ` + "`" + `args` + "`" + `
without erasing those defined by the publisher in the ` + "`" + `command` + "`" + `.

When **specifying values for arguments or flag values, it is best to use an
environment variable read from a generated ConfigMap.**  This enables overriding
the value using kustomize's generators.

Example: Enable setting ` + "`" + `--skip-grant-tables` + "`" + ` as a flag on mysql.

*` + "`" + `# {"$ref": ...` + "`" + ` comments are setter references, defined in the next section.*

  # mysql/instance/statefulset.yaml
  # Wire ConfigMap value from kustomization.yaml to
  # an environment variable used by an arg
  apiVersion: apps/v1
  kind: StatefulSet
  ...
  spec:
    template:
      metadata:
        labels:
          app: release-name-mysql
      spec:
        containers:
        - name: mysql
          ...
          args:
          - --skip-grant-tables=$(SKIP_GRANT_TABLES)
          ...
          env:
          - name: SKIP_GRANT_TABLES
            valueFrom:
              configMapKeyRef:
                name: mysql
                key: skip-grant-tables

  # mysql/instance/kustomization.yaml
  # Changing the literal changes the StatefulSet behavior
  apiVersion: kustomize.config.k8s.io/v1beta1
  kind: Kustomization
  configMapGenerator:
  - name: mysql
    behavior: merge
    literals:
    # for bootstrapping the root table grants -- set to false after bootstrapped
    - "skip-grant-tables=true" # {"$kpt-set":"skip-grant-tables"}

### Generating ConfigMaps and Secrets

Kustomize supports generating ConfigMaps and Secrets from the
kustomization.yaml.

- Generated objects have a suffix applied so that the name is unique for
  the data.  This ensures a rollout of Deployments and StatefulSets occurs.
- Generated object may have their values overridden by downstream consumers.

Example Upstream:

  # mysql/upstream
  apiVersion: kustomize.config.k8s.io/v1beta1
  kind: Kustomization
  configMapGenerator:
  - name: mysql
    literals:
      - skip-grant-tables=true

Example Instance:

  # mysql/instance
  apiVersion: kustomize.config.k8s.io/v1beta1
  kind: Kustomization
  configMapGenerator:
  - name: mysql
    behavior: merge
    literals:
    - "skip-grant-tables=true" # {"$kpt-set":"skip-grant-tables"}
    - "mysql-user=" # {"$kpt-set":"mysql-user"}
    - "mysql-database=" # {"$kpt-set":"mysql-database"}

## Setters and Substitutions

It may be desirable to provide user friendly commands for customizing the
package rather than exclusively through text editors and sed:

- Setting a value in several different patches at once
- Setting common or required values -- e.g. the image name for a Java app
  blueprint
- Setting the image tag to match the digest of an image that was just build.
- Setting a value from the environment when the package is fetched the first
  time -- e.g. GCP project.

Setters and substitutions are a way to define user and automation friendly
commands for performing structured edits of a configuration.

Combined with the preceding techniques, setters or substitutions can be used
to modify generated ConfigMaps and patches in the ` + "`" + `instance` + "`" + ` dir.

See the [setter] and [substitution] guides for details.

  # mysql/instance/kustomization.yaml
  apiVersion: kustomize.config.k8s.io/v1beta1
  kind: Kustomization
  #
  # namespace is the namespace the mysql instance is run in
  namespace: "" # {"$kpt-set":"namespace"}
  configMapGenerator:
  - name: mysql
    behavior: merge
    literals:
    # for bootstrapping the root table grants -- set to false after bootstrapped
    - "skip-grant-tables=true" # {"$kpt-set":"skip-grant-tables"}
    - "mysql-user=" # {"$kpt-set":"mysql-user"}
    - "mysql-database=" # {"$kpt-set":"mysql-database"}
  ...

  # mysql/instance/statefulset.yaml
  apiVersion: apps/v1
  kind: StatefulSet
  metadata:
    name: mysql
  spec:
    template:
      spec:
        containers:
        - name: mysql
  ...
          ports:
          - name: mysql
            containerPort: 3306 # {"$kpt-set":"port"}
          resources:
            requests:
              cpu: 100m # {"$kpt-set":"cpu"}
              memory: 256Mi # {"$kpt-set":"memory"}

  # mysql/instance/service.yaml
  apiVersion: v1
  kind: Service
  ...
  spec:
    ports:
    - name: mysql
      port: 3306 # {"$kpt-set":"port"}
      targetPort: mysql

## Updates

Individual directories may have their own package versions by prefixing the
version with the directory path -- e.g.
` + "`" + `package-examples/mysql-kustomize/v0.1.0` + "`" + `.

When publishing a new version of a package, publishers should think about how
their changes will be merged into existing packages.

Changing values in the instance package is not recommended, but adding them
may be ok -- changes to fields will overwrite user changes to those same
fields, whereas adds will only conflict if the user added the same field.
`
View Source
var BootstrapGuide = `` /* 1208-byte string literal not displayed */
View Source
var ContainerGuide = `
Functions may be written as container images. The container must run a program
which:

- Reads a ResourceList from STDIN
- Writes a ResourceList to STDOUT
- Exits non-0 on failure
- Writes error messages to users on STDERR

By default containers are run without network access, and without the ability
to write to volumes outside the container. All local environment variables
except the ` + "`" + `TMPDIR` + "`" + ` variable are loaded into the container by default. See the
[fn command reference] for more details.

While container functions may be written in any language so long as they
adhere to the [io specification] (read / write ResourceList), the
[kpt-functions-sdk] provides a solution for writing functions using typescript
and the [go libraries] provide utilities for writing them in golang.

## Imperative Run

Container functions may be run imperatively using the ` + "`" + `--image` + "`" + ` flag with
` + "`" + `kpt fn run` + "`" + `. This will create a container from the image, then write to its
STDIN a ResourceList created from the contents of the package directory, and
finally read from it's STDOUT a ResourceList used to write resource back to
the package directory.

  kpt fn run DIR/ --image gcr.io/a/b:v1

## Declarative Run

Container functions may be run by declaring the function in a resource using
the ` + "`" + `config.kubernetes.io/function` + "`" + ` annotation.

  apiVersion: example.com/v1beta1
  kind: ExampleKind
  metadata:
    name: function-input
    annotations:
      config.kubernetes.io/function: |
        container:
          image: gcr.io/a/b:v1

To run the declared function use ` + "`" + `kpt fn run DIR/` + "`" + ` on the directory containing
the example.

## Next Steps

- Explore other ways to run functions from the [Functions Developer Guide].
- Find out how to structure a pipeline of functions from the
  [functions concepts] page.
- Consult the [fn command reference].
`
View Source
var DevelopGuide = `
This guide will walk you through developing a config function using the
Typescript SDK.

## Setup

### System Requirements

Currently supported platforms: amd64 Linux/Mac

### Setting Up Your Local Environment

- Install [node][download-node]
  - The SDK requires ` + "`" + `npm` + "`" + ` version 6 or higher.
  - If installing node from binaries (i.e. without a package manager), follow
    these [installation instructions][install-node].
- Install [docker][install-docker]

### Your Kubernetes Cluster

For the type generation functionality to work, you need a Kubernetes cluster
with the [CRD OpenAPI Publishing][crd-openapi] feature which is beta with
Kubernetes 1.15.

Alternatively, you can use an existing NPM package with pre-generated types
such as the ` + "`" + `hello-world` + "`" + ` package discussed in the [Quickstart] and skip to
[implementing the function](#implement-the-function).

#### Using a ` + "`" + `kind` + "`" + ` Cluster

The easiest way to get developing is to use ` + "`" + `kind` + "`" + ` to bring up a cluster
running in a local container.

1. Download the [kind binary][download-kind] version 0.5.1 or higher
1. Use this config file:

   ` + "`" + `` + "`" + `` + "`" + `sh
   cat > kind.yaml <<EOF
   kind: Cluster
   apiVersion: kind.sigs.k8s.io/v1alpha3
   kubeadmConfigPatches:
   - |
     apiVersion: kubeadm.k8s.io/v1beta2
     kind: ClusterConfiguration
     metadata:
       name: config
     apiServer:
       extraArgs:
         "feature-gates": "CustomResourcePublishOpenAPI=true"
   nodes:
   - role: control-plane
   EOF
   ` + "`" + `` + "`" + `` + "`" + `

   Note the use of the beta feature.

1. Create the cluster:

   ` + "`" + `` + "`" + `` + "`" + `sh
   kind create cluster --name=kpt-functions --config=kind.yaml --image=kindest/node:v1.15.7
   ` + "`" + `` + "`" + `` + "`" + `

#### Using a GKE Cluster

You can also use a deployed cluster in GKE. The beta k8s feature is avilable
only when using GKE's ` + "`" + `--enable-kubernetes-alpha` + "`" + ` flag, as seen here:

  gcloud container clusters create $USER-1-15 --cluster-version=latest --region=us-central1-a --project <PROJECT>
  gcloud container clusters get-credentials $USER-1-15 --zone us-central1-a --project <PROJECT>

### Working with CRDs

The SDK uses the k8s server to generate the typescript classes. If your
function uses a Custom Resource Definition, make sure you apply it to the
cluster used for type generation:

  kubectl apply -f /path/to/my/crd.yaml

## Create the NPM Package

To initialize a new NPM package, first create a package directory:

  mkdir my-package
  cd my-package

> **Note:** All subsequent commands are run from the ` + "`" + `my-package/` + "`" + ` directory.

Run the interactive initializer:

  npm init kpt-functions

Follow the instructions and respond to all prompts.

This process will create the following:

1. ` + "`" + `package.json` + "`" + `: The ` + "`" + `kpt-functions` + "`" + ` framework library is the only item
   declared in ` + "`" + `dependencies` + "`" + `. Everything required to compile and test your
   config function is declared as ` + "`" + `devDependencies` + "`" + `, including the
   ` + "`" + `create-kpt-functions` + "`" + ` CLI discussed later in the ` + "`" + `README` + "`" + `.
1. ` + "`" + `src/` + "`" + `: Directory containing the source files for all your functions, e.g.:
   - ` + "`" + `my_func.ts` + "`" + `: Implement your function's interface here.
   - ` + "`" + `my_func_test.ts` + "`" + `: Unit tests for your function.
   - ` + "`" + `my_func_run.ts` + "`" + `: The entry point from which your function is run.
1. ` + "`" + `src/gen/` + "`" + `: Contains Kubernetes core and CRD types generated from the
   OpenAPI spec published by the cluster you selected.
1. ` + "`" + `build/` + "`" + `: Contains Dockerfile for each function, e.g.:
   - ` + "`" + `my_func.Dockerfile` + "`" + `

Next, install all package dependencies:

  npm install

In addition to installation, ` + "`" + `install` + "`" + ` compiles your function into the ` + "`" + `dist/` + "`" + `
directory.

You can run your function directly:

  node dist/my_func_run.js --help

Currently, it simply passes through the input configuration data. Let's remedy
this.

## Implement the Function

You can now start implementing the function using your favorite IDE, e.g.

  code .

In ` + "`" + `src/my_func.ts` + "`" + `, implement the ` + "`" + `KptFunc` + "`" + ` interface from the [TS SDK API].

Take a look at these [demo functions] to better understand how
to use the typescript library. These functions are available as container
images documented in the [catalog].

Once you've written some code, build the package with:

  npm run build

Alternatively, run the following in a separate terminal. It will continuously
build your function as you make changes:

  npm run watch

To run the tests, use:

  npm test

## Debug and Test the Function

You may want to run a function developed with one of the config function SDKs
using the exec runtime in order to avoid the overhead associated with running
a container. To run your function in the exec runtime, you will first need to
package your function as an executable.

The below example shows how to run a typescript function using the kpt exec
runtime.

### Prerequisites

- Install the pkg CLI.

  ` + "`" + `` + "`" + `` + "`" + `sh
  npm install -g pkg
  ` + "`" + `` + "`" + `` + "`" + `

- Install your kpt-functions package module to create your function's
  distributable file.

  ` + "`" + `` + "`" + `` + "`" + `sh
  npm i
  ` + "`" + `` + "`" + `` + "`" + `

### Steps

1. Use the pkg CLI to create an executable from your function's distributable
   file. For a ` + "`" + `my_fn` + "`" + ` function built using the typescript SDK, this is
   ` + "`" + `dist/my_fn_run.js` + "`" + `.

   ` + "`" + `` + "`" + `` + "`" + `sh
   npx pkg dist/my_fn_run.js
   ` + "`" + `` + "`" + `` + "`" + `

1. Pass the path to the appropriate executable for your OS when running kpt
   using the exec runtime.

   ` + "`" + `` + "`" + `` + "`" + `sh
   kpt fn run DIR/ --enable-exec --exec-path /path/to/my_fn_run-macos -- a=b
   ` + "`" + `` + "`" + `` + "`" + `

## Build and push container images

With your working function in-hand, it's time to package your function into an
executable container image.

To build the docker image:

  npm run kpt:docker-build

You can now run the function container, e.g.:

  docker run gcr.io/kpt-functions-demo/my-func:dev --help

To push the image to your container registry of choice:

  npm run kpt:docker-push

You'll need proper authentication/authorization to push to your registry.

` + "`" + `kpt:docker-push` + "`" + ` pushes to the registry specified in the
` + "`" + `kpt.docker_repo_base` + "`" + ` field in ` + "`" + `package.json` + "`" + `. You can manually edit this
field at any time.

The default value for the container image tag is ` + "`" + `dev` + "`" + `. This can be overridden
using` + "`" + `--tag` + "`" + ` flag:

  npm run kpt:docker-build -- --tag=latest
  npm run kpt:docker-push -- --tag=latest

## Use the SDK CLI

The ` + "`" + `create-kpt-functions` + "`" + ` package (installed as ` + "`" + `devDependencies` + "`" + `), provides
a CLI for managing the NPM package you created above. The CLI sub-commands can
be invoked via ` + "`" + `npm run` + "`" + `. For example, to add a new function to the package:

  npm run kpt:function-create

These sub-commands are available:

  kpt:docker-create       Generate Dockerfiles for all functions. Overwrite
                          files if they exist.
  kpt:docker-build        Build container images for all functions.
  kpt:docker-push         Push container images to the registry for all
                          functions.
  kpt:function-create     Generate stubs for a new function. Overwrites files
                          if they exist.
  kpt:type-create         Generate classes for core and CRD types. Overwrite
                          files if they exist.

Flags are passed to the CLI after the ` + "`" + `--` + "`" + ` separator. For example, to pass a
tag when building a container image:

  npm run kpt:docker-build -- --tag=latest

## Next Steps

- Learn how to [run functions].
- Find out how to structure a pipeline of functions from the
  [functions concepts] page.
- Take a look at these [demo functions] to better understand how to use the
  typescript SDK.
`
View Source
var ExecGuide = `
{{% pageinfo color="warning" %}}
The Exec runtime is Alpha. It is disabled by default, and must be enabled with
the ` + "`" + `--enable-exec` + "`" + ` flag.
{{% /pageinfo %}}

Config functions may be run as executables outside of containers. Exec
functions read input and write output like container functions, but are run
outside of a container.

Running functions as executables can be useful for function development, or for
running trusted executables.

{{% pageinfo color="info" %}}
Exec functions may be converted to container functions by building the
executable into a container and invoking it as the container's ` + "`" + `CMD` + "`" + ` or
` + "`" + `ENTRYPOINT` + "`" + `.
{{% /pageinfo %}}

## Imperative Run

Exec functions may be run imperatively using the ` + "`" + `--exec-path` + "`" + ` flag with
` + "`" + `kpt fn run` + "`" + `.

  kpt fn run DIR/ --enable-exec --exec-path /path/to/executable

This is similar to building ` + "`" + `/path/to/executable` + "`" + ` into the container image
` + "`" + `gcr.io/project/image:tag` + "`" + ` and running -- except that the executable has access
to the local machine.

  kpt fn run DIR/ --image gcr.io/project/image:tag

Just like container functions, exec functions accept input as arguments after
` + "`" + `--` + "`" + `.

  kpt fn run DIR/ --enable-exec --exec-path /path/to/executable -- foo=bar

## Declarative Run

Exec functions may also be run by declaring the function in a resource using
the ` + "`" + `config.kubernetes.io/function` + "`" + ` annotation.

To run the declared function use ` + "`" + `kpt fn run DIR/ --enable-exec` + "`" + ` on the
directory containing the example.

  apiVersion: example.com/v1beta1
  kind: ExampleKind
  metadata:
    name: function-input
    annotations:
      config.kubernetes.io/function: |
        exec:
          path: /path/to/executable

Note: if the ` + "`" + `--enable-exec` + "`" + ` flag is not provided, ` + "`" + `kpt fn run DIR/` + "`" + ` will
ignore the exec function and exit 0.

## Next Steps

- Explore other ways to run functions from the [Functions Developer Guide].
- Find out how to structure a pipeline of functions from the
  [functions concepts] page.
- Consult the [fn command reference].
`
View Source
var FunctionsGuide = `
## Functions Developer Guide

Config functions are conceptually similar to Kubernetes _controllers_ and
_validating webhooks_ -- they are programs which read resources as input, then
write resources as output (creating, modifying, deleting, or validating
resources).

Unlike controllers and validating webhooks, config functions can be run outside
of the Kubernetes control plane. This allows them to run in more contexts or
embedded in other systems. For example, functions could be:

- manually run locally
- automatically run locally as part of _make_, _mvn_, _go generate_, etc
- automatically run in CICD systems
- run by controllers as reconcile implementations

{{< svg src="images/fn" >}}

{{% pageinfo color="primary" %}}
Unlikely pure-templating and DSL approaches, functions must be able to both
_read_ and _write_ resources, and specifically should be able to read resources
they have previously written -- updating the inputs rather generating new
resources.

This mirrors the level-triggered controller architecture used in the Kubernetes
control plane. A function reconciles the desired state of the resource
configuration to match the declared state specified by the functionConfig.

Functions that implement abstractions should update resources they have
generated in the past by reading them from the input.
{{% /pageinfo %}}

The following function runtimes are available in kpt:

| Runtime      | Read Resources From | Write Resources To  | Write Error Messages To | Validation Failure | Maturity |
| ------------ | ------------------- | ------------------- | ----------------------- | ------------------ | -------- |
| [Containers] | STDIN               | STDOUT              | STDERR                  | Exit Code          | Beta     |
| [Exec]       | STDIN               | STDOUT              | STDERR                  | Exit Code          | Alpha    |
| [Starlark]   | ` + "`" + `ctx.resource_list` + "`" + ` | ` + "`" + `ctx.resource_list` + "`" + ` | ` + "`" + `log` + "`" + `                   | Exit Code          | Alpha    |

Additionally, the following libraries are available to create config functions:

| Library    | Link        |
| ---------- | ----------- |
| Golang     | [Go Fn Lib] |
| Typescript | [TS SDK]    |

## Input / Output

Functions read a ` + "`" + `ResourceList` + "`" + `, modify it, and write it back out. The
` + "`" + `ResourceList` + "`" + ` contains:

- (input+output) a list of resource ` + "`" + `items` + "`" + `
- (input) configuration for the function
- (output) validation results

### ResourceList.items

Items are resources read from some source -- such as a package directory --
using a source function -- such as [` + "`" + `kpt fn source` + "`" + `] or [` + "`" + `helm-template` + "`" + `].

After a function adds, deletes or modifies items, the items will be written to
a sink directory using a sink function -- such as [` + "`" + `kpt fn sink` + "`" + `]. In most
cases the sink directory will be the same as the source directory.

  kind: ResourceList
  items:
  - apiVersion: apps/v1
    kind: Deployment
    spec:
    ...
  - apiVersion: v1
    kind: Service
    spec:
    ...

### ResourceList.functionConfig

Functions may optionally be configured using the ` + "`" + `ResourceList.functionConfig` + "`" + `
field. ` + "`" + `functionConfig` + "`" + ` is analogous to a Deployment, and ` + "`" + `items` + "`" + ` is analogous
to the set of all resources in the Deployment controller in-memory cache (e.g.
all the resources in the cluster) -- this includes the ReplicaSets created,
updated and deleted for that Deployment.

  kind: ResourceList
  functionConfig:
    apiVersion: example.com/v1alpha1
    kind: Foo
    spec:
      foo: bar
      ...
  items:
    ...

{{% pageinfo color="primary" %}}
Some functions introduce a new resource type bespoke to the function instead of
using a ConfigMap as the functionConfig kind.
{{% /pageinfo %}}

### ResourceList.results

Functions may define validation results through the ` + "`" + `results` + "`" + ` field. When
functions are run using the ` + "`" + `--results-dir` + "`" + `, each function's results field will
be written to a file under the specified directory.

  kind: ResourceList
  functionConfig:
    apiVersion: example.com/v1alpha1
    kind: Foo
    spec:
      foo: bar
      ...
  results:
  - name: "kubeval"
    items:
    - severity: error # one of ["error", "warn", "info"] -- error code should be non-0 if there are 1 or more errors
      tags: # arbitrary metadata about the result
        error-type: "field"
      message: "Value exceeds the namespace quota, reduce the value to make the pod schedulable"
      resourceRef: # key to lookup the resource
        apiVersion: apps/v1
        kind: Deployment
        name: foo
        namespace: bar
      file:
        # optional if present as annotation
        path: deploy.yaml # read from annotation if present
        # optional if present as annotation
        index: 0 # read from annotation if present
      field:
        path: "spec.template.spec.containers[3].resources.limits.cpu"
        currentValue: "200" # number | string | boolean
        suggestedValue: "2" # number | string | boolean
    - severity: warn
      ...
  - name: "something else"
    items:
    - severity: info
       ...

## Next Steps

- Learn how to [run functions].
- Find out how to structure a pipeline of functions from the
  [functions concepts] page.
- Consult the [fn command reference].
`
View Source
var GolangGuide = `
Function developers can write exec and container functions in Golang using the
following libraries:

| Library                                    | Purpose                |
| ------------------------------------------ | ---------------------- |
| [sigs.k8s.io/kustomize/kyaml/fn/framework] | Setup function command |
| [sigs.k8s.io/kustomize/kyaml/yaml]         | Modify resources       |

Develop using the two examples of writing functions in Go or consult the
kyaml libraries' reference below.

## Hello World Go Function

### Create the go module

  go mod init github.com/user/repo
  go get sigs.k8s.io/kustomize/kyaml

### Create the ` + "`" + `main.go` + "`" + `

  // main.go
  package main
  
  import (
   "os"
  
   "sigs.k8s.io/kustomize/kyaml/fn/framework"
   "sigs.k8s.io/kustomize/kyaml/yaml"
  )
  
  var value string
  
  func main() {
      resourceList := &framework.ResourceList{}
   cmd := framework.Command(resourceList, func() error {
          // cmd.Execute() will parse the ResourceList.functionConfig into
          // cmd.Flags from the ResourceList.functionConfig.data field.
    for i := range resourceList.Items {
              // modify the resources using the kyaml/yaml library:
              // https://pkg.go.dev/sigs.k8s.io/kustomize/kyaml/yaml
     if err := resourceList.Items[i].PipeE(yaml.SetAnnotation("value", value)); err != nil {
      return err
     }
    }
    return nil
   })
   cmd.Flags().StringVar(&value, "value", "", "flag value")
   if err := cmd.Execute(); err != nil {
    os.Exit(1)
   }
  }

### Build and test the function

Build the go binary:

  go build -o my-fn .

Test it by running imperatively as an executable function:

  # run the my-fn function against the configuration in PACKAGE_DIR/
  kpt fn run PACKAGE_DIR/ --enable-exec --exec-path ./my-fn -- value=foo

Or declaratively as an executable function:

  # PACKAGE_DIR/example.yaml
  apiVersion: example.com/v1alpha1
  kind: ConfigMap
  metadata:
    name: foo
    annotations:
      config.kubernetes.io/function: |
        exec:
          path: /path/to/my-fn
  data:
    value: foo

  kpt fn run PACKAGE_DIR/ --enable-exec

### Publish the function

Build the function into a container image:

  # optional: generate a Dockerfile to contain the function
  go run ./main.go gen ./

  # build the function into an image
  docker build . -t gcr.io/project/fn-name:tag
  # optional: push the image to a container registry
  docker push gcr.io/project/fn-name:tag

Run the function imperatively as a container function:

  kpt fn run PACKAGE_DIR/ --image gcr.io/project/fn-name:tag -- value=foo

Or run declaratively as a container function:

  # PACKAGE_DIR/example.yaml
  apiVersion: example.com/v1alpha1
  kind: ConfigMap
  metadata:
    name: foo
    annotations:
      config.kubernetes.io/function: |
        container:
          image: gcr.io/project/fn-name:tag
  data:
    value: foo

  kpt fn run PACKAGE_DIR/

## Advanced Go Function

Functions may alternatively be written using a struct for parsing the
functionConfig rather than flags. The example shown below explicitly
implements what the preceding example implements implicitly.

  package main
  
  import (
   "os"
  
   "sigs.k8s.io/kustomize/kyaml/fn/framework"
   "sigs.k8s.io/kustomize/kyaml/yaml"
  )
  
  func main() {
   type Data struct {
          Value string ` + "`" + `yaml:"value,omitempty"` + "`" + `
   }
   type Example struct {
          // Data contains the function configuration (e.g. client-side CRD).
          // Using "data" as the field name to contain key-value pairs enables
          // the function to be invoked imperatively via
          // ` + "`" + `kpt fn run DIR/ --image img:tag -- key=value` + "`" + ` and the
          // key=value arguments will be parsed into the functionConfig.data
          // field.
          // If the function does not need to be invoked imperatively, other
          // field names may be used.
          Data Data ` + "`" + `yaml:"data,omitempty"` + "`" + `
   }
   functionConfig := &Example{}
      resourceList := &framework.ResourceList{FunctionConfig: functionConfig}
  
   cmd := framework.Command(resourceList, func() error {
    for i := range resourceList.Items {
              // use the kyaml libraries to modify each resource by applying
              // transformations
     err := resourceList.Items[i].PipeE(
                  yaml.SetAnnotation("value", functionConfig.Data.Value),
              )
              if err != nil {
      return nil, err
     }
    }
    return items, nil
   })
  
   if err := cmd.Execute(); err != nil {
    os.Exit(1)
   }
  }

Note: functionConfig need not read from the ` + "`" + `data` + "`" + ` field if it is not going to
be run imperatively with
` + "`" + `kpt fn run DIR/ --image gcr.io/some/image -- foo=bar` + "`" + ` or
` + "`" + `kpt fn run DIR/ --exec-path /some/bin --enable-exec -- foo=bar` + "`" + `. This is more
appropriate for functions implementing abstractions (e.g. client-side CRD
equivalents).

  ...
   type NestedValue struct {
    Value string ` + "`" + `yaml:"value,omitempty"` + "`" + `
   }
   type Spec struct {
          NestedValue string ` + "`" + `yaml:"nestedValue,omitempty"` + "`" + `
          MapValues map[string]string  ` + "`" + `yaml:"mapValues,omitempty"` + "`" + `
          ListItems []string  ` + "`" + `yaml:"listItems,omitempty"` + "`" + `
   }
   type Example struct {
          Spec Spec ` + "`" + `yaml:"spec,omitempty"` + "`" + `
   }
   functionConfig := &Example{}
  ...

  # PACKAGE_DIR/example.yaml
  apiVersion: example.com/v1alpha1
  kind: Example
  metadata:
    name: foo
    annotations:
      config.kubernetes.io/function: |
        exec:
          path: /path/to/my-fn
  spec:
    nestedValue:
      value: something
    mapValues:
      key: value
    listItems:
      - a
      - b

## kyaml Libraries Reference

Functions written in go should use the [sigs.k8s.io/kustomize/kyaml] libraries
for modifying resource configuration.

The [sigs.k8s.io/kustomize/kyaml/yaml] library offers utilities for reading
and modifying yaml configuration, while retaining comments and structure.

To use the kyaml/yaml library, become familiar with:

- The ` + "`" + `*yaml.RNode` + "`" + ` type, which represents a configuration object or field
  - [RNode link]
- The ` + "`" + `Pipe` + "`" + ` and ` + "`" + `PipeE` + "`" + ` functions, which apply a series of pipelined
  operations to the ` + "`" + `*RNode` + "`" + `.
  - [Pipe link]

### Workflow

To modify a ` + "`" + `*yaml.RNode` + "`" + ` call PipeE() on the ` + "`" + `*RNode` + "`" + `, passing in the
operations to be performed.

  // Set the spec.replicas field to 3 if it exists
  var node *yaml.RNode
  ...
  err := node.PipeE(yaml.Lookup("spec", "replicas"), yaml.FieldSetter{StringValue: "3"})

  // Set the spec.replicas field to 3, creating it if it doesn't exist
  var node *yaml.RNode
  ...
  // pass in the type of the node to create if it doesn't exist
  // (e.g. Sequence, Map, Scalar)
  err := node.PipeE(yaml.LookupCreate(yaml.ScalarNode, "spec", "replicas"), yaml.FieldSetter{StringValue: "3"})

To read a value from a \*yaml.RNode call Pipe() on the RNode, passing in the
operations to lookup a field.

  // Read the spec.replicas field
  var node *yaml.RNode
  ...
  replicas, err := node.Pipe(yaml.Lookup("spec", "replicas"))

{{% pageinfo color="info" %}}
Operations are any types implementing the ` + "`" + `yaml.Filter` + "`" + ` interface, so it is
simple to define custom operations and provide them to ` + "`" + `Pipe` + "`" + `, combining them
with the built-in operations.
{{% /pageinfo %}}

### Visiting Fields and Elements

Maps (i.e. Objects) and Sequences (i.e. Lists) support functions for visiting
their fields and elements.

  // Visit each of the elements in a Sequence (i.e. a List)
  err := node.VisitElements(func(elem *yaml.RNode) error {
      // do something with each element in the list
      return nil
  })

  // Visit each of the fields in a Map (i.e. an Object)
  err := node.VisitFields(func(n *yaml.MapNode) error {
      // do something with each field in the map / object
      return nil
  })

### Validation Results

Go functions can implement high fidelity validation results by setting a
` + "`" + `framework.Result` + "`" + ` on the ` + "`" + `ResourceList` + "`" + `.

If run using ` + "`" + `kpt fn run --results-dir SOME_DIR/` + "`" + `, the result will be written
to a file in the specified directory.

If the result is returned and contains an item with severity of
` + "`" + `framework.Error` + "`" + `, the function will exit non-0. Otherwise it will exit 0.

  cmd := framework.Command(resourceList, func() error {
      ...
      if ... {
          // return validation results to be written under the results dir
       resourceList.Result = framework.Result{...}
  
          // return the results as an error if desireds
          return resourceList.Result
      }
      ...
  })
  

## Next Steps

- Learn how to [run functions].
- Consult the [fn command reference].
- Find out how to structure a pipeline of functions from the
  [functions concepts] page.
`
View Source
var InitGuide = `
A kpt package is published as a git subdirectory containing configuration
files (YAML). Publishers of kpt packages can create or generate YAML files
however they like using the tool of their choice.

Publishing a package is done by pushing the git directory
(and optionally [tagging] it with a version).

{{% pageinfo color="primary" %}}
Multiple packages may exist in a single repo under separate subdirectories.

Packages may be nested -- both parent (composite) and child
(component) directories may be fetched as a kpt package.

A package is versioned by tagging the git repo as one of:

- ` + "`" + `package-subdirectory/package-version` + "`" + ` (directory scoped versioning)
- ` + "`" + `package-version` + "`" + ` (repo scoped versioning)

So package example that exists in the example folder of the repo, can
be individually versioned (as version v1.0.2) by creating the tag ` + "`" + `example/v1.0.2` + "`" + `.

{{% /pageinfo %}}

{{< svg src="images/producer-guide" >}}

## Steps

1. [Create a git repo](#create-a-git-repo)
2. [Create the package contents](#create-the-package)
3. [Create configuration](#create-configuration)
4. [Publish package to git](#publish-package-to-git)
5. [Fetch the released package](#fetch-the-released-package)

## Create a git repo

  git clone REPO_URL # or create a new repo with ` + "`" + `git init` + "`" + `
  cd REPO_NAME

## Create the package

  mkdir nginx

Recommended: initialize the package with metadata

  kpt pkg init nginx --tag kpt.dev/app=nginx --description "kpt nginx package"

## Create configuration

  curl https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/controllers/nginx-deployment.yaml --output nginx/nginx-deployment.yaml

## Publish package to git

  git add .
  git commit -m "Add nginx package"

Recommended: tag the commit as a release

  # tag as DIR/VERSION for per-directory versioning
  git tag nginx/v0.1.0
  git push nginx/v0.1.0

## Fetch the released package

  kpt pkg get https://<REPO>/nginx@v0.1.0 nginx
`
View Source
var PackagesGuide = `
{{% pageinfo color="warning" %}}

### Notice: Under Development

{{% /pageinfo %}}

*Reusable, customizable components can be built and shared as packages.*

## Overview

Packages are a **pattern for developing reusable, customizable
configuration**. Packages are typically published and consumed by
different teams.

{{% pageinfo color="primary" %}}
Because packages can be updated to new versions, consumers
can pull in changes to a package after fetching it.
{{% /pageinfo %}}

### Example use cases for packages

- **Languages**: Java / Node / Ruby / Python / Golang application
- **Frameworks**: Spring, Express, Rails, Django
- **Platforms**: Kubeflow, Spark
- **Applications / Stacks**:
  - Rails Backend + Node Frontend + Prometheus
  - Spring Cloud Microservices (discovery-server, config-server, api-gateway,
    admin-server, hystrix, various backends)
- **Infrastructure Stacks**: CloudSQL + Pubsub + GKE

{{< svg src="images/package" >}}

  # Optional: copy the mysql-kustomize package to follow along
  kpt pkg get https://github.com/GoogleContainerTools/kpt.git/package-examples/mysql-kustomize mysql

## Factor / denormalize the configuration data

Structuring packages into separate publisher and consumer focused pieces
provides a clean UX for consumers to modifys the package.

Example: provide separate directories with pieces consumers are expected to
edit (replicas) vs publisher implementation (health check command).

As a package publisher, it is important to think about **where and how you
want to promote customization.**

We will use [kustomize] to structure the package:

1. **Factoring out a common field value**
   - Example: ` + "`" + `namespace` + "`" + `, ` + "`" + `commonLabels` + "`" + `, ` + "`" + `commonAnnotations` + "`" + `
2. **Factoring a single resource into multiple files**
   - Example: ` + "`" + `resources` + "`" + ` + ` + "`" + `patches` + "`" + `

{{% pageinfo color="info" %}}
Remote kustomize bases may be used to reference the publisher focused pieces
directly from a git repository rather than including them in the package.

One disadvantage of this approach is that it creates a dependency on the
remote package being accessible in order to push -- if you can't fetch the
remote package, then you can't push changes.
{{% /pageinfo %}}

Example package structure:

  $ tree mysql/
  mysql/
  ├── Kptfile
  ├── README.md
  ├── instance
  │   ├── kustomization.yaml
  │   ├── service.yaml
  │   └── statefulset.yaml
  └── upstream
      ├── kustomization.yaml
      ├── service.yaml
      └── statefulset.yaml

The ` + "`" + `upstream` + "`" + ` directory acts as a kustomize base to the ` + "`" + `instance` + "`" + ` directory.
Upstream contains things most **consumers are unlikely to modify** --
e.g. the image (for off the shelf software), health check endpoints, etc.

The ` + "`" + `instance` + "`" + ` directory contains patches with fields populated for things
most **consumers are expected to modify** -- e.g. namespace, cpu, memory,
user, password, etc.

{{% pageinfo color="warning" %}}
While the package is structured into publisher and consumer focused pieces,
it is still possible for the package consumer to modify (via direct edits)
or override (via patches) any part of the package.

**Factoring is for UX, not for enforcement of specific configuration values.**
{{% /pageinfo %}}

## Commands, Args and Environment Variables

How do you configure applications in a way that can be extended or overridden --
how can consumers of a package specify new args, flags, environment variables
or configuration files and merge those with those defined by the package
publisher?

### Notes

- Commands and Args are non-associative arrays so it is not possible to
  target specific elements -- any changes replace the entire list of elements.
- Commands and Args are separate fields that are concatenated
- Commands and Args can use values from environment variables
- Environment variables are associative arrays, so it is possible to target
  specific elements within the list to be overridden or added.
- Environment variables can be pulled from ConfigMaps and Secrets
- Kustomize merges ConfigMaps and Secrets per-key (deep merges of the
  values is not supported).
- ConfigMaps and Secrets can be read from apps via environment variables or
  volumes.

Flags and arguments may be factored into publisher and consumer focused pieces
by **specifying the ` + "`" + `command` + "`" + ` in the ` + "`" + `upstream` + "`" + ` base dir and the ` + "`" + `args` + "`" + ` in the
` + "`" + `instance` + "`" + ` dir**.  This allows consumers to set and add flags using ` + "`" + `args` + "`" + `
without erasing those defined by the publisher in the ` + "`" + `command` + "`" + `.

When **specifying values for arguments or flag values, it is best to use an
environment variable read from a generated ConfigMap.**  This enables overriding
the value using kustomize's generators.

Example: Enable setting ` + "`" + `--skip-grant-tables` + "`" + ` as a flag on mysql.

*` + "`" + `# {"$ref": ...` + "`" + ` comments are setter references, defined in the next section.*

  # mysql/instance/statefulset.yaml
  # Wire ConfigMap value from kustomization.yaml to
  # an environment variable used by an arg
  apiVersion: apps/v1
  kind: StatefulSet
  ...
  spec:
    template:
      metadata:
        labels:
          app: release-name-mysql
      spec:
        containers:
        - name: mysql
          ...
          args:
          - --skip-grant-tables=$(SKIP_GRANT_TABLES)
          ...
          env:
          - name: SKIP_GRANT_TABLES
            valueFrom:
              configMapKeyRef:
                name: mysql
                key: skip-grant-tables

  # mysql/instance/kustomization.yaml
  # Changing the literal changes the StatefulSet behavior
  apiVersion: kustomize.config.k8s.io/v1beta1
  kind: Kustomization
  configMapGenerator:
  - name: mysql
    behavior: merge
    literals:
    # for bootstrapping the root table grants -- set to false after bootstrapped
    - "skip-grant-tables=true" # {"$kpt-set":"skip-grant-tables"}

### Generating ConfigMaps and Secrets

Kustomize supports generating ConfigMaps and Secrets from the
kustomization.yaml.

- Generated objects have a suffix applied so that the name is unique for
  the data.  This ensures a rollout of Deployments and StatefulSets occurs.
- Generated object may have their values overridden by downstream consumers.

Example Upstream:

  # mysql/upstream
  apiVersion: kustomize.config.k8s.io/v1beta1
  kind: Kustomization
  configMapGenerator:
  - name: mysql
    literals:
      - skip-grant-tables=true

Example Instance:

  # mysql/instance
  apiVersion: kustomize.config.k8s.io/v1beta1
  kind: Kustomization
  configMapGenerator:
  - name: mysql
    behavior: merge
    literals:
    - "skip-grant-tables=true" # {"$kpt-set":"skip-grant-tables"}
    - "mysql-user=" # {"$kpt-set":"mysql-user"}
    - "mysql-database=" # {"$kpt-set":"mysql-database"}

## Setters and Substitutions

It may be desirable to provide user friendly commands for customizing the
package rather than exclusively through text editors and sed:

- Setting a value in several different patches at once
- Setting common or required values -- e.g. the image name for a Java app
  package
- Setting the image tag to match the digest of an image that was just build.
- Setting a value from the environment when the package is fetched the first
  time -- e.g. GCP project.

Setters and substitutions are a way to define user and automation friendly
commands for performing structured edits of a configuration.

Combined with the preceding techniques, setters or substitutions can be used
to modify generated ConfigMaps and patches in the ` + "`" + `instance` + "`" + ` dir.

See the [setter] and [substitution] guides for details.

  # mysql/instance/kustomization.yaml
  apiVersion: kustomize.config.k8s.io/v1beta1
  kind: Kustomization
  #
  # namespace is the namespace the mysql instance is run in
  namespace: "" # {"$kpt-set":"namespace"}
  configMapGenerator:
  - name: mysql
    behavior: merge
    literals:
    # for bootstrapping the root table grants -- set to false after bootstrapped
    - "skip-grant-tables=true" # {"$kpt-set":"skip-grant-tables"}
    - "mysql-user=" # {"$kpt-set":"mysql-user"}
    - "mysql-database=" # {"$kpt-set":"mysql-database"}
  ...

  # mysql/instance/statefulset.yaml
  apiVersion: apps/v1
  kind: StatefulSet
  metadata:
    name: mysql
  spec:
    template:
      spec:
        containers:
        - name: mysql
  ...
          ports:
          - name: mysql
            containerPort: 3306 # {"$kpt-set":"port"}
          resources:
            requests:
              cpu: 100m # {"$kpt-set":"cpu"}
              memory: 256Mi # {"$kpt-set":"memory"}

  # mysql/instance/service.yaml
  apiVersion: v1
  kind: Service
  ...
  spec:
    ports:
    - name: mysql
      port: 3306 # {"$kpt-set":"port"}
      targetPort: mysql

## Updates

Individual directories may have their own package versions by prefixing the
version with the directory path -- e.g.
` + "`" + `package-examples/mysql-kustomize/v0.1.0` + "`" + `.

When publishing a new version of a package, publishers should think about how
their changes will be merged into existing packages.

Changing values in the instance package is not recommended, but adding them
may be ok -- changes to fields will overwrite user changes to those same
fields, whereas adds will only conflict if the user added the same field.
`
View Source
var ProducerGuide = `
{{< svg src="images/producer-guide" >}}`
View Source
var QuickstartGuide = `
## Developer Quickstart

This quickstart will get you started developing a config function with the
TypeScript SDK, using an existing kpt-functions package. Config functions are
any functions which implement the ` + "`" + `KptFunc` + "`" + ` interface documented in the
[TS SDK API].

### Prerequisites

#### System Requirements

Currently supported platforms: amd64 Linux/Mac

#### Setting Up Your Local Environment

- Install [node][download-node]
- Install [docker][install-docker]
- Install [kpt][download-kpt] and add it to your $PATH

### Explore the Demo Functions Package

1. Get the ` + "`" + `demo-functions` + "`" + ` package:

   ` + "`" + `` + "`" + `` + "`" + `sh
   git clone --depth 1 https://github.com/GoogleContainerTools/kpt-functions-sdk.git
   ` + "`" + `` + "`" + `` + "`" + `

   All subsequent commands are run from the ` + "`" + `demo-functions` + "`" + ` directory:

   ` + "`" + `` + "`" + `` + "`" + `sh
   cd kpt-functions-sdk/ts/demo-functions
   ` + "`" + `` + "`" + `` + "`" + `

1. Install all dependencies:

   ` + "`" + `` + "`" + `` + "`" + `sh
   npm install
   ` + "`" + `` + "`" + `` + "`" + `

1. Run the following in a separate terminal to continuously build your
   function as you make changes:

   ` + "`" + `` + "`" + `` + "`" + `sh
   npm run watch
   ` + "`" + `` + "`" + `` + "`" + `

1. Explore the [` + "`" + `label_namespace` + "`" + `][label-namespace] transformer function. This
   function takes a given ` + "`" + `label_name` + "`" + ` and ` + "`" + `label_value` + "`" + ` to add the
   appropriate label to ` + "`" + `Namespace` + "`" + ` objects using the SDK's ` + "`" + `addLabel` + "`" + `
   function.

  ` + "`" + `` + "`" + `` + "`" + `typescript
  import { addLabel, Configs } from 'kpt-functions';
  import { isNamespace } from './gen/io.k8s.api.core.v1';

  export const LABEL_NAME = 'label_name';
  export const LABEL_VALUE = 'label_value';

  export async function labelNamespace(configs: Configs) {
    const labelName = configs.getFunctionConfigValueOrThrow(LABEL_NAME);
    const labelValue = configs.getFunctionConfigValueOrThrow(LABEL_VALUE);
    configs.get(isNamespace).forEach(n => addLabel(n, labelName, labelValue));
  }
  ` + "`" + `` + "`" + `` + "`" + `

1. Run the ` + "`" + `label_namespace` + "`" + ` function on the ` + "`" + `example-configs` + "`" + ` directory:

   ` + "`" + `` + "`" + `` + "`" + `sh
   export CONFIGS=../../example-configs

   kpt fn source $CONFIGS |
     node dist/label_namespace_run.js -d label_name=color -d label_value=orange |
     kpt fn sink $CONFIGS
   ` + "`" + `` + "`" + `` + "`" + `

   As the name suggests, this function added the given label to all
   ` + "`" + `Namespace` + "`" + ` objects in the ` + "`" + `example-configs` + "`" + ` directory:

   ` + "`" + `` + "`" + `` + "`" + `sh
   git diff $CONFIGS
   ` + "`" + `` + "`" + `` + "`" + `

1. Try modifying the function in ` + "`" + `src/label_namespace.ts` + "`" + ` to perform other
   operations and rerun the function on ` + "`" + `example-configs` + "`" + ` to see the changes.

1. Explore validation functions like [validate-rolebinding]. Instead of
   transforming configuration, this function searches RoleBindings and returns
   a results field containing details about invalid subject names.

  ` + "`" + `` + "`" + `` + "`" + `typescript
  import { Configs, kubernetesObjectResult } from 'kpt-functions';
  import { isRoleBinding } from './gen/io.k8s.api.rbac.v1';

  const SUBJECT_NAME = 'subject_name';

  export async function validateRolebinding(configs: Configs) {
    // Get the subject name parameter.
    const subjectName = configs.getFunctionConfigValueOrThrow(SUBJECT_NAME);

    // Iterate over all RoleBinding objects in the input
    // Filter those that have a subject we're looking for.
    const results = configs
      .get(isRoleBinding)
      .filter(
        (rb) =>
          rb && rb.subjects && rb.subjects.find((s) => s.name === subjectName)
      )
      .map((rb) =>
        kubernetesObjectResult(` + "`" + `Found banned subject '${subjectName}'` + "`" + `, rb)
      );

    configs.addResults(...results);
  }
  ` + "`" + `` + "`" + `` + "`" + `

1. Run ` + "`" + `validate-rolebinding` + "`" + ` on ` + "`" + `example-configs` + "`" + `.

   ` + "`" + `` + "`" + `` + "`" + `sh
   kpt fn source $CONFIGS |
     node dist/validate_rolebinding_run.js -d subject_name=alice@foo-corp.com |
     kpt fn sink $CONFIGS
   git diff $CONFIGS
   ` + "`" + `` + "`" + `` + "`" + `

1. Explore generator functions like [expand-team-cr]. This function generates
   a per-environment Namespace and RoleBinding object for each custom resource
   (CR) of type Team.

  ` + "`" + `` + "`" + `` + "`" + `typescript
  import { Configs } from 'kpt-functions';
  import { isTeam, Team } from './gen/dev.cft.anthos.v1alpha1';
  import { Namespace } from './gen/io.k8s.api.core.v1';
  import { RoleBinding, Subject } from './gen/io.k8s.api.rbac.v1';

  const ENVIRONMENTS = ['dev', 'prod'];

  export async function expandTeamCr(configs: Configs) {
    // For each 'Team' custom resource in the input:
    // 1. Generate a per-enviroment Namespace.
    // 2. Generate RoleBindings in each Namespace.
    configs.get(isTeam).forEach((team) => {
      const name = team.metadata.name;

      ENVIRONMENTS.forEach((suffix) => {
        const ns = ` + "`" + `${name}-${suffix}` + "`" + `;
        configs.insert(Namespace.named(ns));
        configs.insert(...createRoleBindings(team, ns));
      });
    });
  }

  function createRoleBindings(team: Team, namespace: string): RoleBinding[] {
    return (team.spec.roles || []).map((item) => {
      return new RoleBinding({
        metadata: {
          name: item.role,
          namespace,
        },
        subjects: roleSubjects(item),
        roleRef: {
          kind: 'ClusterRole',
          name: item.role,
          apiGroup: 'rbac.authorization.k8s.io',
        },
      });
    });
  }

  function roleSubjects(item: Team.Spec.Item): Subject[] {
    const userSubjects: Subject[] = (item.users || []).map(
      (user) =>
        new Subject({
          kind: 'User',
          name: user,
        })
    );
    const groupSubjects: Subject[] = (item.groups || []).map(
      (group) =>
        new Subject({
          kind: 'Group',
          name: group,
        })
    );
    return userSubjects.concat(groupSubjects);
  }
  ` + "`" + `` + "`" + `` + "`" + `

1. Run ` + "`" + `expand-team-cr` + "`" + ` on ` + "`" + `example-configs` + "`" + `.

   ` + "`" + `` + "`" + `` + "`" + `sh
   kpt fn source $CONFIGS |
     node dist/expand_team_cr_run.js |
     kpt fn sink $CONFIGS
   git diff $CONFIGS
   ` + "`" + `` + "`" + `` + "`" + `

## Next Steps

- Take a look at these [demo functions] to better understand
  how to use the typescript SDK.
- Read the complete [Typescript Developer Guide].
- Learn how to [run functions].
`
View Source
var SettersGuide = `

{{% pageinfo color="primary" %}}
Creating a setter requires that the package has a Kptfile. If one does
not exist for the package, run ` + "`" + `kpt pkg init DIR/` + "`" + ` to create one.
{{% /pageinfo %}}


## Setters explained

Following is a short explanation of the command that will be demonstrated
in this guide.

### Data model

- Fields reference setters through OpenAPI definitions specified as
  line comments -- e.g. ` + "`" + `# { "$kpt-set": "replicas-setter" }` + "`" + `
- OpenAPI definitions are provided through the Kptfile

### Command control flow

1. Read the package Kptfile and resources.
2. Change the setter OpenAPI value in the Kptfile
3. Locate all fields which reference the setter and change their values.
4. Write both the modified Kptfile and resources back to the package.

{{< svg src="images/set-command" >}}

This guide walks you through an end-to-end example to create, invoke and delete setters.

## Steps

1. [Creating a Setter](#creating-a-setter)
2. [Targeting fields using the path](#targeting-fields-using-the-path)
3. [Invoking a Setter](#invoking-a-setter)
4. [Deleting a Setter](#deleting-a-setter)
5. [OpenAPI Validations](#openapi-validations)
6. [Required Setters](#required-setters)
7. [Setting Lists](#setting-lists)

#### Creating a Setter

Setters may be created either manually (by editing the Kptfile directly), or
programmatically (through the ` + "`" + `create-setter` + "`" + ` command). The ` + "`" + `create-setter` + "`" + `
command will:

1. create a new OpenAPI definition for a setter in the Kptfile
2. create references to the setter definition on the resource fields


  cat <<EOF >deployment.yaml
  # deployment.yaml -- original
  kind: Deployment
  metadata:
    name: foo
  spec:
    replicas: 3
  EOF


  # create or update a setter named "replicas"
  # match fields with the value "3"
  kpt cfg create-setter . replicas 3

  # Kptfile -- updated
  openAPI:
    definitions:
      io.k8s.cli.setters.replicas:
        x-k8s-cli:
          setter:
            name: "replicas"
            value: "3"

  # deployment.yaml -- updated
  kind: Deployment
  metadata:
    name: foo
  spec:
    replicas: 3 # {"$kpt-set":"replicas"}


#### Targeting fields using the path

The basic way to create a setter only matches fields based on the value. But
in some situations there might be several fields with the same value, but not all
of them should be targeted by the setter. In these situations, use the ` + "`" + `--field` + "`" + `
flag to provide either the name of the field, the full path to the field, or a
partial (suffix) path to the field. Only fields that match both the path and
the value will be targeted by the setter.

  # create a setter named "replicas" and but only target the field name replicas in the spec
  kpt cfg create-setter hello-world/ replicas 3 --field="spec.replicas"

  # deployment-foo.yaml
  kind: Deployment
  metadata:
    name: foo
    annotations:
      replicas: 3
  spec:
    replicas: 3 # {"$kpt-set":"replicas"}

The path is always just the names of the properties on the path to the field,
regardless whether the field is nested inside a sequence. Targeting specific
elements inside a sequence is not supported.

  # create a setter named "mountName" and only target the name of the volume mount
  kpt cfg create-setter hello-world/ mountName nginx --field="spec.containers.volumeMounts.name"

  # deployment-nginx.yaml
  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: nginx-deployment
  spec:
    containers:
      - name: nginx
        image: nginx
        volumeMounts:
          - name: nginx # {"$kpt-set":"mountName"}
            mountPath: /usr/share/nginx
          - name: temp
            mountPath: /tmp

#### Invoking a Setter

  kind: Deployment
  metadata:
    name: foo
  spec:
    replicas: 3 # {"$kpt-set":"replicas"}


  # set the replicas field to 5
  kpt cfg set . replicas 5

  # deployment.yaml -- updated
  kind: Deployment
  metadata:
    name: foo
  spec:
    replicas: 3 # {"$kpt-set":"replicas"}


#### Deleting a Setter

Setters may be deleted either manually (by editing the Kptfile directly), or
programmatically (through the ` + "`" + `delete-setter` + "`" + ` command). The ` + "`" + `delete-setter` + "`" + `
command will:

1. delete an OpenAPI definition for a setter in the Kptfile
2. remove references to the setter definition on the resource fields

  # Kptfile -- original
  openAPI:
    definitions:
      io.k8s.cli.setters.replicas:
        x-k8s-cli:
          setter:
            name: "replicas"
            value: "3"

  # deployment.yaml -- original
  kind: Deployment
  metadata:
    name: foo
  spec:
    replicas: 3 # {"$kpt-set":"replicas"}


  # delete a setter named "replicas"
  kpt cfg delete-setter . replicas

  # Kptfile -- updated
  openAPI:

  # deployment.yaml -- updated
  kind: Deployment
  metadata:
    name: foo
  spec:
    replicas: 3

#### OpenAPI Validations

Users can input any additional validation constraints during ` + "`" + `create-setter` + "`" + `
operation in the form of openAPI schema. Relevant openAPI specification
constraints can be provided in json file format. The ` + "`" + `set` + "`" + ` operation validates
the input value against provided schema during setter creation and throws an
error if the input value doesn't meet any of the constraints. This example walks
you through the steps to work with openAPI validations.


  cat <<EOF >schema.json
  {"maximum": 10, "type": "integer"}
  EOF
  
  # create setter with openAPI property constraints
  kpt cfg create-setter . replicas 5 --schema-path schema.json

The command creates setter with the following definition

  openAPI:
    definitions:
      io.k8s.cli.setters.replicas:
        maximum: 10
        type: integer
        x-k8s-cli:
          setter:
            name: replicas
            value: "5"

  # try to set value not adhering to the constraints
  kpt cfg set . replicas 11

  error: The input value doesn't validate against provided OpenAPI schema:
  validation failure list: replicas in body should be less than or equal to 10


  Example schema for integer validation
  
  {
    "maximum": 10,
    "type": "integer",
    "minimum": 3,
    "format": "int64",
    "multipleOf": 2
  }
  
  Example schema for string validation
  
  {
    "maxLength": 10,
    "type": "string",
    "minLength": 3,
    "pattern": "^[A-Za-z]+$",
    "enum": [
      "nginx",
      "ubuntu"
    ]
  }
  
  Example schema for array validation
  
  {
    "maxItems": 10,
    "type": "array",
    "minItems": 3,
    "uniqueItems": true,
    "items": {
      "type": "string",
      "maxLength": 4
    }
  }
  

Relevant resources for more information: [OpenAPI types]

#### Required setters

Package publisher can mark a setter as required to convey the consumer that the
setter value must be set before triggering live apply/preview operation
on the package. This example walks you through the steps to work with required setters.

  # create a setter named "replicas" and mark it as required
  kpt cfg create-setter . replicas 3 --required

  # deployment-foo.yaml
  kind: Deployment
  metadata:
    name: foo
  spec:
    replicas: 3 # {"$kpt-set":"replicas"}

  # Kptfile
  openAPI:
    definitions:
      io.k8s.cli.setters.replicas:
        x-k8s-cli:
          setter:
            name: "replicas"
            value: "3"
            required: true

  # if you live apply/preview without setting the value
  kpt live apply .
  
  error: setter replicas is required but not set, please set it and try again

  # set the replicas value
  kpt cfg set hello-world/ replicas 4
  
  kpt live apply hello-world/
  # Success

#### Setting Lists

It is possible to create setters for fields which are a list of strings/integers.
The setter type must be ` + "`" + `array` + "`" + `, and the reference must be on the list field.
The list setter will take variable args for its value rather than a single value.

**Note:** You should skip passing the value arg while creating array setters. ` + "`" + `field` + "`" + `
flag is required for array setters.


  cat <<EOF >example.yaml
  # example.yaml
  apiVersion: example.com/v1beta1
  kind: Example
  spec:
    list:
    - "a"
    - "b"
  EOF

  # Kptfile
  kind: Kptfile


  kpt cfg create-setter . list --type array --field spec.list

  # example.yaml
  apiVersion: example.com/v1beta1
  kind: Example
  spec:
    list: # {"$kpt-set":"list"}
      - "a"
      - "b"

  # Kptfile
  kind: Kptfile
  openAPI:
    definitions:
      io.k8s.cli.setters.list:
        type: array
        x-k8s-cli:
          setter:
            name: list
            listValues:
              - a
              - b



  kpt cfg set . list c d e

  # example.yaml
  apiVersion: example.com/v1beta1
  kind: Example
  spec:
    list: # {"$kpt-set":"list"}
      - "c"
      - "d"
      - "e"

  # Kptfile
  kind: Kptfile
  openAPI:
    definitions:
      io.k8s.cli.setters.list:
        type: array
        x-k8s-cli:
          setter:
            name: list
            listValues:
              - "c"
              - "d"
              - "e"

`
View Source
var StarlarkGuide = `
{{% pageinfo color="warning" %}}
The Starlark runtime is Alpha. It is disabled by default, and must be enabled
with the ` + "`" + `--enable-star` + "`" + ` flag.
{{% /pageinfo %}}

Functions may be written as [Starlark] scripts which modify a ResourceList
provided as a variable.

#### Imperative Run

Starlark functions can be run imperatively by providing the Starlark script as
a flag on ` + "`" + `kpt fn run` + "`" + `. Following is an example of a Starlark function which
adds a "foo" annotation to every resource in the package.

  # c.star
  # set the foo annotation on each resource
  def run(r, an):
    for resource in r:
      # mutate the resource
      resource["metadata"]["annotations"]["foo"] = an
  
  # get the value of the annotation to add
  an = ctx.resource_list["functionConfig"]["data"]["value"]
  
  run(ctx.resource_list["items"], an)

Run the Starlark function with:

  # run c.star as a function, generating a ConfigMap with value=bar as the
  # functionConfig
  kpt fn run . --enable-star --star-path c.star -- value=bar

Any resource under ` + "`" + `.` + "`" + ` will have the ` + "`" + `foo: bar` + "`" + ` annotation added.

#### Declarative Run

Starlark functions can also be run declaratively using the
` + "`" + `config.kubernetes.io/function` + "`" + ` annotation. This annotation indicates that the
resource is functionConfig that should be provided to a function.

Following is an example of a Starlark function which adds a "foo" annotation to
each resource in its package. The ExampleKind resource will be set as the
ResourceList.functionConfig.

  # example.yaml
  apiVersion: example.com/v1beta1
  kind: ExampleKind
  metadata:
    name: function-input
    annotations:
      config.kubernetes.io/function: |
        starlark: {path: c.star, name: example-name}
  data:
    value: "hello world"

Example Starlark function to which will add an annotation to each resource
scoped to ` + "`" + `example.yaml` + "`" + ` (those under the directory containing ` + "`" + `example.yaml` + "`" + `):

  # c.star
  # set the foo annotation on each resource
  def run(r, an):
    for resource in r:
      resource["metadata"]["annotations"]["foo"] = an
  
  an = ctx.resource_list["functionConfig"]["data"]["value"]
  run(ctx.resource_list["items"], an)

Run them on the directory containing ` + "`" + `example.yaml` + "`" + ` using:

  kpt fn run DIR/ --enable-star

## Debugging Functions

It is possible to debug Starlark functions using ` + "`" + `print` + "`" + `

  # c.star
  print(ctx.resource_list["items"][0]["metadata"]["name"])

  kpt fn run . --enable-star --star-path c.star

> foo

## OpenAPI

The OpenAPI known to kpt is provided to the Starlark program through the
` + "`" + `ctx.open_api` + "`" + ` variable. This may contain metadata about the resources and
their types.

  #c.star
  print(ctx.open_api["definitions"]["io.k8s.api.apps.v1.Deployment"]["description"])

  kpt fn run . --enable-star --star-path c.star

> Deployment enables declarative updates for Pods and ReplicaSets.

## Retaining YAML Comments

While Starlark programs are unable to retain comments on resources, kpt will
attempt to retain comments by copying them from the function inputs to the
function outputs.

It is not possible at this time to add, modify or delete comments from
Starlark scripts.

## Next Steps

- Explore other ways to run functions from the [Functions Developer Guide].
- Find out how to structure a pipeline of functions from the
  [functions concepts] page.
- Consult the [fn command reference].
`
View Source
var SubpackagesGuide = `
{{% pageinfo color="warning" %}}

#### Notice: Subpackages support is available with kpt version v0.34.0+ for [cfg] commands only

{{% /pageinfo %}}

This guide walks you through an example to create, parameterize and publish a
kpt package with a [subpackage] in it.

## Steps

1. [Create the package](#create-the-package)
2. [Add setters and substitutions](#add-setters-and-substitutions)
3. [Publish the package](#publish-the-package)

## Create the package

Initialize a ` + "`" + `kpt` + "`" + ` package with a [subpackage] in its directory tree.

  mkdir wordpress
  kpt pkg init wordpress
  
  mkdir wordpress/mysql
  kpt pkg init wordpress/mysql

Download the ` + "`" + `Wordpress` + "`" + ` deployment configuration file.

  cd wordpress
  curl -LO https://k8s.io/examples/application/wordpress/wordpress-deployment.yaml

Download the ` + "`" + `MySQL` + "`" + ` deployment configuration file.

  cd mysql
  curl -LO https://k8s.io/examples/application/wordpress/mysql-deployment.yaml
  cd ../../

## Add setters and substitutions

### Add annotations

As a package publisher you might want to add [annotations] to kubernetes objects.
You can leverage ` + "`" + `--recurse-subpackages(-R)` + "`" + ` flag to create it recursively in both
` + "`" + `wordpress` + "`" + ` and ` + "`" + `mysql` + "`" + ` packages.

  kpt cfg annotate wordpress/ --kv teamname=YOURTEAM -R

Output:

  wordpress/
  added annotations in the package
  
  wordpress/mysql/
  added annotations in the package

Similarly add ` + "`" + `projectId` + "`" + ` annotation to both the packages.

  kpt cfg annotate wordpress/ --kv projectId=PROJECT_ID -R

Output:

  wordpress/
  added annotations in the package
  
  wordpress/mysql/
  added annotations in the package

### Create setters

Create [Setters] for the annotations values which you just added

  kpt cfg create-setter wordpress/ teamname YOURTEAM -R --required

Output:

  wordpress/
  created setter "teamname"
  
  wordpress/mysql/
  created setter "teamname"

Similarly create an [auto-setter] with name ` + "`" + `gcloud.core.project` + "`" + `.

  kpt cfg create-setter wordpress/ gcloud.core.project PROJECT_ID -R

Output:

  wordpress/
  created setter "gcloud.core.project"
  
  wordpress/mysql/
  created setter "gcloud.core.project"

### Create substitutions

Create [Substitutions] so that package consumers can substitute values,
using ` + "`" + `kpt cfg set` + "`" + `

  kpt cfg create-subst wordpress image-tag \
  --field-value wordpress:4.8-apache \
  --pattern \${image}:\${tag}-apache

Output:

  wordpress/
  unable to find setter with name image, creating new setter with value wordpress
  unable to find setter with name tag, creating new setter with value 4.8
  created substitution "image-tag"

  kpt cfg create-subst wordpress/mysql image-tag \
  --field-value mysql:5.6 \
  --pattern \${image}:\${tag}

Output:

  wordpress/mysql/
  unable to find setter with name image, creating new setter with value wordpress
  unable to find setter with name tag, creating new setter with value 4.8
  created substitution "image-tag"

### List and verify setters/substitutions

Use list-setters command to verify that the setters and substitutions are created as expected

  kpt cfg list-setters wordpress/ --include-subst

Output:

  wordpress/
           NAME             VALUE      SET BY   DESCRIPTION   COUNT   REQUIRED
    gcloud.core.project   PROJECT_ID                          3       No
    image                 wordpress                           1       No
    tag                   4.8                                 1       No
    teamname              YOURTEAM                            3       Yes
    SUBSTITUTION       PATTERN       REFERENCES
    image-tag      ${image}:${tag}   [image,tag]

## Publish the package

Now that as a package creator, you have created and parameterized a ` + "`" + `kpt` + "`" + ` package,
publish it so that package consumers can consume it.

Create a [git repo] in your profile with name ` + "`" + `wordpress` + "`" + `

  cd wordpress/
  git init; git add .; git commit -am "Publish package";
  git remote add origin <YOUR_GIT_REPO_LINK>
  git push origin master

## Next steps

Go through the [consumer guide] to consume the published package
`
View Source
var SubstitutionsGuide = `

Substitutions provide a solution for template-free substitution of field values
built on top of [setters].  They enable substituting values into part of a
field, including combining multiple setters into a single value.

Much like setters, substitutions are defined using OpenAPI.

Substitutions may be invoked to programmatically modify the configuration
using ` + "`" + `kpt cfg set` + "`" + ` to substitute values which are derived from the setter.

Substitutions are computed by substituting setter values into a pattern.
They are composed of 2 parts: a pattern and a list of values.

- The pattern is a string containing markers which will be replaced with
  1 or more setter values.
- The values are pairs of markers and setter references.  The *set* command
  retrieves the values from the referenced setters, and replaces the markers
  with the setter values.

{{% pageinfo color="primary" %}}
Creating a substitution requires that the package has a Kptfile.  If one does
not exist for the package, run ` + "`" + `kpt pkg init DIR/` + "`" + ` to create one.
{{% /pageinfo %}}

## Substitutions explained

Following is a short explanation of the command that will be demonstrated
in this guide.

### Data model

- Fields reference substitutions through OpenAPI definitions specified as
  line comments -- e.g. ` + "`" + `# { "$kpt-set": "substitution" }` + "`" + `
- OpenAPI definitions are provided through the Kptfile
- Substitution OpenAPI definitions contain patterns and values to compute
  the field value

### Command control flow

1. Read the package Kptfile and resources.
2. Change the setter OpenAPI value in the Kptfile
3. Locate all fields which reference the setter indirectly through a
   substitution.
4. Compute the new substitution value by substituting the setter values into
   the pattern.
5. Write both the modified Kptfile and resources back to the package.

{{< svg src="images/substitute-command" >}}

## Creating a Substitution

Substitution may be created either manually (by editing the Kptfile directly),
or programmatically (with ` + "`" + `create-subst` + "`" + `).  The ` + "`" + `create-subst` + "`" + ` command will:

1. Create a new OpenAPI definition for a substitution in the Kptfile
2. Create references to the substitution OpenAPI definition on the resource
   fields

### Example

  # deployment.yaml -- original
  kind: Deployment
  metadata:
    name: foo
  spec:
    template:
      spec:
        containers:
        - name: nginx
          image: nginx:1.7.9 # {"$kpt-set":"image-value"}

  # create an image substitution and a setter that populates it
  kpt cfg create-subst hello-world/ image-value --field-value nginx:1.7.9 \
    --pattern nginx:\${TAG_SETTER}

  # Kptfile -- updated
  openAPI:
    definitions:
      io.k8s.cli.setters.TAG_SETTER:
        x-k8s-cli:
          setter:
            name: TAG_SETTER
            value: 1.7.9
      io.k8s.cli.substitutions.image-value:
        x-k8s-cli:
          substitution:
            name: image-value
            pattern: nginx:${TAG_SETTER}
            values:
            - marker: ${TAG_SETTER}
              ref: '#/definitions/io.k8s.cli.setters.TAG_SETTER'

  # deployment.yaml -- updated
  kind: Deployment
  metadata:
    name: foo
  spec:
    template:
      spec:
        containers:
        - name: nginx
          image: nginx:1.7.9 # {"$kpt-set":"image-value"}

This substitution defines how the value for a field may be produced by
substituting the ` + "`" + `tag` + "`" + ` setter value into the pattern.

Any time the ` + "`" + `tag` + "`" + ` value is changed via the *set* command, then then
substitution value will be re-calculated for referencing fields.

## Creation semantics

By default create-subst will create referenced setters if they do not already
exist.  It will infer the current setter value from the pattern and value.

If setters already exist before running the create-subst command, then those
setters are used and left unmodified.

If a setter does not exist and create-subst cannot infer the setter value,
then it will throw and error, and the setter must be manually created.

## Invoking a Substitution

Substitutions are invoked by running ` + "`" + `kpt cfg set` + "`" + ` on a setter used by the
substitution.

  kpt cfg set hello-world/ TAG_SETTER 1.8.1

  # deployment.yaml -- updated
  kind: Deployment
  metadata:
    name: foo
  spec:
    template:
      spec:
        containers:
        - name: nginx
          image: nginx:1.8.1 # {"$kpt-set":"image-value"}

## Nested Substitutions

In addition to referring to setters, a substitution may also refer to another
substitution forming a tree structure. Upon invoking ` + "`" + `kpt cfg set` + "`" + ` on a setter,
the value will be set if a substitution is an ancestor/parent of the setter.

Here is the example of a simple setter and a substitution to start with

  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: nginx-deployment
    namespace: myspace # {"$kpt-set":"namespace-setter"}
  spec:
    replicas: 3
    template:
      spec:
        containers:
        - name: sidecar
          image: nginx:1.7.9 # {"$kpt-set":"image-subst"}
        - name: nginx
          image: myspace/nginx:1.7.9

  apiVersion: v1alpha1
  kind: Kptfile
  openAPI:
    definitions:
      io.k8s.cli.setters.namespace-setter:
        x-k8s-cli:
          setter:
            name: namespace-setter
            value: myspace
      io.k8s.cli.setters.image-setter:
        x-k8s-cli:
          setter:
            name: image-setter
            value: nginx
      io.k8s.cli.setters.tag-setter:
        x-k8s-cli:
          setter:
            name: tag-setter
            value: 1.7.9
      io.k8s.cli.substitutions.image-subst:
        x-k8s-cli:
          substitution:
            name: image-subst
            pattern: ${image-setter}:${tag-setter}
            values:
            - marker: ${image-setter}
              ref: '#/definitions/io.k8s.cli.setters.image-setter'
            - marker: ${tag-setter}
              ref: '#/definitions/io.k8s.cli.setters.tag-setter'

Now create a nested substitution for the value ` + "`" + `myspace/nginx:1.7.9` + "`" + ` which is
a combination of ` + "`" + `namespace-setter` + "`" + ` and ` + "`" + `image-subst` + "`" + `

  kpt cfg create-subst hello-world/ nested-subst --field-value myspace/nginx:1.7.9 \
    --pattern \${namespace-setter}/\${image-subst}

  # deployment.yaml -- updated
  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: nginx-deployment
    namespace: myspace # {"$kpt-set":"namespace-setter"}
  spec:
    replicas: 3
    template:
      spec:
        containers:
        - name: sidecar
          image: nginx:1.7.9 # {"$kpt-set":"image-subst"}
        - name: nginx
          image: myspace/nginx:1.7.9 # {"$kpt-set":"nested-subst"}

  # Kptfile -- updated
  apiVersion: v1alpha1
  kind: Kptfile
  openAPI:
    definitions:
      io.k8s.cli.setters.namespace-setter:
        x-k8s-cli:
          setter:
            name: namespace-setter
            value: myspace
      io.k8s.cli.setters.image-setter:
        x-k8s-cli:
          setter:
            name: image-setter
            value: nginx
      io.k8s.cli.setters.tag-setter:
        x-k8s-cli:
          setter:
            name: tag-setter
            value: 1.7.9
      io.k8s.cli.substitutions.image-subst:
        x-k8s-cli:
          substitution:
            name: image-subst
            pattern: ${image-setter}:${tag-setter}
            values:
            - marker: ${image-setter}
              ref: '#/definitions/io.k8s.cli.setters.image-setter'
            - marker: ${tag-setter}
              ref: '#/definitions/io.k8s.cli.setters.tag-setter'
      io.k8s.cli.substitutions.nested-subst:
        x-k8s-cli:
          substitution:
            name: nested-subst
            pattern: ${namespace-setter}/${image-subst}
            values:
            - marker: ${image-subst}
              ref: '#/definitions/io.k8s.cli.substitutions.image-subst'
            - marker: ${namespace-setter}
              ref: '#/definitions/io.k8s.cli.setters.namespace-setter'

  kpt cfg set hello-world/ namespace-setter otherspace

  # deployment.yaml -- updated
  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: nginx-deployment
    namespace: otherspace # {"$kpt-set":"namespace-setter"}
  spec:
    replicas: 3
    template:
      spec:
        containers:
        - name: sidecar
          image: nginx:1.7.9 # {"$kpt-set":"image-subst"}
        - name: nginx
          image: otherspace/nginx:1.7.9 # {"$kpt-set":"nested-subst"}

{{% pageinfo color="primary" %}}
When setting a field through a substitution, the names of the setters
are used *not* the name of the substitution.  The name of the substitution is
*only used in the configuration field references*.
{{% /pageinfo %}}
`
View Source
var TsGuide = `` /* 1444-byte string literal not displayed */
View Source
var VariantGuide = `
{{% pageinfo color="warning" %}}

# Notice: Under Development

{{% /pageinfo %}}`

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

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