Upbound supports defining your control plane APIs using YAML with Go templates.
Go templating functions can make use of all built-in Go templating features and anything supported by Crossplane’s function-go-templating.
You can organize templates into multiple files with an arbitrary directory
structure, as long as all files have the .gotmpl
file extension. Templates are
read in lexical order and concatenated with YAML separators (---
) between
them.
Prerequisites
To define your control plane APIs using Go templating you need the YAML Visual Studio Code extension and optionally the Modelines extension. Refer to the Visual Studio Code Extensions documentation to learn how to install them.
Example
The following example function composes an S3 bucket based on a simplified bucket XRD.
The 01-compose.yaml.gotmpl
file below takes a composite resource (XR) as
input. It produces a Bucket managed resource (MR) from the S3
provider
based on its parameters.
# code: language=yaml
# yaml-language-server: $schema=../../.up/json/models/index.schema.json
---
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
annotations:
{{ setResourceNameAnnotation "bucket" }}
spec:
forProvider:
region: "{{ $xr.spec.parameters.region }}"
Expand the example below to see a more advanced Go templating function.
The files below take a composite resource (XR) as input and produces managed resources (MRs) from the S3 provider based on its parameters. The templates are split across multiple files for readability.
The function always composes an S3 bucket. When the S3 bucket exists, it also composes a bucket access control list (ACL). The ACL references the bucket by name.
If the composite resource’s spec.versioning
field is true
, the function
enables versioning by composing a bucket versioning configuration. Like the ACL,
the versioning configuration references the bucket by name.
As a best practice, place any Go templating flow control (if
statements,
loops, variable assignments, etc.) in YAML comments, as demonstrated
below. While not required, this avoids confusing the YAML language server with
non-YAML syntax, leading to a better editor experience.
00-prelude.yaml.gotmpl
This file contains generated boilerplate to place the observed composite resource and its parameters in Go templating variables, for use by subsequent templates.
#{{ $xr := getCompositeResource . }}
#{{ $params := $xr.spec.parameters }}
01-bucket.yaml.gotmpl
This file creates the Bucket
MR. It then checks whether Crossplane has
assigned an external name for the bucket and places the name in a variable.
# code: language=yaml
# yaml-language-server: $schema=../../.up/json/models/index.schema.json
---
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
annotations:
{{ setResourceNameAnnotation "bucket" }}
spec:
forProvider:
region: "{{ $params.region }}"
# The desired ACL, encryption, and versioning resources all need to refer to the
# bucket by its external name, which is stored in its external name
# annotation. Fetch the external name into a variable so subsequent templates
# can use it.
#
#{{ $bucket := getComposedResource . "bucket" }}
#{{ $bucket_external_name := "" }}
#{{ if $bucket }}
#{{ $bucket_external_name = get $bucket.metadata.annotations "crossplane.io/external-name" }}
#{{ end }}
02-acl.yaml.gotmpl
This file creates the BucketACL
MR. Since this MR requires the bucket’s
external name, the template produces the MR only when the external name is
available.
# code: language=yaml
# yaml-language-server: $schema=../../.up/json/models/index.schema.json
# Don't create the ACL until the bucket name is available.
#{{ if $bucket_external_name }}
---
apiVersion: s3.aws.upbound.io/v1beta1
kind: BucketACL
metadata:
annotations:
{{ setResourceNameAnnotation "acl" }}
spec:
forProvider:
region: "{{ $params.region }}"
bucket: "{{ $bucket_external_name }}"
acl: "{{ $params.acl }}"
#{{ end }}
03-versioning.yaml.gotmpl
This file creates the BucketVersioning
MR when the XR has versioning
enabled. Like the BucketACL
, this MR requires the bucket’s external name, so
the template produces the MR only after the external name is available.
# code: language=yaml
# yaml-language-server: $schema=../../.up/json/models/index.schema.json
#{{ if $params.versioning }}
# Don't create the BucketVersioning until the bucket name is available.
#{{ if $bucket_external_name }}
---
apiVersion: s3.aws.upbound.io/v1beta1
kind: BucketVersioning
metadata:
annotations:
{{ setResourceNameAnnotation "versioning" }}
spec:
forProvider:
region: "{{ $params.region }}"
bucket: "{{ $bucket_external_name }}"
versioningConfiguration:
- status: Enabled
#{{ end }}
#{{ end }}
Control plane project model
The Upbound programming model defines the core concepts you can use when creating your control plane using Upbound.
Upbound builds embedded Go templating functions on top of Crossplane’s function-go-templating, offering a simplified, Upbound-specific development experience.