mirror of https://github.com/crossplane/docs.git
2069 lines
57 KiB
Markdown
2069 lines
57 KiB
Markdown
---
|
|
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.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 >}}
|
|
|
|
{{<expand "Confused about Compositions, XRDs and XRs?" >}}
|
|
Crossplane has four core components that users commonly mix up:
|
|
|
|
* [Composition]({{<ref "../concepts/compositions">}}) - A template to define
|
|
how to create resources.
|
|
* [composite resource Definition]({{<ref "../concepts/composite-resource-definitions">}})
|
|
(`XRD`) - A custom API specification.
|
|
* [composite resource]({{<ref "../concepts/composite-resources">}}) (`XR`) -
|
|
Created by using the custom API defined in a composite resource Definition.
|
|
XRs use the Composition template to create new managed resources.
|
|
{{</expand >}}
|
|
|
|
## 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 "../concepts/compositions">}}) to learn more
|
|
about Compositions and composition functions.
|
|
{{< /hint >}}
|
|
|
|
|
|
## Resource templates
|
|
|
|
The `resources` field the function's input defines the set of things that a
|
|
composite resource creates when it uses this function.
|
|
|
|
For example, the input can define a template to create a virtual machine and an
|
|
associated storage bucket at the same time.
|
|
|
|
{{<hint "tip" >}}
|
|
Crossplane calls the resources a composite resource creates
|
|
_composed resources_.
|
|
{{< /hint >}}
|
|
|
|
The `resources` field lists the individual resources with a `name`. This name
|
|
identifies the resource inside the Composition. It isn't related to the external
|
|
name used with the Provider.
|
|
|
|
The contents of the `base` are identical to creating a standalone
|
|
[managed resource]({{<ref "../concepts/managed-resources">}}).
|
|
|
|
This example uses
|
|
[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.upbound.io/v1beta1
|
|
kind: Bucket
|
|
spec:
|
|
forProvider:
|
|
region: "us-east-2"
|
|
- name: vm
|
|
base:
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: Instance
|
|
spec:
|
|
forProvider:
|
|
ami: ami-0d9858aa3c6322f73
|
|
instanceType: t2.micro
|
|
region: "us-east-2"
|
|
```
|
|
|
|
When a [composite resource]({{<ref "../concepts/composite-resources" >}}) uses
|
|
this function, the composite resource creates two new managed resources with all
|
|
the provided `spec.forProvider` settings.
|
|
|
|
The `spec` supports any settings used in a managed resource, including applying
|
|
`annotations` and `labels` or using a specific `providerConfigRef`.
|
|
|
|
{{<hint "note" >}}
|
|
Use the `crossplane.io/external-name` annotation on the resource to set
|
|
the resource's name in the external system (like AWS).
|
|
{{< /hint >}}
|
|
|
|
{{<hint "tip" >}}
|
|
You can use Function Patch and Transform to template other kinds of Crossplane
|
|
resources, like ProviderConfigs.
|
|
|
|
You can also template other kinds of composite resource (XR).
|
|
|
|
You can't template namespaced resources.
|
|
{{< /hint >}}
|
|
|
|
## Create a patch
|
|
|
|
Each entry in the `resources` list can include a list of patches. The `patches`
|
|
field takes a list of patches to apply to the individual resource.
|
|
|
|
Each patch has a `type`, which defines what kind of patch action Crossplane
|
|
applies.
|
|
|
|
Patches reference fields inside different resources depending on the patch type,
|
|
but all patches reference a `fromFieldPath` and `toFieldPath`.
|
|
|
|
The `fromFieldPath` is the path to the patch's input values. The `toFieldPath`
|
|
is the path the patch applies to.
|
|
|
|
Here's an example of a patch that copies a value from the composite resource's
|
|
`spec.field1` field to the composed Bucket's labels.
|
|
|
|
```yaml {label="createComp",copy-lines="none"}
|
|
apiVersion: pt.fn.crossplane.io/v1beta1
|
|
kind: Resources
|
|
resources:
|
|
- name: storage-bucket
|
|
base:
|
|
apiVersion: s3.aws.upbound.io/v1beta1
|
|
kind: Bucket
|
|
spec:
|
|
forProvider:
|
|
region: "us-east-2"
|
|
patches:
|
|
- type: FromCompositeFieldPath
|
|
fromFieldPath: spec.field1
|
|
toFieldPath: metadata.labels["patchLabel"]
|
|
```
|
|
|
|
### Selecting fields
|
|
|
|
Crossplane selects fields in a composite resource or managed resource with a
|
|
subset of [JSONPath selectors](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: XExample
|
|
metadata:
|
|
# Removed for brevity
|
|
labels:
|
|
crossplane.io/composite: my-example-978mh
|
|
spec:
|
|
desiredRegion: eu-north-1
|
|
field1: field1-text
|
|
resourceRefs:
|
|
- apiVersion: s3.aws.upbound.io/v1beta1
|
|
kind: Bucket
|
|
name: my-example-978mh-r6z64
|
|
- apiVersion: s3.aws.upbound.io/v1beta1
|
|
kind: Bucket
|
|
name: my-example-978mh-cnlhj
|
|
- apiVersion: s3.aws.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.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-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 "../concepts/environment-configs" >}}) page
|
|
for more information on using EnvironmentConfigs.
|
|
{{< /hint >}}
|
|
|
|
To apply a patch using EnvironmentConfigs, first define which EnvironmentConfigs
|
|
to use with
|
|
`environment.environmentConfigs`.
|
|
|
|
<!-- vale Google.Quotes = NO -->
|
|
<!-- vale gitlab.SentenceLength = NO -->
|
|
<!-- ignore false positive -->
|
|
Use either a
|
|
[reference]({{<ref "../concepts/managed-resources#matching-by-name-reference" >}})
|
|
or a [selector]({{<ref "../concepts/managed-resources#matching-by-selector" >}}) to
|
|
identify the EnvironmentConfigs to use.
|
|
<!-- 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.upbound.io/v1beta1
|
|
kind: VPC
|
|
spec:
|
|
forProvider:
|
|
cidrBlock: 172.16.0.0/16
|
|
patches:
|
|
- type: ToEnvironmentFieldPath
|
|
fromFieldPath: status.atProvider.id
|
|
toFieldPath: vpcId
|
|
- type: FromEnvironmentFieldPath
|
|
fromFieldPath: tags
|
|
toFieldPath: spec.forProvider.tags
|
|
```
|
|
|
|
The [EnvironmentConfigs]({{<ref "../concepts/environment-configs" >}}) page has
|
|
more information on EnvironmentConfigs options and usage.
|
|
|
|
## Types of patches
|
|
Function Patch and Transform supports multiple patch types, each using a
|
|
different source for data and applying the patch to a different location.
|
|
|
|
Summary of Crossplane patches
|
|
{{< table "table table-hover" >}}
|
|
| Patch Type | Data Source | Data Destination |
|
|
| --- | --- | --- |
|
|
| [FromCompositeFieldPath](#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: xExample
|
|
environment:
|
|
environmentConfigs:
|
|
- ref:
|
|
name: example-environment
|
|
mode: Pipeline
|
|
pipeline:
|
|
- step: patch-and-transform
|
|
functionRef:
|
|
name: function-patch-and-transform
|
|
input:
|
|
apiVersion: pt.fn.crossplane.io/v1beta1
|
|
kind: Resources
|
|
resources:
|
|
- name: bucket1
|
|
base:
|
|
apiVersion: s3.aws.upbound.io/v1beta1
|
|
kind: Bucket
|
|
spec:
|
|
forProvider:
|
|
region: us-east-2
|
|
- name: bucket2
|
|
base:
|
|
apiVersion: s3.aws.upbound.io/v1beta1
|
|
kind: Bucket
|
|
spec:
|
|
forProvider:
|
|
region: us-east-2
|
|
```
|
|
{{< /expand >}}
|
|
|
|
{{<expand "Reference CompositeResourceDefinition" >}}
|
|
```yaml {copy-lines="all"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: CompositeResourceDefinition
|
|
metadata:
|
|
name: xexamples.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.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.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.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.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: xExample
|
|
# 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 -->
|
|
|
|
{{<hint "important" >}}
|
|
EnvironmentConfigs are an alpha feature. They aren't enabled by default.
|
|
|
|
For more information about using an EnvironmentConfig, read the
|
|
[EnvironmentConfigs documentation]({{<ref "../concepts/environment-configs">}}).
|
|
{{< /hint >}}
|
|
|
|
The `FromEnvironmentFieldPath` patch takes values from the in-memory environment
|
|
and applies them to the composed resource.
|
|
|
|
{{<hint "tip" >}}
|
|
Use `FromEnvironmentFieldPath` to apply custom managed resource settings based
|
|
on the current environment.
|
|
{{< /hint >}}
|
|
|
|
For example, use the environment's `locations.eu` value and apply it as the
|
|
`region`.
|
|
|
|
```yaml {label="fromEnvField",copy-lines="9-11"}
|
|
apiVersion: pt.fn.crossplane.io/v1beta1
|
|
kind: Resources
|
|
resources:
|
|
- name: bucket1
|
|
base:
|
|
apiVersion: s3.aws.upbound.io/v1beta1
|
|
kind: Bucket
|
|
spec:
|
|
forProvider:
|
|
region: us-east-2
|
|
patches:
|
|
- type: FromEnvironmentFieldPath
|
|
fromFieldPath: locations.eu
|
|
toFieldPath: spec.forProvider.region
|
|
```
|
|
|
|
Verify managed resource to confirm the applied patch.
|
|
|
|
```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 "../concepts/environment-configs">}}).
|
|
{{< /hint >}}
|
|
|
|
The `ToEnvironmentFieldPath` patch takes a value from the composed resource and
|
|
applies it to the in-memory environment.
|
|
|
|
{{<hint "tip" >}}
|
|
Use `ToEnvironmentFieldPath` to write data to the environment that any
|
|
FromEnvironmentFieldPath patch can access.
|
|
{{< /hint >}}
|
|
|
|
For example, use the desired `region` value and apply it as the environment's
|
|
`key1`.
|
|
|
|
|
|
```yaml {label="toEnvField",copy-lines="9-11"}
|
|
apiVersion: pt.fn.crossplane.io/v1beta1
|
|
kind: Resources
|
|
resources:
|
|
- name: bucket1
|
|
base:
|
|
apiVersion: s3.aws.upbound.io/v1beta1
|
|
kind: Bucket
|
|
spec:
|
|
forProvider:
|
|
region: us-east-2
|
|
patches:
|
|
- type: ToEnvironmentFieldPath
|
|
fromFieldPath: spec.forProvider.region
|
|
toFieldPath: key1
|
|
```
|
|
|
|
Because the environment is in-memory, there is no command to confirm the patch
|
|
wrote the value to the environment.
|
|
|
|
|
|
<!-- vale Google.Headings = NO -->
|
|
### CombineFromEnvironment
|
|
<!-- vale Google.Headings = YES -->
|
|
|
|
{{<hint "important" >}}
|
|
For more information about using an EnvironmentConfig, read the
|
|
[EnvironmentConfigs documentation]({{<ref "../concepts/environment-configs">}}).
|
|
{{< /hint >}}
|
|
|
|
The `CombineFromEnvironment` patch combines multiple values from the in-memory
|
|
environment and applies them to the composed resource.
|
|
|
|
{{<hint "tip" >}}
|
|
Use `CombineFromEnvironment` patch to create complex strings, like security
|
|
policies and apply them to a managed resource.
|
|
{{< /hint >}}
|
|
|
|
For example, combine multiple fields in the environment to create a unique
|
|
`annotation` .
|
|
|
|
The `CombineFromEnvironment` patch only supports the `combine` option.
|
|
|
|
The only supported `strategy` is `strategy: string`.
|
|
|
|
The `variables` are the list of `fromFieldPath` values from the in-memory
|
|
environment to combine.
|
|
|
|
Optionally you can apply a `string.fmt`, based on
|
|
[Go string formatting](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.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 "../concepts/environment-configs">}}).
|
|
{{< /hint >}}
|
|
|
|
The `CombineToEnvironment` patch combines multiple values from the composed
|
|
resource and applies them to the in-memory EnvironmentConfig environment.
|
|
|
|
{{<hint "tip" >}}
|
|
Use `CombineToEnvironment` patch to create complex strings, like security
|
|
policies to use in other managed resources.
|
|
{{< /hint >}}
|
|
|
|
For example, combine multiple fields in the managed resource to create a unique
|
|
string and store it in the environment's `key2` value.
|
|
|
|
The string combines the managed resource `Kind` and `region`.
|
|
|
|
The `CombineToEnvironment` patch only supports the `combine` option.
|
|
|
|
The only supported `strategy` is `strategy: string`.
|
|
|
|
The `variables` are the list of `fromFieldPath` values in the managed resource
|
|
to combine.
|
|
|
|
Optionally you can apply a `string.fmt`, based on
|
|
[Go string formatting](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.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.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:
|
|
writeConnectionSecretsToNamespace: other-namespace
|
|
mode: Pipeline
|
|
pipeline:
|
|
- step: patch-and-transform
|
|
functionRef:
|
|
name: function-patch-and-transform
|
|
input:
|
|
apiVersion: pt.fn.crossplane.io/v1beta1
|
|
kind: Resources
|
|
resources:
|
|
- name: key
|
|
base:
|
|
# Removed for brevity
|
|
spec:
|
|
forProvider:
|
|
# Removed for brevity
|
|
writeConnectionSecretToRef:
|
|
namespace: docs
|
|
name: key1
|
|
connectionDetails:
|
|
- name: my-username
|
|
type: FromConnectionSecretKey
|
|
fromConnectionSecretKey: username
|
|
- name: my-field-secret
|
|
type: FromFieldPath
|
|
fromFieldPath: spec.forProvider.user
|
|
- name: my-status-secret
|
|
type: FromValue
|
|
value: "docs.crossplane.io"
|
|
```
|
|
|
|
The `connectionDetails` in a resource can reference a secret from a resource
|
|
with `FromConnectionSecretKey`, from another field in the resource with
|
|
`FromFieldPath` or a statically defined value with `FromValue`.
|
|
|
|
Crossplane sets the secret key to the `name` value.
|
|
|
|
Describe the secret to view the secret keys inside the secret object.
|
|
|
|
{{<hint "tip" >}}
|
|
If more than one resource generates secrets with the same secret key name,
|
|
Crossplane only saves one value.
|
|
|
|
Use a custom `name` to create unique secret keys.
|
|
{{< /hint >}}
|
|
|
|
{{<hint "important">}}
|
|
Crossplane only adds connection details listed in the `connectionDetails` to the
|
|
combined secret object.
|
|
|
|
Any connection secrets in a managed resource, not defined in the
|
|
`connectionDetails` aren't added to the combined secret object.
|
|
{{< /hint >}}
|
|
|
|
|
|
```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.
|
|
|
|
Read the
|
|
[CompositeResourceDefinition documentation]({{<ref "../concepts/composite-resource-definitions#manage-connection-secrets">}})
|
|
for more information on restricting secret keys.
|
|
{{< /hint >}}
|
|
|
|
For more information on connection secrets read the
|
|
[Connection Secrets concepts age]({{<ref "../concepts/connection-details">}}).
|
|
|
|
## Resource readiness checks
|
|
|
|
By default 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 >}}
|