Skip to content

Commit bb768f6

Browse files
authored
Merge pull request #1039 from iciclespider/pythonic
Add function-pythonic information and examples
2 parents 59abc8a + 207125c commit bb768f6

4 files changed

Lines changed: 193 additions & 2 deletions

File tree

content/master/get-started/get-started-with-composition.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,38 @@ crossplane-contrib-function-kcl True True xpkg.crossplane.io/cross
312312
```
313313
{{< /tab >}}
314314

315+
{{< tab "Pythonic" >}}
316+
[Pythonic](https://github.com/crossplane-contrib/function-pythonic?tab=readme-ov-file#function-pythonic)
317+
is an excellent choice for compositions with dynamic logic. The full flexibility and power of python is
318+
available using a set of python classes with an elegant and terse syntax that hides the details of the low level
319+
Crossplane function APIs.
320+
321+
Create this composition function to install Pythonic support:
322+
323+
```yaml
324+
apiVersion: pkg.crossplane.io/v1
325+
kind: Function
326+
metadata:
327+
name: function-pythonic
328+
spec:
329+
package: xpkg.crossplane.io/crossplane-contrib/function-pythonic:v0.3.0
330+
```
331+
332+
Save the function as `fn.yaml` and apply it:
333+
334+
```shell
335+
kubectl apply -f fn.yaml
336+
```
337+
338+
Check that Crossplane installed the function:
339+
340+
```shell {copy-lines="1"}
341+
kubectl get -f fn.yaml
342+
NAME INSTALLED HEALTHY PACKAGE AGE
343+
function-pythonic True True xpkg.crossplane.io/crossplane-contrib/function-pythonic:v0.3.0 1m
344+
```
345+
{{< /tab >}}
346+
315347
{{</ tabs >}}
316348

317349
### Configure the composition
@@ -646,6 +678,52 @@ spec:
646678
```
647679
{{< /tab >}}
648680

681+
{{< tab "Pythonic" >}}
682+
Create this composition to use Pythonic to configure Crossplane:
683+
684+
```yaml
685+
apiVersion: apiextensions.crossplane.io/v1
686+
kind: Composition
687+
metadata:
688+
name: app-pythonic
689+
spec:
690+
compositeTypeRef:
691+
apiVersion: example.crossplane.io/v1
692+
kind: App
693+
mode: Pipeline
694+
pipeline:
695+
- step: create-deployment-and-service
696+
functionRef:
697+
name: function-pythonic
698+
input:
699+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
700+
kind: Composite
701+
composite: |
702+
class Composite(BaseComposite):
703+
def compose(self):
704+
labels = {'example.crossplane.io/app': self.metadata.name}
705+
706+
d = self.resources.deployment('apps/v1', 'Deployment')
707+
d.metadata.labels = labels
708+
d.spec.replicas = 2
709+
d.spec.selector.matchLabels = labels
710+
d.spec.template.metadata.labels = labels
711+
d.spec.template.spec.containers[0].name = 'app'
712+
d.spec.template.spec.containers[0].image = self.spec.image
713+
d.spec.template.spec.containers[0].ports[0].containerPort = 80
714+
715+
s = self.resources.service('v1', 'Service')
716+
s.metadata.labels = labels
717+
s.spec.selector = labels
718+
s.spec.ports[0].protocol = 'TCP'
719+
s.spec.ports[0].port = 8080
720+
s.spec.ports[0].targetPort = 80
721+
722+
self.status.replicas = d.status.availableReplicas
723+
self.status.address = s.observed.spec.clusterIP
724+
```
725+
{{< /tab >}}
726+
649727
{{</ tabs >}}
650728

651729
Save the composition as `composition.yaml` and apply it:

content/master/guides/connection-details-composition.md

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,34 @@ kubectl get -f fn.yaml
283283
NAME INSTALLED HEALTHY PACKAGE AGE
284284
function-kcl True True xpkg.crossplane.io/crossplane-contrib/function-kcl:v0.11.6 6s
285285
```
286+
{{< /tab>}}
287+
288+
{{< tab "Pythonic" >}}
289+
290+
Create this composition function to install [Pythonic](https://github.com/crossplane-contrib/function-pythonic?tab=readme-ov-file#function-pythonic) support:
291+
292+
```yaml
293+
apiVersion: pkg.crossplane.io/v1
294+
kind: Function
295+
metadata:
296+
name: function-pythonic
297+
spec:
298+
package: xpkg.crossplane.io/crossplane-contrib/function-pythonic:v0.3.0
299+
```
300+
301+
Save the function as `fn.yaml` and apply it:
302+
303+
```shell
304+
kubectl apply -f fn.yaml
305+
```
306+
307+
Check that Crossplane installed the function:
308+
309+
```shell {copy-lines="1"}
310+
kubectl get -f fn.yaml
311+
NAME INSTALLED HEALTHY PACKAGE AGE
312+
function-pythonic True True xpkg.crossplane.io/crossplane-contrib/function-pythonic:v0.3.0 1m
313+
```
286314
{{< /tab >}}
287315

288316
{{< /tabs >}}
@@ -786,6 +814,67 @@ spec:
786814

787815
{{< /tab >}}
788816

817+
{{< tab "Pythonic" >}}
818+
819+
```yaml {label="comp-pythonic"}
820+
apiVersion: apiextensions.crossplane.io/v1
821+
kind: Composition
822+
metadata:
823+
name: useraccesskeys-pythonic
824+
spec:
825+
compositeTypeRef:
826+
apiVersion: example.org/v1alpha1
827+
kind: UserAccessKey
828+
mode: Pipeline
829+
pipeline:
830+
- step: render-pythonic
831+
functionRef:
832+
name: function-pythonic
833+
input:
834+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
835+
kind: Composite
836+
composite: |
837+
class Composite(BaseComposite):
838+
def compose(self):
839+
self.connectionSecret = self.spec.writeConnectionSecretToRef
840+
841+
user = self.resources.user('iam.aws.m.upbound.io/v1beta1', 'User')
842+
user.spec.forProvider = {}
843+
844+
for ix in range(2):
845+
key = self.resources[f"access-key-{ix}"]('iam.aws.m.upbound.io/v1beta1', 'AccessKey')
846+
key.spec.forProvider.user = user.status.atProvider.id
847+
key.spec.writeConnectionSecretToRef.name = f"{self.metadata.name}-accesskey-{ix}"
848+
self.connection[f"user-{ix}"] = key.connection.username
849+
self.connection[f"password-{ix}"] = key.connection.password
850+
```
851+
852+
<!-- vale write-good.Passive = NO -->
853+
<!-- vale Google.WordList = NO -->
854+
**How this Composition exposes connection details:**
855+
856+
* Each composed {{<hover label="comp-pythonic" line="26">}}AccessKey{{</hover>}} has
857+
{{<hover label="comp-pythonic" line="28">}}writeConnectionSecretToRef{{</hover>}} set. This
858+
tells each AccessKey to write its credentials to an individual Secret.
859+
* Crossplane observes the connection details from each `AccessKey` and makes them
860+
available to the composition when the function runs.
861+
* The Secret reads `AccessKey`'s connection details via
862+
{{<hover label="comp-pythonic" line="29">}}connection.username{{</hover>}} and
863+
{{<hover label="comp-pythonic" line="30">}}connection.password{{</hover>}}.
864+
* The function establishes the connection `Secret` name from the XR
865+
{{<hover label="comp-pythonic" line="20">}}spec.writeConnectionSecretToRef{{</hover>}}
866+
if it exists.
867+
* The function automatically includes a `Secret` object in the XR's composed
868+
resources that represents the XR's aggregated connection details.
869+
* You don't need to create or compose this `Secret` yourself, it's done
870+
automatically for you.
871+
* In `function-pythonic`, connection details base64 encoding and decoding is handled
872+
automatically for you.
873+
<!-- vale Google.WordList = YES -->
874+
<!-- vale write-good.Passive = YES -->
875+
876+
{{< /tab >}}
877+
789878
{{< /tabs >}}
790879

791880
Save the composition as `composition.yaml` and apply it:
@@ -955,6 +1044,28 @@ You don't need to manually compose a `Secret` resource yourself.
9551044
needed. Use patches to configure these values using data from the XR if
9561045
needed.
9571046

1047+
### Automatic aggregation (`function-pythonic`)
1048+
1049+
`function-pythonic` automatically observes connection details from
1050+
composed resources and creates the aggregated connection secret to
1051+
maintain backward compatibility with v1 behavior.
1052+
1053+
You don't need to manually compose a `Secret` resource yourself.
1054+
1055+
1. **Compose resources**: Create composed resources as usual in your
1056+
composition, such as IAM `User` and `AccessKeys`. These resources expose
1057+
their connection details in a `Secret`.
1058+
1059+
2. **Set `writeConnectionSecretToRef`**: Each composed resource that should have
1060+
connection details stored should have their `resource.spec.writeConnectionSecretToRef` set
1061+
in the composition.
1062+
1063+
3. **Define `connection`**: For each composed resource, assign the connection secret
1064+
values wanted to the aggregated secret using `self.connection[key] = resource.connection[key]`.
1065+
1066+
4. **Configure the `Secret`**: Set the XR `self.connectionSecret` fields
1067+
to override the aggregated secret's default name and namespace.
1068+
9581069
## Troubleshooting
9591070

9601071
### Composite resource's connection details Secret is empty
@@ -995,8 +1106,8 @@ For example, `function-python` requires you to convert connection details to
9951106
base64-encoded strings, while connection details in `function-go-templating` and
9961107
`function-kcl` are already encoded this way and require no conversion logic.
9971108

998-
`function-patch-and-transform` handles encoding when automatically creating the
999-
composed connection secret.
1109+
`function-patch-and-transform` and `function-pythonic` handle encoding when automatically
1110+
creating the composed connection secret.
10001111
<!-- vale write-good.Weasel = YES -->
10011112
<!-- vale Google.Colons = YES -->
10021113

content/master/learn/community-extension-projects.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ use by Crossplane adopters.
9393
- [function-kcl](https://github.com/crossplane-contrib/function-kcl)
9494
- [function-patch-and-transform](https://github.com/crossplane-contrib/function-patch-and-transform)
9595
- [function-python](https://github.com/crossplane-contrib/function-python)
96+
- [function-pythonic](https://github.com/crossplane-contrib/function-pythonic)
9697
- [function-sequencer](https://github.com/crossplane-contrib/function-sequencer)
9798
- [function-shell](https://github.com/crossplane-contrib/function-shell)
9899
- [function-status-transformer](https://github.com/crossplane-contrib/function-status-transformer)

utils/vale/styles/Crossplane/crossplane-words.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ PatchSets
8282
ProviderConfig
8383
ProviderConfigs
8484
ProviderRevision
85+
Pythonic
8586
RunFunctionRequest
8687
RunFunctionRequests
8788
RunFunctionResponse

0 commit comments

Comments
 (0)