crossplane-function-pythonic 0.0.7a0__py3-none-any.whl → 0.0.7b0__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.
@@ -0,0 +1,19 @@
1
+
2
+ import base64
3
+
4
+ from .composite import BaseComposite
5
+ from .protobuf import append, Map, List, Unknown, Yaml, Json
6
+ B64Encode = lambda s: base64.b64encode(s.encode('utf-8')).decode('utf-8')
7
+ B64Decode = lambda s: base64.b64decode(s.encode('utf-8')).decode('utf-8')
8
+
9
+ __all__ = [
10
+ 'BaseComposite',
11
+ 'append',
12
+ 'Map',
13
+ 'List',
14
+ 'Unknown',
15
+ 'Yaml',
16
+ 'Json',
17
+ 'B64Encode',
18
+ 'B64Decode',
19
+ ]
@@ -0,0 +1,670 @@
1
+
2
+ import datetime
3
+ from crossplane.function.proto.v1 import run_function_pb2 as fnv1
4
+
5
+ from . import protobuf
6
+
7
+
8
+ _notset = object()
9
+
10
+
11
+ class BaseComposite:
12
+ def __init__(self, request, response, logger):
13
+ self.request = protobuf.Message(None, 'request', request.DESCRIPTOR, request, 'Function Request')
14
+ self.response = protobuf.Message(None, 'response', response.DESCRIPTOR, response)
15
+ self.logger = logger
16
+ self.credentials = Credentials(self.request)
17
+ self.context = self.response.context
18
+ self.environment = self.context['apiextensions.crossplane.io/environment']
19
+ self.requireds = Requireds(self)
20
+ self.resources = Resources(self)
21
+ self.unknownsFatal = True
22
+ self.autoReady = True
23
+
24
+ observed = self.request.observed.composite
25
+ desired = self.response.desired.composite
26
+ self.observed = observed.resource
27
+ self.desired = desired.resource
28
+ self.apiVersion = self.observed.apiVersion
29
+ self.kind = self.observed.kind
30
+ self.metadata = self.observed.metadata
31
+ self.spec = self.observed.spec
32
+ self.status = Status(self.observed.status, self.desired.status)
33
+ self.conditions = Conditions(observed, self.response)
34
+ self.connection = Connection(observed, desired)
35
+ self.events = Events(self.response)
36
+
37
+ @property
38
+ def ttl(self):
39
+ return self.response.meta.ttl.seconds
40
+
41
+ @ttl.setter
42
+ def ttl(self, ttl):
43
+ self.response.meta.ttl.seconds = ttl
44
+
45
+ @property
46
+ def ready(self):
47
+ ready = self.desired._parent.ready
48
+ if ready == fnv1.Ready.READY_TRUE:
49
+ return True
50
+ if ready == fnv1.Ready.READY_FALSE:
51
+ return False
52
+ return None
53
+
54
+ @ready.setter
55
+ def ready(self, ready):
56
+ if ready:
57
+ ready = fnv1.Ready.READY_TRUE
58
+ elif ready == None or (isinstance(ready, protobuf.Values) and ready._isUnknown):
59
+ ready = fnv1.Ready.READY_UNSPECIFIED
60
+ else:
61
+ ready = fnv1.Ready.READY_FALSE
62
+ self.desired._parent.ready = ready
63
+
64
+ async def compose(self):
65
+ raise NotImplementedError()
66
+
67
+
68
+ class Credentials:
69
+ def __init__(self, request):
70
+ self.__dict__['_request'] = request
71
+
72
+ def __getattr__(self, key):
73
+ return self[key]
74
+
75
+ def __getitem__(self, key):
76
+ return self._request.credentials[key].credentials_data.data
77
+
78
+ def __bool__(self):
79
+ return bool(_request.credentials)
80
+
81
+ def __len__(self):
82
+ return len(self._request.credentials)
83
+
84
+ def __contains__(self, key):
85
+ return key in _request.credentials
86
+
87
+ def __iter__(self):
88
+ for key, resource in self._request.credentials:
89
+ yield key, self[key]
90
+
91
+
92
+ class Resources:
93
+ def __init__(self, composite):
94
+ self.__dict__['_composite'] = composite
95
+
96
+ def __getattr__(self, key):
97
+ return self[key]
98
+
99
+ def __getitem__(self, key):
100
+ return Resource(self._composite, key)
101
+
102
+ def __bool__(self):
103
+ return bool(self._composite.response.desired.resources)
104
+
105
+ def __len__(self):
106
+ return len(self._composite.response.desired.resources)
107
+
108
+ def __contains__(self, key):
109
+ return key in self._composite.response.desired.resources
110
+
111
+ def __iter__(self):
112
+ for name, resource in self._composite.response.desired.resources:
113
+ yield name, self[name]
114
+
115
+ def __setattr__(self, key, resource):
116
+ self[key] = resource
117
+
118
+ def __setitem__(self, key, resource):
119
+ self._composite.response.desired.resources[key].resource = resource
120
+
121
+ def __delattr__(self, key):
122
+ del self[key]
123
+
124
+ def __delitem__(self, key):
125
+ if key in self._composite.response.desired.resources:
126
+ del self._composite.response.desired.resources[key]
127
+
128
+
129
+ class Resource:
130
+ def __init__(self, composite, name):
131
+ self.name = name
132
+ observed = composite.request.observed.resources[name]
133
+ desired = composite.response.desired.resources[name]
134
+ self.observed = observed.resource
135
+ self.desired = desired.resource
136
+ self.conditions = Conditions(observed)
137
+ self.connection = Connection(observed)
138
+ self.unknownsFatal = None
139
+ self.autoReady = None
140
+
141
+ def __call__(self, apiVersion=_notset, kind=_notset, namespace=_notset, name=_notset):
142
+ self.desired()
143
+ if apiVersion != _notset:
144
+ self.apiVersion = apiVersion
145
+ if kind != _notset:
146
+ self.kind = kind
147
+ if namespace != _notset:
148
+ self.metadata.namespace = namespace
149
+ if name != _notset:
150
+ self.metadata.name = name
151
+ return self
152
+
153
+ @property
154
+ def apiVersion(self):
155
+ return self.observed.apiVersion
156
+
157
+ @apiVersion.setter
158
+ def apiVersion(self, apiVersion):
159
+ self.desired.apiVersion = apiVersion
160
+
161
+ @property
162
+ def kind(self):
163
+ return self.observed.kind
164
+
165
+ @kind.setter
166
+ def kind(self, kind):
167
+ self.desired.kind = kind
168
+
169
+ @property
170
+ def externalName(self):
171
+ name = self.metadata.annotations['crossplane.io/external-name']
172
+ if name is None:
173
+ name = self.observed.metadata.annotations['crossplane.io/external-name']
174
+ return name
175
+
176
+ @externalName.setter
177
+ def externalName(self, name):
178
+ self.metadata.annotations['crossplane.io/external-name'] = name
179
+
180
+ @property
181
+ def metadata(self):
182
+ return self.desired.metadata
183
+
184
+ @metadata.setter
185
+ def metadata(self, metadata):
186
+ self.desired.metadata = metadata
187
+
188
+ @property
189
+ def spec(self):
190
+ return self.desired.spec
191
+
192
+ @spec.setter
193
+ def spec(self, spec):
194
+ self.desired.spec = spec
195
+
196
+ @property
197
+ def data(self):
198
+ return self.desired.data
199
+
200
+ @data.setter
201
+ def data(self, data):
202
+ self.desired.data = data
203
+
204
+ @property
205
+ def status(self):
206
+ return self.observed.status
207
+
208
+ @property
209
+ def ready(self):
210
+ ready = self.desired._parent.ready
211
+ if ready == fnv1.Ready.READY_TRUE:
212
+ return True
213
+ if ready == fnv1.Ready.READY_FALSE:
214
+ return False
215
+ return None
216
+
217
+ @ready.setter
218
+ def ready(self, ready):
219
+ if ready:
220
+ ready = fnv1.Ready.READY_TRUE
221
+ elif ready == None or (isinstance(ready, protobuf.Values) and ready._isUnknown):
222
+ ready = fnv1.Ready.READY_UNSPECIFIED
223
+ else:
224
+ ready = fnv1.Ready.READY_FALSE
225
+ self.desired._parent.ready = ready
226
+
227
+
228
+ class Requireds:
229
+ def __init__(self, composite):
230
+ self._composite = composite
231
+
232
+ def __getattr__(self, key):
233
+ return self[key]
234
+
235
+ def __getitem__(self, key):
236
+ return RequiredResources(self._composite, key)
237
+
238
+ def __bool__(self):
239
+ return bool(len(self))
240
+
241
+ def __len__(self):
242
+ names = set()
243
+ for name, resource in self._composite.request.extra_resources:
244
+ names.add(name)
245
+ for name, resource in self._composite.response.requirements.extra_resources:
246
+ names.add(name)
247
+ return len(names)
248
+
249
+ def __contains__(self, key):
250
+ if key in self._composite.request.extra_resources:
251
+ return True
252
+ if key in self._composite.response.desired.resources:
253
+ return True
254
+ return False
255
+
256
+ def __iter__(self):
257
+ names = set()
258
+ for name, resource in self._composite.request.extra_resources:
259
+ names.add(name)
260
+ for name, resource in self._composite.response.requirements.extra_resources:
261
+ names.add(name)
262
+ for name in sorted(names):
263
+ yield name, self[name]
264
+
265
+
266
+ class RequiredResources:
267
+ def __init__(self, composite, name):
268
+ self.name = name
269
+ self._selector = composite.response.requirements.extra_resources[name]
270
+ self._resources = composite.request.extra_resources[name]
271
+
272
+ def __call__(self, apiVersion=_notset, kind=_notset, namespace=_notset, name=_notset, labels=_notset):
273
+ self._selector()
274
+ if apiVersion != _notset:
275
+ self.apiVersion = apiVersion
276
+ if kind != _notset:
277
+ self.kind = kind
278
+ if namespace != _notset:
279
+ self.namespace = namespace
280
+ if name != _notset:
281
+ self.matchName = name
282
+ if labels != _notset:
283
+ self.matchLabels = labels
284
+ return self
285
+
286
+ @property
287
+ def apiVersion(self):
288
+ return self._selector.api_version
289
+
290
+ @apiVersion.setter
291
+ def apiVersion(self, apiVersion):
292
+ self._selector.api_version = apiVersion
293
+
294
+ @property
295
+ def kind(self):
296
+ return self._selector.kind
297
+
298
+ @kind.setter
299
+ def kind(self, kind):
300
+ self._selector.kind = kind
301
+
302
+ @property
303
+ def namespace(self):
304
+ return self._selector.namespace
305
+
306
+ @namespace.setter
307
+ def namespace(self, namespace):
308
+ self._selector.namespace = namespace
309
+
310
+ @property
311
+ def matchName(self):
312
+ return self._selector.match_name
313
+
314
+ @matchName.setter
315
+ def matchName(self, name):
316
+ self._selector.match_name = name
317
+
318
+ @property
319
+ def matchLabels(self):
320
+ return self._selector.match_labels.labels
321
+
322
+ @matchLabels.setter
323
+ def matchLabels(self, labels):
324
+ self._selector.match_labels.labels()
325
+ if labels:
326
+ for entry in labels:
327
+ if isinstance(entry, str):
328
+ self._selector.match_labels.labels[entry] = labels[entry]
329
+ elif isinstance(entry, (list, tuple)):
330
+ self._selector.match_labels.labels[entry[0]] = entry[1]
331
+
332
+ def __getitem__(self, key):
333
+ return RequiredResource(self.name, self._resources.items[key])
334
+
335
+ def __bool__(self):
336
+ return bool(self._resources.items)
337
+
338
+ def __len__(self):
339
+ return len(self._resources.items)
340
+
341
+ def __iter__(self):
342
+ for ix in range(len(self)):
343
+ yield self[ix]
344
+
345
+
346
+ class RequiredResource:
347
+ def __init__(self, name, resource):
348
+ self.name = name
349
+ self.observed = resource.resource
350
+ self.apiVersion = self.observed.apiVersion
351
+ self.kind = self.observed.kind
352
+ self.metadata = self.observed.metadata
353
+ self.spec = self.observed.spec
354
+ self.data = self.observed.data
355
+ self.status = self.observed.status
356
+ self.conditions = Conditions(resource)
357
+
358
+ def __bool__(self):
359
+ return bool(self.observed)
360
+
361
+
362
+ class Status:
363
+ def __init__(self, observed, desired):
364
+ self.__dict__['_observed'] = observed
365
+ self.__dict__['_desired'] = desired
366
+
367
+ def __getattr__(self, key):
368
+ return self[key]
369
+
370
+ def __getitem__(self, key):
371
+ value = self._desired[key]
372
+ if value is None:
373
+ value = self._observed[key]
374
+ return value
375
+
376
+ def __setattr__(self, key, value):
377
+ self[key] = value
378
+
379
+ def __setitem__(self, key, value):
380
+ self._desired[key] = value
381
+
382
+
383
+ class Conditions:
384
+ def __init__(self, observed, response=None):
385
+ self._observed = observed
386
+ self._response = response
387
+
388
+ def __getattr__(self, type):
389
+ return self[type]
390
+
391
+ def __getitem__(self, type):
392
+ return Condition(self, type)
393
+
394
+
395
+ class Condition(protobuf.ProtobufValue):
396
+ def __init__(self, conditions, type):
397
+ self._conditions = conditions
398
+ self.type = type
399
+
400
+ @property
401
+ def _protobuf_value(self):
402
+ status = self.status
403
+ value = {
404
+ 'type': self.type,
405
+ 'status': 'Unknown' if status is None else str(status),
406
+ 'reason': self.reason or '',
407
+ 'message': self.message or '',
408
+ }
409
+ time = self.lastTransitionTime
410
+ if time:
411
+ value['lastTransitionTime'] = time.isoformat().replace('+00:00', 'Z')
412
+ return value
413
+
414
+ def __call__(self, reason=_notset, message=_notset, status=_notset, claim=_notset):
415
+ self._find_condition(True)
416
+ if reason != _notset:
417
+ self.reason = reason
418
+ if message != _notset:
419
+ self.message = message
420
+ if status != _notset:
421
+ self.status = status
422
+ if claim != _notset:
423
+ self.claim = claim
424
+ return self
425
+
426
+ @property
427
+ def status(self):
428
+ condition = self._find_condition()
429
+ if condition:
430
+ if condition.status in (fnv1.Status.STATUS_CONDITION_TRUE, 'True', True):
431
+ return True
432
+ if condition.status in (fnv1.Status.STATUS_CONDITION_FALSE, 'False', False):
433
+ return False
434
+ return None
435
+
436
+ @status.setter
437
+ def status(self, status):
438
+ condition = self._find_condition(True)
439
+ if status:
440
+ condition.status = fnv1.Status.STATUS_CONDITION_TRUE
441
+ elif status == None:
442
+ condition.status = fnv1.Status.STATUS_CONDITION_UNKNOWN
443
+ elif isinstance(status, protobuf.Values) and status._isUnknown:
444
+ condition.status = fnv1.Status.STATUS_CONDITION_UNSPECIFIED
445
+ else:
446
+ condition.status = fnv1.Status.STATUS_CONDITION_FALSE
447
+
448
+
449
+ @property
450
+ def reason(self):
451
+ condition = self._find_condition()
452
+ if condition:
453
+ return condition.reason
454
+ return None
455
+
456
+ @reason.setter
457
+ def reason(self, reason):
458
+ self._find_condition(True).reason = reason
459
+
460
+ @property
461
+ def message(self):
462
+ condition = self._find_condition()
463
+ if condition:
464
+ return condition.message
465
+ return None
466
+
467
+ @message.setter
468
+ def message(self, message):
469
+ self._find_condition(True).message = message
470
+
471
+ @property
472
+ def lastTransitionTime(self):
473
+ for observed in self._conditions._observed.resource.status.conditions:
474
+ if observed.type == self.type:
475
+ time = observed.lastTransitionTime
476
+ if time:
477
+ return datetime.datetime.fromisoformat(time)
478
+ return None
479
+
480
+ @property
481
+ def claim(self):
482
+ condition = self._find_condition()
483
+ return condition and condition.target == fnv1.Target.TARGET_COMPOSITE_AND_CLAIM
484
+
485
+ @claim.setter
486
+ def claim(self, claim):
487
+ condition = self._find_condition(True)
488
+ if claim:
489
+ condition.target = fnv1.Target.TARGET_COMPOSITE_AND_CLAIM
490
+ elif claim == None or (isinstance(claim, protobuf.Values) and claim._isUnknown):
491
+ condition.target = fnv1.Target.TARGET_UNSPECIFIED
492
+ else:
493
+ condition.target = fnv1.Target.TARGET_COMPOSITE
494
+
495
+ def _find_condition(self, create=False):
496
+ if self._conditions._response is not None:
497
+ for condition in self._conditions._response.conditions:
498
+ if condition.type == self.type:
499
+ return condition
500
+ if not create:
501
+ for observed in self._conditions._observed.resource.status.conditions:
502
+ if observed.type == self.type:
503
+ return observed
504
+ return None
505
+ if self._conditions._response is None:
506
+ raise ValueError('Condition is read only')
507
+ condition = fnv1.Condition()
508
+ condition.type = self.type
509
+ return self._conditions._response.conditions.append(condition)
510
+
511
+
512
+ class Connection:
513
+ def __init__(self, observed, desired=None):
514
+ self.__dict__['_observed'] = observed
515
+ self.__dict__['_desired'] = desired
516
+
517
+ def __bool__(self):
518
+ if self._desired is not None and len(self._desired.connection_details) > 0:
519
+ return True
520
+ if self._observed is not None and len(self._observed.connection_details) > 0:
521
+ return True
522
+ return False
523
+
524
+ def __getattr__(self, key):
525
+ return self[key]
526
+
527
+ def __getitem__(self, key):
528
+ value = None
529
+ if self._desired is not None and key in self._desired.connection_details:
530
+ value = self._desired.connection_details[key]
531
+ if value is None and key in self._observed.connection_details:
532
+ value = self._observed.connection_details[key]
533
+ return value
534
+
535
+ def __setattr__(self, key, value):
536
+ self[key] = value
537
+
538
+ def __setitem__(self, key, value):
539
+ if self._desired is None:
540
+ raise ValueError('Connection is read only')
541
+ self._desired.connection_details[key] = value
542
+
543
+
544
+ class Events:
545
+ def __init__(self, response):
546
+ self._results = response.results
547
+
548
+ def info(self, reason=_notset, message=_notset, claim=_notset):
549
+ event = Event(self._results.append())
550
+ event.info = True
551
+ if reason != _notset:
552
+ event.reason = reason
553
+ if message != _notset:
554
+ event.message = message
555
+ if claim != _notset:
556
+ event.claim = claim
557
+ return event
558
+
559
+ def warning(self, reason=_notset, message=_notset, claim=_notset):
560
+ event = Event(self._results.append())
561
+ event.warning = True
562
+ if reason != _notset:
563
+ event.reason = reason
564
+ if message != _notset:
565
+ event.message = message
566
+ if claim != _notset:
567
+ event.claim = claim
568
+ return event
569
+
570
+ def fatal(self, reason=_notset, message=_notset, claim=_notset):
571
+ event = Event(self._results.append())
572
+ event.fatal = True
573
+ if reason != _notset:
574
+ event.reason = reason
575
+ if message != _notset:
576
+ event.message = message
577
+ if claim != _notset:
578
+ event.claim = claim
579
+ return event
580
+
581
+ def __bool__(self):
582
+ return len(self) > 0
583
+
584
+ def __len__(self):
585
+ len(self._results)
586
+
587
+ def __getitem__(self, key):
588
+ if key >= len(self._results):
589
+ return Event()
590
+ return Event(self._results[ix])
591
+
592
+ def __iter__(self):
593
+ for ix in range(len(self._results)):
594
+ yield self[ix]
595
+
596
+
597
+ class Event:
598
+ def __init__(self, result=None):
599
+ self._result = result
600
+
601
+ def __bool__(self):
602
+ return self._result is not None
603
+
604
+ @property
605
+ def info(self):
606
+ return bool(self) and self._result.severity == fnv1.Severity.SEVERITY_NORMAL
607
+
608
+ @info.setter
609
+ def info(self, info):
610
+ if bool(self):
611
+ if info:
612
+ self._result.severity = fnv1.Severity.SEVERITY_NORMAL
613
+ else:
614
+ self._result.severity = fnv1.Severity.SEVERITY_UNSPECIFIED
615
+
616
+ @property
617
+ def warning(self):
618
+ return bool(self) and self._result.severity == fnv1.Severity.SEVERITY_WARNING
619
+
620
+ @warning.setter
621
+ def warning(self, warning):
622
+ if bool(self):
623
+ if warning:
624
+ self._result.severity = fnv1.Severity.SEVERITY_WARNING
625
+ else:
626
+ self._result.severity = fnv1.Severity.SEVERITY_NORMAL
627
+
628
+ @property
629
+ def fatal(self):
630
+ return bool(self) and self._result.severity == fnv1.Severity.SEVERITY_FATAL
631
+
632
+ @fatal.setter
633
+ def fatal(self, fatal):
634
+ if bool(self):
635
+ if fatal:
636
+ self._result.severity = fnv1.Severity.SEVERITY_FATAL
637
+ else:
638
+ self._result.severity = fnv1.Severity.SEVERITY_NORMAL
639
+
640
+ @property
641
+ def message(self):
642
+ return self._result.message if bool(self) else None
643
+
644
+ @message.setter
645
+ def message(self, message):
646
+ if bool(self):
647
+ self._result.message = message
648
+
649
+ @property
650
+ def reason(self):
651
+ return self._result.reason if bool(self) else None
652
+
653
+ @reason.setter
654
+ def reason(self, reason):
655
+ if bool(self):
656
+ self._result.reason = reason
657
+
658
+ @property
659
+ def claim(self):
660
+ return bool(self) and self._result == fnv1.Target.TARGET_COMPOSITE_AND_CLAIM
661
+
662
+ @claim.setter
663
+ def claim(self, claim):
664
+ if bool(self):
665
+ if claim:
666
+ self._result.target = fnv1.Target.TARGET_COMPOSITE_AND_CLAIM
667
+ elif claim == None or (isinstance(claim, protobuf.Values) and claim._isUnknown):
668
+ self._result.target = fnv1.Target.TARGET_UNSPECIFIED
669
+ else:
670
+ self._result.target = fnv1.Target.TARGET_COMPOSITE