Skip to content

Latest commit

 

History

History
1747 lines (1467 loc) · 53.9 KB

patch-and-transform.md

File metadata and controls

1747 lines (1467 loc) · 53.9 KB
title weight description
Patch and Transforms
70
Crossplane Compositions use patches and transforms to modify inputs from claims and composite resources before creating managed resources

Crossplane Compositions allow for "patch and transform" operations. With patches a Composition can apply changes to the resources defined by the Composition.

When users create Claims, Crossplane passes the settings in the Claim to the associated composite resource. Patches can use these settings to change the associated composite resource or managed resources.

Examples of using patch and transforms include:

  • changing the name of the external resource
  • mapping generic terms like "east" or "west" to specific provider locations
  • appending custom labels or strings to resource fields

{{<hint "note" >}}

Crossplane expects patch and transform operations to be simple changes.
Use [Composition Functions]({{<ref "./composition-functions">}}) for more complex or programmatic modifications.

{{}}

A Composition patch is the action of changing a field.
A Composition transform modifies the values before applying the patch.

Create a patch

Patches are part of an individual {{}}resource{{}} inside a {{}}Composition{{}}.

The {{}}patches{{}} field takes a list of patches to apply to the individual resource.

Each patch has a {{}}type{{}}, which defines what kind of patch action Crossplane applies.

Patches reference fields inside a composite resource or Composition differently depending on the patch type, but all patches reference a {{}}fromFieldPath{{}} and {{}}toFieldPath{{}}.

The {{}}fromFieldPath{{}} defines the patch's input values. The {{}}toFieldPath{{}} defines the data to change with a patch.

Here is an example patch applied to a resource in a Composition.

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
spec:
  resources:
    - name: my-composed-resource
      base:
        # Removed for brevity
      patches:
        - type: FromCompositeFieldPath
          fromFieldPath: spec.field1
          toFieldPath: metadata.labels["patchLabel"]

Selecting fields

Crossplane selects fields in a composite resource or managed resource with a subset of JSONPath selectors, called "field selectors."

Field selectors can select any field in a composite resource or managed resource object, including the metadata, spec or status fields.

Field selectors can be a string matching a field name or an array index, in brackets. Field names may use a . character to select child elements.

Example field selectors

Here are some example selectors from a composite resource object. {{<table "table" >}}

Selector Selected element
kind {{}}kind{{}}
metadata.labels['crossplane.io/claim-name'] {{}}my-example-claim{{}}
spec.desiredRegion {{}}eu-north-1{{}}
spec.resourceRefs[0].name {{}}my-example-claim-978mh-r6z64{{}}
{{
}}
$ kubectl get composite -o yaml
apiVersion: example.org/v1alpha1
kind: xExample
metadata:
  # Removed for brevity
  labels:
    crossplane.io/claim-name: my-example-claim
    crossplane.io/claim-namespace: default
    crossplane.io/composite: my-example-claim-978mh
spec:
  desiredRegion: eu-north-1
  field1: field1-text
  resourceRefs:
  - apiVersion: s3.aws.upbound.io/v1beta1
    kind: Bucket
    name: my-example-claim-978mh-r6z64
  - apiVersion: s3.aws.upbound.io/v1beta1
    kind: Bucket
    name: my-example-claim-978mh-cnlhj
  - apiVersion: s3.aws.upbound.io/v1beta1
    kind: Bucket
    name: my-example-claim-978mh-rv5nm
  # Removed for brevity

Reuse a patch

A Composition can reuse a patch object on multiple resources with a PatchSet.

To create a PatchSet, define a {{}}PatchSets{{}} object inside the Composition's {{}}spec{{}}.

Each patch inside a PatchSet has a {{}}name{{}} and a list of {{}}patches{{}}.

{{<hint "note" >}} For multiple PatchSets only use a single {{}}PatchSets{{}} object.

Identify each unique PatchSet with a unique {{}}name{{}}. {{}}

Apply the PatchSet to a resource with a patch {{}}type: PatchSet{{}}.
Set the {{}}patchSetName{{}} to the {{}}name{{}} of the PatchSet.

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
spec:
  patchSets:
  - name: my-patchset
    patches:
    - type: FromCompositeFieldPath
      fromFieldPath: spec.desiredRegion
      toFieldPath: spec.forProvider.region
  resources:
    - name: bucket1
      base:
        # Removed for brevity
      patches:
        - type: PatchSet
          patchSetName: my-patchset
    - name: bucket2
      base:
        # Removed for brevity
      patches:
        - type: PatchSet
          patchSetName: my-patchset  

