> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Crossplane Functions

> Demonstration of Crossplane Composition patch and transform functions mapping, combining, converting, and writing resource fields while composing a WebApp XR into a ConfigMap

In this lesson we demonstrate Crossplane Composition functions that Patch and Transform fields while composing resources. Using a WebApp composite resource (XR), we show four transform types supported by the Patch-and-Transform function:

* map — value mapping (e.g., `tier` -> `cpuLimit`)
* combine — join multiple XR fields into a single string (e.g., `appId`)
* toCompositeFieldPath — write data from composed resources back into the XR `status`
* convert — type conversion (e.g., integer -> string)

The WebApp composite allows platform users to request an application environment by specifying `tier`, `environment`, and `replicas`. The platform (the Composition) decides how those values map to concrete resource configuration (here, a ConfigMap in the `function-lab` namespace).

Prerequisites

* A Crossplane control plane with the function `function-patch-and-transform` installed.
* A Kubernetes cluster where composed resources are created in the `function-lab` namespace.
* Familiarity with Crossplane CompositeResourceDefinitions (XRD) and Compositions.

Overview of the XRD

First, verify the CompositeResourceDefinition (XRD) for WebApp exists and is established:

```console theme={null}
kubectl get xrd webapps.platform.example.com
```

A minimal XRD used in this lesson (before adding a status field) looks like:

```yaml theme={null}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
  name: webapps.platform.example.com
spec:
  group: platform.example.com
  scope: Namespaced
  names:
    kind: WebApp
    plural: webapps
  versions:
  - name: v1
    served: true
    referenceable: true
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              tier:
                type: string
                enum:
                - free
                - standard
                - premium
              environment:
                type: string
              replicas:
                type: integer
            required:
            - tier
            - environment
            - replicas
          status:
            type: object
            x-kubernetes-preserve-unknown-fields: true
```

Composition: pipeline with Patch-and-Transform function

This Composition uses `mode: Pipeline` and a single pipeline step that references the `function-patch-and-transform` function. The pipeline composes one resource: a Kubernetes Object that becomes a ConfigMap (in `function-lab`) whose `data` is populated via patches and transforms.

Important: when editing an existing Composition to add patches, always append to the `patches` array — do not replace it. This preserves previously defined mappings.

When adding new patches, append them to the existing `patches` array. Replacing the array can remove previously defined mappings.

Full Composition (final version used in this lesson)

```yaml theme={null}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: webapp-kubernetes
spec:
  compositeTypeRef:
    apiVersion: platform.example.com/v1
    kind: WebApp
  mode: Pipeline
  pipeline:
  - step: patch-and-transform
    functionRef:
      name: function-patch-and-transform
    input:
      apiVersion: pt.fn.crossplane.io/v1beta1
      kind: Resources
      resources:
      - name: webapp-config
        base:
          apiVersion: kubernetes.m.crossplane.io/v1alpha1
          kind: Object
          spec:
            providerConfigRef:
              kind: ClusterProviderConfig
              name: default
            forProvider:
              manifest:
                apiVersion: v1
                kind: ConfigMap
                metadata:
                  name: webapp-config
                  namespace: function-lab
                data: {}
        patches:
        - type: FromCompositeFieldPath
          fromFieldPath: spec.environment
          toFieldPath: spec.forProvider.manifest.data.environment
        - type: FromCompositeFieldPath
          fromFieldPath: spec.tier
          toFieldPath: spec.forProvider.manifest.data.cpuLimit
          transforms:
          - type: map
            map:
              free: "100m"
              standard: "500m"
              premium: "2000m"
        - type: CombineFromComposite
          combine:
            variables:
            - fromFieldPath: metadata.name
            - fromFieldPath: spec.environment
            strategy: string
            string:
              fmt: "%s-%s"
          toFieldPath: spec.forProvider.manifest.data.appId
        - type: ToCompositeFieldPath
          fromFieldPath: spec.forProvider.manifest.metadata.name
          toFieldPath: status.configName
        - type: FromCompositeFieldPath
          fromFieldPath: spec.replicas
          toFieldPath: spec.forProvider.manifest.data.replicas
          transforms:
          - type: convert
            convert:
              toType: string
```

Notes on the Composition

* ConfigMap `data` is string-keyed and string-valued; conversions are often necessary (e.g., integer -> string).
* `ToCompositeFieldPath` writes back into the XR `status`; the XRD must declare the status field being written or Crossplane will reject the status update.

1. Map transform (value mapping)

Use-case: translate a user-friendly `tier` into a concrete CPU limit string that the composed ConfigMap expects.

Patch snippet (included above):

```yaml theme={null}
- type: FromCompositeFieldPath
  fromFieldPath: spec.tier
  toFieldPath: spec.forProvider.manifest.data.cpuLimit
  transforms:
  - type: map
    map:
      free: "100m"
      standard: "500m"
      premium: "2000m"
```

Apply the updated Composition:

```console theme={null}
kubectl apply -f webapp-composition.yaml
```

Create a WebApp XR to test mapping:

```yaml theme={null}
# xr-example.yaml
apiVersion: platform.example.com/v1
kind: WebApp
metadata:
  name: my-app
  namespace: default
spec:
  environment: prod
  tier: premium
  replicas: 3
```

```console theme={null}
kubectl apply -f xr-example.yaml
```

