This composition function is a fork of the upstream function-patch-and-transform that adds support for Conditional invocation of the function and the rendering of individual resources.
The function can be installed as a Crossplane package, and runs in a Composition Function. This feature requires a minium Crossplane version of 1.14.
apiVersion: pkg.crossplane.io/v1beta1
kind: Function
metadata:
  name: function-conditional-patch-and-transform
  annotations:
    render.crossplane.io/runtime: Development
spec:
  package: xpkg.upbound.io/borrelli-org/function-conditional-patch-and-transform:v0.4.0This function enables conditional rendering of the entire function or select resources.
The language used for Conditionals is the Common Expression Language (CEL), which is widely used in the Kubernetes ecosystem.
Composition authors express a CEL condition, and if it returns true, patch-and-transforms defined in the input will be processed.
 mode: Pipeline
  pipeline:
  - step: patch-and-transform
    functionRef:
      name: function-patch-and-transform
    input:
      apiVersion: conditional-pt.fn.crossplane.io/v1beta1
      kind: Resources
      condition: observed.composite.resource.spec.env == "prod" && observed.composite.resource.spec.render == true
      resources: [...all your resources...]Using the following XR and RunFunctionRequest inputs (click to expand):
apiVersion: nopexample.org/v1alpha1
kind: XNopResource
metadata:
  name: test-resource
spec:
  env: dev
  render: true{
   "desired": {
      "composite": {
         "resource": {
            "apiVersion": "nopexample.org/v1alpha1",
            "kind": "XNopResource",
            "metadata": {
               "name": "test-resource"
            },
            "spec": {
               "env": "dev",
               "render": true
            }
         }
      },
      "resources": {
         "test": {
            "resource": {
               "apiVersion": "example.org/v1",
               "kind": "CD",
               "metadata": {
                  "name": "cool-42",
                  "namespace": "default"
               }
            }
         }
      }
   },
   "observed": {
      "composite": {
         "resource": {
            "apiVersion": "nopexample.org/v1alpha1",
            "kind": "XNopResource",
            "metadata": {
               "name": "test-resource"
            },
            "spec": {
               "env": "dev",
               "render": true
            },
            "status": {
               "id": "123",
               "ready": false
            }
         }
      }
   }
}You can use the CEL Playground to test various queries.
Here are some example queries on the XR and RunFunctionRequest:
- desired.composite.resource.spec.env == "dev"evaluates to- true
- desired.composite.resource.spec.render == true,evaluates to- true
- desired.composite.resource.spec.render == false"evaluates to- false
- observed.composite.resource.status.ready == true"evaluates to- false
- size(desired.resources) == 0evaluates to- false
- "test" in desired.resourcesevaluates to- true
- "bad-resource" in desired.resourcesevaluates to- false
In a similar manner, individual Managed Resources can also be rendered conditionally, see the example at examples/conditional-resources.
Each resource can have a condition.
      resources:
         - name: blue-resource
           condition: observed.composite.resource.spec.deployment.blue == true
           base:
            apiVersion: nop.crossplane.io/v1alpha1
            kind: NopResource
            spec:
              forProvider:If this condition is set in the Claim/XR, the resource will be rendered:
apiVersion: nop.example.org/v1alpha1
kind: XNopConditional
metadata:
  name: test-resource
spec:
  env: dev
  render: true
  deployment:
    blue: true
    green: false
You can use the Crossplane CLI to run any function locally and see what composed resources it would create. This only works with functions - not native P&T.
For example, using the files in the examples directory:
cd examples/conditional-rendering
crossplane beta render xr.yaml composition.yaml functions.yamlProduces the following output, showing what resources Crossplane would compose:
---
apiVersion: nop.example.org/v1alpha1
kind: XNopResource
metadata:
  name: test-resource
---
apiVersion: nop.crossplane.io/v1alpha1
kind: NopResource
metadata:
  annotations:
    crossplane.io/composition-resource-name: test-resource
  generateName: test-resource-
  labels:
    crossplane.io/composite: test-resource
  ownerReferences:
  - apiVersion: nop.example.org/v1alpha1
    blockOwnerDeletion: true
    controller: true
    kind: XNopResource
    name: test-resource
    uid: ""
spec:
  forProvider:
    conditionAfter:
    - conditionStatus: "True"
      conditionType: Ready
      time: 5s
    connectionDetails:
    - name: username
      value: fakeuser
    - name: password
      value: verysecurepassword
    - name: endpoint
      value: 127.0.0.1
    fields:
      arrayField:
      - stringField: array
      integerField: 42
      objectField:
        stringField: object
      stringField: stringSee the composition functions documentation to learn how to
use crossplane beta render.
This function uses Go, Docker, and the Crossplane CLI to build functions.
# Run code generation - see input/generate.go
$ go generate ./...
# Run tests - see fn_test.go
$ go test ./...
# Build the function's runtime image - see Dockerfile
$ docker build . --tag=runtime
# Build a function package - see package/crossplane.yaml
$ crossplane xpkg build -f package --embed-runtime-image=runtime