crossplane-function-pythonic 0.6.2__tar.gz → 0.6.3__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.6.2 → crossplane_function_pythonic-0.6.3}/PKG-INFO +23 -26
- {crossplane_function_pythonic-0.6.2 → crossplane_function_pythonic-0.6.3}/README.md +11 -9
- crossplane_function_pythonic-0.6.3/pyproject.toml +57 -0
- crossplane_function_pythonic-0.6.3/pyproject.toml.orig +58 -0
- crossplane_function_pythonic-0.6.3/src/crossplane/pythonic/__about__.py +8 -0
- crossplane_function_pythonic-0.6.3/src/crossplane/pythonic/__init__.py +25 -0
- {crossplane_function_pythonic-0.6.2 → crossplane_function_pythonic-0.6.3/src}/crossplane/pythonic/__main__.py +1 -0
- {crossplane_function_pythonic-0.6.2 → crossplane_function_pythonic-0.6.3/src}/crossplane/pythonic/auto_ready.py +89 -41
- {crossplane_function_pythonic-0.6.2 → crossplane_function_pythonic-0.6.3/src}/crossplane/pythonic/command.py +43 -39
- {crossplane_function_pythonic-0.6.2 → crossplane_function_pythonic-0.6.3/src}/crossplane/pythonic/composite.py +93 -68
- crossplane_function_pythonic-0.6.3/src/crossplane/pythonic/diff.py +880 -0
- {crossplane_function_pythonic-0.6.2 → crossplane_function_pythonic-0.6.3/src}/crossplane/pythonic/function.py +185 -103
- crossplane_function_pythonic-0.6.3/src/crossplane/pythonic/grpc.py +173 -0
- crossplane_function_pythonic-0.6.3/src/crossplane/pythonic/main.py +37 -0
- {crossplane_function_pythonic-0.6.2 → crossplane_function_pythonic-0.6.3/src}/crossplane/pythonic/packages.py +65 -42
- {crossplane_function_pythonic-0.6.2 → crossplane_function_pythonic-0.6.3/src}/crossplane/pythonic/proto/v1/run_function_pb2.py +3 -3
- {crossplane_function_pythonic-0.6.2 → crossplane_function_pythonic-0.6.3/src}/crossplane/pythonic/proto/v1/run_function_pb2_grpc.py +4 -4
- {crossplane_function_pythonic-0.6.2 → crossplane_function_pythonic-0.6.3/src}/crossplane/pythonic/protobuf.py +281 -214
- {crossplane_function_pythonic-0.6.2 → crossplane_function_pythonic-0.6.3/src}/crossplane/pythonic/render.py +408 -200
- {crossplane_function_pythonic-0.6.2 → crossplane_function_pythonic-0.6.3/src}/crossplane/pythonic/version.py +2 -3
- crossplane_function_pythonic-0.6.2/.gitignore +0 -219
- crossplane_function_pythonic-0.6.2/LICENSE +0 -201
- crossplane_function_pythonic-0.6.2/crossplane/pythonic/__about__.py +0 -2
- crossplane_function_pythonic-0.6.2/crossplane/pythonic/__init__.py +0 -17
- crossplane_function_pythonic-0.6.2/crossplane/pythonic/grpc.py +0 -150
- crossplane_function_pythonic-0.6.2/crossplane/pythonic/main.py +0 -28
- crossplane_function_pythonic-0.6.2/examples/aks-cluster/README.md +0 -129
- crossplane_function_pythonic-0.6.2/examples/aks-cluster/aks/kubernetescluster.py +0 -29
- crossplane_function_pythonic-0.6.2/examples/aks-cluster/aks/resourcegroup.py +0 -12
- crossplane_function_pythonic-0.6.2/examples/aks-cluster/cluster-function-pythonic.yaml +0 -63
- crossplane_function_pythonic-0.6.2/examples/aks-cluster/composition.yaml +0 -24
- crossplane_function_pythonic-0.6.2/examples/aks-cluster/definition.yaml +0 -45
- crossplane_function_pythonic-0.6.2/examples/aks-cluster/install.sh +0 -13
- crossplane_function_pythonic-0.6.2/examples/aks-cluster/kustomization.yaml +0 -20
- crossplane_function_pythonic-0.6.2/examples/aks-cluster/providers.yaml +0 -14
- crossplane_function_pythonic-0.6.2/examples/aks-cluster/render.sh +0 -4
- crossplane_function_pythonic-0.6.2/examples/aks-cluster/xr.yaml +0 -16
- crossplane_function_pythonic-0.6.2/examples/connection-details-composition/composition.yaml +0 -30
- crossplane_function_pythonic-0.6.2/examples/connection-details-composition/definition.yaml +0 -26
- crossplane_function_pythonic-0.6.2/examples/connection-details-composition/observed.yaml +0 -49
- crossplane_function_pythonic-0.6.2/examples/connection-details-composition/render.sh +0 -5
- crossplane_function_pythonic-0.6.2/examples/connection-details-composition/resources.yaml +0 -18
- crossplane_function_pythonic-0.6.2/examples/connection-details-composition/xr.yaml +0 -8
- crossplane_function_pythonic-0.6.2/examples/connections/composition.yaml +0 -39
- crossplane_function_pythonic-0.6.2/examples/connections/observed.yaml +0 -21
- crossplane_function_pythonic-0.6.2/examples/connections/render.sh +0 -7
- crossplane_function_pythonic-0.6.2/examples/connections/resources.yaml +0 -27
- crossplane_function_pythonic-0.6.2/examples/connections/xr.yaml +0 -8
- crossplane_function_pythonic-0.6.2/examples/eks-cluster/composition-v2.yaml +0 -138
- crossplane_function_pythonic-0.6.2/examples/eks-cluster/composition.yaml +0 -126
- crossplane_function_pythonic-0.6.2/examples/eks-cluster/definition.yaml +0 -47
- crossplane_function_pythonic-0.6.2/examples/eks-cluster/render-v2.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/eks-cluster/render.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/eks-cluster/xr.yaml +0 -13
- crossplane_function_pythonic-0.6.2/examples/filing-system/README.md +0 -13
- crossplane_function_pythonic-0.6.2/examples/filing-system/composition.yaml +0 -17
- crossplane_function_pythonic-0.6.2/examples/filing-system/definition.yaml +0 -21
- crossplane_function_pythonic-0.6.2/examples/filing-system/kustomization.yaml +0 -18
- crossplane_function_pythonic-0.6.2/examples/filing-system/runtime.yaml +0 -23
- crossplane_function_pythonic-0.6.2/examples/filing-system/vcluster.py +0 -38
- crossplane_function_pythonic-0.6.2/examples/filing-system/vcluster.yaml +0 -5
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/conditions/composition.yaml +0 -31
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/conditions/render.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/conditions/xr.yaml +0 -5
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/conditions/xrd.yaml +0 -25
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/context/composition.yaml +0 -31
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/context/render.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/context/resources.yaml +0 -10
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/context/xr.yaml +0 -5
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/context/xrd.yaml +0 -25
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/fromYaml/composition.yaml +0 -21
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/fromYaml/render.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/fromYaml/xr.yaml +0 -9
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/getComposedResource/composition.yaml +0 -28
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/getComposedResource/observed.yaml +0 -20
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/getComposedResource/render.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/getComposedResource/xr.yaml +0 -6
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/getCompositeResource/composition.yaml +0 -23
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/getCompositeResource/render.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/getCompositeResource/xr.yaml +0 -7
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/getCredentialData/composition.yaml +0 -27
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/getCredentialData/render.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/getCredentialData/resources.yaml +0 -9
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/getCredentialData/xr.yaml +0 -5
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/getResourceCondition/composition.yaml +0 -27
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/getResourceCondition/observed.yaml +0 -21
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/getResourceCondition/render.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/getResourceCondition/xr.yaml +0 -12
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/include/composition.yaml +0 -41
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/include/render.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/include/xr.yaml +0 -7
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/toYaml/composition.yaml +0 -21
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/toYaml/render.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/functions/toYaml/xr.yaml +0 -12
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/inline/composition.yaml +0 -35
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/inline/render.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/inline/xr.yaml +0 -6
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/recursive/composition-real.yaml +0 -21
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/recursive/composition.yaml +0 -23
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/recursive/render.sh +0 -4
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/recursive/xr.yaml +0 -8
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/required-resources/composition.yaml +0 -29
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/required-resources/render.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/required-resources/resources.yaml +0 -14
- crossplane_function_pythonic-0.6.2/examples/function-go-templating/required-resources/xr.yaml +0 -6
- crossplane_function_pythonic-0.6.2/examples/function-sequencer/composition.yaml +0 -48
- crossplane_function_pythonic-0.6.2/examples/function-sequencer/observed.yaml +0 -27
- crossplane_function_pythonic-0.6.2/examples/function-sequencer/render.sh +0 -11
- crossplane_function_pythonic-0.6.2/examples/function-sequencer/sequencer.py +0 -12
- crossplane_function_pythonic-0.6.2/examples/function-sequencer/xr.yaml +0 -6
- crossplane_function_pythonic-0.6.2/examples/get-started-app/composition.yaml +0 -39
- crossplane_function_pythonic-0.6.2/examples/get-started-app/definition.yaml +0 -35
- crossplane_function_pythonic-0.6.2/examples/get-started-app/observed.yaml +0 -53
- crossplane_function_pythonic-0.6.2/examples/get-started-app/render.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/get-started-app/xr.yaml +0 -7
- crossplane_function_pythonic-0.6.2/examples/helm-copy-secret/composition.yaml +0 -17
- crossplane_function_pythonic-0.6.2/examples/helm-copy-secret/kustomization.yaml +0 -16
- crossplane_function_pythonic-0.6.2/examples/helm-copy-secret/render.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/helm-copy-secret/vcluster.py +0 -63
- crossplane_function_pythonic-0.6.2/examples/helm-copy-secret/xr.yaml +0 -5
- crossplane_function_pythonic-0.6.2/examples/helm-copy-secret/xrd.yaml +0 -21
- crossplane_function_pythonic-0.6.2/examples/import-existing-vpc/README.md +0 -35
- crossplane_function_pythonic-0.6.2/examples/import-existing-vpc/composition.yaml +0 -68
- crossplane_function_pythonic-0.6.2/examples/import-existing-vpc/definition.yaml +0 -39
- crossplane_function_pythonic-0.6.2/examples/import-existing-vpc/observed.yaml +0 -6
- crossplane_function_pythonic-0.6.2/examples/import-existing-vpc/provider-ec2.yaml +0 -20
- crossplane_function_pythonic-0.6.2/examples/import-existing-vpc/render.sh +0 -4
- crossplane_function_pythonic-0.6.2/examples/import-existing-vpc/xr.yaml +0 -10
- crossplane_function_pythonic-0.6.2/examples/inlined/composition.yaml +0 -17
- crossplane_function_pythonic-0.6.2/examples/inlined/definition.yaml +0 -32
- crossplane_function_pythonic-0.6.2/examples/inlined/render.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/inlined/xr.yaml +0 -10
- crossplane_function_pythonic-0.6.2/examples/run-all.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/usages-extra/composition.yaml +0 -26
- crossplane_function_pythonic-0.6.2/examples/usages-extra/observed.yaml +0 -6
- crossplane_function_pythonic-0.6.2/examples/usages-extra/render.sh +0 -3
- crossplane_function_pythonic-0.6.2/examples/usages-extra/resources.yaml +0 -7
- crossplane_function_pythonic-0.6.2/examples/usages-extra/xr.yaml +0 -6
- crossplane_function_pythonic-0.6.2/pyproject.toml +0 -153
- {crossplane_function_pythonic-0.6.2 → crossplane_function_pythonic-0.6.3/src}/crossplane/pythonic/proto/v1/run_function.proto +0 -0
- {crossplane_function_pythonic-0.6.2 → crossplane_function_pythonic-0.6.3/src}/crossplane/pythonic/proto/v1/run_function_pb2.pyi +0 -0
|
@@ -1,28 +1,23 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: crossplane-function-pythonic
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.3
|
|
4
4
|
Summary: A Python centric Crossplane Function
|
|
5
|
-
|
|
6
|
-
Project-URL: Issues, https://github.com/crossplane-contrib/function-pythonic/issues
|
|
7
|
-
Project-URL: Source, https://github.com/crossplane-contrib/function-pythonic
|
|
5
|
+
Author: Patrick J McNerthney
|
|
8
6
|
Author-email: Patrick J McNerthney <pat@mcnerthney.com>
|
|
9
7
|
License-Expression: Apache-2.0
|
|
10
|
-
|
|
11
|
-
|
|
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: grpcio==1.83.0
|
|
18
|
-
Requires-Dist: inflect==7.5.0
|
|
8
|
+
Requires-Dist: grpcio==1.84.0
|
|
9
|
+
Requires-Dist: inflect==7.6.0
|
|
19
10
|
Requires-Dist: kr8s==0.20.15
|
|
20
|
-
Requires-Dist: protobuf==7.
|
|
11
|
+
Requires-Dist: protobuf==7.36.2
|
|
21
12
|
Requires-Dist: pyyaml==6.0.3
|
|
13
|
+
Requires-Dist: kopf==1.45.1 ; extra == 'packages'
|
|
14
|
+
Requires-Dist: pip==26.2.2 ; extra == 'pip-install'
|
|
15
|
+
Requires-Python: >=3.12, <3.16
|
|
16
|
+
Project-URL: Documentation, https://github.com/crossplane-contrib/function-pythonic#readme
|
|
17
|
+
Project-URL: Issues, https://github.com/crossplane-contrib/function-pythonic/issues
|
|
18
|
+
Project-URL: Source, https://github.com/crossplane-contrib/function-pythonic
|
|
22
19
|
Provides-Extra: packages
|
|
23
|
-
Requires-Dist: kopf==1.44.6; extra == 'packages'
|
|
24
20
|
Provides-Extra: pip-install
|
|
25
|
-
Requires-Dist: pip==26.2.1; extra == 'pip-install'
|
|
26
21
|
Description-Content-Type: text/markdown
|
|
27
22
|
|
|
28
23
|
# function-pythonic
|
|
@@ -213,7 +208,7 @@ message contents. For example, the following examples obtain the same value
|
|
|
213
208
|
from the RunFunctionRequest message:
|
|
214
209
|
```python
|
|
215
210
|
region = request.observed.composite.resource.spec.region
|
|
216
|
-
region = request[
|
|
211
|
+
region = request["observed"]["composite"]["resource"]["spec"]["region"]
|
|
217
212
|
```
|
|
218
213
|
Getting values from free form map and list values will not throw
|
|
219
214
|
errors for keys that do not exist, but will return an unknown placeholder
|
|
@@ -232,13 +227,15 @@ When setting fields, all intermediary unknown placeholders will automatically
|
|
|
232
227
|
be created. For example, this will create all items needed to set the
|
|
233
228
|
region on the desired resource:
|
|
234
229
|
```python
|
|
235
|
-
response.desired.resources.vpc.resource.spec.forProvider.region =
|
|
230
|
+
response.desired.resources.vpc.resource.spec.forProvider.region = "us-east-1"
|
|
236
231
|
```
|
|
237
232
|
Calling a message or map will clear it and will set any provided key word
|
|
238
233
|
arguments. For example, this will either create or clear the resource
|
|
239
234
|
and then set its apiVersion and kind:
|
|
240
235
|
```python
|
|
241
|
-
response.desired.resources.vpc.resource(
|
|
236
|
+
response.desired.resources.vpc.resource(
|
|
237
|
+
kind="VPC", apiVersion="ec2.aws.crossplane.io/v1beta1"
|
|
238
|
+
)
|
|
242
239
|
```
|
|
243
240
|
The following functions are provided to create Protobuf structures:
|
|
244
241
|
| Function | Description |
|
|
@@ -257,12 +254,12 @@ The following items are supported in all the Protobuf Message wrapper classes: `
|
|
|
257
254
|
|
|
258
255
|
To convert a Protobuf message to a string value, use either `str` or `format`.
|
|
259
256
|
```python
|
|
260
|
-
yaml
|
|
261
|
-
yaml
|
|
262
|
-
yaml
|
|
263
|
-
json
|
|
264
|
-
json
|
|
265
|
-
proto = format(request,
|
|
257
|
+
yaml = str(request) # get the request as yaml
|
|
258
|
+
yaml = format(request) # also get the request as yaml
|
|
259
|
+
yaml = format(request, "yaml") # yet another get the request as yaml
|
|
260
|
+
json = format(request, "json") # get the request as json
|
|
261
|
+
json = format(request, "jsonc") # get the request as json compact
|
|
262
|
+
proto = format(request, "protobuf") # get the request as a protobuf string
|
|
266
263
|
```
|
|
267
264
|
## Composite Composition
|
|
268
265
|
|
|
@@ -186,7 +186,7 @@ message contents. For example, the following examples obtain the same value
|
|
|
186
186
|
from the RunFunctionRequest message:
|
|
187
187
|
```python
|
|
188
188
|
region = request.observed.composite.resource.spec.region
|
|
189
|
-
region = request[
|
|
189
|
+
region = request["observed"]["composite"]["resource"]["spec"]["region"]
|
|
190
190
|
```
|
|
191
191
|
Getting values from free form map and list values will not throw
|
|
192
192
|
errors for keys that do not exist, but will return an unknown placeholder
|
|
@@ -205,13 +205,15 @@ When setting fields, all intermediary unknown placeholders will automatically
|
|
|
205
205
|
be created. For example, this will create all items needed to set the
|
|
206
206
|
region on the desired resource:
|
|
207
207
|
```python
|
|
208
|
-
response.desired.resources.vpc.resource.spec.forProvider.region =
|
|
208
|
+
response.desired.resources.vpc.resource.spec.forProvider.region = "us-east-1"
|
|
209
209
|
```
|
|
210
210
|
Calling a message or map will clear it and will set any provided key word
|
|
211
211
|
arguments. For example, this will either create or clear the resource
|
|
212
212
|
and then set its apiVersion and kind:
|
|
213
213
|
```python
|
|
214
|
-
response.desired.resources.vpc.resource(
|
|
214
|
+
response.desired.resources.vpc.resource(
|
|
215
|
+
kind="VPC", apiVersion="ec2.aws.crossplane.io/v1beta1"
|
|
216
|
+
)
|
|
215
217
|
```
|
|
216
218
|
The following functions are provided to create Protobuf structures:
|
|
217
219
|
| Function | Description |
|
|
@@ -230,12 +232,12 @@ The following items are supported in all the Protobuf Message wrapper classes: `
|
|
|
230
232
|
|
|
231
233
|
To convert a Protobuf message to a string value, use either `str` or `format`.
|
|
232
234
|
```python
|
|
233
|
-
yaml
|
|
234
|
-
yaml
|
|
235
|
-
yaml
|
|
236
|
-
json
|
|
237
|
-
json
|
|
238
|
-
proto = format(request,
|
|
235
|
+
yaml = str(request) # get the request as yaml
|
|
236
|
+
yaml = format(request) # also get the request as yaml
|
|
237
|
+
yaml = format(request, "yaml") # yet another get the request as yaml
|
|
238
|
+
json = format(request, "json") # get the request as json
|
|
239
|
+
json = format(request, "jsonc") # get the request as json compact
|
|
240
|
+
proto = format(request, "protobuf") # get the request as a protobuf string
|
|
239
241
|
```
|
|
240
242
|
## Composite Composition
|
|
241
243
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "crossplane-function-pythonic"
|
|
3
|
+
version = "0.6.3"
|
|
4
|
+
description = "A Python centric Crossplane Function"
|
|
5
|
+
license = "Apache-2.0"
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
requires-python = ">=3.12,<3.16"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"grpcio==1.84.0",
|
|
10
|
+
"inflect==7.6.0",
|
|
11
|
+
"kr8s==0.20.15",
|
|
12
|
+
"protobuf==7.36.2",
|
|
13
|
+
"pyyaml==6.0.3",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[[project.authors]]
|
|
17
|
+
name = "Patrick J McNerthney"
|
|
18
|
+
email = "pat@mcnerthney.com"
|
|
19
|
+
|
|
20
|
+
[project.optional-dependencies]
|
|
21
|
+
packages = ["kopf==1.45.1"]
|
|
22
|
+
pip-install = ["pip==26.2.2"]
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
Documentation = "https://github.com/crossplane-contrib/function-pythonic#readme"
|
|
26
|
+
Issues = "https://github.com/crossplane-contrib/function-pythonic/issues"
|
|
27
|
+
Source = "https://github.com/crossplane-contrib/function-pythonic"
|
|
28
|
+
|
|
29
|
+
[project.scripts]
|
|
30
|
+
function-pythonic = "crossplane.pythonic.main:main"
|
|
31
|
+
|
|
32
|
+
[build-system]
|
|
33
|
+
requires = ["uv_build>=0.12.23,<0.13.0"]
|
|
34
|
+
build-backend = "uv_build"
|
|
35
|
+
|
|
36
|
+
[dependency-groups]
|
|
37
|
+
dev = [
|
|
38
|
+
"grpcio-tools>=1.84.0",
|
|
39
|
+
"poethepoet>=0.48.0",
|
|
40
|
+
"pytest>=9.1.1",
|
|
41
|
+
"pytest-asyncio>=1.4.0",
|
|
42
|
+
"pytest-cov>=7.1.0",
|
|
43
|
+
"ruff>=0.17.0",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[tool.uv.build-backend]
|
|
47
|
+
module-name = "crossplane.pythonic"
|
|
48
|
+
|
|
49
|
+
[tool.poe.tasks]
|
|
50
|
+
generate-protoc = "python -m grpc_tools.protoc --proto_path=src --python_out=src --pyi_out=src --grpc_python_out=src crossplane/pythonic/proto/v1/run_function.proto"
|
|
51
|
+
test = "pytest tests -x --verbose --verbose --cov --cov-report=term --cov-report=html:reports"
|
|
52
|
+
test-protobuf = "pytest tests/test_protobuf_*.py -x --verbose --verbose --cov --cov-report=term --cov-report=html:reports"
|
|
53
|
+
test-ci = "pytest tests --verbose --verbose --junitxml=reports/pytest-junit.xml --cov --cov-report=term --cov-report=xml:reports/pytest-coverage.xml"
|
|
54
|
+
|
|
55
|
+
[tool.pytest.ini_options]
|
|
56
|
+
pythonpath = ["."]
|
|
57
|
+
filterwarnings = ["ignore:'asyncio.iscoroutinefunction' is deprecated:DeprecationWarning:kr8s._vendored.asyncache"]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "crossplane-function-pythonic"
|
|
3
|
+
version = "0.6.3"
|
|
4
|
+
description = "A Python centric Crossplane Function"
|
|
5
|
+
license = "Apache-2.0"
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "Patrick J McNerthney", email = "pat@mcnerthney.com" }
|
|
9
|
+
]
|
|
10
|
+
requires-python = ">=3.12,<3.16"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"grpcio==1.84.0",
|
|
13
|
+
"inflect==7.6.0",
|
|
14
|
+
"kr8s==0.20.15",
|
|
15
|
+
"protobuf==7.36.2",
|
|
16
|
+
"pyyaml==6.0.3",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.optional-dependencies]
|
|
20
|
+
packages = ["kopf==1.45.1"]
|
|
21
|
+
pip-install = ["pip==26.2.2"]
|
|
22
|
+
|
|
23
|
+
[project.urls]
|
|
24
|
+
Documentation = "https://github.com/crossplane-contrib/function-pythonic#readme"
|
|
25
|
+
Issues = "https://github.com/crossplane-contrib/function-pythonic/issues"
|
|
26
|
+
Source = "https://github.com/crossplane-contrib/function-pythonic"
|
|
27
|
+
|
|
28
|
+
[project.scripts]
|
|
29
|
+
function-pythonic = "crossplane.pythonic.main:main"
|
|
30
|
+
|
|
31
|
+
[build-system]
|
|
32
|
+
requires = ["uv_build>=0.12.23,<0.13.0"]
|
|
33
|
+
build-backend = "uv_build"
|
|
34
|
+
|
|
35
|
+
[dependency-groups]
|
|
36
|
+
dev = [
|
|
37
|
+
"grpcio-tools>=1.84.0",
|
|
38
|
+
"poethepoet>=0.48.0",
|
|
39
|
+
"pytest>=9.1.1",
|
|
40
|
+
"pytest-asyncio>=1.4.0",
|
|
41
|
+
"pytest-cov>=7.1.0",
|
|
42
|
+
"ruff>=0.17.0",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[tool.uv.build-backend]
|
|
46
|
+
module-name = "crossplane.pythonic"
|
|
47
|
+
|
|
48
|
+
[tool.poe.tasks]
|
|
49
|
+
generate-protoc = "python -m grpc_tools.protoc --proto_path=src --python_out=src --pyi_out=src --grpc_python_out=src crossplane/pythonic/proto/v1/run_function.proto"
|
|
50
|
+
test = "pytest tests -x --verbose --verbose --cov --cov-report=term --cov-report=html:reports"
|
|
51
|
+
test-protobuf = "pytest tests/test_protobuf_*.py -x --verbose --verbose --cov --cov-report=term --cov-report=html:reports"
|
|
52
|
+
test-ci = "pytest tests --verbose --verbose --junitxml=reports/pytest-junit.xml --cov --cov-report=term --cov-report=xml:reports/pytest-coverage.xml"
|
|
53
|
+
|
|
54
|
+
[tool.pytest.ini_options]
|
|
55
|
+
pythonpath = ["."]
|
|
56
|
+
filterwarnings = [
|
|
57
|
+
"ignore:'asyncio.iscoroutinefunction' is deprecated:DeprecationWarning:kr8s._vendored.asyncache",
|
|
58
|
+
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from .composite import BaseComposite
|
|
2
|
+
from .protobuf import (
|
|
3
|
+
B64Decode,
|
|
4
|
+
B64Encode,
|
|
5
|
+
Json,
|
|
6
|
+
List,
|
|
7
|
+
Map,
|
|
8
|
+
Unknown,
|
|
9
|
+
Yaml,
|
|
10
|
+
YamlAll,
|
|
11
|
+
append,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"B64Decode",
|
|
16
|
+
"B64Encode",
|
|
17
|
+
"BaseComposite",
|
|
18
|
+
"Json",
|
|
19
|
+
"List",
|
|
20
|
+
"Map",
|
|
21
|
+
"Unknown",
|
|
22
|
+
"Yaml",
|
|
23
|
+
"YamlAll",
|
|
24
|
+
"append",
|
|
25
|
+
]
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
2
1
|
def resource_ready(resource):
|
|
3
2
|
if not resource.observed:
|
|
4
3
|
return None
|
|
5
|
-
return _checks.get(
|
|
4
|
+
return _checks.get(
|
|
5
|
+
(resource.observed.apiVersion, resource.observed.kind), _check_default
|
|
6
|
+
).ready(resource)
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class ReadyCondition:
|
|
@@ -16,35 +17,42 @@ class ReadyCondition:
|
|
|
16
17
|
return resource.status.notReadyCondition[ready.reason]
|
|
17
18
|
return resource.status.notReadyCondition
|
|
18
19
|
|
|
20
|
+
|
|
19
21
|
_checks = {}
|
|
20
22
|
_check_default = ReadyCondition()
|
|
21
23
|
|
|
24
|
+
|
|
22
25
|
class Check:
|
|
23
26
|
@classmethod
|
|
24
27
|
def __init_subclass__(cls, **kwargs):
|
|
25
28
|
super().__init_subclass__(**kwargs)
|
|
26
|
-
if hasattr(cls,
|
|
29
|
+
if hasattr(cls, "apiVersion"):
|
|
27
30
|
_checks[(cls.apiVersion, cls.__name__)] = cls()
|
|
28
31
|
|
|
29
32
|
def ready(self, resource):
|
|
30
33
|
raise NotImplementedError()
|
|
31
34
|
|
|
35
|
+
|
|
32
36
|
class AlwaysReady(Check):
|
|
33
37
|
def ready(self, resource):
|
|
34
38
|
return resource.observed.metadata.name
|
|
35
39
|
|
|
36
40
|
|
|
37
41
|
class ClusterRole(AlwaysReady):
|
|
38
|
-
apiVersion =
|
|
42
|
+
apiVersion = "rbac.authorization.k8s.io/v1"
|
|
43
|
+
|
|
39
44
|
|
|
40
45
|
class ClusterRoleBinding(AlwaysReady):
|
|
41
|
-
apiVersion =
|
|
46
|
+
apiVersion = "rbac.authorization.k8s.io/v1"
|
|
47
|
+
|
|
42
48
|
|
|
43
49
|
class ConfigMap(AlwaysReady):
|
|
44
|
-
apiVersion =
|
|
50
|
+
apiVersion = "v1"
|
|
51
|
+
|
|
45
52
|
|
|
46
53
|
class CronJob(Check):
|
|
47
|
-
apiVersion =
|
|
54
|
+
apiVersion = "batch/v1"
|
|
55
|
+
|
|
48
56
|
def ready(self, resource):
|
|
49
57
|
if resource.observed.spec.suspend and len(resource.observed.spec.suspend):
|
|
50
58
|
return resource.observed.metadata.name
|
|
@@ -54,17 +62,21 @@ class CronJob(Check):
|
|
|
54
62
|
return resource.observed.metadata.name
|
|
55
63
|
if not resource.status.lastSuccessfulTime:
|
|
56
64
|
return resource.status.lastSuccessfulTime
|
|
57
|
-
if str(resource.status.lastSuccessfulTime) < str(
|
|
65
|
+
if str(resource.status.lastSuccessfulTime) < str(
|
|
66
|
+
resource.status.lastScheduleTime
|
|
67
|
+
):
|
|
58
68
|
return resource.status.successfulBeforeSchedule
|
|
59
69
|
return resource.observed.metadata.name
|
|
60
70
|
|
|
71
|
+
|
|
61
72
|
class DaemonSet(Check):
|
|
62
|
-
apiVersion =
|
|
73
|
+
apiVersion = "apps/v1"
|
|
74
|
+
|
|
63
75
|
def ready(self, resource):
|
|
64
76
|
scheduled = resource.status.desiredNumberScheduled
|
|
65
77
|
if not scheduled:
|
|
66
78
|
return scheduled
|
|
67
|
-
for field in (
|
|
79
|
+
for field in ("numberReady", "updatedNumberScheduled", "numberAvailable"):
|
|
68
80
|
value = resource.status[field]
|
|
69
81
|
if not value:
|
|
70
82
|
return value
|
|
@@ -72,16 +84,18 @@ class DaemonSet(Check):
|
|
|
72
84
|
return resource.status[f"{field}NotScheduled"]
|
|
73
85
|
return resource.observed.metadata.name
|
|
74
86
|
|
|
87
|
+
|
|
75
88
|
class Deployment(Check):
|
|
76
|
-
apiVersion =
|
|
89
|
+
apiVersion = "apps/v1"
|
|
90
|
+
|
|
77
91
|
def ready(self, resource):
|
|
78
92
|
replicas = resource.observed.spec.replicas or 1
|
|
79
|
-
for field in (
|
|
93
|
+
for field in ("updatedReplicas", "availableReplicas"):
|
|
80
94
|
value = resource.status[field]
|
|
81
95
|
if not value:
|
|
82
96
|
return value
|
|
83
97
|
if replicas != value:
|
|
84
|
-
return resource.status[
|
|
98
|
+
return resource.status[f"{field}NotReplicas"]
|
|
85
99
|
available = resource.conditions.Available
|
|
86
100
|
if not available:
|
|
87
101
|
return resource.status.notAvailable
|
|
@@ -91,28 +105,39 @@ class Deployment(Check):
|
|
|
91
105
|
return resource.status.notAvailable
|
|
92
106
|
return resource.observed.metadata.name
|
|
93
107
|
|
|
108
|
+
|
|
94
109
|
class HorizontalPodAutoscaler(Check):
|
|
95
|
-
apiVersion =
|
|
110
|
+
apiVersion = "autoscaling/v2"
|
|
111
|
+
|
|
96
112
|
def ready(self, resource):
|
|
97
|
-
for type in (
|
|
113
|
+
for type in (
|
|
114
|
+
"FailedGetScale",
|
|
115
|
+
"FailedUpdateScale",
|
|
116
|
+
"FailedGetResourceMetric",
|
|
117
|
+
"InvalidSelector",
|
|
118
|
+
):
|
|
98
119
|
if resource.conditions[type].status:
|
|
99
120
|
return resource.status[f"is{type}"]
|
|
100
|
-
for type in (
|
|
121
|
+
for type in ("ScalingActive", "ScalingLimited"):
|
|
101
122
|
if resource.conditions[type].status:
|
|
102
123
|
return resource.observed.metadata.name
|
|
103
124
|
return resource.status.notScalingActiveOrLimiited
|
|
104
125
|
|
|
126
|
+
|
|
105
127
|
class Ingress(Check):
|
|
106
|
-
apiVersion =
|
|
128
|
+
apiVersion = "networking.k8s.io/v1"
|
|
129
|
+
|
|
107
130
|
def ready(self, resource):
|
|
108
131
|
if not len(resource.status.loadBalancer.ingress):
|
|
109
132
|
return resource.status.noLoadBalanceIngresses
|
|
110
133
|
return resource.observed.metadata.name
|
|
111
134
|
|
|
135
|
+
|
|
112
136
|
class Job(Check):
|
|
113
|
-
apiVersion =
|
|
137
|
+
apiVersion = "batch/v1"
|
|
138
|
+
|
|
114
139
|
def ready(self, resource):
|
|
115
|
-
for type in (
|
|
140
|
+
for type in ("Failed", "Suspended"):
|
|
116
141
|
if resource.conditions[type].status:
|
|
117
142
|
return resource.status[f"is{type}"]
|
|
118
143
|
complete = resource.conditions.Complete
|
|
@@ -124,71 +149,94 @@ class Job(Check):
|
|
|
124
149
|
return resource.status.notComplete
|
|
125
150
|
return resource.observed.metadata.name
|
|
126
151
|
|
|
152
|
+
|
|
127
153
|
class Namespace(AlwaysReady):
|
|
128
|
-
apiVersion =
|
|
154
|
+
apiVersion = "v1"
|
|
155
|
+
|
|
129
156
|
|
|
130
157
|
class PersistentVolumeClaim(Check):
|
|
131
|
-
apiVersion =
|
|
158
|
+
apiVersion = "v1"
|
|
159
|
+
|
|
132
160
|
def ready(self, resource):
|
|
133
|
-
if resource.status.phase !=
|
|
161
|
+
if resource.status.phase != "Bound":
|
|
134
162
|
return resource.status.phaseNotBound
|
|
135
163
|
return resource.observed.metadata.name
|
|
136
164
|
|
|
165
|
+
|
|
137
166
|
class Pod(Check):
|
|
138
|
-
apiVersion =
|
|
167
|
+
apiVersion = "v1"
|
|
168
|
+
|
|
139
169
|
def ready(self, resource):
|
|
140
|
-
if resource.status.phase ==
|
|
170
|
+
if resource.status.phase == "Succeeded":
|
|
171
|
+
return resource.observed.metadata.name
|
|
172
|
+
if (
|
|
173
|
+
resource.status.phase == "Running"
|
|
174
|
+
and resource.observed.spec.restartPolicy == "Always"
|
|
175
|
+
and resource.conditions.Ready.status
|
|
176
|
+
):
|
|
141
177
|
return resource.observed.metadata.name
|
|
142
|
-
if resource.status.phase == 'Running':
|
|
143
|
-
if resource.observed.spec.restartPolicy == 'Always':
|
|
144
|
-
if resource.conditions.Ready.status:
|
|
145
|
-
return resource.observed.metadata.name
|
|
146
178
|
return resource.status.notSucceededOrRunning
|
|
147
179
|
|
|
180
|
+
|
|
148
181
|
class ReplicaSet(Check):
|
|
149
|
-
apiVersion =
|
|
182
|
+
apiVersion = "v1"
|
|
183
|
+
|
|
150
184
|
def ready(self, resource):
|
|
151
|
-
if int(resource.status.observedGeneration) < int(
|
|
185
|
+
if int(resource.status.observedGeneration) < int(
|
|
186
|
+
resource.observed.metadata.generation
|
|
187
|
+
):
|
|
152
188
|
return resource.status.priorObservedGeneration
|
|
153
189
|
if resource.conditions.ReplicaFailure.status:
|
|
154
190
|
if resource.conditions.ReplicaFailure.reason:
|
|
155
|
-
return resource.status.isReplicaFailure[
|
|
191
|
+
return resource.status.isReplicaFailure[
|
|
192
|
+
resource.conditions.ReplicaFailure.reason
|
|
193
|
+
]
|
|
156
194
|
return resource.status.isReplicaFailure
|
|
157
|
-
if int(resource.status.availableReplicas) < int(
|
|
195
|
+
if int(resource.status.availableReplicas) < int(
|
|
196
|
+
resource.observed.spec.replicas or 1
|
|
197
|
+
):
|
|
158
198
|
return resource.status.tooFewavailableReplicas
|
|
159
199
|
return resource.observed.metadata.name
|
|
160
200
|
|
|
201
|
+
|
|
161
202
|
class Role(AlwaysReady):
|
|
162
|
-
apiVersion =
|
|
203
|
+
apiVersion = "rbac.authorization.k8s.io/v1"
|
|
204
|
+
|
|
163
205
|
|
|
164
206
|
class RoleBinding(AlwaysReady):
|
|
165
|
-
apiVersion =
|
|
207
|
+
apiVersion = "rbac.authorization.k8s.io/v1"
|
|
208
|
+
|
|
166
209
|
|
|
167
210
|
class Secret(AlwaysReady):
|
|
168
|
-
apiVersion =
|
|
211
|
+
apiVersion = "v1"
|
|
212
|
+
|
|
169
213
|
|
|
170
214
|
class Service(Check):
|
|
171
|
-
apiVersion =
|
|
215
|
+
apiVersion = "v1"
|
|
216
|
+
|
|
172
217
|
def ready(self, resource):
|
|
173
|
-
if resource.observed.spec.type !=
|
|
218
|
+
if resource.observed.spec.type != "LoadBalancer":
|
|
174
219
|
return resource.observed.metadata.name
|
|
175
220
|
if not len(resource.status.loadBalancer.ingress):
|
|
176
221
|
return resource.status.noLoadBalancerIngresses
|
|
177
222
|
return resource.observed.metadata.name
|
|
178
223
|
|
|
224
|
+
|
|
179
225
|
class ServiceAccount(AlwaysReady):
|
|
180
|
-
apiVersion =
|
|
226
|
+
apiVersion = "v1"
|
|
227
|
+
|
|
181
228
|
|
|
182
229
|
class StatefulSet(Check):
|
|
183
|
-
apiVersion =
|
|
230
|
+
apiVersion = "apps/v1"
|
|
231
|
+
|
|
184
232
|
def ready(self, resource):
|
|
185
233
|
replicas = resource.observed.spec.replicas or 1
|
|
186
|
-
for field in (
|
|
234
|
+
for field in ("readyReplicas", "currentReplicas"):
|
|
187
235
|
value = resource.status[field]
|
|
188
236
|
if not value:
|
|
189
237
|
return value
|
|
190
238
|
if replicas != value:
|
|
191
|
-
return resource.status[
|
|
239
|
+
return resource.status[f"{field}NotReplicas"]
|
|
192
240
|
if resource.status.currentRevision != resource.status.updateRevision:
|
|
193
241
|
return resource.status.currentRevisionNotUpdateReivsion
|
|
194
242
|
return resource.observed.metadata.name
|