{{<hint "important" >}} A PatchSet can't contain other PatchSets.

Crossplane ignores any transforms or policies in a PatchSet. {{< /hint >}}

Patching between resources

Compositions can't directly patch between resources in the same Composition.
For example, generating a network resource and patching the resource name to a compute resource.

{{<hint "important">}} The ToEnvironmentFieldPath patch can't read from a Status field. {{< /hint >}}

A resource can patch to a user-defined {{}}Status{{}} field in the composite resource.

A resource can then read from that {{}}Status{{}} field to patch a field.

First, define a custom {{}}Status{{}} in the Composite Resource Definition and a custom field, for example {{}}secondResource{{}}

kind: CompositeResourceDefinition
# Removed for brevity.
spec:
  # Removed for brevity.
  versions:
  - name: v1alpha1
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            # Removed for brevity.
          status:
              type: object
              properties:
                secondResource:
                  type: string

Inside the Composition the resource with the source data uses a {{}}ToCompositeFieldPath{{}} patch to write data to the {{}}status.secondResource{{}} field in the composite resource.

The destination resource uses a {{}}FromCompositeFieldPath{{}} patch to read data from the composite resource {{}}status.secondResource{{}} field in the composite resource and write it to a label named {{}}secondResource{{}} in the managed resource.

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
    - name: bucket1
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: Bucket
        # Removed for brevity
      patches:
        - type: ToCompositeFieldPath
          fromFieldPath: metadata.name
          toFieldPath: status.secondResource
    - name: bucket2
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: Bucket
        # Removed for brevity
      patches:
        - type: FromCompositeFieldPath
          fromFieldPath: status.secondResource
          toFieldPath: metadata.labels['secondResource']

Describe the composite resource to view the {{}}resources{{}} and the {{}}status.secondResource{{}} value.

$ kubectl describe composite
Name:         my-example-claim-jp7rx
Spec:
  # Removed for brevity
  Resource Refs:
    Name:         my-example-claim-jp7rx-gfg4m
    # Removed for brevity
    Name:         my-example-claim-jp7rx-fttpj
Status:
  # Removed for brevity
  Second Resource:         my-example-claim-jp7rx-gfg4m

Describe the destination managed resource to see the label {{}}secondResource{{}}.

$ kubectl describe bucket
kubectl describe bucket my-example-claim-jp7rx-fttpj
Name:         my-example-claim-jp7rx-fttpj
Labels:       crossplane.io/composite=my-example-claim-jp7rx
              secondResource=my-example-claim-jp7rx-gfg4m

Types of patches

Crossplane supports multiple patch types, each using a different source for data and applying the patch to a different location.

{{<hint "important" >}}

This section describes patches applied to individual resources inside a Composition.

For information about applying patches to an entire composite resource with a Composition's environment.patches read the [Environment Configurations]({{<ref "environment-configs" >}}) documentation.

{{< /hint >}}

Summary of Crossplane patches {{< table "table table-hover" >}}

Patch Type Data Source Data Destination
FromCompositeFieldPath A field in the composite resource. A field in the patched managed resource.
ToCompositeFieldPath A field in the patched managed resource. A field in the composite resource.
CombineFromComposite Multiple fields in the composite resource. A field in the patched managed resource.
CombineToComposite Multiple fields in the patched managed resource. A field in the composite resource.
FromEnvironmentFieldPath Data in the in-memory EnvironmentConfig Environment A field in the patched managed resource.
ToEnvironmentFieldPath A field in the patched managed resource. The in-memory EnvironmentConfig Environment.
CombineFromEnvironment Multiple fields in the in-memory EnvironmentConfig Environment. A field in the patched managed resource.
CombineToEnvironment Multiple fields in the patched managed resource. A field in the in-memory EnvironmentConfig Environment.
{{< /table >}}

{{<hint "note" >}} All the following examples use the same set of Compositions, CompositeResourceDefinitions, Claims and EnvironmentConfigs.
Only the applied patches change between examples.

All examples rely on Upbound provider-aws-s3 to create resources.

{{< expand "Reference Composition" >}}

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: example-composition
spec:
  compositeTypeRef:
    apiVersion: example.org/v1alpha1
    kind: xExample
  environment:
    environmentConfigs:
    - ref:
        name: example-environment
  resources:
    - name: bucket1
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: Bucket
        spec:
          forProvider:
            region: us-east-2
    - name: bucket2
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: Bucket
        spec:
          forProvider:
            region: us-east-2

{{< /expand >}}

