This reference provides detailed examples of defining, configuring, and using Composite Resources in Crossplane. You can also refer to Crossplane’s API documentation for more details. If you’re looking for a more general overview of Composite Resources and Composition in Crossplane, try the Composite Resources page under Concepts.

Composite Resources and Claims

The type and most of the schema of Composite Resources and claims are largely of your own choosing, but there is some common ‘machinery’ injected into them. Here’s a hypothetical XR that doesn’t have any user-defined fields and thus only includes the automatically injected Crossplane machinery:

 2kind: XPostgreSQLInstance
 4  # This XR was created automatically by a claim, so its name is derived from
 5  # the claim's name.
 6  name: my-db-mfd1b
 7  annotations:
 8    # The external name annotation has special meaning in Crossplane. When a
 9    # claim creates an XR its external name will automatically be propagated to
10    # the XR. Whether and how the external name is propagated to the resources
11    # the XR composes is up to its Composition.
12 production-db-0
14  # XRs have a reference to the claim that created them (or, if the XR was
15  # pre-provisioned, to the claim that later claimed them).
16  claimRef:
17    apiVersion:
18    kind: PostgreSQLInstance
19    name: my-db
20  # The compositeDeletePolicy specifies the propagation policy that will be used by Crossplane
21  # when deleting the Composite Resource that is associated with the Claim.  The default
22  # value is Background, which causes the Composite resource to be deleted using
23  # the kubernetes default propagation policy of Background, and all associated
24  # resources will be deleted simultaneously.  The other value for this field is Foreground,
25  # which will cause the Composite resource to be deleted using Foreground Cascading Deletion.
26  # Kubernetes will add a foregroundDeletion finalizer to all of the resources in the
27  # dependency graph, and they will be deleted starting with the edge or leaf nodes and
28  # working back towards the root Composite.  See
29  # for more information on cascading deletion.
30  compositeDeletePolicy: Background
31  # The compositionRef specifies which Composition this XR will use to compose
32  # resources when it is created, updated, or deleted. This can be omitted and
33  # will be set automatically if the XRD has a default or enforced composition
34  # reference, or if the below composition selector is set.
35  compositionRef:
36    name: production-us-east
37  # The compositionSelector allows you to match a Composition by labels rather
38  # than naming one explicitly. It is used to set the compositionRef if none is
39  # specified explicitly.
40  compositionSelector:
41    matchLabels:
42      environment: production
43      region: us-east
44      provider: gcp
45  # The resourceRefs array contains references to all of the resources of which
46  # this XR is composed. Despite being in spec this field isn't intended to be
47  # configured by humans - Crossplane will take care of keeping it updated.
48  resourceRefs:
49  - apiVersion:
50    kind: CloudSQLInstance
51    name: my-db-mfd1b-md9ab
52  # The writeConnectionSecretToRef field specifies a Kubernetes Secret that this
53  # XR should write its connection details (if any) to.
54  writeConnectionSecretToRef:
55    namespace: crossplane-system
56    name: my-db-connection-details
58  # An XR's 'Ready' condition will become True when all of the resources it
59  # composes are deemed ready. Refer to the Composition 'readinessChecks' field
60  # for more information.
61  conditions:
62  - type: Ready
63    statue: "True"
64    reason: Available
65    lastTransitionTime: 2021-10-02T07:20:50.52Z
66  # The last time the XR published its connection details to a Secret.
67  connectionDetails:
68    lastPublishedTime: 2021-10-02T07:20:51.24Z

Similarly, here’s an example of the claim that corresponds to the above XR:

 2kind: PostgreSQLInstance
 4  # Claims are namespaced, unlike XRs.
 5  namespace: default
 6  name: my-db
 7  annotations:
 8    # The external name annotation has special meaning in Crossplane. When a
 9    # claim creates an XR its external name will automatically be propagated to
