crossplane-function-pythonic 0.1.4__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crossplane_function_pythonic-0.1.4/README.md → crossplane_function_pythonic-0.2.0/PKG-INFO +106 -48
- crossplane_function_pythonic-0.1.4/PKG-INFO → crossplane_function_pythonic-0.2.0/README.md +82 -72
- crossplane_function_pythonic-0.2.0/crossplane/pythonic/__about__.py +2 -0
- crossplane_function_pythonic-0.2.0/crossplane/pythonic/__main__.py +2 -0
- crossplane_function_pythonic-0.2.0/crossplane/pythonic/command.py +102 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/crossplane/pythonic/composite.py +50 -23
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/crossplane/pythonic/function.py +14 -10
- crossplane_function_pythonic-0.2.0/crossplane/pythonic/grpc.py +123 -0
- crossplane_function_pythonic-0.2.0/crossplane/pythonic/main.py +28 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/crossplane/pythonic/protobuf.py +9 -2
- crossplane_function_pythonic-0.2.0/crossplane/pythonic/render.py +432 -0
- crossplane_function_pythonic-0.2.0/crossplane/pythonic/version.py +13 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/.dev/functions.yaml +2 -2
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/aks-cluster/cluster-function-pythonic.yaml +1 -1
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/aks-cluster/composition.yaml +2 -2
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/aks-cluster/functions.yaml +2 -2
- crossplane_function_pythonic-0.2.0/examples/aks-cluster/render.sh +10 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/eks-cluster/composition-v2.yaml +3 -3
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/eks-cluster/composition.yaml +3 -3
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/eks-cluster/definition.yaml +3 -3
- {crossplane_function_pythonic-0.1.4/examples/import-existing-vpc → crossplane_function_pythonic-0.2.0/examples/eks-cluster}/functions.yaml +2 -2
- crossplane_function_pythonic-0.2.0/examples/eks-cluster/render-v2.sh +4 -0
- {crossplane_function_pythonic-0.1.4/examples/import-existing-vpc → crossplane_function_pythonic-0.2.0/examples/eks-cluster}/render.sh +1 -1
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/eks-cluster/xr.yaml +2 -2
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/filing-system/composition.yaml +1 -1
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/filing-system/function.yaml +2 -2
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/conditions/composition.yaml +1 -5
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/conditions/functions.yaml +10 -0
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/conditions/render.sh +4 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/context/composition.yaml +6 -17
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/context/environmentConfigs.yaml +1 -1
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/context/functions.yaml +10 -0
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/context/render.sh +4 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/extra-resources/composition.yaml +1 -1
- {crossplane_function_pythonic-0.1.4/examples/function-go-templating/functions/fromYaml → crossplane_function_pythonic-0.2.0/examples/function-go-templating/extra-resources}/functions.yaml +2 -2
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/extra-resources/render.sh +4 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/functions/fromYaml/composition.yaml +1 -1
- {crossplane_function_pythonic-0.1.4/examples/function-go-templating/functions/getComposedResource → crossplane_function_pythonic-0.2.0/examples/function-go-templating/functions/fromYaml}/functions.yaml +2 -2
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/functions/fromYaml/render.sh +4 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/functions/getComposedResource/composition.yaml +1 -1
- {crossplane_function_pythonic-0.1.4/examples/function-go-templating/extra-resources → crossplane_function_pythonic-0.2.0/examples/function-go-templating/functions/getComposedResource}/functions.yaml +2 -2
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/functions/getComposedResource/render.sh +4 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/functions/getCompositeResource/composition.yaml +1 -1
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/functions/getCompositeResource/functions.yaml +2 -2
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/functions/getCompositeResource/render.sh +4 -0
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/functions/getCredentialData/composition.yaml +27 -0
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/functions/getCredentialData/credentials.yaml +9 -0
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/functions/getCredentialData/functions.yaml +9 -0
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/functions/getCredentialData/render.sh +4 -0
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/functions/getCredentialData/xr.yaml +5 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/functions/getResourceCondition/composition.yaml +1 -1
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/functions/getResourceCondition/functions.yaml +9 -0
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/functions/getResourceCondition/render.sh +4 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/functions/include/composition.yaml +1 -1
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/functions/include/functions.yaml +9 -0
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/functions/include/render.sh +4 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/functions/toYaml/composition.yaml +1 -1
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/functions/toYaml/functions.yaml +9 -0
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/functions/toYaml/render.sh +4 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/inline/composition.yaml +1 -1
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/inline/functions.yaml +9 -0
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/inline/render.sh +4 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/recursive/composition-real.yaml +1 -1
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/recursive/composition-wrapper.yaml +1 -1
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/recursive/functions.yaml +9 -0
- crossplane_function_pythonic-0.2.0/examples/function-go-templating/recursive/render.sh +7 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/get-started-app/composition.yaml +1 -1
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/get-started-app/functions.yaml +2 -2
- crossplane_function_pythonic-0.2.0/examples/get-started-app/render.sh +4 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/helm-copy-secret/composition.yaml +1 -1
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/helm-copy-secret/functions.yaml +2 -2
- crossplane_function_pythonic-0.2.0/examples/helm-copy-secret/render.sh +4 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/helm-copy-secret/vcluster.py +1 -1
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/import-existing-vpc/composition.yaml +2 -2
- {crossplane_function_pythonic-0.1.4/examples/eks-cluster → crossplane_function_pythonic-0.2.0/examples/import-existing-vpc}/functions.yaml +2 -2
- crossplane_function_pythonic-0.2.0/examples/import-existing-vpc/render.sh +7 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/import-existing-vpc/xr.yaml +1 -1
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/single-purpose/functions.yaml +2 -2
- crossplane_function_pythonic-0.2.0/examples/single-purpose/render.sh +4 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/single-purpose/xr.yaml +1 -1
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/usages-extra/composition.yaml +1 -1
- crossplane_function_pythonic-0.2.0/examples/usages-extra/functions.yaml +9 -0
- crossplane_function_pythonic-0.2.0/examples/usages-extra/render.sh +4 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/pyproject.toml +16 -16
- crossplane_function_pythonic-0.1.4/crossplane/pythonic/main.py +0 -198
- crossplane_function_pythonic-0.1.4/examples/aks-cluster/render.sh +0 -9
- crossplane_function_pythonic-0.1.4/examples/eks-cluster/render-v2.sh +0 -3
- crossplane_function_pythonic-0.1.4/examples/eks-cluster/render.sh +0 -3
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/conditions/functions.yaml +0 -25
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/conditions/render.sh +0 -3
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/context/functions.yaml +0 -25
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/context/render.sh +0 -3
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/extra-resources/render.sh +0 -3
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/functions/fromYaml/render.sh +0 -3
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/functions/getComposedResource/render.sh +0 -3
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/functions/getCompositeResource/render.sh +0 -3
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/functions/getResourceCondition/functions.yaml +0 -9
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/functions/getResourceCondition/render.sh +0 -3
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/functions/include/functions.yaml +0 -9
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/functions/include/render.sh +0 -3
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/functions/toYaml/functions.yaml +0 -9
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/functions/toYaml/render.sh +0 -3
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/inline/functions.yaml +0 -9
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/inline/render.sh +0 -3
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/recursive/functions.yaml +0 -9
- crossplane_function_pythonic-0.1.4/examples/function-go-templating/recursive/render.sh +0 -4
- crossplane_function_pythonic-0.1.4/examples/get-started-app/render.sh +0 -3
- crossplane_function_pythonic-0.1.4/examples/helm-copy-secret/render.sh +0 -3
- crossplane_function_pythonic-0.1.4/examples/single-purpose/render.sh +0 -3
- crossplane_function_pythonic-0.1.4/examples/usages-extra/functions.yaml +0 -9
- crossplane_function_pythonic-0.1.4/examples/usages-extra/render.sh +0 -3
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/.gitignore +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/LICENSE +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/crossplane/pythonic/__init__.py +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/crossplane/pythonic/packages.py +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/aks-cluster/README.md +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/aks-cluster/aks/kubernetescluster.py +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/aks-cluster/aks/resourcegroup.py +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/aks-cluster/definition.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/aks-cluster/install.sh +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/aks-cluster/kustomization.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/aks-cluster/providers.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/aks-cluster/xr.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/filing-system/README.md +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/filing-system/definition.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/filing-system/kustomization.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/filing-system/runtime.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/filing-system/vcluster.py +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/filing-system/vcluster.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/conditions/xr.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/conditions/xrd.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/context/xr.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/context/xrd.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/extra-resources/extraResources.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/extra-resources/xr.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/functions/fromYaml/xr.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/functions/getComposedResource/observed.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/functions/getComposedResource/xr.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/functions/getCompositeResource/xr.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/functions/getResourceCondition/observed.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/functions/getResourceCondition/xr.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/functions/include/xr.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/functions/toYaml/xr.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/inline/xr.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/function-go-templating/recursive/xr.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/get-started-app/definition.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/get-started-app/xr.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/helm-copy-secret/kustomization.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/helm-copy-secret/run-function.sh +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/helm-copy-secret/xr.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/helm-copy-secret/xrd.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/import-existing-vpc/README.md +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/import-existing-vpc/definition.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/import-existing-vpc/observed.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/import-existing-vpc/provider-ec2.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/usages-extra/extraResources.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/usages-extra/observedResources.yaml +0 -0
- {crossplane_function_pythonic-0.1.4 → crossplane_function_pythonic-0.2.0}/examples/usages-extra/xr.yaml +0 -0
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: crossplane-function-pythonic
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: A Python centric Crossplane Function
|
|
5
|
+
Project-URL: Documentation, https://github.com/crossplane-contrib/function-pythonic#readme
|
|
6
|
+
Project-URL: Issues, https://github.com/crossplane-contrib/function-pythonic/issues
|
|
7
|
+
Project-URL: Source, https://github.com/crossplane-contrib/function-pythonic
|
|
8
|
+
Author-email: Patrick J McNerthney <pat@mcnerthney.com>
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Requires-Python: <3.15,>=3.12
|
|
17
|
+
Requires-Dist: crossplane-function-sdk-python==0.10.0
|
|
18
|
+
Requires-Dist: pyyaml==6.0.3
|
|
19
|
+
Provides-Extra: packages
|
|
20
|
+
Requires-Dist: kopf==1.39.1; extra == 'packages'
|
|
21
|
+
Provides-Extra: pip-install
|
|
22
|
+
Requires-Dist: pip==25.3; extra == 'pip-install'
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
1
25
|
# function-pythonic
|
|
2
26
|
|
|
3
27
|
## Introduction
|
|
@@ -21,11 +45,11 @@ spec:
|
|
|
21
45
|
kind: XR
|
|
22
46
|
mode: Pipeline
|
|
23
47
|
pipeline:
|
|
24
|
-
- step:
|
|
48
|
+
- step:
|
|
25
49
|
functionRef:
|
|
26
50
|
name: function-pythonic
|
|
27
51
|
input:
|
|
28
|
-
apiVersion: pythonic.fn.
|
|
52
|
+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
|
|
29
53
|
kind: Composite
|
|
30
54
|
composite: |
|
|
31
55
|
class VpcComposite(BaseComposite):
|
|
@@ -57,7 +81,7 @@ kind: Function
|
|
|
57
81
|
metadata:
|
|
58
82
|
name: function-pythonic
|
|
59
83
|
spec:
|
|
60
|
-
package:
|
|
84
|
+
package: xpkg.upbound.io/crossplane-contrib/function-pythonic:v0.2.0
|
|
61
85
|
```
|
|
62
86
|
## Composed Resource Dependencies
|
|
63
87
|
|
|
@@ -203,7 +227,7 @@ The BaseComposite class provides the following fields for manipulating the Compo
|
|
|
203
227
|
| self.spec | Map | The composite observed spec |
|
|
204
228
|
| self.status | Map | The composite desired and observed status, read from observed if not in desired |
|
|
205
229
|
| self.conditions | Conditions | The composite desired and observed conditions, read from observed if not in desired |
|
|
206
|
-
| self.
|
|
230
|
+
| self.results | Results | Returned results applied to the Composite and optionally on the Claim |
|
|
207
231
|
| self.connection | Connection | The composite desired and observed connection detials, read from observed if not in desired |
|
|
208
232
|
| self.ready | Boolean | The composite desired ready state |
|
|
209
233
|
|
|
@@ -302,19 +326,19 @@ The fields are read only for `Resource.conditions` and `RequiredResource.conditi
|
|
|
302
326
|
| Condition.lastTransitionTime | Timestamp | Last transition time, read only |
|
|
303
327
|
| Condition.claim | Boolean | Also apply the condition the claim |
|
|
304
328
|
|
|
305
|
-
###
|
|
329
|
+
### Results
|
|
306
330
|
|
|
307
|
-
The `BaseComposite.
|
|
331
|
+
The `BaseComposite.results` field is a list of results to apply to the Composite and
|
|
308
332
|
optionally to the Claim.
|
|
309
333
|
|
|
310
334
|
| Field | Type | Description |
|
|
311
335
|
| ----- | ---- | ----------- |
|
|
312
|
-
|
|
|
313
|
-
|
|
|
314
|
-
|
|
|
315
|
-
|
|
|
316
|
-
|
|
|
317
|
-
|
|
|
336
|
+
| Result.info | Boolean | Normal informational result |
|
|
337
|
+
| Result.warning | Boolean | Warning level result |
|
|
338
|
+
| Result.fatal | Boolean | Fatal results also terminate composing the Composite |
|
|
339
|
+
| Result.reason | String | PascalCase, machine-readable reason for this result |
|
|
340
|
+
| Result.message | String | Human-readable details about the result |
|
|
341
|
+
| Result.claim | Boolean | Also apply the result to the claim |
|
|
318
342
|
|
|
319
343
|
## Single use Composites
|
|
320
344
|
|
|
@@ -324,7 +348,7 @@ just to run that Composition once in a single use or initialize task?
|
|
|
324
348
|
function-pythonic installs a `Composite` CompositeResourceDefinition that enables
|
|
325
349
|
creating such tasks using a single Composite resource:
|
|
326
350
|
```yaml
|
|
327
|
-
apiVersion: pythonic.
|
|
351
|
+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
|
|
328
352
|
kind: Composite
|
|
329
353
|
metadata:
|
|
330
354
|
name: composite-example
|
|
@@ -337,16 +361,62 @@ spec:
|
|
|
337
361
|
|
|
338
362
|
## Quick Start Development
|
|
339
363
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
364
|
+
function-pythonic includes a pure python implementation of the `crossplane render ...`
|
|
365
|
+
command, which can be used to render Compositions that only use function-pythonic. This
|
|
366
|
+
makes it very easy to test and debug using your IDE of choice. It is also blindingly
|
|
367
|
+
fast compared to `crossplane render`. To use, install the `crossplane-function-pythonic`
|
|
368
|
+
python package into the python environment.
|
|
343
369
|
```shell
|
|
344
370
|
$ pip install crossplane-function-pythonic
|
|
345
371
|
```
|
|
346
|
-
|
|
372
|
+
Then to render function-pythonic Compositions, use the `function-pythonic render ...`
|
|
373
|
+
command.
|
|
374
|
+
```shell
|
|
375
|
+
$ function-pythonic render --help
|
|
376
|
+
usage: Crossplane Function Pythonic render [-h] [--debug] [--log-name-width WIDTH] [--python-path DIRECTORY] [--render-unknowns]
|
|
377
|
+
[--allow-oversize-protos] [--context-files KEY=PATH] [--context-values KEY=VALUE]
|
|
378
|
+
[--observed-resources PATH] [--extra-resources PATH] [--required-resources PATH]
|
|
379
|
+
[--function-credentials PATH] [--include-full-xr] [--include-function-results] [--include-context]
|
|
380
|
+
PATH [PATH/CLASS]
|
|
381
|
+
|
|
382
|
+
positional arguments:
|
|
383
|
+
PATH A YAML file containing the Composite resource to render.
|
|
384
|
+
PATH/CLASS A YAML file containing the Composition resource or the complete path of a function=-pythonic BaseComposite subclass.
|
|
385
|
+
|
|
386
|
+
options:
|
|
387
|
+
-h, --help show this help message and exit
|
|
388
|
+
--debug, -d Emit debug logs.
|
|
389
|
+
--log-name-width WIDTH
|
|
390
|
+
Width of the logger name in the log output, default 40.
|
|
391
|
+
--python-path DIRECTORY
|
|
392
|
+
Filing system directories to add to the python path.
|
|
393
|
+
--render-unknowns, -u
|
|
394
|
+
Render resources with unknowns, useful during local development.
|
|
395
|
+
--allow-oversize-protos
|
|
396
|
+
Allow oversized protobuf messages
|
|
397
|
+
--context-files KEY=PATH
|
|
398
|
+
Context key-value pairs to pass to the Function pipeline. Values must be files containing YAML/JSON.
|
|
399
|
+
--context-values KEY=VALUE
|
|
400
|
+
Context key-value pairs to pass to the Function pipeline. Values must be YAML/JSON. Keys take precedence over --context-files.
|
|
401
|
+
--observed-resources, -o PATH
|
|
402
|
+
A YAML file or directory of YAML files specifying the observed state of composed resources.
|
|
403
|
+
--extra-resources PATH
|
|
404
|
+
A YAML file or directory of YAML files specifying required resources (deprecated, use --required-resources).
|
|
405
|
+
--required-resources, -e PATH
|
|
406
|
+
A YAML file or directory of YAML files specifying required resources to pass to the Function pipeline.
|
|
407
|
+
--function-credentials PATH
|
|
408
|
+
A YAML file or directory of YAML files specifying credentials to use for Functions to render the XR.
|
|
409
|
+
--include-full-xr, -x
|
|
410
|
+
Include a direct copy of the input XR's spedc and metadata fields in the rendered output.
|
|
411
|
+
--include-function-results, -r
|
|
412
|
+
Include informational and warning messages from Functions in the rendered output as resources of kind: Result..
|
|
413
|
+
--include-context, -c
|
|
414
|
+
Include the context in the rendered output as a resource of kind: Context.
|
|
415
|
+
```
|
|
416
|
+
The following example demonstrates how to locally render function-python compositions. First, create the following files:
|
|
347
417
|
#### xr.yaml
|
|
348
418
|
```yaml
|
|
349
|
-
apiVersion: pythonic.
|
|
419
|
+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
|
|
350
420
|
kind: Hello
|
|
351
421
|
metadata:
|
|
352
422
|
name: world
|
|
@@ -358,10 +428,10 @@ spec:
|
|
|
358
428
|
apiVersion: apiextensions.crossplane.io/v1
|
|
359
429
|
kind: Composition
|
|
360
430
|
metadata:
|
|
361
|
-
name: hellos.pythonic.
|
|
431
|
+
name: hellos.pythonic.crossplane.io
|
|
362
432
|
spec:
|
|
363
433
|
compositeTypeRef:
|
|
364
|
-
apiVersion: pythonic.
|
|
434
|
+
apiVersion: pythonic.crossplane.io/v1alpha1
|
|
365
435
|
kind: Hello
|
|
366
436
|
mode: Pipeline
|
|
367
437
|
pipeline:
|
|
@@ -369,50 +439,38 @@ spec:
|
|
|
369
439
|
functionRef:
|
|
370
440
|
name: function-pythonic
|
|
371
441
|
input:
|
|
372
|
-
apiVersion: pythonic.fn.
|
|
442
|
+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
|
|
373
443
|
kind: Composite
|
|
374
444
|
composite: |
|
|
375
445
|
class GreetingComposite(BaseComposite):
|
|
376
446
|
def compose(self):
|
|
377
447
|
self.status.greeting = f"Hello, {self.spec.who}!"
|
|
378
448
|
```
|
|
379
|
-
|
|
380
|
-
```yaml
|
|
381
|
-
apiVersion: pkg.crossplane.io/v1beta1
|
|
382
|
-
kind: Function
|
|
383
|
-
metadata:
|
|
384
|
-
name: function-pythonic
|
|
385
|
-
annotations:
|
|
386
|
-
render.crossplane.io/runtime: Development
|
|
387
|
-
spec:
|
|
388
|
-
package: ghcr.io/fortra/function-pythonic:v0.1.3
|
|
389
|
-
```
|
|
390
|
-
In one terminal session, run function-pythonic:
|
|
391
|
-
```shell
|
|
392
|
-
$ function-pythonic --insecure --debug --render-unknowns
|
|
393
|
-
[2025-08-21 15:32:37.966] grpc._cython.cygrpc [DEBUG ] Using AsyncIOEngine.POLLER as I/O engine
|
|
394
|
-
```
|
|
395
|
-
In another terminal session, render the Composite:
|
|
449
|
+
Then, to render the above composite and composition, run:
|
|
396
450
|
```shell
|
|
397
|
-
$
|
|
451
|
+
$ function-pythonic render --debug --render-unknowns xr.yaml composition.yaml
|
|
452
|
+
[2025-12-29 09:44:57.949] io.crossplane.fn.pythonic.Hello.world [DEBUG ] Starting compose, 1st step, 1st pass
|
|
453
|
+
[2025-12-29 09:44:57.949] io.crossplane.fn.pythonic.Hello.world [INFO ] Completed compose
|
|
398
454
|
---
|
|
399
|
-
apiVersion: pythonic.
|
|
455
|
+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
|
|
400
456
|
kind: Hello
|
|
401
457
|
metadata:
|
|
402
458
|
name: world
|
|
403
459
|
status:
|
|
404
460
|
conditions:
|
|
405
|
-
- lastTransitionTime:
|
|
461
|
+
- lastTransitionTime: '2026-01-01T00:00:00Z'
|
|
406
462
|
reason: Available
|
|
407
|
-
status:
|
|
463
|
+
status: 'True'
|
|
408
464
|
type: Ready
|
|
409
|
-
- lastTransitionTime:
|
|
465
|
+
- lastTransitionTime: '2026-01-01T00:00:00Z'
|
|
410
466
|
message: All resources are composed
|
|
411
467
|
reason: AllComposed
|
|
412
|
-
status:
|
|
468
|
+
status: 'True'
|
|
413
469
|
type: ResourcesComposed
|
|
414
470
|
greeting: Hello, World!
|
|
415
471
|
```
|
|
472
|
+
Most of the examples contain a `render.sh` command which uses `function-pythonic render` to
|
|
473
|
+
render the example.
|
|
416
474
|
|
|
417
475
|
## ConfigMap Packages
|
|
418
476
|
|
|
@@ -441,7 +499,7 @@ Then, in your Composition:
|
|
|
441
499
|
functionRef:
|
|
442
500
|
name: function-pythonic
|
|
443
501
|
input:
|
|
444
|
-
apiVersion: pythonic.fn.
|
|
502
|
+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
|
|
445
503
|
kind: Composite
|
|
446
504
|
composite: |
|
|
447
505
|
from example.pythonic import features
|
|
@@ -473,7 +531,7 @@ data:
|
|
|
473
531
|
functionRef:
|
|
474
532
|
name: function-pythonic
|
|
475
533
|
input:
|
|
476
|
-
apiVersion: pythonic.fn.
|
|
534
|
+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
|
|
477
535
|
kind: Composite
|
|
478
536
|
composite: example.pythonic.features.FeatureOneComposite
|
|
479
537
|
...
|
|
@@ -487,7 +545,7 @@ kind: Function
|
|
|
487
545
|
metadata:
|
|
488
546
|
name: function-pythonic
|
|
489
547
|
spec:
|
|
490
|
-
package:
|
|
548
|
+
package: xpkg.upbound.io/crossplane-contrib/function-pythonic:v0.2.0
|
|
491
549
|
runtimeConfigRef:
|
|
492
550
|
name: function-pythonic
|
|
493
551
|
---
|
|
@@ -580,7 +638,7 @@ data:
|
|
|
580
638
|
functionRef:
|
|
581
639
|
name: function-pythonic
|
|
582
640
|
input:
|
|
583
|
-
apiVersion: pythonic.fn.
|
|
641
|
+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
|
|
584
642
|
kind: Composite
|
|
585
643
|
parameters:
|
|
586
644
|
who: World
|
|
@@ -1,27 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: crossplane-function-pythonic
|
|
3
|
-
Version: 0.1.4
|
|
4
|
-
Summary: A Python centric Crossplane Function
|
|
5
|
-
Project-URL: Documentation, https://github.com/fortra/function-pythonic#readme
|
|
6
|
-
Project-URL: Issues, https://github.com/fortra/function-pythonic/issues
|
|
7
|
-
Project-URL: Source, https://github.com/fortra/function-pythonic
|
|
8
|
-
Author-email: Patrick J McNerthney <pat@mcnerthney.com>
|
|
9
|
-
License-Expression: Apache-2.0
|
|
10
|
-
License-File: LICENSE
|
|
11
|
-
Classifier: Development Status :: 4 - Beta
|
|
12
|
-
Classifier: Programming Language :: Python
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
-
Requires-Python: <3.14,>=3.11
|
|
17
|
-
Requires-Dist: crossplane-function-sdk-python==0.9.0
|
|
18
|
-
Requires-Dist: pyyaml==6.0.2
|
|
19
|
-
Provides-Extra: packages
|
|
20
|
-
Requires-Dist: kopf==1.38.0; extra == 'packages'
|
|
21
|
-
Provides-Extra: pip-install
|
|
22
|
-
Requires-Dist: pip==25.2; extra == 'pip-install'
|
|
23
|
-
Description-Content-Type: text/markdown
|
|
24
|
-
|
|
25
1
|
# function-pythonic
|
|
26
2
|
|
|
27
3
|
## Introduction
|
|
@@ -45,11 +21,11 @@ spec:
|
|
|
45
21
|
kind: XR
|
|
46
22
|
mode: Pipeline
|
|
47
23
|
pipeline:
|
|
48
|
-
- step:
|
|
24
|
+
- step:
|
|
49
25
|
functionRef:
|
|
50
26
|
name: function-pythonic
|
|
51
27
|
input:
|
|
52
|
-
apiVersion: pythonic.fn.
|
|
28
|
+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
|
|
53
29
|
kind: Composite
|
|
54
30
|
composite: |
|
|
55
31
|
class VpcComposite(BaseComposite):
|
|
@@ -81,7 +57,7 @@ kind: Function
|
|
|
81
57
|
metadata:
|
|
82
58
|
name: function-pythonic
|
|
83
59
|
spec:
|
|
84
|
-
package:
|
|
60
|
+
package: xpkg.upbound.io/crossplane-contrib/function-pythonic:v0.2.0
|
|
85
61
|
```
|
|
86
62
|
## Composed Resource Dependencies
|
|
87
63
|
|
|
@@ -227,7 +203,7 @@ The BaseComposite class provides the following fields for manipulating the Compo
|
|
|
227
203
|
| self.spec | Map | The composite observed spec |
|
|
228
204
|
| self.status | Map | The composite desired and observed status, read from observed if not in desired |
|
|
229
205
|
| self.conditions | Conditions | The composite desired and observed conditions, read from observed if not in desired |
|
|
230
|
-
| self.
|
|
206
|
+
| self.results | Results | Returned results applied to the Composite and optionally on the Claim |
|
|
231
207
|
| self.connection | Connection | The composite desired and observed connection detials, read from observed if not in desired |
|
|
232
208
|
| self.ready | Boolean | The composite desired ready state |
|
|
233
209
|
|
|
@@ -326,19 +302,19 @@ The fields are read only for `Resource.conditions` and `RequiredResource.conditi
|
|
|
326
302
|
| Condition.lastTransitionTime | Timestamp | Last transition time, read only |
|
|
327
303
|
| Condition.claim | Boolean | Also apply the condition the claim |
|
|
328
304
|
|
|
329
|
-
###
|
|
305
|
+
### Results
|
|
330
306
|
|
|
331
|
-
The `BaseComposite.
|
|
307
|
+
The `BaseComposite.results` field is a list of results to apply to the Composite and
|
|
332
308
|
optionally to the Claim.
|
|
333
309
|
|
|
334
310
|
| Field | Type | Description |
|
|
335
311
|
| ----- | ---- | ----------- |
|
|
336
|
-
|
|
|
337
|
-
|
|
|
338
|
-
|
|
|
339
|
-
|
|
|
340
|
-
|
|
|
341
|
-
|
|
|
312
|
+
| Result.info | Boolean | Normal informational result |
|
|
313
|
+
| Result.warning | Boolean | Warning level result |
|
|
314
|
+
| Result.fatal | Boolean | Fatal results also terminate composing the Composite |
|
|
315
|
+
| Result.reason | String | PascalCase, machine-readable reason for this result |
|
|
316
|
+
| Result.message | String | Human-readable details about the result |
|
|
317
|
+
| Result.claim | Boolean | Also apply the result to the claim |
|
|
342
318
|
|
|
343
319
|
## Single use Composites
|
|
344
320
|
|
|
@@ -348,7 +324,7 @@ just to run that Composition once in a single use or initialize task?
|
|
|
348
324
|
function-pythonic installs a `Composite` CompositeResourceDefinition that enables
|
|
349
325
|
creating such tasks using a single Composite resource:
|
|
350
326
|
```yaml
|
|
351
|
-
apiVersion: pythonic.
|
|
327
|
+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
|
|
352
328
|
kind: Composite
|
|
353
329
|
metadata:
|
|
354
330
|
name: composite-example
|
|
@@ -361,16 +337,62 @@ spec:
|
|
|
361
337
|
|
|
362
338
|
## Quick Start Development
|
|
363
339
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
340
|
+
function-pythonic includes a pure python implementation of the `crossplane render ...`
|
|
341
|
+
command, which can be used to render Compositions that only use function-pythonic. This
|
|
342
|
+
makes it very easy to test and debug using your IDE of choice. It is also blindingly
|
|
343
|
+
fast compared to `crossplane render`. To use, install the `crossplane-function-pythonic`
|
|
344
|
+
python package into the python environment.
|
|
367
345
|
```shell
|
|
368
346
|
$ pip install crossplane-function-pythonic
|
|
369
347
|
```
|
|
370
|
-
|
|
348
|
+
Then to render function-pythonic Compositions, use the `function-pythonic render ...`
|
|
349
|
+
command.
|
|
350
|
+
```shell
|
|
351
|
+
$ function-pythonic render --help
|
|
352
|
+
usage: Crossplane Function Pythonic render [-h] [--debug] [--log-name-width WIDTH] [--python-path DIRECTORY] [--render-unknowns]
|
|
353
|
+
[--allow-oversize-protos] [--context-files KEY=PATH] [--context-values KEY=VALUE]
|
|
354
|
+
[--observed-resources PATH] [--extra-resources PATH] [--required-resources PATH]
|
|
355
|
+
[--function-credentials PATH] [--include-full-xr] [--include-function-results] [--include-context]
|
|
356
|
+
PATH [PATH/CLASS]
|
|
357
|
+
|
|
358
|
+
positional arguments:
|
|
359
|
+
PATH A YAML file containing the Composite resource to render.
|
|
360
|
+
PATH/CLASS A YAML file containing the Composition resource or the complete path of a function=-pythonic BaseComposite subclass.
|
|
361
|
+
|
|
362
|
+
options:
|
|
363
|
+
-h, --help show this help message and exit
|
|
364
|
+
--debug, -d Emit debug logs.
|
|
365
|
+
--log-name-width WIDTH
|
|
366
|
+
Width of the logger name in the log output, default 40.
|
|
367
|
+
--python-path DIRECTORY
|
|
368
|
+
Filing system directories to add to the python path.
|
|
369
|
+
--render-unknowns, -u
|
|
370
|
+
Render resources with unknowns, useful during local development.
|
|
371
|
+
--allow-oversize-protos
|
|
372
|
+
Allow oversized protobuf messages
|
|
373
|
+
--context-files KEY=PATH
|
|
374
|
+
Context key-value pairs to pass to the Function pipeline. Values must be files containing YAML/JSON.
|
|
375
|
+
--context-values KEY=VALUE
|
|
376
|
+
Context key-value pairs to pass to the Function pipeline. Values must be YAML/JSON. Keys take precedence over --context-files.
|
|
377
|
+
--observed-resources, -o PATH
|
|
378
|
+
A YAML file or directory of YAML files specifying the observed state of composed resources.
|
|
379
|
+
--extra-resources PATH
|
|
380
|
+
A YAML file or directory of YAML files specifying required resources (deprecated, use --required-resources).
|
|
381
|
+
--required-resources, -e PATH
|
|
382
|
+
A YAML file or directory of YAML files specifying required resources to pass to the Function pipeline.
|
|
383
|
+
--function-credentials PATH
|
|
384
|
+
A YAML file or directory of YAML files specifying credentials to use for Functions to render the XR.
|
|
385
|
+
--include-full-xr, -x
|
|
386
|
+
Include a direct copy of the input XR's spedc and metadata fields in the rendered output.
|
|
387
|
+
--include-function-results, -r
|
|
388
|
+
Include informational and warning messages from Functions in the rendered output as resources of kind: Result..
|
|
389
|
+
--include-context, -c
|
|
390
|
+
Include the context in the rendered output as a resource of kind: Context.
|
|
391
|
+
```
|
|
392
|
+
The following example demonstrates how to locally render function-python compositions. First, create the following files:
|
|
371
393
|
#### xr.yaml
|
|
372
394
|
```yaml
|
|
373
|
-
apiVersion: pythonic.
|
|
395
|
+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
|
|
374
396
|
kind: Hello
|
|
375
397
|
metadata:
|
|
376
398
|
name: world
|
|
@@ -382,10 +404,10 @@ spec:
|
|
|
382
404
|
apiVersion: apiextensions.crossplane.io/v1
|
|
383
405
|
kind: Composition
|
|
384
406
|
metadata:
|
|
385
|
-
name: hellos.pythonic.
|
|
407
|
+
name: hellos.pythonic.crossplane.io
|
|
386
408
|
spec:
|
|
387
409
|
compositeTypeRef:
|
|
388
|
-
apiVersion: pythonic.
|
|
410
|
+
apiVersion: pythonic.crossplane.io/v1alpha1
|
|
389
411
|
kind: Hello
|
|
390
412
|
mode: Pipeline
|
|
391
413
|
pipeline:
|
|
@@ -393,50 +415,38 @@ spec:
|
|
|
393
415
|
functionRef:
|
|
394
416
|
name: function-pythonic
|
|
395
417
|
input:
|
|
396
|
-
apiVersion: pythonic.fn.
|
|
418
|
+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
|
|
397
419
|
kind: Composite
|
|
398
420
|
composite: |
|
|
399
421
|
class GreetingComposite(BaseComposite):
|
|
400
422
|
def compose(self):
|
|
401
423
|
self.status.greeting = f"Hello, {self.spec.who}!"
|
|
402
424
|
```
|
|
403
|
-
|
|
404
|
-
```yaml
|
|
405
|
-
apiVersion: pkg.crossplane.io/v1beta1
|
|
406
|
-
kind: Function
|
|
407
|
-
metadata:
|
|
408
|
-
name: function-pythonic
|
|
409
|
-
annotations:
|
|
410
|
-
render.crossplane.io/runtime: Development
|
|
411
|
-
spec:
|
|
412
|
-
package: ghcr.io/fortra/function-pythonic:v0.1.3
|
|
413
|
-
```
|
|
414
|
-
In one terminal session, run function-pythonic:
|
|
415
|
-
```shell
|
|
416
|
-
$ function-pythonic --insecure --debug --render-unknowns
|
|
417
|
-
[2025-08-21 15:32:37.966] grpc._cython.cygrpc [DEBUG ] Using AsyncIOEngine.POLLER as I/O engine
|
|
418
|
-
```
|
|
419
|
-
In another terminal session, render the Composite:
|
|
425
|
+
Then, to render the above composite and composition, run:
|
|
420
426
|
```shell
|
|
421
|
-
$
|
|
427
|
+
$ function-pythonic render --debug --render-unknowns xr.yaml composition.yaml
|
|
428
|
+
[2025-12-29 09:44:57.949] io.crossplane.fn.pythonic.Hello.world [DEBUG ] Starting compose, 1st step, 1st pass
|
|
429
|
+
[2025-12-29 09:44:57.949] io.crossplane.fn.pythonic.Hello.world [INFO ] Completed compose
|
|
422
430
|
---
|
|
423
|
-
apiVersion: pythonic.
|
|
431
|
+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
|
|
424
432
|
kind: Hello
|
|
425
433
|
metadata:
|
|
426
434
|
name: world
|
|
427
435
|
status:
|
|
428
436
|
conditions:
|
|
429
|
-
- lastTransitionTime:
|
|
437
|
+
- lastTransitionTime: '2026-01-01T00:00:00Z'
|
|
430
438
|
reason: Available
|
|
431
|
-
status:
|
|
439
|
+
status: 'True'
|
|
432
440
|
type: Ready
|
|
433
|
-
- lastTransitionTime:
|
|
441
|
+
- lastTransitionTime: '2026-01-01T00:00:00Z'
|
|
434
442
|
message: All resources are composed
|
|
435
443
|
reason: AllComposed
|
|
436
|
-
status:
|
|
444
|
+
status: 'True'
|
|
437
445
|
type: ResourcesComposed
|
|
438
446
|
greeting: Hello, World!
|
|
439
447
|
```
|
|
448
|
+
Most of the examples contain a `render.sh` command which uses `function-pythonic render` to
|
|
449
|
+
render the example.
|
|
440
450
|
|
|
441
451
|
## ConfigMap Packages
|
|
442
452
|
|
|
@@ -465,7 +475,7 @@ Then, in your Composition:
|
|
|
465
475
|
functionRef:
|
|
466
476
|
name: function-pythonic
|
|
467
477
|
input:
|
|
468
|
-
apiVersion: pythonic.fn.
|
|
478
|
+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
|
|
469
479
|
kind: Composite
|
|
470
480
|
composite: |
|
|
471
481
|
from example.pythonic import features
|
|
@@ -497,7 +507,7 @@ data:
|
|
|
497
507
|
functionRef:
|
|
498
508
|
name: function-pythonic
|
|
499
509
|
input:
|
|
500
|
-
apiVersion: pythonic.fn.
|
|
510
|
+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
|
|
501
511
|
kind: Composite
|
|
502
512
|
composite: example.pythonic.features.FeatureOneComposite
|
|
503
513
|
...
|
|
@@ -511,7 +521,7 @@ kind: Function
|
|
|
511
521
|
metadata:
|
|
512
522
|
name: function-pythonic
|
|
513
523
|
spec:
|
|
514
|
-
package:
|
|
524
|
+
package: xpkg.upbound.io/crossplane-contrib/function-pythonic:v0.2.0
|
|
515
525
|
runtimeConfigRef:
|
|
516
526
|
name: function-pythonic
|
|
517
527
|
---
|
|
@@ -604,7 +614,7 @@ data:
|
|
|
604
614
|
functionRef:
|
|
605
615
|
name: function-pythonic
|
|
606
616
|
input:
|
|
607
|
-
apiVersion: pythonic.fn.
|
|
617
|
+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
|
|
608
618
|
kind: Composite
|
|
609
619
|
parameters:
|
|
610
620
|
who: World
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
|
|
2
|
+
import logging
|
|
3
|
+
import pathlib
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Command:
|
|
8
|
+
name = None
|
|
9
|
+
command = None
|
|
10
|
+
description = None
|
|
11
|
+
|
|
12
|
+
@classmethod
|
|
13
|
+
def create(cls, subparsers):
|
|
14
|
+
parser = subparsers.add_parser(cls.name, help=cls.help, description=cls.description)
|
|
15
|
+
parser.set_defaults(command=cls)
|
|
16
|
+
cls.add_parser_arguments(parser)
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def add_parser_arguments(cls, parser):
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
@classmethod
|
|
23
|
+
def add_function_arguments(cls, parser):
|
|
24
|
+
parser.add_argument(
|
|
25
|
+
'--debug', '-d',
|
|
26
|
+
action='store_true',
|
|
27
|
+
help='Emit debug logs.',
|
|
28
|
+
)
|
|
29
|
+
parser.add_argument(
|
|
30
|
+
'--log-name-width',
|
|
31
|
+
type=int,
|
|
32
|
+
default=40,
|
|
33
|
+
metavar='WIDTH',
|
|
34
|
+
help='Width of the logger name in the log output, default 40.',
|
|
35
|
+
)
|
|
36
|
+
parser.add_argument(
|
|
37
|
+
'--python-path',
|
|
38
|
+
action='append',
|
|
39
|
+
default=[],
|
|
40
|
+
metavar='DIRECTORY',
|
|
41
|
+
help='Filing system directories to add to the python path.',
|
|
42
|
+
)
|
|
43
|
+
parser.add_argument(
|
|
44
|
+
'--render-unknowns', '-u',
|
|
45
|
+
action='store_true',
|
|
46
|
+
help='Render resources with unknowns, useful during local development.'
|
|
47
|
+
)
|
|
48
|
+
parser.add_argument(
|
|
49
|
+
'--allow-oversize-protos',
|
|
50
|
+
action='store_true',
|
|
51
|
+
help='Allow oversized protobuf messages',
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def __init__(self, args):
|
|
55
|
+
self.args = args
|
|
56
|
+
self.initialize()
|
|
57
|
+
|
|
58
|
+
def initialize(self):
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
def initialize_function(self):
|
|
62
|
+
formatter = Formatter(self.args.log_name_width)
|
|
63
|
+
handler = logging.StreamHandler(sys.stdout)
|
|
64
|
+
handler.setFormatter(formatter)
|
|
65
|
+
logger = logging.getLogger()
|
|
66
|
+
logger.handlers = [handler]
|
|
67
|
+
logger.setLevel(logging.DEBUG if self.args.debug else logging.INFO)
|
|
68
|
+
|
|
69
|
+
for path in reversed(self.args.python_path):
|
|
70
|
+
sys.path.insert(0, str(pathlib.Path(path).expanduser().resolve()))
|
|
71
|
+
|
|
72
|
+
if self.args.allow_oversize_protos:
|
|
73
|
+
from google.protobuf.internal import api_implementation
|
|
74
|
+
if api_implementation._c_module:
|
|
75
|
+
api_implementation._c_module.SetAllowOversizeProtos(True)
|
|
76
|
+
|
|
77
|
+
async def run(self):
|
|
78
|
+
raise NotImplementedError()
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class Formatter(logging.Formatter):
|
|
82
|
+
def __init__(self, name_width):
|
|
83
|
+
super(Formatter, self).__init__(
|
|
84
|
+
f"[{{asctime}}.{{msecs:03.0f}}] {{sname:{name_width}.{name_width}}} [{{levelname:8.8}}] {{message}}",
|
|
85
|
+
'%Y-%m-%d %H:%M:%S',
|
|
86
|
+
'{',
|
|
87
|
+
)
|
|
88
|
+
self.name_width = name_width
|
|
89
|
+
|
|
90
|
+
def format(self, record):
|
|
91
|
+
record.sname = record.name
|
|
92
|
+
extra = len(record.sname) - self.name_width
|
|
93
|
+
if extra > 0:
|
|
94
|
+
names = record.sname.split('.')
|
|
95
|
+
for ix, name in enumerate(names):
|
|
96
|
+
if len(name) > extra:
|
|
97
|
+
names[ix] = name[extra:]
|
|
98
|
+
break
|
|
99
|
+
names[ix] = name[:1]
|
|
100
|
+
extra -= len(name) - 1
|
|
101
|
+
record.sname = '.'.join(names)
|
|
102
|
+
return super(Formatter, self).format(record)
|