illumio-pylo 0.3.1__tar.gz → 0.3.3__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 (110) hide show
  1. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/.github/workflows/make-binaries.yml +20 -19
  2. {illumio_pylo-0.3.1/illumio_pylo.egg-info → illumio_pylo-0.3.3}/PKG-INFO +1 -1
  3. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/examples/explorer_query.py +1 -1
  4. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/API/APIConnector.py +42 -9
  5. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/API/CredentialsManager.py +9 -9
  6. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/API/JsonPayloadTypes.py +29 -0
  7. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/Helpers/exports.py +3 -4
  8. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/IPMap.py +9 -0
  9. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/LabeledObject.py +1 -1
  10. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/Organization.py +4 -1
  11. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/Rule.py +27 -1
  12. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/Ruleset.py +15 -27
  13. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/Service.py +49 -52
  14. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/__init__.py +1 -1
  15. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/__init__.py +19 -6
  16. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/credential_manager.py +91 -26
  17. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/ruleset_export.py +44 -38
  18. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/utils/misc.py +4 -0
  19. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/ven_upgrader.py +10 -78
  20. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/workload_export.py +7 -4
  21. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/workload_import.py +44 -13
  22. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/tmp.py +8 -4
  23. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3/illumio_pylo.egg-info}/PKG-INFO +1 -1
  24. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/.devcontainer/Dockerfile +0 -0
  25. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/.devcontainer/devcontainer.json +0 -0
  26. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/.gitattributes +0 -0
  27. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/.github/workflows/doxygen-publish.yml +0 -0
  28. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/.github/workflows/python-publish.yml +0 -0
  29. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/.gitignore +0 -0
  30. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/LICENSE +0 -0
  31. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/README.md +0 -0
  32. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/check_unique_hostnames.py +0 -0
  33. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/check_unique_services.py +0 -0
  34. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/delete_all_workloads.py +0 -0
  35. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/delete_unused_services.py +0 -0
  36. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/explorer_report_exporter.py +0 -0
  37. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/export_rules_to_firewall.py +0 -0
  38. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/generate-random-workloads.py +0 -0
  39. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/healthcheck_log.py +0 -0
  40. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/import-labels.py +0 -0
  41. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/import_workloads_placeholders.py +0 -0
  42. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/iplists_stats_duplicates_unused_finder.py +0 -0
  43. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/recalculate_explorer_logs.py +0 -0
  44. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/recalculate_explorer_logs_multithreaded.py +0 -0
  45. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/rules_exporter.py +0 -0
  46. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/rules_exporter_special.py +0 -0
  47. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/test.py +0 -0
  48. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/test_change_workload_desc.py +0 -0
  49. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/test_query.py +0 -0
  50. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/test_query2.py +0 -0
  51. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/test_securityprincipals.py +0 -0
  52. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/ven_idle_to_illumination.py +0 -0
  53. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/dev_playground/ven_reassign_pce.py +0 -0
  54. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/examples/extend_cli.py +0 -0
  55. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/API/AuditLog.py +0 -0
  56. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/API/ClusterHealth.py +0 -0
  57. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/API/Explorer.py +0 -0
  58. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/API/RuleSearchQuery.py +0 -0
  59. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/API/__init__.py +0 -0
  60. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/AgentStore.py +0 -0
  61. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/Exception.py +0 -0
  62. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/Helpers/__init__.py +0 -0
  63. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/Helpers/functions.py +0 -0
  64. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/IPList.py +0 -0
  65. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/Label.py +0 -0
  66. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/LabelCommon.py +0 -0
  67. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/LabelGroup.py +0 -0
  68. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/LabelStore.py +0 -0
  69. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/Query.py +0 -0
  70. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/ReferenceTracker.py +0 -0
  71. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/RulesetStore.py +0 -0
  72. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/SecurityPrincipal.py +0 -0
  73. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/SoftwareVersion.py +0 -0
  74. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/VirtualService.py +0 -0
  75. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/VirtualServiceStore.py +0 -0
  76. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/Workload.py +0 -0
  77. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/WorkloadStore.py +0 -0
  78. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/WorkloadStoreSubClasses.py +0 -0
  79. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/NativeParsers.py +0 -0
  80. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/__main__.py +0 -0
  81. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/__init__.py +0 -0
  82. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/iplist_analyzer.py +0 -0
  83. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/iplist_import_from_file.py +0 -0
  84. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/update_pce_objects_cache.py +0 -0
  85. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/utils/LabelCreation.py +0 -0
  86. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/utils/__init__.py +0 -0
  87. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/ven_compatibility_report_export.py +0 -0
  88. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/ven_duplicate_remover.py +0 -0
  89. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/ven_idle_to_visibility.py +0 -0
  90. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/workload_reset_names_to_null.py +0 -0
  91. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/workload_update.py +0 -0
  92. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/cli/commands/workload_used_in_rule_finder.py +0 -0
  93. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/docs/Doxygen +0 -0
  94. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/utilities/__init__.py +0 -0
  95. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/utilities/cli.py +0 -0
  96. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/utilities/credentials.example.json +0 -0
  97. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/utilities/health_monitoring.py +0 -0
  98. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/utilities/resources/iplists-import-example.csv +0 -0
  99. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/utilities/resources/iplists-import-example.xlsx +0 -0
  100. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/utilities/resources/workload-exporter-filter-example.csv +0 -0
  101. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/utilities/resources/workloads-import-example.csv +0 -0
  102. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo/utilities/resources/workloads-import-example.xlsx +0 -0
  103. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo.egg-info/SOURCES.txt +0 -0
  104. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo.egg-info/dependency_links.txt +0 -0
  105. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo.egg-info/requires.txt +0 -0
  106. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/illumio_pylo.egg-info/top_level.txt +0 -0
  107. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/pyproject.toml +0 -0
  108. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/requirements.txt +0 -0
  109. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/setup.cfg +0 -0
  110. {illumio_pylo-0.3.1 → illumio_pylo-0.3.3}/setup.py +0 -0
