Crossplane Composition Patches – ToCompositeFieldPath

By the end of this post, combined with my previous Crossplane intro posts, you should be capable of implementing a fairly robust Crossplane configuration. There is a lot more to be familiar with, but you can get a long way just knowing what I’ve covered so far.

Continuing with the series on Crossplane Composition patches, Im covering ToCompositeFieldPath here. As the name implies, this is the inverse of FromCompositeFieldPath. It’s used when we need a value created in one resource template (Managed Resource) supplied to another resource template or nested XR. We can even use combinations of ToCompositeFieldPath and FromCompositeFieldPath to pass values from one nested XR to another,

I’ll once again use the aws platform reference configuration (link to repo here), as it has examples of ToCompositeFieldPath in several spots. To review, XRs (Composite Resources) select a Composition, within the Composition we have resource templates that create Managed Resources and/or other XRs (nested XR). All of the Managed Resources created by a Composition are then tied to the XR that selected the Composition.

Within the aws platform reference configuration, we see an XR called XCluster. XCluster accepts a few inputs to provision an EKS cluster (number of nodes, node size, and a chart version for Prometheus Helm chart). It selects a Composition called that has three templates in its resources block. All three are other XRs (this is referred to as nested XRs). I’ll focus on the XNetwork and XEKS resource templates. These two nested XRs result in a VPC with all the networking and an attached EKS cluster with all of the required IAM roles and attached policies.

Note: The XNetwork and XEKS XRs could be combined into a single XR, but having them separated provides modularity, allowing us to reuse the networking XR for other use cases that don’t include EKS.

Let’s take a look at a ‘basic’ ToCompositeFieldPath patch. In the ‘Clustter’ resource template of the nested XEKS XR Composition (This is the resource to create an EKS cluster, docs here) . Since ToCompositeFieldPath is the inverse of FromCompositeFieldPath, we have to think of the fromFieldPath and toFieldPath as inverse. We are taking a value created within the resource the template provisions and patching it to a field of the XR. In the case of the third patch below, the we are patching the status.atProvider.identity[0].oidc[0].issuer value to the status.eks.oidc field of the XR. In doing so, we can then patch that value into a separate resource template within the Composition.

Below, we see the resource template within the Composition that is patching from the field. We’ve create an EKS cluster, which generated an OIDC Issuer url, patched that value to the XR, and then created an OIDC Provider and supplied the Issuer url to it.

This next one is a bit trickier because it’s not patching to the XR from a Managed Resource. It’s patching to the XR from a nested XR. Again, think about From and To as inverse. When this nested XR is created it selects its own Composition. Within that Composition we patch that XR at the status.subnetIds field from resource templates that create subnets. Then via the second patch below, we patch the value of that XR’s status.subnetIds to this XR’s status.subnetIds. This is ultimately used to patch the subnetIds to the nested XEKS XR. This more complex patching method is how we pass values from one nested XR to another,

Note: In many cases, we can use Selectors to retrieve values between XRs and resource templates. In this case, we are going the longer way to work around a json patching challenge with arrays.

That’s the ToCompositeFieldPath patch. Next up will be CombineFromComposite and CombineToComposite patches.

Note: When patching to an XR, the field you are patching to must be defined via the XRD. A convenient ‘easy button’ is to add a freeform field within the XR’s status schema. With the below field, anything you patch to status.values will be created (e.g. status.values.someId will create the status.values.someId field on the fly)