Inspect the generated ConfigMap (namespace `function-lab`):

```console theme={null}
kubectl get configmap -n function-lab webapp-config -o yaml
```

Example resulting ConfigMap `data`:

```yaml theme={null}
apiVersion: v1
data:
  cpuLimit: 2000m
  environment: prod
kind: ConfigMap
metadata:
  name: webapp-config
  namespace: function-lab
```

2. Combine transform (CombineFromComposite)

Use-case: generate a unique app ID by concatenating the XR resource name and the requested environment.

Patch snippet (included in the full composition above):

```yaml theme={null}
- type: CombineFromComposite
  combine:
    variables:
    - fromFieldPath: metadata.name
    - fromFieldPath: spec.environment
    strategy: string
    string:
      fmt: "%s-%s"
  toFieldPath: spec.forProvider.manifest.data.appId
```

After applying the Composition and the XR (example above), the ConfigMap will include:

```yaml theme={null}
data:
  appId: my-app-prod
  cpuLimit: 2000m
  environment: prod
```

3. ToCompositeFieldPath (write back to XR status)

Use-case: surface composed resource metadata back to the XR status so users can easily find composed resource identifiers (e.g., the generated ConfigMap name).

Patch snippet (included in the full composition):

```yaml theme={null}
- type: ToCompositeFieldPath
  fromFieldPath: spec.forProvider.manifest.metadata.name
  toFieldPath: status.configName
```

Crossplane requires that any status field you write with `ToCompositeFieldPath` be declared in the XRD schema. If `status.configName` is not declared, Crossplane will reject the status patch with an error like:

```bash theme={null}
.failed to create typed patch object (default/my-app; platform.example.com/v1, Kind=WebApp): .status.configName: field not declared in schema
```

Add the `configName` field to your XRD `status` properties before applying this patch.

Example XRD status addition:

```yaml theme={null}
# webapp-xrd.yaml (status addition)
...
        properties:
          status:
            type: object
            x-kubernetes-preserve-unknown-fields: true
            properties:
              configName:
                type: string
```

After updating the XRD and reapplying the Composition and XR, the WebApp's status will include the composed ConfigMap name:

```console theme={null}
kubectl get webapps.platform.example.com my-app -o yaml
```

Excerpt of status:

```yaml theme={null}
status:
  configName: my-app-97c0b06b087b
  conditions:
    - type: Ready
      status: "True"
    - type: Synced
      status: "True"
```

4. Convert transform (type conversion)

Use-case: ConfigMap `data` values must be strings. Convert integer `spec.replicas` to a string and place it in the ConfigMap `data`.

Patch snippet (included earlier):

```yaml theme={null}
- type: FromCompositeFieldPath
  fromFieldPath: spec.replicas
  toFieldPath: spec.forProvider.manifest.data.replicas
  transforms:
  - type: convert
    convert:
      toType: string
```

After applying the Composition and XR, the ConfigMap `data` will include replicas as a string:

```yaml theme={null}
data:
  appId: my-app-prod
  cpuLimit: 2000m
  environment: prod
  replicas: "3"
```

Transform summary table

| Transform | Used in patch type | Purpose | Example output |
| - | - | - | - |
| map | `FromCompositeFieldPath` + `transforms` | Map user-friendly values to concrete strings (tier -> cpuLimit) | `cpuLimit: 2000m` |
| combine | `CombineFromComposite` | Concatenate multiple XR fields into a single value (name + env -> appId) | `appId: my-app-prod` |
| toCompositeFieldPath | `ToCompositeFieldPath` | Write composed resource metadata back into XR status | `status.configName: my-app-97c0b06b087b` |
| convert | `FromCompositeFieldPath` + `transforms` | Convert types for compatibility with composed resource schema | `replicas: "3"` |

Putting it all together — expected results

* Map: maps `spec.tier` -> `data.cpuLimit` according to the map table.
* Combine: concatenates `metadata.name` and `spec.environment` -> `data.appId`.
* ToCompositeFieldPath: writes the composed ConfigMap name back to `status.configName` on the XR (requires XRD declaration).
* Convert: converts `spec.replicas` (integer) -> `data.replicas` (string).

Best practices and tips

* Always append new patches to the end of the `patches` array instead of replacing it to avoid accidental removal of existing mappings.
* When writing back to XR `status`, update the XRD first to include any new status properties you plan to set.
* Verify composed resource types (e.g., ConfigMap expects string data) and use `convert` transforms when necessary.

References and next steps

* Crossplane Composition docs: [https://crossplane.io/docs/](https://crossplane.io/docs/)
* Crossplane Functions (patch-and-transform): check your installed function manifest and documentation for additional transform options.

Try applying these patterns in your own Compositions to standardize how platform users express intent (XR fields) and how the platform maps that intent to concrete Kubernetes resources.

> **[Watch Video](https://learn.kodekloud.com/user/courses/prep-course-certified-cloud-native-platform-engineer-cnpe/module/756ffaae-767b-4743-9724-c05d3fbf9a18/lesson/248dcf28-f81b-417f-ab7a-c9fd53237e28)**

> **[Practice Lab](https://learn.kodekloud.com/user/courses/prep-course-certified-cloud-native-platform-engineer-cnpe/module/756ffaae-767b-4743-9724-c05d3fbf9a18/lesson/5c8eaf8d-b487-45cc-be5d-bb228eea6645)**


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.