10    # the XR. Whether and how the external name is propagated to the resources
11    # the XR composes is up to its Composition.
12 production-db-0
14  # The resourceRef field references the XR this claim corresponds to. You can
15  # either set it to an existing (compatible) XR that you'd like to claim or
16  # (the more common approach) leave it blank and let Crossplane automatically
17  # create and reference an XR for you.
18  resourceRef:
19    apiVersion:
20    kind: XPostgreSQLInstance
21    name: my-db-mfd1b
22  # A claim's compositionRef and compositionSelector work the same way as an XR.
23  compositionRef:
24    name: production-us-east
25  compositionSelector:
26    matchLabels:
27      environment: production
28      region: us-east
29      provider: gcp
30  # A claim's writeConnectionSecretToRef mostly works the same way as an XR's.
31  # The one difference is that the Secret is always written to the namespace of
32  # the claim.
33  writeConnectionSecretToRef:
34    name: my-db-connection-details
36  # A claim's 'Ready' condition will become True when its XR's 'Ready' condition
37  # becomes True.
38  conditions:
39  - type: Ready
40    statue: "True"
41    reason: Available
42    lastTransitionTime: 2021-10-02T07:20:50.52Z
43  # The last time the claim published its connection details to a Secret.
44  connectionDetails:
45    lastPublishedTime: 2021-10-02T07:20:51.24Z

If your XR or claim isn’t working as you’d expect you can try running kubectl describe against it for details - pay particular attention to any events and status conditions. You may need to follow the references from claim to XR to composed resources to find out what’s happening.


Below is an example CompositeResourceDefinition that includes all configurable fields.

 2kind: CompositeResourceDefinition
 4  # XRDs must be named '<plural>.<group>', per the plural and group names below.
 5  name:
 7  # This XRD defines an XR in the '' API group.
 8  group:
 9  # The kind of this XR will be 'XPostgreSQLInstance`. You may also optionally
10  # specify a singular name and a listKind.
11  names:
12    kind: XPostgreSQLInstance
13    plural: xpostgresqlinstances
14  # This type of XR offers a claim. Omit claimNames if you don't want to do so.
15  # The claimNames must be different from the names above - a common convention
16  # is that names are prefixed with 'X' while claim names are not. This lets app
17  # team members think of creating a claim as (e.g.) 'creating a
18  # PostgreSQLInstance'.
19  claimNames:
20    kind: PostgreSQLInstance
21    plural: postgresqlinstances
22  # Each type of XR can declare any keys they write to their connection secret
23  # which will act as a filter during aggregation of the connection secret from
24  # composed resources. It's recommended to provide the set of keys here so that
25  # consumers of claims and XRs can see what to expect in the connection secret.
26  # If no key is given, then all keys in the aggregated connection secret will
27  # be written to the connection secret of the XR.
28  connectionSecretKeys:
29  - hostname
30  # Each type of XR may specify a default Composition to be used when none is
31  # specified (e.g. when the XR has no compositionRef or selector). A similar
32  # enforceCompositionRef field also exists to allow XRs to enforce a specific
33  # Composition that should always be used.
34  defaultCompositionRef:
35    name: example
36  # Each type of XR may be served at different versions - e.g. v1alpha1, v1beta1
37  # and v1 - simultaneously. Currently Crossplane requires that all versions
38  # have an identical schema, so this is mostly useful to 'promote' a type of XR
39  # from alpha to beta to production ready.
40  versions:
41  - name: v1alpha1
42    # Served specifies that XRs should be served at this version. It can be set
43    # to false to temporarily disable a version, for example to test whether
44    # doing so breaks anything before a version is removed wholesale.
45    served: true
46    # Referenceable denotes the version of a type of XR that Compositions may
47    # use. Only one version may be referenceable.
48    referenceable: true
49    # Schema is an OpenAPI schema just like the one used by Kubernetes CRDs. It
50    # determines what fields your XR and claim will have. Note that Crossplane
51    # will automatically extend with some additional Crossplane machinery.
52    schema:
53      openAPIV3Schema:
54        type: object
55        properties:
56          spec:
57            type: object
58            properties:
59              parameters:
60                type: object
61                properties:
62                  storageGB:
63                    type: integer
64                required:
65                - storageGB
66            required:
67            - parameters
68          status:
69            type: object
70            properties:
71              address:
72                description: Address of this MySQL server.
73                type: string

Take a look at the Kubernetes CRD documentation for a more detailed guide to writing OpenAPI schemas. Note that the following fields are reserved for Crossplane machinery, and will be ignored if your schema includes them:

  • spec.resourceRef
  • spec.resourceRefs
  • spec.claimRef
  • spec.writeConnectionSecretToRef
  • status.conditions
  • status.connectionDetails

