Skip to content

kcl-lang/kustomize-kcl

Repository files navigation

Kustomize KCL Function

Go Report Card GoDoc License FOSSA Status

This is an example of implementing a KCL function for Kustomize. KCL is a constraint-based record & functional domain language. Full documents of KCL can be found here.

KCL can be used to create functions to mutate and/or validate the YAML Kubernetes Resource Model (KRM) input/output format, and we provide Kustomize KCL functions to simplify the function authoring process.

Quick Start

Let’s write a KCL function that adds annotation managed-by=kustomize-kcl only to Deployment resources.

Prerequisites

Test and Run

Local Test

cat ./examples/set-annotation/local-resource/example-use.yaml | go run main.go

The output YAML is

apiVersion: krm.kcl.dev/v1alpha1
kind: KCLRun
metadata:
  name: set-annotation
  annotations:
    config.kubernetes.io/function: |
      container:
        image: docker.io/kcllang/kustomize-kcl:v0.2.0
    config.kubernetes.io/path: example-use.yaml
    internal.config.kubernetes.io/path: example-use.yaml
# EDIT THE SOURCE!
# This should be your KCL code which preloads the `ResourceList` to `option("resource_list")
spec:
  source: |
    [resource | {if resource.kind == "Deployment": metadata.annotations: {"managed-by" = "kustomize-kcl"}} for resource in option("resource_list").items]
---
apiVersion: v1
kind: Service
metadata:
  name: test
  annotations:
    config.kubernetes.io/path: example-use.yaml
    internal.config.kubernetes.io/path: example-use.yaml
spec:
  selector:
    app: MyApp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
  annotations:
    managed-by: kustomize-kcl
    config.kubernetes.io/path: example-use.yaml
    internal.config.kubernetes.io/path: example-use.yaml
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

Integration Test

# Note: you need add sudo and --as-current-user flags to ensure KCL has permission to write temp files in the container filesystem.
kustomize fn run examples/set-annotation/local-resource/ --dry-run

The output YAML is

apiVersion: krm.kcl.dev/v1alpha1
kind: KCLRun
metadata:
  name: set-annotation
  annotations:
    config.kubernetes.io/function: |
      container:
        image: docker.io/kcllang/kustomize-kcl:v0.2.0
    config.kubernetes.io/path: example-use.yaml
    internal.config.kubernetes.io/path: example-use.yaml
# EDIT THE SOURCE!
# This should be your KCL code which preloads the `ResourceList` to `option("resource_list")
spec:
  source: |
    [resource | {if resource.kind == "Deployment": metadata.annotations: {"managed-by" = "kustomize-kcl"}} for resource in option("resource_list").items]
---
apiVersion: v1
kind: Service
metadata:
  name: test
  annotations:
    config.kubernetes.io/path: example-use.yaml
    internal.config.kubernetes.io/path: example-use.yaml
spec:
  selector:
    app: MyApp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
  annotations:
    managed-by: kustomize-kcl
    config.kubernetes.io/path: example-use.yaml
    internal.config.kubernetes.io/path: example-use.yaml
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

This exists non-zero if the KCL code has no errors.

Function Implementation

The function is implemented as an image, and built using make image, and its function is implemented as a go program, which reads a collection of input Resource configuration, passing them to KCL.

Function Configuration

See the API struct definition in main.go for documentation.

  • source - the KCL function code.
  • params - top-level arguments for KCL

Function Invocation

The function is invoked by authoring a local Resource with metadata.annotations.[config.kubernetes.io/function].

Guides for Developing KCL

Here's what you can do in the KCL script:

  • Read resources from option("resource_list"). The option("resource_list") complies with the KRM Functions Specification. You can read the input resources from option("resource_list")["items"] and the functionConfig from option("resource_list")["functionConfig"].
  • Return a KPM list for output resources.
  • Return an error using assert {condition}, {error_message}.
  • Read the environment variables. e.g. option("PATH") (Not yet implemented).
  • Read the OpenAPI schema. e.g. option("open_api")["definitions"]["io.k8s.api.apps.v1.Deployment"] (Not yet implemented).

Examples

See here for more examples.

Library

You can directly use KCL standard libraries without importing them, such as regex.match, math.log.

License

FOSSA Status

git tag v0.9.0 git push origin v0.9.0 gh release create v0.9.0 --draft --generate-notes --title "v0.9.0 Release"