crossplane-function-pythonic 0.4.2__py3-none-any.whl → 0.5.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/composite.py +2 -5
- crossplane/pythonic/function.py +5 -7
- crossplane/pythonic/protobuf.py +2 -0
- crossplane/pythonic/render.py +64 -74
- {crossplane_function_pythonic-0.4.2.dist-info → crossplane_function_pythonic-0.5.0.dist-info}/METADATA +68 -10
- crossplane_function_pythonic-0.5.0.dist-info/RECORD +18 -0
- {crossplane_function_pythonic-0.4.2.dist-info → crossplane_function_pythonic-0.5.0.dist-info}/WHEEL +1 -1
- crossplane_function_pythonic-0.4.2.dist-info/RECORD +0 -18
- {crossplane_function_pythonic-0.4.2.dist-info → crossplane_function_pythonic-0.5.0.dist-info}/entry_points.txt +0 -0
- {crossplane_function_pythonic-0.4.2.dist-info → crossplane_function_pythonic-0.5.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.5.0"
|
crossplane/pythonic/composite.py
CHANGED
|
@@ -89,7 +89,7 @@ class Ready:
|
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
class BaseComposite:
|
|
92
|
-
def __init__(self, crossplane_v1, request,
|
|
92
|
+
def __init__(self, crossplane_v1, request, logger):
|
|
93
93
|
self.crossplane_v1 = crossplane_v1
|
|
94
94
|
self.request = protobuf.Message(None, 'request', request.DESCRIPTOR, request, 'Function Request')
|
|
95
95
|
response = fnv1.RunFunctionResponse(
|
|
@@ -104,10 +104,7 @@ class BaseComposite:
|
|
|
104
104
|
)
|
|
105
105
|
self.response = protobuf.Message(None, 'response', response.DESCRIPTOR, response)
|
|
106
106
|
self.logger = logger
|
|
107
|
-
|
|
108
|
-
self.parameters = self.request.observed.composite.resource.spec.parameters
|
|
109
|
-
else:
|
|
110
|
-
self.parameters = self.request.input.parameters
|
|
107
|
+
self.parameters = self.request.input.parameters
|
|
111
108
|
self.credentials = Credentials(self.request)
|
|
112
109
|
self.context = self.response.context
|
|
113
110
|
self.environment = self.context['apiextensions.crossplane.io/environment']
|
crossplane/pythonic/function.py
CHANGED
|
@@ -48,15 +48,13 @@ class FunctionRunner(grpcv1.FunctionRunnerService):
|
|
|
48
48
|
name.append(composite['metadata']['name'])
|
|
49
49
|
logger = logging.getLogger('.'.join(name))
|
|
50
50
|
|
|
51
|
-
if
|
|
52
|
-
if 'spec' not in composite or '
|
|
53
|
-
return self.fatal(request, logger,
|
|
54
|
-
|
|
55
|
-
composite = composite['spec']['composite']
|
|
51
|
+
if 'inlined' in request.input and request.input['inlined']:
|
|
52
|
+
if 'spec' not in composite or request.input['inlined'] not in composite['spec']:
|
|
53
|
+
return self.fatal(request, logger, f"Missing inlined spec.{request.input['inlined']}")
|
|
54
|
+
composite = composite['spec'][request.input['inlined']]
|
|
56
55
|
else:
|
|
57
56
|
if 'composite' not in request.input:
|
|
58
57
|
return self.fatal(request, logger, 'Missing input "composite"')
|
|
59
|
-
single_use = False
|
|
60
58
|
composite = request.input['composite']
|
|
61
59
|
|
|
62
60
|
# Ideally this is something the Function API provides
|
|
@@ -100,7 +98,7 @@ class FunctionRunner(grpcv1.FunctionRunnerService):
|
|
|
100
98
|
self.clazzes[composite] = clazz
|
|
101
99
|
|
|
102
100
|
try:
|
|
103
|
-
composite = clazz(self.crossplane_v1, request,
|
|
101
|
+
composite = clazz(self.crossplane_v1, request, logger)
|
|
104
102
|
except Exception as e:
|
|
105
103
|
return self.fatal(request, logger, 'Instantiate', e)
|
|
106
104
|
|
crossplane/pythonic/protobuf.py
CHANGED
|
@@ -796,8 +796,10 @@ class Value:
|
|
|
796
796
|
def __contains__(self, item):
|
|
797
797
|
match self._kind:
|
|
798
798
|
case 'struct_value':
|
|
799
|
+
item = self._validate_key(item)
|
|
799
800
|
return item in self._value.struct_value.fields or item in self._unknowns
|
|
800
801
|
case 'Struct':
|
|
802
|
+
item = self._validate_key(item)
|
|
801
803
|
return item in self._value.fields or item in self._unknowns
|
|
802
804
|
case 'list_value' | 'ListValue':
|
|
803
805
|
for value in self:
|
crossplane/pythonic/render.py
CHANGED
|
@@ -3,6 +3,7 @@ import asyncio
|
|
|
3
3
|
import importlib
|
|
4
4
|
import inflect
|
|
5
5
|
import inspect
|
|
6
|
+
import kr8s
|
|
6
7
|
import logging
|
|
7
8
|
import pathlib
|
|
8
9
|
import sys
|
|
@@ -16,6 +17,9 @@ from . import (
|
|
|
16
17
|
protobuf,
|
|
17
18
|
)
|
|
18
19
|
|
|
20
|
+
INFLECT = inflect.engine()
|
|
21
|
+
INFLECT.classical(all=False)
|
|
22
|
+
|
|
19
23
|
|
|
20
24
|
class Command(command.Command):
|
|
21
25
|
name = 'render'
|
|
@@ -54,7 +58,7 @@ class Command(command.Command):
|
|
|
54
58
|
action='append',
|
|
55
59
|
default=[],
|
|
56
60
|
metavar='KEY=VALUE',
|
|
57
|
-
help='Context key-value pairs to pass to the Function pipeline. Values must be
|
|
61
|
+
help='Context key-value pairs to pass to the Function pipeline. Values must be sYAML/JSON. Keys take precedence over --context-files.',
|
|
58
62
|
)
|
|
59
63
|
parser.add_argument(
|
|
60
64
|
'--observed-resources', '-o',
|
|
@@ -108,18 +112,18 @@ class Command(command.Command):
|
|
|
108
112
|
|
|
109
113
|
async def run(self):
|
|
110
114
|
if self.args.kube_context:
|
|
111
|
-
|
|
115
|
+
api = await kr8s.asyncio.api(context=self.args.kube_context)
|
|
112
116
|
else:
|
|
113
|
-
|
|
114
|
-
composite = await self.setup_composite(
|
|
117
|
+
api = None
|
|
118
|
+
composite = await self.setup_composite(api)
|
|
115
119
|
observed = self.collect_resources(self.args.observed_resources)
|
|
116
|
-
composition = await self.setup_composition(composite,
|
|
120
|
+
composition = await self.setup_composition(composite, api)
|
|
117
121
|
resources = self.collect_resources(self.args.required_resources)
|
|
118
122
|
resources += self.collect_resources(self.args.secret_store)
|
|
119
123
|
resources.sort(key=lambda resource: str(resource.metadata.name))
|
|
120
124
|
context = self.setup_context()
|
|
121
125
|
|
|
122
|
-
render = await self.render(composite, observed, composition, resources, context,
|
|
126
|
+
render = await self.render(composite, observed, composition, resources, context, api, self.args.render_unknowns, self.args.crossplane_v1)
|
|
123
127
|
if not render:
|
|
124
128
|
sys.exit(1)
|
|
125
129
|
|
|
@@ -154,11 +158,11 @@ class Command(command.Command):
|
|
|
154
158
|
print('---')
|
|
155
159
|
print(str(render.context), end='')
|
|
156
160
|
|
|
157
|
-
async def setup_composite(self,
|
|
161
|
+
async def setup_composite(self, api=None):
|
|
158
162
|
# Obtain the Composite to render.
|
|
159
163
|
if self.args.composite.is_file():
|
|
160
164
|
return protobuf.Yaml(self.args.composite.read_text())
|
|
161
|
-
if not
|
|
165
|
+
if not api:
|
|
162
166
|
print(f"Composite \"{self.args.composite}\" is not a file", file=sys.stderr)
|
|
163
167
|
sys.exit(1)
|
|
164
168
|
composite = str(self.args.composite).split(':')
|
|
@@ -172,13 +176,13 @@ class Command(command.Command):
|
|
|
172
176
|
else:
|
|
173
177
|
print(f"Composite \"{self.args.composite}\" is not kind:apiVersion:namespace:name", file=sys.stderr)
|
|
174
178
|
sys.exit(1)
|
|
175
|
-
composite = await
|
|
179
|
+
composite = await self.kr8s_get(api, composite[0], composite[1], namespace, composite[-1])
|
|
176
180
|
if not composite:
|
|
177
181
|
print(f"Composite \"{self.args.composite}\" not found", file=sys.stderr)
|
|
178
182
|
sys.exit(1)
|
|
179
183
|
return composite
|
|
180
184
|
|
|
181
|
-
async def setup_composition(self, composite,
|
|
185
|
+
async def setup_composition(self, composite, api=None):
|
|
182
186
|
# Obtain the Composition that will be used to render the Composite.
|
|
183
187
|
if not self.args.composition:
|
|
184
188
|
return None
|
|
@@ -265,35 +269,35 @@ class Command(command.Command):
|
|
|
265
269
|
context[key_value[0]] = protobuf.Yaml(key_value[1])
|
|
266
270
|
return context
|
|
267
271
|
|
|
268
|
-
async def render(self, composite, observed=[], composition=None, resources=[], context=None,
|
|
272
|
+
async def render(self, composite, observed=[], composition=None, resources=[], context=None, api=None, render_unknowns=False, crossplane_v1=False, composite_observeds=True):
|
|
269
273
|
# Create the request used when running Composition steps.
|
|
270
274
|
request = protobuf.Message(None, 'request', fnv1.RunFunctionRequest.DESCRIPTOR, fnv1.RunFunctionRequest())
|
|
271
275
|
if context is not None:
|
|
272
276
|
request.context = context
|
|
273
277
|
|
|
274
278
|
# Establish the request observed composite.
|
|
275
|
-
await self.set_resource(composite, request.observed.composite, resources,
|
|
279
|
+
await self.set_resource(composite, request.observed.composite, resources, api)
|
|
276
280
|
# Establish the manually configured observed resources.
|
|
277
281
|
if observed:
|
|
278
282
|
async with asyncio.TaskGroup() as group:
|
|
279
283
|
for resource in observed:
|
|
280
284
|
name = resource.metadata.annotations['crossplane.io/composition-resource-name']
|
|
281
285
|
if name:
|
|
282
|
-
group.create_task(self.set_resource(resource, request.observed.resources[name], resources,
|
|
283
|
-
if
|
|
286
|
+
group.create_task(self.set_resource(resource, request.observed.resources[name], resources, api))
|
|
287
|
+
if api and composite_observeds:
|
|
284
288
|
refs = composite.spec.crossplane.resourceRefs
|
|
285
289
|
if not refs:
|
|
286
290
|
refs = composite.spec.resourceRefs
|
|
287
291
|
if refs:
|
|
288
292
|
async with asyncio.TaskGroup() as group:
|
|
289
293
|
for ref in refs:
|
|
290
|
-
group.create_task(self.get_composite_ref(composite, ref, request, resources,
|
|
294
|
+
group.create_task(self.get_composite_ref(composite, ref, request, resources, api))
|
|
291
295
|
|
|
292
296
|
if not composition:
|
|
293
297
|
if composite.apiVersion in ('pythonic.crossplane.io/v1alpha1', 'pythonic.fortra.com/v1alpha1') and composite.kind == 'Composite':
|
|
294
298
|
composition = self.create_composition(composite)
|
|
295
299
|
else:
|
|
296
|
-
if not
|
|
300
|
+
if not api:
|
|
297
301
|
print('"composition" required', file=sys.stderr)
|
|
298
302
|
return None
|
|
299
303
|
revision = composite.spec.crossplane.compositionRevisionRef
|
|
@@ -303,7 +307,7 @@ class Command(command.Command):
|
|
|
303
307
|
if not revision.name:
|
|
304
308
|
print('Composite does not contain a CompositionRevision name', file=sys.stderr)
|
|
305
309
|
return None
|
|
306
|
-
composition = await
|
|
310
|
+
composition = await self.kr8s_get(api, 'CompositionRevision', 'apiextensions.crossplane.io/v1', None, revision.name)
|
|
307
311
|
if not composition:
|
|
308
312
|
print(f"Compositioin \"{revision.name}\" not found", file=sys.stderr)
|
|
309
313
|
return None
|
|
@@ -350,14 +354,14 @@ class Command(command.Command):
|
|
|
350
354
|
# Fetch the step bootstrap resources specified.
|
|
351
355
|
request.required_resources()
|
|
352
356
|
for requirement in step.requirements.requiredResources:
|
|
353
|
-
await self.set_required(requirement.requirementName, requirement, request.required_resources, resources,
|
|
357
|
+
await self.set_required(requirement.requirementName, requirement, request.required_resources, resources, api)
|
|
354
358
|
# Fetch the required resources requested.
|
|
355
359
|
for name, selector in requirements.resources:
|
|
356
|
-
await self.set_required(name, selector, request.required_resources, resources,
|
|
360
|
+
await self.set_required(name, selector, request.required_resources, resources, api)
|
|
357
361
|
# Fetch the now deprecated extra resources requested.
|
|
358
362
|
request.extra_resources()
|
|
359
363
|
for name, selector in requirements.extra_resources:
|
|
360
|
-
await self.set_required(name, selector, request.extra_resources, resources,
|
|
364
|
+
await self.set_required(name, selector, request.extra_resources, resources, api)
|
|
361
365
|
# Run the step using the function-pythonic function runner.
|
|
362
366
|
response = protobuf.Message(
|
|
363
367
|
None,
|
|
@@ -365,13 +369,15 @@ class Command(command.Command):
|
|
|
365
369
|
fnv1.RunFunctionResponse.DESCRIPTOR,
|
|
366
370
|
await runner.RunFunction(request._message, None),
|
|
367
371
|
)
|
|
372
|
+
# Copy the response context to the request context to use in subsequent steps.
|
|
373
|
+
request.context = response.context
|
|
368
374
|
# All done if there is a fatal result.
|
|
369
375
|
for result in response.results:
|
|
370
376
|
if result.severity == fnv1.Severity.SEVERITY_FATAL:
|
|
371
377
|
fatal = True
|
|
372
378
|
break
|
|
373
|
-
|
|
374
|
-
|
|
379
|
+
if fatal:
|
|
380
|
+
break
|
|
375
381
|
# Exit this loop if the function has not requested additional extra/required resources.
|
|
376
382
|
if response.requirements == requirements:
|
|
377
383
|
break
|
|
@@ -479,21 +485,21 @@ class Command(command.Command):
|
|
|
479
485
|
),
|
|
480
486
|
)
|
|
481
487
|
|
|
482
|
-
async def get_composite_ref(self, composite, ref, request, resources,
|
|
488
|
+
async def get_composite_ref(self, composite, ref, request, resources, api):
|
|
483
489
|
namespace = ref.namespace
|
|
484
490
|
if not namespace:
|
|
485
491
|
namespace = composite.metadata.namespace
|
|
486
492
|
if not namespace:
|
|
487
493
|
namespace = None
|
|
488
|
-
source = await
|
|
494
|
+
source = await self.kr8s_get(api, ref.kind, ref.apiVersion, namespace, ref.name)
|
|
489
495
|
if source:
|
|
490
496
|
name = source.metadata.annotations['crossplane.io/composition-resource-name']
|
|
491
497
|
if name:
|
|
492
498
|
destination = request.observed.resources[name]
|
|
493
499
|
if not destination: # Do not override manual observed
|
|
494
|
-
await self.set_resource(source, destination, resources,
|
|
500
|
+
await self.set_resource(source, destination, resources, api)
|
|
495
501
|
|
|
496
|
-
async def set_required(self, name, selector, requireds, resources=[],
|
|
502
|
+
async def set_required(self, name, selector, requireds, resources=[], api=None):
|
|
497
503
|
if not name:
|
|
498
504
|
return
|
|
499
505
|
name = str(name)
|
|
@@ -505,23 +511,23 @@ class Command(command.Command):
|
|
|
505
511
|
or (selector.namespace == resource.metadata.namespace)
|
|
506
512
|
):
|
|
507
513
|
if selector.match_name == resource.metadata.name:
|
|
508
|
-
await self.set_resource(resource, items[protobuf.append], resources,
|
|
514
|
+
await self.set_resource(resource, items[protobuf.append], resources, api)
|
|
509
515
|
elif selector.match_labels.labels:
|
|
510
516
|
for key, value in selector.match_labels.labels:
|
|
511
517
|
if value != resource.metadata.labels[key]:
|
|
512
518
|
break
|
|
513
519
|
else:
|
|
514
|
-
await self.set_resource(resource, items[protobuf.append], resources,
|
|
515
|
-
if not len(items) and
|
|
520
|
+
await self.set_resource(resource, items[protobuf.append], resources, api)
|
|
521
|
+
if not len(items) and api:
|
|
516
522
|
if len(selector.match_name):
|
|
517
|
-
resource = await
|
|
523
|
+
resource = await self.kr8s_get(api, selector.kind, selector.api_version, selector.namespace, selector.match_name)
|
|
518
524
|
if resource:
|
|
519
|
-
await self.set_resource(resource, items[protobuf.append], resources,
|
|
525
|
+
await self.set_resource(resource, items[protobuf.append], resources, api)
|
|
520
526
|
elif len(selector.match_labels.labels):
|
|
521
|
-
for resource in await
|
|
522
|
-
await self.set_resource(resource, items[protobuf.append], resources,
|
|
527
|
+
for resource in await self.kr8s_list(api, selector.kind, selector.api_version, selector.namespace, selector.match_labels.labels):
|
|
528
|
+
await self.set_resource(resource, items[protobuf.append], resources, api)
|
|
523
529
|
|
|
524
|
-
async def set_resource(self, source, destination, resources=[],
|
|
530
|
+
async def set_resource(self, source, destination, resources=[], api=None):
|
|
525
531
|
destination.resource = source
|
|
526
532
|
namespace = source.spec.writeConnectionSecretToRef.namespace or source.metadata.namespace
|
|
527
533
|
name = source.spec.writeConnectionSecretToRef.name
|
|
@@ -533,8 +539,8 @@ class Command(command.Command):
|
|
|
533
539
|
connection = resource
|
|
534
540
|
break
|
|
535
541
|
else:
|
|
536
|
-
if
|
|
537
|
-
connection = await
|
|
542
|
+
if api:
|
|
543
|
+
connection = await self.kr8s_get(api, 'Secret', 'v1', namespace, name)
|
|
538
544
|
if connection:
|
|
539
545
|
destination.connection_details()
|
|
540
546
|
for key, value in connection.data:
|
|
@@ -572,69 +578,53 @@ class Command(command.Command):
|
|
|
572
578
|
condition['message'] = message
|
|
573
579
|
return condition
|
|
574
580
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
self.kr8s = importlib.import_module('kr8s')
|
|
579
|
-
self.inflect = inflect.engine()
|
|
580
|
-
self.inflect.classical(all=False)
|
|
581
|
-
self.context = context
|
|
582
|
-
self.logger = logger
|
|
583
|
-
self._api = None
|
|
584
|
-
|
|
585
|
-
async def api(self):
|
|
586
|
-
if not self._api:
|
|
587
|
-
self._api = await self.kr8s.asyncio.api(context=self.context)
|
|
588
|
-
return self._api
|
|
589
|
-
|
|
590
|
-
async def get(self, kind, apiVersion, namespace, name):
|
|
591
|
-
clazz = self._get_clazz(kind, apiVersion, namespace)
|
|
581
|
+
async def kr8s_get(self, api, kind, apiVersion, namespace, name):
|
|
582
|
+
namespaced = namespace and len(namespace)
|
|
583
|
+
clazz = self.kr8s_class(kind, apiVersion, namespaced)
|
|
592
584
|
try:
|
|
593
585
|
fullName = [str(kind), str(apiVersion), str(name)]
|
|
594
|
-
if
|
|
586
|
+
if namespaced:
|
|
595
587
|
fullName.insert(-1, str(namespace))
|
|
596
|
-
resource = await clazz.get(str(name), namespace=str(namespace), api=
|
|
588
|
+
resource = await clazz.get(str(name), namespace=str(namespace), api=api)
|
|
597
589
|
else:
|
|
598
|
-
resource = await clazz.get(str(name), api=
|
|
590
|
+
resource = await clazz.get(str(name), api=api)
|
|
599
591
|
resource = protobuf.Value(None, None, resource.raw)
|
|
600
592
|
result = 'found'
|
|
601
|
-
except
|
|
593
|
+
except kr8s.NotFoundError:
|
|
602
594
|
resource = None
|
|
603
595
|
result = 'missing'
|
|
604
|
-
|
|
605
|
-
self.logger.debug(f"Resource {result}: {':'.join(fullName)}")
|
|
596
|
+
self.logger.debug(f"Resource {result}: {':'.join(fullName)}")
|
|
606
597
|
return resource
|
|
607
598
|
|
|
608
|
-
async def
|
|
609
|
-
|
|
599
|
+
async def kr8s_list(self, api, kind, apiVersion, namespace, labelSelector):
|
|
600
|
+
namespaced = namespace and len(namespace)
|
|
601
|
+
clazz = self.kr8s_class(kind, apiVersion, namespaced)
|
|
610
602
|
resources = [
|
|
611
603
|
protobuf.Value(None, None, resource.raw)
|
|
612
604
|
async for resource in clazz.list(
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
605
|
+
namespace=str(namespace) if namespaced else None,
|
|
606
|
+
label_selector={
|
|
607
|
+
label: str(value)
|
|
608
|
+
for label, value in labelSelector
|
|
609
|
+
},
|
|
610
|
+
api=api,
|
|
619
611
|
)
|
|
620
612
|
]
|
|
621
613
|
if self.logger.isEnabledFor(logging.DEBUG):
|
|
622
614
|
fullName = [str(kind), str(apiVersion)]
|
|
623
|
-
if
|
|
615
|
+
if namespaced:
|
|
624
616
|
fullName.append(str(namespace))
|
|
625
617
|
fullName.append('&'.join(f"{label}={value}" for label, value in labelSelector))
|
|
626
618
|
if resources:
|
|
627
|
-
result = f"found {
|
|
619
|
+
result = f"found {INFLECT.number_to_words(len(resources))}"
|
|
628
620
|
else:
|
|
629
621
|
result = 'missing'
|
|
630
622
|
self.logger.debug(f"Resources {result}: {':'.join(fullName)}")
|
|
631
623
|
return resources
|
|
632
624
|
|
|
633
|
-
def
|
|
634
|
-
kind = str(kind)
|
|
635
|
-
apiVersion = str(apiVersion)
|
|
625
|
+
def kr8s_class(self, kind, apiVersion, namespaced):
|
|
636
626
|
try:
|
|
637
|
-
return
|
|
627
|
+
return kr8s.asyncio.objects.get_class(str(kind), str(apiVersion), True)
|
|
638
628
|
except KeyError:
|
|
639
629
|
pass
|
|
640
|
-
return
|
|
630
|
+
return kr8s.asyncio.objects.new_class(str(kind), str(apiVersion), True, namespaced, plural=INFLECT.plural_noun(str(kind)).lower())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crossplane-function-pythonic
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: A Python centric Crossplane Function
|
|
5
5
|
Project-URL: Documentation, https://github.com/crossplane-contrib/function-pythonic#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/crossplane-contrib/function-pythonic/issues
|
|
@@ -199,6 +199,11 @@ subnet.spec.forProvider.cidrBlock = '10.0.0.0/20'
|
|
|
199
199
|
```
|
|
200
200
|
Will generate the appropriate Crossplane Usage resource.
|
|
201
201
|
|
|
202
|
+
## API Documentation
|
|
203
|
+
|
|
204
|
+
- [Composite API (`composite.py`)](https://github.com/crossplane-contrib/function-pythonic/blob/main/docs/composite.md)
|
|
205
|
+
- [Protobuf Wrapper API (`protobuf.py`)](https://github.com/crossplane-contrib/function-pythonic/blob/main/docs/protobuf.md)
|
|
206
|
+
|
|
202
207
|
## Pythonic access of Protobuf Messages
|
|
203
208
|
|
|
204
209
|
All Protobuf messages are wrapped by a set of python classes which enable using
|
|
@@ -406,25 +411,78 @@ optionally to the Claim.
|
|
|
406
411
|
| Result.message | String | Human-readable details about the result |
|
|
407
412
|
| Result.claim | Boolean | Also apply the result to the claim |
|
|
408
413
|
|
|
409
|
-
##
|
|
414
|
+
## Inlined Composites
|
|
410
415
|
|
|
411
416
|
Tired of creating a CompositeResourceDefinition, a Composition, and a Composite
|
|
412
|
-
just to run that Composition once in a
|
|
417
|
+
just to run that Composition once in a setup or initialize task?
|
|
413
418
|
|
|
414
|
-
function-pythonic
|
|
415
|
-
|
|
419
|
+
function-pythonic supports "inlined" Compositions, where the python module
|
|
420
|
+
is obtained from a field in the Composite's spec.
|
|
416
421
|
```yaml
|
|
417
|
-
apiVersion:
|
|
418
|
-
kind:
|
|
422
|
+
apiVersion: inlined.example.org/v1alpha1
|
|
423
|
+
kind: Step
|
|
419
424
|
metadata:
|
|
420
|
-
name:
|
|
425
|
+
name: inlined-example
|
|
421
426
|
spec:
|
|
422
427
|
composite: |
|
|
423
428
|
class HelloComposite(BaseComposite):
|
|
424
429
|
def compose(self):
|
|
425
|
-
self.status.
|
|
430
|
+
self.status.step = 'Hello, World!'
|
|
431
|
+
```
|
|
432
|
+
The CompositeResourceDefinition and Composition to support the above example:
|
|
433
|
+
```yaml
|
|
434
|
+
apiVersion: apiextensions.crossplane.io/v1
|
|
435
|
+
kind: CompositeResourceDefinition
|
|
436
|
+
metadata:
|
|
437
|
+
name: inlined.example.org/v1alpha1
|
|
438
|
+
spec:
|
|
439
|
+
group: inlined.example.org
|
|
440
|
+
names:
|
|
441
|
+
kind: Step
|
|
442
|
+
plural: steps
|
|
443
|
+
defaultCompositionRef:
|
|
444
|
+
name: steps.inlined.example.org
|
|
445
|
+
versions:
|
|
446
|
+
- name: v1alpha1
|
|
447
|
+
served: true
|
|
448
|
+
referenceable: true
|
|
449
|
+
schema:
|
|
450
|
+
openAPIV3Schema:
|
|
451
|
+
type: object
|
|
452
|
+
properties:
|
|
453
|
+
spec:
|
|
454
|
+
type: object
|
|
455
|
+
properties:
|
|
456
|
+
composite:
|
|
457
|
+
type: string
|
|
458
|
+
description: 'A Python module that defines a class with the signature: class Composite(BaseComposite)'
|
|
459
|
+
required:
|
|
460
|
+
- composite
|
|
461
|
+
status:
|
|
462
|
+
type: object
|
|
463
|
+
properties:
|
|
464
|
+
composite:
|
|
465
|
+
x-kubernetes-preserve-unknown-fields: true
|
|
466
|
+
```
|
|
467
|
+
```yaml
|
|
468
|
+
apiVersion: apiextensions.crossplane.io/v1
|
|
469
|
+
kind: Composition
|
|
470
|
+
metadata:
|
|
471
|
+
name: steps.inlined.example.org
|
|
472
|
+
spec:
|
|
473
|
+
compositeTypeRef:
|
|
474
|
+
apiVersion: inlined.example.org/v1alpha1
|
|
475
|
+
kind: Step
|
|
476
|
+
mode: Pipeline
|
|
477
|
+
pipeline:
|
|
478
|
+
- step: inlined
|
|
479
|
+
functionRef:
|
|
480
|
+
name: function-pythonic
|
|
481
|
+
input:
|
|
482
|
+
apiVersion: pythonic.fn.crossplane.io/v1alpha1
|
|
483
|
+
kind: Composite
|
|
484
|
+
inlined: composite
|
|
426
485
|
```
|
|
427
|
-
|
|
428
486
|
## Quick Start Development
|
|
429
487
|
|
|
430
488
|
function-pythonic includes a pure python implementation of the `crossplane render ...`
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
crossplane/pythonic/__about__.py,sha256=S3lIpABQ5LwPMuO5TLfDrT_eJOQtFzsph4TXcfnx4OY,73
|
|
2
|
+
crossplane/pythonic/__init__.py,sha256=cRk12kc18RLhc9s5dW6sQqZSCEp80fooRO5zxXqc1oA,292
|
|
3
|
+
crossplane/pythonic/__main__.py,sha256=6vYRlYDJtqFgLyiTamnl3htiNOtz8QlDl5WlIP98I8o,31
|
|
4
|
+
crossplane/pythonic/auto_ready.py,sha256=sPetUuJRhwZbg9muaDmbdqmtTIIUDmY4qoadoJA0EtQ,7201
|
|
5
|
+
crossplane/pythonic/command.py,sha256=aT58WBrhU_scaOGeqmsBfofIDnXyW1CQOpCktVGBj5s,4211
|
|
6
|
+
crossplane/pythonic/composite.py,sha256=niq-JSVZ8NB53Q7khkMqH9vQTJPb6yB-13O-wa2Is1U,30311
|
|
7
|
+
crossplane/pythonic/function.py,sha256=CL2j_Br0eYWbn_8r8md9O9ErfHizz78H1KR8l2oV1IA,17964
|
|
8
|
+
crossplane/pythonic/grpc.py,sha256=9ZQceboDju37NB6AhcUSWpBx_hZQ5W7uo7CZF6ynhfI,4451
|
|
9
|
+
crossplane/pythonic/main.py,sha256=ujUa_FYElQSGqnhZ-0NJrD3kSyYjfRbIp79FV2Yl7hs,599
|
|
10
|
+
crossplane/pythonic/packages.py,sha256=4TxyT6V79R0m4tJbC8R1gwU_vgHGLXKSBzeTTKd8xGo,5120
|
|
11
|
+
crossplane/pythonic/protobuf.py,sha256=nmVf-Xn_-ER8BEfEbqd8uQo2gdhmNYyQh9QlhcaYebs,53083
|
|
12
|
+
crossplane/pythonic/render.py,sha256=Y1-fdjQxvPBSkGjfJnNwCOOg6I-bX7Ys9X4jXkqIZp4,30140
|
|
13
|
+
crossplane/pythonic/version.py,sha256=-RiB0p146ayqJj0SXfYxTNv49u9Fx9pPgm59Ji2blhc,214
|
|
14
|
+
crossplane_function_pythonic-0.5.0.dist-info/METADATA,sha256=yMVu_bg-pjIrhuHDjeTAmKEa082V2pq5NroKIeo9poI,33133
|
|
15
|
+
crossplane_function_pythonic-0.5.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
16
|
+
crossplane_function_pythonic-0.5.0.dist-info/entry_points.txt,sha256=jJ4baywFDviB9WyAhyhNYF2VOCb6XtbRSjKf7bnBwhg,68
|
|
17
|
+
crossplane_function_pythonic-0.5.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
18
|
+
crossplane_function_pythonic-0.5.0.dist-info/RECORD,,
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
crossplane/pythonic/__about__.py,sha256=6nxRspkiSsLkBLqHh-X--3FLozkQy1xfr-6ZG0LORbs,73
|
|
2
|
-
crossplane/pythonic/__init__.py,sha256=cRk12kc18RLhc9s5dW6sQqZSCEp80fooRO5zxXqc1oA,292
|
|
3
|
-
crossplane/pythonic/__main__.py,sha256=6vYRlYDJtqFgLyiTamnl3htiNOtz8QlDl5WlIP98I8o,31
|
|
4
|
-
crossplane/pythonic/auto_ready.py,sha256=sPetUuJRhwZbg9muaDmbdqmtTIIUDmY4qoadoJA0EtQ,7201
|
|
5
|
-
crossplane/pythonic/command.py,sha256=aT58WBrhU_scaOGeqmsBfofIDnXyW1CQOpCktVGBj5s,4211
|
|
6
|
-
crossplane/pythonic/composite.py,sha256=f9SYjtXVqRx7vse7nQ06Ic6EnnfCYVtpoOmBhR9Jv6g,30451
|
|
7
|
-
crossplane/pythonic/function.py,sha256=uILb3XICcWi2JA5W1xuq37nFQA3_TqbdJefo0-gUUNI,18063
|
|
8
|
-
crossplane/pythonic/grpc.py,sha256=9ZQceboDju37NB6AhcUSWpBx_hZQ5W7uo7CZF6ynhfI,4451
|
|
9
|
-
crossplane/pythonic/main.py,sha256=ujUa_FYElQSGqnhZ-0NJrD3kSyYjfRbIp79FV2Yl7hs,599
|
|
10
|
-
crossplane/pythonic/packages.py,sha256=4TxyT6V79R0m4tJbC8R1gwU_vgHGLXKSBzeTTKd8xGo,5120
|
|
11
|
-
crossplane/pythonic/protobuf.py,sha256=YcKqH0Y4Vj63m6pUb1ptL4gIKcdNLU-WR8TaQ5eGW-M,52987
|
|
12
|
-
crossplane/pythonic/render.py,sha256=e_WQF5TlemfsZim2oGkTPAWuU6BDJztexJ9iBbuFQbo,30417
|
|
13
|
-
crossplane/pythonic/version.py,sha256=-RiB0p146ayqJj0SXfYxTNv49u9Fx9pPgm59Ji2blhc,214
|
|
14
|
-
crossplane_function_pythonic-0.4.2.dist-info/METADATA,sha256=KemrVxbVM4-B6I1P-Gq3hDdqE67sPMCRyfu9gjBY4_w,31561
|
|
15
|
-
crossplane_function_pythonic-0.4.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
16
|
-
crossplane_function_pythonic-0.4.2.dist-info/entry_points.txt,sha256=jJ4baywFDviB9WyAhyhNYF2VOCb6XtbRSjKf7bnBwhg,68
|
|
17
|
-
crossplane_function_pythonic-0.4.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
18
|
-
crossplane_function_pythonic-0.4.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|