If your CompositeResourceDefinition isn’t working as you’d expect you can try running kubectl describe xrd for details - pay particular attention to any events and status conditions.


You’ll encounter a lot of ‘field paths’ when reading or writing a Composition. Field paths reference a field within a Kubernetes object via a simple string ‘path’. API conventions describe the syntax as:

Standard JavaScript syntax for accessing that field, assuming the JSON object was transformed into a JavaScript object, without the leading dot, such as

Valid field paths include:

  • - The name field of the metadata object.
  • spec.containers[0].name - The name field of the 0th containers element.
  • data[.config.yml] - The .config.yml field of the data object.
  • apiVersion - The apiVersion field of the root object.

While the following are invalid:

  • - Leading period.
  • - Double period.
  • - Trailing period.
  • spec.containers[] - Empty brackets.
  • spec.containers.[0].name - Period before open bracket.

Below is a detailed example of a Composition. While detailed, this example doesn’t include every patch, transform, connection detail, and readiness check type. Keep reading below to discover those.

  2kind: Composition
  4  name: example
  5  labels:
  6    # An optional convention is to include a label of the XRD. This allows
  7    # easy discovery of compatible Compositions.
  9    # The following label marks this Composition for GCP. This label can 
 10    # be used in 'compositionSelector' in an XR or Claim.
 11    provider: gcp
 14  # Each Composition must declare that it is compatible with a particular type
 15  # of Composite Resource using its 'compositeTypeRef' field. The referenced
 16  # version must be marked 'referenceable' in the XRD that defines the XR.
 17  compositeTypeRef:
 18    apiVersion:
 19    kind: XPostgreSQLInstance
 21  # When an XR is created in response to a claim Crossplane needs to know where
 22  # it should create the XR's connection secret. This is configured using the
 23  # 'writeConnectionSecretsToNamespace' field.
 24  writeConnectionSecretsToNamespace: crossplane-system
 26  # Each Composition must specify at least one composed resource template. In
 27  # this case the Composition tells Crossplane that it should create, update, or
 28  # delete a CloudSQLInstance whenever someone creates, updates, or deletes an
 29  # XPostgresSQLInstance.
 30  resources:
 32    # It's good practice to provide a unique name for each entry. Note that
 33    # this identifies the resources entry within the Composition - it's not
 34    # the name the CloudSQLInstance. The 'name' field will be required in a
 35    # future version of this API.
 36  - name: cloudsqlinstance
 38    # The 'base' template for the CloudSQLInstance Crossplane will create.
 39    # You can use the base template to specify fields that never change, or
 40    # default values for fields that may optionally be patched over. Bases must
 41    # be a valid Crossplane resource - a Managed Resource, Composite Resource,
 42    # or a ProviderConfig.
 43    base:
 44      apiVersion:
 45      kind: CloudSQLInstance
 46      spec:
 47        forProvider:
 48          databaseVersion: POSTGRES_12
 49          region: us-central1
 50          settings:
 51            dataDiskType: PD_SSD
 52            ipConfiguration:
 53              ipv4Enabled: true
 54              authorizedNetworks:
 55                - value: ""
 57    # Each resource can optionally specify a set of 'patches' that copy fields
 58    # from (or to) the XR.
 59    patches:
 60      # FromCompositeFieldPath is the default when 'type' is omitted, but it's
 61      # good practice to always include the type for readability.
 62    - type: FromCompositeFieldPath
 63      fromFieldPath: spec.parameters.size
 64      toFieldPath: spec.forProvider.settings.tier
 66      # Each patch can optionally specify one or more 'transforms', which
 67      # transform the 'from' field's value before applying it to the 'to' field.
 68      # Transforms are applied in the order they are specified; each transform's
 69      # output is passed to the following transform's input.
 70      transforms:
 71      - type: map
 72        map:
 73          medium: db-custom-1-3840
 75      policy:
 76        # By default a patch from a field path that does not exist is simply
 77        # skipped until it does. Use the 'Required' policy to instead block and
 78        # return an error when the field path does not exist.
 79        fromFieldPath: Required
 81        # You can patch entire objects or arrays from one resource to another.
 82        # By default the 'to' object or array will be overwritten, not merged.
 83        # Use the 'mergeOptions' field to override this behaviour. Note that
 84        # these fields accidentally leak Go terminology - 'slice' means 'array'.
 85        # 'map' means 'map' in YAML or 'object' in JSON.
 86        mergeOptions:
 87          appendSlice: true
 88          keepMapValues: true
 90    # You can include connection details to propagate from this CloudSQLInstance
 91    # up to the XPostgreSQLInstance XR (and then on to the PostgreSQLInstance
 92    # claim). Remember that your XRD must declare which connection secret keys
 93    # it supports.
 94    connectionDetails:
 95    - name: hostname
 96      fromConnectionSecretKey: hostname
 98    # By default an XR's 'Ready' status condition will become True when the
 99    # 'Ready' status conditions of all of its composed resources become true.
