Skip to content

Commit 7cd9d35

Browse files
authored
Merge pull request #1036 from jbw976/v2-conn-deets
backport connection details content to v2.1/v2.0
2 parents f9e78e8 + b1292f0 commit 7cd9d35

File tree

8 files changed

+708
-92
lines changed

8 files changed

+708
-92
lines changed

content/v2.0/composition/compositions.md

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ A [composite resource]({{<ref "./composite-resources">}}) or XR is a custom API.
5858
You use two Crossplane types to create a new custom API:
5959
6060
* A [Composite Resource Definition]({{<ref "./composite-resource-definitions">}})
61-
(XRD) - Defines the XR's schema.
61+
(XRD) - Defines the XR's schema.
6262
* A Composition - This page. Configures how the XR creates other resources.
6363
{{</expand >}}
6464
@@ -659,11 +659,11 @@ A function can change:
659659
* The `status` of the composite resource.
660660
* The `metadata` and `spec` of any composed resource.
661661

662-
A function can also change the connection details and readiness of the composite
663-
resource. A function indicates that the composite resource is ready by telling
664-
Crossplane whether its composed resources are ready. When the function pipeline
665-
tells Crossplane that all composed resources are ready, Crossplane marks the
666-
composite resource as ready.
662+
A function can also change the readiness of the composite resource. A function
663+
indicates that the composite resource is ready by telling Crossplane whether its
664+
composed resources are ready. When the function pipeline tells Crossplane that
665+
all composed resources are ready, Crossplane marks the composite resource as
666+
ready.
667667

668668
A function can't change:
669669