@@ -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: softprops/action-gh-release@975c1b265e11dd76618af1c374e7981f9a6ff44a # v0.1.16
71
+ uses: "crowbarmaster/GH-Automatic-Releases@latest"
70
72
  with:
71
- files: dist/windows/*
72
- token: ${{ secrets.GITHUB_TOKEN }}
73
- draft: false
73
+ repo_token: "${{ secrets.GITHUB_TOKEN }}"
74
+ automatic_release_tag: "dev-latest"
74
75
  prerelease: false
75
- tag_name: "dev-build"
76
- name: "Latest DEV/Unstable Binaries"
77
-
76
+ title: "Latest Binaries for DEV/Unstable branch"
77
+ files: |
78
+ dist/windows/*
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: illumio_pylo
3
- Version: 0.3.1
3
+ Version: 0.3.3
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
@@ -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.count_results()))
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, \
@@ -12,7 +12,7 @@ from .JsonPayloadTypes import LabelGroupObjectJsonStructure, LabelObjectCreation
12
12
  LabelDimensionObjectStructure, AuditLogApiReplyEventJsonStructure, WorkloadsGetQueryLabelFilterJsonStructure, \
13
13
  NetworkDeviceObjectJsonStructure, NetworkDeviceEndpointObjectJsonStructure, HrefReference, \
14
14
  WorkloadObjectCreateJsonStructure, WorkloadObjectMultiCreateJsonRequestPayload, \
15
- WorkloadBulkUpdateEntryJsonStructure, WorkloadBulkUpdateResponseEntry
15
+ WorkloadBulkUpdateEntryJsonStructure, WorkloadBulkUpdateResponseEntry, VenObjectJsonStructure
16
16
 
17
17
  try:
18
18
  import requests as requests
@@ -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.fqdn, credentials.port, credentials.api_user,
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
 
@@ -620,6 +624,35 @@ class APIConnector:
620
624
 
621
625
  return None
622
626
 
627
+ def objects_ven_get(self,
628
+ include_deleted=False,
629
+ filter_by_ip: str = None,
630
+ filter_by_label: Optional[WorkloadsGetQueryLabelFilterJsonStructure] = None,
631
+ filter_by_name: str = None,
632
+ max_results: int = None,
633
+ async_mode=True) -> List[VenObjectJsonStructure]:
634
+ path = '/vens'
635
+ data = {}
636
+
637
+ if include_deleted:
638
+ data['include_deleted'] = 'yes'
639
+
640
+ if filter_by_ip is not None:
641
+ data['ip_address'] = filter_by_ip
642
+
643
+ if filter_by_label is not None:
644
+ # filter_by_label must be converted to json text
645
+ data['labels'] = json.dumps(filter_by_label)
646
+
647
+ if filter_by_name is not None:
648
+ data['name'] = filter_by_name
649
+
650
+ if max_results is not None:
651
+ data['max_results'] = max_results
652
+
653
+ return self.do_get_call(path=path, async_call=async_mode, params=data)
654
+
655
+
623
656
  def objects_workload_get(self,
624
657
  include_deleted=False,
625
658
  filter_by_ip: str = None,
@@ -14,7 +14,6 @@ except ImportError:
14
14
  paramiko = None
15
15
 
16
16
 
17
-
18
17
  class CredentialFileEntry(TypedDict):
19
18
  name: str
20
19
  fqdn: str
@@ -97,7 +96,7 @@ def get_all_credentials_from_file(credential_file: str ) -> List[CredentialProfi
97
96
 
98
97
 
99
98
  def get_credentials_from_file(fqdn_or_profile_name: str = None,
100
- credential_file: str = None) -> CredentialProfile:
99
+ credential_file: str = None, fail_with_an_exception=True) -> Optional[CredentialProfile]:
101
100
 
102
101
  if fqdn_or_profile_name is None:
103
102
  log.debug("No fqdn_or_profile_name provided, profile_name=default will be used")
@@ -121,9 +120,12 @@ def get_credentials_from_file(fqdn_or_profile_name: str = None,
121
120
  if credential_profile.fqdn.lower() == fqdn_or_profile_name.lower():
122
121
  return credential_profile
123
122
 
124
- raise PyloEx("No profile found in credential file '{}' with fqdn: {}".
123
+ if fail_with_an_exception:
124
+ raise PyloEx("No profile found in credential file '{}' with fqdn: {}".
125
125
  format(credential_file, fqdn_or_profile_name))
126
126
 
127
+ return None
128
+
127
129
 
128
130
  def list_potential_credential_files() -> List[str]:
129
131
  """
@@ -204,9 +206,7 @@ def create_credential_in_default_file(data: CredentialFileEntry) -> str:
204
206
  return file_path
205
207
 
206
208
 
207
- def encrypt_api_key_with_paramiko_key(ssh_key: paramiko.AgentKey, api_key: str) -> str:
208
-
209
-
209
+ def encrypt_api_key_with_paramiko_ssh_key_fernet(ssh_key: paramiko.AgentKey, api_key: str) -> str:
210
210
  def encrypt(raw: str, key: bytes) -> bytes:
211
211
  """
212
212
 
@@ -220,7 +220,7 @@ def encrypt_api_key_with_paramiko_key(ssh_key: paramiko.AgentKey, api_key: str)
220
220
 
221
221
 
222
222
  # generate a random 128bit key
223
- session_key_to_sign = os.urandom(16)
223
+ session_key_to_sign = os.urandom(32)
224
224
 
225
225
  signed_message = ssh_key.sign_ssh_data(session_key_to_sign)
226
226
 
@@ -236,7 +236,7 @@ def encrypt_api_key_with_paramiko_key(ssh_key: paramiko.AgentKey, api_key: str)
236
236
  return api_key
237
237
 
238
238
 
239
- def decrypt_api_key_with_paramiko_key(encrypted_api_key_payload: str) -> str:
239
+ def decrypt_api_key_with_paramiko_ssh_key_fernet(encrypted_api_key_payload: str) -> str:
240
240
  def decrypt(token_b64_encoded: str, key: bytes):
241
241
  f = Fernet(base64.urlsafe_b64encode(key))
242
242
  return f.decrypt(token_b64_encoded).decode('utf-8')
@@ -277,7 +277,7 @@ def decrypt_api_key(encrypted_api_key_payload: str) -> str:
277
277
  if not encrypted_api_key_payload.startswith("$encrypted$:"):
278
278
  raise PyloEx("Invalid encrypted API key format")
279
279
  if encrypted_api_key_payload.startswith("$encrypted$:ssh-Fernet:"):
280
- return decrypt_api_key_with_paramiko_key(encrypted_api_key_payload)
280
+ return decrypt_api_key_with_paramiko_ssh_key_fernet(encrypted_api_key_payload)
281
281
 
282
282
  raise PyloEx("Unsupported encryption method: {}".format(encrypted_api_key_payload.split(":")[1]))
283
283
 
@@ -121,6 +121,35 @@ class WorkloadBulkUpdateResponseEntry(TypedDict):
121
121
  message: NotRequired[str]
122
122
 
123
123
 
124
+ class VenObjectWorkloadSummaryJsonStructure(TypedDict):
125
+ href: str
126
+ mode: str
127
+ online: bool
128
+
129
+
130
+ class VenObjectJsonStructure(TypedDict):
131
+ created_at: str
132
+ created_by: Optional[HrefReferenceWithName]
133
+ description: Optional[str]
134
+ hostname: Optional[str]
135
+ href: str
136
+ labels: List[HrefReference]
137
+ name: Optional[str]
138
+ interfaces: List[WorkloadInterfaceObjectJsonStructure]
139
+ updated_at: str
140
+ updated_by: Optional[HrefReferenceWithName]
141
+ last_heartbeat_at: Optional[str]
142
+ last_goodbye_at: Optional[str]
143
+ ven_type: Literal['server', 'endpoint', 'containerized-ven']
144
+ active_pce_fqdn: Optional[str]
145
+ target_pce_fqdn: Optional[str]
146
+ workloads: List[VenObjectWorkloadSummaryJsonStructure]
147
+ version: Optional[str]
148
+ os_id: Optional[str]
149
+ os_version: Optional[str]
150
+ os_platform: Optional[str]
151
+ uid: Optional[str]
152
+
124
153
 
125
154
  class RuleServiceReferenceObjectJsonStructure(TypedDict):
126
155
  href: str
@@ -255,10 +255,9 @@ class ArraysToExcel:
255
255
  new_line.append('=HYPERLINK("{}", "{}")'.format(item,self._headers[item_index].url_text))
256
256
  else:
257
257
  new_line.append(item)
258
-
259
- length = find_length(new_line[item_index])
260
- if length > columns_max_width[item_index]:
261
- columns_max_width[item_index] = length
258
+ length = find_length(new_line[item_index])
259
+ if length > columns_max_width[item_index]:
260
+ columns_max_width[item_index] = length
262
261
 
263
262
 
264
263
  xls_data.append(new_line)
@@ -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()
@@ -13,7 +13,7 @@ class LabeledObject:
13
13
  def get_labels_dict(self):
14
14
  return self._labels.copy()
15
15
 
16
- def get_labels(self):
16
+ def get_labels(self) -> Iterable['pylo.Label']:
17
17
  return self._labels.values()
18
18
 
19
19
  def set_label(self, label :'pylo.Label'):
@@ -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
- raise pylo.PyloEx('Organization has no "version" specified')
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 = 'All' + label_separator
105
- if self.app_label is not None:
106
- if use_href:
107
- string = self.app_label.href + label_separator
108
- else:
109
- string = self.app_label.name + label_separator
110
-
111
- if self.env_label is None:
112
- string += 'All' + label_separator
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 += self.loc_label.name
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.hostname
278
+ pce_fqdn = connector.fqdn
291
279
  if pce_port is None:
292
280
  pce_port = connector.port
293
281
 
@@ -7,10 +7,20 @@ from typing import *
7
7
 
8
8
  class PortMap:
9
9
  def __init__(self):
10
- self._tcp_map = []
11
- self._udp_map = []
10
+ self._tcp_map: List[List[2]] = [] # [start, end]
11
+ self._udp_map: List[List[2]] = [] # [start, end]
12
12
  self._protocol_map = {}
13
13
 
14
+ def copy(self) -> 'PortMap':
15
+ new_map = PortMap()
16
+ new_map._tcp_map = self._tcp_map.copy()
17
+ new_map._udp_map = self._udp_map.copy()
18
+ new_map._protocol_map = self._protocol_map.copy()
19
+ return new_map
20
+
21
+ def count(self) -> int:
22
+ return len(self._tcp_map) + len(self._udp_map) + len(self._protocol_map)
23
+
14
24
  def add(self, protocol, start_port: int, end_port: int = None, skip_recalculation=False):
15
25
 
16
26
  proto = None
@@ -31,67 +41,54 @@ class PortMap:
31
41
  return
32
42
 
33
43
  if start_port is None:
44
+ start_port = end_port
45
+
46
+ if end_port is None:
34
47
  end_port = start_port
35
48
 
36
- new_entry = [start_port, end_port]
49
+ if proto == 6:
50
+ self._tcp_map.append([start_port, end_port])
51
+ else:
52
+ self._udp_map.append([start_port, end_port])
37
53
 
38
54
  if not skip_recalculation:
39
55
  self.merge_overlapping_maps()
40
56
 
41
- def merge_overlapping_maps(self):
42
- self._sort_maps()
43
-
44
- new_map = []
45
-
46
- cur_entry = None
47
-
48
- for original_entry in self._tcp_map:
49
- if cur_entry is None:
50
- cur_entry = original_entry
51
- continue
52
-
53
- cur_start = cur_entry[0]
54
- cur_end = cur_entry[1]
55
- new_start = original_entry[0]
56
- new_end = original_entry[1]
57
+ def to_list_of_objects(self) -> List[Dict]:
58
+ result = []
59
+ for entry in self._tcp_map:
60
+ result.append({'proto': 6, 'port': entry[0], 'to_port': entry[1]})
57
61
 
58
- if new_start > cur_end + 1:
59
- new_map.append(cur_entry)
60
- continue
62
+ for entry in self._udp_map:
63
+ result.append({'proto': 17, 'port': entry[0], 'to_port': entry[1]})
61
64
 
62
- if new_end > cur_end:
63
- cur_entry[1] = new_end
65
+ for proto in self._protocol_map:
66
+ result.append({'proto': proto})
64
67
 
65
- if cur_entry is not None:
66
- self._tcp_map = []
67
- else:
68
- new_map.append(cur_entry)
69
- self._tcp_map = new_map
70
-
71
- new_map = []
72
-
73
- for original_entry in self._udp_map:
74
- if cur_entry is None:
75
- cur_entry = original_entry
76
- continue
77
-
78
- cur_start = cur_entry[0]
79
- cur_end = cur_entry[1]
80
- new_start = original_entry[0]
81
- new_end = original_entry[1]
82
-
83
- if new_start > cur_end + 1:
84
- new_map.append(cur_entry)
85
- continue
68
+ return result
86
69
 
87
- if new_end > cur_end:
88
- cur_entry[1] = new_end
70
+ def merge_overlapping_maps(self):
71
+ self._sort_maps()
89
72
 
90
- if cur_entry is not None:
91
- self._udp_map = []
92
- else:
93
- new_map.append(cur_entry)
94
- self._udp_map = new_map
73
+ def merge_maps(map_list):
74
+ new_list = []
75
+ current = None
76
+ for entry in map_list:
77
+ if current is None:
78
+ current = entry
79
+ continue
80
+
81
+ if entry[0] <= current[1] + 1:
82
+ current[1] = entry[1]
83
+ else:
84
+ new_list.append(current)
85
+ current = entry
86
+ if current is not None:
87
+ new_list.append(current)
88
+ return new_list
89
+
90
+ self._tcp_map = merge_maps(self._tcp_map)
91
+ self._udp_map = merge_maps(self._udp_map)
95
92
 
96
93
  def _sort_maps(self):
97
94
  def first_entry(my_list):
@@ -1,4 +1,4 @@
1
- __version__ = "0.3.1"
1
+ __version__ = "0.3.3"
2
2
 
3
3
  import os
4
4
  import sys