100    # You can optionally specify custom readiness checks to override this.
101    readinessChecks:
102    - type: None
105  # If you find yourself repeating patches a lot you can group them as a named
106  # 'patch set' then use a PatchSet type patch to reference them.
107  patchSets:
108  - name: metadata
109    patches:
110    - type: FromCompositeFieldPath
111      # When both field paths are the same you can omit the 'toFieldPath' and it
112      # will default to the 'fromFieldPath'.
113      fromFieldPath: metadata.labels[some-important-label]

Pause Annotation

There is an annotation named that you can use on Composite Resources and Composite Resource Claims to temporarily pause reconciliations of their respective controllers on them. An example for a Composite Resource Claim is as follows:

 2kind: MyResource
 4  annotations:
 5 true
 6  namespace: upbound-system
 7  name: my-resource
 9  parameters:
10    tagValue: demo-test
11  compositionRef:
12    name: example

where MyResource is a Composite Resource Claim kind. When a Composite Resource or a Claim has the annotation with its value set to true, the Composite Resource controller or the Claim controller pauses reconciliations on the resource until the annotation is removed or its value set to something other than true. Before temporarily pausing reconciliations, an event with the type Synced, the status False, and the reason ReconcilePaused is emitted on the resource. Please also note that annotations on a Composite Resource Claim are propagated to the associated Composite Resource but when the true annotation is added to a Claim, because reconciliations on the Claim are now paused, this newly added annotation will not be propagated. However, whenever the annotation’s value is set to a non-true value, reconciliations on the Claim will now resume, and thus the annotation will now be propagated to the associated Composite Resource with a non-true value. An implication of the described behavior is that pausing reconciliations on the Claim will not inherently pause reconciliations on the associated Composite Resource.

Patch Types

You can use the following types of patch in a Composition:

FromCompositeFieldPath. The default if the type is omitted. This type patches from a field within the XR to a field within the composed resource. It’s commonly used to expose a composed resource spec field as an XR spec field.

1# Patch from the XR's spec.parameters.size field to the composed resource's
2# spec.forProvider.settings.tier field.
3- type: FromCompositeFieldPath
4  fromFieldPath: spec.parameters.size
5  toFieldPath: spec.forProvider.settings.tier

ToCompositeFieldPath. The inverse of FromCompositeFieldPath. This type patches from a field within the composed resource to a field within the XR. It’s commonly used to derive an XR status field from a composed resource status field.

1# Patch from the composed resource's field to the XR's
2# field.
3- type: ToCompositeFieldPath
4  fromFieldPath:
5  toFieldPath:

FromCompositeFieldPath and ToCompositeFieldPath patches can also take a wildcarded field path in the toFieldPath parameter and patch each array element in the toFieldPath with the singular value provided in the fromFieldPath.

 1# Patch from the XR's spec.parameters.allowedIPs to the CIDRBlock elements
 2# inside the array spec.forProvider.firewallRules on the composed resource.
 4- name: exampleFirewall
 5  base:
 6    apiVersion:
 7    kind: Firewall
 8    spec:
 9      forProvider:
10        firewallRules:
11        - Action: "Allow"
12          Destination: "example1"
13          CIDRBlock: ""
14        - Action: "Allow"
15          Destination: "example2"
16          CIDRBlock: ""
17- type: FromCompositeFieldPath
18  fromFieldPath: spec.parameters.allowedIP
19  toFieldPath: spec.forProvider.firewallRules[*].CIDRBlock

