---
title: Function Patch and Transform
weight: 70
description: "A function that use patches and transforms to modify inputs from 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
composite resource (XR).

A [patch](#create-a-patch) copies a value from one resource and _patches_ it
onto another resource. A [transform](#transform-a-patch) 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.

```yaml {label="intro"}
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.m.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.
{{</hint >}}

## 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:

```yaml
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
  name: function-patch-and-transform
spec:
  package: xpkg.crossplane.io/crossplane-contrib/function-patch-and-transform:v0.8.2
```

{{<hint "tip" >}}
Read the [Composition page]({{<ref "../composition/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 "../managed-resources/managed-resources">}}).

This example uses
[provider-upjet-aws](https://github.com/crossplane-contrib/provider-upjet-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.

```yaml {copy-lines="none",label="resources"}
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: storage-bucket
  base:
    apiVersion: s3.aws.m.upbound.io/v1beta1
    kind: Bucket
    spec:
      forProvider:
        region: "us-east-2"
- name: vm
  base:
    apiVersion: ec2.aws.m.upbound.io/v1beta1
    kind: Instance
    spec:
      forProvider:
        ami: ami-0d9858aa3c6322f73
        instanceType: t2.micro
        region: "us-east-2"
```

When a [composite resource]({{<ref "../composition/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 any kind of Kubernetes
resource.
{{< /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.

```yaml {label="createComp",copy-lines="none"}
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: storage-bucket
  base:
    apiVersion: s3.aws.m.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](https://kubernetes.io/docs/reference/kubectl/jsonpath/),
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` |
| `spec.desiredRegion` | `eu-north-1` |
| `spec.resourceRefs[0].name` | `my-example-978mh-r6z64` |
{{</table >}}

```yaml {label="select",copy-lines="none"}
$ kubectl get composite -o yaml
apiVersion: example.org/v1alpha1
kind: Example
metadata:
  # Removed for brevity
  labels:
    crossplane.io/composite: my-example-978mh
spec:
  desiredRegion: eu-north-1
  field1: field1-text
  crossplane:
    resourceRefs:
    - apiVersion: s3.aws.m.upbound.io/v1beta1
      kind: Bucket
      name: my-example-978mh-r6z64
    - apiVersion: s3.aws.m.upbound.io/v1beta1
      kind: Bucket
      name: my-example-978mh-cnlhj
    - apiVersion: s3.aws.m.upbound.io/v1beta1
      kind: Bucket
      name: my-example-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.

```yaml {label="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](#transform-a-patch) or
[policies](#patch-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`

```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 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.

```yaml {label="patchBetween",copy-lines="9-11"}
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
  base:
    apiVersion: s3.aws.m.upbound.io/v1beta1
    kind: Bucket
    # Removed for brevity
  patches:
    - type: ToCompositeFieldPath
      fromFieldPath: metadata.name
      toFieldPath: status.secondResource
- name: bucket2
  base:
    apiVersion: s3.aws.m.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-jp7rx
Spec:
  # Removed for brevity
  Resource Refs:
    Name:         my-example-jp7rx-gfg4m
    # Removed for brevity
    Name:         my-example-jp7rx-fttpj
Status:
  # Removed for brevity
  Second Resource:         my-example-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-jp7rx-fttpj
Name:         my-example-jp7rx-fttpj
Labels:       crossplane.io/composite=my-example-jp7rx
              secondResource=my-example-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.

 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.

<!-- vale off -->
{{< hint "note" >}}
<!-- vale on -->
Read the [EnvironmentConfigs]({{<ref "../composition/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`.

<!-- vale Google.Quotes = NO -->
<!-- vale gitlab.SentenceLength = NO -->
<!-- ignore false positive -->
Use either a
[reference]({{<ref "../managed-resources/managed-resources#matching-by-name-reference" >}})
or a [selector]({{<ref "../managed-resources/managed-resources#matching-by-selector" >}}) to
identify the EnvironmentConfigs to use.
<!-- vale Google.Quotes = YES -->

```yaml {label="envselect",copy-lines="none"}
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.

```yaml {label="xrpatch",copy-lines="none"}
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.

```yaml {label="envpatch",copy-lines="none"}
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: vpc
  base:
    apiVersion: ec2.aws.m.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 "../composition/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](#fromcompositefieldpath) | A field in the composite resource. | A field in the composed resource. |
| [ToCompositeFieldPath](#tocompositefieldpath) | A field in the composed resource. | A field in the composite resource. |
| [CombineFromComposite](#combinefromcomposite) | Multiple fields in the composite resource. | A field in the composed resource. |
| [CombineToComposite](#combinetocomposite) | Multiple fields in the composed resource. | A field in the composite resource. |
| [FromEnvironmentFieldPath](#fromenvironmentfieldpath) | Data in the in-memory environment | A field in the composed resource. |
| [ToEnvironmentFieldPath](#toenvironmentfieldpath) | A field in the composed resource. | The in-memory environment. |
| [CombineFromEnvironment](#combinefromenvironment) | Multiple fields in the in-memory environment. | A field in the composed resource. |
| [CombineToEnvironment](#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 and EnvironmentConfigs.
Only the applied patches change between examples.

All examples rely on
[provider-aws-s3](https://github.com/crossplane-contrib/provider-upjet-aws)
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: Example
  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.m.upbound.io/v1beta1
          kind: Bucket
          spec:
            forProvider:
              region: us-east-2
      - name: bucket2
        base:
          apiVersion: s3.aws.m.upbound.io/v1beta1
          kind: Bucket
          spec:
            forProvider:
              region: us-east-2
```
{{< /expand >}}

{{<expand "Reference CompositeResourceDefinition" >}}
```yaml {copy-lines="all"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
  name: examples.example.org
spec:
  group: example.org
  names:
    kind: Example
    plural: examples
  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 XR" >}}
```yaml {copy-lines="all"}
apiVersion: example.org/v1alpha1
kind: Example
metadata:
  namespace: default
  name: my-example
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/v1beta1
kind: EnvironmentConfig
metadata:
  name: example-environment
data:
  locations:
    us: us-east-2
    eu: eu-north-1
  key1: value1
  key2: value2

```
{{< /expand >}}
{{< /hint >}}

<!-- vale Google.Headings = NO -->
### FromCompositeFieldPath
<!-- vale Google.Headings = YES -->

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 XRs
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.

```yaml {label="fromComposite",copy-lines="9-11"}
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
  base:
    apiVersion: s3.aws.m.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-qlr68-29nqf
# Removed for brevity
Spec:
  For Provider:
    Region:  eu-north-1
```

<!-- vale Google.Headings = NO -->
### ToCompositeFieldPath
<!-- vale Google.Headings = YES -->

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.

```yaml {label="toComposite",copy-lines="9-11"}
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
  base:
    apiVersion: s3.aws.m.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-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-p5pxf
Labels:       ZoneID=Z2O1EMRO9K5GLX
```

<!-- vale Google.Headings = NO -->
### CombineFromComposite
<!-- vale Google.Headings = YES -->

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 XR 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 composed resource to apply the new string
to.

```yaml {label="combineFromComp",copy-lines="11-20"}
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
  base:
    apiVersion: s3.aws.m.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
```

<!-- vale Google.Headings = NO -->
### CombineToComposite
<!-- vale Google.Headings = YES -->

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](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: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
  base:
    apiVersion: s3.aws.m.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-bjdjw
API Version:  example.org/v1alpha1
Kind:         Example
# Removed for brevity
Status:
  # Removed for brevity
  URL:                     https://my-example-bjdjw-r6ncd.us-east-2.com
```

<!-- vale Google.Headings = NO -->
### FromEnvironmentFieldPath
<!-- vale Google.Headings = YES -->

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`.

```yaml {label="fromEnvField",copy-lines="9-11"}
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
  base:
    apiVersion: s3.aws.m.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-8vrvc-xx5sr
# Removed for brevity
Spec:
  For Provider:
    Region:  eu-north-1
  # Removed for brevity
```

<!-- vale Google.Headings = NO -->
### ToEnvironmentFieldPath
<!-- vale Google.Headings = YES -->

{{<hint "important" >}}
For more information about using an EnvironmentConfig, read the
[EnvironmentConfigs documentation]({{<ref "../composition/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`.


```yaml {label="toEnvField",copy-lines="9-11"}
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
  base:
    apiVersion: s3.aws.m.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.


<!-- vale Google.Headings = NO -->
### CombineFromEnvironment
<!-- vale Google.Headings = YES -->

{{<hint "important" >}}
For more information about using an EnvironmentConfig, read the
[EnvironmentConfigs documentation]({{<ref "../composition/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](https://pkg.go.dev/fmt) to specify how to combine the
strings.

The `toFieldPath` is the field in the composed resource to apply the new string
to.

```yaml {label="combineFromEnv",copy-lines="11-20"}
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
  base:
    apiVersion: s3.aws.m.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-zmxdg-grl6p
# Removed for brevity
Annotations:  EnvironmentPatch: value1-value2
# Removed for brevity
```

<!-- vale Google.Headings = NO -->
### CombineToEnvironment
<!-- vale Google.Headings = YES -->

{{<hint "important" >}}
For more information about using an EnvironmentConfig, read the
[EnvironmentConfigs documentation]({{<ref "../composition/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](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: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
  base:
    apiVersion: s3.aws.m.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: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: bucket1
  base:
    apiVersion: s3.aws.m.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.

{{<hint "note" >}}
Refer to the [Go language docs](https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#Quantity)
for a full list of supported suffixes.
{{</hint >}}

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`.

{{<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`.

```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-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-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.

{{<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`.

```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.

{{<hint "important">}}
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:
          ...
```

<!-- vale Google.Headings = NO -->
#### clampMin
<!-- vale Google.Headings = YES -->

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
```

<!-- vale Google.Headings = NO -->
#### clampMax
<!-- vale Google.Headings = YES -->

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
```

<!-- vale Google.Headings = NO -->
#### Multiply
<!-- vale Google.Headings = YES -->

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
```

{{<hint "note" >}}
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`
* `toFieldPath`

<!-- vale Google.Headings = NO -->
### fromFieldPath policy
<!-- vale Google.Headings = YES -->

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.

```yaml {label="required"}
patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.desiredRegion
    toFieldPath: metadata.annotations["eu"]
    policy:
      fromFieldPath: Required
```

<!-- vale Google.Headings = NO -->
### toFieldPath policy
<!-- vale Google.Headings = YES -->

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 >}}

```yaml {label="merge"}
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 >}}

```yaml {label="conDeet",copy-lines="none"}
kind: Composition
spec:
  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 >}}


```shell {copy-lines="1"}
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.


For more information on connection secrets read about
[managed resources]({{<ref "../managed-resources/managed-resources">}}).
{{</hint>}}

## Resource readiness checks

By default function-patch-and-transform considers a composite resource 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 >}}

<!-- vale Google.WordList = NO -->
Define a custom readiness check with the `readinessChecks` field on a resource.
<!-- vale Google.WordList = YES -->

Checks have a `type` defining how to match the resource and a `fieldPath` of
which field in the resource to compare.

```yaml {label="check",copy-lines="none"}
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:
 * [string match](#match-a-string)
 * [integer match](#match-an-integer)
 * [non-empty match](#match-that-a-field-exists)
 * [always ready](#always-consider-a-resource-ready)
 * [condition match](#match-a-condition)
 * [boolean match](#match-a-boolean)

### 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" >}}
<!-- vale Google.WordList = NO -->
Crossplane only supports exact string matches. Substrings and regular
expressions aren't supported in a readiness check.
<!-- vale Google.WordList = YES -->
{{</hint >}}


For example, matching the string `Online` in the resource's
`status.atProvider.state` field.

```yaml {label="matchstring",copy-lines="none"}
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" >}}
<!-- vale Google.WordList = NO -->
Crossplane doesn't support matching `0`.
<!-- vale Google.WordList = YES -->
{{</hint >}}

For example, matching the number `4` in the resource's `status.atProvider.state`
field.

```yaml {label="matchint",copy-lines="none"}
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" >}}
<!-- vale Google.WordList = NO -->
Crossplane considers a value of `0` or an empty string as empty.
{{</hint >}}

For example, to check that a resource's `status.atProvider.state` field isn't
empty.
<!-- vale Google.WordList = YES -->

```yaml {label="NonEmpty",copy-lines="none"}
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.


```yaml {label="none",copy-lines="none"}
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`.

```yaml {label="condition",copy-lines="none"}
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:
 * `MatchTrue`
 * `MatchFalse`

`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`.

```yaml {label="matchTrue",copy-lines="none"}
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`.

```yaml {label="matchFalse",copy-lines="none"}
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 >}}
