diff --git a/.gitignore b/.gitignore index 3b735ec..cd92d26 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,6 @@ # Go workspace file go.work + +# Binaries +function-go-templating \ No newline at end of file diff --git a/README.md b/README.md index f2f2b61..4ce0cac 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # function-go-templating + [![CI](https://github.com/crossplane-contrib/function-go-templating/actions/workflows/ci.yml/badge.svg)](https://github.com/crossplane-contrib/function-go-templating/actions/workflows/ci.yml) ![GitHub release (latest SemVer)](https://img.shields.io/github/release/crossplane-contrib/function-go-templating) This [composition function][docs-functions] allows you to compose Crossplane resources using [Go templates][go-templates]. If you've written a [Helm -chart][helm-chart] before, using this function will be a familiar experience. +chart][helm-chart] before, using this function will be a familiar experience. Here's an example: @@ -18,26 +19,26 @@ spec: kind: XR mode: Pipeline pipeline: - - step: create-a-bucket - functionRef: - name: function-go-templating - input: - apiVersion: gotemplating.fn.crossplane.io/v1beta1 - kind: GoTemplate - source: Inline - inline: - template: | - apiVersion: s3.aws.upbound.io/v1beta1 - kind: Bucket - metadata: - annotations: - gotemplating.fn.crossplane.io/composition-resource-name: bucket - spec: - forProvider: - region: {{ .observed.composite.resource.spec.region }} - - step: automatically-detect-ready-composed-resources - functionRef: - name: function-auto-ready + - step: create-a-bucket + functionRef: + name: function-go-templating + input: + apiVersion: gotemplating.fn.crossplane.io/v1beta1 + kind: GoTemplate + source: Inline + inline: + template: | + apiVersion: s3.aws.upbound.io/v1beta1 + kind: Bucket + metadata: + annotations: + gotemplating.fn.crossplane.io/composition-resource-name: bucket + spec: + forProvider: + region: {{ .observed.composite.resource.spec.region }} + - step: automatically-detect-ready-composed-resources + functionRef: + name: function-auto-ready ``` ## Using this function @@ -54,10 +55,10 @@ The templates are passed a [`RunFunctionRequest`][bsr] as data. This means that you can access the composite resource, any composed resources, and the function pipeline context using notation like: -* `{{ .observed.composite.resource.metadata.name }}` -* `{{ .desired.composite.resource.status.widgets }}` -* `{{ (index .desired.composed.resource "resource-name").spec.widgets }}` -* `{{ index .context "apiextensions.crossplane.io/environment" }}` +- `{{ .observed.composite.resource.metadata.name }}` +- `{{ .desired.composite.resource.status.widgets }}` +- `{{ (index .desired.composed.resource "resource-name").spec.widgets }}` +- `{{ index .context "apiextensions.crossplane.io/environment" }}` This function supports all of Go's [built-in template functions][builtin]. The above examples use the `index` function to access keys like `resource-name` that @@ -99,11 +100,11 @@ about `crossplane beta render`. ## Additional functions -| Name | Description | -| -------------- | --------------------------------------- | -| `randomChoice` | Randomly selects one of a given strings | -| `toYaml` | Marshals any object into a YAML string | -| `fromYaml`` | Unmarshals a YAML string into an object | +| Name | Description | +| ------------------------------------------------- | --------------------------------------- | +| [`randomChoice``](example/functions/randomChoice) | Randomly selects one of a given strings | +| [`toYaml`](example/functions/toYaml) | Marshals any object into a YAML string | +| [`fromYaml`](example/functions/fromYaml) | Unmarshals a YAML string into an object | ## Developing this function diff --git a/example/.dev/functions.yaml b/example/.dev/functions.yaml new file mode 100644 index 0000000..79a19af --- /dev/null +++ b/example/.dev/functions.yaml @@ -0,0 +1,13 @@ +--- +# Use this function yaml when developing and executing the function directly instead of in a container +# E.g. `go run . --insecure --debug --address=":9443"` + +apiVersion: pkg.crossplane.io/v1beta1 +kind: Function +metadata: + name: function-go-templating + annotations: + render.crossplane.io/runtime: Development + render.crossplane.io/runtime-development-target: localhost:9443 +spec: + package: xpkg.upbound.io/crossplane-contrib/function-go-templating:latest # ignored diff --git a/example/functions/fromYaml/composition.yaml b/example/functions/fromYaml/composition.yaml new file mode 100644 index 0000000..d483e1c --- /dev/null +++ b/example/functions/fromYaml/composition.yaml @@ -0,0 +1,25 @@ +apiVersion: apiextensions.crossplane.io/v1 +kind: Composition +metadata: + name: example-function-from-yaml +spec: + compositeTypeRef: + apiVersion: example.crossplane.io/v1beta1 + kind: XR + mode: Pipeline + pipeline: + - step: render-templates + functionRef: + name: function-go-templating + input: + apiVersion: gotemplating.fn.crossplane.io/v1beta1 + kind: GoTemplate + source: Inline + inline: + template: | + --- + apiVersion: {{ .observed.composite.resource.apiVersion }} + kind: {{ .observed.composite.resource.kind }} + status: + # Extract single value from encoded yaml string + dummy: {{ (.observed.composite.resource.spec.yamlBlob | fromYaml).key2 }} diff --git a/example/functions/fromYaml/functions.yaml b/example/functions/fromYaml/functions.yaml new file mode 100644 index 0000000..c4a446f --- /dev/null +++ b/example/functions/fromYaml/functions.yaml @@ -0,0 +1,6 @@ +apiVersion: pkg.crossplane.io/v1beta1 +kind: Function +metadata: + name: function-go-templating +spec: + package: xpkg.upbound.io/crossplane-contrib/function-go-templating:latest \ No newline at end of file diff --git a/example/functions/fromYaml/xr.yaml b/example/functions/fromYaml/xr.yaml new file mode 100644 index 0000000..3e80ac1 --- /dev/null +++ b/example/functions/fromYaml/xr.yaml @@ -0,0 +1,9 @@ +apiVersion: example.crossplane.io/v1beta1 +kind: XR +metadata: + name: example +spec: + yamlBlob: | + key1: value1 + key2: value2 + key3: value3 \ No newline at end of file diff --git a/example/functions/toYaml/composition.yaml b/example/functions/toYaml/composition.yaml new file mode 100644 index 0000000..0558fc9 --- /dev/null +++ b/example/functions/toYaml/composition.yaml @@ -0,0 +1,25 @@ +apiVersion: apiextensions.crossplane.io/v1 +kind: Composition +metadata: + name: example-function-to-yaml +spec: + compositeTypeRef: + apiVersion: example.crossplane.io/v1beta1 + kind: XR + mode: Pipeline + pipeline: + - step: render-templates + functionRef: + name: function-go-templating + input: + apiVersion: gotemplating.fn.crossplane.io/v1beta1 + kind: GoTemplate + source: Inline + inline: + template: | + --- + apiVersion: {{ .observed.composite.resource.apiVersion }} + kind: {{ .observed.composite.resource.kind }} + status: + # Copy the whole 'complexDictionary' as is by fomatting it as yaml + dummy: {{ .observed.composite.resource.spec.complexDictionary | toYaml | nindent 7 }} diff --git a/example/functions/toYaml/functions.yaml b/example/functions/toYaml/functions.yaml new file mode 100644 index 0000000..c4a446f --- /dev/null +++ b/example/functions/toYaml/functions.yaml @@ -0,0 +1,6 @@ +apiVersion: pkg.crossplane.io/v1beta1 +kind: Function +metadata: + name: function-go-templating +spec: + package: xpkg.upbound.io/crossplane-contrib/function-go-templating:latest \ No newline at end of file diff --git a/example/functions/toYaml/xr.yaml b/example/functions/toYaml/xr.yaml new file mode 100644 index 0000000..5bbe124 --- /dev/null +++ b/example/functions/toYaml/xr.yaml @@ -0,0 +1,12 @@ +apiVersion: example.crossplane.io/v1beta1 +kind: XR +metadata: + name: example +spec: + complexDictionary: + scalar1: true + scalar2: text + scalar3: 123 + list: + - abc + - def