illumio-pylo 0.3.9__tar.gz → 0.3.11__tar.gz
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-0.3.9 → illumio_pylo-0.3.11}/.github/workflows/python-publish.yml +2 -2
- {illumio_pylo-0.3.9/illumio_pylo.egg-info → illumio_pylo-0.3.11}/PKG-INFO +9 -3
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/API/APIConnector.py +65 -8
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/API/Explorer.py +44 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/API/JsonPayloadTypes.py +39 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/IPList.py +15 -8
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/IPMap.py +9 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/__init__.py +1 -1
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/__init__.py +1 -0
- illumio_pylo-0.3.11/illumio_pylo/cli/commands/label_delete_unused.py +82 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/ven_duplicate_remover.py +72 -40
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11/illumio_pylo.egg-info}/PKG-INFO +9 -3
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo.egg-info/SOURCES.txt +1 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo.egg-info/requires.txt +1 -1
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/requirements.txt +1 -1
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/.devcontainer/Dockerfile +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/.devcontainer/devcontainer.json +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/.gitattributes +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/.github/workflows/doxygen-publish.yml +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/.github/workflows/make-binaries.yml +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/.gitignore +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/LICENSE +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/README.md +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/check_unique_hostnames.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/check_unique_services.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/delete_all_workloads.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/delete_unused_services.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/explorer_report_exporter.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/export_rules_to_firewall.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/generate-random-workloads.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/healthcheck_log.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/import-labels.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/import_workloads_placeholders.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/iplists_stats_duplicates_unused_finder.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/recalculate_explorer_logs.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/recalculate_explorer_logs_multithreaded.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/rules_exporter.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/rules_exporter_special.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/test.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/test_change_workload_desc.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/test_query.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/test_query2.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/test_securityprincipals.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/ven_idle_to_illumination.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/ven_reassign_pce.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/examples/explorer_query.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/examples/extend_cli.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/API/AuditLog.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/API/ClusterHealth.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/API/CredentialsManager.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/API/RuleSearchQuery.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/API/__init__.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/AgentStore.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/Exception.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/Helpers/__init__.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/Helpers/exports.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/Helpers/functions.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/Label.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/LabelCommon.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/LabelGroup.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/LabelStore.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/LabeledObject.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/Organization.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/Query.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/ReferenceTracker.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/Rule.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/Ruleset.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/RulesetStore.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/SecurityPrincipal.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/Service.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/SoftwareVersion.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/VirtualService.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/VirtualServiceStore.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/Workload.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/WorkloadStore.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/WorkloadStoreSubClasses.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/NativeParsers.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/__init__.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/__main__.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/credential_manager.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/iplist_analyzer.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/iplist_import_from_file.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/ruleset_export.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/update_pce_objects_cache.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/utils/LabelCreation.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/utils/__init__.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/utils/misc.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/ven_compatibility_report_export.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/ven_idle_to_visibility.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/ven_upgrader.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/workload_export.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/workload_import.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/workload_reset_names_to_null.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/workload_update.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/workload_used_in_rule_finder.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/docs/Doxygen +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/tmp.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/utilities/__init__.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/utilities/cli.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/utilities/credentials.example.json +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/utilities/health_monitoring.py +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/utilities/resources/iplists-import-example.csv +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/utilities/resources/iplists-import-example.xlsx +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/utilities/resources/workload-exporter-filter-example.csv +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/utilities/resources/workloads-import-example.csv +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/utilities/resources/workloads-import-example.xlsx +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo.egg-info/dependency_links.txt +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo.egg-info/top_level.txt +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/pyproject.toml +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/setup.cfg +0 -0
- {illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/setup.py +0 -0
|
@@ -26,10 +26,10 @@ jobs:
|
|
|
26
26
|
python-version: '3.11'
|
|
27
27
|
- name: Install dependencies
|
|
28
28
|
run: |
|
|
29
|
-
python -m pip install --upgrade pip
|
|
29
|
+
python -m pip install --upgrade pip setuptools wheel twine pkginfo
|
|
30
30
|
pip install build
|
|
31
31
|
- name: Build package
|
|
32
32
|
run: python -m build
|
|
33
33
|
- name: Publish package
|
|
34
|
-
uses: pypa/gh-action-pypi-publish@
|
|
34
|
+
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
|
|
35
35
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: illumio_pylo
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.11
|
|
4
4
|
Summary: A set of tools and library for working with Illumio PCE
|
|
5
5
|
Home-page: https://github.com/cpainchaud/pylo
|
|
6
6
|
Author: Christophe Painchaud
|
|
@@ -187,11 +187,17 @@ Requires-Python: >=3.11
|
|
|
187
187
|
License-File: LICENSE
|
|
188
188
|
Requires-Dist: click==8.1.7
|
|
189
189
|
Requires-Dist: colorama~=0.4.4
|
|
190
|
-
Requires-Dist: cryptography==
|
|
190
|
+
Requires-Dist: cryptography==44.0.1
|
|
191
191
|
Requires-Dist: openpyxl~=3.1.3
|
|
192
192
|
Requires-Dist: paramiko~=3.4.0
|
|
193
193
|
Requires-Dist: prettytable~=3.10.0
|
|
194
194
|
Requires-Dist: requests~=2.32.0
|
|
195
195
|
Requires-Dist: xlsxwriter~=3.2.0
|
|
196
|
+
Dynamic: author
|
|
197
|
+
Dynamic: author-email
|
|
198
|
+
Dynamic: description
|
|
199
|
+
Dynamic: home-page
|
|
200
|
+
Dynamic: license-file
|
|
201
|
+
Dynamic: requires-python
|
|
196
202
|
|
|
197
203
|
README.md
|
|
@@ -69,14 +69,14 @@ class APIConnector:
|
|
|
69
69
|
if type(port) is int:
|
|
70
70
|
port = str(port)
|
|
71
71
|
self.port: int = port
|
|
72
|
-
self._api_key: str = api_key
|
|
73
|
-
self._decrypted_api_key: Optional[str] = None
|
|
74
72
|
self.api_user: str = api_user
|
|
73
|
+
self._api_key: str = api_key
|
|
74
|
+
self._decrypted_api_key: Optional[str] = None # if api_key is encrypted, this will hold the decrypted value after first use
|
|
75
75
|
self.org_id: int = org_id
|
|
76
76
|
self.skipSSLCertCheck: bool = skip_ssl_cert_check
|
|
77
77
|
self.version: Optional['pylo.SoftwareVersion'] = None
|
|
78
78
|
self.version_string: str = "Not Defined"
|
|
79
|
-
self._cached_session = requests.
|
|
79
|
+
self._cached_session = requests.sessions.Session()
|
|
80
80
|
|
|
81
81
|
@property
|
|
82
82
|
def api_key(self):
|
|
@@ -533,13 +533,19 @@ class APIConnector:
|
|
|
533
533
|
params = {'include_deny_rules': include_boundary_rules}
|
|
534
534
|
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
535
|
|
|
536
|
-
def objects_label_get(self, max_results: int = None, async_mode=True) -> List[LabelObjectJsonStructure]:
|
|
536
|
+
def objects_label_get(self, max_results: int = None, async_mode=True, get_usage: bool = False, get_deleted: bool = False) -> List[LabelObjectJsonStructure]:
|
|
537
537
|
path = '/labels'
|
|
538
538
|
data = {}
|
|
539
539
|
|
|
540
540
|
if max_results is not None:
|
|
541
541
|
data['max_results'] = max_results
|
|
542
542
|
|
|
543
|
+
if get_usage:
|
|
544
|
+
data['usage'] = 'true'
|
|
545
|
+
|
|
546
|
+
if get_deleted:
|
|
547
|
+
data['includeDeleted'] = 'true'
|
|
548
|
+
|
|
543
549
|
return self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
544
550
|
|
|
545
551
|
def objects_label_update(self, href: str, data: LabelObjectUpdateJsonStructure):
|
|
@@ -553,6 +559,60 @@ class APIConnector:
|
|
|
553
559
|
|
|
554
560
|
return self.do_delete_call(path=path, json_output_expected=False, include_org_id=False)
|
|
555
561
|
|
|
562
|
+
class LabelMultiDeleteTracker:
|
|
563
|
+
_errors: Dict[str, str]
|
|
564
|
+
_hrefs: Dict[str, bool]
|
|
565
|
+
_labels: Dict[str, 'pylo.Label'] # dict of workloads by HREF
|
|
566
|
+
connector: 'pylo.APIConnector'
|
|
567
|
+
|
|
568
|
+
def __init__(self, connector: 'pylo.APIConnector'):
|
|
569
|
+
self.connector = connector
|
|
570
|
+
self._errors: Dict[str, Union[bool, str]] = {}
|
|
571
|
+
self._hrefs: Dict[str, str] = {}
|
|
572
|
+
self._labels: Dict[str, 'pylo.Label'] = {}
|
|
573
|
+
|
|
574
|
+
def add_label(self, label_or_href: Union['pylo.Label', str]):
|
|
575
|
+
if type(label_or_href) is str:
|
|
576
|
+
self._hrefs[label_or_href] = True
|
|
577
|
+
return
|
|
578
|
+
self._labels[label_or_href.href] = label_or_href
|
|
579
|
+
self._hrefs[label_or_href.href] = True
|
|
580
|
+
|
|
581
|
+
def execute_deletion(self):
|
|
582
|
+
for href in self._hrefs.keys():
|
|
583
|
+
try:
|
|
584
|
+
self.connector.objects_label_delete(href)
|
|
585
|
+
self._errors[href] = False
|
|
586
|
+
except Exception as e:
|
|
587
|
+
self._errors[href] = str(e)
|
|
588
|
+
|
|
589
|
+
return self._errors
|
|
590
|
+
|
|
591
|
+
def has_errors(self) -> bool:
|
|
592
|
+
for href in self._errors.keys():
|
|
593
|
+
if self._errors[href] is not False:
|
|
594
|
+
return True
|
|
595
|
+
return False
|
|
596
|
+
|
|
597
|
+
def get_errors_count(self) -> int:
|
|
598
|
+
count = 0
|
|
599
|
+
for href in self._errors.keys():
|
|
600
|
+
if self._errors[href] is not False:
|
|
601
|
+
count += 1
|
|
602
|
+
return count
|
|
603
|
+
|
|
604
|
+
def get_error(self, label_or_href: Union['pylo.Label', str]) -> Optional[str]:
|
|
605
|
+
href = label_or_href
|
|
606
|
+
if type(label_or_href) is pylo.Label:
|
|
607
|
+
href = label_or_href.href
|
|
608
|
+
error = self._errors.get(href, None)
|
|
609
|
+
if error is None or error is False:
|
|
610
|
+
return None
|
|
611
|
+
return error
|
|
612
|
+
|
|
613
|
+
def new_tracker_for_label_multi_deletion(self) -> 'pylo.APIConnector.LabelMultiDeleteTracker':
|
|
614
|
+
return pylo.APIConnector.LabelMultiDeleteTracker(self)
|
|
615
|
+
|
|
556
616
|
def objects_label_create(self, label_name: str, label_type: str):
|
|
557
617
|
path = '/labels'
|
|
558
618
|
data: LabelObjectCreationJsonStructure = {'key': label_type, 'value': label_name}
|
|
@@ -1378,7 +1438,4 @@ class APIConnector:
|
|
|
1378
1438
|
def get_pce_ui_workload_url(self, href: str) -> str:
|
|
1379
1439
|
# extract UUID from workload HREF:
|
|
1380
1440
|
uuid = href.split('/')[-1]
|
|
1381
|
-
return self._make_base_url('/#/workloads/' + uuid
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1441
|
+
return self._make_base_url('/#/workloads/' + uuid)
|
|
@@ -6,6 +6,7 @@ import illumio_pylo as pylo
|
|
|
6
6
|
from .JsonPayloadTypes import RuleCoverageQueryEntryJsonStructure
|
|
7
7
|
from illumio_pylo.API.APIConnector import APIConnector
|
|
8
8
|
|
|
9
|
+
|
|
9
10
|
class ExplorerResult:
|
|
10
11
|
_draft_mode_policy_decision: Optional[Literal['allowed', 'blocked', 'blocked_by_boundary']]
|
|
11
12
|
destination_workload_labels_href: List[str]
|
|
@@ -375,6 +376,15 @@ class RuleCoverageQueryManager:
|
|
|
375
376
|
if log_id not in self.service_index_to_log_ids[service_index]:
|
|
376
377
|
self.service_index_to_log_ids[service_index].append(log_id)
|
|
377
378
|
|
|
379
|
+
def get_allow_rules_for_log_id(self, log_id: int):
|
|
380
|
+
rules = []
|
|
381
|
+
for service_id, list_of_log_ids in self.service_index_to_log_ids.items():
|
|
382
|
+
if log_id in list_of_log_ids:
|
|
383
|
+
policy_coverage = self.service_index_policy_coverage[service_id]
|
|
384
|
+
for rule in policy_coverage:
|
|
385
|
+
rules.append(rule)
|
|
386
|
+
return rules
|
|
387
|
+
|
|
378
388
|
def get_policy_decision_for_log_id(self, log_id: int) -> Optional[Literal['allowed', 'blocked', 'blocked_by_boundary']]:
|
|
379
389
|
policy_decision = None
|
|
380
390
|
found_boundary_block = False
|
|
@@ -406,6 +416,9 @@ class RuleCoverageQueryManager:
|
|
|
406
416
|
def add_service(self, service_record: Dict, log_id: int):
|
|
407
417
|
self.services.add_service(service_record, log_id)
|
|
408
418
|
|
|
419
|
+
def get_allow_rules_for_log_id(self, log_id: int) -> List[str]:
|
|
420
|
+
return self.services.get_allow_rules_for_log_id(log_id)
|
|
421
|
+
|
|
409
422
|
def get_policy_decision_for_log_id(self, log_id: int) -> Optional[Literal['allowed', 'blocked', 'blocked_by_boundary']]:
|
|
410
423
|
return self.services.get_policy_decision_for_log_id(log_id)
|
|
411
424
|
|
|
@@ -511,6 +524,19 @@ class RuleCoverageQueryManager:
|
|
|
511
524
|
# print(f'Processing deny_edge {edge} against query {query.src_workload_href} -> {query.dst_workload_href} -> {len(query.services.services_array)}')
|
|
512
525
|
query.process_response_boundary_deny(deny_rules, edge)
|
|
513
526
|
|
|
527
|
+
def get_allow_rules_for_log_id(self, log_id: int) -> List[str]:
|
|
528
|
+
rules = []
|
|
529
|
+
for query in self.queries.values():
|
|
530
|
+
results = query.get_allow_rules_for_log_id(log_id)
|
|
531
|
+
if results is not None:
|
|
532
|
+
for rule_dict in results:
|
|
533
|
+
rules.append(rule_dict['href'])
|
|
534
|
+
|
|
535
|
+
# make them unique
|
|
536
|
+
rules = list(set(rules))
|
|
537
|
+
|
|
538
|
+
return rules
|
|
539
|
+
|
|
514
540
|
def get_policy_decision_for_log_id(self, log_id: int) -> Optional[Literal["allowed", "blocked", "blocked_by_boundary"]]:
|
|
515
541
|
policy_decision: Optional[Literal["allowed", "blocked", "blocked_by_boundary"]] = None
|
|
516
542
|
found_blocked_by_boundary = False
|
|
@@ -615,6 +641,24 @@ class RuleCoverageQueryManager:
|
|
|
615
641
|
|
|
616
642
|
return len(_log_ids)
|
|
617
643
|
|
|
644
|
+
def get_allow_rules_for_log(self, log: ExplorerResult) -> List[str]:
|
|
645
|
+
log_id = self.log_to_id[log]
|
|
646
|
+
if log_id is None:
|
|
647
|
+
raise pylo.PyloEx('No log_id found for log', log)
|
|
648
|
+
|
|
649
|
+
rules: List[str] = []
|
|
650
|
+
|
|
651
|
+
rules.extend(self.iplist_to_workload_query_manager.get_allow_rules_for_log_id(log_id))
|
|
652
|
+
rules.extend(self.workload_to_iplist_query_manager.get_allow_rules_for_log_id(log_id))
|
|
653
|
+
rules.extend(self.workload_to_workload_query_manager.get_allow_rules_for_log_id(log_id))
|
|
654
|
+
|
|
655
|
+
# make them unique
|
|
656
|
+
rules = list(set(rules))
|
|
657
|
+
|
|
658
|
+
return rules
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
|
|
618
662
|
def _get_policy_decision_for_log_id(self, log_id: int) -> Optional[Literal['allowed', 'blocked', 'blocked_by_boundary']]:
|
|
619
663
|
decision = self.iplist_to_workload_query_manager.get_policy_decision_for_log_id(log_id)
|
|
620
664
|
if decision == 'allowed':
|
|
@@ -25,6 +25,26 @@ class ServiceHrefRef(TypedDict):
|
|
|
25
25
|
class VirtualServiceHrefRef(TypedDict):
|
|
26
26
|
virtual_service: HrefReference
|
|
27
27
|
|
|
28
|
+
|
|
29
|
+
class LabelObjectUsageJsonStructure(TypedDict):
|
|
30
|
+
virtual_server: bool
|
|
31
|
+
label_group: bool
|
|
32
|
+
static_policy_scopes: bool
|
|
33
|
+
pairing_profile: bool
|
|
34
|
+
permission: bool
|
|
35
|
+
workload: bool
|
|
36
|
+
container_workload: bool
|
|
37
|
+
firewall_coexistence_scope: bool
|
|
38
|
+
containers_inherit_host_policy_scopes: bool
|
|
39
|
+
container_workload_profile: bool
|
|
40
|
+
blocked_connection_reject_scopes: bool
|
|
41
|
+
enforcement_boundary: bool
|
|
42
|
+
loopback_interfaces_in_policy_scopes: bool
|
|
43
|
+
ip_forwarding_enabled_scopes: bool
|
|
44
|
+
rule_hit_count_enabled_scopes: bool
|
|
45
|
+
label_mapping_rule: bool
|
|
46
|
+
virtual_service: bool
|
|
47
|
+
|
|
28
48
|
class LabelObjectJsonStructure(TypedDict):
|
|
29
49
|
created_at: str
|
|
30
50
|
created_by: Optional[HrefReferenceWithName]
|
|
@@ -33,6 +53,7 @@ class LabelObjectJsonStructure(TypedDict):
|
|
|
33
53
|
key: str
|
|
34
54
|
updated_at: str
|
|
35
55
|
updated_by: Optional[HrefReferenceWithName]
|
|
56
|
+
usage: Optional[LabelObjectUsageJsonStructure]
|
|
36
57
|
value: str
|
|
37
58
|
|
|
38
59
|
|
|
@@ -81,6 +102,7 @@ class WorkloadInterfaceObjectJsonStructure(TypedDict):
|
|
|
81
102
|
name: str
|
|
82
103
|
address: str
|
|
83
104
|
|
|
105
|
+
|
|
84
106
|
class WorkloadObjectJsonStructure(TypedDict):
|
|
85
107
|
created_at: str
|
|
86
108
|
created_by: Optional[HrefReferenceWithName]
|
|
@@ -95,6 +117,7 @@ class WorkloadObjectJsonStructure(TypedDict):
|
|
|
95
117
|
updated_at: str
|
|
96
118
|
updated_by: Optional[HrefReferenceWithName]
|
|
97
119
|
|
|
120
|
+
|
|
98
121
|
class WorkloadObjectCreateJsonStructure(TypedDict):
|
|
99
122
|
"""
|
|
100
123
|
This is the structure of the JSON payload for creating a workload.
|
|
@@ -106,14 +129,18 @@ class WorkloadObjectCreateJsonStructure(TypedDict):
|
|
|
106
129
|
name: NotRequired[str]
|
|
107
130
|
public_ip: NotRequired[Optional[str]]
|
|
108
131
|
|
|
132
|
+
|
|
109
133
|
class WorkloadObjectMultiCreateJsonStructure(WorkloadObjectCreateJsonStructure):
|
|
110
134
|
href: str
|
|
111
135
|
|
|
136
|
+
|
|
112
137
|
WorkloadObjectMultiCreateJsonRequestPayload = List[WorkloadObjectMultiCreateJsonStructure]
|
|
113
138
|
|
|
139
|
+
|
|
114
140
|
class WorkloadBulkUpdateEntryJsonStructure(WorkloadObjectCreateJsonStructure):
|
|
115
141
|
href: str
|
|
116
142
|
|
|
143
|
+
|
|
117
144
|
class WorkloadBulkUpdateResponseEntry(TypedDict):
|
|
118
145
|
href: str
|
|
119
146
|
status: Literal['updated', 'error', 'validation_failure']
|
|
@@ -150,11 +177,13 @@ class VenObjectJsonStructure(TypedDict):
|
|
|
150
177
|
os_platform: Optional[str]
|
|
151
178
|
uid: Optional[str]
|
|
152
179
|
|
|
180
|
+
|
|
153
181
|
class VENUnpairApiResponseSingleErrorObjectJsonStructure(TypedDict):
|
|
154
182
|
token: str
|
|
155
183
|
message: str
|
|
156
184
|
hrefs: List[str]
|
|
157
185
|
|
|
186
|
+
|
|
158
187
|
class VENUnpairApiResponseObjectJsonStructure(TypedDict):
|
|
159
188
|
errors: List[VENUnpairApiResponseSingleErrorObjectJsonStructure]
|
|
160
189
|
|
|
@@ -173,6 +202,7 @@ class RuleDirectServiceReferenceObjectJsonStructure(TypedDict):
|
|
|
173
202
|
class RuleObjectJsonStructure(TypedDict):
|
|
174
203
|
created_at: str
|
|
175
204
|
created_by: Optional[HrefReferenceWithName]
|
|
205
|
+
description: str
|
|
176
206
|
href: str
|
|
177
207
|
ingress_services: List[RuleDirectServiceReferenceObjectJsonStructure|RuleServiceReferenceObjectJsonStructure]
|
|
178
208
|
updated_at: str
|
|
@@ -219,26 +249,31 @@ class VirtualServiceObjectJsonStructure(TypedDict):
|
|
|
219
249
|
updated_at: str
|
|
220
250
|
updated_by: Optional[HrefReferenceWithName]
|
|
221
251
|
|
|
252
|
+
|
|
222
253
|
class NetworkDeviceConfigObjectJsonStructure(TypedDict):
|
|
223
254
|
device_type: Literal['switch']
|
|
224
255
|
name: str
|
|
225
256
|
|
|
257
|
+
|
|
226
258
|
class NetworkDeviceObjectJsonStructure(TypedDict):
|
|
227
259
|
href: str
|
|
228
260
|
config: NetworkDeviceConfigObjectJsonStructure
|
|
229
261
|
supported_endpoint_type: Literal['switch_port']
|
|
230
262
|
|
|
263
|
+
|
|
231
264
|
class NetworkDeviceEndpointConfigObjectJsonStructure(TypedDict):
|
|
232
265
|
type: Literal['switch_port']
|
|
233
266
|
name: str
|
|
234
267
|
workload_discovery: bool
|
|
235
268
|
|
|
269
|
+
|
|
236
270
|
class NetworkDeviceEndpointObjectJsonStructure(TypedDict):
|
|
237
271
|
href: str
|
|
238
272
|
config: NetworkDeviceEndpointConfigObjectJsonStructure
|
|
239
273
|
status: Literal['unmonitored', 'monitored']
|
|
240
274
|
workloads: List[HrefReference]
|
|
241
275
|
|
|
276
|
+
|
|
242
277
|
class SecurityPrincipalObjectJsonStructure(TypedDict):
|
|
243
278
|
created_at: str
|
|
244
279
|
created_by: Optional[HrefReferenceWithName]
|
|
@@ -247,6 +282,7 @@ class SecurityPrincipalObjectJsonStructure(TypedDict):
|
|
|
247
282
|
updated_at: str
|
|
248
283
|
updated_by: Optional[HrefReferenceWithName]
|
|
249
284
|
|
|
285
|
+
|
|
250
286
|
class LabelDimensionObjectStructure(TypedDict):
|
|
251
287
|
created_at: str
|
|
252
288
|
created_by: Optional[HrefReferenceWithName]
|
|
@@ -286,13 +322,16 @@ WorkloadsGetQueryLabelFilterJsonStructure = List[List[str]]
|
|
|
286
322
|
|
|
287
323
|
AuditLogApiEventType = Literal['agent.clone_detected', 'workloads.update', 'workload.update', 'workload_interfaces.update']
|
|
288
324
|
|
|
325
|
+
|
|
289
326
|
class AuditLogEntryJsonStructure(TypedDict):
|
|
290
327
|
event_type: AuditLogApiEventType
|
|
291
328
|
timestamp: str
|
|
292
329
|
|
|
330
|
+
|
|
293
331
|
class AuditLogApiRequestPayloadStructure(TypedDict):
|
|
294
332
|
pass
|
|
295
333
|
|
|
334
|
+
|
|
296
335
|
class AuditLogApiReplyEventJsonStructure(TypedDict):
|
|
297
336
|
pass
|
|
298
337
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from .API.JsonPayloadTypes import IPListObjectJsonStructure
|
|
2
|
-
from illumio_pylo import log
|
|
2
|
+
from illumio_pylo import log, IP4Map
|
|
3
3
|
from .Helpers import *
|
|
4
4
|
|
|
5
5
|
|
|
@@ -20,6 +20,7 @@ class IPList(pylo.ReferenceTracker):
|
|
|
20
20
|
self.description = description
|
|
21
21
|
self.raw_json = None
|
|
22
22
|
self.raw_entries = {}
|
|
23
|
+
self._ip4map: IP4Map = None
|
|
23
24
|
|
|
24
25
|
def count_entries(self) -> int:
|
|
25
26
|
return len(self.raw_entries)
|
|
@@ -56,15 +57,21 @@ class IPList(pylo.ReferenceTracker):
|
|
|
56
57
|
self.raw_entries[entry] = entry
|
|
57
58
|
|
|
58
59
|
def get_ip4map(self) -> pylo.IP4Map:
|
|
59
|
-
|
|
60
|
+
return self.ip4map
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
@property
|
|
63
|
+
def ip4map(self) -> pylo.IP4Map:
|
|
64
|
+
if self._ip4map is None:
|
|
65
|
+
new_map = pylo.IP4Map()
|
|
66
|
+
self._ip4map = new_map
|
|
67
|
+
|
|
68
|
+
for entry in self.raw_entries:
|
|
69
|
+
if entry[0] == '!':
|
|
70
|
+
new_map.subtract_from_text(entry[1:], ignore_ipv6=True)
|
|
71
|
+
else:
|
|
72
|
+
new_map.add_from_text(entry, ignore_ipv6=True)
|
|
66
73
|
|
|
67
|
-
return
|
|
74
|
+
return self._ip4map
|
|
68
75
|
|
|
69
76
|
def get_raw_entries_as_string_list(self, separator=',') -> str:
|
|
70
77
|
return pylo.string_list_to_text(self.raw_entries.values(), separator=separator)
|
|
@@ -107,6 +107,15 @@ class IP4Map:
|
|
|
107
107
|
return True
|
|
108
108
|
return False
|
|
109
109
|
|
|
110
|
+
def match_single_ip(self, ip: str) -> bool:
|
|
111
|
+
ip_object = ipaddress.IPv4Address(ip)
|
|
112
|
+
for entry in self._entries:
|
|
113
|
+
if entry[start] <= int(ip_object) <= entry[end]:
|
|
114
|
+
return True
|
|
115
|
+
if entry[start] > int(ip_object):
|
|
116
|
+
return False
|
|
117
|
+
return False
|
|
118
|
+
|
|
110
119
|
def substract(self, another_map: 'IP4Map'):
|
|
111
120
|
affected_rows = 0
|
|
112
121
|
for entry in another_map._entries:
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
from typing import Optional, List
|
|
3
|
+
|
|
4
|
+
import illumio_pylo as pylo
|
|
5
|
+
import json
|
|
6
|
+
import hashlib
|
|
7
|
+
|
|
8
|
+
from illumio_pylo import log
|
|
9
|
+
from . import Command
|
|
10
|
+
from illumio_pylo.API.JsonPayloadTypes import LabelObjectJsonStructure
|
|
11
|
+
|
|
12
|
+
command_name = "label-delete-unused"
|
|
13
|
+
objects_load_filter = [] # No need to load any objects from PCE
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def fill_parser(parser: argparse.ArgumentParser):
|
|
17
|
+
parser.add_argument('--confirm', action='store_true',
|
|
18
|
+
help='No change will be implemented in the PCE until you use this function to confirm you\'re good with them after review')
|
|
19
|
+
parser.add_argument('--limit', type=int, required=False, default=None,
|
|
20
|
+
help='Maximum number of unused labels to delete (default: all found unused labels)')
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def __main(args, org: pylo.Organization = None, connector: pylo.APIConnector = None, config_data=None, **kwargs):
|
|
24
|
+
|
|
25
|
+
settings_confirmed_changes: bool = args['confirm']
|
|
26
|
+
settings_limit_deletions: Optional[int] = args['limit']
|
|
27
|
+
|
|
28
|
+
print("Fetching all Labels from the PCE... ", end='', flush=True)
|
|
29
|
+
# pylo.log_set_debug()
|
|
30
|
+
labels_json = connector.objects_label_get(max_results=199000, get_usage=True, async_mode=False)
|
|
31
|
+
print("OK!")
|
|
32
|
+
|
|
33
|
+
print(f"Analyzing {len(labels_json)} labels to find unused ones... ")
|
|
34
|
+
unused_labels: List[LabelObjectJsonStructure] = []
|
|
35
|
+
|
|
36
|
+
for label_json in labels_json:
|
|
37
|
+
usage_json = label_json.get('usage', {})
|
|
38
|
+
label_is_used = False
|
|
39
|
+
|
|
40
|
+
for usage_type, usage_confirmed in usage_json.items():
|
|
41
|
+
if usage_confirmed:
|
|
42
|
+
label_is_used = True
|
|
43
|
+
print(f"Label '{label_json.get('value')}' is used in '{usage_type}', skipping deletion.")
|
|
44
|
+
break
|
|
45
|
+
|
|
46
|
+
if not label_is_used:
|
|
47
|
+
print(f"Label '{label_json.get('value')}' is unused, marking for deletion.")
|
|
48
|
+
unused_labels.append(label_json)
|
|
49
|
+
|
|
50
|
+
print()
|
|
51
|
+
print(f"Found {len(unused_labels)} unused labels vs total of {len(labels_json)} labels.")
|
|
52
|
+
|
|
53
|
+
if len(unused_labels) > 0:
|
|
54
|
+
if not settings_confirmed_changes:
|
|
55
|
+
print("No change will be implemented in the PCE until you use the '--confirm' flag to confirm you're good with them after review.")
|
|
56
|
+
else:
|
|
57
|
+
print()
|
|
58
|
+
print(f"Proceeding to delete unused labels up to the limit of '{settings_limit_deletions if settings_limit_deletions is not None else 'all'}'...")
|
|
59
|
+
tracker = connector.new_tracker_for_label_multi_deletion()
|
|
60
|
+
|
|
61
|
+
if settings_limit_deletions is not None:
|
|
62
|
+
unused_labels = unused_labels[:settings_limit_deletions]
|
|
63
|
+
|
|
64
|
+
for label_json in unused_labels:
|
|
65
|
+
tracker.add_label(label_json['href'])
|
|
66
|
+
|
|
67
|
+
tracker.execute_deletion()
|
|
68
|
+
errors_count = tracker.get_errors_count()
|
|
69
|
+
success_count = len(unused_labels) - errors_count
|
|
70
|
+
|
|
71
|
+
for label_json in unused_labels:
|
|
72
|
+
error = tracker.get_error(label_json['href'])
|
|
73
|
+
if error is not None:
|
|
74
|
+
print(f" - ERROR deleting label '{label_json.get('value')}': {error}")
|
|
75
|
+
else:
|
|
76
|
+
print(f" - SUCCESS deleting label '{label_json.get('value')}'")
|
|
77
|
+
|
|
78
|
+
print()
|
|
79
|
+
print(f"Deletion completed: {success_count} labels deleted successfully, {errors_count} errors encountered.")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
command_object = Command(command_name, __main, fill_parser, skip_pce_config_loading=True, load_specific_objects_only=objects_load_filter)
|
{illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/ven_duplicate_remover.py
RENAMED
|
@@ -4,7 +4,7 @@ import click
|
|
|
4
4
|
import argparse
|
|
5
5
|
|
|
6
6
|
import illumio_pylo as pylo
|
|
7
|
-
from illumio_pylo import ExcelHeader
|
|
7
|
+
from illumio_pylo import ExcelHeader, nice_json
|
|
8
8
|
|
|
9
9
|
from .utils.misc import make_filename_with_timestamp
|
|
10
10
|
from . import Command
|
|
@@ -134,8 +134,8 @@ def __main(args, org: pylo.Organization, pce_cache_was_used: bool, **kwargs):
|
|
|
134
134
|
url_link_to_pce = workload.get_pce_ui_url()
|
|
135
135
|
new_row = {
|
|
136
136
|
'hostname': workload.hostname,
|
|
137
|
-
'online': workload.online,
|
|
138
|
-
'last_heartbeat': workload.ven_agent.get_last_heartbeat_date().strftime('%Y-%m-%d %H:%M'),
|
|
137
|
+
'online': workload.online if not workload.unmanaged else 'UNMANAGED',
|
|
138
|
+
'last_heartbeat': workload.ven_agent.get_last_heartbeat_date().strftime('%Y-%m-%d %H:%M') if not workload.unmanaged else 'UNMANAGED',
|
|
139
139
|
'created_at': workload.created_at_datetime().strftime('%Y-%m-%d %H:%M'),
|
|
140
140
|
'href': workload.href,
|
|
141
141
|
'link_to_pce': url_link_to_pce,
|
|
@@ -172,48 +172,66 @@ def __main(args, org: pylo.Organization, pce_cache_was_used: bool, **kwargs):
|
|
|
172
172
|
len(dup_record.offline),
|
|
173
173
|
len(dup_record.unmanaged)))
|
|
174
174
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
175
|
+
if not dup_record.has_no_managed_workloads():
|
|
176
|
+
latest_created_workload = dup_record.find_latest_managed_created_at()
|
|
177
|
+
latest_heartbeat_workload = dup_record.find_latest_heartbeat()
|
|
178
178
|
|
|
179
|
-
|
|
180
|
-
print(" - IGNORED: there is no VEN online")
|
|
181
|
-
for wkl in dup_record.offline:
|
|
182
|
-
add_workload_to_report(wkl, "ignored (no VEN online)")
|
|
183
|
-
continue
|
|
179
|
+
print(" - Latest created at {} and latest heartbeat at {}".format(latest_created_workload.created_at, latest_heartbeat_workload.ven_agent.get_last_heartbeat_date()))
|
|
184
180
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
181
|
+
if dup_record.count_online() == 0:
|
|
182
|
+
print(" - IGNORED: there is no VEN online")
|
|
183
|
+
for wkl in dup_record.offline:
|
|
184
|
+
add_workload_to_report(wkl, "ignored (no VEN online)")
|
|
185
|
+
continue
|
|
186
|
+
|
|
187
|
+
if dup_record.count_online() > 1:
|
|
188
|
+
print(" - WARNING: there are more than 1 VEN online")
|
|
189
|
+
|
|
190
|
+
# Don't delete online workloads but still show them in the report
|
|
191
|
+
for wkl in dup_record.online:
|
|
192
|
+
add_workload_to_report(wkl, "ignored (VEN is online)")
|
|
193
|
+
|
|
194
|
+
for wkl in dup_record.offline:
|
|
195
|
+
if arg_do_not_delete_the_most_recent_workload and wkl is latest_created_workload:
|
|
196
|
+
print(" - IGNORED: wkl {}/{} is the most recent".format(wkl.get_name_stripped_fqdn(), wkl.href))
|
|
197
|
+
add_workload_to_report(wkl, "ignored (it is the most recently created)")
|
|
198
|
+
elif arg_do_not_delete_the_most_recently_heartbeating_workload and wkl is latest_heartbeat_workload:
|
|
199
|
+
print(" - IGNORED: wkl {}/{} is the most recently heartbeating".format(wkl.get_name_stripped_fqdn(), wkl.href))
|
|
200
|
+
add_workload_to_report(wkl, "ignored (it is the most recently heartbeating)")
|
|
201
|
+
elif arg_do_not_delete_if_last_heartbeat_is_more_recent_than is not None and wkl.ven_agent.get_last_heartbeat_date() > datetime.datetime.now() - datetime.timedelta(days=arg_do_not_delete_if_last_heartbeat_is_more_recent_than):
|
|
202
|
+
print(" - IGNORED: wkl {}/{} has a last heartbeat more recent than {} days".format(wkl.get_name_stripped_fqdn(), wkl.href, arg_do_not_delete_if_last_heartbeat_is_more_recent_than))
|
|
203
|
+
add_workload_to_report(wkl, "ignored (last heartbeat is more recent than {} days)".format(arg_do_not_delete_if_last_heartbeat_is_more_recent_than))
|
|
204
|
+
else:
|
|
205
|
+
if arg_limit_number_of_deleted_workloads is not None and delete_tracker.count_entries() >= arg_limit_number_of_deleted_workloads:
|
|
206
|
+
print(" - IGNORED: wkl {}/{} because the limit of {} workloads to be deleted was reached".format(wkl.get_name_stripped_fqdn(), wkl.href, arg_limit_number_of_deleted_workloads))
|
|
207
|
+
add_workload_to_report(wkl, "ignored (limit of {} workloads to be deleted was reached)".format(arg_limit_number_of_deleted_workloads))
|
|
208
|
+
else:
|
|
209
|
+
delete_tracker.add_workload(wkl)
|
|
210
|
+
print(" - added offline wkl {}/{} to the delete list".format(wkl.get_name_stripped_fqdn(), wkl.href))
|
|
211
|
+
|
|
212
|
+
for wkl in dup_record.unmanaged:
|
|
203
213
|
if arg_limit_number_of_deleted_workloads is not None and delete_tracker.count_entries() >= arg_limit_number_of_deleted_workloads:
|
|
204
214
|
print(" - IGNORED: wkl {}/{} because the limit of {} workloads to be deleted was reached".format(wkl.get_name_stripped_fqdn(), wkl.href, arg_limit_number_of_deleted_workloads))
|
|
205
215
|
add_workload_to_report(wkl, "ignored (limit of {} workloads to be deleted was reached)".format(arg_limit_number_of_deleted_workloads))
|
|
206
216
|
else:
|
|
207
217
|
delete_tracker.add_workload(wkl)
|
|
208
|
-
print(" - added
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
if
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
218
|
+
print(" - added unmanaged wkl {}/{} to the delete list".format(wkl.get_name_stripped_fqdn(), wkl.href))
|
|
219
|
+
else:
|
|
220
|
+
latest_created_workload = dup_record.find_latest_unmanaged_created_at()
|
|
221
|
+
if latest_created_workload is None:
|
|
222
|
+
raise pylo.PyloEx("Internal error: cannot find the latest created unmanaged workload for hostname '{}'".format(dup_hostname))
|
|
223
|
+
print(" - All workloads are unmanaged. Latest created at {} will be kept".format(latest_created_workload.created_at))
|
|
224
|
+
for wkl in dup_record.unmanaged:
|
|
225
|
+
if wkl is latest_created_workload:
|
|
226
|
+
print(" - IGNORED: wkl {}/{} is the most recent".format(wkl.get_name_stripped_fqdn(), wkl.href))
|
|
227
|
+
add_workload_to_report(wkl, "ignored (it is the most recently created)")
|
|
228
|
+
else:
|
|
229
|
+
if arg_limit_number_of_deleted_workloads is not None and delete_tracker.count_entries() >= arg_limit_number_of_deleted_workloads:
|
|
230
|
+
print(" - IGNORED: wkl {}/{} because the limit of {} workloads to be deleted was reached".format(wkl.get_name_stripped_fqdn(), wkl.href, arg_limit_number_of_deleted_workloads))
|
|
231
|
+
add_workload_to_report(wkl, "ignored (limit of {} workloads to be deleted was reached)".format(arg_limit_number_of_deleted_workloads))
|
|
232
|
+
else:
|
|
233
|
+
delete_tracker.add_workload(wkl)
|
|
234
|
+
print(" - added unmanaged wkl {}/{} to the delete list".format(wkl.get_name_stripped_fqdn(), wkl.href))
|
|
217
235
|
|
|
218
236
|
print()
|
|
219
237
|
|
|
@@ -324,7 +342,12 @@ class DuplicateRecordManager:
|
|
|
324
342
|
return True
|
|
325
343
|
return False
|
|
326
344
|
|
|
327
|
-
def
|
|
345
|
+
def has_no_managed_workloads(self):
|
|
346
|
+
if len(self.offline) + len(self.online) == 0:
|
|
347
|
+
return True
|
|
348
|
+
return False
|
|
349
|
+
|
|
350
|
+
def find_latest_managed_created_at(self) -> Optional['pylo.Workload']:
|
|
328
351
|
latest: Optional[pylo.Workload] = None
|
|
329
352
|
for wkl in self.all:
|
|
330
353
|
if wkl.unmanaged:
|
|
@@ -333,7 +356,16 @@ class DuplicateRecordManager:
|
|
|
333
356
|
latest = wkl
|
|
334
357
|
return latest
|
|
335
358
|
|
|
336
|
-
def
|
|
359
|
+
def find_latest_unmanaged_created_at(self) -> Optional['pylo.Workload']:
|
|
360
|
+
latest: Optional[pylo.Workload] = None
|
|
361
|
+
for wkl in self.all:
|
|
362
|
+
if not wkl.unmanaged:
|
|
363
|
+
continue
|
|
364
|
+
if latest is None or wkl.created_at > latest.created_at:
|
|
365
|
+
latest = wkl
|
|
366
|
+
return latest
|
|
367
|
+
|
|
368
|
+
def find_latest_heartbeat(self) -> Optional['pylo.Workload']:
|
|
337
369
|
latest: Optional[pylo.Workload] = None
|
|
338
370
|
for wkl in self.all:
|
|
339
371
|
if wkl.unmanaged:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: illumio_pylo
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.11
|
|
4
4
|
Summary: A set of tools and library for working with Illumio PCE
|
|
5
5
|
Home-page: https://github.com/cpainchaud/pylo
|
|
6
6
|
Author: Christophe Painchaud
|
|
@@ -187,11 +187,17 @@ Requires-Python: >=3.11
|
|
|
187
187
|
License-File: LICENSE
|
|
188
188
|
Requires-Dist: click==8.1.7
|
|
189
189
|
Requires-Dist: colorama~=0.4.4
|
|
190
|
-
Requires-Dist: cryptography==
|
|
190
|
+
Requires-Dist: cryptography==44.0.1
|
|
191
191
|
Requires-Dist: openpyxl~=3.1.3
|
|
192
192
|
Requires-Dist: paramiko~=3.4.0
|
|
193
193
|
Requires-Dist: prettytable~=3.10.0
|
|
194
194
|
Requires-Dist: requests~=2.32.0
|
|
195
195
|
Requires-Dist: xlsxwriter~=3.2.0
|
|
196
|
+
Dynamic: author
|
|
197
|
+
Dynamic: author-email
|
|
198
|
+
Dynamic: description
|
|
199
|
+
Dynamic: home-page
|
|
200
|
+
Dynamic: license-file
|
|
201
|
+
Dynamic: requires-python
|
|
196
202
|
|
|
197
203
|
README.md
|
|
@@ -82,6 +82,7 @@ illumio_pylo/cli/commands/__init__.py
|
|
|
82
82
|
illumio_pylo/cli/commands/credential_manager.py
|
|
83
83
|
illumio_pylo/cli/commands/iplist_analyzer.py
|
|
84
84
|
illumio_pylo/cli/commands/iplist_import_from_file.py
|
|
85
|
+
illumio_pylo/cli/commands/label_delete_unused.py
|
|
85
86
|
illumio_pylo/cli/commands/ruleset_export.py
|
|
86
87
|
illumio_pylo/cli/commands/update_pce_objects_cache.py
|
|
87
88
|
illumio_pylo/cli/commands/ven_compatibility_report_export.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/iplists_stats_duplicates_unused_finder.py
RENAMED
|
File without changes
|
|
File without changes
|
{illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/dev_playground/recalculate_explorer_logs_multithreaded.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/iplist_import_from_file.py
RENAMED
|
File without changes
|
|
File without changes
|
{illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/update_pce_objects_cache.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/ven_idle_to_visibility.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/workload_reset_names_to_null.py
RENAMED
|
File without changes
|
|
File without changes
|
{illumio_pylo-0.3.9 → illumio_pylo-0.3.11}/illumio_pylo/cli/commands/workload_used_in_rule_finder.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|