{{<expand "Reference CompositeResourceDefinition" >}}

apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
  name: xexamples.example.org
spec:
  group: example.org
  names:
    kind: xExample
    plural: xexamples
  claimNames:
    kind: ExampleClaim
    plural: exampleclaims
  versions:
  - name: v1alpha1
    served: true
    referenceable: true
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              field1:
                type: string
              field2:
                type: string
              field3: 
                type: string
              desiredRegion: 
                type: string
              boolField:
                type: boolean
              numberField:
                type: integer
          status:
              type: object
              properties:
                url:
                  type: string

{{< /expand >}}

{{< expand "Reference Claim" >}}

apiVersion: example.org/v1alpha1
kind: ExampleClaim
metadata:
  name: my-example-claim
spec:
  field1: "field1-text"
  field2: "field2-text"
  desiredRegion: "eu-north-1"
  boolField: false
  numberField: 10

{{< /expand >}}

{{< expand "Reference EnvironmentConfig" >}}

apiVersion: apiextensions.crossplane.io/v1alpha1
kind: EnvironmentConfig
metadata:
  name: example-environment
data:
  locations:
    us: us-east-2
    eu: eu-north-1
  key1: value1
  key2: value2

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

FromCompositeFieldPath

The {{}}FromCompositeFieldPath{{}} patch takes a value in a composite resource and applies it to a field in the managed resource.

{{< hint "tip" >}} Use the {{}}FromCompositeFieldPath{{}} patch to apply options from users in their Claims to settings in managed resource forProvider settings. {{< /hint >}}

For example, to use the value {{}}desiredRegion{{}} provided by a user in a composite resource to a managed resource's {{}}region{{}}.

The {{}}fromFieldPath{{}} value is a field in the composite resource.

The {{}}toFieldPath{{}} value is the field in the managed resource to change.

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
    - name: bucket1
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: Bucket
        spec:
          forProvider:
            region: us-east-2
      patches:
        - type: FromCompositeFieldPath
          fromFieldPath: spec.desiredRegion
          toFieldPath: spec.forProvider.region

View the managed resource to see the updated {{}}region{{}}

$ kubectl describe bucket
Name:         my-example-claim-qlr68-29nqf
# Removed for brevity
Spec:
  For Provider:
    Region:  eu-north-1

ToCompositeFieldPath

The {{}}ToCompositeFieldPath{{}} writes data from an individual managed resource to the composite resource that created it.

{{< hint "tip" >}} Use {{}}ToCompositeFieldPath{{}} patches to take data from one managed resource in a Composition and use it in a second managed resource in the same Composition. {{< /hint >}}

For example, after Crossplane creates a new managed resource, take the value {{}}hostedZoneID{{}} and apply it as a {{}}label{{}} in the composite resource.

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
    - name: bucket1
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: Bucket
        spec:
          forProvider:
            region: us-east-2
      patches:
        - type: ToCompositeFieldPath
          fromFieldPath: status.atProvider.hostedZoneId
          toFieldPath: metadata.labels['ZoneID']

View the created managed resource to see the {{}}Hosted Zone Id{{}} field.

$ kubectl describe bucket
Name:         my-example-claim-p5pxf-5vnp8
# Removed for brevity
Status:
  At Provider:
    Hosted Zone Id:       Z2O1EMRO9K5GLX
    # Removed for brevity

Next view the composite resource and confirm the patch applied the {{}}label{{}}

$ kubectl describe composite
Name:         my-example-claim-p5pxf
Labels:       ZoneID=Z2O1EMRO9K5GLX

{{<hint "important">}} Crossplane doesn't apply the patch to the composite resource until the next reconcile loop, after creating the managed resource. This creates a delay between a managed resource being Ready and applying the patch. {{< /hint >}}

CombineFromComposite

The {{}}CombineFromComposite{{}} patch takes values from the composite resource, combines them and applies them to the managed resource.

{{< hint "tip" >}} Use the {{}}CombineFromComposite{{}} patch to create complex strings, like security policies and apply them to a managed resource. {{< /hint >}}

For example, use the Claim value {{}}desiredRegion{{}} and {{}}field2{{}} to generate the managed resource's {{}}name{{}}

The {{}}CombineFromComposite{{}} patch only supports the {{}}combine{{}} option.

The {{}}variables{{}} are the list of {{}}fromFieldPath{{}} values from the composite resource to combine.

The only supported {{}}strategy{{}} is {{}}strategy: string{{}}.

Optionally you can apply a {{}}string.fmt{{}}, based on Go string formatting to specify how to combine the strings.