Note that the field to be patched requires some initial value to be set.

CombineFromComposite. Combines multiple fields from the XR to produce one composed resource field.

 1# Patch from the XR's spec.parameters.location field and the
 2# metadata.labels[] label to the composed
 3# resource's spec.forProvider.administratorLogin field.
 4- type: CombineFromComposite
 5  combine:
 6    # The patch will only be applied when all variables have non-zero values.
 7    variables:
 8    - fromFieldPath: spec.parameters.location
 9    - fromFieldPath: metadata.labels[]
10    strategy: string
11    string:
12      fmt: "%s-%s"
13  toFieldPath: spec.forProvider.administratorLogin
14  # By default Crossplane will skip the patch until all of the variables to be
15  # combined have values. Set the fromFieldPath policy to 'Required' to instead
16  # abort composition and return an error if a variable has no value.
17  policy:
18    fromFieldPath: Required

At the time of writing only the string combine strategy is supported. It uses Go string formatting to combine values, so if the XR’s location was us-west and its claim name was db the composed resource’s administratorLogin would be set to us-west-db.

CombineToComposite is the inverse of CombineFromComposite.

 1# Patch from the composed resource's spec.parameters.administratorLogin and
 2# status.atProvider.fullyQualifiedDomainName fields back to the XR's
 3# status.adminDSN field.
 4- type: CombineToComposite
 5  combine:
 6    variables:
 7      - fromFieldPath: spec.parameters.administratorLogin
 8      - fromFieldPath: status.atProvider.fullyQualifiedDomainName
 9    strategy: string
10    # Here, our administratorLogin parameter and fullyQualifiedDomainName
11    # status are formatted to a single output string representing a DSN.
12    string:
13      fmt: "mysql://%s@%s:3306/my-database-name"
14  toFieldPath: status.adminDSN

PatchSet. References a named set of patches defined in the spec.patchSets array of a Composition.

1# This is equivalent to specifying all of the patches included in the 'metadata'
2# PatchSet.
3- type: PatchSet
4  patchSetName: metadata

The patchSets array may not contain patches of type: PatchSet. The transforms and patchPolicy fields are ignored by type: PatchSet.

Transform Types

You can use the following types of transform on a value being patched:

map. Transforms values using a map.

1# If the value of the 'from' field is 'us-west', the value of the 'to' field
2# will be set to 'West US'.
3- type: map
4  map:
5    us-west: West US
6    us-east: East US
7    au-east: Australia East

math. Transforms values using math. The input value must be an integer. Currently only multiply is supported.

1# If the value of the 'from' field is 2, the value of the 'to' field will be set
2# to 4.
3- type: math
4  math:
5    multiply: 2

string. Transforms string values.

  • string transform type Format, Currently only Go style fmt is supported. Go style fmt is supported.
  • string transform type Convert, accepts one of ToUpper, ToLower, ToBase64, FromBase64.
  • string transform type TrimPrefix, accepts a string to be trimmed from the beginning of the input.
  • string transform type TrimSuffix, accepts a string to be trimmed from the end of the input.
  • string transform type Regexp, accepts a string for regexp to be applied to.
 1# If you omit the field type, by default type is set to `Format` 
 2# If the value of the 'from' field is 'hello', the value of the 'to' field will
 3# be set to 'hello-world'.
 4- type: string
 5  string:
 6    fmt: "%s-world"
 8# This is the same as above
 9# the value of the 'to' field will be set to 'hello-world'.
