This composition function does everything Crossplane's
built-in patch & transform (P&T) composition does. Instead of
specifying spec.resources
in your Composition, you can use this function.
Using this function, P&T looks like this:
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example
spec:
# Omitted for brevity.
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: us-east-2
patches:
- type: FromCompositeFieldPath
fromFieldPath: "spec.location"
toFieldPath: "spec.forProvider.region"
transforms:
- type: map
map:
EU: "eu-north-1"
US: "us-east-2"
Notice that it looks very similar to native P&T. The difference is that
everything is under spec.pipeline[0].input.resources
, not spec.resources
.
This is the Function's input.
There are a lot of good reasons to use a function to use a function to do P&T composition. In fact, it's so compelling that the Crossplane maintainers are considering deprecating native P&T. See Crossplane issue #4746 for details.
With this function you can use P&T with other functions. For example you can create a desired resource using the Go Templating function, then patch the result using this function.
To include results from previous functions, simply provide a resources
entry
for each and specify a name
field that matches the name of the resource from
the previous function. Also, do not specify any value for the base
field of
each resource.
It's not just patches either. You can use P&T to derive composite resource connection details from a resource produced by another function, or use it to determine whether a resource produced by another function is ready.
A straightforward example for multistep mix and match pipeline with function-patch-and-transform and function-go-templating can be found here
When P&T development happens in a function, it's not coupled to the Crossplane release cycle. The maintainers of this function can cut releases more frequently to add new features to P&T.
It also becomes easier to fork. You could fork this function, add a new kind of transform and try it out for a few weeks before sending a PR upstream. Or, if your new feature is controversial, it's now a lot less work to maintain your own fork long term.
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 example directory:
$ crossplane beta render xr.yaml composition.yaml functions.yaml
Produces the following output, showing what resources Crossplane would compose:
---
apiVersion: example.crossplane.io/v1
kind: XR
metadata:
name: example-xr
---
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
annotations:
crossplane.io/composition-resource-name: bucket
generateName: example-xr-
labels:
crossplane.io/composite: example-xr
ownerReferences:
# Omitted for brevity
spec:
forProvider:
region: us-east-2
See the composition functions documentation to learn how to
use crossplane beta render
.
This function has a few small, intentional breaking changes compared to the native implementation.
These fields are now required. This makes P&T configuration less ambiguous:
resources[i].name
resources[i].connectionDetails[i].name
resources[i].connectionDetails[i].type
resources[i].patches[i].transforms[i].string.type
resources[i].patches[i].transforms[i].math.type
Also, the resources[i].patches[i].policy.mergeOptions
field is no longer
supported. This functionality has been replaced by the
resources[i].patches[i].policy.toFieldPath
field. The table below outlines
previous behavior that was possible with mergeOptions
and how to achieve it
with the new toFieldPath
field:
# | mergeOptions |
appendSlice |
keepMapValues |
toFieldPath |
---|---|---|---|---|
1 | nil |
N/A | N/A | nil which defaults to Replace |
2 | non-nil |
nil or false |
true |
MergeObjects |
3 | non-nil |
true |
nil or false |
ForceMergeObjectsAppendArrays |
4 | non-nil |
nil or false |
nil or false |
ForceMergeObjects |
5 | non-nil |
true |
true |
MergeObjectsAppendArrays |
As an example, a previous configuration using the no longer supported mergeOptions
:
policy:
mergeOptions:
appendSlice: true
keepMapValues: true
Should be replaced with:
policy:
toFieldPath: MergeObjectsAppendArrays
Starting with Crossplane v1.16.0, the convert
command in the Crossplane
CLI will automatically convert mergeOptions
to toFieldPath
for
you.
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