@@ -812,20 +812,20 @@ spec:
812812
kind: Script
813813
script: |
814814
from crossplane.function import request
815-
815+
816816
def compose(req, rsp):
817817
observed_xr = req.observed.composite.resource
818-
818+
819819
# Access the required ConfigMap using the helper function
820820
config_map = request.get_required_resource(req, "app-config")
821-
821+
822822
if not config_map:
823823
# Fallback image if ConfigMap not found
824824
image = "nginx:latest"
825825
else:
826826
# Read image from ConfigMap data
827827
image = config_map.get("data", {}).get("image", "nginx:latest")
828-
828+
829829
# Create deployment with the configured image
830830
rsp.desired.resources["deployment"].resource.update({
831831
"apiVersion": "apps/v1",
@@ -877,33 +877,33 @@ spec:
877877
kind: Script
878878
script: |
879879
from crossplane.function import request, response
880-
880+
881881
def compose(req, rsp):
882882
observed_xr = req.observed.composite.resource
883-
883+
884884
# Always request the ConfigMap to ensure stable requirements
885885
config_name = observed_xr["spec"].get("configName", "default-config")
886886
namespace = observed_xr["metadata"].get("namespace", "default")
887-
887+
888888
response.require_resources(
889-
rsp,
889+
rsp,
890890
name="dynamic-config",
891891
api_version="v1",
892892
kind="ConfigMap",
893893
match_name=config_name,
894894
namespace=namespace
895895
)
896-
896+
897897
# Check if we have the required ConfigMap
898898
config_map = request.get_required_resource(req, "dynamic-config")
899-
899+
900900
if not config_map:
901901
# ConfigMap not found yet - Crossplane will call us again
902902
return
903-
903+
904904
# ConfigMap found - use the image data to create deployment
905905
image = config_map.get("data", {}).get("image", "nginx:latest")
906-
906+
907907
rsp.desired.resources["deployment"].resource.update({
908908
"apiVersion": "apps/v1",
909909
"kind": "Deployment",
@@ -955,12 +955,12 @@ context.
955955
### Function response cache
956956

957957
{{<hint "note" >}}
958-
Function response caching is an alpha feature. Enable it by setting the
958+
Function response caching is an alpha feature. Enable it by setting the
959959
`--enable-function-response-cache` feature flag.
960960
{{< /hint >}}
961961

962-
Crossplane can cache function responses to improve performance by reducing
963-
repeated function calls. When enabled, Crossplane caches responses from
962+
Crossplane can cache function responses to improve performance by reducing
963+
repeated function calls. When enabled, Crossplane caches responses from
964964
composition functions that include a time to live (TTL) value.
965965

966966
The cache works by:
@@ -981,5 +981,5 @@ Control the cache behavior with these Crossplane pod arguments:
981981
- `--xfn-cache-max-ttl` - Maximum cache duration (default: 24 hours)
982982

983983
The cache stores files in the `/cache/xfn/` directory in the Crossplane pod.
984-
For better performance, consider using an in-memory cache by mounting an
984+
For better performance, consider using an in-memory cache by mounting an
985985
emptyDir volume with `medium: Memory`.

content/v2.0/guides/connection-details-composition.md

Lines changed: 195 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,34 @@ from the tabs below.
171171

172172
{{< tabs >}}
173173

174+
{{< tab "YAML" >}}
175+
176+
Create this composition function to install YAML support:
177+
178+
```yaml
179+
apiVersion: pkg.crossplane.io/v1
180+
kind: Function
181+
metadata:
182+
name: function-patch-and-transform
183+
spec:
184+
package: xpkg.crossplane.io/crossplane-contrib/function-patch-and-transform:v0.10.0
185+
```
186+
187+
Save the function as `fn.yaml` and apply it:
188+
189+
```shell
190+
kubectl apply -f fn.yaml
191+
```
192+
193+
Check that Crossplane installed the function:
194+
195+
```shell {copy-lines="1"}
196+
kubectl get -f fn.yaml
197+
NAME INSTALLED HEALTHY PACKAGE AGE
198+
function-patch-and-transform True True xpkg.crossplane.io/crossplane-contrib/function-patch-and-transform:v0.10.0 8s
199+
```
200+
{{< /tab >}}
201+
174202
{{< tab "Templated YAML" >}}
175203
Templated YAML is a good choice if you're used to writing
176204
[Helm charts](https://helm.sh).
@@ -306,6 +334,124 @@ exposes their credentials as the composite resource's connection details `Secret
306334

307335
{{< tabs >}}
308336

337+
{{< tab "YAML" >}}
338+
339+
```yaml {label="comp-pt"}
340+
apiVersion: apiextensions.crossplane.io/v1
341+
kind: Composition
342+
metadata:
343+
name: useraccesskeys-patch-and-transform
344+
spec:
345+
compositeTypeRef:
346+
apiVersion: example.org/v1alpha1
347+
kind: UserAccessKey
348+
mode: Pipeline
349+
pipeline:
350+
- step: patch-and-transform
351+
functionRef:
352+
name: function-patch-and-transform
353+
input:
354+
apiVersion: pt.fn.crossplane.io/v1beta1
355+
kind: Resources
356+
writeConnectionSecretToRef:
357+
patches:
358+
- type: FromCompositeFieldPath
359+
fromFieldPath: spec.writeConnectionSecretToRef.name
360+
toFieldPath: name
361+
resources:
362+
- name: user
363+
base:
364+
apiVersion: iam.aws.m.upbound.io/v1beta1
365+
kind: User
366+
spec:
367+
forProvider: {}
368+
- name: accesskey-0
369+
base:
370+
apiVersion: iam.aws.m.upbound.io/v1beta1
371+
kind: AccessKey
372+
spec:
373+
forProvider:
374+
userSelector:
375+
matchControllerRef: true
376+
writeConnectionSecretToRef:
377+
name: accesskey-secret-0
378+
connectionDetails:
379+
- name: user-0
380+
type: FromConnectionSecretKey
381+
fromConnectionSecretKey: username
382+
- name: password-0
383+
type: FromConnectionSecretKey
384+
fromConnectionSecretKey: password
385+
patches:
386+
- type: FromCompositeFieldPath
387+
fromFieldPath: metadata.name
388+
toFieldPath: spec.writeConnectionSecretToRef.name
389+
transforms:
390+
- type: string
391+
string:
392+
type: Format
393+
fmt: "%s-accesskey-secret-0"
394+
- name: accesskey-1
395+
base:
396+
apiVersion: iam.aws.m.upbound.io/v1beta1
397+
kind: AccessKey
398+
spec:
399+
forProvider:
400+
userSelector:
401+
matchControllerRef: true
402+
writeConnectionSecretToRef:
403+
name: accesskey-secret-1
404+
connectionDetails:
405+
- name: user-1
406+
type: FromConnectionSecretKey
407+
fromConnectionSecretKey: username
408+
- name: password-1
409+
type: FromConnectionSecretKey
410+
fromConnectionSecretKey: password
411+
patches:
412+
- type: FromCompositeFieldPath
413+
fromFieldPath: metadata.name
414+
toFieldPath: spec.writeConnectionSecretToRef.name
415+
transforms:
416+
- type: string
417+
string:
418+
type: Format
419+
fmt: "%s-accesskey-secret-1"
420+
- step: ready
421+
functionRef:
422+
name: function-auto-ready
423+
```
424+
425+
<!-- vale write-good.Passive = NO -->
426+
<!-- vale Google.WordList = NO -->
427+
**How this Composition exposes connection details:**
428+
429+
* Each composed {{<hover label="comp-pt" line="32">}}AccessKey{{</hover>}} has
430+
{{<hover label="comp-pt" line="37">}}writeConnectionSecretToRef{{</hover>}} set. This
431+
tells each `AccessKey` to write its credentials to an individual `Secret`.
432+
* Each {{<hover label="comp-pt" line="32">}}AccessKey{{</hover>}} defines
433+
{{<hover label="comp-pt" line="39">}}connectionDetails{{</hover>}} that specify which
434+
keys from its connection secret should be included in the XR's
435+
aggregated connection details secret.
436+
* The {{<hover label="comp-pt" line="40">}}name{{</hover>}} field in each connection
437+
detail entry sets the key name in the aggregated secret.
438+
* The {{<hover label="comp-pt" line="42">}}fromConnectionSecretKey{{</hover>}} field
439+
specifies which key to read from the composed resource's individual connection secret.
440+
* The function's input includes a top-level
441+
{{<hover label="comp-pt" line="17">}}writeConnectionSecretToRef{{</hover>}} section
442+
that allows you to specify where to create the connection secret.
443+
* The {{<hover label="comp-pt" line="18">}}patches{{</hover>}} in the
444+
`writeConnectionSecretToRef` section read the secret name from the XR's
445+
`.spec.writeConnectionSecretToRef.name` field.
446+
* The function automatically includes a `Secret` object in the XR's composed
447+
resources that represents the XR's aggregated connection details.
448+
* You don't need to create or compose this `Secret` yourself, it's done
449+
automatically for you.
450+
<!-- vale Google.WordList = YES -->
451+
<!-- vale write-good.Passive = YES -->
452+
453+
{{< /tab >}}
454+
309455
{{< tab "Templated YAML" >}}
310456

311457
```yaml {label="comp-gotmpl"}
@@ -754,22 +900,27 @@ kubectl get secret -n default -l crossplane.io/composite=my-keys -o jsonpath='{.
754900

755901
## Understanding how composing connection details works
756902

757-
The basic steps to expose connection details for a composite resource are:
903+
You can expose connection details for a composite resource using two approaches:
904+
905+
### Manual composition (most functions)
906+
907+
With functions like `function-go-templating`, `function-python`, `function-kcl`, and others,
908+
manually compose a `Secret` resource:
758909

759910
1. **Compose resources**: Create composed resources as usual in your
760911
composition, such as IAM `User` and `AccessKeys`. These resources expose
761912
their connection details in a `Secret`.
762913

763914
2. **Set `writeConnectionSecretToRef`**: Each composed resource that should have
764-
connection details stored in their own individual `Secret` should have their
765-
`writeConnectionSecretToRef` set in the composition.
915+
connection details stored should have their `writeConnectionSecretToRef` set
916+
in the composition.
766917

767918
3. **Observed connection details**: Crossplane observes the actual state of
768919
each composed resource, including its connection details, and makes this data
769-
available when it runs the function.
920+
available when the function runs.
770921

771-
4. **Compose the combined `Secret`**: With the observed connection details of
772-
your composed resources in hand, compose a `Secret` resource that combines
922+
4. **Compose the combined `Secret`**: Compose a `Secret` resource that reads
923+
from the observed connection details of your composed resources and combines
773924
the important connection details you want to expose for the XR. Consider
774925
allowing the consumer of the XR to specify the name they want this secret to
775926
have.
@@ -779,6 +930,30 @@ The basic steps to expose connection details for a composite resource are:
779930
Composition should handle these cases by checking if resources and
780931
their connection details exist before accessing them.
781932

933+
### Automatic aggregation (`function-patch-and-transform`)
934+
935+
`function-patch-and-transform` automatically observes connection details from
936+
composed resources and creates the aggregated connection secret to
937+
maintain backward compatibility with v1 behavior.
938+
939+
You don't need to manually compose a `Secret` resource yourself.
940+
941+
1. **Compose resources**: Create composed resources as usual in your
942+
composition, such as IAM `User` and `AccessKeys`. These resources expose
943+
their connection details in a `Secret`.
944+
945+
2. **Set `writeConnectionSecretToRef`**: Each composed resource that should have
946+
connection details stored should have their `writeConnectionSecretToRef` set
947+
in the composition.
948+
949+
3. **Define `connectionDetails`**: On each composed resource, define which
950+
connection secret keys to include in the aggregated secret using the
951+
`connectionDetails` field.
952+
953+
4. **Configure the `Secret`**: Add a `writeConnectionSecretToRef` section in the
954+
function's `input` to set the aggregated secret's name and namespace as
955+
needed. Use patches to configure these values using data from the XR if
956+
needed.
782957

783958
## Troubleshooting
784959

@@ -789,7 +964,8 @@ The basic steps to expose connection details for a composite resource are:
789964
<!-- vale write-good.Weasel = NO -->
790965
* Composed resources don't have `writeConnectionSecretToRef` set
791966
* Composed resources aren't ready/healthy yet
792-
* Not handling initial nil state correctly in the Composition
967+
* (`function-patch-and-transform`) Missing `connectionDetails` field on composed resources
968+
* (Manual composition) Not handling initial nil state correctly in the Composition
793969
<!-- vale write-good.Weasel = YES -->
794970

795971
<!-- vale write-good.Passive = NO -->
@@ -800,7 +976,10 @@ The basic steps to expose connection details for a composite resource are:
800976
* Wait for composed resources to become ready (`kubectl get` and check the `READY` column)
801977
* Verify the composed resource is actually producing connection details:
802978
`kubectl get secret <composed-resource-secret-name> -o yaml`
803-
* Add nil/empty checks in your Composition logic to safeguard access to data that may not exist yet
979+
* (`function-patch-and-transform`) Ensure each composed resource has a
980+
`connectionDetails` section that maps the desired secret keys
981+
* (Manual composition) Add nil/empty checks in your Composition logic to
982+
safeguard access to data that may not exist yet
804983
<!-- vale Google.WordList = YES -->
805984
<!-- vale write-good.Passive = YES -->
806985

@@ -810,11 +989,14 @@ The basic steps to expose connection details for a composite resource are:
810989

811990
**Cause:** Not encoding the combined secret data correctly in your Composition logic
812991

813-
**Solution:** Ensure that your connection details data is correctly encoded for
814-
the function you're using. For example, `function-python` requires you to
815-
convert connection details to base64-encoded strings, while connection details
816-
in `function-go-templating` and `function-kcl` are already encoded this way and
817-
require no conversion logic.
992+
**Solution:** This only applies to manual composition approaches. Ensure that
993+
your connection details data is correctly encoded for the function you're using.
994+
For example, `function-python` requires you to convert connection details to
995+
base64-encoded strings, while connection details in `function-go-templating` and
996+
`function-kcl` are already encoded this way and require no conversion logic.
997+
998+
`function-patch-and-transform` handles encoding when automatically creating the
999+
composed connection secret.
8181000
<!-- vale write-good.Weasel = YES -->
8191001
<!-- vale Google.Colons = YES -->
8201002

0 commit comments

Comments
 (0)