crossplane-function-pythonic 0.4.2__py3-none-any.whl → 0.6.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 +154 -5
- crossplane/pythonic/function.py +24 -11
- crossplane/pythonic/grpc.py +24 -3
- crossplane/pythonic/packages.py +128 -96
- crossplane/pythonic/protobuf.py +4 -0
- crossplane/pythonic/render.py +165 -79
- {crossplane_function_pythonic-0.4.2.dist-info → crossplane_function_pythonic-0.6.0.dist-info}/METADATA +179 -25
- crossplane_function_pythonic-0.6.0.dist-info/RECORD +18 -0
- {crossplane_function_pythonic-0.4.2.dist-info → crossplane_function_pythonic-0.6.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.6.0.dist-info}/entry_points.txt +0 -0
- {crossplane_function_pythonic-0.4.2.dist-info → crossplane_function_pythonic-0.6.0.dist-info}/licenses/LICENSE +0 -0
crossplane/pythonic/render.py
CHANGED
|
@@ -3,6 +3,8 @@ import asyncio
|
|
|
3
3
|
import importlib
|
|
4
4
|
import inflect
|
|
5
5
|
import inspect
|
|
6
|
+
import json
|
|
7
|
+
import kr8s
|
|
6
8
|
import logging
|
|
7
9
|
import pathlib
|
|
8
10
|
import sys
|
|
@@ -11,10 +13,13 @@ from crossplane.function.proto.v1 import run_function_pb2 as fnv1
|
|
|
11
13
|
|
|
12
14
|
from . import (
|
|
13
15
|
command,
|
|
14
|
-
composite,
|
|
15
16
|
function,
|
|
16
17
|
protobuf,
|
|
17
18
|
)
|
|
19
|
+
from .composite import BaseComposite
|
|
20
|
+
|
|
21
|
+
INFLECT = inflect.engine()
|
|
22
|
+
INFLECT.classical(all=False)
|
|
18
23
|
|
|
19
24
|
|
|
20
25
|
class Command(command.Command):
|
|
@@ -73,12 +78,12 @@ class Command(command.Command):
|
|
|
73
78
|
help='A YAML file or directory of YAML files specifying required resources to pass to the Function pipeline.',
|
|
74
79
|
)
|
|
75
80
|
parser.add_argument(
|
|
76
|
-
'--
|
|
81
|
+
'--required-schemas', '-s',
|
|
77
82
|
action='append',
|
|
78
83
|
type=pathlib.Path,
|
|
79
84
|
default=[],
|
|
80
85
|
metavar='PATH',
|
|
81
|
-
help='A
|
|
86
|
+
help='A JSON file or directory of JSON files specifying required schemas to pass to the Function pipeline.',
|
|
82
87
|
)
|
|
83
88
|
parser.add_argument(
|
|
84
89
|
'--include-full-xr', '-x',
|
|
@@ -108,18 +113,17 @@ class Command(command.Command):
|
|
|
108
113
|
|
|
109
114
|
async def run(self):
|
|
110
115
|
if self.args.kube_context:
|
|
111
|
-
|
|
116
|
+
api = await kr8s.asyncio.api(context=self.args.kube_context)
|
|
112
117
|
else:
|
|
113
|
-
|
|
114
|
-
composite = await self.setup_composite(
|
|
118
|
+
api = None
|
|
119
|
+
composite = await self.setup_composite(api)
|
|
115
120
|
observed = self.collect_resources(self.args.observed_resources)
|
|
116
|
-
composition = await self.setup_composition(composite,
|
|
121
|
+
composition = await self.setup_composition(composite, api)
|
|
117
122
|
resources = self.collect_resources(self.args.required_resources)
|
|
118
|
-
|
|
119
|
-
resources.sort(key=lambda resource: str(resource.metadata.name))
|
|
123
|
+
schemas = self.collect_schemas(self.args.required_schemas)
|
|
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, schemas, 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
|
|
@@ -208,7 +212,7 @@ class Command(command.Command):
|
|
|
208
212
|
if not inspect.isclass(clazz):
|
|
209
213
|
print(f"Composition class {self.args.composition} is not a class", file=sys.stderr)
|
|
210
214
|
sys.exit(1)
|
|
211
|
-
if not issubclass(clazz,
|
|
215
|
+
if not issubclass(clazz, BaseComposite):
|
|
212
216
|
print(f"Composition class {self.args.composition} is not a subclass of BaseComposite", file=sys.stderr)
|
|
213
217
|
sys.exit(1)
|
|
214
218
|
return self.create_composition(composite, self.args.composition)
|
|
@@ -242,8 +246,25 @@ class Command(command.Command):
|
|
|
242
246
|
else:
|
|
243
247
|
print(f"Specified resource is not a file or a directory: {entry}", file=sys.stderr)
|
|
244
248
|
sys.exit(1)
|
|
249
|
+
resources.sort(key=lambda resource: str(resource.metadata.name))
|
|
245
250
|
return resources
|
|
246
251
|
|
|
252
|
+
def collect_schemas(self, entries):
|
|
253
|
+
schemas = []
|
|
254
|
+
for entry in entries:
|
|
255
|
+
if entry.is_file():
|
|
256
|
+
document = json.loads(entry.read_text())
|
|
257
|
+
schemas.append(protobuf.Value(None, None, document))
|
|
258
|
+
elif entry.is_dir():
|
|
259
|
+
for file in entry.iterdir():
|
|
260
|
+
if file.suffix == '.json':
|
|
261
|
+
document = json.loads(file.read_text())
|
|
262
|
+
schemas.append(protobuf.Value(None, None, document))
|
|
263
|
+
else:
|
|
264
|
+
print(f"Specified resource is not a file or a directory: {entry}", file=sys.stderr)
|
|
265
|
+
sys.exit(1)
|
|
266
|
+
return schemas
|
|
267
|
+
|
|
247
268
|
def setup_context(self):
|
|
248
269
|
# Load the request context with any specified command line options.
|
|
249
270
|
context = protobuf.Map()
|
|
@@ -265,35 +286,35 @@ class Command(command.Command):
|
|
|
265
286
|
context[key_value[0]] = protobuf.Yaml(key_value[1])
|
|
266
287
|
return context
|
|
267
288
|
|
|
268
|
-
async def render(self, composite, observed=[], composition=None, resources=[], context=None,
|
|
289
|
+
async def render(self, composite, observed=[], composition=None, resources=[], schemas=[], context=None, api=None, render_unknowns=False, crossplane_v1=False, composite_observeds=True):
|
|
269
290
|
# Create the request used when running Composition steps.
|
|
270
291
|
request = protobuf.Message(None, 'request', fnv1.RunFunctionRequest.DESCRIPTOR, fnv1.RunFunctionRequest())
|
|
271
292
|
if context is not None:
|
|
272
293
|
request.context = context
|
|
273
294
|
|
|
274
295
|
# Establish the request observed composite.
|
|
275
|
-
await self.set_resource(composite, request.observed.composite, resources,
|
|
296
|
+
await self.set_resource(composite, request.observed.composite, resources, api)
|
|
276
297
|
# Establish the manually configured observed resources.
|
|
277
298
|
if observed:
|
|
278
299
|
async with asyncio.TaskGroup() as group:
|
|
279
300
|
for resource in observed:
|
|
280
301
|
name = resource.metadata.annotations['crossplane.io/composition-resource-name']
|
|
281
302
|
if name:
|
|
282
|
-
group.create_task(self.set_resource(resource, request.observed.resources[name], resources,
|
|
283
|
-
if
|
|
303
|
+
group.create_task(self.set_resource(resource, request.observed.resources[name], resources, api))
|
|
304
|
+
if api and composite_observeds:
|
|
284
305
|
refs = composite.spec.crossplane.resourceRefs
|
|
285
306
|
if not refs:
|
|
286
307
|
refs = composite.spec.resourceRefs
|
|
287
308
|
if refs:
|
|
288
309
|
async with asyncio.TaskGroup() as group:
|
|
289
310
|
for ref in refs:
|
|
290
|
-
group.create_task(self.get_composite_ref(composite, ref, request, resources,
|
|
311
|
+
group.create_task(self.get_composite_ref(composite, ref, request, resources, api))
|
|
291
312
|
|
|
292
313
|
if not composition:
|
|
293
314
|
if composite.apiVersion in ('pythonic.crossplane.io/v1alpha1', 'pythonic.fortra.com/v1alpha1') and composite.kind == 'Composite':
|
|
294
315
|
composition = self.create_composition(composite)
|
|
295
316
|
else:
|
|
296
|
-
if not
|
|
317
|
+
if not api:
|
|
297
318
|
print('"composition" required', file=sys.stderr)
|
|
298
319
|
return None
|
|
299
320
|
revision = composite.spec.crossplane.compositionRevisionRef
|
|
@@ -303,7 +324,7 @@ class Command(command.Command):
|
|
|
303
324
|
if not revision.name:
|
|
304
325
|
print('Composite does not contain a CompositionRevision name', file=sys.stderr)
|
|
305
326
|
return None
|
|
306
|
-
composition = await
|
|
327
|
+
composition = await self.kr8s_get(api, 'CompositionRevision', 'apiextensions.crossplane.io/v1', None, revision.name)
|
|
307
328
|
if not composition:
|
|
308
329
|
print(f"Compositioin \"{revision.name}\" not found", file=sys.stderr)
|
|
309
330
|
return None
|
|
@@ -350,14 +371,18 @@ class Command(command.Command):
|
|
|
350
371
|
# Fetch the step bootstrap resources specified.
|
|
351
372
|
request.required_resources()
|
|
352
373
|
for requirement in step.requirements.requiredResources:
|
|
353
|
-
await self.set_required(requirement.requirementName, requirement, request.required_resources, resources,
|
|
374
|
+
await self.set_required(requirement.requirementName, requirement, request.required_resources, resources, api)
|
|
354
375
|
# Fetch the required resources requested.
|
|
355
376
|
for name, selector in requirements.resources:
|
|
356
|
-
await self.set_required(name, selector, request.required_resources, resources,
|
|
377
|
+
await self.set_required(name, selector, request.required_resources, resources, api)
|
|
357
378
|
# Fetch the now deprecated extra resources requested.
|
|
358
379
|
request.extra_resources()
|
|
359
380
|
for name, selector in requirements.extra_resources:
|
|
360
|
-
await self.set_required(name, selector, request.extra_resources, resources,
|
|
381
|
+
await self.set_required(name, selector, request.extra_resources, resources, api)
|
|
382
|
+
# Fetch the schemas requested.
|
|
383
|
+
request.required_schemas()
|
|
384
|
+
for name, selector in requirements.schemas:
|
|
385
|
+
await self.set_schema(name, selector, request.required_schemas, schemas, api)
|
|
361
386
|
# Run the step using the function-pythonic function runner.
|
|
362
387
|
response = protobuf.Message(
|
|
363
388
|
None,
|
|
@@ -365,13 +390,15 @@ class Command(command.Command):
|
|
|
365
390
|
fnv1.RunFunctionResponse.DESCRIPTOR,
|
|
366
391
|
await runner.RunFunction(request._message, None),
|
|
367
392
|
)
|
|
393
|
+
# Copy the response context to the request context to use in subsequent steps.
|
|
394
|
+
request.context = response.context
|
|
368
395
|
# All done if there is a fatal result.
|
|
369
396
|
for result in response.results:
|
|
370
397
|
if result.severity == fnv1.Severity.SEVERITY_FATAL:
|
|
371
398
|
fatal = True
|
|
372
399
|
break
|
|
373
|
-
|
|
374
|
-
|
|
400
|
+
if fatal:
|
|
401
|
+
break
|
|
375
402
|
# Exit this loop if the function has not requested additional extra/required resources.
|
|
376
403
|
if response.requirements == requirements:
|
|
377
404
|
break
|
|
@@ -479,21 +506,21 @@ class Command(command.Command):
|
|
|
479
506
|
),
|
|
480
507
|
)
|
|
481
508
|
|
|
482
|
-
async def get_composite_ref(self, composite, ref, request, resources,
|
|
509
|
+
async def get_composite_ref(self, composite, ref, request, resources, api):
|
|
483
510
|
namespace = ref.namespace
|
|
484
511
|
if not namespace:
|
|
485
512
|
namespace = composite.metadata.namespace
|
|
486
513
|
if not namespace:
|
|
487
514
|
namespace = None
|
|
488
|
-
source = await
|
|
515
|
+
source = await self.kr8s_get(api, ref.kind, ref.apiVersion, namespace, ref.name)
|
|
489
516
|
if source:
|
|
490
517
|
name = source.metadata.annotations['crossplane.io/composition-resource-name']
|
|
491
518
|
if name:
|
|
492
519
|
destination = request.observed.resources[name]
|
|
493
520
|
if not destination: # Do not override manual observed
|
|
494
|
-
await self.set_resource(source, destination, resources,
|
|
521
|
+
await self.set_resource(source, destination, resources, api)
|
|
495
522
|
|
|
496
|
-
async def set_required(self, name, selector, requireds, resources=[],
|
|
523
|
+
async def set_required(self, name, selector, requireds, resources=[], api=None):
|
|
497
524
|
if not name:
|
|
498
525
|
return
|
|
499
526
|
name = str(name)
|
|
@@ -505,23 +532,23 @@ class Command(command.Command):
|
|
|
505
532
|
or (selector.namespace == resource.metadata.namespace)
|
|
506
533
|
):
|
|
507
534
|
if selector.match_name == resource.metadata.name:
|
|
508
|
-
await self.set_resource(resource, items[protobuf.append], resources,
|
|
535
|
+
await self.set_resource(resource, items[protobuf.append], resources, api)
|
|
509
536
|
elif selector.match_labels.labels:
|
|
510
537
|
for key, value in selector.match_labels.labels:
|
|
511
538
|
if value != resource.metadata.labels[key]:
|
|
512
539
|
break
|
|
513
540
|
else:
|
|
514
|
-
await self.set_resource(resource, items[protobuf.append], resources,
|
|
515
|
-
if not len(items) and
|
|
541
|
+
await self.set_resource(resource, items[protobuf.append], resources, api)
|
|
542
|
+
if not len(items) and api:
|
|
516
543
|
if len(selector.match_name):
|
|
517
|
-
resource = await
|
|
544
|
+
resource = await self.kr8s_get(api, selector.kind, selector.api_version, selector.namespace, selector.match_name)
|
|
518
545
|
if resource:
|
|
519
|
-
await self.set_resource(resource, items[protobuf.append], resources,
|
|
546
|
+
await self.set_resource(resource, items[protobuf.append], resources, api)
|
|
520
547
|
elif len(selector.match_labels.labels):
|
|
521
|
-
for resource in await
|
|
522
|
-
await self.set_resource(resource, items[protobuf.append], resources,
|
|
548
|
+
for resource in await self.kr8s_list(api, selector.kind, selector.api_version, selector.namespace, selector.match_labels.labels):
|
|
549
|
+
await self.set_resource(resource, items[protobuf.append], resources, api)
|
|
523
550
|
|
|
524
|
-
async def set_resource(self, source, destination, resources=[],
|
|
551
|
+
async def set_resource(self, source, destination, resources=[], api=None):
|
|
525
552
|
destination.resource = source
|
|
526
553
|
namespace = source.spec.writeConnectionSecretToRef.namespace or source.metadata.namespace
|
|
527
554
|
name = source.spec.writeConnectionSecretToRef.name
|
|
@@ -533,13 +560,88 @@ class Command(command.Command):
|
|
|
533
560
|
connection = resource
|
|
534
561
|
break
|
|
535
562
|
else:
|
|
536
|
-
if
|
|
537
|
-
connection = await
|
|
563
|
+
if api:
|
|
564
|
+
connection = await self.kr8s_get(api, 'Secret', 'v1', namespace, name)
|
|
538
565
|
if connection:
|
|
539
566
|
destination.connection_details()
|
|
540
567
|
for key, value in connection.data:
|
|
541
568
|
destination.connection_details[key] = protobuf.B64Decode(value)
|
|
542
569
|
|
|
570
|
+
async def set_schema(self, name, selector, schemas, documents=[], api=None):
|
|
571
|
+
if not name:
|
|
572
|
+
return
|
|
573
|
+
name = str(name)
|
|
574
|
+
schema = schemas[name].openapi_v3
|
|
575
|
+
schema() # Force this to get created
|
|
576
|
+
gvk = protobuf.Map(kind=selector.kind)
|
|
577
|
+
version = str(selector.api_version)
|
|
578
|
+
if '/' in version:
|
|
579
|
+
gvk.group, gvk.version = version.split('/', 1)
|
|
580
|
+
else:
|
|
581
|
+
gvk.group = ''
|
|
582
|
+
gvk.version = version
|
|
583
|
+
for document in documents:
|
|
584
|
+
if self.find_schema(gvk, document, schema):
|
|
585
|
+
return
|
|
586
|
+
if api:
|
|
587
|
+
if gvk.group == '':
|
|
588
|
+
url = f"api/{gvk.version}"
|
|
589
|
+
else:
|
|
590
|
+
url = f"apis/{gvk.group}/{gvk.version}"
|
|
591
|
+
try:
|
|
592
|
+
async with api.call_api(base='/openapi/v3', version='', url=url) as response:
|
|
593
|
+
document = protobuf.Value(None, None, response.json())
|
|
594
|
+
except kr8s.NotFoundError:
|
|
595
|
+
return
|
|
596
|
+
self.find_schema(gvk, document, schema)
|
|
597
|
+
|
|
598
|
+
def find_schema(self, gvk, document, schema):
|
|
599
|
+
for name, s in document.components.schemas:
|
|
600
|
+
gvks = s['x-kubernetes-group-version-kind']
|
|
601
|
+
if len(gvks) == 1 and gvks[0] == gvk:
|
|
602
|
+
self.resolve_ref(document, set(), f"#/components/schemas/{name}", schema)
|
|
603
|
+
return True
|
|
604
|
+
return False
|
|
605
|
+
|
|
606
|
+
def resolve_ref(self, document, visiting, ref, schema):
|
|
607
|
+
if not ref:
|
|
608
|
+
return
|
|
609
|
+
ref = str(ref)
|
|
610
|
+
if ref in visiting:
|
|
611
|
+
return
|
|
612
|
+
d = None
|
|
613
|
+
for segment in ref.split('/'):
|
|
614
|
+
if segment == '#':
|
|
615
|
+
d = document
|
|
616
|
+
else:
|
|
617
|
+
d = d[segment]
|
|
618
|
+
if not d:
|
|
619
|
+
return
|
|
620
|
+
visiting.add(ref)
|
|
621
|
+
try:
|
|
622
|
+
for name, value in d:
|
|
623
|
+
self.copy_schema(document, visiting, name, value, schema)
|
|
624
|
+
finally:
|
|
625
|
+
visiting.remove(ref)
|
|
626
|
+
|
|
627
|
+
def copy_schema(self, document, visiting, key, value, schema):
|
|
628
|
+
if key == '$ref':
|
|
629
|
+
self.resolve_ref(document, visiting, value, schema)
|
|
630
|
+
elif key == 'allOf':
|
|
631
|
+
if value._isList and len(value) == 1:
|
|
632
|
+
self.resolve_ref(document, visiting, value[0]['$ref'], schema)
|
|
633
|
+
else:
|
|
634
|
+
if value._isMap:
|
|
635
|
+
s = schema[key]
|
|
636
|
+
for n, v in value:
|
|
637
|
+
self.copy_schema(document, visiting, n, v, s)
|
|
638
|
+
elif value._isList:
|
|
639
|
+
s = schema[key]
|
|
640
|
+
for ix, v in enumerate(value):
|
|
641
|
+
self.copy_schema(document, visiting, ix, v, s)
|
|
642
|
+
else:
|
|
643
|
+
schema[key] = value
|
|
644
|
+
|
|
543
645
|
def copy_resource(self, source, destination):
|
|
544
646
|
destination.resource = source.resource
|
|
545
647
|
destination.connection_details()
|
|
@@ -572,69 +674,53 @@ class Command(command.Command):
|
|
|
572
674
|
condition['message'] = message
|
|
573
675
|
return condition
|
|
574
676
|
|
|
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)
|
|
677
|
+
async def kr8s_get(self, api, kind, apiVersion, namespace, name):
|
|
678
|
+
namespaced = namespace and len(namespace)
|
|
679
|
+
clazz = self.kr8s_class(kind, apiVersion, namespaced)
|
|
592
680
|
try:
|
|
593
681
|
fullName = [str(kind), str(apiVersion), str(name)]
|
|
594
|
-
if
|
|
682
|
+
if namespaced:
|
|
595
683
|
fullName.insert(-1, str(namespace))
|
|
596
|
-
resource = await clazz.get(str(name), namespace=str(namespace), api=
|
|
684
|
+
resource = await clazz.get(str(name), namespace=str(namespace), api=api)
|
|
597
685
|
else:
|
|
598
|
-
resource = await clazz.get(str(name), api=
|
|
686
|
+
resource = await clazz.get(str(name), api=api)
|
|
599
687
|
resource = protobuf.Value(None, None, resource.raw)
|
|
600
688
|
result = 'found'
|
|
601
|
-
except
|
|
689
|
+
except kr8s.NotFoundError:
|
|
602
690
|
resource = None
|
|
603
691
|
result = 'missing'
|
|
604
|
-
|
|
605
|
-
self.logger.debug(f"Resource {result}: {':'.join(fullName)}")
|
|
692
|
+
self.logger.debug(f"Resource {result}: {':'.join(fullName)}")
|
|
606
693
|
return resource
|
|
607
694
|
|
|
608
|
-
async def
|
|
609
|
-
|
|
695
|
+
async def kr8s_list(self, api, kind, apiVersion, namespace, labelSelector):
|
|
696
|
+
namespaced = namespace and len(namespace)
|
|
697
|
+
clazz = self.kr8s_class(kind, apiVersion, namespaced)
|
|
610
698
|
resources = [
|
|
611
699
|
protobuf.Value(None, None, resource.raw)
|
|
612
700
|
async for resource in clazz.list(
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
701
|
+
namespace=str(namespace) if namespaced else None,
|
|
702
|
+
label_selector={
|
|
703
|
+
label: str(value)
|
|
704
|
+
for label, value in labelSelector
|
|
705
|
+
},
|
|
706
|
+
api=api,
|
|
619
707
|
)
|
|
620
708
|
]
|
|
621
709
|
if self.logger.isEnabledFor(logging.DEBUG):
|
|
622
710
|
fullName = [str(kind), str(apiVersion)]
|
|
623
|
-
if
|
|
711
|
+
if namespaced:
|
|
624
712
|
fullName.append(str(namespace))
|
|
625
713
|
fullName.append('&'.join(f"{label}={value}" for label, value in labelSelector))
|
|
626
714
|
if resources:
|
|
627
|
-
result = f"found {
|
|
715
|
+
result = f"found {INFLECT.number_to_words(len(resources))}"
|
|
628
716
|
else:
|
|
629
717
|
result = 'missing'
|
|
630
718
|
self.logger.debug(f"Resources {result}: {':'.join(fullName)}")
|
|
631
719
|
return resources
|
|
632
720
|
|
|
633
|
-
def
|
|
634
|
-
kind = str(kind)
|
|
635
|
-
apiVersion = str(apiVersion)
|
|
721
|
+
def kr8s_class(self, kind, apiVersion, namespaced):
|
|
636
722
|
try:
|
|
637
|
-
return
|
|
723
|
+
return kr8s.asyncio.objects.get_class(str(kind), str(apiVersion), True)
|
|
638
724
|
except KeyError:
|
|
639
725
|
pass
|
|
640
|
-
return
|
|
726
|
+
return kr8s.asyncio.objects.new_class(str(kind), str(apiVersion), True, namespaced, plural=INFLECT.plural_noun(str(kind)).lower())
|