producer

package
v0.34.0 Latest Latest
Warning

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

Go to latest
Published: Sep 16, 2020 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.

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 CompositepkgsGuide = `
{{% pageinfo color="warning" %}}

#### Notice: Composite packages feature support is in alpha phase

{{% /pageinfo %}}

This guide walks you through an example to create, parameterize and publish a kpt
package which has subpackages in it. A kpt package is a directory of resource
configs with valid ` + "`" + `Kptfile` + "`" + ` in it. A composite package is a ` + "`" + `kpt` + "`" + ` package with 1
or more subpackages in it.

Principles:

1. Each kpt package is an independent building block and
   should contain resources(ex: setter definitions) of its own.
2. If a package is present in the directory tree of parent package,
   the configs of that package are out of scope for the actions performed
   on the parent package.
3. To run a command recursively on all the subpackages, users can leverage
   ` + "`" + `--recurse-subpackages(-R)` + "`" + ` flag. This is equivalent to running the same
   command on each package path in the directory tree.

## Steps

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

## Create a composite package

Create a composite package directory structure and initialize ` + "`" + `kpt` + "`" + ` packages.

  mkdir hello-composite-pkg
  kpt pkg init hello-composite-pkg
  
  mkdir hello-composite-pkg/hello-subpkg
  kpt pkg init hello-composite-pkg/hello-subpkg
  
  # this is a subdir and not a package
  mkdir hello-composite-pkg/hello-subpkg/hello-dir
  
  mkdir hello-composite-pkg/hello-subpkg/hello-nestedpkg
  kpt pkg init hello-composite-pkg/hello-subpkg/hello-nestedpkg

Add resource files(.yaml) to the directories. You may use(copy/paste) the resource files from
[hello-composite-pkg] to respective directories on local and delete the ` + "`" + `$kpt-set` + "`" + ` comments.

## Add setters and substitutions

### Create setters

[Setters] provide a solution for template-free setting of field values through
package metadata (OpenAPI). Setters will be invoked by package consumers to
programmatically modify the configuration using ` + "`" + `kpt cfg set` + "`" + ` to [set] values.
Create ` + "`" + `namespace` + "`" + ` setter in all the packages.

  kpt cfg create-setter hello-composite-pkg/ namespace YOURSPACE -R --required

Output:

  hello-composite-pkg/
  created setter "namespace"
  
  hello-composite-pkg/hello-subpkg/
  created setter "namespace"
  
  hello-composite-pkg/hello-subpkg/hello-nestedpkg/
  created setter "namespace"

Similarly create a setter with name ` + "`" + `gcloud.core.project` + "`" + `. If the package consumer
has ` + "`" + `gcloud` + "`" + ` set up on local, they can observe that the value of the setter
` + "`" + `gcloud.core.project` + "`" + ` will be set automatically when the package is fetched.
[Auto-setters] are automatically set deriving the values from the output of
` + "`" + `gcloud config list` + "`" + ` command, when the package is fetched using [kpt pkg get].

  kpt cfg create-setter hello-composite-pkg/ gcloud.core.project PROJECT_ID -R

### Create substitutions

[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.

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

  kpt cfg create-subst hello-composite-pkg/ image-tag \
  --field-value gcr.io/kpt-dev/helloworld-gke:0.1.0 \
  --pattern gcr.io/kpt-dev/\${image}:\${tag} -R

Output:

  hello-composite-pkg/
  unable to find setter with name image, creating new setter with value helloworld-gke
  unable to find setter with name tag, creating new setter with value 0.1.0
  created substitution "image-tag"
  
  hello-composite-pkg/hello-subpkg/
  unable to find setter with name image, creating new setter with value helloworld-gke
  unable to find setter with name tag, creating new setter with value 0.1.0
  created substitution "image-tag"
  
  hello-composite-pkg/hello-subpkg/hello-nestedpkg/
  unable to find setter with name image, creating new setter with value helloworld-gke
  unable to find setter with name tag, creating new setter with value 0.1.0
  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 hello-composite-pkg/ --include-subst

Output:

  hello-composite-pkg/
           NAME                VALUE        SET BY   DESCRIPTION   COUNT   REQUIRED
    gcloud.core.project   YOUR_PROJECT_ID                          1       No
    image                 helloworld-gke                           1       No
    namespace             YOURSPACE                                1       Yes
    tag                   0.1.0                                    1       No
    SUBSTITUTION              PATTERN               REFERENCES
    image-tag      gcr.io/kpt-dev/${image}:${tag}   [image,tag]
  
  hello-composite-pkg/hello-subpkg/hello-nestedpkg/
           NAME                VALUE        SET BY   DESCRIPTION   COUNT   REQUIRED
    gcloud.core.project   YOUR_PROJECT_ID                          1       No
    image                 helloworld-gke                           1       No
    namespace             YOURSPACE                                1       Yes
    tag                   0.1.0                                    1       No`
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 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 = `Setters provide a solution for template-free setting or substitution of field
values through package metadata (OpenAPI).  They are a safer alternative to
other substitution techniques which do not have the context of the
structured data -- e.g. using ` + "`" + `sed` + "`" + ` to replace values.

The OpenAPI definitions for setters are defined in a Kptfile and referenced by
a fields through comments on the fields.

Setters may be invoked to programmatically modify the configuration
using ` + "`" + `kpt cfg set` + "`" + ` to set and/or substitute values.

{{% 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" >}}

#### 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

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

  # create or update a setter named "replicas"
  # match fields with the value "3"
  kpt cfg create-setter hello-world/ 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"}

#### Auto setters

Some setters are automatically set deriving the values from the output of ` + "`" + `gcloud config list` + "`" + `
command, when the package is fetched using ` + "`" + `kpt pkg get` + "`" + `. Package consumers need not
invoke ` + "`" + `kpt cfg set` + "`" + ` on them explicitly. Following are the names of supported auto-setters:

  gcloud.core.project
  gcloud.project.projectNumber
  gcloud.compute.region
  gcloud.compute.zone

#### Invoking a Setter

  # deployment.yaml -- original
  kind: Deployment
  metadata:
   name: helloworld-gke
   labels:
     app: hello
  spec:
   replicas: 3 # {"$kpt-set":"replicas"}

  # set the replicas field to 5
  kpt cfg set DIR/ replicas 5

  # deployment.yaml -- updated
  kind: Deployment
  metadata:
   name: helloworld-gke
   labels:
     app: hello
  spec:
   replicas: 5 # {"$kpt-set":"replicas"}

#### 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.

  $ cat /path/to/file.json
  {"maximum": 10, "type": "integer"}
  
  # create setter with openAPI property constraints
  kpt cfg create-setter DIR/ replicas 3 --schema-path /path/to/file.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: "3"

  # try to set value not adhering to the constraints
  kpt cfg set DIR/ 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]

#### 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.

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

  # Kptfile
  kind: Kptfile

` + "`" + `$ kpt cfg create-setter DIR/ 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 DIR/ 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"

#### Enumerations

Setters may be configured to map an enum input to a different value set
in the configuration.

e.g. users set ` + "`" + `small` + "`" + `, ` + "`" + `medium` + "`" + `, ` + "`" + `large` + "`" + ` cpu sizes, and these are mapped
to numeric values set in the configuration.

This may be done by modifying the Kptfile OpenAPI definitions as shown here:

  openAPI:
    definitions:
      io.k8s.cli.setters.cpu:
        x-k8s-cli:
          setter:
            name: "cpu"
            value: "small"
            # enumValues will replace the user provided key with the
            # map value when setting fields.
            enumValues:
              small: "0.5"
              medium: "2"
              large: "4"

Set would change the configuration like this:

  kind: Deployment
  metadata:
    name: foo
  spec:
    template:
      spec:
        containers:
        - name: foo
      resources:
        requests:
          cpu: "0.5" # {"$kpt-set":"cpu"}

#### Marking a field as required

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.

  # create a setter named "replicas" and mark it as required
  kpt cfg create-setter hello-world/ 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 hello-world/
  
  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

#### Modifying a Setter

Setters are uniquely identified by their name. create-setter command can be leveraged
to modify an existing setter definition. Users may choose to modify setters in following
scenarios.

1. Add new features to existing setters, such as openAPI validations, marking setter
as required setter etc.
2. Add existing setter references to new resources that are added to package.

Consider an existing package with deployment-foo.yaml and Kptfile as follows.

  # 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"

Add new resource to the package

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

  $ cat /path/to/file.json
  {"maximum": 10, "type": "integer"}
  
  # modify existing setter replicas with openAPI property constraints and required flag
  kpt cfg create-setter DIR/ replicas 3 --schema-path /path/to/file.json --required

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

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

  # deployment-bar.yaml -- setter ref added
  kind: Deployment
  metadata:
    name: bar
  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
`
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 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