10- type: string
11  string:
12    type: Format
13    fmt: "%s-world"
15# If the value of the 'from' field is 'hello', the value of the 'to' field will
16# be set to 'HELLO'.
17- type: string
18  string:
19    type: Convert
20    convert: ToUpper
22# If the value of the 'from' field is 'Hello', the value of the 'to' field will
23# be set to 'hello'.
24- type: string
25  string:
26    type: Convert
27    convert: ToLower
29# If the value of the 'from' field is 'Hello', the value of the 'to' field will
30# be set to 'SGVsbG8='.
31- type: string
32  string:
33     type: Convert
34     convert: ToBase64
36# If the value of the 'from' field is 'SGVsbG8=', the value of the 'to' field will
37# be set to 'Hello'.
38- type: string
39  string:
40     type: Convert
41     convert: FromBase64
43# If the value of the 'from' field is, the value of the 'to' field will
44# be set to
45- type: string
46  string:
47    type: TrimPrefix
48    trim: 'https://'
50# If the value of the 'from' field is my-string-test, the value of the 'to' field will
51# be set to my-string
52- type: string
53  string:
54     type: TrimSuffix
55     trim: '-test'
57# If the value of the 'from' field is 'arn:aws:iam::42:example, the value of the
58# 'to' field will be set to "42". Note that the 'to' field is always a string. 
59- type: string
60  string:
61     type: Regexp
62     regexp:
63      match: 'arn:aws:iam::(\d+):.*'
64      group: 1  # Optional capture group. Omit to match the entire regexp.

convert. Transforms values of one type to another, for example from a string to an integer. The following values are supported by the from and to fields:

  • string
  • bool
  • int
  • int64
  • float64

The strings 1, t, T, TRUE, true, and True are considered ’true’, while 0, f, F, FALSE, false, and False are considered ‘false’. The integer 1 and float 1.0 are considered true, while all other values are considered false. Similarly, boolean true converts to integer 1 and float 1.0, while false converts to 0 and 0.0.

1# If the value to be converted is "1" (a string), the value of the 'toType'
2# field will be set to 1 (an integer).
3- type: convert
4  convert:
5   toType: int

Connection Details

Connection details secret of XR is an aggregated sum of the connection details of the composed resources. It’s recommended that the author of XRD specify exactly which keys will be allowed in the XR connection secret by listing them in spec.connectionSecretKeys so that consumers of claims and XRs can see what they can expect in the connection details secret.

If spec.connectionSecretKeys is empty, then all keys of the aggregated connection details secret will be propagated.

You can derive the following types of connection details from a composed resource to be aggregated:

FromConnectionSecretKey. Derives an XR connection detail from a connection secret key of a composed resource.

1# Derive the XR's 'user' connection detail from the 'username' key of the
2# composed resource's connection secret.
3- type: FromConnectionSecretKey
4  name: user
5  fromConnectionSecretKey: username

FromFieldPath. Derives an XR connection detail from a field path within the composed resource.

1# Derive the XR's 'user' connection detail from the 'adminUser' status field of
2# the composed resource.
3- type: FromFieldPath
4  name: user
5  fromFieldPath: status.atProvider.adminUser

FromValue. Derives an XR connection detail from a fixed value.

1# Always sets the XR's 'user' connection detail to 'admin'.
2- type: FromValue
3  name: user
4  value: admin

Readiness Checks

Crossplane can use the following types of readiness check to determine whether a composed resource is ready (and therefore whether the XR and claim should be considered ready). Specify multiple readiness checks if multiple conditions must be met for a composed resource to be considered ready.

Note that if you don’t specify any readiness checks Crossplane will consider the composed resource to be ready when its ‘Ready’ status condition becomes ‘True’.

MatchString. Considers the composed resource to be ready when the value of a field within that resource matches a specified string.

1# The composed resource will be considered ready when the 'state' status field
2# matches the string 'Online'.
3- type: MatchString
4  fieldPath: status.atProvider.state
5  matchString: "Online"

MatchInteger. Considers the composed resource to be ready when the value of a field within that resource matches a specified integer.

1# The composed resource will be considered ready when the 'state' status field
2# matches the integer 4.
3- type: MatchInteger
4  fieldPath: status.atProvider.state
5  matchInteger: 4

NonEmpty. Considers the composed resource to be ready when a field exists in the composed resource. The name of this check can be a little confusing in that a field that exists with a zero value (e.g. an empty string or zero integer) is not considered to be ’empty’, and thus will pass the readiness check.

1# The composed resource will be considered ready if and when 'online' status
2# field  exists.
3- type: NonEmpty
4  fieldPath:

None. Considers the composed resource to be ready as soon as it exists.

Missing Functionality

You might find while reading through this reference that Crossplane is missing some functionality you need to compose resources. If that’s the case, please raise an issue with as much detail about your use case as possible. Please understand that the Crossplane maintainers are growing the feature set of the Composition type conservatively. We highly value the input of our users and community, but we also feel it’s critical to avoid bloat and complexity. We therefore wish to carefully consider each new addition. We feel some features may be better suited for a real, expressive programming language and intend to build an alternative to the Composition type as it is documented here per this proposal.

