---
title: Patch and Transforms
weight: 70
description: "Crossplane Compositions use patches and transforms to modify inputs from claims and composite resources before creating managed resources"
---
Crossplane Compositions allow for "patch and transform" operations. With patches
a Composition can apply changes to the resources defined by the Composition.
When users create Claims, Crossplane passes the settings in the Claim to
the associated composite resource. Patches can use these settings to change the
associated composite resource or managed resources.
Examples of using patch and transforms include:
* changing the name of the external resource
* mapping generic terms like "east" or "west" to specific provider locations
* appending custom labels or strings to resource fields
{{}}
Crossplane expects patch and transform operations to be simple changes.
Use [Composition Functions]({{[}}) for more
complex or programmatic modifications.
{{]}}
A Composition [patch](#create-a-patch) is the action of changing a field.
A Composition [transform](#transform-a-patch) modifies the values before
applying the patch.
## Create a patch
Patches are part of an individual
{{}}resource{{}} inside a
{{}}Composition{{}}.
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 a composite resource or Composition differently
depending on the patch type, but all patches reference a
{{}}fromFieldPath{{}} and
{{}}toFieldPath{{}}.
The {{}}fromFieldPath{{}} defines
the patch's input values.
The {{}}toFieldPath{{}} defines the
data to change with a patch.
Here is an example patch applied to a resource in a Composition.
```yaml {label="createComp",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
spec:
resources:
- name: my-composed-resource
base:
# Removed for brevity
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](https://kubernetes.io/docs/reference/kubectl/jsonpath/),
called "field selectors."
Field selectors can select any field in a composite resource or managed resource
object, including the `metadata`, `spec` or `status` fields.
Field selectors 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 selectors
Here are some example selectors from a composite resource object.
{{
}}
| 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{{}} |
{{
}}
```yaml {label="select",copy-lines="none"}
$ 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
# Removed for brevity
```
## Reuse a patch
A Composition can reuse a patch object on multiple resources with a
PatchSet.
To create a PatchSet, define a
{{}}PatchSets{{}} object inside the
Composition's
{{}}spec{{}}.
Each patch inside a PatchSet has a
{{}}name{{}} and a list of
{{}}patches{{}}.
{{}}
For multiple PatchSets only use a single
{{}}PatchSets{{}} object.
Identify each unique PatchSet with a unique
{{}}name{{}}.
{{}}
Apply the PatchSet to a resource with a patch
{{}}type: PatchSet{{}}.
Set the
{{}}patchSetName{{}} to the
{{}}name{{}} of the PatchSet.
```yaml {label="patchset"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
spec:
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
```
{{}}
A PatchSet can't contain other PatchSets.
Crossplane ignores any [transforms](#transform-a-patch) or
[policies](#patch-policies) in a PatchSet.
{{< /hint >}}
## Patching between resources
Compositions can't directly patch between resources in the same Composition.
For example, generating a network resource and patching the resource name to
a compute resource.
{{}}
The [ToEnvironmentFieldPath](#toenvironmentfieldpath) patch can't read from a
`Status` field.
{{< /hint >}}
A resource can patch to a user-defined
{{}}Status{{}}
field in the composite resource.
A 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{{}}
```yaml {label="xrdPatch",copy-lines="13-17"}
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 Composition 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.
```yaml {label="patchBetween",copy-lines="9-11"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
- 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.
```yaml {label="descCompPatch",copy-lines="none"}
$ 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{{}}.
```yaml {label="bucketlabel",copy-lines="none"}
$ 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
```
## Types of patches
Crossplane supports multiple patch types, each using a different source for data
and applying the patch to a different location.
{{}}
This section describes patches applied to individual resources inside a
Composition.
For information about applying patches to an entire composite resource with a
Composition's `environment.patches` read the
[Environment Configurations]({{[}}) documentation.
{{< /hint >}}
Summary of Crossplane patches
{{< table "table table-hover" >}}
| Patch Type | Data Source | Data Destination |
| --- | --- | --- |
| [FromCompositeFieldPath](#fromcompositefieldpath) | A field in the composite resource. | A field in the patched managed resource. |
| [ToCompositeFieldPath](#tocompositefieldpath) | A field in the patched managed resource. | A field in the composite resource. |
| [CombineFromComposite](#combinefromcomposite) | Multiple fields in the composite resource. | A field in the patched managed resource. |
| [CombineToComposite](#combinetocomposite) | Multiple fields in the patched managed resource. | A field in the composite resource. |
| [FromEnvironmentFieldPath](#fromenvironmentfieldpath) | Data in the in-memory EnvironmentConfig Environment | A field in the patched managed resource. |
| [ToEnvironmentFieldPath](#toenvironmentfieldpath) | A field in the patched managed resource. | The in-memory EnvironmentConfig Environment. |
| [CombineFromEnvironment](#combinefromenvironment) | Multiple fields in the in-memory EnvironmentConfig Environment. | A field in the patched managed resource. |
| [CombineToEnvironment](#combinetoenvironment) | Multiple fields in the patched managed resource. | A field in the in-memory EnvironmentConfig Environment. |
{{< /table >}}
{{}}
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](https://marketplace.upbound.io/providers/upbound/provider-aws-s3/)
to create resources.
{{< expand "Reference Composition" >}}
```yaml {copy-lines="all"}
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
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 >}}
{{}}
```yaml {copy-lines="all"}
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" >}}
```yaml {copy-lines="all"}
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" >}}
```yaml {copy-lines="all"}
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
managed 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 managed resource to change.
```yaml {label="fromComposite",copy-lines="9-11"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
- 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{{}}
```yaml {label="fromCompMR",copy-lines="1"}
$ 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 managed resource to
the composite resource that created it.
{{< hint "tip" >}}
Use {{}}ToCompositeFieldPath{{}}
patches to take data from one managed resource in a Composition and use it in a
second managed 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.
```yaml {label="toComposite",copy-lines="9-11"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
- 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.
```yaml {label="toCompMR",copy-lines="none"}
$ 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{{}}
```yaml {label="toCompositeXR",copy-lines="none"}
$ kubectl describe composite
Name: my-example-claim-p5pxf
Labels: ZoneID=Z2O1EMRO9K5GLX
```
{{}}
Crossplane doesn't apply the patch to the composite resource until the next
reconcile loop, after creating the managed resource. This creates a delay
between a managed resource being Ready and applying the patch.
{{< /hint >}}
### CombineFromComposite
The
{{}}CombineFromComposite{{}}
patch takes values from the composite resource, combines them and applies them
to the managed resource.
{{< hint "tip" >}}
Use the
{{}}CombineFromComposite{{}}
patch to create complex strings, like security policies and apply them to
a managed 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](https://pkg.go.dev/fmt) to specify how to combine the
strings.
The {{}}toFieldPath{{}} is the
field in the managed resource to apply the new string to.
```yaml {label="combineFromComp",copy-lines="11-20"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
- 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.
```yaml {label="describeCombineFromComp",copy-lines="none"}
$ kubectl describe bucket
Name: my-resource-eu-north-1-field2-text
```
### CombineToComposite
The
{{}}CombineToComposite{{}}
patch takes values from the managed resource, combines them and applies them
to the composite resource.
{{}}
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](https://pkg.go.dev/fmt) to specify how to combine the
strings.
The {{}}toFieldPath{{}} is the
field in the composite resource to apply the new string to.
```yaml {label="combineToComposite",copy-lines="9-11"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
- 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.
```yaml {copy-lines="none"}
$ 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
{{}}
EnvironmentConfigs are an alpha feature. They aren't enabled by default.
For more information about using an EnvironmentConfig, read the
[EnvironmentConfigs]({{][}}) documentation.
{{< /hint >}}
The
{{}}FromEnvironmentFieldPath{{}}
patch takes values from the in-memory EnvironmentConfig environment and applies
them to the managed resource.
{{}}
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{{}}.
```yaml {label="fromEnvField",copy-lines="9-11"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
- 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.
```yaml {copy-lines="none"}
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
{{}}
EnvironmentConfigs are an alpha feature. They aren't enabled by default.
For more information about using an EnvironmentConfig, read the
[EnvironmentConfigs]({{][}}) documentation.
{{< /hint >}}
The
{{}}ToEnvironmentFieldPath{{}}
patch takes values the managed resource and applies them to the in-memory
EnvironmentConfig environment.
{{}}
Use
{{}}ToEnvironmentFieldPath{{}}
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{{}}.
```yaml {label="toEnvField",copy-lines="9-11"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
- 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
{{}}
EnvironmentConfigs are an alpha feature. They aren't enabled by default.
For more information about using an EnvironmentConfig, read the
[EnvironmentConfigs]({{][}}) documentation.
{{< /hint >}}
The
{{}}CombineFromEnvironment{{}}
patch combines multiple values from the in-memory EnvironmentConfig environment and applies
them to the managed resource.
{{}}
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](https://pkg.go.dev/fmt) to specify how to combine the
strings.
The {{}}toFieldPath{{}} is the
field in the managed resource to apply the new string to.
```yaml {label="combineFromEnv",copy-lines="11-20"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
- 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{{}}.
```yaml {copy-lines="none",label="combineFromEnvDesc"}
$ kubectl describe bucket
Name: my-example-claim-zmxdg-grl6p
# Removed for brevity
Annotations: EnvironmentPatch: value1-value2
# Removed for brevity
```
### CombineToEnvironment
{{}}
EnvironmentConfigs are an alpha feature. They aren't enabled by default.
For more information about using an EnvironmentConfig, read the
[EnvironmentConfigs]({{][}}) documentation.
{{< /hint >}}
The
{{}}CombineToEnvironment{{}}
patch combines multiple values from the managed resource and applies them to the in-memory EnvironmentConfig environment.
{{}}
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](https://pkg.go.dev/fmt) to specify how to combine the
strings.
The {{}}toFieldPath{{}} is the
key in the environment to write the new string to.
```yaml {label="combineToEnv",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
- 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](#convert-transforms) | Converts an input data type to a different type. Also called "casting." |
| [map](#map-transforms) | Selects a specific output based on a specific input. |
| [match](#match-transform) | Selects a specific output based on a string or regular expression. |
| [math](#math-transforms) | Applies a mathematical operation on the input. |
| [string](#string-transforms) | Change the input string using [Go string formatting](https://pkg.go.dev/fmt). |
{{< /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.
```yaml {label="transform1",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
- 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.
```yaml {label="convert",copy-lines="none"}
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.
{{}}
Refer to the [Go language docs](https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#Quantity)
for a full list of supported suffixes.
{{}}
Add {{}}format: quantity{{}} to the
{{}}convert{{}} object to enable quantity
suffix support.
```yaml {label="format",copy-lines="all"}
- 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.
```yaml {label="object",copy-lines="all"}
- 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{{}}:
```yaml {label="patch-key",copy-lines="all"}
- 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.
```yaml {label="array",copy-lines="all"}
- 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{{}}.
{{}}
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{{}}.
```yaml {label="map",copy-lines="none"}
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{{}}.
```yaml {label="comositeMap",copy-lines="none"}
$ kubectl describe composite
Name: my-example-claim-twx7n
Spec:
# Removed for brevity
field1: field1-text
```
The annotation applied to the managed resource is
{{}}firstField{{}}.
```yaml {label="mrMap",copy-lines="none"}
$ 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.
```yaml {label="match",copy-lines="1-8"}
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.
{{}}
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{{}}.
```yaml {label="matchLiteral"}
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{{}}.
```yaml {label="matchRegex"}
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{{}}
```yaml {label="defaultValue"}
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.
```yaml {label="defaultInput"}
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.
{{}}
A {{}}math{{}} transform only supports
integer inputs.
{{< /hint >}}
```yaml {label="math",copy-lines="1-7"}
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{{}}.
```yaml {label="clampMin"}
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{{}}.
```yaml {label="clampMax"}
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{{}}
```yaml {label="multiply"}
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.numberField
toFieldPath: metadata.annotations["mathAnnotation"]
transforms:
- type: math
math:
type: multiply
multiply: 2
```
{{}}
The {{}}multiply{{}} value only
supports integers.
{{< /hint >}}
### String transforms
The {{}}string{{}} transform applies
string formatting or manipulation to string inputs.
```yaml {label="string"}
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.field1
toFieldPath: metadata.annotations["stringAnnotation"]
transforms:
- type: string
string:
type: ...
```
String transforms support the following
{{}}types{{}}
* [Convert](#string-convert)
* [Format](#string-format)
* [Join](#join)
* [Regexp](#regular-expression-type)
* [TrimPrefix](#trim-prefix)
* [TrimSuffix](#trim-suffix)
#### 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.
```yaml {label="stringConvert"}
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](https://pkg.go.dev/fmt) to the input.
```yaml {label="typeFormat"}
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.
```yaml {label="typeJoin"}
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.
```yaml {label="typeRegex"}
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](https://pkg.go.dev/strings#TrimPrefix) and removes characters
from the beginning of a line.
```yaml {label="typeTrimP"}
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](https://pkg.go.dev/strings#TrimSuffix) and removes characters
from the end of a line.
```yaml {label="typeTrimS"}
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:
* `fromFieldPath`
* `mergeOptions`
### fromFieldPath policy
Using a `fromFieldPath: Required` policy on a patch requires the
`fromFieldPath` to exist in the composite resource.
{{}}
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.
```yaml {label="required"}
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.desiredRegion
toFieldPath: metadata.annotations["eu"]
policy:
fromFieldPath: Required
```
### Merge options
By default when applying a patch the destination data is overridden. Use
{{}}mergeOptions{{}} to allow patches to
merge arrays and objects without overwriting them.
With an array input, use
{{}}appendSlice: true{{}} to append the
array data to the end of the existing array.
With an object, use
{{}}keepMapValues: true{{}} to leave
existing object keys in tact. The patch updates any matching keys between the
input and destination data.
```yaml {label="merge"}
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.desiredRegion
toFieldPath: metadata.annotations["eu"]
policy:
mergeOptions:
appendSlice: true
keepMapValues: true
```
]