The {{}}toFieldPath{{}} is the field in the managed resource to apply the new string to.

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
    - name: bucket1
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: Bucket
        spec:
          forProvider:
            region: us-east-2
      patches:
        - type: CombineFromComposite
          combine:
            variables:
              - fromFieldPath: spec.desiredRegion
              - fromFieldPath: spec.field2
            strategy: string
            string:
              fmt: "my-resource-%s-%s"
          toFieldPath: metadata.name

Describe the managed resource to see the applied patch.

$ kubectl describe bucket
Name:         my-resource-eu-north-1-field2-text

CombineToComposite

The {{}}CombineToComposite{{}} patch takes values from the managed resource, combines them and applies them to the composite resource.

{{<hint "tip" >}} Use {{}}CombineToComposite{{}} patches to create a single field like a URL from multiple fields in a managed resource. {{< /hint >}}

For example, use the managed resource {{}}name{{}} and {{}}region{{}} to generate a custom {{}}url{{}} field.

{{< hint "important" >}} Writing custom fields in the Status field of a composite resource requires defining the custom fields in the CompositeResourceDefinition first.

{{< /hint >}}

The {{}}CombineToComposite{{}} patch only supports the {{}}combine{{}} option.

The {{}}variables{{}} are the list of {{}}fromFieldPath{{}} the managed resource to combine.

The only supported {{}}strategy{{}} is {{}}strategy: string{{}}.

Optionally you can apply a {{}}string.fmt{{}}, based on Go string formatting to specify how to combine the strings.

The {{}}toFieldPath{{}} is the field in the composite resource to apply the new string to.

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
    - name: bucket1
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: Bucket
        spec:
          forProvider:
            region: us-east-2
      patches:
        - type: CombineToComposite
          combine:
            variables:
              - fromFieldPath: metadata.name
              - fromFieldPath: spec.forProvider.region
            strategy: string
            string:
              fmt: "https://%s.%s.com"
          toFieldPath: status.url

View the composite resource to verify the applied patch.

$ kubectl describe composite
Name:         my-example-claim-bjdjw
API Version:  example.org/v1alpha1
Kind:         xExample
# Removed for brevity
Status:
  # Removed for brevity
  URL:                     https://my-example-claim-bjdjw-r6ncd.us-east-2.com

FromEnvironmentFieldPath

{{<hint "important" >}} EnvironmentConfigs are an alpha feature. They aren't enabled by default.

For more information about using an EnvironmentConfig, read the [EnvironmentConfigs]({{<ref "./environment-configs">}}) documentation. {{< /hint >}}

The {{}}FromEnvironmentFieldPath{{}} patch takes values from the in-memory EnvironmentConfig environment and applies them to the managed resource.

{{<hint "tip" >}} Use {{}}FromEnvironmentFieldPath{{}} to apply custom managed resource settings based on the current environment.
{{< /hint >}}

For example, use the environment's {{}}locations.eu{{}} value and apply it as the {{}}region{{}}.

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
    - name: bucket1
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: Bucket
        spec:
          forProvider:
            region: us-east-2
        patches:
        - type: FromEnvironmentFieldPath
          fromFieldPath: locations.eu
          toFieldPath: spec.forProvider.region

Verify managed resource to confirm the applied patch.

kubectl describe bucket
Name:         my-example-claim-8vrvc-xx5sr
Labels:       crossplane.io/claim-name=my-example-claim
# Removed for brevity
Spec:
  For Provider:
    Region:  eu-north-1
  # Removed for brevity

ToEnvironmentFieldPath

{{<hint "important" >}} EnvironmentConfigs are an alpha feature. They aren't enabled by default.

For more information about using an EnvironmentConfig, read the [EnvironmentConfigs]({{<ref "./environment-configs">}}) documentation. {{< /hint >}}

The {{}}ToEnvironmentFieldPath{{}} patch takes values the managed resource and applies them to the in-memory EnvironmentConfig environment.

{{<hint "tip" >}} Use {{}}ToEnvironmentFieldPath{{}} write data to the environment that any FromEnvironmentFieldPath patch can access. {{< /hint >}}

For example, use the desired {{}}region{{}} value and apply it as the environment's {{}}key1{{}}.

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
    - name: bucket1
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: Bucket
        spec:
          forProvider:
            region: us-east-2
        patches:
        - type: ToEnvironmentFieldPath
          fromFieldPath: spec.forProvider.region
          toFieldPath: key1

Because the environment is in-memory, there is no command to confirm the patch wrote the value to the environment.