Tips, Tricks, and Troubleshooting

In this section we’ll cover some common tips, tricks, and troubleshooting steps for working with Composite Resources. If you’re trying to track down why your Composite Resources aren’t working the Troubleshooting page also has some useful information.

Troubleshooting Claims and XRs

Crossplane relies heavily on status conditions and events for troubleshooting. You can see both using kubectl describe - for example:

1# Describe the PostgreSQLInstance claim named my-db
2kubectl describe my-db

Per Kubernetes convention, Crossplane keeps errors close to the place they happen. This means that if your claim is not becoming ready due to an issue with your Composition or with a composed resource you’ll need to “follow the references” to find out why. Your claim will only tell you that the XR is not yet ready.

To follow the references:

  1. Find your XR by running kubectl describe on your claim and looking for its “Resource Ref” (aka spec.resourceRef).
  2. Run kubectl describe on your XR. This is where you’ll find out about issues with the Composition you’re using, if any.
  3. If there are no issues but your XR doesn’t seem to be becoming ready, take a look for the “Resource Refs” (or spec.resourceRefs) to find your composed resources.
  4. Run kubectl describe on each referenced composed resource to determine whether it is ready and what issues, if any, it is encountering.

Composite Resource Connection Secrets

Claim and Composite Resource connection secrets are often derived from the connection secrets of the managed resources they compose. This is a common source of confusion because several things need to align for it to work:

  1. The XR/claim’s connection secret keys must be declared by the XRD.
  2. The Composition must specify how to derive connection details from each composed resource.
  3. If connection details are derived from a composed resource’s connection secret that composed resource must specify its writeConnectionSecretToRef.
  4. The claim and XR must both specify a writeConnectionSecretToRef.

Finally, you can’t currently edit a XRD’s supported connection details. The XRD’s spec.connectionSecretKeys is effectively immutable. This may change in future per this issue

Claiming an Existing Composite Resource

Most people create Composite Resources using a claim, but you can actually claim an existing Composite Resource as long as its a type of XR that offers a claim and no one else has already claimed it. To do so:

  1. Set the spec.resourceRef of your claim to reference the existing XR.
  2. Make sure the rest of your claim’s spec fields match the XR’s.

If your claim’s spec fields don’t match the XR’s Crossplane will still claim it but will then try to update the XR’s spec fields to match the claim’s.

Influencing External Names

The annotation has special meaning to Crossplane managed resources - it specifies the name (or identifier) of the resource in the external system, for example the actual name of a CloudSQLInstance in the GCP API. Some managed resources don’t let you specify an external name - in those cases Crossplane will set it for you to whatever the external system requires.

If you add the annotation to a claim Crossplane will automatically propagate it when it creates an XR. It’s good practice to have your Composition further propagate the annotation to one or more composed resources, but it’s not required.

Mixing and Matching Providers

Crossplane has providers for many things in addition to the big clouds. Take a look at the Upbound Marketplace to find many of them. Keep in mind that you can mix and match managed resources from different providers within a Composition to create Composite Resources. For example you might use provider-aws and provider-sql to create an XR that provisions an RDSInstance then creates an SQL Database and User, or provider-gcp and provider-helm to create a GKECluster and deploy a Helm Chart Release to it.

Often when mixing and matching providers you’ll need to compose a ProviderConfig for one provider that loads credentials from the connection secret of a managed resource from another provider. Sometimes you may need to use an intermediary XR to mutate the connection details to suit your needs. This example from provider-helm demonstrates using a GKE cluster connection secret as Helm ProviderConfig credentials.

Patching From One Composed Resource to Another

It’s not possible to patch directly from one composed resource to another - i.e. from one entry in the spec.resources array of a Composition to another. It is however possible to achieve this by using the XR as an intermediary. To do so:

  1. Use a ToCompositeFieldPath patch to patch from your source composed resource to the XR. Typically you’ll want to patch to a status field or an annotation.
  2. Use a FromCompositeFieldPath patch to patch from the ‘intermediary’ field you patched to in step 1 to a field on the destination composed resource.