illumio-pylo 0.3.11__tar.gz → 0.3.13__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.
Files changed (125) hide show
  1. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/.github/workflows/make-binaries.yml +40 -2
  2. {illumio_pylo-0.3.11/illumio_pylo.egg-info → illumio_pylo-0.3.13}/PKG-INFO +2 -1
  3. illumio_pylo-0.3.13/docs/ENV_CREDENTIALS.md +205 -0
  4. illumio_pylo-0.3.13/examples/example_env_credentials.py +77 -0
  5. illumio_pylo-0.3.13/examples/explorer_query.py +101 -0
  6. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/examples/extend_cli.py +1 -0
  7. illumio_pylo-0.3.13/examples/filter_query_example.py +122 -0
  8. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/API/APIConnector.py +138 -106
  9. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/API/CredentialsManager.py +168 -3
  10. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/API/Explorer.py +619 -14
  11. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/API/JsonPayloadTypes.py +64 -4
  12. illumio_pylo-0.3.13/illumio_pylo/FilterQuery.py +892 -0
  13. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/Helpers/exports.py +1 -1
  14. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/LabelCommon.py +13 -3
  15. illumio_pylo-0.3.13/illumio_pylo/LabelDimension.py +109 -0
  16. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/LabelStore.py +97 -38
  17. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/WorkloadStore.py +58 -0
  18. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/__init__.py +9 -3
  19. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/__init__.py +5 -2
  20. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/__init__.py +1 -0
  21. illumio_pylo-0.3.13/illumio_pylo/cli/commands/credential_manager.py +767 -0
  22. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/label_delete_unused.py +0 -3
  23. illumio_pylo-0.3.13/illumio_pylo/cli/commands/traffic_export.py +358 -0
  24. illumio_pylo-0.3.13/illumio_pylo/cli/commands/ui/credential_manager_ui/app.js +638 -0
  25. illumio_pylo-0.3.13/illumio_pylo/cli/commands/ui/credential_manager_ui/index.html +217 -0
  26. illumio_pylo-0.3.13/illumio_pylo/cli/commands/ui/credential_manager_ui/styles.css +581 -0
  27. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/update_pce_objects_cache.py +1 -2
  28. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/ven_duplicate_remover.py +79 -59
  29. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/workload_export.py +29 -0
  30. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/utilities/cli.py +4 -1
  31. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/utilities/health_monitoring.py +5 -1
  32. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13/illumio_pylo.egg-info}/PKG-INFO +2 -1
  33. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo.egg-info/SOURCES.txt +13 -2
  34. illumio_pylo-0.3.11/requirements.txt → illumio_pylo-0.3.13/illumio_pylo.egg-info/requires.txt +2 -1
  35. illumio_pylo-0.3.11/illumio_pylo.egg-info/requires.txt → illumio_pylo-0.3.13/requirements.txt +1 -0
  36. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/setup.py +1 -1
  37. illumio_pylo-0.3.13/tests/test_env_credentials.py +198 -0
  38. illumio_pylo-0.3.13/tests/test_filter_query.py +344 -0
  39. illumio_pylo-0.3.13/tests/test_nested_queries.py +34 -0
  40. illumio_pylo-0.3.11/examples/explorer_query.py +0 -84
  41. illumio_pylo-0.3.11/illumio_pylo/Query.py +0 -331
  42. illumio_pylo-0.3.11/illumio_pylo/cli/commands/credential_manager.py +0 -216
  43. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/.devcontainer/Dockerfile +0 -0
  44. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/.devcontainer/devcontainer.json +0 -0
  45. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/.gitattributes +0 -0
  46. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/.github/workflows/doxygen-publish.yml +0 -0
  47. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/.github/workflows/python-publish.yml +0 -0
  48. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/.gitignore +0 -0
  49. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/LICENSE +0 -0
  50. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/README.md +0 -0
  51. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/check_unique_hostnames.py +0 -0
  52. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/check_unique_services.py +0 -0
  53. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/delete_all_workloads.py +0 -0
  54. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/delete_unused_services.py +0 -0
  55. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/explorer_report_exporter.py +0 -0
  56. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/export_rules_to_firewall.py +0 -0
  57. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/generate-random-workloads.py +0 -0
  58. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/healthcheck_log.py +0 -0
  59. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/import-labels.py +0 -0
  60. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/import_workloads_placeholders.py +0 -0
  61. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/iplists_stats_duplicates_unused_finder.py +0 -0
  62. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/recalculate_explorer_logs.py +0 -0
  63. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/recalculate_explorer_logs_multithreaded.py +0 -0
  64. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/rules_exporter.py +0 -0
  65. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/rules_exporter_special.py +0 -0
  66. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/test.py +0 -0
  67. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/test_change_workload_desc.py +0 -0
  68. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/test_query.py +0 -0
  69. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/test_query2.py +0 -0
  70. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/test_securityprincipals.py +0 -0
  71. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/ven_idle_to_illumination.py +0 -0
  72. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/dev_playground/ven_reassign_pce.py +0 -0
  73. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/API/AuditLog.py +0 -0
  74. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/API/ClusterHealth.py +0 -0
  75. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/API/RuleSearchQuery.py +0 -0
  76. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/API/__init__.py +0 -0
  77. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/AgentStore.py +0 -0
  78. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/Exception.py +0 -0
  79. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/Helpers/__init__.py +0 -0
  80. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/Helpers/functions.py +0 -0
  81. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/IPList.py +0 -0
  82. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/IPMap.py +0 -0
  83. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/Label.py +0 -0
  84. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/LabelGroup.py +0 -0
  85. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/LabeledObject.py +0 -0
  86. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/Organization.py +0 -0
  87. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/ReferenceTracker.py +0 -0
  88. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/Rule.py +0 -0
  89. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/Ruleset.py +0 -0
  90. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/RulesetStore.py +0 -0
  91. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/SecurityPrincipal.py +0 -0
  92. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/Service.py +0 -0
  93. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/SoftwareVersion.py +0 -0
  94. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/VirtualService.py +0 -0
  95. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/VirtualServiceStore.py +0 -0
  96. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/Workload.py +0 -0
  97. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/WorkloadStoreSubClasses.py +0 -0
  98. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/NativeParsers.py +0 -0
  99. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/__main__.py +0 -0
  100. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/iplist_analyzer.py +0 -0
  101. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/iplist_import_from_file.py +0 -0
  102. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/ruleset_export.py +0 -0
  103. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/utils/LabelCreation.py +0 -0
  104. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/utils/__init__.py +0 -0
  105. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/utils/misc.py +0 -0
  106. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/ven_compatibility_report_export.py +0 -0
  107. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/ven_idle_to_visibility.py +0 -0
  108. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/ven_upgrader.py +0 -0
  109. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/workload_import.py +0 -0
  110. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/workload_reset_names_to_null.py +0 -0
  111. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/workload_update.py +0 -0
  112. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/cli/commands/workload_used_in_rule_finder.py +0 -0
  113. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/docs/Doxygen +0 -0
  114. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/tmp.py +0 -0
  115. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/utilities/__init__.py +0 -0
  116. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/utilities/credentials.example.json +0 -0
  117. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/utilities/resources/iplists-import-example.csv +0 -0
  118. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/utilities/resources/iplists-import-example.xlsx +0 -0
  119. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/utilities/resources/workload-exporter-filter-example.csv +0 -0
  120. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/utilities/resources/workloads-import-example.csv +0 -0
  121. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo/utilities/resources/workloads-import-example.xlsx +0 -0
  122. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo.egg-info/dependency_links.txt +0 -0
  123. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/illumio_pylo.egg-info/top_level.txt +0 -0
  124. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/pyproject.toml +0 -0
  125. {illumio_pylo-0.3.11 → illumio_pylo-0.3.13}/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: illumio_pylo/utilities/