CombineFromEnvironment

{{<hint "important" >}} EnvironmentConfigs are an alpha feature. They aren't enabled by default.

For more information about using an EnvironmentConfig, read the [EnvironmentConfigs]({{<ref "./environment-configs">}}) documentation. {{< /hint >}}

The {{}}CombineFromEnvironment{{}} patch combines multiple values from the in-memory EnvironmentConfig environment and applies them to the managed resource.

{{<hint "tip" >}} Use {{}}CombineFromEnvironment{{}} patch to create complex strings, like security policies and apply them to a managed resource. {{< /hint >}}

For example, combine multiple fields in the environment to create a unique {{}}annotation{{}} .

The {{}}CombineFromEnvironment{{}} patch only supports the {{}}combine{{}} option.

The only supported {{}}strategy{{}} is {{}}strategy: string{{}}.

The {{}}variables{{}} are the list of {{}}fromFieldPath{{}} values from the in-memory environment to combine.

Optionally you can apply a {{}}string.fmt{{}}, based on Go string formatting to specify how to combine the strings.

The {{}}toFieldPath{{}} is the field in the managed resource to apply the new string to.

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
    - name: bucket1
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: Bucket
        spec:
          forProvider:
            region: us-east-2
      patches:
        - type: CombineFromEnvironment
          combine:
            strategy: string
            variables:
            - fromFieldPath: key1
            - fromFieldPath: key2
            string: 
              fmt: "%s-%s"
          toFieldPath: metadata.annotations[EnvironmentPatch]

Describe the managed resource to see new {{}}annotation{{}}.

$ kubectl describe bucket
Name:         my-example-claim-zmxdg-grl6p
# Removed for brevity
Annotations:  EnvironmentPatch: value1-value2
# Removed for brevity

CombineToEnvironment

{{<hint "important" >}} EnvironmentConfigs are an alpha feature. They aren't enabled by default.

For more information about using an EnvironmentConfig, read the [EnvironmentConfigs]({{<ref "./environment-configs">}}) documentation. {{< /hint >}}

The {{}}CombineToEnvironment{{}} patch combines multiple values from the managed resource and applies them to the in-memory EnvironmentConfig environment.

{{<hint "tip" >}} Use {{}}CombineToEnvironment{{}} patch to create complex strings, like security policies to use in other managed resources. {{< /hint >}}

For example, combine multiple fields in the managed resource to create a unique string and store it in the environment's {{}}key2{{}} value.

The string combines the managed resource {{}}Kind{{}} and {{}}region{{}}.

The {{}}CombineToEnvironment{{}} patch only supports the {{}}combine{{}} option.

The only supported {{}}strategy{{}} is {{}}strategy: string{{}}.

The {{}}variables{{}} are the list of {{}}fromFieldPath{{}} values in the managed resource to combine.

Optionally you can apply a {{}}string.fmt{{}}, based on Go string formatting to specify how to combine the strings.

The {{}}toFieldPath{{}} is the key in the environment to write the new string to.

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
    - name: bucket1
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: Bucket
        spec:
          forProvider:
            region: us-east-2
      patches:
        - type: CombineToEnvironment
          combine:
            strategy: string
            variables:
            - fromFieldPath: kind
            - fromFieldPath: spec.forProvider.region
            string:
              fmt: "%s.%s"
          toFieldPath: key2

Because the environment is in-memory, there is no command to confirm the patch wrote the value to the environment.

Transform a patch

When applying a patch, Crossplane supports modifying the data before applying it as a patch. Crossplane calls this a "transform" operation.

Summary of Crossplane transforms. {{< table "table table-hover" >}}

Transform Type Action
convert Converts an input data type to a different type. Also called "casting."
map Selects a specific output based on a specific input.
match Selects a specific output based on a string or regular expression.
math Applies a mathematical operation on the input.
string Change the input string using Go string formatting.
{{< /table >}}

Apply a transform directly to an individual patch with the {{}}transforms{{}} field.

A {{}}transform{{}} requires a {{}}type{{}}, indicating the transform action to take.

The other transform field is the same as the {{}}type{{}}, in this example, {{}}map{{}}.

The other fields depend on the patch type used.

This example uses a {{}}type: map{{}} transform, taking the input {{}}spec.desiredRegion{{}}, matching it to either {{}}us{{}} or {{}}eu{{}} and returning the corresponding AWS region for the {{}}spec.forProvider.region{{}} value.

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for brevity
    - name: bucket1
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: Bucket
        spec:
          forProvider:
            region: us-east-2
      patches:
        - type: FromCompositeFieldPath
          fromFieldPath: spec.desiredRegion
          toFieldPath: spec.forProvider.region
          transforms:
            - type: map
              map:
                us: us-east-2
                eu: eu-north-1

