crossplane-function-pythonic 0.3.0__py3-none-any.whl → 0.4.0__py3-none-any.whl
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/pythonic/__about__.py +1 -1
- crossplane/pythonic/auto_ready.py +86 -45
- crossplane/pythonic/command.py +12 -0
- crossplane/pythonic/composite.py +98 -69
- crossplane/pythonic/function.py +14 -5
- crossplane/pythonic/protobuf.py +37 -5
- crossplane/pythonic/render.py +327 -159
- {crossplane_function_pythonic-0.3.0.dist-info → crossplane_function_pythonic-0.4.0.dist-info}/METADATA +66 -29
- crossplane_function_pythonic-0.4.0.dist-info/RECORD +18 -0
- crossplane_function_pythonic-0.3.0.dist-info/RECORD +0 -18
- {crossplane_function_pythonic-0.3.0.dist-info → crossplane_function_pythonic-0.4.0.dist-info}/WHEEL +0 -0
- {crossplane_function_pythonic-0.3.0.dist-info → crossplane_function_pythonic-0.4.0.dist-info}/entry_points.txt +0 -0
- {crossplane_function_pythonic-0.3.0.dist-info → crossplane_function_pythonic-0.4.0.dist-info}/licenses/LICENSE +0 -0
crossplane/pythonic/__about__.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# This is set at build time, using "hatch version"
|
|
2
|
-
__version__ = "0.
|
|
2
|
+
__version__ = "0.4.0"
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
|
|
2
|
+
def resource_ready(resource):
|
|
3
|
+
if not resource.observed:
|
|
4
|
+
return None
|
|
5
|
+
return _checks.get((resource.observed.apiVersion, resource.observed.kind), _check_default).ready(resource)
|
|
2
6
|
|
|
3
|
-
def process(composite):
|
|
4
|
-
for name, resource in composite.resources:
|
|
5
|
-
if resource.observed:
|
|
6
|
-
if resource.autoReady or (resource.autoReady is None and composite.autoReady):
|
|
7
|
-
if resource.ready is None:
|
|
8
|
-
if _checks.get((resource.apiVersion, resource.kind), _check_default).ready(resource):
|
|
9
|
-
resource.ready = True
|
|
10
7
|
|
|
11
|
-
|
|
12
|
-
class ConditionReady:
|
|
8
|
+
class ReadyCondition:
|
|
13
9
|
def ready(self, resource):
|
|
14
|
-
|
|
10
|
+
ready = resource.conditions.Ready
|
|
11
|
+
if not ready._find_condition():
|
|
12
|
+
return None
|
|
13
|
+
if ready.status:
|
|
14
|
+
return resource.observed.metadata.name
|
|
15
|
+
if ready.reason:
|
|
16
|
+
return resource.status.notReadyCondition[ready.reason]
|
|
17
|
+
return resource.status.notReadyCondition
|
|
15
18
|
|
|
16
19
|
_checks = {}
|
|
17
|
-
_check_default =
|
|
20
|
+
_check_default = ReadyCondition()
|
|
18
21
|
|
|
19
22
|
class Check:
|
|
20
23
|
@classmethod
|
|
@@ -28,7 +31,7 @@ class Check:
|
|
|
28
31
|
|
|
29
32
|
class AlwaysReady(Check):
|
|
30
33
|
def ready(self, resource):
|
|
31
|
-
return
|
|
34
|
+
return resource.observed.metadata.name
|
|
32
35
|
|
|
33
36
|
|
|
34
37
|
class ClusterRole(AlwaysReady):
|
|
@@ -44,57 +47,82 @@ class CronJob(Check):
|
|
|
44
47
|
apiVersion = 'batch/v1'
|
|
45
48
|
def ready(self, resource):
|
|
46
49
|
if resource.observed.spec.suspend and len(resource.observed.spec.suspend):
|
|
47
|
-
return
|
|
50
|
+
return resource.observed.metadata.name
|
|
48
51
|
if not resource.status.lastScheduleTime:
|
|
49
|
-
return
|
|
52
|
+
return resource.status.lastScheduleTime
|
|
50
53
|
if resource.status.active:
|
|
51
|
-
return
|
|
54
|
+
return resource.observed.metadata.name
|
|
52
55
|
if not resource.status.lastSuccessfulTime:
|
|
53
|
-
return
|
|
54
|
-
|
|
56
|
+
return resource.status.lastSuccessfulTime
|
|
57
|
+
if str(resource.status.lastSuccessfulTime) < str(resource.status.lastScheduleTime):
|
|
58
|
+
return resource.status.successfulBeforeSchedule
|
|
59
|
+
return resource.observed.metadata.name
|
|
55
60
|
|
|
56
61
|
class DaemonSet(Check):
|
|
57
62
|
apiVersion = 'apps/v1'
|
|
58
63
|
def ready(self, resource):
|
|
59
|
-
if not resource.status.desiredNumberScheduled:
|
|
60
|
-
return False
|
|
61
64
|
scheduled = resource.status.desiredNumberScheduled
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
if not scheduled:
|
|
66
|
+
return scheduled
|
|
67
|
+
for field in ('numberReady', 'updatedNumberScheduled', 'numberAvailable'):
|
|
68
|
+
value = resource.status[field]
|
|
69
|
+
if not value:
|
|
70
|
+
return value
|
|
71
|
+
if scheduled != value:
|
|
72
|
+
return resource.status[f"{field}NotScheduled"]
|
|
73
|
+
return resource.observed.metadata.name
|
|
66
74
|
|
|
67
75
|
class Deployment(Check):
|
|
68
76
|
apiVersion = 'apps/v1'
|
|
69
77
|
def ready(self, resource):
|
|
70
78
|
replicas = resource.observed.spec.replicas or 1
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
for field in ('updatedReplicas', 'availableReplicas'):
|
|
80
|
+
value = resource.status[field]
|
|
81
|
+
if not value:
|
|
82
|
+
return value
|
|
83
|
+
if replicas != value:
|
|
84
|
+
return resource.status[F"{field}NotReplicas"]
|
|
85
|
+
available = resource.conditions.Available
|
|
86
|
+
if not available:
|
|
87
|
+
return resource.status.notAvailable
|
|
88
|
+
if not available.status:
|
|
89
|
+
if available.reason:
|
|
90
|
+
return resource.status.notAvailable[available.reason]
|
|
91
|
+
return resource.status.notAvailable
|
|
92
|
+
return resource.observed.metadata.name
|
|
74
93
|
|
|
75
94
|
class HorizontalPodAutoscaler(Check):
|
|
76
95
|
apiVersion = 'autoscaling/v2'
|
|
77
96
|
def ready(self, resource):
|
|
78
97
|
for type in ('FailedGetScale', 'FailedUpdateScale', 'FailedGetResourceMetric', 'InvalidSelector'):
|
|
79
98
|
if resource.conditions[type].status:
|
|
80
|
-
return
|
|
99
|
+
return resource.status[f"is{type}"]
|
|
81
100
|
for type in ('ScalingActive', 'ScalingLimited'):
|
|
82
101
|
if resource.conditions[type].status:
|
|
83
|
-
return
|
|
84
|
-
return
|
|
102
|
+
return resource.observed.metadata.name
|
|
103
|
+
return resource.status.notScalingActiveOrLimiited
|
|
85
104
|
|
|
86
105
|
class Ingress(Check):
|
|
87
106
|
apiVersion = 'networking.k8s.io/v1'
|
|
88
107
|
def ready(self, resource):
|
|
89
|
-
|
|
108
|
+
if not len(resource.status.loadBalancer.ingress):
|
|
109
|
+
return resource.status.noLoadBalanceIngresses
|
|
110
|
+
return resource.observed.metadata.name
|
|
90
111
|
|
|
91
112
|
class Job(Check):
|
|
92
113
|
apiVersion = 'batch/v1'
|
|
93
114
|
def ready(self, resource):
|
|
94
115
|
for type in ('Failed', 'Suspended'):
|
|
95
116
|
if resource.conditions[type].status:
|
|
96
|
-
return
|
|
97
|
-
|
|
117
|
+
return resource.status[f"is{type}"]
|
|
118
|
+
complete = resource.conditions.Complete
|
|
119
|
+
if not complete:
|
|
120
|
+
return resource.status.notComplete
|
|
121
|
+
if not complete.status:
|
|
122
|
+
if complete.reason:
|
|
123
|
+
return resource.status.notComplete[complete.reason]
|
|
124
|
+
return resource.status.notComplete
|
|
125
|
+
return resource.observed.metadata.name
|
|
98
126
|
|
|
99
127
|
class Namespace(AlwaysReady):
|
|
100
128
|
apiVersion = 'v1'
|
|
@@ -102,27 +130,33 @@ class Namespace(AlwaysReady):
|
|
|
102
130
|
class PersistentVolumeClaim(Check):
|
|
103
131
|
apiVersion = 'v1'
|
|
104
132
|
def ready(self, resource):
|
|
105
|
-
|
|
133
|
+
if resource.status.phase != 'Bound':
|
|
134
|
+
return resource.status.phaseNotBound
|
|
135
|
+
return resource.observed.metadata.name
|
|
106
136
|
|
|
107
137
|
class Pod(Check):
|
|
108
138
|
apiVersion = 'v1'
|
|
109
139
|
def ready(self, resource):
|
|
110
140
|
if resource.status.phase == 'Succeeded':
|
|
111
|
-
return
|
|
141
|
+
return resource.observed.metadata.name
|
|
112
142
|
if resource.status.phase == 'Running':
|
|
113
143
|
if resource.observed.spec.restartPolicy == 'Always':
|
|
114
144
|
if resource.conditions.Ready.status:
|
|
115
|
-
return
|
|
116
|
-
return
|
|
145
|
+
return resource.observed.metadata.name
|
|
146
|
+
return resource.status.notSucceededOrRunning
|
|
117
147
|
|
|
118
148
|
class ReplicaSet(Check):
|
|
119
149
|
apiVersion = 'v1'
|
|
120
150
|
def ready(self, resource):
|
|
121
151
|
if int(resource.status.observedGeneration) < int(resource.observed.metadata.generation):
|
|
122
|
-
return
|
|
152
|
+
return resource.status.priorObservedGeneration
|
|
123
153
|
if resource.conditions.ReplicaFailure.status:
|
|
124
|
-
|
|
125
|
-
|
|
154
|
+
if resource.conditions.ReplicaFailure.reason:
|
|
155
|
+
return resource.status.isReplicaFailure[resource.conditions.ReplicaFailure.reason]
|
|
156
|
+
return resource.status.isReplicaFailure
|
|
157
|
+
if int(resource.status.availableReplicas) < int(resource.observed.spec.replicas or 1):
|
|
158
|
+
return resource.status.tooFewavailableReplicas
|
|
159
|
+
return resource.observed.metadata.name
|
|
126
160
|
|
|
127
161
|
class Role(AlwaysReady):
|
|
128
162
|
apiVersion = 'rbac.authorization.k8s.io/v1'
|
|
@@ -137,8 +171,10 @@ class Service(Check):
|
|
|
137
171
|
apiVersion = 'v1'
|
|
138
172
|
def ready(self, resource):
|
|
139
173
|
if resource.observed.spec.type != 'LoadBalancer':
|
|
140
|
-
return
|
|
141
|
-
|
|
174
|
+
return resource.observed.metadata.name
|
|
175
|
+
if not len(resource.status.loadBalancer.ingress):
|
|
176
|
+
return resource.status.noLoadBalancerIngresses
|
|
177
|
+
return resource.observed.metadata.name
|
|
142
178
|
|
|
143
179
|
class ServiceAccount(AlwaysReady):
|
|
144
180
|
apiVersion = 'v1'
|
|
@@ -147,7 +183,12 @@ class StatefulSet(Check):
|
|
|
147
183
|
apiVersion = 'apps/v1'
|
|
148
184
|
def ready(self, resource):
|
|
149
185
|
replicas = resource.observed.spec.replicas or 1
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
186
|
+
for field in ('readyReplicas', 'currentReplicas'):
|
|
187
|
+
value = resource.status[field]
|
|
188
|
+
if not value:
|
|
189
|
+
return value
|
|
190
|
+
if replicas != value:
|
|
191
|
+
return resource.status[F"{field}NotReplicas"]
|
|
192
|
+
if resource.status.currentRevision != resource.status.updateRevision:
|
|
193
|
+
return resource.status.currentRevisionNotUpdateReivsion
|
|
194
|
+
return resource.observed.metadata.name
|
crossplane/pythonic/command.py
CHANGED
|
@@ -33,6 +33,13 @@ class Command:
|
|
|
33
33
|
metavar='WIDTH',
|
|
34
34
|
help='Width of the logger name in the log output, default 40.',
|
|
35
35
|
)
|
|
36
|
+
parser.add_argument(
|
|
37
|
+
'--logger-level',
|
|
38
|
+
action='append',
|
|
39
|
+
default=[],
|
|
40
|
+
metavar='LOGGER=LEVEL',
|
|
41
|
+
help='Logger level, for example: botocore.hooks=INFO',
|
|
42
|
+
)
|
|
36
43
|
parser.add_argument(
|
|
37
44
|
'--python-path',
|
|
38
45
|
action='append',
|
|
@@ -70,6 +77,11 @@ class Command:
|
|
|
70
77
|
logger = logging.getLogger()
|
|
71
78
|
logger.handlers = [handler]
|
|
72
79
|
logger.setLevel(logging.DEBUG if self.args.debug else logging.INFO)
|
|
80
|
+
for logger_level in self.args.logger_level:
|
|
81
|
+
for logger_level in logger_level.split(','):
|
|
82
|
+
logger_level = logger_level.split('=')
|
|
83
|
+
if len(logger_level) == 2:
|
|
84
|
+
logging.getLogger(logger_level[0]).setLevel(logger_level[1].upper())
|
|
73
85
|
|
|
74
86
|
for path in reversed(self.args.python_path):
|
|
75
87
|
sys.path.insert(0, str(pathlib.Path(path).expanduser().resolve()))
|
crossplane/pythonic/composite.py
CHANGED
|
@@ -3,6 +3,7 @@ import datetime
|
|
|
3
3
|
from google.protobuf.duration_pb2 import Duration
|
|
4
4
|
from crossplane.function.proto.v1 import run_function_pb2 as fnv1
|
|
5
5
|
|
|
6
|
+
from . import auto_ready
|
|
6
7
|
from . import protobuf
|
|
7
8
|
|
|
8
9
|
|
|
@@ -69,21 +70,22 @@ class TTL:
|
|
|
69
70
|
|
|
70
71
|
class Ready:
|
|
71
72
|
def __get__(self, composite, objtype=None):
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
if hasattr(composite, '_ready'):
|
|
74
|
+
return composite._ready
|
|
75
|
+
if composite.desired._parent.ready == fnv1.Ready.READY_TRUE:
|
|
74
76
|
return True
|
|
75
|
-
if ready == fnv1.Ready.READY_FALSE:
|
|
77
|
+
if composite.desired._parent.ready == fnv1.Ready.READY_FALSE:
|
|
76
78
|
return False
|
|
77
79
|
return None
|
|
78
80
|
|
|
79
81
|
def __set__(self, composite, ready):
|
|
82
|
+
composite._ready = ready
|
|
80
83
|
if ready:
|
|
81
|
-
ready = fnv1.Ready.READY_TRUE
|
|
82
|
-
elif ready
|
|
83
|
-
ready = fnv1.Ready.READY_UNSPECIFIED
|
|
84
|
+
composite.desired._parent.ready = fnv1.Ready.READY_TRUE
|
|
85
|
+
elif ready is None:
|
|
86
|
+
composite.desired._parent.ready = fnv1.Ready.READY_UNSPECIFIED
|
|
84
87
|
else:
|
|
85
|
-
ready = fnv1.Ready.READY_FALSE
|
|
86
|
-
composite.desired._parent.ready = ready
|
|
88
|
+
composite.desired._parent.ready = fnv1.Ready.READY_FALSE
|
|
87
89
|
|
|
88
90
|
|
|
89
91
|
class BaseComposite:
|
|
@@ -111,9 +113,9 @@ class BaseComposite:
|
|
|
111
113
|
self.environment = self.context['apiextensions.crossplane.io/environment']
|
|
112
114
|
self.requireds = Requireds(self)
|
|
113
115
|
self.resources = Resources(self)
|
|
114
|
-
self.unknownsFatal = True
|
|
115
116
|
self.autoReady = True
|
|
116
117
|
self.usages = False
|
|
118
|
+
self.unknownsFatal = False
|
|
117
119
|
|
|
118
120
|
observed = self.request.observed.composite
|
|
119
121
|
desired = self.response.desired.composite
|
|
@@ -231,6 +233,7 @@ class Resources:
|
|
|
231
233
|
|
|
232
234
|
class Resource:
|
|
233
235
|
def __init__(self, composite, name):
|
|
236
|
+
self._composite = composite
|
|
234
237
|
self.name = name
|
|
235
238
|
observed = composite.request.observed.resources[name]
|
|
236
239
|
desired = composite.response.desired.resources[name]
|
|
@@ -238,16 +241,22 @@ class Resource:
|
|
|
238
241
|
self.desired = desired.resource
|
|
239
242
|
self.conditions = Conditions(observed)
|
|
240
243
|
self.connection = observed.connection_details
|
|
241
|
-
self.unknownsFatal = None
|
|
242
244
|
self.autoReady = None
|
|
243
245
|
self.usages = None
|
|
246
|
+
self.unknownsFatal = None
|
|
244
247
|
|
|
245
|
-
def __call__(self,
|
|
248
|
+
def __call__(self, kind=_notset, apiVersion=_notset, namespace=_notset, name=_notset):
|
|
246
249
|
self.desired()
|
|
250
|
+
if kind != _notset:
|
|
251
|
+
# Allow for apiVersion in the first arg and kind in the second arg
|
|
252
|
+
if '/' in kind or kind == 'v1':
|
|
253
|
+
if apiVersion != _notset:
|
|
254
|
+
self.kind = apiVersion
|
|
255
|
+
apiVersion = kind
|
|
256
|
+
else:
|
|
257
|
+
self.kind = kind
|
|
247
258
|
if apiVersion != _notset:
|
|
248
259
|
self.apiVersion = apiVersion
|
|
249
|
-
if kind != _notset:
|
|
250
|
-
self.kind = kind
|
|
251
260
|
if namespace != _notset:
|
|
252
261
|
self.metadata.namespace = namespace
|
|
253
262
|
if name != _notset:
|
|
@@ -272,9 +281,12 @@ class Resource:
|
|
|
272
281
|
|
|
273
282
|
@property
|
|
274
283
|
def externalName(self):
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
284
|
+
name = self.metadata.annotations['crossplane.io/external-name']
|
|
285
|
+
if not name:
|
|
286
|
+
name = self.observed.metadata.annotations['crossplane.io/external-name']
|
|
287
|
+
if name:
|
|
288
|
+
self.externalName = name
|
|
289
|
+
return name
|
|
278
290
|
|
|
279
291
|
@externalName.setter
|
|
280
292
|
def externalName(self, name):
|
|
@@ -296,6 +308,7 @@ class Resource:
|
|
|
296
308
|
def spec(self, spec):
|
|
297
309
|
self.desired.spec = spec
|
|
298
310
|
|
|
311
|
+
# Used by Secret:v1
|
|
299
312
|
@property
|
|
300
313
|
def type(self):
|
|
301
314
|
return self.desired.type
|
|
@@ -318,23 +331,60 @@ class Resource:
|
|
|
318
331
|
|
|
319
332
|
@property
|
|
320
333
|
def ready(self):
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
334
|
+
if not hasattr(self, '_ready'):
|
|
335
|
+
if self.desired._parent.ready == fnv1.Ready.READY_TRUE:
|
|
336
|
+
self._ready = True
|
|
337
|
+
elif self.desired._parent.ready == fnv1.Ready.READY_FALSE:
|
|
338
|
+
self._ready = False
|
|
339
|
+
else:
|
|
340
|
+
self._ready = None
|
|
341
|
+
if self.autoReady or (self.autoReady is None and self._composite.autoReady):
|
|
342
|
+
ready = auto_ready.resource_ready(self)
|
|
343
|
+
if ready:
|
|
344
|
+
self._ready = ready
|
|
345
|
+
self.desired._parent.ready = fnv1.Ready.READY_TRUE
|
|
346
|
+
return self._ready
|
|
327
347
|
|
|
328
348
|
@ready.setter
|
|
329
349
|
def ready(self, ready):
|
|
350
|
+
self._ready = ready
|
|
330
351
|
if ready:
|
|
331
|
-
ready = fnv1.Ready.READY_TRUE
|
|
332
|
-
elif ready
|
|
333
|
-
ready = fnv1.Ready.READY_UNSPECIFIED
|
|
352
|
+
self.desired._parent.ready = fnv1.Ready.READY_TRUE
|
|
353
|
+
elif ready is None:
|
|
354
|
+
self.desired._parent.ready = fnv1.Ready.READY_UNSPECIFIED
|
|
334
355
|
else:
|
|
335
|
-
ready = fnv1.Ready.READY_FALSE
|
|
336
|
-
self.desired._parent.ready = ready
|
|
356
|
+
self.desired._parent.ready = fnv1.Ready.READY_FALSE
|
|
337
357
|
|
|
358
|
+
def setReadyCondition(self, type='Ready'):
|
|
359
|
+
condition = self.conditions[type]
|
|
360
|
+
if condition.status:
|
|
361
|
+
self.ready = self.observed.metadata.name
|
|
362
|
+
else:
|
|
363
|
+
error = f"not{type}Condition"
|
|
364
|
+
if condition.reason:
|
|
365
|
+
self.ready = self.status[error][condition.reason]
|
|
366
|
+
else:
|
|
367
|
+
self.ready = self.status[error]
|
|
368
|
+
|
|
369
|
+
def addDependency(self, resource, field=_notset):
|
|
370
|
+
if field is _notset:
|
|
371
|
+
field = resource.ready
|
|
372
|
+
if field is None:
|
|
373
|
+
field = auto_ready.resource_ready(resource)
|
|
374
|
+
if field is None:
|
|
375
|
+
field = False
|
|
376
|
+
resource.ready = field
|
|
377
|
+
elif field is None:
|
|
378
|
+
field = True
|
|
379
|
+
if not isinstance(field, (protobuf.FieldMessage, protobuf.Value)):
|
|
380
|
+
if field:
|
|
381
|
+
field = resource.observed.metadata.name
|
|
382
|
+
else:
|
|
383
|
+
if not resource.observed.metadata.name:
|
|
384
|
+
field = resource.observed.metadata.name
|
|
385
|
+
else:
|
|
386
|
+
field = resource.status.notReady
|
|
387
|
+
self.metadata.annotations[f"Dependency{resource.name}"] = field
|
|
338
388
|
|
|
339
389
|
class Requireds:
|
|
340
390
|
def __init__(self, composite):
|
|
@@ -408,12 +458,18 @@ class RequiredResources:
|
|
|
408
458
|
self._resources = composite.request.required_resources[name]
|
|
409
459
|
self._cache = {}
|
|
410
460
|
|
|
411
|
-
def __call__(self,
|
|
461
|
+
def __call__(self, kind=_notset, apiVersion=_notset, namespace=_notset, name=_notset, labels=_notset):
|
|
412
462
|
self._selector()
|
|
463
|
+
if kind != _notset:
|
|
464
|
+
# Allow for apiVersion in the first arg and kind in the second arg
|
|
465
|
+
if '/' in kind or kind == 'v1':
|
|
466
|
+
if apiVersion != _notset:
|
|
467
|
+
self.kind = apiVersion
|
|
468
|
+
apiVersion = kind
|
|
469
|
+
else:
|
|
470
|
+
self.kind = kind
|
|
413
471
|
if apiVersion != _notset:
|
|
414
472
|
self.apiVersion = apiVersion
|
|
415
|
-
if kind != _notset:
|
|
416
|
-
self.kind = kind
|
|
417
473
|
if namespace != _notset:
|
|
418
474
|
self.namespace = namespace
|
|
419
475
|
if name != _notset:
|
|
@@ -802,60 +858,36 @@ class _Connection:
|
|
|
802
858
|
|
|
803
859
|
@property
|
|
804
860
|
def observed(self):
|
|
805
|
-
|
|
806
|
-
return self._composite.response.observed.composite.connection_details
|
|
807
|
-
data = protobuf.Map()
|
|
808
|
-
for key, value in self._composite.resources[self._resource_name].observed.data:
|
|
809
|
-
data[key] = protobuf.B64Decode(value)
|
|
810
|
-
return data
|
|
861
|
+
return self._composite.response.observed.composite.connection_details
|
|
811
862
|
|
|
812
863
|
def __getattr__(self, key):
|
|
813
864
|
return self[key]
|
|
814
865
|
|
|
815
866
|
def __getitem__(self, key):
|
|
816
|
-
|
|
817
|
-
return self._composite.response.desired.composite.connection_details[key]
|
|
818
|
-
value = self._composite.resources[self._resource_name].data[key]
|
|
819
|
-
if value:
|
|
820
|
-
value = protobuf.B64Decode(value)
|
|
821
|
-
return value
|
|
867
|
+
return self._composite.response.desired.composite.connection_details[key]
|
|
822
868
|
|
|
823
869
|
def __bool__(self):
|
|
824
|
-
|
|
825
|
-
return bool(self._composite.response.desired.composite.connection_details)
|
|
826
|
-
return bool(self._composite.resources[self._resource_name].data)
|
|
870
|
+
return bool(self._composite.response.desired.composite.connection_details)
|
|
827
871
|
|
|
828
872
|
def __len__(self):
|
|
829
|
-
|
|
830
|
-
return len(self._composite.response.desired.composite.connection_details)
|
|
831
|
-
return len(self._composite.resources[self._resource_name].data)
|
|
873
|
+
return len(self._composite.response.desired.composite.connection_details)
|
|
832
874
|
|
|
833
875
|
def __contains__(self, key):
|
|
834
|
-
|
|
835
|
-
return key in self._composite.response.desired.composite.connection_details
|
|
876
|
+
return key in self._composite.response.desired.composite.connection_details
|
|
836
877
|
|
|
837
878
|
def __iter__(self):
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
for key, value in self._composite.response.desired.composite.connection_details:
|
|
841
|
-
yield key, value
|
|
842
|
-
for key, value in self._composite.resources[self._resource_name].data:
|
|
843
|
-
yield key, protobuf.B64Decode(value)
|
|
879
|
+
for key, value in self._composite.response.desired.composite.connection_details:
|
|
880
|
+
yield key, value
|
|
844
881
|
|
|
845
882
|
def __str__(self):
|
|
846
883
|
return format(self)
|
|
847
884
|
|
|
848
885
|
def __format__(self, spec='yaml'):
|
|
849
|
-
|
|
850
|
-
return format(self._composite.response.desired.composite.connection_details, spec)
|
|
851
|
-
data = protobuf.Map()
|
|
852
|
-
for key, value in self._composite.resources[self._resource_name].data:
|
|
853
|
-
data[key] = protobuf.B64Decode(value)
|
|
854
|
-
return format(data, spec)
|
|
886
|
+
return format(self._composite.response.desired.composite.connection_details, spec)
|
|
855
887
|
|
|
856
888
|
def __call__(self, **kwargs):
|
|
889
|
+
self._composite.response.desired.composite.connection_details(**kwargs)
|
|
857
890
|
if self._composite_v1:
|
|
858
|
-
self._composite.response.desired.composite.connection_details(**kwargs)
|
|
859
891
|
return
|
|
860
892
|
del self._composite.resources[self._resource_name]
|
|
861
893
|
for key, value in kwargs:
|
|
@@ -872,16 +904,13 @@ class _Connection:
|
|
|
872
904
|
if not value:
|
|
873
905
|
return
|
|
874
906
|
value = str(value)
|
|
875
|
-
|
|
876
|
-
|
|
907
|
+
self._composite.response.desired.composite.connection_details[key] = value
|
|
908
|
+
if self._composite.crossplane_v1 or not self._composite.connectionSecret.name:
|
|
877
909
|
return
|
|
878
|
-
#if not self._composite.connectionSecret.name:
|
|
879
|
-
# return
|
|
880
910
|
if self._resource_name in self._composite.resources:
|
|
881
911
|
secret = self._composite.resources[self._resource_name]
|
|
882
912
|
else:
|
|
883
913
|
secret = self._composite.resources[self._resource_name]('v1', 'Secret')
|
|
884
|
-
print(bool(self._composite.connectionSecret.name), len(self._composite.connectionSecret.name))
|
|
885
914
|
if self._composite.connectionSecret.name and len(self._composite.connectionSecret.name):
|
|
886
915
|
secret.metadata.name = self._composite.connectionSecret.name
|
|
887
916
|
if not self._composite.metadata.namespace:
|
|
@@ -896,8 +925,8 @@ class _Connection:
|
|
|
896
925
|
del self[key]
|
|
897
926
|
|
|
898
927
|
def __delitem__(self, key):
|
|
928
|
+
del self._composite.response.desired.composite.connection_details[key]
|
|
899
929
|
if self._composite.crossplane_v1:
|
|
900
|
-
del self._composite.response.desired.composite.connection_details[key]
|
|
901
930
|
return
|
|
902
931
|
if self._resource_name in self._composite.resources:
|
|
903
932
|
del self._composite.resources[self._resource_name].data[key]
|
crossplane/pythonic/function.py
CHANGED
|
@@ -9,7 +9,6 @@ import sys
|
|
|
9
9
|
import grpc
|
|
10
10
|
from crossplane.function.proto.v1 import run_function_pb2 as fnv1
|
|
11
11
|
from crossplane.function.proto.v1 import run_function_pb2_grpc as grpcv1
|
|
12
|
-
from . import auto_ready
|
|
13
12
|
from .. import pythonic
|
|
14
13
|
|
|
15
14
|
logger = logging.getLogger(__name__)
|
|
@@ -110,7 +109,13 @@ class FunctionRunner(grpcv1.FunctionRunnerService):
|
|
|
110
109
|
iteration = int(step.iteration) + 1
|
|
111
110
|
step.iteration = iteration
|
|
112
111
|
composite.context.iteration = iteration
|
|
113
|
-
|
|
112
|
+
if iteration == 1 and not logger.isEnabledFor(logging.DEBUG):
|
|
113
|
+
if len(composite.context._pythonic) == 1:
|
|
114
|
+
logger.info('Starting compose')
|
|
115
|
+
else:
|
|
116
|
+
logger.info(f"Starting compose, {ordinal(len(composite.context._pythonic))} step")
|
|
117
|
+
else:
|
|
118
|
+
logger.debug(f"Starting compose, {ordinal(len(composite.context._pythonic))} step, {ordinal(iteration)} pass")
|
|
114
119
|
|
|
115
120
|
try:
|
|
116
121
|
result = composite.compose()
|
|
@@ -120,11 +125,13 @@ class FunctionRunner(grpcv1.FunctionRunnerService):
|
|
|
120
125
|
return self.fatal(request, logger, 'Compose', e)
|
|
121
126
|
|
|
122
127
|
if requireds := self.get_requireds(step, composite):
|
|
123
|
-
logger.
|
|
128
|
+
logger.debug(f"Requireds requested: {','.join(requireds)}")
|
|
124
129
|
else:
|
|
125
130
|
self.process_usages(composite)
|
|
126
131
|
self.process_unknowns(composite)
|
|
127
|
-
|
|
132
|
+
# Perform auto ready on all resources.
|
|
133
|
+
for name, resource in composite.resources:
|
|
134
|
+
resource.ready
|
|
128
135
|
logger.info('Completed compose')
|
|
129
136
|
|
|
130
137
|
return composite.response._message
|
|
@@ -322,9 +329,11 @@ class FunctionRunner(grpcv1.FunctionRunnerService):
|
|
|
322
329
|
name = name.split('.')
|
|
323
330
|
for values in (
|
|
324
331
|
('request', 'observed', 'composite', 'resource'),
|
|
332
|
+
('response', 'desired', 'composite', 'resource'),
|
|
325
333
|
('request', 'observed', 'resources', None, 'resource'),
|
|
326
|
-
('request', 'extra_resources', None, 'items', None, 'resource'),
|
|
327
334
|
('response', 'desired', 'resources', None, 'resource'),
|
|
335
|
+
('request', 'required_resources', None, 'items', None, 'resource'),
|
|
336
|
+
('request', 'extra_resources', None, 'items', None, 'resource'),
|
|
328
337
|
):
|
|
329
338
|
if len(values) < len(name):
|
|
330
339
|
ix = 0
|