illumio-pylo 0.3.11__tar.gz → 0.3.12__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.11 → illumio_pylo-0.3.12}/.github/workflows/make-binaries.yml +40 -2
- {illumio_pylo-0.3.11/illumio_pylo.egg-info → illumio_pylo-0.3.12}/PKG-INFO +2 -1
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/examples/extend_cli.py +1 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/API/APIConnector.py +82 -97
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/API/CredentialsManager.py +38 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/Helpers/exports.py +1 -1
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/__init__.py +1 -1
- illumio_pylo-0.3.12/illumio_pylo/cli/commands/credential_manager.py +591 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/label_delete_unused.py +0 -3
- illumio_pylo-0.3.12/illumio_pylo/cli/commands/ui/credential_manager_ui/app.js +449 -0
- illumio_pylo-0.3.12/illumio_pylo/cli/commands/ui/credential_manager_ui/index.html +168 -0
- illumio_pylo-0.3.12/illumio_pylo/cli/commands/ui/credential_manager_ui/styles.css +430 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/ven_duplicate_remover.py +79 -59
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/utilities/cli.py +4 -1
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/utilities/health_monitoring.py +5 -1
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12/illumio_pylo.egg-info}/PKG-INFO +2 -1
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo.egg-info/SOURCES.txt +3 -0
- illumio_pylo-0.3.11/requirements.txt → illumio_pylo-0.3.12/illumio_pylo.egg-info/requires.txt +2 -1
- illumio_pylo-0.3.11/illumio_pylo.egg-info/requires.txt → illumio_pylo-0.3.12/requirements.txt +1 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/setup.py +1 -1
- illumio_pylo-0.3.11/illumio_pylo/cli/commands/credential_manager.py +0 -216
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/.devcontainer/Dockerfile +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/.devcontainer/devcontainer.json +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/.gitattributes +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/.github/workflows/doxygen-publish.yml +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/.github/workflows/python-publish.yml +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/.gitignore +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/LICENSE +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/README.md +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/check_unique_hostnames.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/check_unique_services.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/delete_all_workloads.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/delete_unused_services.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/explorer_report_exporter.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/export_rules_to_firewall.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/generate-random-workloads.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/healthcheck_log.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/import-labels.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/import_workloads_placeholders.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/iplists_stats_duplicates_unused_finder.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/recalculate_explorer_logs.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/recalculate_explorer_logs_multithreaded.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/rules_exporter.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/rules_exporter_special.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/test.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/test_change_workload_desc.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/test_query.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/test_query2.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/test_securityprincipals.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/ven_idle_to_illumination.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/dev_playground/ven_reassign_pce.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/examples/explorer_query.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/API/AuditLog.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/API/ClusterHealth.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/API/Explorer.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/API/JsonPayloadTypes.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/API/RuleSearchQuery.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/API/__init__.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/AgentStore.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/Exception.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/Helpers/__init__.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/Helpers/functions.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/IPList.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/IPMap.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/Label.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/LabelCommon.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/LabelGroup.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/LabelStore.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/LabeledObject.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/Organization.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/Query.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/ReferenceTracker.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/Rule.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/Ruleset.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/RulesetStore.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/SecurityPrincipal.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/Service.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/SoftwareVersion.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/VirtualService.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/VirtualServiceStore.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/Workload.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/WorkloadStore.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/WorkloadStoreSubClasses.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/NativeParsers.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/__init__.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/__main__.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/__init__.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/iplist_analyzer.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/iplist_import_from_file.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/ruleset_export.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/update_pce_objects_cache.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/utils/LabelCreation.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/utils/__init__.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/utils/misc.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/ven_compatibility_report_export.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/ven_idle_to_visibility.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/ven_upgrader.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/workload_export.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/workload_import.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/workload_reset_names_to_null.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/workload_update.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/cli/commands/workload_used_in_rule_finder.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/docs/Doxygen +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/tmp.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/utilities/__init__.py +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/utilities/credentials.example.json +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/utilities/resources/iplists-import-example.csv +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/utilities/resources/iplists-import-example.xlsx +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/utilities/resources/workload-exporter-filter-example.csv +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/utilities/resources/workloads-import-example.csv +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo/utilities/resources/workloads-import-example.xlsx +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo.egg-info/dependency_links.txt +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/illumio_pylo.egg-info/top_level.txt +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/pyproject.toml +0 -0
- {illumio_pylo-0.3.11 → illumio_pylo-0.3.12}/setup.cfg +0 -0
|
@@ -20,6 +20,7 @@ jobs:
|
|
|
20
20
|
- name: Change Pylo Version if this is a DEV build
|
|
21
21
|
if: github.ref == 'refs/heads/dev' && github.event_name == 'push'
|
|
22
22
|
run: |
|
|
23
|
+
pwd
|
|
23
24
|
echo "Update version to append '-dev-' and current date ISO format:"
|
|
24
25
|
# for double quoted strings version
|
|
25
26
|
sed -i -E "s/__version__ = \"([0-9]+\.[0-9]+\.[0-9]+)\"/__version__ = '\\1-dev-$(date +'%Y%m%d')'/" illumio_pylo/__init__.py
|
|
@@ -28,12 +29,49 @@ jobs:
|
|
|
28
29
|
grep __version__ illumio_pylo/__init__.py
|
|
29
30
|
|
|
30
31
|
|
|
32
|
+
- name: copy scripts and pkg to build folder
|
|
33
|
+
run: |
|
|
34
|
+
# build the package
|
|
35
|
+
pip install build
|
|
36
|
+
python -m build
|
|
37
|
+
echo "current working directory:"
|
|
38
|
+
pwd
|
|
39
|
+
# get package whl filename for later use, it is in dist/
|
|
40
|
+
package_filename=$(find dist/ -name "illumio_pylo-*.whl" | sed 's|dist/||')
|
|
41
|
+
echo "*** Package filename is: $package_filename"
|
|
42
|
+
mkdir cli-build
|
|
43
|
+
# move package to cli-build
|
|
44
|
+
mv "dist/$package_filename" cli-build/
|
|
45
|
+
|
|
46
|
+
# create requirements.txt that points to the local package
|
|
47
|
+
echo "illumio_pylo@file:./cli-build/$package_filename" > cli-build/requirements.txt
|
|
48
|
+
#echo "pyinstaller==6.16.0" >> cli-build/requirements.txt
|
|
49
|
+
echo "*** Created cli-build/requirements.txt with contents:"
|
|
50
|
+
cat cli-build/requirements.txt
|
|
51
|
+
|
|
52
|
+
# copy cli.py removing any sys.path.insert lines
|
|
53
|
+
grep -v 'sys.path.insert' illumio_pylo/utilities/cli.py > cli-build/cli.py
|
|
54
|
+
mv illumio_pylo/utilities/health_monitoring.py cli-build/
|
|
55
|
+
|
|
56
|
+
# delete illumio_pylo to avoid confusion
|
|
57
|
+
rm -rf illumio_pylo/
|
|
58
|
+
|
|
59
|
+
echo "*** Contents of cli-build/:"
|
|
60
|
+
find cli-build/
|
|
61
|
+
|
|
31
62
|
- name: Make executables
|
|
32
63
|
uses: cpainchaud/pyinstaller-action-windows@main
|
|
33
64
|
with:
|
|
34
65
|
path: ./
|
|
35
|
-
spec:
|
|
36
|
-
|
|
66
|
+
spec: ./cli-build/
|
|
67
|
+
requirements: ./cli-build/requirements.txt
|
|
68
|
+
collect_data: illumio_pylo
|
|
69
|
+
extra_python_paths: Z:\\github\\workspace\\;C:\\Windows\\System32\\downlevel
|
|
70
|
+
|
|
71
|
+
- name: show spec files
|
|
72
|
+
run: |
|
|
73
|
+
echo "Showing the spec files created by PyInstaller:"
|
|
74
|
+
find ../ -name "*.spec" -exec cat {} \;
|
|
37
75
|
|
|
38
76
|
- name: rename executables
|
|
39
77
|
run: |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: illumio_pylo
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.12
|
|
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
|
|
@@ -193,6 +193,7 @@ 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
|
+
Requires-Dist: flask~=2.2.0
|
|
196
197
|
Dynamic: author
|
|
197
198
|
Dynamic: author-email
|
|
198
199
|
Dynamic: description
|
|
@@ -23,6 +23,7 @@ class MyBuiltInParser: # optional, if you want to use built-in parsers
|
|
|
23
23
|
label_type='env', # optional, it will ensure that selected labels are of a specified type
|
|
24
24
|
is_required=False, allow_multiple=True)
|
|
25
25
|
|
|
26
|
+
|
|
26
27
|
def fill_parser(parser: argparse.ArgumentParser):
|
|
27
28
|
""" This function will be called by the CLI to fill the parser with the arguments of your command """
|
|
28
29
|
parser.add_argument('--sort-by-name', '-s', action='store_true',
|
|
@@ -28,9 +28,13 @@ from typing import Union, Dict, Any, List, Optional, Literal
|
|
|
28
28
|
|
|
29
29
|
requests.packages.urllib3.disable_warnings()
|
|
30
30
|
|
|
31
|
+
objects_types_strings = Literal[
|
|
32
|
+
'workloads', 'virtual_services', 'labels', 'labelgroups', 'iplists', 'services',
|
|
33
|
+
'rulesets', 'security_principals', 'label_dimensions']
|
|
34
|
+
|
|
31
35
|
default_retry_count_if_api_call_limit_reached = 3
|
|
32
36
|
default_retry_wait_time_if_api_call_limit_reached = 10
|
|
33
|
-
default_max_objects_for_sync_calls =
|
|
37
|
+
default_max_objects_for_sync_calls = 200000
|
|
34
38
|
|
|
35
39
|
|
|
36
40
|
def get_field_or_die(field_name: str, data):
|
|
@@ -153,6 +157,33 @@ class APIConnector:
|
|
|
153
157
|
|
|
154
158
|
return url
|
|
155
159
|
|
|
160
|
+
def _get_objects_auto_switch_async(self, path: str, data: Dict[str, Any], async_mode: bool, max_results: Optional[int]) -> Any:
|
|
161
|
+
# use a copy of data to not modify the original
|
|
162
|
+
data_copy = data.copy()
|
|
163
|
+
|
|
164
|
+
if async_mode:
|
|
165
|
+
if max_results is not None:
|
|
166
|
+
data_copy['max_results'] = max_results
|
|
167
|
+
return self.do_get_call(path=path, async_call=True, params=data_copy)
|
|
168
|
+
|
|
169
|
+
if max_results is not None:
|
|
170
|
+
data_copy['max_results'] = max_results
|
|
171
|
+
return self.do_get_call(path=path, async_call=False, params=data_copy)
|
|
172
|
+
|
|
173
|
+
# We will grab the maximum allowed with sync mode (variable default_max_objects_for_sync_calls) and switch to async if it's higher
|
|
174
|
+
data_copy['max_results'] = default_max_objects_for_sync_calls
|
|
175
|
+
results = self.do_get_call(path=path, async_call=False, params=data_copy, return_headers=True)
|
|
176
|
+
total_count = results[1].get('x-total-count')
|
|
177
|
+
if total_count is None:
|
|
178
|
+
raise pylo.PyloApiEx('API didnt provide field "x-total-count" in headers')
|
|
179
|
+
if not total_count.isdigit():
|
|
180
|
+
raise pylo.PyloApiEx('API returned invalid value for "x-total-count": {}'.format(total_count))
|
|
181
|
+
if int(total_count) > default_max_objects_for_sync_calls:
|
|
182
|
+
# remove the max_results from data
|
|
183
|
+
del data_copy['max_results']
|
|
184
|
+
return self.do_get_call(path=path, async_call=True, params=data_copy)
|
|
185
|
+
return results[0]
|
|
186
|
+
|
|
156
187
|
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
188
|
retry_count_if_api_call_limit_reached=default_retry_count_if_api_call_limit_reached,
|
|
158
189
|
retry_wait_time_if_api_call_limit_reached=default_retry_wait_time_if_api_call_limit_reached,
|
|
@@ -275,7 +306,7 @@ class APIConnector:
|
|
|
275
306
|
log.info("Job status is " + job_poll_status)
|
|
276
307
|
|
|
277
308
|
log.info("Job is done, we will now download the resulting dataset")
|
|
278
|
-
dataset = self.do_get_call(result_href, include_org_id=False)
|
|
309
|
+
dataset = self.do_get_call(result_href, include_org_id=False, return_headers=return_headers)
|
|
279
310
|
|
|
280
311
|
return dataset
|
|
281
312
|
|
|
@@ -313,9 +344,6 @@ class APIConnector:
|
|
|
313
344
|
raise pylo.PyloApiEx('API returned error status "' + str(req.status_code) + ' ' + req.reason
|
|
314
345
|
+ '" and error message: ' + req.text)
|
|
315
346
|
|
|
316
|
-
if return_headers:
|
|
317
|
-
return req.headers
|
|
318
|
-
|
|
319
347
|
if json_output_expected:
|
|
320
348
|
log.info("Parsing API answer to JSON (with a size of " + str(int(answer_size)) + "KB)")
|
|
321
349
|
json_out = req.json()
|
|
@@ -325,8 +353,12 @@ class APIConnector:
|
|
|
325
353
|
log.info(json.dumps(json_out, indent=2, sort_keys=True))
|
|
326
354
|
else:
|
|
327
355
|
log.info("Answer is too large to be printed")
|
|
356
|
+
if return_headers:
|
|
357
|
+
return json_out, req.headers
|
|
328
358
|
return json_out
|
|
329
359
|
|
|
360
|
+
if return_headers:
|
|
361
|
+
return req.text, req.headers
|
|
330
362
|
return req.text
|
|
331
363
|
|
|
332
364
|
raise pylo.PyloApiEx("Unexpected API output or race condition")
|
|
@@ -339,33 +371,39 @@ class APIConnector:
|
|
|
339
371
|
self.collect_pce_infos()
|
|
340
372
|
return self.version_string
|
|
341
373
|
|
|
342
|
-
def get_objects_count_by_type(self, object_type:
|
|
374
|
+
def get_objects_count_by_type(self, object_type: objects_types_strings) -> int:
|
|
343
375
|
|
|
344
376
|
def extract_count(headers):
|
|
345
377
|
count = headers.get('x-total-count')
|
|
346
378
|
if count is None:
|
|
347
379
|
raise pylo.PyloApiEx('API didnt provide field "x-total-count"')
|
|
348
380
|
|
|
381
|
+
# count should be an integer
|
|
382
|
+
if not count.isdigit():
|
|
383
|
+
raise pylo.PyloApiEx('API returned invalid value for "x-total-count": {}'.format(count))
|
|
384
|
+
|
|
349
385
|
return int(count)
|
|
350
386
|
|
|
387
|
+
params = {'max_results': 1}
|
|
388
|
+
|
|
351
389
|
if object_type == 'workloads':
|
|
352
|
-
return extract_count(self.do_get_call('/workloads', async_call=False, return_headers=True))
|
|
390
|
+
return extract_count(self.do_get_call('/workloads', async_call=False, return_headers=True, params=params)[1])
|
|
353
391
|
elif object_type == 'virtual_services':
|
|
354
|
-
return extract_count(self.do_get_call('/sec_policy/draft/virtual_services', async_call=False, return_headers=True))
|
|
392
|
+
return extract_count(self.do_get_call('/sec_policy/draft/virtual_services', async_call=False, return_headers=True, params=params)[1])
|
|
355
393
|
elif object_type == 'labels':
|
|
356
|
-
return extract_count(self.do_get_call('/labels', async_call=False, return_headers=True))
|
|
394
|
+
return extract_count(self.do_get_call('/labels', async_call=False, return_headers=True, params=params)[1])
|
|
357
395
|
elif object_type == 'labelgroups':
|
|
358
|
-
return extract_count(self.do_get_call('/sec_policy/draft/label_groups', async_call=False, return_headers=True))
|
|
396
|
+
return extract_count(self.do_get_call('/sec_policy/draft/label_groups', async_call=False, return_headers=True, params=params)[1])
|
|
359
397
|
elif object_type == 'iplists':
|
|
360
|
-
return extract_count(self.do_get_call('/sec_policy/draft/ip_lists', async_call=False, return_headers=True))
|
|
398
|
+
return extract_count(self.do_get_call('/sec_policy/draft/ip_lists', async_call=False, return_headers=True, params=params)[1])
|
|
361
399
|
elif object_type == 'services':
|
|
362
|
-
return extract_count(self.do_get_call('/sec_policy/draft/services', async_call=False, return_headers=True))
|
|
400
|
+
return extract_count(self.do_get_call('/sec_policy/draft/services', async_call=False, return_headers=True, params=params)[1])
|
|
363
401
|
elif object_type == 'rulesets':
|
|
364
|
-
return extract_count(self.do_get_call('/sec_policy/draft/rule_sets', async_call=False, return_headers=True))
|
|
402
|
+
return extract_count(self.do_get_call('/sec_policy/draft/rule_sets', async_call=False, return_headers=True, params=params)[1])
|
|
365
403
|
elif object_type == 'security_principals':
|
|
366
|
-
return extract_count(self.do_get_call('/security_principals', async_call=False, return_headers=True))
|
|
404
|
+
return extract_count(self.do_get_call('/security_principals', async_call=False, return_headers=True, params=params)[1])
|
|
367
405
|
elif object_type == 'label_dimensions':
|
|
368
|
-
return extract_count(self.do_get_call('/label_dimensions', async_call=False, return_headers=True))
|
|
406
|
+
return extract_count(self.do_get_call('/label_dimensions', async_call=False, return_headers=True, params=params)[1])
|
|
369
407
|
else:
|
|
370
408
|
raise pylo.PyloEx("Unsupported object type '{}'".format(object_type))
|
|
371
409
|
|
|
@@ -403,57 +441,32 @@ class APIConnector:
|
|
|
403
441
|
q.task_done()
|
|
404
442
|
continue
|
|
405
443
|
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)
|
|
444
|
+
data['workloads'] = self.objects_workload_get(include_deleted=include_deleted_workloads, async_mode=force_async_mode)
|
|
410
445
|
|
|
411
446
|
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)
|
|
447
|
+
data['virtual_services'] = self.objects_virtual_service_get(async_mode=force_async_mode)
|
|
416
448
|
|
|
417
449
|
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)
|
|
450
|
+
data['labels'] = self.objects_label_get(async_mode=force_async_mode)
|
|
422
451
|
|
|
423
452
|
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)
|
|
453
|
+
data['labelgroups'] = self.objects_labelgroup_get(async_mode=force_async_mode)
|
|
428
454
|
|
|
429
455
|
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)
|
|
456
|
+
data['iplists'] = self.objects_iplist_get(async_mode=force_async_mode)
|
|
434
457
|
|
|
435
458
|
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)
|
|
459
|
+
data['services'] = self.objects_service_get(async_mode=force_async_mode)
|
|
440
460
|
|
|
441
461
|
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)
|
|
462
|
+
data['rulesets'] = self.objects_ruleset_get(async_mode=force_async_mode)
|
|
446
463
|
|
|
447
464
|
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)
|
|
465
|
+
data['security_principals'] = self.objects_securityprincipal_get(async_mode=force_async_mode)
|
|
466
|
+
|
|
452
467
|
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)
|
|
468
|
+
data['label_dimensions'] = self.objects_label_dimension_get()
|
|
469
|
+
|
|
457
470
|
else:
|
|
458
471
|
raise pylo.PyloEx("Unsupported object type '{}'".format(object_type))
|
|
459
472
|
except Exception as e:
|
|
@@ -533,20 +546,17 @@ class APIConnector:
|
|
|
533
546
|
params = {'include_deny_rules': include_boundary_rules}
|
|
534
547
|
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
548
|
|
|
536
|
-
def objects_label_get(self, max_results: int = None, async_mode=
|
|
549
|
+
def objects_label_get(self, max_results: int = None, async_mode=False, get_usage: bool = False, get_deleted: bool = False) -> List[LabelObjectJsonStructure]:
|
|
537
550
|
path = '/labels'
|
|
538
551
|
data = {}
|
|
539
552
|
|
|
540
|
-
if max_results is not None:
|
|
541
|
-
data['max_results'] = max_results
|
|
542
|
-
|
|
543
553
|
if get_usage:
|
|
544
554
|
data['usage'] = 'true'
|
|
545
555
|
|
|
546
556
|
if get_deleted:
|
|
547
557
|
data['includeDeleted'] = 'true'
|
|
548
558
|
|
|
549
|
-
return self.
|
|
559
|
+
return self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
550
560
|
|
|
551
561
|
def objects_label_update(self, href: str, data: LabelObjectUpdateJsonStructure):
|
|
552
562
|
path = href
|
|
@@ -618,14 +628,11 @@ class APIConnector:
|
|
|
618
628
|
data: LabelObjectCreationJsonStructure = {'key': label_type, 'value': label_name}
|
|
619
629
|
return self.do_post_call(path=path, json_arguments=data)
|
|
620
630
|
|
|
621
|
-
def objects_labelgroup_get(self, max_results: int = None, async_mode=
|
|
631
|
+
def objects_labelgroup_get(self, max_results: int = None, async_mode=False) -> List[LabelGroupObjectJsonStructure]:
|
|
622
632
|
path = '/sec_policy/draft/label_groups'
|
|
623
633
|
data = {}
|
|
624
634
|
|
|
625
|
-
|
|
626
|
-
data['max_results'] = max_results
|
|
627
|
-
|
|
628
|
-
return self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
635
|
+
return self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
629
636
|
|
|
630
637
|
def objects_labelgroup_update(self, href: str, data: LabelGroupObjectUpdateJsonStructure):
|
|
631
638
|
path = href
|
|
@@ -635,34 +642,26 @@ class APIConnector:
|
|
|
635
642
|
path = '/label_dimensions'
|
|
636
643
|
data = {}
|
|
637
644
|
|
|
638
|
-
|
|
639
|
-
data['max_results'] = max_results
|
|
640
|
-
return self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
645
|
+
return self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
641
646
|
|
|
642
|
-
def objects_virtual_service_get(self, max_results: int = None, async_mode=
|
|
647
|
+
def objects_virtual_service_get(self, max_results: int = None, async_mode=False) -> List[VirtualServiceObjectJsonStructure]:
|
|
643
648
|
path = '/sec_policy/draft/virtual_services'
|
|
644
649
|
data = {}
|
|
645
650
|
|
|
646
|
-
|
|
647
|
-
data['max_results'] = max_results
|
|
648
|
-
|
|
649
|
-
results = self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
651
|
+
results = self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
650
652
|
# check type
|
|
651
653
|
if type(results) is list:
|
|
652
654
|
return results
|
|
653
655
|
raise pylo.PyloEx("Unexpected result type '{}' while expecting an array of Virtual Service objects".format(type(results)), results)
|
|
654
656
|
|
|
655
|
-
def objects_iplist_get(self, max_results: int = None, async_mode=
|
|
657
|
+
def objects_iplist_get(self, max_results: int = None, async_mode=False, search_name: str = None) -> List[IPListObjectJsonStructure]:
|
|
656
658
|
path = '/sec_policy/draft/ip_lists'
|
|
657
659
|
data = {}
|
|
658
660
|
|
|
659
661
|
if search_name is not None:
|
|
660
662
|
data['name'] = search_name
|
|
661
663
|
|
|
662
|
-
|
|
663
|
-
data['max_results'] = max_results
|
|
664
|
-
|
|
665
|
-
results: List[IPListObjectJsonStructure] = self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
664
|
+
results: List[IPListObjectJsonStructure] = self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
666
665
|
# check type
|
|
667
666
|
if type(results) is list:
|
|
668
667
|
return results
|
|
@@ -714,10 +713,7 @@ class APIConnector:
|
|
|
714
713
|
if representation is not None:
|
|
715
714
|
data['representation'] = representation
|
|
716
715
|
|
|
717
|
-
|
|
718
|
-
data['max_results'] = max_results
|
|
719
|
-
|
|
720
|
-
return self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
716
|
+
return self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
721
717
|
|
|
722
718
|
def objects_workload_get(self,
|
|
723
719
|
include_deleted=False,
|
|
@@ -727,7 +723,7 @@ class APIConnector:
|
|
|
727
723
|
filter_by_managed: bool = None,
|
|
728
724
|
filer_by_policy_health: Literal['active', 'warning', 'error'] = None,
|
|
729
725
|
max_results: int = None,
|
|
730
|
-
async_mode=
|
|
726
|
+
async_mode=False) -> List[WorkloadObjectJsonStructure]:
|
|
731
727
|
path = '/workloads'
|
|
732
728
|
data = {}
|
|
733
729
|
|
|
@@ -750,10 +746,8 @@ class APIConnector:
|
|
|
750
746
|
if filer_by_policy_health is not None:
|
|
751
747
|
data['policy_health'] = filer_by_policy_health
|
|
752
748
|
|
|
753
|
-
|
|
754
|
-
data['max_results'] = max_results
|
|
749
|
+
return self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
755
750
|
|
|
756
|
-
return self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
757
751
|
|
|
758
752
|
def objects_workload_agent_upgrade(self, workload_href: str, target_version: str):
|
|
759
753
|
path = '{}/upgrade'.format(workload_href)
|
|
@@ -1001,14 +995,11 @@ class APIConnector:
|
|
|
1001
995
|
path = '/workloads/bulk_create'
|
|
1002
996
|
return self.do_put_call(path=path, json_arguments=workloads_json_payload)
|
|
1003
997
|
|
|
1004
|
-
def objects_service_get(self, max_results: int = None, async_mode=
|
|
998
|
+
def objects_service_get(self, max_results: int = None, async_mode=False):
|
|
1005
999
|
path = '/sec_policy/draft/services'
|
|
1006
1000
|
data = {}
|
|
1007
1001
|
|
|
1008
|
-
|
|
1009
|
-
data['max_results'] = max_results
|
|
1010
|
-
|
|
1011
|
-
return self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
1002
|
+
return self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
1012
1003
|
|
|
1013
1004
|
def objects_service_delete(self, href):
|
|
1014
1005
|
"""
|
|
@@ -1050,14 +1041,11 @@ class APIConnector:
|
|
|
1050
1041
|
|
|
1051
1042
|
return self.do_post_call(path=path, async_call=False, include_org_id=False, json_arguments=data, json_output_expected=True)
|
|
1052
1043
|
|
|
1053
|
-
def objects_ruleset_get(self, max_results: int = None, async_mode=
|
|
1044
|
+
def objects_ruleset_get(self, max_results: int = None, async_mode=False) -> List[RulesetObjectJsonStructure]:
|
|
1054
1045
|
path = '/sec_policy/draft/rule_sets'
|
|
1055
1046
|
data = {}
|
|
1056
1047
|
|
|
1057
|
-
|
|
1058
|
-
data['max_results'] = max_results
|
|
1059
|
-
|
|
1060
|
-
return self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
1048
|
+
return self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
1061
1049
|
|
|
1062
1050
|
def objects_ruleset_create(self, name: str,
|
|
1063
1051
|
scope_app: 'pylo.Label' = None,
|
|
@@ -1176,14 +1164,11 @@ class APIConnector:
|
|
|
1176
1164
|
|
|
1177
1165
|
return self.do_post_call(path, json_arguments=data, json_output_expected=True, include_org_id=False)
|
|
1178
1166
|
|
|
1179
|
-
def objects_securityprincipal_get(self, max_results: int = None, async_mode=
|
|
1167
|
+
def objects_securityprincipal_get(self, max_results: int = None, async_mode=False) -> List[SecurityPrincipalObjectJsonStructure]:
|
|
1180
1168
|
path = '/security_principals'
|
|
1181
1169
|
data = {}
|
|
1182
1170
|
|
|
1183
|
-
|
|
1184
|
-
data['max_results'] = max_results
|
|
1185
|
-
|
|
1186
|
-
return self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
1171
|
+
return self._get_objects_auto_switch_async(path=path, data=data, async_mode=async_mode, max_results=max_results)
|
|
1187
1172
|
|
|
1188
1173
|
def objects_securityprincipal_create(self, name: str = None, sid: str = None, json_data=None) -> str:
|
|
1189
1174
|
"""
|
|
@@ -199,6 +199,44 @@ def create_credential_in_file(file_full_path: str, data: CredentialFileEntry, ov
|
|
|
199
199
|
return file_full_path
|
|
200
200
|
|
|
201
201
|
|
|
202
|
+
def delete_credential_from_file(profile_name: str, file_path: str) -> bool:
|
|
203
|
+
"""
|
|
204
|
+
Delete a credential from a file by profile name.
|
|
205
|
+
:param profile_name: Name of the profile to delete
|
|
206
|
+
:param file_path: Path to the credential file
|
|
207
|
+
:return: True if deleted successfully
|
|
208
|
+
"""
|
|
209
|
+
if not os.path.exists(file_path):
|
|
210
|
+
raise PyloEx("Credential file does not exist: {}".format(file_path))
|
|
211
|
+
|
|
212
|
+
with open(file_path, 'r') as f:
|
|
213
|
+
credentials: CredentialsFileType = json.load(f)
|
|
214
|
+
|
|
215
|
+
if isinstance(credentials, list):
|
|
216
|
+
original_len = len(credentials)
|
|
217
|
+
credentials = [c for c in credentials if c['name'].lower() != profile_name.lower()]
|
|
218
|
+
if len(credentials) == original_len:
|
|
219
|
+
raise PyloEx("Profile '{}' not found in file '{}'".format(profile_name, file_path))
|
|
220
|
+
|
|
221
|
+
if len(credentials) == 0:
|
|
222
|
+
# If no credentials left, delete the file
|
|
223
|
+
os.remove(file_path)
|
|
224
|
+
return True
|
|
225
|
+
else:
|
|
226
|
+
if credentials['name'].lower() == profile_name.lower():
|
|
227
|
+
# Single credential in file, delete the file
|
|
228
|
+
os.remove(file_path)
|
|
229
|
+
return True
|
|
230
|
+
else:
|
|
231
|
+
raise PyloEx("Profile '{}' not found in file '{}'".format(profile_name, file_path))
|
|
232
|
+
|
|
233
|
+
# Write the updated credentials back to the file
|
|
234
|
+
with open(file_path, 'w') as f:
|
|
235
|
+
json.dump(credentials, f, indent=4)
|
|
236
|
+
|
|
237
|
+
return True
|
|
238
|
+
|
|
239
|
+
|
|
202
240
|
def create_credential_in_default_file(data: CredentialFileEntry) -> str:
|
|
203
241
|
"""
|
|
204
242
|
Create a credential in the default credential file and return the full path to the file
|
|
@@ -9,7 +9,7 @@ import illumio_pylo as pylo
|
|
|
9
9
|
|
|
10
10
|
|
|
11
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:
|
|
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
13
|
self.name = name
|
|
14
14
|
self.nice_name:str = nice_name if nice_name is not None else name
|
|
15
15
|
self.max_width = max_width
|