illumio-pylo 0.3.0__tar.gz → 0.3.2__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.0 → illumio_pylo-0.3.2}/.github/workflows/doxygen-publish.yml +1 -1
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/.github/workflows/make-binaries.yml +21 -20
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/.github/workflows/python-publish.yml +1 -1
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/PKG-INFO +1 -1
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/examples/explorer_query.py +1 -1
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/API/APIConnector.py +12 -8
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/API/CredentialsManager.py +9 -8
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/Helpers/exports.py +77 -63
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/IPMap.py +9 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/LabeledObject.py +1 -1
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/Organization.py +4 -1
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/Rule.py +27 -1
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/Ruleset.py +15 -27
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/Service.py +49 -52
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/__init__.py +1 -1
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/__init__.py +19 -6
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/credential_manager.py +91 -26
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/ruleset_export.py +44 -37
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/utils/misc.py +4 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/ven_compatibility_report_export.py +14 -8
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/ven_duplicate_remover.py +18 -15
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/ven_upgrader.py +10 -78
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/workload_export.py +16 -12
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/workload_import.py +50 -17
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/workload_update.py +3 -2
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/tmp.py +8 -4
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo.egg-info/PKG-INFO +1 -1
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo.egg-info/SOURCES.txt +4 -4
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/.devcontainer/Dockerfile +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/.devcontainer/devcontainer.json +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/.gitattributes +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/.gitignore +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/LICENSE +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/README.md +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/check_unique_hostnames.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/check_unique_services.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/delete_all_workloads.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/delete_unused_services.py +0 -0
- {illumio_pylo-0.3.0/illumio_pylo/utilities → illumio_pylo-0.3.2/dev_playground}/explorer_report_exporter.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/export_rules_to_firewall.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/generate-random-workloads.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/healthcheck_log.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/import-labels.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/import_workloads_placeholders.py +0 -0
- {illumio_pylo-0.3.0/illumio_pylo/utilities → illumio_pylo-0.3.2/dev_playground}/iplists_stats_duplicates_unused_finder.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/recalculate_explorer_logs.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/recalculate_explorer_logs_multithreaded.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/rules_exporter.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/rules_exporter_special.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/test.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/test_change_workload_desc.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/test_query.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/test_query2.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/dev_playground/test_securityprincipals.py +0 -0
- {illumio_pylo-0.3.0/illumio_pylo/utilities → illumio_pylo-0.3.2/dev_playground}/ven_idle_to_illumination.py +0 -0
- {illumio_pylo-0.3.0/illumio_pylo/utilities → illumio_pylo-0.3.2/dev_playground}/ven_reassign_pce.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/examples/extend_cli.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/API/AuditLog.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/API/ClusterHealth.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/API/Explorer.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/API/JsonPayloadTypes.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/API/RuleSearchQuery.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/API/__init__.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/AgentStore.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/Exception.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/Helpers/__init__.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/Helpers/functions.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/IPList.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/Label.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/LabelCommon.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/LabelGroup.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/LabelStore.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/Query.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/ReferenceTracker.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/RulesetStore.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/SecurityPrincipal.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/SoftwareVersion.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/VirtualService.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/VirtualServiceStore.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/Workload.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/WorkloadStore.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/WorkloadStoreSubClasses.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/NativeParsers.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/__main__.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/__init__.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/iplist_analyzer.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/iplist_import_from_file.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/update_pce_objects_cache.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/utils/LabelCreation.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/utils/__init__.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/ven_idle_to_visibility.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/workload_reset_names_to_null.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/cli/commands/workload_used_in_rule_finder.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/docs/Doxygen +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/utilities/__init__.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/utilities/cli.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/utilities/credentials.example.json +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/utilities/health_monitoring.py +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/utilities/resources/iplists-import-example.csv +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/utilities/resources/iplists-import-example.xlsx +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/utilities/resources/workload-exporter-filter-example.csv +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/utilities/resources/workloads-import-example.csv +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo/utilities/resources/workloads-import-example.xlsx +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo.egg-info/dependency_links.txt +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo.egg-info/requires.txt +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/illumio_pylo.egg-info/top_level.txt +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/pyproject.toml +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/requirements.txt +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/setup.cfg +0 -0
- {illumio_pylo-0.3.0 → illumio_pylo-0.3.2}/setup.py +0 -0
|
@@ -15,7 +15,7 @@ jobs:
|
|
|
15
15
|
runs-on: ubuntu-latest
|
|
16
16
|
|
|
17
17
|
steps:
|
|
18
|
-
- uses: actions/checkout@
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
19
|
|
|
20
20
|
- name: Change Pylo Version if this is a DEV build
|
|
21
21
|
if: github.ref == 'refs/heads/dev' && github.event_name == 'push'
|
|
@@ -39,18 +39,6 @@ jobs:
|
|
|
39
39
|
run: |
|
|
40
40
|
mv dist/windows/cli.exe dist/windows/pylo-cli.exe
|
|
41
41
|
|
|
42
|
-
- name: Publish executables for Master branch with 'latest' tag
|
|
43
|
-
# only if this is a TAG type
|
|
44
|
-
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
|
45
|
-
|
|
46
|
-
uses: "marvinpinto/action-automatic-releases@latest"
|
|
47
|
-
with:
|
|
48
|
-
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
|
49
|
-
automatic_release_tag: "latest"
|
|
50
|
-
prerelease: true
|
|
51
|
-
title: "Latest Binaries"
|
|
52
|
-
files: |
|
|
53
|
-
dist/windows/*
|
|
54
42
|
|
|
55
43
|
- name: Publish executables along with the tag for a release
|
|
56
44
|
# only if this is a TAG type
|
|
@@ -64,14 +52,27 @@ jobs:
|
|
|
64
52
|
draft: false
|
|
65
53
|
prerelease: false
|
|
66
54
|
|
|
55
|
+
|
|
56
|
+
- name: Publish executables for Master branch with 'latest' tag
|
|
57
|
+
# only if this is a TAG type
|
|
58
|
+
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
|
59
|
+
uses: "crowbarmaster/GH-Automatic-Releases@latest"
|
|
60
|
+
with:
|
|
61
|
+
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
|
62
|
+
automatic_release_tag: "latest"
|
|
63
|
+
prerelease: true
|
|
64
|
+
title: "Latest Binaries"
|
|
65
|
+
files: |
|
|
66
|
+
dist/windows/*
|
|
67
|
+
|
|
68
|
+
|
|
67
69
|
- name: Publish executables for Dev branch
|
|
68
70
|
if: github.ref == 'refs/heads/dev' && github.event_name == 'push'
|
|
69
|
-
uses:
|
|
71
|
+
uses: "crowbarmaster/GH-Automatic-Releases@latest"
|
|
70
72
|
with:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
draft: false
|
|
73
|
+
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
|
74
|
+
automatic_release_tag: "dev-latest"
|
|
74
75
|
prerelease: false
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
title: "Latest Binaries for DEV/Unstable branch"
|
|
77
|
+
files: |
|
|
78
|
+
dist/windows/*
|
|
@@ -60,7 +60,7 @@ explorer_query.filters.set_time_from_x_days_ago(5)
|
|
|
60
60
|
# Query the PCE for traffic logs matching the filter
|
|
61
61
|
print("Querying PCE for traffic logs matching the filter... ", end='', flush=True)
|
|
62
62
|
traffic_logs = explorer_query.execute()
|
|
63
|
-
print("OK! found {} traffic logs".format(traffic_logs.
|
|
63
|
+
print("OK! found {} traffic logs".format(traffic_logs.count_records()))
|
|
64
64
|
|
|
65
65
|
# Print the results
|
|
66
66
|
records = traffic_logs.get_all_records()
|
|
@@ -2,7 +2,7 @@ import json
|
|
|
2
2
|
import time
|
|
3
3
|
import getpass
|
|
4
4
|
|
|
5
|
-
from .CredentialsManager import is_api_key_encrypted, decrypt_api_key
|
|
5
|
+
from .CredentialsManager import is_api_key_encrypted, decrypt_api_key, CredentialProfile
|
|
6
6
|
from .JsonPayloadTypes import LabelGroupObjectJsonStructure, LabelObjectCreationJsonStructure, \
|
|
7
7
|
LabelObjectJsonStructure, LabelObjectUpdateJsonStructure, PCEObjectsJsonStructure, \
|
|
8
8
|
LabelGroupObjectUpdateJsonStructure, IPListObjectCreationJsonStructure, IPListObjectJsonStructure, \
|
|
@@ -108,6 +108,12 @@ class APIConnector:
|
|
|
108
108
|
def get_all_object_types():
|
|
109
109
|
return all_object_types.copy()
|
|
110
110
|
|
|
111
|
+
@staticmethod
|
|
112
|
+
def create_from_credentials_object(credentials: CredentialProfile) -> Optional['APIConnector']:
|
|
113
|
+
return APIConnector(credentials.fqdn, credentials.port, credentials.api_user,
|
|
114
|
+
credentials.api_key, skip_ssl_cert_check=not credentials.verify_ssl,
|
|
115
|
+
org_id=credentials.org_id, name=credentials.name)
|
|
116
|
+
|
|
111
117
|
@staticmethod
|
|
112
118
|
def create_from_credentials_in_file(fqdn_or_profile_name: str, request_if_missing: bool = False,
|
|
113
119
|
credential_file: Optional[str] = None) -> Optional['APIConnector']:
|
|
@@ -115,9 +121,7 @@ class APIConnector:
|
|
|
115
121
|
credentials = pylo.get_credentials_from_file(fqdn_or_profile_name, credential_file)
|
|
116
122
|
|
|
117
123
|
if credentials is not None:
|
|
118
|
-
return APIConnector(credentials
|
|
119
|
-
credentials.api_key, skip_ssl_cert_check=not credentials.verify_ssl,
|
|
120
|
-
org_id=credentials.org_id, name=credentials.name)
|
|
124
|
+
return APIConnector.create_from_credentials_object(credentials)
|
|
121
125
|
|
|
122
126
|
if not request_if_missing:
|
|
123
127
|
return None
|
|
@@ -362,7 +366,7 @@ class APIConnector:
|
|
|
362
366
|
else:
|
|
363
367
|
raise pylo.PyloEx("Unsupported object type '{}'".format(object_type))
|
|
364
368
|
|
|
365
|
-
def get_pce_objects(self, include_deleted_workloads=False, list_of_objects_to_load: Optional[List[str]] = None):
|
|
369
|
+
def get_pce_objects(self, include_deleted_workloads=False, list_of_objects_to_load: Optional[List[str]] = None, force_async_mode=False):
|
|
366
370
|
|
|
367
371
|
objects_to_load = {}
|
|
368
372
|
if list_of_objects_to_load is not None:
|
|
@@ -389,7 +393,7 @@ class APIConnector:
|
|
|
389
393
|
errors = []
|
|
390
394
|
thread_queue = Queue()
|
|
391
395
|
|
|
392
|
-
def get_objects(q: Queue, thread_num: int):
|
|
396
|
+
def get_objects(q: Queue, thread_num: int, force_async_mode=False):
|
|
393
397
|
while True:
|
|
394
398
|
object_type, errors = q.get()
|
|
395
399
|
try:
|
|
@@ -397,7 +401,7 @@ class APIConnector:
|
|
|
397
401
|
q.task_done()
|
|
398
402
|
continue
|
|
399
403
|
if object_type == 'workloads':
|
|
400
|
-
if self.get_objects_count_by_type(object_type) > default_max_objects_for_sync_calls:
|
|
404
|
+
if self.get_objects_count_by_type(object_type) > default_max_objects_for_sync_calls or force_async_mode:
|
|
401
405
|
data['workloads'] = self.objects_workload_get(include_deleted=include_deleted_workloads)
|
|
402
406
|
else:
|
|
403
407
|
data['workloads'] = self.objects_workload_get(include_deleted=include_deleted_workloads, async_mode=False, max_results=default_max_objects_for_sync_calls)
|
|
@@ -456,7 +460,7 @@ class APIConnector:
|
|
|
456
460
|
q.task_done()
|
|
457
461
|
|
|
458
462
|
for i in range(threads_count):
|
|
459
|
-
worker = Thread(target=get_objects, args=(thread_queue, i))
|
|
463
|
+
worker = Thread(target=get_objects, args=(thread_queue, i, force_async_mode,))
|
|
460
464
|
worker.daemon = True
|
|
461
465
|
worker.start()
|
|
462
466
|
|
|
@@ -97,7 +97,7 @@ def get_all_credentials_from_file(credential_file: str ) -> List[CredentialProfi
|
|
|
97
97
|
|
|
98
98
|
|
|
99
99
|
def get_credentials_from_file(fqdn_or_profile_name: str = None,
|
|
100
|
-
credential_file: str = None) -> CredentialProfile:
|
|
100
|
+
credential_file: str = None, fail_with_an_exception=True) -> Optional[CredentialProfile]:
|
|
101
101
|
|
|
102
102
|
if fqdn_or_profile_name is None:
|
|
103
103
|
log.debug("No fqdn_or_profile_name provided, profile_name=default will be used")
|
|
@@ -121,9 +121,12 @@ def get_credentials_from_file(fqdn_or_profile_name: str = None,
|
|
|
121
121
|
if credential_profile.fqdn.lower() == fqdn_or_profile_name.lower():
|
|
122
122
|
return credential_profile
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
if fail_with_an_exception:
|
|
125
|
+
raise PyloEx("No profile found in credential file '{}' with fqdn: {}".
|
|
125
126
|
format(credential_file, fqdn_or_profile_name))
|
|
126
127
|
|
|
128
|
+
return None
|
|
129
|
+
|
|
127
130
|
|
|
128
131
|
def list_potential_credential_files() -> List[str]:
|
|
129
132
|
"""
|
|
@@ -204,9 +207,7 @@ def create_credential_in_default_file(data: CredentialFileEntry) -> str:
|
|
|
204
207
|
return file_path
|
|
205
208
|
|
|
206
209
|
|
|
207
|
-
def
|
|
208
|
-
|
|
209
|
-
|
|
210
|
+
def encrypt_api_key_with_paramiko_ssh_key_fernet(ssh_key: paramiko.AgentKey, api_key: str) -> str:
|
|
210
211
|
def encrypt(raw: str, key: bytes) -> bytes:
|
|
211
212
|
"""
|
|
212
213
|
|
|
@@ -220,7 +221,7 @@ def encrypt_api_key_with_paramiko_key(ssh_key: paramiko.AgentKey, api_key: str)
|
|
|
220
221
|
|
|
221
222
|
|
|
222
223
|
# generate a random 128bit key
|
|
223
|
-
session_key_to_sign = os.urandom(
|
|
224
|
+
session_key_to_sign = os.urandom(32)
|
|
224
225
|
|
|
225
226
|
signed_message = ssh_key.sign_ssh_data(session_key_to_sign)
|
|
226
227
|
|
|
@@ -236,7 +237,7 @@ def encrypt_api_key_with_paramiko_key(ssh_key: paramiko.AgentKey, api_key: str)
|
|
|
236
237
|
return api_key
|
|
237
238
|
|
|
238
239
|
|
|
239
|
-
def
|
|
240
|
+
def decrypt_api_key_with_paramiko_ssh_key_fernet(encrypted_api_key_payload: str) -> str:
|
|
240
241
|
def decrypt(token_b64_encoded: str, key: bytes):
|
|
241
242
|
f = Fernet(base64.urlsafe_b64encode(key))
|
|
242
243
|
return f.decrypt(token_b64_encoded).decode('utf-8')
|
|
@@ -277,7 +278,7 @@ def decrypt_api_key(encrypted_api_key_payload: str) -> str:
|
|
|
277
278
|
if not encrypted_api_key_payload.startswith("$encrypted$:"):
|
|
278
279
|
raise PyloEx("Invalid encrypted API key format")
|
|
279
280
|
if encrypted_api_key_payload.startswith("$encrypted$:ssh-Fernet:"):
|
|
280
|
-
return
|
|
281
|
+
return decrypt_api_key_with_paramiko_ssh_key_fernet(encrypted_api_key_payload)
|
|
281
282
|
|
|
282
283
|
raise PyloEx("Unsupported encryption method: {}".format(encrypted_api_key_payload.split(":")[1]))
|
|
283
284
|
|
|
@@ -1,29 +1,56 @@
|
|
|
1
|
-
from typing import Dict, Any, List, Optional, TypedDict, NotRequired, Union
|
|
2
|
-
|
|
3
|
-
try:
|
|
4
|
-
import xlsxwriter
|
|
5
|
-
except ImportError:
|
|
6
|
-
import xlsxwriter
|
|
7
|
-
|
|
8
|
-
try:
|
|
9
|
-
import openpyxl
|
|
10
|
-
except ImportError:
|
|
11
|
-
import openpyxl
|
|
1
|
+
from typing import Dict, Any, List, Optional, TypedDict, NotRequired, Union, Iterable
|
|
12
2
|
|
|
3
|
+
import xlsxwriter
|
|
4
|
+
import openpyxl
|
|
13
5
|
import csv
|
|
14
|
-
import illumio_pylo as pylo
|
|
15
6
|
import os
|
|
16
7
|
|
|
8
|
+
import illumio_pylo as pylo
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ExcelHeader:
|
|
12
|
+
def __init__(self, name: str, nice_name: Optional[str] = None, max_width: Optional[int] = None, wrap_text: Optional[bool] = None, is_url: [bool] = False, url_text: str = 'Link'):
|
|
13
|
+
self.name = name
|
|
14
|
+
self.nice_name:str = nice_name if nice_name is not None else name
|
|
15
|
+
self.max_width = max_width
|
|
16
|
+
self.wrap_text = wrap_text
|
|
17
|
+
self.url_text = url_text
|
|
18
|
+
self.is_url = is_url
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ExcelHeaderSet(list[ExcelHeader]):
|
|
22
|
+
def __init__(self, headers: Optional[Iterable[str|ExcelHeader]]):
|
|
23
|
+
super(ExcelHeaderSet, self).__init__()
|
|
24
|
+
if headers is not None:
|
|
25
|
+
for header in headers:
|
|
26
|
+
self.append(header)
|
|
27
|
+
|
|
28
|
+
def append(self, value: str|ExcelHeader):
|
|
29
|
+
if type(value) is str:
|
|
30
|
+
super(ExcelHeaderSet, self).append(ExcelHeader(name=value))
|
|
31
|
+
elif type(value) is ExcelHeader:
|
|
32
|
+
super(ExcelHeaderSet, self).append(value)
|
|
33
|
+
else:
|
|
34
|
+
raise pylo.PyloEx("ExcelHeaderSet.append() must be a string or a dict (ExcelHeader)")
|
|
35
|
+
|
|
36
|
+
def _check_unique(self, new_header_name: str):
|
|
37
|
+
if new_header_name in self:
|
|
38
|
+
raise pylo.PyloEx("Header '{}' is already in the set".format(new_header_name))
|
|
17
39
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
40
|
+
def extend(self, iterable):
|
|
41
|
+
for item in iterable:
|
|
42
|
+
self.append(item)
|
|
43
|
+
|
|
44
|
+
def get_header(self, header_name: str) -> Optional[ExcelHeader]:
|
|
45
|
+
for header in self:
|
|
46
|
+
if header.name == header_name:
|
|
47
|
+
return header
|
|
48
|
+
return None
|
|
23
49
|
|
|
24
50
|
|
|
25
51
|
class ArrayToExport:
|
|
26
|
-
|
|
52
|
+
|
|
53
|
+
def __init__(self, headers: List[str]):
|
|
27
54
|
self._headers = headers
|
|
28
55
|
self._columns_count = len(headers)
|
|
29
56
|
self._lines = []
|
|
@@ -106,8 +133,8 @@ class ArraysToExcel:
|
|
|
106
133
|
_sheets: Dict[str, 'ArraysToExcel.Sheet']
|
|
107
134
|
|
|
108
135
|
class Sheet:
|
|
109
|
-
def __init__(self, headers:
|
|
110
|
-
self._headers:
|
|
136
|
+
def __init__(self, headers: ExcelHeaderSet, force_all_wrap_text=True, sheet_color: Optional[str] = None, order_by: Optional[List[str]] = None, multivalues_cell_delimiter=' '):
|
|
137
|
+
self._headers: ExcelHeaderSet = headers
|
|
111
138
|
self._columns_count = len(headers)
|
|
112
139
|
self._lines = []
|
|
113
140
|
self._columns_wrap = []
|
|
@@ -121,20 +148,18 @@ class ArraysToExcel:
|
|
|
121
148
|
self._headers_index_to_name = []
|
|
122
149
|
index = 0
|
|
123
150
|
|
|
124
|
-
for
|
|
151
|
+
for header in headers:
|
|
125
152
|
self._columns_wrap.append(force_all_wrap_text)
|
|
126
153
|
|
|
127
|
-
if
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
self._headers_index_to_name.append(header_name['name'])
|
|
133
|
-
self._headers_name_to_index[header_name['name']] = index
|
|
154
|
+
if header.nice_name is not None:
|
|
155
|
+
header.nice_name = header.name
|
|
156
|
+
|
|
157
|
+
self._headers_index_to_name.append(header.name)
|
|
158
|
+
self._headers_name_to_index[header.name] = index
|
|
134
159
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
160
|
+
wrap = header.wrap_text
|
|
161
|
+
if wrap is not None and not wrap:
|
|
162
|
+
self._columns_wrap[len(self._columns_wrap)-1] = False
|
|
138
163
|
|
|
139
164
|
index += 1
|
|
140
165
|
|
|
@@ -142,20 +167,11 @@ class ArraysToExcel:
|
|
|
142
167
|
):
|
|
143
168
|
headers: List[str] = []
|
|
144
169
|
for header in self._headers:
|
|
145
|
-
|
|
146
|
-
headers.append(header)
|
|
147
|
-
continue
|
|
148
|
-
if 'nice_name' in header:
|
|
149
|
-
headers.append(header['nice_name'])
|
|
150
|
-
continue
|
|
151
|
-
headers.append(header['name'])
|
|
170
|
+
headers.append(header.name)
|
|
152
171
|
|
|
153
172
|
headers_id: List[str] = []
|
|
154
173
|
for header in self._headers:
|
|
155
|
-
|
|
156
|
-
headers_id.append(header)
|
|
157
|
-
continue
|
|
158
|
-
headers_id.append(header['name'])
|
|
174
|
+
headers_id.append(header.name)
|
|
159
175
|
|
|
160
176
|
|
|
161
177
|
exporter = ArrayToExport(headers)
|
|
@@ -180,10 +196,7 @@ class ArraysToExcel:
|
|
|
180
196
|
def add_line_from_object(self, record):
|
|
181
197
|
new_line = []
|
|
182
198
|
for header in self._headers:
|
|
183
|
-
|
|
184
|
-
new_line.append(record.get(header))
|
|
185
|
-
else:
|
|
186
|
-
new_line.append(record.get(header['name']))
|
|
199
|
+
new_line.append(record.get(header.name))
|
|
187
200
|
|
|
188
201
|
self._lines.append(new_line)
|
|
189
202
|
|
|
@@ -226,21 +239,26 @@ class ArraysToExcel:
|
|
|
226
239
|
|
|
227
240
|
columns_max_width = []
|
|
228
241
|
for header in self._headers:
|
|
229
|
-
|
|
242
|
+
columns_max_width.append(0)
|
|
230
243
|
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
# for each line, find the max length of string for each column and also add it to the data array
|
|
231
247
|
for line in self._lines:
|
|
232
248
|
new_line = []
|
|
233
|
-
|
|
234
|
-
for item in line:
|
|
249
|
+
|
|
250
|
+
for item_index, item in enumerate(line):
|
|
235
251
|
if type(item) is list:
|
|
236
252
|
new_line.append(pylo.string_list_to_text(item, self._multivalues_cell_delimiter))
|
|
237
253
|
else:
|
|
238
|
-
|
|
254
|
+
if self._headers[item_index].is_url:
|
|
255
|
+
new_line.append('=HYPERLINK("{}", "{}")'.format(item,self._headers[item_index].url_text))
|
|
256
|
+
else:
|
|
257
|
+
new_line.append(item)
|
|
258
|
+
length = find_length(new_line[item_index])
|
|
259
|
+
if length > columns_max_width[item_index]:
|
|
260
|
+
columns_max_width[item_index] = length
|
|
239
261
|
|
|
240
|
-
length = find_length(new_line[item_index])
|
|
241
|
-
if length > columns_max_width[item_index]:
|
|
242
|
-
columns_max_width[item_index] = length
|
|
243
|
-
item_index += 1
|
|
244
262
|
|
|
245
263
|
xls_data.append(new_line)
|
|
246
264
|
|
|
@@ -252,14 +270,10 @@ class ArraysToExcel:
|
|
|
252
270
|
|
|
253
271
|
header_max_width_setting = None
|
|
254
272
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
column_name = header.get('nice_name') or header.get('name')
|
|
260
|
-
xls_headers.append({'header': column_name, 'format': cell_format})
|
|
261
|
-
column_name_length = len(column_name) + 2 # add 2 for dropdown menus
|
|
262
|
-
header_max_width_setting = header.get('max_width')
|
|
273
|
+
column_name = header.nice_name
|
|
274
|
+
xls_headers.append({'header': column_name, 'format': cell_format})
|
|
275
|
+
column_name_length = len(column_name) + 2 # add 2 for dropdown menus
|
|
276
|
+
header_max_width_setting = header.max_width
|
|
263
277
|
|
|
264
278
|
# default is to use width=longest string
|
|
265
279
|
column_width = columns_max_width[header_index]+1
|
|
@@ -296,7 +310,7 @@ class ArraysToExcel:
|
|
|
296
310
|
def __init__(self):
|
|
297
311
|
self._sheets = {}
|
|
298
312
|
|
|
299
|
-
def create_sheet(self, name: str, headers, force_all_wrap_text: bool = True, sheet_color: Optional[str] = None,
|
|
313
|
+
def create_sheet(self, name: str, headers: ExcelHeaderSet, force_all_wrap_text: bool = True, sheet_color: Optional[str] = None,
|
|
300
314
|
order_by: Optional[List[str]] = None, multivalues_cell_delimiter: str = ' ') -> Sheet:
|
|
301
315
|
if name in self._sheets:
|
|
302
316
|
pylo.PyloEx("A sheet named '{}' already exists".format(name))
|
|
@@ -71,6 +71,15 @@ class IP4Map:
|
|
|
71
71
|
self._entries.append(new_entry)
|
|
72
72
|
self.sort_and_recalculate()
|
|
73
73
|
|
|
74
|
+
def add_another_map(self, another_map: 'IP4Map', skip_recalculation=False):
|
|
75
|
+
for entry in another_map._entries:
|
|
76
|
+
self._entries.append(entry)
|
|
77
|
+
|
|
78
|
+
if skip_recalculation:
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
self.sort_and_recalculate()
|
|
82
|
+
|
|
74
83
|
def intersection(self, another_map: 'IP4Map'):
|
|
75
84
|
|
|
76
85
|
inverted_map = IP4Map()
|
|
@@ -135,7 +135,10 @@ class Organization:
|
|
|
135
135
|
object_to_load = pylo.APIConnector.get_all_object_types()
|
|
136
136
|
|
|
137
137
|
if self.pce_version is None:
|
|
138
|
-
|
|
138
|
+
if 'pce_version' in data:
|
|
139
|
+
self.pce_version = pylo.SoftwareVersion(data['pce_version'])
|
|
140
|
+
else:
|
|
141
|
+
raise pylo.PyloEx('Organization has no "version" specified')
|
|
139
142
|
|
|
140
143
|
self.LabelStore.load_label_dimensions(data.get('label_dimensions'))
|
|
141
144
|
|
|
@@ -4,7 +4,7 @@ from typing import Optional, List, Union, Dict, Any, NewType
|
|
|
4
4
|
import illumio_pylo as pylo
|
|
5
5
|
from .API.JsonPayloadTypes import RuleServiceReferenceObjectJsonStructure, RuleDirectServiceReferenceObjectJsonStructure
|
|
6
6
|
from illumio_pylo import Workload, Label, LabelGroup, Ruleset, Referencer, SecurityPrincipal, PyloEx, \
|
|
7
|
-
Service, nice_json, string_list_to_text, find_connector_or_die, VirtualService, IPList
|
|
7
|
+
Service, nice_json, string_list_to_text, find_connector_or_die, VirtualService, IPList, PortMap
|
|
8
8
|
|
|
9
9
|
RuleActorsAcceptableTypes = NewType('RuleActorsAcceptableTypes', Union[Workload, Label, LabelGroup, IPList, VirtualService])
|
|
10
10
|
|
|
@@ -250,6 +250,7 @@ class RuleServiceContainer(pylo.Referencer):
|
|
|
250
250
|
self.owner = owner
|
|
251
251
|
self._items: Dict[Service, Service] = {}
|
|
252
252
|
self._direct_services: List[DirectServiceInRule] = []
|
|
253
|
+
self._cached_port_map: Optional[PortMap] = None
|
|
253
254
|
|
|
254
255
|
def load_from_json(self, data_list: List[RuleServiceReferenceObjectJsonStructure|RuleDirectServiceReferenceObjectJsonStructure]):
|
|
255
256
|
ss_store = self.owner.owner.owner.owner.ServiceStore # make it a local variable for fast lookups
|
|
@@ -295,6 +296,8 @@ class RuleServiceContainer(pylo.Referencer):
|
|
|
295
296
|
:param service:
|
|
296
297
|
:return: True if the service was removed, False if it was not found
|
|
297
298
|
"""
|
|
299
|
+
self._cached_port_map = None
|
|
300
|
+
|
|
298
301
|
for i in range(0, len(self._direct_services)):
|
|
299
302
|
if self._direct_services[i] is service:
|
|
300
303
|
del(self._direct_services[i])
|
|
@@ -302,6 +305,8 @@ class RuleServiceContainer(pylo.Referencer):
|
|
|
302
305
|
return False
|
|
303
306
|
|
|
304
307
|
def add_direct_service(self, service: DirectServiceInRule) -> bool:
|
|
308
|
+
self._cached_port_map = None
|
|
309
|
+
|
|
305
310
|
for member in self._direct_services:
|
|
306
311
|
if service is member:
|
|
307
312
|
return False
|
|
@@ -352,6 +357,27 @@ class RuleServiceContainer(pylo.Referencer):
|
|
|
352
357
|
|
|
353
358
|
self.owner.raw_json.update(data)
|
|
354
359
|
|
|
360
|
+
def get_port_map(self) -> PortMap:
|
|
361
|
+
"""
|
|
362
|
+
Get a PortMap object with all ports and protocols from all services in this container
|
|
363
|
+
:return:
|
|
364
|
+
"""
|
|
365
|
+
if self._cached_port_map is not None:
|
|
366
|
+
return self._cached_port_map
|
|
367
|
+
|
|
368
|
+
result = PortMap()
|
|
369
|
+
for service in self._items.values():
|
|
370
|
+
for entry in service.entries:
|
|
371
|
+
result.add(entry.protocol, entry.port, entry.to_port, skip_recalculation=True)
|
|
372
|
+
for direct in self._direct_services:
|
|
373
|
+
result.add(direct.protocol, direct.port, direct.to_port, skip_recalculation=True)
|
|
374
|
+
|
|
375
|
+
result.merge_overlapping_maps()
|
|
376
|
+
|
|
377
|
+
self._cached_port_map = result
|
|
378
|
+
|
|
379
|
+
return result
|
|
380
|
+
|
|
355
381
|
|
|
356
382
|
class RuleHostContainer(pylo.Referencer):
|
|
357
383
|
def __init__(self, owner: 'pylo.Rule', name: str):
|
|
@@ -101,29 +101,17 @@ class RulesetScopeEntry:
|
|
|
101
101
|
|
|
102
102
|
|
|
103
103
|
def to_string(self, label_separator = '|', use_href=False):
|
|
104
|
-
string = '
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
else:
|
|
114
|
-
if use_href:
|
|
115
|
-
string += self.env_label.href + label_separator
|
|
116
|
-
else:
|
|
117
|
-
string += self.env_label.name + label_separator
|
|
118
|
-
|
|
119
|
-
if self.loc_label is None:
|
|
120
|
-
string += 'All'
|
|
121
|
-
else:
|
|
122
|
-
if use_href:
|
|
123
|
-
string += self.loc_label.href
|
|
104
|
+
string = ''
|
|
105
|
+
for label_type in self.owner.owner.owner.owner.LabelStore.label_types:
|
|
106
|
+
label = self._labels.get(label_type)
|
|
107
|
+
if len(string) > 0:
|
|
108
|
+
string += label_separator
|
|
109
|
+
if label is None:
|
|
110
|
+
string += 'All'
|
|
111
|
+
elif use_href:
|
|
112
|
+
string += label.href
|
|
124
113
|
else:
|
|
125
|
-
string +=
|
|
126
|
-
|
|
114
|
+
string += label.name
|
|
127
115
|
return string
|
|
128
116
|
|
|
129
117
|
def is_all_all_all(self):
|
|
@@ -156,10 +144,6 @@ class RulesetScopeEntry:
|
|
|
156
144
|
|
|
157
145
|
class Ruleset:
|
|
158
146
|
|
|
159
|
-
name: str
|
|
160
|
-
href: Optional[str]
|
|
161
|
-
description: str
|
|
162
|
-
|
|
163
147
|
def __init__(self, owner: 'pylo.RulesetStore'):
|
|
164
148
|
self.owner: 'pylo.RulesetStore' = owner
|
|
165
149
|
self.href: Optional[str] = None
|
|
@@ -169,6 +153,7 @@ class Ruleset:
|
|
|
169
153
|
# must keep an ordered list of rules while the dict by href is there for quick searches
|
|
170
154
|
self._rules_by_href: Dict[str, 'pylo.Rule'] = {}
|
|
171
155
|
self._rules: List['pylo.Rule'] = []
|
|
156
|
+
self.disabled: bool = False
|
|
172
157
|
|
|
173
158
|
@property
|
|
174
159
|
def rules(self):
|
|
@@ -211,6 +196,9 @@ class Ruleset:
|
|
|
211
196
|
raise pylo.PyloEx("Cannot find Ruleset href in JSON data: \n" + pylo.Helpers.nice_json(data))
|
|
212
197
|
self.href = data['href']
|
|
213
198
|
|
|
199
|
+
if 'enabled' in data:
|
|
200
|
+
self.disabled = not data['enabled']
|
|
201
|
+
|
|
214
202
|
scopes_json = data.get('scopes')
|
|
215
203
|
if scopes_json is None:
|
|
216
204
|
raise pylo.PyloEx("Cannot find Ruleset scope in JSON data: \n" + pylo.Helpers.nice_json(data))
|
|
@@ -287,7 +275,7 @@ class Ruleset:
|
|
|
287
275
|
if pce_fqdn is None or pce_port is None:
|
|
288
276
|
connector = pylo.find_connector_or_die(self)
|
|
289
277
|
if pce_fqdn is None:
|
|
290
|
-
pce_fqdn = connector.
|
|
278
|
+
pce_fqdn = connector.fqdn
|
|
291
279
|
if pce_port is None:
|
|
292
280
|
pce_port = connector.port
|
|
293
281
|
|