Convert transforms

The {{}}convert{{}} transform type changes the input data type to a different data type.

{{< hint "tip" >}} Some provider APIs require a field to be a string. Use a {{}}convert{{}} type to change any boolean or integer fields to strings. {{< /hint >}}

A {{}}convert{{}} transform requires a {{}}toType{{}}, defining the output data type.

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.numberField
    toFieldPath: metadata.label["numberToString"]
    transforms:
      - type: convert
        convert:
          toType: string

Supported toType values: {{< table "table table-sm table-hover" >}}

toType value Description
bool A boolean value of true or false.
float64 A 64-bit float value.
int A 32-bit integer value.
int64 A 64-bit integer value.
string A string value.
object An object.
array An array.
{{< /table >}}

Converting strings to booleans

When converting from a string to a bool Crossplane considers the string values
1, t, T, TRUE, True and true
equal to the boolean value True.

The strings
0, f, F, FALSE, False and false
are equal to the boolean value False.

Converting numbers to booleans

Crossplane considers the integer 1 and float 1.0 equal to the boolean value True.
Any other integer or float value is False.

Converting booleans to numbers

Crossplane converts the boolean value True to the integer 1 or float64 1.0.

The value False converts to the integer 0 or float64 0.0

Converting strings to float64

When converting from a string to a {{}}float64{{}} Crossplane supports an optional
{{}}format: quantity{{}} field.

Using {{}}format: quantity{{}} translates size suffixes like M for megabyte or Mi for megabit into the correct float64 value.

{{<hint "note" >}} Refer to the Go language docs for a full list of supported suffixes. {{}}

Add {{}}format: quantity{{}} to the {{}}convert{{}} object to enable quantity suffix support.

- type: convert
  convert:
   toType: float64
   format: quantity

Converting strings to objects

Crossplane converts JSON strings to objects.

Add {{}}format: json{{}} to the {{}}convert{{}} object which is the only supported string format for this conversion.

- type: convert
  convert:
   toType: object
   format: json

{{< hint "tip" >}} This conversion is useful for patching keys in an object. {{< /hint >}}

The following example adds a tag to a resource with a {{}}customized key{{}}:

    - type: FromCompositeFieldPath
      fromFieldPath: spec.clusterName
      toFieldPath: spec.forProvider.tags
      transforms:
      - type: string
        string:
          type: Format
          fmt: '{"kubernetes.io/cluster/%s": "true"}'
      - type: convert
        convert:
          toType: object
          format: json

Converting strings to arrays

Crossplane converts JSON strings to arrays.

Add {{}}format: json{{}} to the {{}}convert{{}} object which is the only supported string format for this conversion.

- type: convert
  convert:
   toType: array
   format: json

Map transforms

The {{}}map{{}} transform type maps an input value to an output value.

{{< hint "tip" >}} The {{}}map{{}} transform is useful for translating generic region names like US or EU to provider specific region names. {{< /hint >}}

The {{}}map{{}} transform compares the value from the {{}}fromFieldPath{{}} to the options listed in the {{}}map{{}}.

If Crossplane finds the value, Crossplane puts the mapped value in the {{}}toFieldPath{{}}.

{{<hint "note" >}} Crossplane throws an error for the patch if the value isn't found. {{< /hint >}}

{{}}spec.field1{{}} is the string {{}}"field1-text"{{}} then Crossplane uses the string {{}}firstField{{}} for the {{}}annotation{{}}.

If {{}}spec.field1{{}} is the string {{}}"field2-text"{{}} then Crossplane uses the string {{}}secondField{{}} for the {{}}annotation{{}}.

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.field1
    toFieldPath: metadata.annotations["myAnnotation"]
    transforms:
      - type: map
        map:
          "field1-text": "firstField"
          "field2-text": "secondField"

In this example, the value of {{}}spec.field1{{}} is {{}}field1-text{{}}.

$ kubectl describe composite
Name:         my-example-claim-twx7n
Spec:
  # Removed for brevity
  field1:         field1-text

The annotation applied to the managed resource is {{}}firstField{{}}.

$ kubectl describe bucket
Name:         my-example-claim-twx7n-ndb2f
Annotations:  crossplane.io/composition-resource-name: bucket1
              myAnnotation: firstField
