crossplane-function-pythonic 0.0.11__tar.gz → 0.1.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.0.11 → crossplane_function_pythonic-0.1.0}/PKG-INFO +23 -1
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/README.md +22 -0
- crossplane_function_pythonic-0.1.0/crossplane/pythonic/__init__.py +16 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/crossplane/pythonic/composite.py +16 -13
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/crossplane/pythonic/function.py +121 -38
- crossplane_function_pythonic-0.1.0/crossplane/pythonic/protobuf.py +1278 -0
- crossplane_function_pythonic-0.1.0/examples/aks-cluster/README.md +129 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/aks-cluster/aks/kubernetescluster.py +1 -1
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/aks-cluster/cluster-function-pythonic.yaml +1 -1
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/aks-cluster/composition.yaml +1 -1
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/aks-cluster/definition.yaml +2 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/aks-cluster/functions.yaml +1 -1
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/aks-cluster/xr.yaml +1 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/eks-cluster/composition.yaml +2 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/eks-cluster/xr.yaml +1 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/conditions/composition.yaml +6 -6
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/inline/composition.yaml +1 -1
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/helm-copy-secret/vcluster.py +1 -1
- crossplane_function_pythonic-0.1.0/examples/usages-extra/composition.yaml +26 -0
- crossplane_function_pythonic-0.1.0/examples/usages-extra/extraResources.yaml +7 -0
- crossplane_function_pythonic-0.1.0/examples/usages-extra/functions.yaml +9 -0
- crossplane_function_pythonic-0.1.0/examples/usages-extra/observedResources.yaml +6 -0
- crossplane_function_pythonic-0.1.0/examples/usages-extra/render.sh +3 -0
- crossplane_function_pythonic-0.1.0/examples/usages-extra/xr.yaml +6 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/pyproject.toml +3 -2
- crossplane_function_pythonic-0.0.11/crossplane/pythonic/__init__.py +0 -19
- crossplane_function_pythonic-0.0.11/crossplane/pythonic/protobuf.py +0 -955
- crossplane_function_pythonic-0.0.11/examples/aks-cluster/README.md +0 -32
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/.gitignore +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/LICENSE +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/crossplane/pythonic/main.py +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/crossplane/pythonic/packages.py +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/.dev/functions.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/aks-cluster/aks/resourcegroup.py +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/aks-cluster/install.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/aks-cluster/kustomization.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/aks-cluster/providers.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/aks-cluster/render.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/eks-cluster/composition-v2.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/eks-cluster/definition.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/eks-cluster/functions.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/eks-cluster/render-v2.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/eks-cluster/render.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/filing-system/README.md +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/filing-system/composition.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/filing-system/definition.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/filing-system/function.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/filing-system/kustomization.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/filing-system/runtime.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/filing-system/vcluster.py +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/filing-system/vcluster.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/conditions/functions.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/conditions/render.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/conditions/xr.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/conditions/xrd.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/context/composition.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/context/environmentConfigs.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/context/functions.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/context/render.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/context/xr.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/context/xrd.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/extra-resources/composition.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/extra-resources/extraResources.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/extra-resources/functions.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/extra-resources/render.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/extra-resources/xr.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/fromYaml/composition.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/fromYaml/functions.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/fromYaml/render.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/fromYaml/xr.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/getComposedResource/composition.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/getComposedResource/functions.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/getComposedResource/observed.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/getComposedResource/render.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/getComposedResource/xr.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/getCompositeResource/composition.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/getCompositeResource/functions.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/getCompositeResource/render.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/getCompositeResource/xr.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/getResourceCondition/composition.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/getResourceCondition/functions.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/getResourceCondition/observed.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/getResourceCondition/render.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/getResourceCondition/xr.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/include/composition.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/include/functions.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/include/render.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/include/xr.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/toYaml/composition.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/toYaml/functions.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/toYaml/render.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/functions/toYaml/xr.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/inline/functions.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/inline/render.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/inline/xr.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/recursive/composition-real.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/recursive/composition-wrapper.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/recursive/functions.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/recursive/render.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/function-go-templating/recursive/xr.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/get-started-app/composition.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/get-started-app/definition.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/get-started-app/functions.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/get-started-app/render.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/get-started-app/xr.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/helm-copy-secret/composition.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/helm-copy-secret/functions.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/helm-copy-secret/kustomization.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/helm-copy-secret/render.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/helm-copy-secret/run-function.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/helm-copy-secret/xr.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/helm-copy-secret/xrd.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/single-purpose/functions.yaml +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/single-purpose/render.sh +0 -0
- {crossplane_function_pythonic-0.0.11 → crossplane_function_pythonic-0.1.0}/examples/single-purpose/xr.yaml +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: crossplane-function-pythonic
|
3
|
-
Version: 0.0
|
3
|
+
Version: 0.1.0
|
4
4
|
Summary: A Python centric Crossplane Function
|
5
5
|
Project-URL: Documentation, https://github.com/fortra/function-pythonic#readme
|
6
6
|
Project-URL: Issues, https://github.com/fortra/function-pythonic/issues
|
@@ -119,6 +119,26 @@ overridden for all composed resource by setting the Composite `self.unknownsFata
|
|
119
119
|
to False, or at the individual composed resource level by setting the
|
120
120
|
`Resource.unknownsFatal` field to False.
|
121
121
|
|
122
|
+
## Usage Dependencies
|
123
|
+
|
124
|
+
function-pythonic can be configured to automatically create
|
125
|
+
[Crossplane Usages](https://docs.crossplane.io/latest/managed-resources/usages/)
|
126
|
+
dependencies between resources. Modifying the above VPC example with:
|
127
|
+
```yaml
|
128
|
+
self.usages = True
|
129
|
+
|
130
|
+
vpc = self.resources.VPC('ec2.aws.crossplane.io/v1beta1', 'VPC')
|
131
|
+
vpc.spec.forProvider.region = 'us-east-1
|
132
|
+
vpc.spec.forProvider.cidrBlock = '10.0.0.0/16'
|
133
|
+
|
134
|
+
subnet = self.resources.SubnetA('ec2.aws.crossplane.io/v1beta1', 'Subnet')
|
135
|
+
subnet.spec.forProvider.region = 'us-east-1'
|
136
|
+
subnet.spec.forProvider.vpcId = vpc.status.atProvider.vpcId
|
137
|
+
subnet.spec.forProvider.availabilityZone = 'us-east-1a'
|
138
|
+
subnet.spec.forProvider.cidrBlock = '10.0.0.0/20'
|
139
|
+
```
|
140
|
+
Will generate the appropriate Crossplane Usage resource.
|
141
|
+
|
122
142
|
## Pythonic access of Protobuf Messages
|
123
143
|
|
124
144
|
All Protobuf messages are wrapped by a set of python classes which enable using
|
@@ -225,6 +245,7 @@ The BaseComposite also provides access to the following Crossplane Function leve
|
|
225
245
|
| self.requireds | Requireds | Request and read additional local Kubernetes resources |
|
226
246
|
| self.resources | Resources | Define and process composed resources |
|
227
247
|
| self.unknownsFatal | Boolean | Terminate the composition if already created resources are assigned unknown values, default True |
|
248
|
+
| self.usages| Boolean | Generate Crossplane Usages for resource dependencies, default False |
|
228
249
|
| self.autoReady | Boolean | Perform auto ready processing on all composed resources, default True |
|
229
250
|
|
230
251
|
### Composed Resources
|
@@ -251,6 +272,7 @@ Resource class:
|
|
251
272
|
| Resource.connection | Connection | The resource connection details |
|
252
273
|
| Resource.ready | Boolean | The resource ready state |
|
253
274
|
| Resource.unknownsFatal | Boolean | Terminate the composition if this resource has been created and is assigned unknown values, default is Composite.unknownsFatal |
|
275
|
+
| Resource.usages | Boolean | Generate Crossplane Usages for this resource, default is Composite.autoReady |
|
254
276
|
| Resource.autoReady | Boolean | Perform auto ready processing on this resource, default is Composite.autoReady |
|
255
277
|
|
256
278
|
### Required Resources (AKA Extra Resources)
|
@@ -95,6 +95,26 @@ overridden for all composed resource by setting the Composite `self.unknownsFata
|
|
95
95
|
to False, or at the individual composed resource level by setting the
|
96
96
|
`Resource.unknownsFatal` field to False.
|
97
97
|
|
98
|
+
## Usage Dependencies
|
99
|
+
|
100
|
+
function-pythonic can be configured to automatically create
|
101
|
+
[Crossplane Usages](https://docs.crossplane.io/latest/managed-resources/usages/)
|
102
|
+
dependencies between resources. Modifying the above VPC example with:
|
103
|
+
```yaml
|
104
|
+
self.usages = True
|
105
|
+
|
106
|
+
vpc = self.resources.VPC('ec2.aws.crossplane.io/v1beta1', 'VPC')
|
107
|
+
vpc.spec.forProvider.region = 'us-east-1
|
108
|
+
vpc.spec.forProvider.cidrBlock = '10.0.0.0/16'
|
109
|
+
|
110
|
+
subnet = self.resources.SubnetA('ec2.aws.crossplane.io/v1beta1', 'Subnet')
|
111
|
+
subnet.spec.forProvider.region = 'us-east-1'
|
112
|
+
subnet.spec.forProvider.vpcId = vpc.status.atProvider.vpcId
|
113
|
+
subnet.spec.forProvider.availabilityZone = 'us-east-1a'
|
114
|
+
subnet.spec.forProvider.cidrBlock = '10.0.0.0/20'
|
115
|
+
```
|
116
|
+
Will generate the appropriate Crossplane Usage resource.
|
117
|
+
|
98
118
|
## Pythonic access of Protobuf Messages
|
99
119
|
|
100
120
|
All Protobuf messages are wrapped by a set of python classes which enable using
|
@@ -201,6 +221,7 @@ The BaseComposite also provides access to the following Crossplane Function leve
|
|
201
221
|
| self.requireds | Requireds | Request and read additional local Kubernetes resources |
|
202
222
|
| self.resources | Resources | Define and process composed resources |
|
203
223
|
| self.unknownsFatal | Boolean | Terminate the composition if already created resources are assigned unknown values, default True |
|
224
|
+
| self.usages| Boolean | Generate Crossplane Usages for resource dependencies, default False |
|
204
225
|
| self.autoReady | Boolean | Perform auto ready processing on all composed resources, default True |
|
205
226
|
|
206
227
|
### Composed Resources
|
@@ -227,6 +248,7 @@ Resource class:
|
|
227
248
|
| Resource.connection | Connection | The resource connection details |
|
228
249
|
| Resource.ready | Boolean | The resource ready state |
|
229
250
|
| Resource.unknownsFatal | Boolean | Terminate the composition if this resource has been created and is assigned unknown values, default is Composite.unknownsFatal |
|
251
|
+
| Resource.usages | Boolean | Generate Crossplane Usages for this resource, default is Composite.autoReady |
|
230
252
|
| Resource.autoReady | Boolean | Perform auto ready processing on this resource, default is Composite.autoReady |
|
231
253
|
|
232
254
|
### Required Resources (AKA Extra Resources)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
from .composite import BaseComposite
|
4
|
+
from .protobuf import append, Map, List, Unknown, Yaml, Json, B64Encode, B64Decode
|
5
|
+
|
6
|
+
__all__ = [
|
7
|
+
'BaseComposite',
|
8
|
+
'append',
|
9
|
+
'Map',
|
10
|
+
'List',
|
11
|
+
'Unknown',
|
12
|
+
'Yaml',
|
13
|
+
'Json',
|
14
|
+
'B64Encode',
|
15
|
+
'B64Decode',
|
16
|
+
]
|
@@ -31,6 +31,7 @@ class BaseComposite:
|
|
31
31
|
self.resources = Resources(self)
|
32
32
|
self.unknownsFatal = True
|
33
33
|
self.autoReady = True
|
34
|
+
self.usages = False
|
34
35
|
|
35
36
|
observed = self.request.observed.composite
|
36
37
|
desired = self.response.desired.composite
|
@@ -49,7 +50,7 @@ class BaseComposite:
|
|
49
50
|
def ttl(self):
|
50
51
|
if self.response.meta.ttl.nanos:
|
51
52
|
return float(self.response.meta.ttl.seconds) + (float(self.response.meta.ttl.nanos) / 1000000000.0)
|
52
|
-
return self.response.meta.ttl.seconds
|
53
|
+
return int(self.response.meta.ttl.seconds)
|
53
54
|
|
54
55
|
@ttl.setter
|
55
56
|
def ttl(self, ttl):
|
@@ -61,7 +62,7 @@ class BaseComposite:
|
|
61
62
|
if ttl.is_integer():
|
62
63
|
self.response.meta.ttl.nanos = 0
|
63
64
|
else:
|
64
|
-
self.response.meta.ttl.nanos = int((ttl -
|
65
|
+
self.response.meta.ttl.nanos = int((ttl - int(self.response.meta.ttl.seconds)) * 1000000000)
|
65
66
|
else:
|
66
67
|
raise ValueError('ttl must be an int or float')
|
67
68
|
|
@@ -78,7 +79,7 @@ class BaseComposite:
|
|
78
79
|
def ready(self, ready):
|
79
80
|
if ready:
|
80
81
|
ready = fnv1.Ready.READY_TRUE
|
81
|
-
elif ready == None or (isinstance(ready, protobuf.
|
82
|
+
elif ready == None or (isinstance(ready, protobuf.Value) and ready._isUnknown):
|
82
83
|
ready = fnv1.Ready.READY_UNSPECIFIED
|
83
84
|
else:
|
84
85
|
ready = fnv1.Ready.READY_FALSE
|
@@ -184,6 +185,7 @@ class Resource:
|
|
184
185
|
self.connection = Connection(observed)
|
185
186
|
self.unknownsFatal = None
|
186
187
|
self.autoReady = None
|
188
|
+
self.usages = None
|
187
189
|
|
188
190
|
def __call__(self, apiVersion=_notset, kind=_notset, namespace=_notset, name=_notset):
|
189
191
|
self.desired()
|
@@ -199,7 +201,7 @@ class Resource:
|
|
199
201
|
|
200
202
|
@property
|
201
203
|
def apiVersion(self):
|
202
|
-
return self.
|
204
|
+
return self.desired.apiVersion
|
203
205
|
|
204
206
|
@apiVersion.setter
|
205
207
|
def apiVersion(self, apiVersion):
|
@@ -207,7 +209,7 @@ class Resource:
|
|
207
209
|
|
208
210
|
@property
|
209
211
|
def kind(self):
|
210
|
-
return self.
|
212
|
+
return self.desired.kind
|
211
213
|
|
212
214
|
@kind.setter
|
213
215
|
def kind(self, kind):
|
@@ -265,7 +267,7 @@ class Resource:
|
|
265
267
|
def ready(self, ready):
|
266
268
|
if ready:
|
267
269
|
ready = fnv1.Ready.READY_TRUE
|
268
|
-
elif ready == None or (isinstance(ready, protobuf.
|
270
|
+
elif ready == None or (isinstance(ready, protobuf.Value) and ready._isUnknown):
|
269
271
|
ready = fnv1.Ready.READY_UNSPECIFIED
|
270
272
|
else:
|
271
273
|
ready = fnv1.Ready.READY_FALSE
|
@@ -376,8 +378,8 @@ class RequiredResources:
|
|
376
378
|
elif isinstance(entry, (list, tuple)):
|
377
379
|
self._selector.match_labels.labels[entry[0]] = entry[1]
|
378
380
|
|
379
|
-
def __getitem__(self,
|
380
|
-
return RequiredResource(self.name, self._resources.items[
|
381
|
+
def __getitem__(self, ix):
|
382
|
+
return RequiredResource(self.name, ix, self._resources.items[ix])
|
381
383
|
|
382
384
|
def __bool__(self):
|
383
385
|
return bool(self._resources.items)
|
@@ -391,8 +393,9 @@ class RequiredResources:
|
|
391
393
|
|
392
394
|
|
393
395
|
class RequiredResource:
|
394
|
-
def __init__(self, name, resource):
|
396
|
+
def __init__(self, name, ix, resource):
|
395
397
|
self.name = name
|
398
|
+
self.ix = ix
|
396
399
|
self.observed = resource.resource
|
397
400
|
self.apiVersion = self.observed.apiVersion
|
398
401
|
self.kind = self.observed.kind
|
@@ -487,7 +490,7 @@ class Condition(protobuf.ProtobufValue):
|
|
487
490
|
condition.status = fnv1.Status.STATUS_CONDITION_TRUE
|
488
491
|
elif status == None:
|
489
492
|
condition.status = fnv1.Status.STATUS_CONDITION_UNKNOWN
|
490
|
-
elif isinstance(status, protobuf.
|
493
|
+
elif isinstance(status, protobuf.Value) and status._isUnknown:
|
491
494
|
condition.status = fnv1.Status.STATUS_CONDITION_UNSPECIFIED
|
492
495
|
else:
|
493
496
|
condition.status = fnv1.Status.STATUS_CONDITION_FALSE
|
@@ -521,7 +524,7 @@ class Condition(protobuf.ProtobufValue):
|
|
521
524
|
if observed.type == self.type:
|
522
525
|
time = observed.lastTransitionTime
|
523
526
|
if time:
|
524
|
-
return datetime.datetime.fromisoformat(time)
|
527
|
+
return datetime.datetime.fromisoformat(str(time))
|
525
528
|
return None
|
526
529
|
|
527
530
|
@property
|
@@ -534,7 +537,7 @@ class Condition(protobuf.ProtobufValue):
|
|
534
537
|
condition = self._find_condition(True)
|
535
538
|
if claim:
|
536
539
|
condition.target = fnv1.Target.TARGET_COMPOSITE_AND_CLAIM
|
537
|
-
elif claim == None or (isinstance(claim, protobuf.
|
540
|
+
elif claim == None or (isinstance(claim, protobuf.Value) and claim._isUnknown):
|
538
541
|
condition.target = fnv1.Target.TARGET_UNSPECIFIED
|
539
542
|
else:
|
540
543
|
condition.target = fnv1.Target.TARGET_COMPOSITE
|
@@ -711,7 +714,7 @@ class Event:
|
|
711
714
|
if bool(self):
|
712
715
|
if claim:
|
713
716
|
self._result.target = fnv1.Target.TARGET_COMPOSITE_AND_CLAIM
|
714
|
-
elif claim == None or (isinstance(claim, protobuf.
|
717
|
+
elif claim == None or (isinstance(claim, protobuf.Value) and claim._isUnknown):
|
715
718
|
self._result.target = fnv1.Target.TARGET_UNSPECIFIED
|
716
719
|
else:
|
717
720
|
self._result.target = fnv1.Target.TARGET_COMPOSITE
|
@@ -99,7 +99,7 @@ class FunctionRunner(grpcv1.FunctionRunnerService):
|
|
99
99
|
return self.fatal(request, logger, 'Instantiate', e)
|
100
100
|
|
101
101
|
step = composite.context._pythonic[step]
|
102
|
-
iteration = (step.iteration
|
102
|
+
iteration = int(step.iteration) + 1
|
103
103
|
step.iteration = iteration
|
104
104
|
composite.context.iteration = iteration
|
105
105
|
logger.debug(f"Starting compose, {ordinal(len(composite.context._pythonic))} step, {ordinal(iteration)} pass")
|
@@ -111,7 +111,40 @@ class FunctionRunner(grpcv1.FunctionRunnerService):
|
|
111
111
|
except Exception as e:
|
112
112
|
return self.fatal(request, logger, 'Compose', e)
|
113
113
|
|
114
|
-
|
114
|
+
if requireds := self.get_requireds(step, composite):
|
115
|
+
logger.info(f"Requireds requested: {','.join(requireds)}")
|
116
|
+
else:
|
117
|
+
self.process_usages(composite)
|
118
|
+
self.process_unknowns(composite)
|
119
|
+
self.process_auto_readies(composite)
|
120
|
+
logger.info('Completed compose')
|
121
|
+
|
122
|
+
return composite.response._message
|
123
|
+
|
124
|
+
def fatal(self, request, logger, message, exception=None):
|
125
|
+
if exception:
|
126
|
+
message += ' exceptiion'
|
127
|
+
logger.exception(message)
|
128
|
+
m = str(exception)
|
129
|
+
if not m:
|
130
|
+
m = exception.__class__.__name__
|
131
|
+
message += ': ' + m
|
132
|
+
else:
|
133
|
+
logger.error(message)
|
134
|
+
return fnv1.RunFunctionResponse(
|
135
|
+
meta=fnv1.ResponseMeta(
|
136
|
+
tag=request.meta.tag,
|
137
|
+
),
|
138
|
+
results=[
|
139
|
+
fnv1.Result(
|
140
|
+
severity=fnv1.SEVERITY_FATAL,
|
141
|
+
message=message,
|
142
|
+
)
|
143
|
+
]
|
144
|
+
)
|
145
|
+
|
146
|
+
def get_requireds(self, step, composite):
|
147
|
+
requireds = []
|
115
148
|
for name, required in composite.requireds:
|
116
149
|
if required.apiVersion and required.kind:
|
117
150
|
r = pythonic.Map(apiVersion=required.apiVersion, kind=required.kind)
|
@@ -123,11 +156,84 @@ class FunctionRunner(grpcv1.FunctionRunnerService):
|
|
123
156
|
r.matchLabels[key] = value
|
124
157
|
if r != step.requireds[name]:
|
125
158
|
step.requireds[name] = r
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
159
|
+
requireds.append(name)
|
160
|
+
return requireds
|
161
|
+
|
162
|
+
def process_usages(self, composite):
|
163
|
+
for _, resource in sorted(entry for entry in composite.resources):
|
164
|
+
dependencies = resource.desired._getDependencies
|
165
|
+
if dependencies:
|
166
|
+
if self.debug:
|
167
|
+
for destination, source in sorted(dependencies.items()):
|
168
|
+
destination = self.trimFullName(destination)
|
169
|
+
source = self.trimFullName(source)
|
170
|
+
composite.logger.debug(f"Dependency: {destination} = {source}")
|
171
|
+
if resource.usages or (resource.usages is None and composite.usages):
|
172
|
+
resources = {}
|
173
|
+
requireds = {}
|
174
|
+
for destination, source in sorted(dependencies.items()):
|
175
|
+
name = source.split('.')
|
176
|
+
if (len(name) > 5 and
|
177
|
+
name[0] == 'request' and
|
178
|
+
name[1] == 'observed' and
|
179
|
+
name[2] == 'resources' and
|
180
|
+
name[4] == 'resource'
|
181
|
+
):
|
182
|
+
if name[3] not in resources:
|
183
|
+
resources[name[3]] = []
|
184
|
+
resources[name[3]].append(f"{'.'.join(destination.split('.')[5:])} = {'.'.join(name[5:])}")
|
185
|
+
elif (len(name) > 5 and
|
186
|
+
name[0] == 'request' and
|
187
|
+
name[1] == 'extra_resources' and
|
188
|
+
name[3].startswith('items[') and name[3][-1] == ']' and
|
189
|
+
name[4] == 'resource'
|
190
|
+
):
|
191
|
+
key = (name[2], int(name[3][6:-1]))
|
192
|
+
if key not in requireds:
|
193
|
+
requireds[key] = []
|
194
|
+
requireds[key].append(f"{'.'.join(destination.split('.')[5:])} = {'.'.join(name[5:])}")
|
195
|
+
for name, dependencies in resources.items():
|
196
|
+
source = composite.resources[name]
|
197
|
+
name = [resource.name, str(source.kind)]
|
198
|
+
if source.metadata.namespace:
|
199
|
+
name.append(str(source.metadata.namespace))
|
200
|
+
name.append(str(source.observed.metadata.name))
|
201
|
+
usage = composite.resources['_'.join(name)]('apiextensions.crossplane.io/v1beta1', 'Usage')
|
202
|
+
#usage = composite.resources['_'.join(name)]('protection.crossplane.io/v1beta1', 'Usage')
|
203
|
+
if resource.metadata.namespace:
|
204
|
+
usage.metadata.namespace = resource.metadata.namespace
|
205
|
+
usage.spec.reason = '\n'.join(dependencies)
|
206
|
+
usage.spec.replayDeletion = True
|
207
|
+
usage.spec.by.apiVersion = resource.apiVersion
|
208
|
+
usage.spec.by.kind = resource.kind
|
209
|
+
usage.spec.by.resourceRef.name = resource.observed.metadata.name
|
210
|
+
usage.spec.of.apiVersion = source.apiVersion
|
211
|
+
usage.spec.of.kind = source.kind
|
212
|
+
if source.metadata.namespace:
|
213
|
+
usage.spec.of.resourceRef.namespace = source.metadata.namespace
|
214
|
+
usage.spec.of.resourceRef.name = source.observed.metadata.name
|
215
|
+
for key, dependencies in requireds.items():
|
216
|
+
source = composite.requireds[key[0]][key[1]]
|
217
|
+
name = [resource.name, str(source.kind)]
|
218
|
+
if source.metadata.namespace:
|
219
|
+
name.append(str(source.metadata.namespace))
|
220
|
+
name.append(str(source.metadata.name))
|
221
|
+
usage = composite.resources['_'.join(name)]('apiextensions.crossplane.io/v1beta1', 'Usage')
|
222
|
+
#usage = composite.resources['_'.join(name)]('protection.crossplane.io/v1beta1', 'Usage')
|
223
|
+
if resource.metadata.namespace:
|
224
|
+
usage.metadata.namespace = resource.metadata.namespace
|
225
|
+
usage.spec.reason = '\n'.join(dependencies)
|
226
|
+
usage.spec.replayDeletion = True
|
227
|
+
usage.spec.by.apiVersion = resource.apiVersion
|
228
|
+
usage.spec.by.kind = resource.kind
|
229
|
+
usage.spec.by.resourceRef.name = resource.observed.metadata.name
|
230
|
+
usage.spec.of.apiVersion = source.apiVersion
|
231
|
+
usage.spec.of.kind = source.kind
|
232
|
+
if source.metadata.namespace:
|
233
|
+
usage.spec.of.resourceRef.namespace = source.metadata.namespace
|
234
|
+
usage.spec.of.resourceRef.name = source.observed.metadata.name
|
130
235
|
|
236
|
+
def process_unknowns(self, composite):
|
131
237
|
unknownResources = []
|
132
238
|
warningResources = []
|
133
239
|
fatalResources = []
|
@@ -148,11 +254,11 @@ class FunctionRunner(grpcv1.FunctionRunnerService):
|
|
148
254
|
destination = self.trimFullName(destination)
|
149
255
|
source = self.trimFullName(source)
|
150
256
|
if fatal:
|
151
|
-
logger.error(f'Observed unknown: {destination} = {source}')
|
257
|
+
composite.logger.error(f'Observed unknown: {destination} = {source}')
|
152
258
|
elif warning:
|
153
|
-
logger.warning(f'Observed unknown: {destination} = {source}')
|
259
|
+
composite.logger.warning(f'Observed unknown: {destination} = {source}')
|
154
260
|
else:
|
155
|
-
logger.debug(f'Desired unknown: {destination} = {source}')
|
261
|
+
composite.logger.debug(f'Desired unknown: {destination} = {source}')
|
156
262
|
if resource.observed:
|
157
263
|
resource.desired._patchUnknowns(resource.observed)
|
158
264
|
elif self.renderUnknowns:
|
@@ -161,19 +267,19 @@ class FunctionRunner(grpcv1.FunctionRunnerService):
|
|
161
267
|
del composite.resources[name]
|
162
268
|
|
163
269
|
if fatalResources:
|
164
|
-
level = logger.error
|
270
|
+
level = composite.logger.error
|
165
271
|
reason = 'FatalUnknowns'
|
166
272
|
message = f"Observed resources with unknowns: {','.join(fatalResources)}"
|
167
273
|
status = False
|
168
274
|
event = composite.events.fatal
|
169
275
|
elif warningResources:
|
170
|
-
level = logger.warning
|
276
|
+
level = composite.logger.warning
|
171
277
|
reason = 'ObservedUnknowns'
|
172
278
|
message = f"Observed resources with unknowns: {','.join(warningResources)}"
|
173
279
|
status = False
|
174
280
|
event = composite.events.warning
|
175
281
|
elif unknownResources:
|
176
|
-
level = logger.info
|
282
|
+
level = composite.logger.info
|
177
283
|
reason = 'DesiredUnknowns'
|
178
284
|
message = f"Desired resources with unknowns: {','.join(unknownResources)}"
|
179
285
|
status = False
|
@@ -190,42 +296,19 @@ class FunctionRunner(grpcv1.FunctionRunnerService):
|
|
190
296
|
if event:
|
191
297
|
event(reason, message)
|
192
298
|
|
299
|
+
def process_auto_readies(self, composite):
|
193
300
|
for name, resource in composite.resources:
|
194
301
|
if resource.autoReady or (resource.autoReady is None and composite.autoReady):
|
195
302
|
if resource.ready is None:
|
196
303
|
if resource.conditions.Ready.status:
|
197
304
|
resource.ready = True
|
198
305
|
|
199
|
-
logger.info('Completed compose')
|
200
|
-
return composite.response._message
|
201
|
-
|
202
|
-
def fatal(self, request, logger, message, exception=None):
|
203
|
-
if exception:
|
204
|
-
message += ' exceptiion'
|
205
|
-
logger.exception(message)
|
206
|
-
m = str(exception)
|
207
|
-
if not m:
|
208
|
-
m = exception.__class__.__name__
|
209
|
-
message += ': ' + m
|
210
|
-
else:
|
211
|
-
logger.error(message)
|
212
|
-
return fnv1.RunFunctionResponse(
|
213
|
-
meta=fnv1.ResponseMeta(
|
214
|
-
tag=request.meta.tag,
|
215
|
-
),
|
216
|
-
results=[
|
217
|
-
fnv1.Result(
|
218
|
-
severity=fnv1.SEVERITY_FATAL,
|
219
|
-
message=message,
|
220
|
-
)
|
221
|
-
]
|
222
|
-
)
|
223
|
-
|
224
306
|
def trimFullName(self, name):
|
225
307
|
name = name.split('.')
|
226
308
|
for values in (
|
309
|
+
('request', 'observed', 'composite', 'resource'),
|
227
310
|
('request', 'observed', 'resources', None, 'resource'),
|
228
|
-
('request', 'extra_resources', None, 'items', 'resource'),
|
311
|
+
('request', 'extra_resources', None, 'items', None, 'resource'),
|
229
312
|
('response', 'desired', 'resources', None, 'resource'),
|
230
313
|
):
|
231
314
|
if len(values) < len(name):
|