illumio-pylo 0.3.11__py3-none-any.whl → 0.3.13__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.
- illumio_pylo/API/APIConnector.py +138 -106
- illumio_pylo/API/CredentialsManager.py +168 -3
- illumio_pylo/API/Explorer.py +619 -14
- illumio_pylo/API/JsonPayloadTypes.py +64 -4
- illumio_pylo/FilterQuery.py +892 -0
- illumio_pylo/Helpers/exports.py +1 -1
- illumio_pylo/LabelCommon.py +13 -3
- illumio_pylo/LabelDimension.py +109 -0
- illumio_pylo/LabelStore.py +97 -38
- illumio_pylo/WorkloadStore.py +58 -0
- illumio_pylo/__init__.py +9 -3
- illumio_pylo/cli/__init__.py +5 -2
- illumio_pylo/cli/commands/__init__.py +1 -0
- illumio_pylo/cli/commands/credential_manager.py +555 -4
- illumio_pylo/cli/commands/label_delete_unused.py +0 -3
- illumio_pylo/cli/commands/traffic_export.py +358 -0
- illumio_pylo/cli/commands/ui/credential_manager_ui/app.js +638 -0
- illumio_pylo/cli/commands/ui/credential_manager_ui/index.html +217 -0
- illumio_pylo/cli/commands/ui/credential_manager_ui/styles.css +581 -0
- illumio_pylo/cli/commands/update_pce_objects_cache.py +1 -2
- illumio_pylo/cli/commands/ven_duplicate_remover.py +79 -59
- illumio_pylo/cli/commands/workload_export.py +29 -0
- illumio_pylo/utilities/cli.py +4 -1
- illumio_pylo/utilities/health_monitoring.py +5 -1
- {illumio_pylo-0.3.11.dist-info → illumio_pylo-0.3.13.dist-info}/METADATA +2 -1
- {illumio_pylo-0.3.11.dist-info → illumio_pylo-0.3.13.dist-info}/RECORD +29 -24
- {illumio_pylo-0.3.11.dist-info → illumio_pylo-0.3.13.dist-info}/WHEEL +1 -1
- illumio_pylo/Query.py +0 -331
- {illumio_pylo-0.3.11.dist-info → illumio_pylo-0.3.13.dist-info}/licenses/LICENSE +0 -0
- {illumio_pylo-0.3.11.dist-info → illumio_pylo-0.3.13.dist-info}/top_level.txt +0 -0
illumio_pylo/API/APIConnector.py
CHANGED
|
@@ -30,7 +30,7 @@ requests.packages.urllib3.disable_warnings()
|
|
|
30
30
|
|
|
31
31
|
default_retry_count_if_api_call_limit_reached = 3
|
|
32
32
|
default_retry_wait_time_if_api_call_limit_reached = 10
|
|
33
|
-
default_max_objects_for_sync_calls =
|
|
33
|
+
default_max_objects_for_sync_calls = 200000
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
def get_field_or_die(field_name: str, data):
|
|
@@ -45,7 +45,7 @@ def get_field_or_die(field_name: str, data):
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
ObjectTypes = Literal['iplists', 'workloads', 'virtual_services', 'labels', 'labelgroups', 'services', 'rulesets',
|
|
48
|
-
|
|
48
|
+
'security_principals', 'label_dimensions']
|
|
49
49
|
|
|
50
50
|
all_object_types: Dict[ObjectTypes, ObjectTypes] = {
|
|
51
51
|
'iplists': 'iplists',
|
|
@@ -153,6 +153,33 @@ class APIConnector:
|
|
|
153
153
|
|
|
154
154
|
return url
|
|
155
155
|
|
|
156
|
+
def _get_objects_auto_switch_async(self, path: str, data: Dict[str, Any], async_mode: bool, max_results: Optional[int]) -> Any:
|
|
157
|
+
# use a copy of data to not modify the original
|
|
158
|
+
data_copy = data.copy()
|
|
159
|
+
|
|
160
|
+
if async_mode:
|
|
161
|
+
if max_results is not None:
|
|
162
|
+
data_copy['max_results'] = max_results
|
|
163
|
+
return self.do_get_call(path=path, async_call=True, params=data_copy)
|
|
164
|
+
|
|
165
|
+
if max_results is not None:
|
|
166
|
+
data_copy['max_results'] = max_results
|
|
167
|
+
return self.do_get_call(path=path, async_call=False, params=data_copy)
|
|
168
|
+
|
|
169
|
+
# We will grab the maximum allowed with sync mode (variable default_max_objects_for_sync_calls) and switch to async if it's higher
|
|
170
|
+
data_copy['max_results'] = default_max_objects_for_sync_calls
|
|
171
|
+
results = self.do_get_call(path=path, async_call=False, params=data_copy, return_headers=True)
|
|
172
|
+
total_count = results[1].get('x-total-count')
|
|
173
|
+
if total_count is None:
|
|
174
|
+
raise pylo.PyloApiEx('API didnt provide field "x-total-count" in headers')
|
|
175
|
+
if not total_count.isdigit():
|
|
176
|
+
raise pylo.PyloApiEx('API returned invalid value for "x-total-count": {}'.format(total_count))
|
|
177
|
+
if int(total_count) > default_max_objects_for_sync_calls:
|
|
178
|
+
# remove the max_results from data
|
|
179
|
+
del data_copy['max_results']
|
|
180
|
+
return self.do_get_call(path=path, async_call=True, params=data_copy)
|
|
181
|
+
return results[0]
|
|
182
|
+
|
|
156
183
|
def do_get_call(self, path, json_arguments=None, include_org_id=True, json_output_expected=True, async_call=False, params=None, skip_product_version_check=False,
|
|
157
184
|
retry_count_if_api_call_limit_reached=default_retry_count_if_api_call_limit_reached,
|
|
158
185
|
retry_wait_time_if_api_call_limit_reached=default_retry_wait_time_if_api_call_limit_reached,
|
|
@@ -275,7 +302,7 @@ class APIConnector:
|
|
|
275
302
|
log.info("Job status is " + job_poll_status)
|
|
276
303
|
|
|
277
304
|
log.info("Job is done, we will now download the resulting dataset")
|
|
278
|
-
dataset = self.do_get_call(result_href, include_org_id=False)
|
|
305
|
+
dataset = self.do_get_call(result_href, include_org_id=False, return_headers=return_headers)
|
|
279
306
|
|
|
280
307
|
return dataset
|
|
281
308
|
|
|
@@ -285,7 +312,7 @@ class APIConnector:
|
|
|
285
312
|
or\
|
|
286
313
|
method == 'DELETE' and req.status_code != 204 \
|
|
287
314
|
or \
|
|
288
|
-
method == 'PUT' and req.status_code != 204 and req.status_code != 200:
|
|
315
|
+
method == 'PUT' and req.status_code != 204 and req.status_code != 202 and req.status_code != 200:
|
|
289
316
|
|
|
290
317
|
if req.status_code == 429:
|
|
291
318
|
# too many requests sent in short amount of time? [{"token":"too_many_requests_error", ....}]
|
|
@@ -313,9 +340,6 @@ class APIConnector:
|
|
|
313
340
|
raise pylo.PyloApiEx('API returned error status "' + str(req.status_code) + ' ' + req.reason
|
|
314
341
|
+ '" and error message: ' + req.text)
|
|
315
342
|
|
|
316
|
-
if return_headers:
|
|
317
|
-
return req.headers
|
|
318
|
-
|
|
319
343
|
if json_output_expected:
|
|
320
344
|
log.info("Parsing API answer to JSON (with a size of " + str(int(answer_size)) + "KB)")
|
|
321
345
|
json_out = req.json()
|
|
@@ -325,8 +349,12 @@ class APIConnector:
|
|
|
325
349
|
log.info(json.dumps(json_out, indent=2, sort_keys=True))
|
|
326
350
|
else:
|
|
327
351
|
log.info("Answer is too large to be printed")
|
|
352
|
+
if return_headers:
|
|
353
|
+
return json_out, req.headers
|
|
328
354
|
return json_out
|
|
329
355
|
|
|
356
|
+
if return_headers:
|
|
357
|
+
return req.text, req.headers
|
|
330
358
|
return req.text
|
|
331
359
|
|
|
332
360
|
raise pylo.PyloApiEx("Unexpected API output or race condition")
|
|
@@ -339,33 +367,39 @@ class APIConnector:
|
|
|
339
367
|
self.collect_pce_infos()
|
|
340
368
|
return self.version_string
|
|
341
369
|
|
|
342
|
-
def get_objects_count_by_type(self, object_type:
|
|
370
|
+
def get_objects_count_by_type(self, object_type: ObjectTypes) -> int:
|
|
343
371
|
|
|
344
372
|
def extract_count(headers):
|
|
345
373
|
count = headers.get('x-total-count')
|
|
346
374
|
if count is None:
|
|
347
375
|
raise pylo.PyloApiEx('API didnt provide field "x-total-count"')
|
|
348
376
|
|
|
377
|
+
# count should be an integer
|
|
378
|
+
if not count.isdigit():
|
|
379
|
+
raise pylo.PyloApiEx('API returned invalid value for "x-total-count": {}'.format(count))
|
|
380
|
+
|
|
349
381
|
return int(count)
|
|
350
382
|
|
|
383
|
+
params = {'max_results': 1}
|
|
384
|
+
|
|
351
385
|
if object_type == 'workloads':
|
|
352
|
-
return extract_count(self.do_get_call('/workloads', async_call=False, return_headers=True))
|
|
386
|
+
return extract_count(self.do_get_call('/workloads', async_call=False, return_headers=True, params=params)[1])
|
|
353
387
|
elif object_type == 'virtual_services':
|
|
354
|
-
return extract_count(self.do_get_call('/sec_policy/draft/virtual_services', async_call=False, return_headers=True))
|
|
388
|
+
return extract_count(self.do_get_call('/sec_policy/draft/virtual_services', async_call=False, return_headers=True, params=params)[1])
|
|
355
389
|
elif object_type == 'labels':
|
|
356
|
-
return extract_count(self.do_get_call('/labels', async_call=False, return_headers=True))
|
|
390
|
+
return extract_count(self.do_get_call('/labels', async_call=False, return_headers=True, params=params)[1])
|
|
357
391
|
elif object_type == 'labelgroups':
|
|
358
|
-
return extract_count(self.do_get_call('/sec_policy/draft/label_groups', async_call=False, return_headers=True))
|
|
392
|
+
return extract_count(self.do_get_call('/sec_policy/draft/label_groups', async_call=False, return_headers=True, params=params)[1])
|
|
359
393
|
elif object_type == 'iplists':
|
|
360
|
-
return extract_count(self.do_get_call('/sec_policy/draft/ip_lists', async_call=False, return_headers=True))
|
|
394
|
+
return extract_count(self.do_get_call('/sec_policy/draft/ip_lists', async_call=False, return_headers=True, params=params)[1])
|
|
361
395
|
elif object_type == 'services':
|
|
362
|
-
return extract_count(self.do_get_call('/sec_policy/draft/services', async_call=False, return_headers=True))
|
|
396
|
+
return extract_count(self.do_get_call('/sec_policy/draft/services', async_call=False, return_headers=True, params=params)[1])
|
|
363
397
|
elif object_type == 'rulesets':
|
|
364
|
-
return extract_count(self.do_get_call('/sec_policy/draft/rule_sets', async_call=False, return_headers=True))
|
|
398
|
+
return extract_count(self.do_get_call('/sec_policy/draft/rule_sets', async_call=False, return_headers=True, params=params)[1])
|
|
365
399
|
elif object_type == 'security_principals':
|
|
366
|
-
return extract_count(self.do_get_call('/security_principals', async_call=False, return_headers=True))
|
|
400
|
+
return extract_count(self.do_get_call('/security_principals', async_call=False, return_headers=True, params=params)[1])
|
|
367
401
|
elif object_type == 'label_dimensions':
|
|
368
|
-
return extract_count(self.do_get_call('/label_dimensions', async_call=False, return_headers=True))
|
|
402
|
+
return extract_count(self.do_get_call('/label_dimensions', async_call=False, return_headers=True, params=params)[1])
|
|
369
403
|
else:
|
|
370
404
|
raise pylo.PyloEx("Unsupported object type '{}'".format(object_type))
|
|
371
405
|
|
|
@@ -403,57 +437,32 @@ class APIConnector:
|
|
|
403
437
|
q.task_done()
|
|
404
438
|
continue
|
|
405
439
|
if object_type == 'workloads':
|
|
406
|
-
|
|
407
|
-
data['workloads'] = self.objects_workload_get(include_deleted=include_deleted_workloads)
|
|
408
|
-
else:
|
|
409
|
-
data['workloads'] = self.objects_workload_get(include_deleted=include_deleted_workloads, async_mode=False, max_results=default_max_objects_for_sync_calls)
|
|
440
|
+
data['workloads'] = self.objects_workload_get(include_deleted=include_deleted_workloads, async_mode=force_async_mode)
|
|
410
441
|
|
|
411
442
|
elif object_type == 'virtual_services':
|
|
412
|
-
|
|
413
|
-
data['virtual_services'] = self.objects_virtual_service_get()
|
|
414
|
-
else:
|
|
415
|
-
data['virtual_services'] = self.objects_virtual_service_get(async_mode=False, max_results=default_max_objects_for_sync_calls)
|
|
443
|
+
data['virtual_services'] = self.objects_virtual_service_get(async_mode=force_async_mode)
|
|
416
444
|
|
|
417
445
|
elif object_type == 'labels':
|
|
418
|
-
|
|
419
|
-
data['labels'] = self.objects_label_get()
|
|
420
|
-
else:
|
|
421
|
-
data['labels'] = self.objects_label_get(async_mode=False, max_results=default_max_objects_for_sync_calls)
|
|
446
|
+
data['labels'] = self.objects_label_get(async_mode=force_async_mode)
|
|
422
447
|
|
|
423
448
|
elif object_type == 'labelgroups':
|
|
424
|
-
|
|
425
|
-
data['labelgroups'] = self.objects_labelgroup_get()
|
|
426
|
-
else:
|
|
427
|
-
data['labelgroups'] = self.objects_labelgroup_get(async_mode=False, max_results=default_max_objects_for_sync_calls)
|
|
449
|
+
data['labelgroups'] = self.objects_labelgroup_get(async_mode=force_async_mode)
|
|
428
450
|
|
|
429
451
|
elif object_type == 'iplists':
|
|
430
|
-
|
|
431
|
-
data['iplists'] = self.objects_iplist_get()
|
|
432
|
-
else:
|
|
433
|
-
data['iplists'] = self.objects_iplist_get(async_mode=False, max_results=default_max_objects_for_sync_calls)
|
|
452
|
+
data['iplists'] = self.objects_iplist_get(async_mode=force_async_mode)
|
|
434
453
|
|
|
435
454
|
elif object_type == 'services':
|
|
436
|
-
|
|
437
|
-
data['services'] = self.objects_service_get()
|
|
438
|
-
else:
|
|
439
|
-
data['services'] = self.objects_service_get(async_mode=False, max_results=default_max_objects_for_sync_calls)
|
|
455
|
+
data['services'] = self.objects_service_get(async_mode=force_async_mode)
|
|
440
456
|
|
|
441
457
|
elif object_type == 'rulesets':
|
|
442
|
-
|
|
443
|
-
data['rulesets'] = self.objects_ruleset_get()
|
|
444
|
-
else:
|
|
445
|
-
data['rulesets'] = self.objects_ruleset_get(async_mode=False, max_results=default_max_objects_for_sync_calls)
|
|
458
|
+
data['rulesets'] = self.objects_ruleset_get(async_mode=force_async_mode)
|
|
446
459
|
|
|
447
460
|
elif object_type == 'security_principals':
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
else:
|
|
451
|
-
data['security_principals'] = self.objects_securityprincipal_get(async_mode=False, max_results=default_max_objects_for_sync_calls)
|
|
461
|
+
data['security_principals'] = self.objects_securityprincipal_get(async_mode=force_async_mode)
|
|
462
|
+
|
|
452
463
|
elif object_type == 'label_dimensions':
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
else:
|
|
456
|
-
data['label_dimensions'] = self.objects_label_dimension_get(async_mode=False, max_results=default_max_objects_for_sync_calls)
|
|
464
|
+
data['label_dimensions'] = self.objects_label_dimension_get()
|
|
465
|
+
|
|
457
466
|
else:
|
|
458
467
|
raise pylo.PyloEx("Unsupported object type '{}'".format(object_type))
|
|
459
468
|
except Exception as e:
|
|
@@ -533,20 +542,17 @@ class APIConnector:
|
|
|
533
542
|
params = {'include_deny_rules': include_boundary_rules}
|
|
534
543
|
return self.do_post_call(path='/sec_policy/draft/rule_coverage', json_arguments=data, include_org_id=True, json_output_expected=True, async_call=False, params=params)
|
|
535
544
|
|
|
536
|
-
def objects_label_get(self, max_results: int = None, async_mode=
|
|
545
|
+
def objects_label_get(self, max_results: int = None, async_mode=False, get_usage: bool = False, get_deleted: bool = False) -> List[LabelObjectJsonStructure]:
|
|
537
546
|
path = '/labels'
|
|
538
547
|
data = {}
|
|
539
548
|
|
|
540
|
-
if max_results is not None:
|
|
541
|
-
data['max_results'] = max_results
|
|
542
|
-
|
|
543
549
|
if get_usage:
|
|
544
550
|
data['usage'] = 'true'
|
|
545
551
|
|
|
546
552
|
if get_deleted:
|
|
547
553
|
data['includeDeleted'] = 'true'
|
|
548
554
|
|
|
549
|
-
return self.
|
|
555
|
+
return self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
550
556
|
|
|
551
557
|
def objects_label_update(self, href: str, data: LabelObjectUpdateJsonStructure):
|
|
552
558
|
path = href
|
|
@@ -618,14 +624,11 @@ class APIConnector:
|
|
|
618
624
|
data: LabelObjectCreationJsonStructure = {'key': label_type, 'value': label_name}
|
|
619
625
|
return self.do_post_call(path=path, json_arguments=data)
|
|
620
626
|
|
|
621
|
-
def objects_labelgroup_get(self, max_results: int = None, async_mode=
|
|
627
|
+
def objects_labelgroup_get(self, max_results: int = None, async_mode=False) -> List[LabelGroupObjectJsonStructure]:
|
|
622
628
|
path = '/sec_policy/draft/label_groups'
|
|
623
629
|
data = {}
|
|
624
630
|
|
|
625
|
-
|
|
626
|
-
data['max_results'] = max_results
|
|
627
|
-
|
|
628
|
-
return self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
631
|
+
return self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
629
632
|
|
|
630
633
|
def objects_labelgroup_update(self, href: str, data: LabelGroupObjectUpdateJsonStructure):
|
|
631
634
|
path = href
|
|
@@ -635,34 +638,26 @@ class APIConnector:
|
|
|
635
638
|
path = '/label_dimensions'
|
|
636
639
|
data = {}
|
|
637
640
|
|
|
638
|
-
|
|
639
|
-
data['max_results'] = max_results
|
|
640
|
-
return self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
641
|
+
return self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
641
642
|
|
|
642
|
-
def objects_virtual_service_get(self, max_results: int = None, async_mode=
|
|
643
|
+
def objects_virtual_service_get(self, max_results: int = None, async_mode=False) -> List[VirtualServiceObjectJsonStructure]:
|
|
643
644
|
path = '/sec_policy/draft/virtual_services'
|
|
644
645
|
data = {}
|
|
645
646
|
|
|
646
|
-
|
|
647
|
-
data['max_results'] = max_results
|
|
648
|
-
|
|
649
|
-
results = self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
647
|
+
results = self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
650
648
|
# check type
|
|
651
649
|
if type(results) is list:
|
|
652
650
|
return results
|
|
653
651
|
raise pylo.PyloEx("Unexpected result type '{}' while expecting an array of Virtual Service objects".format(type(results)), results)
|
|
654
652
|
|
|
655
|
-
def objects_iplist_get(self, max_results: int = None, async_mode=
|
|
653
|
+
def objects_iplist_get(self, max_results: int = None, async_mode=False, search_name: str = None) -> List[IPListObjectJsonStructure]:
|
|
656
654
|
path = '/sec_policy/draft/ip_lists'
|
|
657
655
|
data = {}
|
|
658
656
|
|
|
659
657
|
if search_name is not None:
|
|
660
658
|
data['name'] = search_name
|
|
661
659
|
|
|
662
|
-
|
|
663
|
-
data['max_results'] = max_results
|
|
664
|
-
|
|
665
|
-
results: List[IPListObjectJsonStructure] = self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
660
|
+
results: List[IPListObjectJsonStructure] = self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
666
661
|
# check type
|
|
667
662
|
if type(results) is list:
|
|
668
663
|
return results
|
|
@@ -714,10 +709,7 @@ class APIConnector:
|
|
|
714
709
|
if representation is not None:
|
|
715
710
|
data['representation'] = representation
|
|
716
711
|
|
|
717
|
-
|
|
718
|
-
data['max_results'] = max_results
|
|
719
|
-
|
|
720
|
-
return self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
712
|
+
return self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
721
713
|
|
|
722
714
|
def objects_workload_get(self,
|
|
723
715
|
include_deleted=False,
|
|
@@ -727,7 +719,7 @@ class APIConnector:
|
|
|
727
719
|
filter_by_managed: bool = None,
|
|
728
720
|
filer_by_policy_health: Literal['active', 'warning', 'error'] = None,
|
|
729
721
|
max_results: int = None,
|
|
730
|
-
async_mode=
|
|
722
|
+
async_mode=False) -> List[WorkloadObjectJsonStructure]:
|
|
731
723
|
path = '/workloads'
|
|
732
724
|
data = {}
|
|
733
725
|
|
|
@@ -750,10 +742,8 @@ class APIConnector:
|
|
|
750
742
|
if filer_by_policy_health is not None:
|
|
751
743
|
data['policy_health'] = filer_by_policy_health
|
|
752
744
|
|
|
753
|
-
|
|
754
|
-
data['max_results'] = max_results
|
|
745
|
+
return self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
755
746
|
|
|
756
|
-
return self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
757
747
|
|
|
758
748
|
def objects_workload_agent_upgrade(self, workload_href: str, target_version: str):
|
|
759
749
|
path = '{}/upgrade'.format(workload_href)
|
|
@@ -1001,14 +991,11 @@ class APIConnector:
|
|
|
1001
991
|
path = '/workloads/bulk_create'
|
|
1002
992
|
return self.do_put_call(path=path, json_arguments=workloads_json_payload)
|
|
1003
993
|
|
|
1004
|
-
def objects_service_get(self, max_results: int = None, async_mode=
|
|
994
|
+
def objects_service_get(self, max_results: int = None, async_mode=False):
|
|
1005
995
|
path = '/sec_policy/draft/services'
|
|
1006
996
|
data = {}
|
|
1007
997
|
|
|
1008
|
-
|
|
1009
|
-
data['max_results'] = max_results
|
|
1010
|
-
|
|
1011
|
-
return self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
998
|
+
return self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
1012
999
|
|
|
1013
1000
|
def objects_service_delete(self, href):
|
|
1014
1001
|
"""
|
|
@@ -1050,14 +1037,11 @@ class APIConnector:
|
|
|
1050
1037
|
|
|
1051
1038
|
return self.do_post_call(path=path, async_call=False, include_org_id=False, json_arguments=data, json_output_expected=True)
|
|
1052
1039
|
|
|
1053
|
-
def objects_ruleset_get(self, max_results: int = None, async_mode=
|
|
1040
|
+
def objects_ruleset_get(self, max_results: int = None, async_mode=False) -> List[RulesetObjectJsonStructure]:
|
|
1054
1041
|
path = '/sec_policy/draft/rule_sets'
|
|
1055
1042
|
data = {}
|
|
1056
1043
|
|
|
1057
|
-
|
|
1058
|
-
data['max_results'] = max_results
|
|
1059
|
-
|
|
1060
|
-
return self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
1044
|
+
return self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
1061
1045
|
|
|
1062
1046
|
def objects_ruleset_create(self, name: str,
|
|
1063
1047
|
scope_app: 'pylo.Label' = None,
|
|
@@ -1176,14 +1160,11 @@ class APIConnector:
|
|
|
1176
1160
|
|
|
1177
1161
|
return self.do_post_call(path, json_arguments=data, json_output_expected=True, include_org_id=False)
|
|
1178
1162
|
|
|
1179
|
-
def objects_securityprincipal_get(self, max_results: int = None, async_mode=
|
|
1163
|
+
def objects_securityprincipal_get(self, max_results: int = None, async_mode=False) -> List[SecurityPrincipalObjectJsonStructure]:
|
|
1180
1164
|
path = '/security_principals'
|
|
1181
1165
|
data = {}
|
|
1182
1166
|
|
|
1183
|
-
|
|
1184
|
-
data['max_results'] = max_results
|
|
1185
|
-
|
|
1186
|
-
return self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
1167
|
+
return self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
1187
1168
|
|
|
1188
1169
|
def objects_securityprincipal_create(self, name: str = None, sid: str = None, json_data=None) -> str:
|
|
1189
1170
|
"""
|
|
@@ -1338,12 +1319,23 @@ class APIConnector:
|
|
|
1338
1319
|
|
|
1339
1320
|
raise pylo.PyloObjectNotFound("Request with ID {} not found".format(request_href))
|
|
1340
1321
|
|
|
1341
|
-
def explorer_search(self, filters: Union[Dict, 'pylo.ExplorerFilterSetV1'],
|
|
1342
|
-
max_running_time_seconds=1800,
|
|
1343
|
-
|
|
1322
|
+
def explorer_search(self, filters: Union[Dict, 'pylo.ExplorerFilterSetV1', 'pylo.ExplorerFilterSetV2'],
|
|
1323
|
+
max_running_time_seconds=1800,check_for_update_interval_seconds=10, draft_mode_enabled=False)\
|
|
1324
|
+
-> Union['pylo.ExplorerResultSetV1', 'pylo.ExplorerResultSetV2']:
|
|
1325
|
+
"""
|
|
1326
|
+
|
|
1327
|
+
:param filters:
|
|
1328
|
+
:param max_running_time_seconds:
|
|
1329
|
+
:param check_for_update_interval_seconds:
|
|
1330
|
+
:param draft_mode_enabled: only for V2 filters
|
|
1331
|
+
:return:
|
|
1332
|
+
"""
|
|
1333
|
+
|
|
1344
1334
|
path = "/traffic_flows/async_queries"
|
|
1345
1335
|
if isinstance(filters, pylo.ExplorerFilterSetV1):
|
|
1346
1336
|
data = filters.generate_json_query()
|
|
1337
|
+
elif isinstance(filters, pylo.ExplorerFilterSetV2):
|
|
1338
|
+
data = filters.generate_json_query()
|
|
1347
1339
|
else:
|
|
1348
1340
|
data = filters
|
|
1349
1341
|
|
|
@@ -1388,11 +1380,45 @@ class APIConnector:
|
|
|
1388
1380
|
if query_status is None:
|
|
1389
1381
|
raise pylo.PyloEx("Unexpected logic where query_status is None", query_queued_json_response)
|
|
1390
1382
|
|
|
1391
|
-
|
|
1383
|
+
# if draft mode is not enabled we can download the results and pass them over
|
|
1384
|
+
if not draft_mode_enabled or isinstance(filters, pylo.ExplorerFilterSetV1):
|
|
1385
|
+
query_json_response = self.do_get_call(query_href + "/download", json_output_expected=True, include_org_id=False)
|
|
1392
1386
|
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1387
|
+
if isinstance(filters, pylo.ExplorerFilterSetV1):
|
|
1388
|
+
result = pylo.ExplorerResultSetV1(query_json_response,
|
|
1389
|
+
owner=self,
|
|
1390
|
+
emulated_process_exclusion=filters.exclude_processes_emulate)
|
|
1391
|
+
else:
|
|
1392
|
+
result = pylo.ExplorerResultSetV2(query_json_response)
|
|
1393
|
+
|
|
1394
|
+
return result
|
|
1395
|
+
|
|
1396
|
+
# from here we are in draft mode with V2 filters so we must request API to calculate the draft results
|
|
1397
|
+
draft_mode_trigger_url = query_href + "/update_rules?label_based_rules=false&offset=0&limit=250000"
|
|
1398
|
+
draft_mode_trigger_response = self.do_put_call(draft_mode_trigger_url, json_output_expected=False, include_org_id=False)
|
|
1399
|
+
|
|
1400
|
+
time.sleep(5) # wait a bit before checking for results
|
|
1401
|
+
|
|
1402
|
+
while True:
|
|
1403
|
+
# check that we don't wait too long
|
|
1404
|
+
if time.time() - start_time > max_running_time_seconds:
|
|
1405
|
+
raise pylo.PyloApiEx("Timeout while waiting for draft mode results to be calculated", draft_mode_trigger_response)
|
|
1406
|
+
|
|
1407
|
+
draft_mode_status_response = self.explorer_async_query_get_specific_request_status(query_href)
|
|
1408
|
+
if draft_mode_status_response['rules'] == "completed":
|
|
1409
|
+
query_status = draft_mode_status_response
|
|
1410
|
+
break
|
|
1411
|
+
|
|
1412
|
+
if draft_mode_status_response['rules'] not in ["queued", "working"]:
|
|
1413
|
+
raise pylo.PyloApiEx("Draft mode results calculation failed with status {}".format(draft_mode_status_response['status']),
|
|
1414
|
+
draft_mode_status_response)
|
|
1415
|
+
|
|
1416
|
+
time.sleep(check_for_update_interval_seconds)
|
|
1417
|
+
|
|
1418
|
+
if query_status is None:
|
|
1419
|
+
raise pylo.PyloEx("Unexpected logic where query_status is None", query_queued_json_response)
|
|
1420
|
+
query_json_response = self.do_get_call(query_href + "/download", json_output_expected=True, include_org_id=False)
|
|
1421
|
+
result = pylo.ExplorerResultSetV2(query_json_response)
|
|
1396
1422
|
|
|
1397
1423
|
return result
|
|
1398
1424
|
|
|
@@ -1422,6 +1448,12 @@ class APIConnector:
|
|
|
1422
1448
|
check_for_update_interval_seconds: int = 10) -> 'pylo.ExplorerQuery':
|
|
1423
1449
|
return pylo.ExplorerQuery(self, max_results, max_running_time_seconds, check_for_update_interval_seconds)
|
|
1424
1450
|
|
|
1451
|
+
def new_explorer_query_v2(self, max_results: int = 2500, draft_mode_enabled=False, max_running_time_seconds: int = 1800,
|
|
1452
|
+
check_for_update_interval_seconds: int = 10) -> 'pylo.ExplorerQueryV2':
|
|
1453
|
+
return pylo.ExplorerQueryV2(self, max_results=max_results, draft_mode_enabled=draft_mode_enabled,
|
|
1454
|
+
max_running_time_seconds=max_running_time_seconds,
|
|
1455
|
+
check_for_update_interval_seconds=check_for_update_interval_seconds)
|
|
1456
|
+
|
|
1425
1457
|
def new_audit_log_query(self, max_results: int = 10000, max_running_time_seconds: int = 1800,
|
|
1426
1458
|
check_for_update_interval_seconds: int = 10) -> 'pylo.AuditLogQuery':
|
|
1427
1459
|
return pylo.AuditLogQuery(self, max_results, max_running_time_seconds)
|