# Removed for brevity.

Match transform

The {{}}match{{}} transform is like the map transform.

The {{}}match{{}} transform adds support for regular expressions along with exact strings and can provide default values if there isn't a match.

A {{}}match{{}} object requires a {{}}patterns{{}} object.

The {{}}patterns{{}} is a list of one or more patterns to attempt to match the input value against.

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.field1
    toFieldPath: metadata.annotations["myAnnotation"]
    transforms:
      - type: match
        match:
          patterns:
            - type: literal
              # Removed for brevity
            - type: regexp
              # Removed for brevity

Match {{}}patterns{{}} can be either {{}}type: literal{{}} to match an exact string or {{}}type: regexp{{}} to match a regular expression.

{{<hint "note" >}} Crossplane stops processing matches after the first pattern match. {{< /hint >}}

Match an exact string

Use a {{}}pattern{{}} with {{}}type: literal{{}} to match an exact string.

On a successful match Crossplane provides the {{}}result:{{}} to the patch {{}}toFieldPath{{}}.

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.field1
    toFieldPath: metadata.annotations["myAnnotation"]
    transforms:
      - type: match
        match:
          patterns:
            - type: literal
              literal: "field1-text"
              result: "matchedLiteral"

Match a regular expression

Use a {{}}pattern{{}} with {{}}type: regexp{{}} to match a regular expression.
Define a {{}}regexp{{}} key with the value of the regular expression to match.

On a successful match Crossplane provides the {{}}result:{{}} to the patch {{}}toFieldPath{{}}.

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.field1
    toFieldPath: metadata.annotations["myAnnotation"]
    transforms:
      - type: match
        match:
          patterns:
            - type: regexp
              regexp: '^field1.*'
              result: "foundField1"

Using default values

Optionally you can provide a default value to use if there is no matching pattern.

The default value can either be the original input value or a defined default value.

Use {{}}fallbackTo: Value{{}} to provide a default value if a match isn't found.

For example if the string {{}}unknownString{{}} isn't matched, Crossplane provides the {{}}Value{{}} {{}}StringNotFound{{}} to the {{}}toFieldPath{{}}

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.field1
    toFieldPath: metadata.annotations["myAnnotation"]
    transforms:
      - type: match
        match:
          patterns:
            - type: literal
              literal: "UnknownString"
              result: "foundField1"
          fallbackTo: Value
          fallbackValue: "StringNotFound"

To use the original input as the fallback value use {{}}fallbackTo: Input{{}}.

Crossplane uses the original {{}}fromFieldPath{{}} input for the {{}}toFieldPath{{}} value.

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.field1
    toFieldPath: metadata.annotations["myAnnotation"]
    transforms:
      - type: match
        match:
          patterns:
            - type: literal
              literal: "UnknownString"
              result: "foundField1"
          fallbackTo: Input

Math transforms

Use the {{}}math{{}} transform to multiply an input or apply a minimum or maximum value.

{{<hint "important">}} A {{}}math{{}} transform only supports integer inputs. {{< /hint >}}

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.numberField
    toFieldPath: metadata.annotations["mathAnnotation"]
    transforms:
      - type: math
        math:
          ...

clampMin

The {{}}type: clampMin{{}} uses a defined minimum value if an input is larger than the {{}}type: clampMin{{}} value.

For example, this {{}}type: clampMin{{}} requires an input to be greater than {{}}20{{}}.

If an input is lower than {{}}20{{}}, Crossplane uses the {{}}clampMin{{}} value for the {{}}toFieldPath{{}}.

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.numberField
    toFieldPath: metadata.annotations["mathAnnotation"]
    transforms:
      - type: math
        math:
          type: clampMin
          clampMin: 20

clampMax

The {{}}type: clampMax{{}} uses a defined minimum value if an input is larger than the {{}}type: clampMax{{}} value.

For example, this {{}}type: clampMax{{}} requires an input to be less than {{}}5{{}}.

If an input is higher than {{}}5{{}}, Crossplane uses the {{}}clampMax{{}} value for the {{}}toFieldPath{{}}.

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.numberField
    toFieldPath: metadata.annotations["mathAnnotation"]
    transforms:
      - type: math
        math:
          type: clampMax
          clampMax: 5

Multiply

The {{}}type: multiply{{}} multiplies the input by the {{}}multiply{{}} value.

For example, this {{}}type: multiply{{}} multiplies the value from the {{}}fromFieldPath{{}} value by {{}}2{{}}

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.numberField
    toFieldPath: metadata.annotations["mathAnnotation"]
    transforms:
      - type: math
        math:
          type: multiply
          multiply: 2