36
- extra_python_paths: Z:\\github\\workspace\\;Z:\\github\\workspace\\pylo;C:\\Windows\\System32\\downlevel
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.11
3
+ Version: 0.3.13
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
@@ -0,0 +1,205 @@
1
+ # Environment Variable Credentials
2
+
3
+ ## Overview
4
+
5
+ The `CredentialProfile.from_environment_variables()` feature allows you to provide Illumio PCE credentials via environment variables instead of storing them in credential files on disk. This is particularly useful for:
6
+
7
+ - CI/CD pipelines
8
+ - Docker containers
9
+ - Security-conscious environments where credentials shouldn't be written to disk
10
+ - Temporary credential usage
11
+
12
+ ## Usage
13
+
14
+ To use environment variable credentials, simply specify the profile name `'ENV'` (case-insensitive) when loading credentials:
15
+
16
+ ```python
17
+ import illumio_pylo as pylo
18
+
19
+ # Load credentials from environment variables
20
+ credentials = pylo.get_credentials_from_file('ENV')
21
+
22
+ # Or use with APIConnector
23
+ connector = pylo.APIConnector.create_from_credentials_in_file('ENV')
24
+
25
+ # Or use with Organization
26
+ org = pylo.Organization.get_from_api_using_credential_file('ENV')
27
+ ```
28
+
29
+ ## Required Environment Variables
30
+
31
+ - **`PYLO_FQDN`**: Fully qualified domain name of the PCE (e.g., `pce.example.com`)
32
+ - **`PYLO_API_USER`**: API username
33
+ - **`PYLO_API_KEY`**: API key (can be encrypted with `$encrypted$:` prefix)
34
+
35
+ ## Optional Environment Variables
36
+
37
+ - **`PYLO_PORT`**: Port number
38
+ - Default: `8443` for standard PCE
39
+ - Default: `443` for illum.io hosted domains (SaaS)
40
+ - Valid range: 1-65535
41
+
42
+ - **`PYLO_ORG_ID`**: Organization ID
43
+ - Default: `1` for standard PCE
44
+ - **Required** for illum.io hosted domains (no default)
45
+ - Must be a positive integer
46
+
47
+ - **`PYLO_VERIFY_SSL`**: Verify SSL certificate
48
+ - Default: `true`
49
+ - Accepts: `true`, `false`, `1`, `0`, `yes`, `no`, `y`, `n` (case-insensitive)
50
+
51
+ ## Examples
52
+
53
+ ### Basic Example (Standard PCE)
54
+
55
+ ```bash
56
+ # Set environment variables
57
+ export PYLO_FQDN="pce.example.com"
58
+ export PYLO_API_USER="api_12345"
59
+ export PYLO_API_KEY="your_api_key_here"
60
+
61
+ # Run your Python script
62
+ python your_script.py
63
+ ```
64
+
65
+ ```python
66
+ import illumio_pylo as pylo
67
+
68
+ # Load from environment
69
+ org = pylo.Organization.get_from_api_using_credential_file('ENV')
70
+ print(f"Connected to {org.connector.fqdn}")
71
+ ```
72
+
73
+ ### Illumio SaaS Example
74
+
75
+ ```bash
76
+ # For illum.io domains, ORG_ID is required
77
+ export PYLO_FQDN="mycompany.illum.io"
78
+ export PYLO_API_USER="api_12345"
79
+ export PYLO_API_KEY="your_api_key_here"
80
+ export PYLO_ORG_ID="5"
81
+
82
+ # Port defaults to 443 for illum.io domains
83
+ python your_script.py
84
+ ```
85
+
86
+ ### Custom Configuration
87
+
88
+ ```bash
89
+ # Custom port and disable SSL verification
90
+ export PYLO_FQDN="pce.internal.local"
91
+ export PYLO_API_USER="api_12345"
92
+ export PYLO_API_KEY="your_api_key_here"
93
+ export PYLO_PORT="9443"
94
+ export PYLO_ORG_ID="2"
95
+ export PYLO_VERIFY_SSL="false"
96
+
97
+ python your_script.py
98
+ ```
99
+
100
+ ### Docker Container Example
101
+
102
+ ```bash
103
+ docker run -e PYLO_FQDN="pce.example.com" \
104
+ -e PYLO_API_USER="api_12345" \
105
+ -e PYLO_API_KEY="your_api_key" \
106
+ your-container:latest
107
+ ```
108
+
109
+ ### Encrypted API Key
110
+
111
+ If you have an encrypted API key (generated with the `cred-manager` tool), you can use it directly:
112
+
113
+ ```bash
114
+ export PYLO_FQDN="pce.example.com"
115
+ export PYLO_API_USER="api_12345"
116
+ export PYLO_API_KEY='$encrypted$:ssh-ChaCha20Poly1305:...'
117
+
118
+ python your_script.py
119
+ ```
120
+
121
+ The API key will be automatically decrypted using your SSH agent.
122
+
123
+ ## Checking Availability
124
+
125
+ You can check if required environment variables are set before attempting to load:
126
+
127
+ ```python
128
+ from illumio_pylo.API.CredentialsManager import is_env_credentials_available
129
+
130
+ if is_env_credentials_available():
131
+ print("Environment credentials are available")
132
+ credentials = pylo.get_credentials_from_file('ENV')
133
+ else:
134
+ print("Missing required environment variables")
135
+ # Fall back to file-based credentials
136
+ credentials = pylo.get_credentials_from_file('default')
137
+ ```
138
+
139
+ ## Validation and Error Handling
140
+
141
+ The implementation includes comprehensive validation:
142
+
143
+ - **Missing required variables**: Clear error message listing which variables are missing
144
+ - **Invalid port**: Must be a valid integer between 1-65535
145
+ - **Invalid org_id**: Must be a positive integer
146
+ - **Invalid verify_ssl**: Must be a boolean-like value
147
+ - **illum.io domains**: Automatically defaults port to 443 and requires ORG_ID
148
+
149
+ Example error messages:
150
+
151
+ ```
152
+ Missing required environment variables for ENV profile: PYLO_FQDN, PYLO_API_KEY.
153
+ Required: PYLO_FQDN, PYLO_API_USER, PYLO_API_KEY.
154
+ Optional: PYLO_PORT, PYLO_ORG_ID, PYLO_VERIFY_SSL
155
+
156
+ Invalid PYLO_PORT value 'abc': must be a valid port number (1-65535)
157
+
158
+ PYLO_ORG_ID is required for illum.io domains (no default available)
159
+
160
+ Invalid PYLO_VERIFY_SSL value 'maybe': must be true/false/1/0/yes/no/y/n (case-insensitive)
161
+ ```
162
+
163
+ ## Security Considerations
164
+
165
+ ### Advantages
166
+ - Credentials never written to disk
167
+ - Easier to rotate in CI/CD environments
168
+ - No risk of accidentally committing credentials to version control
169
+ - Better integration with secrets management tools (AWS Secrets Manager, HashiCorp Vault, etc.)
170
+
171
+ ### Best Practices
172
+ 1. **Never log environment variables** - Be careful not to print or log the actual API key
173
+ 2. **Use encrypted keys when possible** - Leverage SSH agent encryption for additional security
174
+ 3. **Rotate credentials regularly** - Environment-based approach makes rotation easier
175
+ 4. **Use secrets management** - In production, use proper secrets management tools to inject environment variables
176
+ 5. **Limit scope** - Set environment variables only for the specific process that needs them
177
+
178
+ ### Example with AWS Secrets Manager
179
+
180
+ ```python
181
+ import boto3
182
+ import json
183
+ import os
184
+ import illumio_pylo as pylo
185
+
186
+ # Fetch credentials from AWS Secrets Manager
187
+ client = boto3.client('secretsmanager')
188
+ secret = client.get_secret_value(SecretId='pylo/pce/credentials')
189
+ creds = json.loads(secret['SecretString'])
190
+
191
+ # Set environment variables
192
+ os.environ['PYLO_FQDN'] = creds['fqdn']
193
+ os.environ['PYLO_API_USER'] = creds['api_user']
194
+ os.environ['PYLO_API_KEY'] = creds['api_key']
195
+
196
+ # Use ENV profile
197
+ org = pylo.Organization.get_from_api_using_credential_file('ENV')
198
+ ```
199
+
200
+ ## Notes
201
+
202
+ - The profile name is always `'ENV'` (case-insensitive: `'env'`, `'Env'`, `'ENV'` all work)
203
+ - The `originating_file` attribute is set to `'environment'` for env-based profiles
204
+ - Environment credentials are **never** included in `get_all_credentials()` - they must be explicitly requested
205
+ - Environment credentials don't require any credential files to exist on disk
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Practical example of using environment variable credentials with Illumio Pylo
4
+ This demonstrates how to connect to a PCE using only environment variables
5
+ """
6
+ import os
7
+ import illumio_pylo as pylo
8
+
9
+ def main():
10
+ # Check if environment credentials are available
11
+ from illumio_pylo.API.CredentialsManager import is_env_credentials_available
12
+
13
+ if not is_env_credentials_available():
14
+ print("ERROR: Required environment variables are not set!")
15
+ print("Please set: PYLO_FQDN, PYLO_API_USER, PYLO_API_KEY")
16
+ print("\nExample:")
17
+ print(" export PYLO_FQDN='pce.example.com'")
18
+ print(" export PYLO_API_USER='api_12345'")
19
+ print(" export PYLO_API_KEY='your_api_key_here'")
20
+ return 1
21
+
22
+ print("Environment credentials detected!")
23
+ print("-" * 60)
24
+
25
+ # Load credentials from environment
26
+ try:
27
+ credentials = pylo.get_credentials_from_file('ENV')
28
+ print(f"Credentials loaded:")
29
+ print(f" FQDN: {credentials.fqdn}")
30
+ print(f" Port: {credentials.port}")
31
+ print(f" Org ID: {credentials.org_id}")
32
+ print(f" API User: {credentials.api_user}")
33
+ print(f" Verify SSL: {credentials.verify_ssl}")
34
+ print(f" Source: {credentials.originating_file}")
35
+ print("-" * 60)
36
+ except pylo.PyloEx as e:
37
+ print(f"ERROR loading credentials: {e}")
38
+ return 1
39
+
40
+ # Example 1: Create an APIConnector
41
+ print("\nExample 1: Creating APIConnector from ENV profile")
42
+ try:
43
+ connector = pylo.APIConnector.create_from_credentials_in_file('ENV')
44
+ print(f"✓ APIConnector created for {connector.fqdn}:{connector.port}")
45
+
46
+ # Test connection by getting software version
47
+ version = connector.get_software_version()
48
+ print(f"✓ Connected successfully! PCE Version: {version}")
49
+
50
+ except Exception as e:
51
+ print(f"✗ Connection failed: {e}")
52
+ print(" (This is expected if the PCE is not accessible)")
53
+
54
+ # Example 2: Load Organization data
55
+ print("\nExample 2: Loading Organization from ENV profile")
56
+ try:
57
+ org = pylo.Organization.get_from_api_using_credential_file(
58
+ 'ENV',
59
+ list_of_objects_to_load=[
60
+ pylo.ObjectTypes.LABEL,
61
+ pylo.ObjectTypes.WORKLOAD
62
+ ]
63
+ )
64
+ print(f"✓ Organization loaded successfully!")
65
+ print(f" Labels: {len(org.LabelStore.itemsByHref)}")
66
+ print(f" Workloads: {len(org.WorkloadStore.itemsByHref)}")
67
+
68
+ except Exception as e:
69
+ print(f"✗ Failed to load organization: {e}")
70
+ print(" (This is expected if the PCE is not accessible)")
71
+
72
+ print("\n" + "=" * 60)
73
+ print("Example complete!")
74
+ return 0
75
+
76
+ if __name__ == '__main__':
77
+ exit(main())
@@ -0,0 +1,101 @@
1
+ """
2
+ In this example we will show how to query traffic logs from the PCE using the Explorer V2 APIs.
3
+ We will make a query for all traffic logs matching the following conditions:
4
+ - Source (consumer) has a label 'E-PRODUCTION' or 'E-PREPROD' or is part of IPList 'I-Prod-Networks'
5
+ - Destination (provider) can be any workload or IP
6
+ - Service is TCP port 80 or 443 or ICMP protocol
7
+ - Policy decision is 'allowed'
8
+ - Traffic was detected within the last 5 days
9
+ """
10
+
11
+ import os
12
+ import sys
13
+
14
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))) # only required if you run this script from the examples folder without installing pylo
15
+ import illumio_pylo as pylo
16
+
17
+ # PCE connection parameters
18
+ pce_hostname = 'pce1.company.com'
19
+ pce_port = 9443
20
+ pce_api_user = 'api_xxxxxxxxx'
21
+ pce_api_key = 'xxxxxxxxxxxxxxxxxxxx'
22
+ pce_org_id = 1
23
+ pce_verify_ssl = True
24
+
25
+ print("Loading organization from PCE '{}'... ".format(pce_hostname), end='', flush=True)
26
+ organization = pylo.get_organization(pce_hostname, pce_port, pce_api_user, pce_api_key, pce_org_id, pce_verify_ssl)
27
+ print("OK!")
28
+
29
+ # Create a new V2 Explorer query with a max of 1500 results
30
+ explorer_query = organization.connector.new_explorer_query_v2(max_results=1500)
31
+
32
+ # Define source filter criteria
33
+ source_labels_names = ['E-PRODUCTION', 'E-PREPROD']
34
+ source_ip_list_name = 'I-Prod-Networks'
35
+
36
+ # Create a source filter that combines labels and IPList (treated with OR logic)
37
+ source_filter = explorer_query.filters.new_source_filter()
38
+
39
+ # Lookup and add Label objects to the source filter
40
+ for label_name in source_labels_names:
41
+ label_search_result = organization.LabelStore.find_label_by_name(label_name, raise_exception_if_not_found=False, case_sensitive=False)
42
+ if len(label_search_result) == 0:
43
+ raise pylo.PyloEx("Label '{}' not found in PCE!".format(label_name))
44
+ elif len(label_search_result) > 1:
45
+ raise pylo.PyloEx("Multiple labels found for name '{}', please use a more specific name!".format(label_name))
46
+ source_filter.add_label(label_search_result[0])
47
+
48
+ # Lookup and add IPList object to the source filter
49
+ source_iplist = organization.IPListStore.find_by_name(source_ip_list_name)
50
+ if source_iplist is None:
51
+ raise pylo.PyloEx("IPList '{}' not found in PCE!".format(source_ip_list_name))
52
+ source_filter.add_iplist(source_iplist)
53
+
54
+ # Filter by services (ICMP, HTTP, HTTPS)
55
+ explorer_query.filters.service_include_add_protocol(1) # ICMP
56
+ explorer_query.filters.service_include_add('tcp/80') # HTTP
57
+ explorer_query.filters.service_include_add('tcp/443') # HTTPS
58
+
59
+ # Filter by policy decision (only allowed traffic)
60
+ explorer_query.filters.filter_on_policy_decision_allowed()
61
+
62
+ # Filter by time range (last 5 days)
63
+ explorer_query.filters.set_time_from_x_days_ago(5)
64
+
65
+ # Execute the query and retrieve traffic logs
66
+ print("Querying PCE for traffic logs matching the filter... ", end='', flush=True)
67
+ traffic_logs = explorer_query.execute()
68
+ records = traffic_logs.get_all_records()
69
+ print("OK! Found {} traffic log(s)".format(len(records)))
70
+
71
+ # Print the results
72
+ for record in records:
73
+ # Format source information
74
+ if record.source_is_workload():
75
+ workload = record.get_source_workload(organization)
76
+ # Get labels as a formatted string
77
+ label_values = [record.source_workload_labels_by_type.get(lt) for lt in organization.LabelStore.label_types]
78
+ label_values = [lv for lv in label_values if lv is not None]
79
+ labels_str = '|'.join(label_values) if label_values else 'unlabeled'
80
+ consumer_text = "Workload '{}' ({})".format(workload.name if workload else record.source_workload_hostname, labels_str)
81
+ else:
82
+ consumer_text = "IP '{}'".format(record.source_ip)
83
+
84
+ # Format destination information
85
+ if record.destination_is_workload():
86
+ workload = record.get_destination_workload(organization)
87
+ # Get labels as a formatted string
88
+ label_values = [record.destination_workload_labels_by_type.get(lt) for lt in organization.LabelStore.label_types]
89
+ label_values = [lv for lv in label_values if lv is not None]
90
+ labels_str = '|'.join(label_values) if label_values else 'unlabeled'
91
+ provider_text = "Workload '{}' ({})".format(workload.name if workload else record.destination_workload_hostname, labels_str)
92
+ else:
93
+ provider_text = "IP '{}'".format(record.destination_ip)
94
+
95
+ # Format service information
96
+ service_text = record.service_to_str()
97
+
98
+ # Print the traffic log entry
99
+ print("Traffic log: {} -> {} via {} (policy decision: {})".format(
100
+ consumer_text, provider_text, service_text, record.policy_decision_string))
101
+
@@ -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',
@@ -0,0 +1,122 @@
1
+ """
2
+ Example: Using the Filter Query feature to search workloads
3
+
4
+ This example demonstrates how to use the find_workloads_matching_query() method
5
+ to filter workloads using a SQL-like query syntax.
6
+ """
7
+
8
+ import sys
9
+ import os
10
+
11
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
12
+
13
+ import illumio_pylo as pylo
14
+
15
+
16
+ def main():
17
+ # Load organization from PCE (using credentials file or cached data)
18
+ # Replace 'your-pce-hostname' with your actual PCE hostname
19
+ pce_hostname = 'your-pce-hostname'
20
+
21
+ print(f"Loading PCE configuration from {pce_hostname}...")
22
+ org = pylo.Organization(1)
23
+
24
+ # Option 1: Load from API using saved credentials
25
+ # org.load_from_api_using_credential_file(pce_hostname)
26
+
27
+ # Option 2: Load from cache (if you've previously cached the data)
28
+ try:
29
+ org.load_from_cache_or_saved_credentials(pce_hostname)
30
+ except Exception as e:
31
+ print(f"Failed to load PCE data: {e}")
32
+ print("\nTo use this example, you need to either:")
33
+ print(" 1. Configure credentials in ~/.pylo/credentials.json")
34
+ print(" 2. Have cached PCE data available")
35
+ return
36
+
37
+ print(f"Loaded {len(org.WorkloadStore.workloads)} workloads from PCE\n")
38
+
39
+ # Example queries
40
+ example_queries = [
41
+ # Find workloads by name
42
+ "name == 'web-server-01'",
43
+
44
+ # Find workloads by partial name match
45
+ "name contains 'web'",
46
+
47
+ # Find workloads by name using regex
48
+ "name matches 'web-.*-[0-9]+'",
49
+
50
+ # Find workloads by IP address
51
+ "ip_address == '192.168.1.100'",
52
+
53
+ # Find online workloads
54
+ "online == true",
55
+
56
+ # Find workloads by label
57
+ "env == 'Production'",
58
+ "label.app == 'WebApp' and label.env == 'Production'",
59
+
60
+ # Complex query with OR
61
+ "(name == 'server-01' or name == 'server-02') and online == true",
62
+
63
+ # Find workloads with old heartbeat
64
+ "last_heartbeat <= '2024-01-01'",
65
+
66
+ # Find workloads in a specific mode
67
+ "mode == 'enforced'",
68
+
69
+ # Find deleted workloads (need to pass include_deleted=True)
70
+ "deleted == true",
71
+
72
+ # Combine multiple conditions
73
+ "hostname contains 'prod' and env == 'Production' and not deleted == true",
74
+ ]
75
+
76
+ print("=" * 60)
77
+ print("Filter Query Examples")
78
+ print("=" * 60)
79
+
80
+ for query in example_queries:
81
+ print(f"\nQuery: {query}")
82
+ try:
83
+ results = org.WorkloadStore.find_workloads_matching_query(query)
84
+ print(f"Found {len(results)} workload(s)")
85
+ for wkl in results[:5]: # Show first 5 results
86
+ print(f" - {wkl.get_name()} ({wkl.href})")
87
+ if len(results) > 5:
88
+ print(f" ... and {len(results) - 5} more")
89
+ except pylo.PyloEx as e:
90
+ print(f"Error: {e}")
91
+
92
+ # Interactive query mode
93
+ print("\n" + "=" * 60)
94
+ print("Interactive Query Mode")
95
+ print("Enter a query to search workloads, or 'quit' to exit")
96
+ print("=" * 60)
97
+
98
+ while True:
99
+ try:
100
+ query = input("\nQuery> ").strip()
101
+ if query.lower() in ('quit', 'exit', 'q'):
102
+ break
103
+ if not query:
104
+ continue
105
+
106
+ results = org.WorkloadStore.find_workloads_matching_query(query)
107
+ print(f"Found {len(results)} workload(s)")
108
+ for wkl in results[:10]:
109
+ labels = wkl.get_labels_str()
110
+ print(f" - {wkl.get_name()} | {labels} | online={wkl.online}")
111
+ if len(results) > 10:
112
+ print(f" ... and {len(results) - 10} more")
113
+ except pylo.PyloEx as e:
114
+ print(f"Query error: {e}")
115
+ except KeyboardInterrupt:
116
+ break
117
+
118
+ print("\nGoodbye!")
119
+
120
+
121
+ if __name__ == '__main__':
122
+ main()