58 KiB
| title | weight | description |
|---|---|---|
| Function Patch and Transform | 70 | A function that use patches and transforms to modify inputs from claims and composite resources before creating managed resources |
Function Patch and Transform allows you to write a Composition that specifies managed resource (MR) templates, and uses "patch and transform" operations to fill them out. Crossplane fills the templates out with values copied from a claim or composite resource (XR).
A patch copies a value from one resource and patches it onto another resource. A transform modifies the values before applying the patch.
{{<hint "tip" >}} All Compositions used Patch and Transform before Crossplane added support for composition functions.
Function Patch and Transform works like legacy mode: Resources Compositions,
which Crossplane deprecated in v1.17. The difference is that it uses a
mode: Pipeline Composition and a function instead of a mode: Resources
Composition.
{{< /hint >}}
Here's an example Composition that uses Function Patch and Transform. When you
create an AcmeBucket XR that uses this Composition, Crossplane uses the
template to create the Amazon S3 Bucket MR.
Crossplane copies the value from the AcmeBucket XR's spec.desiredRegion
field and patch it onto the Bucket managed resource's
spec.forProvider.region field.
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example
spec:
compositeTypeRef:
apiVersion: custom-api.example.org/v1alpha1
kind: AcmeBucket
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: storage-bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: "us-east-2"
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.desiredRegion
toFieldPath: spec.forProvider.region
{{<hint "note" >}} Patch and transform is best for simpler compositions. It intentionally doesn't support features like loops and conditionals. {{}}
{{<expand "Confused about Compositions, XRDs, XRs and Claims?" >}} Crossplane has four core components that users commonly mix up:
- [Composition]({{<ref "../concepts/compositions">}}) - A template to define how to create resources.
- [composite resource Definition]({{<ref "../concepts/composite-resource-definitions">}})
(
XRD) - A custom API specification. - [composite resource]({{<ref "../concepts/composite-resources">}}) (
XR) - Created by using the custom API defined in a composite resource Definition. XRs use the Composition template to create new managed resources. - [Claim]({{<ref "../concepts/claims" >}}) (
XRC) - Like a composite resource, but with namespace scoping. {{}}
Install the function
You must install Function Patch and Transform before you can use it in a Composition. Apply this manifest to install Function Patch and Transform:
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
name: function-patch-and-transform
spec:
package: xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.1.4
{{<hint "tip" >}} Read the [Composition page]({{<ref "../concepts/compositions">}}) to learn more about Compositions and composition functions. {{< /hint >}}
Resource templates
The resources field the function's input defines the set of things that a
composite resource creates when it uses this function.
For example, the input can define a template to create a virtual machine and an associated storage bucket at the same time.
{{<hint "tip" >}} Crossplane calls the resources a composite resource creates composed resources. {{< /hint >}}
The resources field lists the individual resources with a name. This name
identifies the resource inside the Composition. It isn't related to the external
name used with the Provider.
The contents of the base are identical to creating a standalone
[managed resource]({{<ref "../concepts/managed-resources">}}).
This example uses
Upbound's Provider AWS
to define a S3 storage Bucket and EC2 compute Instance.
After defining the apiVersion and kind, define the spec.forProvider fields
defining the settings of the resource.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: storage-bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: "us-east-2"
- name: vm
base:
apiVersion: ec2.aws.upbound.io/v1beta1
kind: Instance
spec:
forProvider:
ami: ami-0d9858aa3c6322f73
instanceType: t2.micro
region: "us-east-2"
When a [composite resource]({{<ref "../concepts/composite-resources" >}}) uses
this function, the composite resource creates two new managed resources with all
the provided spec.forProvider settings.
The spec supports any settings used in a managed resource, including applying
annotations and labels or using a specific providerConfigRef.
{{<hint "note" >}}
Use the crossplane.io/external-name annotation on the resource to set
the resource's name in the external system (like AWS).
{{< /hint >}}
{{<hint "tip" >}} You can use Function Patch and Transform to template other kinds of Crossplane resources, like ProviderConfigs.
You can also template other kinds of composite resource (XR).
You can't template namespaced resources. {{< /hint >}}
Create a patch
Each entry in the resources list can include a list of patches. The patches
field takes a list of patches to apply to the individual resource.
Each patch has a type, which defines what kind of patch action Crossplane
applies.
Patches reference fields inside different resources depending on the patch type,
but all patches reference a fromFieldPath and toFieldPath.
The fromFieldPath is the path to the patch's input values. The toFieldPath
is the path the patch applies to.
Here's an example of a patch that copies a value from the composite resource's
spec.field1 field to the composed Bucket's labels.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: storage-bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: "us-east-2"
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.field1
toFieldPath: metadata.labels["patchLabel"]
Selecting fields
Crossplane selects fields in a composite resource or managed resource with a subset of JSONPath selectors, called "field paths."
Field paths can select any field in a composite resource or managed resource
object, including the metadata, spec or status fields.
Field paths can be a string matching a field name or an array index, in
brackets. Field names may use a . character to select child elements.
Example field paths
Here are some example selectors from a composite resource object. {{<table "table" >}}
| Selector | Selected element |
|---|---|
kind |
kind |
metadata.labels['crossplane.io/claim-name'] |
my-example-claim |
spec.desiredRegion |
eu-north-1 |
spec.resourceRefs[0].name |
my-example-claim-978mh-r6z64 |
| {{ |
$ kubectl get composite -o yaml
apiVersion: example.org/v1alpha1
kind: XExample
metadata:
# Removed for brevity
labels:
crossplane.io/claim-name: my-example-claim
crossplane.io/claim-namespace: default
crossplane.io/composite: my-example-claim-978mh
spec:
desiredRegion: eu-north-1
field1: field1-text
resourceRefs:
- apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
name: my-example-claim-978mh-r6z64
- apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
name: my-example-claim-978mh-cnlhj
- apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
name: my-example-claim-978mh-rv5nm
Reuse a patch
You can reuse a patch object on multiple resources by using a PatchSet.
To create a PatchSet, define a patchSets object in the function's input.
Each patch inside a PatchSet has a name and a list of patches.
Apply the PatchSet to a resource with a patch type: PatchSet. Set the
patchSetName to the name of the PatchSet.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
patchSets:
- name: my-patchset
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.desiredRegion
toFieldPath: spec.forProvider.region
resources:
- name: bucket1
base:
# Removed for brevity
patches:
- type: PatchSet
patchSetName: my-patchset
- name: bucket2
base:
# Removed for brevity
patches:
- type: PatchSet
patchSetName: my-patchset
{{<hint "important" >}} A PatchSet can't contain other PatchSets.
Crossplane ignores any transforms or policies in a PatchSet. {{< /hint >}}
Patching between resources
Function Patch and Transform can't directly patch between two composed resources. For example, generating a network resource and patching the resource name to a compute resource.
A resource can patch to a user-defined status field in the composite resource.
Another resource can then read from that Status field to patch a field.
First, define a custom status in the composite resource Definition and a
custom field, for example secondResource
kind: CompositeResourceDefinition
# Removed for brevity.
spec:
# Removed for brevity.
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
type: object
properties:
spec:
# Removed for brevity.
status:
type: object
properties:
secondResource:
type: string
Inside the function input the resource with the source data uses a
ToCompositeFieldPath patch to write data to the status.secondResource field
in the composite resource.
The destination resource uses a FromCompositeFieldPath patch to read data from
the composite resource status.secondResource field in the composite resource
and write it to a label named secondResource in the managed resource.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
# Removed for brevity
patches:
- type: ToCompositeFieldPath
fromFieldPath: metadata.name
toFieldPath: status.secondResource
- name: bucket2
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
# Removed for brevity
patches:
- type: FromCompositeFieldPath
fromFieldPath: status.secondResource
toFieldPath: metadata.labels['secondResource']
Describe the composite resource to view the resources and the
status.secondResource value.
$ kubectl describe composite
Name: my-example-claim-jp7rx
Spec:
# Removed for brevity
Resource Refs:
Name: my-example-claim-jp7rx-gfg4m
# Removed for brevity
Name: my-example-claim-jp7rx-fttpj
Status:
# Removed for brevity
Second Resource: my-example-claim-jp7rx-gfg4m
Describe the destination managed resource to see the label secondResource.
$ kubectl describe bucket
kubectl describe bucket my-example-claim-jp7rx-fttpj
Name: my-example-claim-jp7rx-fttpj
Labels: crossplane.io/composite=my-example-claim-jp7rx
secondResource=my-example-claim-jp7rx-gfg4m
Patch with EnvironmentConfigs
Crossplane uses EnvironmentConfigs to create in-memory data stores. Compositions can read and write from this data store as part of the patch process.
{{<hint "important" >}} EnvironmentConfigs are an alpha feature. Alpha features aren't enabled by default. {{< /hint >}}
EnvironmentConfigs can predefine data that Compositions can use or a composite resource can write data to their in-memory environment for other resources to read.
{{< hint "note" >}}
Read the [EnvironmentConfigs]({{<ref "../concepts/environment-configs" >}}) page for more information on using EnvironmentConfigs. {{< /hint >}}
To apply a patch using EnvironmentConfigs, first define which EnvironmentConfigs
to use with
environment.environmentConfigs.
Use either a [reference]({{<ref "../concepts/managed-resources#matching-by-name-reference" >}}) or a [selector]({{<ref "../concepts/managed-resources#matching-by-selector" >}}) to identify the EnvironmentConfigs to use.
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for Brevity
spec:
environment:
environmentConfigs:
- ref:
name: example-environment
# Removed for Brevity
Patch a composite resource
To patch between the composite resource and the in-memory environment use
patches inside of the environment.
Use the ToCompositeFieldPath to copy data from the in-memory environment to
the composite resource.
Use the FromCompositeFieldPath to copy data from the composite resource to the
in-memory environment.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
environment:
patches:
- type: ToCompositeFieldPath
fromFieldPath: tags
toFieldPath: metadata.labels[envTag]
- type: FromCompositeFieldPath
fromFieldPath: metadata.name
toFieldPath: newEnvironmentKey
Individual resources can use any data written to their in-memory environment.
Patch an individual resource
To patch an individual resource, inside the patches of the resource, use
ToEnvironmentFieldPath to copy data from the resource to the in-memory
environment.
Use FromEnvironmentFieldPath to copy data to the resource from the in-memory
environment.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: vpc
base:
apiVersion: ec2.aws.upbound.io/v1beta1
kind: VPC
spec:
forProvider:
cidrBlock: 172.16.0.0/16
patches:
- type: ToEnvironmentFieldPath
fromFieldPath: status.atProvider.id
toFieldPath: vpcId
- type: FromEnvironmentFieldPath
fromFieldPath: tags
toFieldPath: spec.forProvider.tags
The [EnvironmentConfigs]({{<ref "../concepts/environment-configs" >}}) page has more information on EnvironmentConfigs options and usage.
Types of patches
Function Patch and Transform supports multiple patch types, each using a different source for data and applying the patch to a different location.
Summary of Crossplane patches {{< table "table table-hover" >}}
| Patch Type | Data Source | Data Destination |
|---|---|---|
| FromCompositeFieldPath | A field in the composite resource. | A field in the composed resource. |
| ToCompositeFieldPath | A field in the composed resource. | A field in the composite resource. |
| CombineFromComposite | Multiple fields in the composite resource. | A field in the composed resource. |
| CombineToComposite | Multiple fields in the composed resource. | A field in the composite resource. |
| FromEnvironmentFieldPath | Data in the in-memory environment | A field in the composed resource. |
| ToEnvironmentFieldPath | A field in the composed resource. | The in-memory environment. |
| CombineFromEnvironment | Multiple fields in the in-memory environment. | A field in the composed resource. |
| CombineToEnvironment | Multiple fields in the composed resource. | A field in the in-memory environment. |
| {{< /table >}} |
{{<hint "note" >}}
All the following examples use the same set of Compositions,
CompositeResourceDefinitions, Claims and EnvironmentConfigs.
Only the applied patches change between examples.
All examples rely on Upbound provider-aws-s3 to create resources.
{{< expand "Reference Composition" >}}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example-composition
spec:
compositeTypeRef:
apiVersion: example.org/v1alpha1
kind: xExample
environment:
environmentConfigs:
- ref:
name: example-environment
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: us-east-2
- name: bucket2
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: us-east-2
{{< /expand >}}
{{<expand "Reference CompositeResourceDefinition" >}}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xexamples.example.org
spec:
group: example.org
names:
kind: xExample
plural: xexamples
claimNames:
kind: ExampleClaim
plural: exampleclaims
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
field1:
type: string
field2:
type: string
field3:
type: string
desiredRegion:
type: string
boolField:
type: boolean
numberField:
type: integer
status:
type: object
properties:
url:
type: string
{{< /expand >}}
{{< expand "Reference Claim" >}}
apiVersion: example.org/v1alpha1
kind: ExampleClaim
metadata:
name: my-example-claim
spec:
field1: "field1-text"
field2: "field2-text"
desiredRegion: "eu-north-1"
boolField: false
numberField: 10
{{< /expand >}}
{{< expand "Reference EnvironmentConfig" >}}
apiVersion: apiextensions.crossplane.io/v1alpha1
kind: EnvironmentConfig
metadata:
name: example-environment
data:
locations:
us: us-east-2
eu: eu-north-1
key1: value1
key2: value2
{{< /expand >}} {{< /hint >}}
FromCompositeFieldPath
The FromCompositeFieldPath patch takes a value in a composite resource and
applies it to a field in the composed resource.
{{< hint "tip" >}}
Use the FromCompositeFieldPath patch to apply options from users in their
Claims to settings in managed resource forProvider settings.
{{< /hint >}}
For example, to use the value desiredRegion provided by a user in a composite
resource to a managed resource's region.
The fromFieldPath value is a field in the composite resource.
The toFieldPath value is the field in the composed resource to change.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: us-east-2
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.desiredRegion
toFieldPath: spec.forProvider.region
View the managed resource to see the updated region
$ kubectl describe bucket
Name: my-example-claim-qlr68-29nqf
# Removed for brevity
Spec:
For Provider:
Region: eu-north-1
ToCompositeFieldPath
The ToCompositeFieldPath writes data from an individual composed resource to
the composite resource that created it.
{{< hint "tip" >}}
Use ToCompositeFieldPath patches to take data from one composed resource in a
Composition and use it in a second composed resource in the same Composition.
{{< /hint >}}
For example, after Crossplane creates a new managed resource, take the value
hostedZoneID and apply it as a label in the composite resource.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: us-east-2
patches:
- type: ToCompositeFieldPath
fromFieldPath: status.atProvider.hostedZoneId
toFieldPath: metadata.labels['ZoneID']
View the created managed resource to see the
Hosted Zone Id field.
$ kubectl describe bucket
Name: my-example-claim-p5pxf-5vnp8
# Removed for brevity
Status:
At Provider:
Hosted Zone Id: Z2O1EMRO9K5GLX
# Removed for brevity
Next view the composite resource and confirm the patch applied the label
$ kubectl describe composite
Name: my-example-claim-p5pxf
Labels: ZoneID=Z2O1EMRO9K5GLX
CombineFromComposite
The CombineFromComposite patch takes values from the composite resource,
combines them and applies them to the composed resource.
{{< hint "tip" >}}
Use the CombineFromComposite patch to create complex strings, like security
policies and apply them to a composed resource.
{{< /hint >}}
For example, use the Claim value desiredRegion and field2 to generate the
managed resource's name
The CombineFromComposite patch only supports the combine option.
The variables are the list of fromFieldPath values from the composite
resource to combine.
The only supported strategy is strategy: string.
Optionally you can apply a string.fmt, based on
Go string formatting to specify how to combine the
strings.
The toFieldPath is the field in the composed resource to apply the new string
to.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: us-east-2
patches:
- type: CombineFromComposite
combine:
variables:
- fromFieldPath: spec.desiredRegion
- fromFieldPath: spec.field2
strategy: string
string:
fmt: "my-resource-%s-%s"
toFieldPath: metadata.name
Describe the managed resource to see the applied patch.
$ kubectl describe bucket
Name: my-resource-eu-north-1-field2-text
CombineToComposite
The CombineToComposite patch takes values from the composed resource, combines
them and applies them to the composite resource.
{{<hint "tip" >}}
Use CombineToComposite patches to create a single field like a URL from
multiple fields in a managed resource.
{{< /hint >}}
For example, use the managed resource name and region to generate a custom
url field.
{{< hint "important" >}} Writing custom fields in the status field of a composite resource requires defining the custom fields in the CompositeResourceDefinition first. {{< /hint >}}
The CombineToComposite patch only supports the combine option.
The variables are the list of fromFieldPath the managed resource to combine.
The only supported strategy is strategy: string.
Optionally you can apply a string.fmt, based on
Go string formatting to specify how to combine the
strings.
The toFieldPath is the field in the composite resource to apply the new string
to.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: us-east-2
patches:
- type: CombineToComposite
combine:
variables:
- fromFieldPath: metadata.name
- fromFieldPath: spec.forProvider.region
strategy: string
string:
fmt: "https://%s.%s.com"
toFieldPath: status.url
View the composite resource to verify the applied patch.
$ kubectl describe composite
Name: my-example-claim-bjdjw
API Version: example.org/v1alpha1
Kind: xExample
# Removed for brevity
Status:
# Removed for brevity
URL: https://my-example-claim-bjdjw-r6ncd.us-east-2.com
FromEnvironmentFieldPath
{{<hint "important" >}} EnvironmentConfigs are an alpha feature. They aren't enabled by default.
For more information about using an EnvironmentConfig, read the [EnvironmentConfigs documentation]({{<ref "../concepts/environment-configs">}}). {{< /hint >}}
The FromEnvironmentFieldPath patch takes values from the in-memory environment
and applies them to the composed resource.
{{<hint "tip" >}}
Use FromEnvironmentFieldPath to apply custom managed resource settings based
on the current environment.
{{< /hint >}}
For example, use the environment's locations.eu value and apply it as the
region.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: us-east-2
patches:
- type: FromEnvironmentFieldPath
fromFieldPath: locations.eu
toFieldPath: spec.forProvider.region
Verify managed resource to confirm the applied patch.
kubectl describe bucket
Name: my-example-claim-8vrvc-xx5sr
Labels: crossplane.io/claim-name=my-example-claim
# Removed for brevity
Spec:
For Provider:
Region: eu-north-1
# Removed for brevity
ToEnvironmentFieldPath
{{<hint "important" >}} EnvironmentConfigs are an alpha feature. They aren't enabled by default.
For more information about using an EnvironmentConfig, read the [EnvironmentConfigs documentation]({{<ref "../concepts/environment-configs">}}). {{< /hint >}}
The ToEnvironmentFieldPath patch takes a value from the composed resource and
applies it to the in-memory environment.
{{<hint "tip" >}}
Use ToEnvironmentFieldPath to write data to the environment that any
FromEnvironmentFieldPath patch can access.
{{< /hint >}}
For example, use the desired region value and apply it as the environment's
key1.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: us-east-2
patches:
- type: ToEnvironmentFieldPath
fromFieldPath: spec.forProvider.region
toFieldPath: key1
Because the environment is in-memory, there is no command to confirm the patch wrote the value to the environment.
CombineFromEnvironment
{{<hint "important" >}} EnvironmentConfigs are an alpha feature. They aren't enabled by default.
For more information about using an EnvironmentConfig, read the [EnvironmentConfigs documentation]({{<ref "../concepts/environment-configs">}}). {{< /hint >}}
The CombineFromEnvironment patch combines multiple values from the in-memory
environment and applies them to the composed resource.
{{<hint "tip" >}}
Use CombineFromEnvironment patch to create complex strings, like security
policies and apply them to a managed resource.
{{< /hint >}}
For example, combine multiple fields in the environment to create a unique
annotation .
The CombineFromEnvironment patch only supports the combine option.
The only supported strategy is strategy: string.
The variables are the list of fromFieldPath values from the in-memory
environment to combine.
Optionally you can apply a string.fmt, based on
Go string formatting to specify how to combine the
strings.
The toFieldPath is the field in the composed resource to apply the new string
to.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: us-east-2
patches:
- type: CombineFromEnvironment
combine:
strategy: string
variables:
- fromFieldPath: key1
- fromFieldPath: key2
string:
fmt: "%s-%s"
toFieldPath: metadata.annotations[EnvironmentPatch]
Describe the managed resource to see new
annotation.
$ kubectl describe bucket
Name: my-example-claim-zmxdg-grl6p
# Removed for brevity
Annotations: EnvironmentPatch: value1-value2
# Removed for brevity
CombineToEnvironment
{{<hint "important" >}} EnvironmentConfigs are an alpha feature. They aren't enabled by default.
For more information about using an EnvironmentConfig, read the [EnvironmentConfigs documentation]({{<ref "../concepts/environment-configs">}}). {{< /hint >}}
The CombineToEnvironment patch combines multiple values from the composed
resource and applies them to the in-memory EnvironmentConfig environment.
{{<hint "tip" >}}
Use CombineToEnvironment patch to create complex strings, like security
policies to use in other managed resources.
{{< /hint >}}
For example, combine multiple fields in the managed resource to create a unique
string and store it in the environment's key2 value.
The string combines the managed resource Kind and region.
The CombineToEnvironment patch only supports the combine option.
The only supported strategy is strategy: string.
The variables are the list of fromFieldPath values in the managed resource
to combine.
Optionally you can apply a string.fmt, based on
Go string formatting to specify how to combine the
strings.
The toFieldPath is the key in the environment to write the new string to.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: us-east-2
patches:
- type: CombineToEnvironment
combine:
strategy: string
variables:
- fromFieldPath: kind
- fromFieldPath: spec.forProvider.region
string:
fmt: "%s.%s"
toFieldPath: key2
Because the environment is in-memory, there is no command to confirm the patch wrote the value to the environment.
Transform a patch
When applying a patch, Crossplane supports modifying the data before applying it as a patch. Crossplane calls this a "transform" operation.
Summary of Crossplane transforms. {{< table "table table-hover" >}}
| Transform Type | Action |
|---|---|
| convert | Converts an input data type to a different type. Also called "casting." |
| map | Selects a specific output based on a specific input. |
| match | Selects a specific output based on a string or regular expression. |
| math | Applies a mathematical operation on the input. |
| string | Change the input string using Go string formatting. |
| {{< /table >}} |
Apply a transform directly to an individual patch with the transforms field.
A transform requires a type, indicating the transform action to take.
The other transform field is the same as the type, in this example, map.
The other fields depend on the patch type used.
This example uses a type: map transform, taking the input
spec.desiredRegion, matching it to either us or eu and returning the
corresponding AWS region for the spec.forProvider.region value.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: us-east-2
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.desiredRegion
toFieldPath: spec.forProvider.region
transforms:
- type: map
map:
us: us-east-2
eu: eu-north-1
Convert transforms
The convert transform type changes the input data type to a different data
type.
{{< hint "tip" >}}
Some provider APIs require a field to be a string. Use a convert type to
change any boolean or integer fields to strings.
{{< /hint >}}
A convert transform requires a toType, defining the output data type.
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.numberField
toFieldPath: metadata.label["numberToString"]
transforms:
- type: convert
convert:
toType: string
Supported toType values:
{{< table "table table-sm table-hover" >}}
toType value |
Description |
|---|---|
bool |
A boolean value of true or false. |
float64 |
A 64-bit float value. |
int |
A 32-bit integer value. |
int64 |
A 64-bit integer value. |
string |
A string value. |
object |
An object. |
array |
An array. |
| {{< /table >}} |
Converting strings to booleans
When converting from a string to a bool Crossplane considers the string values
1, t, T, TRUE, True and true equal to the boolean value True.
The strings 0, f, F, FALSE, False and false are equal to the boolean
value False.
Converting numbers to booleans
Crossplane considers the integer 1 and float 1.0 equal to the boolean value
True. Any other integer or float value is False.
Converting booleans to numbers
Crossplane converts the boolean value True to the integer 1 or float64
1.0.
The value False converts to the integer 0 or float64 0.0
Converting strings to float64
When converting from a string to a float64 Crossplane supports an optional
format: quantity field.
Using format: quantity translates size suffixes like M for megabyte or Mi
for megabit into the correct float64 value.
{{<hint "note" >}} Refer to the Go language docs for a full list of supported suffixes. {{}}
Add format: quantity to the convert object to enable quantity suffix
support.
- type: convert
convert:
toType: float64
format: quantity
Converting strings to objects
Crossplane converts JSON strings to objects.
Add format: json to the convert object which is the only supported string
format for this conversion.
- type: convert
convert:
toType: object
format: json
{{< hint "tip" >}} This conversion is useful for patching keys in an object. {{< /hint >}}
The following example adds a tag to a resource with a
customized key:
- type: FromCompositeFieldPath
fromFieldPath: spec.clusterName
toFieldPath: spec.forProvider.tags
transforms:
- type: string
string:
type: Format
fmt: '{"kubernetes.io/cluster/%s": "true"}'
- type: convert
convert:
toType: object
format: json
Converting strings to arrays
Crossplane converts JSON strings to arrays.
Add format: json to the convert object which is the only supported string
format for this conversion.
- type: convert
convert:
toType: array
format: json
Map transforms
The map transform type maps an input value to an output value.
{{< hint "tip" >}}
The map transform is useful for translating generic region names like US or
EU to provider specific region names.
{{< /hint >}}
The map transform compares the value from the fromFieldPath to the options
listed in the map.
If Crossplane finds the value, Crossplane puts the mapped value in the
toFieldPath.
{{<hint "note" >}} Crossplane throws an error for the patch if the value isn't found. {{< /hint >}}
spec.field1 is the string "field1-text" then Crossplane uses the string
firstField for the annotation.
If spec.field1 is the string "field2-text" then Crossplane uses the string
secondField for the annotation.
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.field1
toFieldPath: metadata.annotations["myAnnotation"]
transforms:
- type: map
map:
"field1-text": "firstField"
"field2-text": "secondField"
In this example, the value of spec.field1 is field1-text.
$ kubectl describe composite
Name: my-example-claim-twx7n
Spec:
# Removed for brevity
field1: field1-text
The annotation applied to the managed resource is firstField.
$ kubectl describe bucket
Name: my-example-claim-twx7n-ndb2f
Annotations: crossplane.io/composition-resource-name: bucket1
myAnnotation: firstField
# Removed for brevity.
Match transform
The match transform is like the map transform.
The match transform adds support for regular expressions along with exact
strings and can provide default values if there isn't a match.
A match object requires a patterns object.
The patterns is a list of one or more patterns to attempt to match the input
value against.
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.field1
toFieldPath: metadata.annotations["myAnnotation"]
transforms:
- type: match
match:
patterns:
- type: literal
# Removed for brevity
- type: regexp
# Removed for brevity
Match patterns can be either type: literal to match an exact string or
type: regexp to match a regular expression.
{{<hint "note" >}} Crossplane stops processing matches after the first pattern match. {{< /hint >}}
Match an exact string
Use a pattern with
type: literal to match an
exact string.
On a successful match Crossplane provides the
result: to
the patch toFieldPath.
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.field1
toFieldPath: metadata.annotations["myAnnotation"]
transforms:
- type: match
match:
patterns:
- type: literal
literal: "field1-text"
result: "matchedLiteral"
Match a regular expression
Use a pattern with type: regexp to match a regular expression.
Define a regexp key with the value of the regular expression to match.
On a successful match Crossplane provides the result: to the patch
toFieldPath.
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.field1
toFieldPath: metadata.annotations["myAnnotation"]
transforms:
- type: match
match:
patterns:
- type: regexp
regexp: '^field1.*'
result: "foundField1"
Using default values
Optionally you can provide a default value to use if there is no matching pattern.
The default value can either be the original input value or a defined default value.
Use fallbackTo: Value to provide a default value if a match isn't found.
For example if the string unknownString isn't matched, Crossplane provides the
Value StringNotFound to the toFieldPath
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.field1
toFieldPath: metadata.annotations["myAnnotation"]
transforms:
- type: match
match:
patterns:
- type: literal
literal: "UnknownString"
result: "foundField1"
fallbackTo: Value
fallbackValue: "StringNotFound"
To use the original input as the fallback value use fallbackTo: Input.
Crossplane uses the original fromFieldPath input for the toFieldPath value.
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.field1
toFieldPath: metadata.annotations["myAnnotation"]
transforms:
- type: match
match:
patterns:
- type: literal
literal: "UnknownString"
result: "foundField1"
fallbackTo: Input
Math transforms
Use the math transform to multiply an input or apply a minimum or maximum
value.
{{<hint "important">}}
A math transform only supports integer inputs.
{{< /hint >}}
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.numberField
toFieldPath: metadata.annotations["mathAnnotation"]
transforms:
- type: math
math:
...
clampMin
The type: clampMin uses a defined minimum value if an input is larger than the
type: clampMin value.
For example, this type: clampMin requires an input to be greater than 20.
If an input is lower than 20, Crossplane uses the clampMin value for the
toFieldPath.
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.numberField
toFieldPath: metadata.annotations["mathAnnotation"]
transforms:
- type: math
math:
type: clampMin
clampMin: 20
clampMax
The type: clampMax uses a defined minimum value if an input is larger than the
type: clampMax value.
For example, this type: clampMax requires an input to be less than 5.
If an input is higher than 5, Crossplane uses the clampMax value for the
toFieldPath.
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.numberField
toFieldPath: metadata.annotations["mathAnnotation"]
transforms:
- type: math
math:
type: clampMax
clampMax: 5
Multiply
The type: multiply multiplies the input by the multiply value.
For example, this type: multiply multiplies the value from the fromFieldPath
value by 2
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.numberField
toFieldPath: metadata.annotations["mathAnnotation"]
transforms:
- type: math
math:
type: multiply
multiply: 2
{{<hint "note" >}}
The multiply value only supports integers.
{{< /hint >}}
String transforms
The string transform applies string formatting or manipulation to string
inputs.
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.field1
toFieldPath: metadata.annotations["stringAnnotation"]
transforms:
- type: string
string:
type: ...
String transforms support the following
types
String convert
The type: convert
converts the input based on one of the following conversion types:
ToUpper- Change the string to all upper case letters.ToLower- Change the string to all lower case letters.ToBase64- Create a new base64 string from the input.FromBase64- Create a new text string from a base64 input.ToJson- Convert the input string to valid JSON.ToSha1- Create a SHA-1 hash of the input string.ToSha256- Create a SHA-256 hash of the input string.ToSha512- Create a SHA-512 hash of the input string.ToAdler32- Create an Adler32 hash of the input string.
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.field1
toFieldPath: metadata.annotations["FIELD1-TEXT"]
transforms:
- type: string
string:
type: Convert
convert: "ToUpper"
String format
The type: format applies Go string formatting to the
input.
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.field1
toFieldPath: metadata.annotations["stringAnnotation"]
transforms:
- type: string
string:
type: Format
fmt: "the-field-%s"
Join
The type: Join joins all values in the input array into a string using the
given separator.
This transform only works with array inputs.
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.inputList
toFieldPath: spec.targetJoined
transforms:
- type: string
string:
type: Join
join:
separator: ","
Regular expression type
The type: Regexp extracts the part of the input matching a regular expression.
Optionally use a group to match a regular expression capture group.
By default Crossplane matches the entire regular expression.
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.desiredRegion
toFieldPath: metadata.annotations["euRegion"]
transforms:
- type: string
string:
type: Regexp
regexp:
match: '^eu-(.*)-'
group: 1
Trim prefix
The type: TrimPrefix uses
Go's TrimPrefix and removes characters
from the beginning of a line.
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.desiredRegion
toFieldPath: metadata.annotations["north-1"]
transforms:
- type: string
string:
type: TrimPrefix
trim: `eu-
Trim suffix
The type: TrimSuffix uses
Go's TrimSuffix and removes characters
from the end of a line.
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.desiredRegion
toFieldPath: metadata.annotations["eu"]
transforms:
- type: string
string:
type: TrimSuffix
trim: `-north-1'
Patch policies
Crossplane supports two types of patch policies:
fromFieldPathtoFieldPath
fromFieldPath policy
Using a fromFieldPath: Required policy on a patch requires the fromFieldPath
to exist in the data source resource.
{{<hint "tip" >}}
If a resource patch isn't working applying the fromFieldPath: Required policy
may produce an error in the composite resource to help troubleshoot.
{{< /hint >}}
By default, Crossplane applies the policy fromFieldPath: Optional. With
fromFieldPath: Optional Crossplane ignores a patch if the fromFieldPath
doesn't exist.
With fromFieldPath: Required the composite resource produces an error if the
fromFieldPath doesn't exist.
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.desiredRegion
toFieldPath: metadata.annotations["eu"]
policy:
fromFieldPath: Required
toFieldPath policy
By default when applying a patch the function replaces the destination data. Use
toFieldPath to allow patches to merge arrays and objects without overwriting
them.
The toFieldPath policy supports these options:
{{< table "table table-hover" >}}
| Policy | Action |
|---|---|
Replace (default) |
Replace the value at toFieldPath. |
MergeObjects |
Recursively merge into the value at toFieldPath. Keep any conflicting object keys. |
ForceMergeObjects |
Recursively merge into the value at toFieldPath. Replace any conflicting object keys. |
MergeObjectsAppendArrays |
Like MergeObjects, but append values to arrays instead of replacing them. |
ForceMergeObjectsAppendArrays |
Like ForceMergeObjects, but append values to arrays instead of replacing them. |
| {{< /table >}} |
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.desiredRegion
toFieldPath: metadata.annotations["eu"]
policy:
toFieldPath: MergeObjectsAppendArrays
Composite resource connection details
Function patch and Transform must define the specific secret keys a resource
creates with the connectionDetails object.
{{<table "table table-sm" >}}
| Secret Type | Description |
|---|---|
FromConnectionSecretKey |
Create a secret key matching the key of a secret generated by the resource. |
FromFieldPath |
Create a secret key matching a field path of the resource. |
FromValue |
Create a secret key with a predefined value. |
| {{< /table >}} |
{{<hint "note">}}
The value type must use a string value.
The value isn't added to the individual resource secret object. The value
only appears in the combined composite resource secret.
{{< /hint >}}
kind: Composition
spec:
writeConnectionSecretsToNamespace: other-namespace
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: key
base:
# Removed for brevity
spec:
forProvider:
# Removed for brevity
writeConnectionSecretToRef:
namespace: docs
name: key1
connectionDetails:
- name: my-username
type: FromConnectionSecretKey
fromConnectionSecretKey: username
- name: my-field-secret
type: FromFieldPath
fromFieldPath: spec.forProvider.user
- name: my-status-secret
type: FromValue
value: "docs.crossplane.io"
The connectionDetails in a resource can reference a secret from a resource
with FromConnectionSecretKey, from another field in the resource with
FromFieldPath or a statically defined value with FromValue.
Crossplane sets the secret key to the name value.
Describe the secret to view the secret keys inside the secret object.
{{<hint "tip" >}} If more than one resource generates secrets with the same secret key name, Crossplane only saves one value.
Use a custom name to create unique secret keys.
{{< /hint >}}
{{<hint "important">}}
Crossplane only adds connection details listed in the connectionDetails to the
combined secret object.
Any connection secrets in a managed resource, not defined in the
connectionDetails aren't added to the combined secret object.
{{< /hint >}}
kubectl describe secret
Name: my-access-key-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: connection.crossplane.io/v1alpha1
Data
====
myUsername: 20 bytes
myFieldSecret: 24 bytes
myStaticSecret: 18 bytes
{{<hint "note" >}} The CompositeResourceDefinition can also limit which keys Crossplane stores from the composite resources.
By default an XRD writes all secret keys listed in the composed resources
connectionDetails to the combined secret object.
Read the [CompositeResourceDefinition documentation]({{<ref "../concepts/composite-resource-definitions#manage-connection-secrets">}}) for more information on restricting secret keys. {{< /hint >}}
For more information on connection secrets read the [Connection Secrets concepts age]({{<ref "../concepts/connection-details">}}).
Resource readiness checks
By default Crossplane considers a composite resource or Claim as READY when
the status of all created resource are Type: Ready and Status: True
Some resources, for example, a ProviderConfig, don't have a Kubernetes status
and are never considered Ready.
Custom readiness checks allow Compositions to define what custom conditions to
meet for a resource to be Ready.
{{< hint "tip" >}}
Use multiple readiness checks if a resource must meet multiple conditions for it
to be Ready.
{{< /hint >}}
Define a custom readiness check with the readinessChecks field on a resource.
Checks have a type defining how to match the resource and a fieldPath of
which field in the resource to compare.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: my-resource
base:
# Removed for brevity
readinessChecks:
- type: <match type>
fieldPath: <resource field>
Compositions support matching resource fields by:
Match a string
MatchString considers the composed resource to be ready when the value of a
field in that resource matches a specified string.
{{<hint "note" >}}
Crossplane only supports exact string matches. Substrings and regular expressions aren't supported in a readiness check.
{{}}
For example, matching the string Online in the resource's
status.atProvider.state field.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: my-resource
base:
# Removed for brevity
readinessChecks:
- type: MatchString
fieldPath: status.atProvider.state
matchString: "Online"
Match an integer
MatchInteger considers the composed resource to be ready when the value of a
field in that resource matches a specified integer.
{{<hint "note" >}}
Crossplane doesn't support matching 0.
{{}}
For example, matching the number 4 in the resource's status.atProvider.state
field.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: my-resource
base:
# Removed for brevity
readinessChecks:
- type: MatchInteger
fieldPath: status.atProvider.state
matchInteger: 4
Match that a field exists
NonEmpty considers the composed resource to be ready when a field exists with
a value.
{{<hint "note" >}}
Crossplane considers a value of 0 or an empty string as empty.
{{}}
For example, to check that a resource's status.atProvider.state field isn't
empty.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: my-resource
base:
# Removed for brevity
readinessChecks:
- type: NonEmpty
fieldPath: status.atProvider.state
{{<hint "tip" >}}
Checking NonEmpty doesn't
require setting any other fields.
{{< /hint >}}
Always consider a resource ready
None considers the composed resource to be ready as soon as it's created.
Crossplane doesn't wait for any other conditions before declaring the resource
ready.
For example, consider my-resource ready as soon as it's created.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: my-resource
base:
# Removed for brevity
readinessChecks:
- type: None
Match a condition
Condition considers the composed resource to be ready when it finds the
expected condition type, with the expected status for it in its
status.conditions.
For example, consider my-resource, which is ready if there is a condition of
type MyType with a status of Success.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: my-resource
base:
# Removed for brevity
readinessChecks:
- type: MatchCondition
matchCondition:
type: MyType
status: Success
Match a boolean
Two types of checks exist for matching boolean fields:
MatchTrueMatchFalse
MatchTrue considers the composed resource to be ready when the value of a
field inside that resource is true.
MatchFalse considers the composed resource to be ready when the value of a
field inside that resource is false.
For example, consider
my-resource, which is
ready if
status.atProvider.manifest.status.ready
is true.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: my-resource
base:
# Removed for brevity
readinessChecks:
- type: MatchTrue
fieldPath: status.atProvider.manifest.status.ready
{{<hint "tip" >}}
Checking MatchTrue doesn't
require setting any other fields.
{{< /hint >}}
MatchFalse matches fields that express readiness with the value false.
For example, consider my-resource, is ready if status.atProvider.manifest.status.pending is false.
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: my-resource
base:
# Removed for brevity
readinessChecks:
- type: MatchFalse
fieldPath: status.atProvider.manifest.status.pending
{{<hint "tip" >}}
Checking MatchFalse doesn't require setting any other fields.
{{< /hint >}}