{{<hint "note" >}} The {{}}multiply{{}} value only supports integers. {{< /hint >}}

String transforms

The {{}}string{{}} transform applies string formatting or manipulation to string inputs.

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.field1
    toFieldPath: metadata.annotations["stringAnnotation"]
    transforms:
      - type: string
        string:
          type: ...

String transforms support the following {{}}types{{}}

String convert

The {{}}type: convert{{}} converts the input based on one of the following conversion types:

  • ToUpper - Change the string to all upper case letters.
  • ToLower - Change the string to all lower case letters.
  • ToBase64 - Create a new base64 string from the input.
  • FromBase64 - Create a new text string from a base64 input.
  • ToJson - Convert the input string to valid JSON.
  • ToSha1 - Create a SHA-1 hash of the input string.
  • ToSha256 - Create a SHA-256 hash of the input string.
  • ToSha512 - Create a SHA-512 hash of the input string.
  • ToAdler32 - Create an Adler32 hash of the input string.
patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.field1
    toFieldPath: metadata.annotations["FIELD1-TEXT"]
    transforms:
      - type: string
        string:
          type: Convert
          convert: "ToUpper"

String format

The {{}}type: format{{}} applies Go string formatting to the input.

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.field1
    toFieldPath: metadata.annotations["stringAnnotation"]
    transforms:
      - type: string
        string:
          type: Format
          fmt: "the-field-%s"

Join

The {{}}type: Join{{}} joins all values in the input array into a string using the given separator.

This transform only works with array inputs.

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.parameters.inputList
    toFieldPath: spec.targetJoined
    transforms:
      - type: string
        string:
          type: Join
          join:
            separator: ","

Regular expression type

The {{}}type: Regexp{{}} extracts the part of the input matching a regular expression.

Optionally use a {{}}group{{}} to match a regular expression capture group.
By default Crossplane matches the entire regular expression.

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.desiredRegion
    toFieldPath: metadata.annotations["euRegion"]
    transforms:
      - type: string
        string:
          type: Regexp
          regexp:
            match: '^eu-(.*)-'
            group: 1

Trim prefix

The {{}}type: TrimPrefix{{}} uses Go's TrimPrefix and removes characters from the beginning of a line.

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.desiredRegion
    toFieldPath: metadata.annotations["north-1"]
    transforms:
      - type: string
        string:
          type: TrimPrefix
          trim: `eu-

Trim suffix

The {{}}type: TrimSuffix{{}} uses Go's TrimSuffix and removes characters from the end of a line.

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.desiredRegion
    toFieldPath: metadata.annotations["eu"]
    transforms:
      - type: string
        string:
          type: TrimSuffix
          trim: `-north-1'

Replace

The {{}}type: Replace{{}} replaces all occurrences of the {{}}search{{}} string with the {{}}replace{{}} string. If replace is an empty string, then the search string is removed.

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.location
    toFieldPath: spec.forProvider.region
    transforms:
      - type: string
        string:
          type: Replace
          replace:
            search: "europe"
            replace: "eu"

Patch policies

Crossplane supports two types of patch policies:

  • fromFieldPath
  • mergeOptions

fromFieldPath policy

Using a fromFieldPath: Required policy on a patch requires the fromFieldPath to exist in the composite resource.

{{<hint "tip" >}} If a resource patch isn't working applying the fromFieldPath: Required policy may produce an error in the composite resource to help troubleshoot. {{< /hint >}}

By default, Crossplane applies the policy fromFieldPath: Optional. With fromFieldPath: Optional Crossplane ignores a patch if the fromFieldPath doesn't exist.

With {{}}fromFieldPath: Required{{}} the composite resource produces an error if the {{}}fromFieldPath{{}} doesn't exist.

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.desiredRegion
    toFieldPath: metadata.annotations["eu"]
    policy:
      fromFieldPath: Required

Merge options

By default when applying a patch the destination data is overridden. Use {{}}mergeOptions{{}} to allow patches to merge arrays and objects without overwriting them.

With an array input, use {{}}appendSlice: true{{}} to append the array data to the end of the existing array.

With an object, use {{}}keepMapValues: true{{}} to leave existing object keys in tact. The patch updates any matching keys between the input and destination data.

patches:
  - type: FromCompositeFieldPath
    fromFieldPath: spec.desiredRegion
    toFieldPath: metadata.annotations["eu"]
    policy:
      mergeOptions:
        appendSlice: true
        keepMapValues: true