illumio-pylo 0.2.5__py3-none-any.whl

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 (73) hide show
  1. illumio_pylo/API/APIConnector.py +1308 -0
  2. illumio_pylo/API/AuditLog.py +42 -0
  3. illumio_pylo/API/ClusterHealth.py +136 -0
  4. illumio_pylo/API/CredentialsManager.py +286 -0
  5. illumio_pylo/API/Explorer.py +1077 -0
  6. illumio_pylo/API/JsonPayloadTypes.py +240 -0
  7. illumio_pylo/API/RuleSearchQuery.py +128 -0
  8. illumio_pylo/API/__init__.py +0 -0
  9. illumio_pylo/AgentStore.py +139 -0
  10. illumio_pylo/Exception.py +44 -0
  11. illumio_pylo/Helpers/__init__.py +3 -0
  12. illumio_pylo/Helpers/exports.py +508 -0
  13. illumio_pylo/Helpers/functions.py +166 -0
  14. illumio_pylo/IPList.py +135 -0
  15. illumio_pylo/IPMap.py +285 -0
  16. illumio_pylo/Label.py +25 -0
  17. illumio_pylo/LabelCommon.py +48 -0
  18. illumio_pylo/LabelGroup.py +68 -0
  19. illumio_pylo/LabelStore.py +403 -0
  20. illumio_pylo/LabeledObject.py +25 -0
  21. illumio_pylo/Organization.py +258 -0
  22. illumio_pylo/Query.py +331 -0
  23. illumio_pylo/ReferenceTracker.py +41 -0
  24. illumio_pylo/Rule.py +671 -0
  25. illumio_pylo/Ruleset.py +306 -0
  26. illumio_pylo/RulesetStore.py +101 -0
  27. illumio_pylo/SecurityPrincipal.py +62 -0
  28. illumio_pylo/Service.py +256 -0
  29. illumio_pylo/SoftwareVersion.py +125 -0
  30. illumio_pylo/VirtualService.py +17 -0
  31. illumio_pylo/VirtualServiceStore.py +75 -0
  32. illumio_pylo/Workload.py +506 -0
  33. illumio_pylo/WorkloadStore.py +289 -0
  34. illumio_pylo/__init__.py +82 -0
  35. illumio_pylo/cli/NativeParsers.py +96 -0
  36. illumio_pylo/cli/__init__.py +134 -0
  37. illumio_pylo/cli/__main__.py +10 -0
  38. illumio_pylo/cli/commands/__init__.py +32 -0
  39. illumio_pylo/cli/commands/credential_manager.py +168 -0
  40. illumio_pylo/cli/commands/iplist_import_from_file.py +185 -0
  41. illumio_pylo/cli/commands/misc.py +7 -0
  42. illumio_pylo/cli/commands/ruleset_export.py +129 -0
  43. illumio_pylo/cli/commands/update_pce_objects_cache.py +44 -0
  44. illumio_pylo/cli/commands/ven_duplicate_remover.py +366 -0
  45. illumio_pylo/cli/commands/ven_idle_to_visibility.py +287 -0
  46. illumio_pylo/cli/commands/ven_upgrader.py +226 -0
  47. illumio_pylo/cli/commands/workload_export.py +251 -0
  48. illumio_pylo/cli/commands/workload_import.py +423 -0
  49. illumio_pylo/cli/commands/workload_relabeler.py +510 -0
  50. illumio_pylo/cli/commands/workload_reset_names_to_null.py +83 -0
  51. illumio_pylo/cli/commands/workload_used_in_rule_finder.py +80 -0
  52. illumio_pylo/docs/Doxygen +1757 -0
  53. illumio_pylo/tmp.py +104 -0
  54. illumio_pylo/utilities/__init__.py +0 -0
  55. illumio_pylo/utilities/cli.py +10 -0
  56. illumio_pylo/utilities/credentials.example.json +20 -0
  57. illumio_pylo/utilities/explorer_report_exporter.py +86 -0
  58. illumio_pylo/utilities/health_monitoring.py +102 -0
  59. illumio_pylo/utilities/iplist_analyzer.py +148 -0
  60. illumio_pylo/utilities/iplists_stats_duplicates_unused_finder.py +75 -0
  61. illumio_pylo/utilities/resources/iplists-import-example.csv +3 -0
  62. illumio_pylo/utilities/resources/iplists-import-example.xlsx +0 -0
  63. illumio_pylo/utilities/resources/workload-exporter-filter-example.csv +3 -0
  64. illumio_pylo/utilities/resources/workloads-import-example.csv +2 -0
  65. illumio_pylo/utilities/resources/workloads-import-example.xlsx +0 -0
  66. illumio_pylo/utilities/ven_compatibility_report_export.py +240 -0
  67. illumio_pylo/utilities/ven_idle_to_illumination.py +344 -0
  68. illumio_pylo/utilities/ven_reassign_pce.py +183 -0
  69. illumio_pylo-0.2.5.dist-info/LICENSE +176 -0
  70. illumio_pylo-0.2.5.dist-info/METADATA +197 -0
  71. illumio_pylo-0.2.5.dist-info/RECORD +73 -0
  72. illumio_pylo-0.2.5.dist-info/WHEEL +5 -0
  73. illumio_pylo-0.2.5.dist-info/top_level.txt +1 -0
@@ -0,0 +1,289 @@
1
+ from illumio_pylo import log, IP4Map, PyloEx, Workload, nice_json, Label, LabelGroup
2
+ from .Helpers import *
3
+ from .Organization import Organization
4
+ from typing import Optional, List, Union, Set
5
+
6
+
7
+ class WorkloadStore:
8
+
9
+ def __init__(self, owner: 'Organization'):
10
+ self.owner: Organization = owner
11
+ self.itemsByHRef: Dict[str, Workload] = {}
12
+
13
+ def load_workloads_from_json(self, json_list):
14
+ for json_item in json_list:
15
+ if 'name' not in json_item or 'href' not in json_item:
16
+ raise PyloEx("Cannot find 'value'/name or href for Workload in JSON:\n" + nice_json(json_item))
17
+
18
+ new_item_name = json_item['name']
19
+ new_item_href = json_item['href']
20
+
21
+ # Workload's name is None when it's provided by VEN through its hostname until it's manually overwritten
22
+ # (eventually) by someone. In such a case, you need to use hostname instead
23
+ if new_item_name is None:
24
+ if 'hostname' not in json_item:
25
+ raise PyloEx("Cannot find 'value'/hostname in JSON:\n" + nice_json(json_item))
26
+ new_item_name = json_item['hostname']
27
+
28
+ new_item = Workload(new_item_name, new_item_href, self)
29
+ new_item.load_from_json(json_item)
30
+
31
+ if new_item_href in self.itemsByHRef:
32
+ raise PyloEx("A Workload with href '%s' already exists in the table", new_item_href)
33
+
34
+ self.itemsByHRef[new_item_href] = new_item
35
+
36
+ log.debug("Found Workload '%s' with href '%s'", new_item_name, new_item_href)
37
+
38
+ def find_by_href_or_die(self, href: str) -> 'Workload':
39
+ """
40
+ Find a Workload from its HREF, throw an Exception if not found
41
+
42
+ :param href: the HREF you are looking for
43
+ :return:
44
+ :raises:
45
+ PyloEx: if no Workload matching provided HREF
46
+ """
47
+ find_object = self.itemsByHRef.get(href)
48
+ if find_object is None:
49
+ raise PyloEx("Workload with HREF '%s' was not found" % href)
50
+
51
+ return find_object
52
+
53
+ def find_by_href_or_create_tmp(self, href: str, tmp_wkl_name: str) -> 'Workload':
54
+ """
55
+ Find a Workload from its HREF, creates a fake temporary one if not found. *Reserved for developers*
56
+
57
+ :param href: the HREF you are looking for
58
+ :return:
59
+ """
60
+ find_object = self.itemsByHRef.get(href)
61
+ if find_object is not None:
62
+ return find_object
63
+
64
+ new_tmp_item = Workload(tmp_wkl_name, href, self)
65
+ new_tmp_item.deleted = True
66
+ new_tmp_item.temporary = True
67
+
68
+ self.itemsByHRef[href] = new_tmp_item
69
+
70
+ return new_tmp_item
71
+
72
+ def find_workloads_matching_label(self, label: 'Label') -> Dict[str, 'Workload']:
73
+ """
74
+ Find all Workloads which are using a specific Label.
75
+
76
+ :param label: Label you want to match on
77
+ :return: a dictionary of all matching Workloads using their HREF as key
78
+ """
79
+ result = {}
80
+
81
+ for href, workload in self.itemsByHRef.items():
82
+ if workload.is_using_label(label):
83
+ result[href] = workload
84
+
85
+ return result
86
+
87
+ def find_workloads_matching_all_labels(self, labels: Union[List[Label|LabelGroup], Dict[str,Label|LabelGroup]])\
88
+ -> Dict[str, 'Workload']:
89
+ """
90
+ Find all Workloads which are using all the Labels from a specified list/dict. Note that labels will be ordered by type
91
+ and workloads will need to match 1 Label of each specified. LabelGroups will be expanded.
92
+ If one of the labels is None, it will be ignored
93
+
94
+ :param labels: list of Labels you want to match on
95
+ :return: a dictionary of all matching Workloads using their HREF as key
96
+ """
97
+ unique_labels: Set[Union[Label, LabelGroup]] = set()
98
+
99
+ if isinstance(labels, list):
100
+ for label in labels:
101
+ if label is None:
102
+ pylo.log.debug("Label is None, skipping")
103
+ continue
104
+ if isinstance(label, LabelGroup):
105
+ unique_labels.update(label.expand_nested_to_dict_by_href().values())
106
+ else:
107
+ unique_labels.add(label)
108
+ else:
109
+ for label in labels.values():
110
+ if label is None:
111
+ pylo.log.warn("Label is None, skipping")
112
+ continue
113
+ if isinstance(label, LabelGroup):
114
+ unique_labels.update(label.expand_nested_to_dict_by_href().values())
115
+ else:
116
+ unique_labels.add(label)
117
+
118
+ labels_by_type = pylo.LabelStore.Utils.list_to_dict_by_type(unique_labels)
119
+
120
+ result = {}
121
+
122
+ for workload in self.itemsByHRef.values():
123
+ workload_is_a_match = True
124
+ for label_type, labels_to_find in labels_by_type.items():
125
+ workload_label = workload.get_label(label_type)
126
+ if workload_label is None or workload_label not in labels_to_find:
127
+ workload_is_a_match = False
128
+ break
129
+ if workload_is_a_match:
130
+ result[workload.href] = workload
131
+
132
+ return result
133
+
134
+
135
+ def find_workload_matching_forced_name(self, name: str, case_sensitive: bool = True, strip_fqdn: bool = False) -> Optional[Workload]:
136
+ """
137
+ Find a Workload based on its name (case-sensitive). Beware that if several are matching, only the first one will be returned
138
+
139
+ :param name: the name string you are looking for
140
+ :param case_sensitive: make it a case-sensitive search or not
141
+ :param strip_fqdn: remove the fqdn part of the hostname
142
+ :return: the Workload it found, None otherwise
143
+ """
144
+ if not case_sensitive:
145
+ name = name.lower()
146
+
147
+ for workload in self.itemsByHRef.values():
148
+ wkl_name = workload.forced_name
149
+ if strip_fqdn:
150
+ wkl_name = Workload.static_name_stripped_fqdn(wkl_name)
151
+ if case_sensitive:
152
+ if wkl_name == name:
153
+ return workload
154
+ else:
155
+ if wkl_name.lower() == name:
156
+ return workload
157
+
158
+ return None
159
+
160
+ def find_workload_matching_hostname(self, name: str, case_sensitive: bool = True, strip_fqdn: bool = False, fall_back_to_name: bool = False) -> Optional[Workload]:
161
+ """
162
+ Find a workload based on its hostname.Beware that if several are matching, only the first one will be returned
163
+
164
+ :param name: the name string you are looking for
165
+ :param case_sensitive: make it a case-sensitive search or not
166
+ :param strip_fqdn: remove the fqdn part of the hostname
167
+ :param fall_back_to_name: if True, will fall back to the forced name if no hostname is found
168
+ :return: the Workload it found, None otherwise
169
+ """
170
+ if not case_sensitive:
171
+ name = name.lower()
172
+
173
+ for workload in self.itemsByHRef.values():
174
+ wkl_name = workload.hostname
175
+ if wkl_name is None:
176
+ if fall_back_to_name:
177
+ wkl_name = workload.forced_name
178
+ if wkl_name is None:
179
+ continue
180
+ else:
181
+ continue
182
+ if strip_fqdn:
183
+ wkl_name = Workload.static_name_stripped_fqdn(wkl_name)
184
+ if case_sensitive:
185
+ if wkl_name == name:
186
+ return workload
187
+ else:
188
+ if wkl_name.lower() == name:
189
+ return workload
190
+
191
+ return None
192
+
193
+ def find_all_workloads_matching_hostname(self, name: str, case_sensitive: bool = True, strip_fqdn: bool = False, fall_back_to_name: bool = False) -> List[Workload]:
194
+ """
195
+ Find all workloads based on their hostnames.
196
+ :param name: the name string you are looking for
197
+ :param case_sensitive: make it a case-sensitive search or not
198
+ :param strip_fqdn: remove the fqdn part of the hostname
199
+ :param fall_back_to_name: if True, will fall back to the forced name if no hostname is found
200
+ :return: list of matching Workloads
201
+ """
202
+ result = []
203
+
204
+ if not case_sensitive:
205
+ name = name.lower()
206
+
207
+ for workload in self.itemsByHRef.values():
208
+ wkl_name = workload.hostname
209
+ if wkl_name is None:
210
+ if fall_back_to_name:
211
+ wkl_name = workload.forced_name
212
+ if wkl_name is None:
213
+ continue
214
+ else:
215
+ continue
216
+ if strip_fqdn:
217
+ wkl_name = Workload.static_name_stripped_fqdn(wkl_name)
218
+ if case_sensitive:
219
+ if wkl_name == name:
220
+ result.append(workload)
221
+ else:
222
+ if wkl_name.lower() == name:
223
+ result.append(workload)
224
+
225
+ return result
226
+
227
+ def count_workloads(self) -> int:
228
+ return len(self.itemsByHRef)
229
+
230
+ def count_managed_workloads(self) -> int:
231
+ count = 0
232
+
233
+ for item in self.itemsByHRef.values():
234
+ if not item.unmanaged and not item.deleted:
235
+ count += 1
236
+
237
+ return count
238
+
239
+ def get_managed_workloads_list(self) -> List['Workload']:
240
+ """
241
+ Get a list of all managed workloads
242
+ :return:
243
+ """
244
+ results = []
245
+ for item in self.itemsByHRef.values():
246
+ if not item.unmanaged:
247
+ results.append(item)
248
+
249
+ return results
250
+
251
+ def get_managed_workloads_dict_by_href(self) -> Dict[str, 'Workload']:
252
+ """
253
+ Get a dictionary of all managed workloads using their HREF as key
254
+ :return:
255
+ """
256
+ results = {}
257
+ for item in self.itemsByHRef.values():
258
+ if not item.unmanaged:
259
+ results[item.href] = item
260
+
261
+ return results
262
+
263
+ def count_deleted_workloads(self) -> int:
264
+ count = 0
265
+ for item in self.itemsByHRef.values():
266
+ if item.deleted:
267
+ count += 1
268
+ #print(item.href)
269
+
270
+ return count
271
+
272
+ def count_unmanaged_workloads(self, if_not_deleted=False) -> int:
273
+ count = 0
274
+
275
+ for item in self.itemsByHRef.values():
276
+ if item.unmanaged and (not if_not_deleted or (if_not_deleted and not item.deleted)):
277
+ count += 1
278
+
279
+ return count
280
+
281
+ @property
282
+ def workloads(self) -> List['Workload']:
283
+ """
284
+ Get a list of all workloads
285
+ :return:
286
+ """
287
+ return list(self.itemsByHRef.values())
288
+
289
+
@@ -0,0 +1,82 @@
1
+ import os
2
+ import sys
3
+ from typing import Callable
4
+
5
+ from .tmp import *
6
+ from .Helpers import *
7
+
8
+ from .Exception import PyloEx, PyloApiEx, PyloApiTooManyRequestsEx, PyloApiUnexpectedSyntax, PyloObjectNotFound, PyloApiRequestForbiddenEx
9
+ from .SoftwareVersion import SoftwareVersion
10
+ from .IPMap import IP4Map
11
+ from .ReferenceTracker import ReferenceTracker, Referencer, Pathable
12
+ from .API.APIConnector import APIConnector, ObjectTypes
13
+ from .API.RuleSearchQuery import RuleSearchQuery, RuleSearchQueryResolvedResultSet
14
+ from .API.ClusterHealth import ClusterHealth
15
+ from .API.Explorer import ExplorerResultSetV1, RuleCoverageQueryManager, ExplorerFilterSetV1, ExplorerQuery
16
+ from .API.AuditLog import AuditLogQuery, AuditLogQueryResultSet, AuditLogFilterSet
17
+ from .API.CredentialsManager import get_credentials_from_file
18
+ from .LabelCommon import LabelCommon
19
+ from .Label import Label
20
+ from .LabelGroup import LabelGroup
21
+ from .LabelStore import LabelStore, label_type_app, label_type_env, label_type_loc, label_type_role
22
+ from .IPList import IPList, IPListStore
23
+ from .AgentStore import AgentStore, VENAgent
24
+ from .Workload import Workload, WorkloadInterface
25
+ from .WorkloadStore import WorkloadStore
26
+ from .VirtualService import VirtualService
27
+ from .VirtualServiceStore import VirtualServiceStore
28
+ from .Service import Service, ServiceStore, PortMap, ServiceEntry
29
+ from .Rule import Rule, RuleServiceContainer, RuleSecurityPrincipalContainer, DirectServiceInRule, RuleHostContainer, RuleActorsAcceptableTypes
30
+ from .Ruleset import Ruleset, RulesetScope, RulesetScopeEntry
31
+ from .RulesetStore import RulesetStore
32
+ from .SecurityPrincipal import SecurityPrincipal, SecurityPrincipalStore
33
+ from .Organization import Organization
34
+ from .Query import Query
35
+
36
+
37
+ def get_organization(fqdn: str, port: int, api_user: str, api_key: str,
38
+ organization_id: int, verify_ssl: bool = True,
39
+ list_of_objects_to_load: Optional[List['pylo.ObjectTypes']] = None,
40
+ include_deleted_workloads: bool = False) -> Organization:
41
+ """
42
+ Load an organization from the API with parameters provided as arguments.
43
+ """
44
+ api = APIConnector(fqdn=fqdn, port=port, apiuser=api_user, apikey=api_key, org_id=organization_id,
45
+ skip_ssl_cert_check=not verify_ssl)
46
+ org = Organization(1)
47
+ org.load_from_api(api, include_deleted_workloads=include_deleted_workloads,
48
+ list_of_objects_to_load=list_of_objects_to_load)
49
+
50
+ return org
51
+
52
+
53
+ def get_organization_using_credential_file(fqdn_or_profile_name: str = None,
54
+ credential_file: str = None,
55
+ list_of_objects_to_load: Optional[List['pylo.ObjectTypes']] = None,
56
+ include_deleted_workloads: bool = False,
57
+ callback_api_objects_downloaded: Callable = None) -> Organization:
58
+ """
59
+ Credentials files will be looked for in the following order:
60
+ 1. The path provided in the credential_file argument
61
+ 2. The path provided in the Pylo_CREDENTIAL_FILE environment variable
62
+ 3. The path ~/.pylo/credentials.json
63
+ 4. Current working directory credentials.json
64
+ :param fqdn_or_profile_name:
65
+ :param credential_file:
66
+ :param list_of_objects_to_load:
67
+ :param include_deleted_workloads:
68
+ :param callback_api_objects_downloaded: callback function that will be called after each API has finished downloading all objects
69
+ :return:
70
+ """
71
+ return Organization.get_from_api_using_credential_file(fqdn_or_profile_name=fqdn_or_profile_name,
72
+ credential_file=credential_file,
73
+ list_of_objects_to_load=list_of_objects_to_load,
74
+ include_deleted_workloads=include_deleted_workloads,
75
+ callback_api_objects_downloaded=callback_api_objects_downloaded)
76
+
77
+
78
+
79
+ ignoreWorkloadsWithSameName = True
80
+
81
+ objectNotFound = object()
82
+
@@ -0,0 +1,96 @@
1
+ import argparse
2
+ from typing import Optional, List, Dict
3
+
4
+ import illumio_pylo as pylo
5
+
6
+
7
+ class BaseParser:
8
+ _action: Optional[argparse.Action] = None
9
+
10
+ def fill_parser(self, parser: argparse.ArgumentParser):
11
+ raise NotImplementedError
12
+
13
+ def execute(self, args: str | int, org: 'pylo.Organization', padding: str = '') -> Optional[List['pylo.Label']]:
14
+ raise NotImplementedError
15
+
16
+ def get_arg_name(self) -> str:
17
+ return self._action.dest
18
+
19
+
20
+ class LabelParser(BaseParser):
21
+ def __init__(self, action_name: str, action_short_name: Optional[str], label_type: Optional[str] = None, is_required: bool = True, allow_multiple: bool = False, help_text: Optional[str] = None):
22
+ self.action_name = action_name
23
+ self.action_short_name = action_short_name
24
+ self.label_type = label_type
25
+ self.is_required = is_required
26
+ self.allow_multiple = allow_multiple
27
+ self.results: Optional[List['pylo.Label']] = None
28
+ self.results_as_dict_by_href: Dict[str, 'pylo.Label'] = {}
29
+ self.help_text = help_text
30
+
31
+ def fill_parser(self, parser: argparse.ArgumentParser):
32
+
33
+ help_text = self.help_text
34
+ if help_text is None:
35
+ if self.allow_multiple:
36
+ if self.label_type is None:
37
+ help_text = f"Filter by label name. Multiple labels can be specified by separating them with a comma."
38
+ else:
39
+ help_text = f"Filter by label name of type '{self.label_type}'. Multiple labels can be specified by separating them with a comma."
40
+ else:
41
+ if self.label_type is None:
42
+ help_text = f"Filter by label name."
43
+ else:
44
+ help_text = f"Filter by label name of type '{self.label_type}'."
45
+
46
+ if self.action_short_name is None:
47
+ self._action = parser.add_argument(self.action_name, type=str,
48
+ required=self.is_required, help=help_text)
49
+ else:
50
+ self._action = parser.add_argument(self.action_short_name, self.action_name, type=str,
51
+ required=self.is_required, help=help_text)
52
+
53
+ def execute(self, args: str, org: 'pylo.Organization', padding: str = ''):
54
+ print(f"{padding}{self.action_name}:", end="")
55
+ if args is None:
56
+ print(" None")
57
+ return
58
+
59
+ if self.allow_multiple:
60
+ label_names = args.split(",")
61
+ else:
62
+ label_names = [args]
63
+
64
+ missing_labels: List[str] = []
65
+
66
+ label_objects = org.LabelStore.find_label_by_name(label_names, label_type=self.label_type, missing_labels_names=missing_labels)
67
+ if len(missing_labels) > 0:
68
+ raise pylo.PyloEx(f"Could not find labels: {pylo.string_list_to_text(missing_labels)}, please check their spelling, case and type.")
69
+
70
+ # just in case make sure it's a list of unique labels
71
+ self.results = list(set(label_objects))
72
+ self.results_as_dict_by_href = {label.href: label for label in self.results}
73
+ print(f" {pylo.string_list_to_text(self.results)}")
74
+
75
+
76
+ def filter_workloads_matching_labels(self, workloads: List['pylo.Workload']) -> List['pylo.Workload']:
77
+ if self.results is None:
78
+ return workloads
79
+
80
+ # we must group Labels by their type first
81
+ labels_dict_by_type: Dict[str, List[pylo.Label]] = {}
82
+ for label in self.results:
83
+ if labels_dict_by_type.get(label.type) is None:
84
+ labels_dict_by_type[label.type] = [label]
85
+ else:
86
+ labels_dict_by_type[label.type].append(label)
87
+
88
+ # now we can filter the workloads, they must match at least one Label per type
89
+ filtered_workloads = []
90
+ for workload in workloads:
91
+ for label_type in labels_dict_by_type:
92
+ if workload.get_label(label_type) in labels_dict_by_type[label_type]:
93
+ filtered_workloads.append(workload)
94
+
95
+ return filtered_workloads
96
+
@@ -0,0 +1,134 @@
1
+ import os
2
+ from typing import Optional, Dict
3
+
4
+ import sys
5
+ import argparse
6
+ from .NativeParsers import BaseParser
7
+
8
+ # in case user wants to run this utility while having a version of pylo already installed
9
+ if __name__ == "__main__":
10
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))
11
+
12
+ import illumio_pylo as pylo
13
+ from illumio_pylo.cli import commands
14
+
15
+
16
+ def run(forced_command_name: Optional[str] = None):
17
+
18
+ def add_native_parser_to_argparse(parser: argparse.ArgumentParser, native_parsers: object):
19
+ # each property of the native parser is an extension of BaseParser, we need to iterate over them and add them to the argparse parser
20
+ for attr_name in dir(native_parsers):
21
+ attr = getattr(native_parsers, attr_name)
22
+ if isinstance(attr, BaseParser):
23
+ attr.fill_parser(parser)
24
+
25
+ def execute_native_parsers(args: Dict, org: pylo.Organization, native_parsers: object):
26
+ first_native_parser_found = False
27
+
28
+ for attr_name in dir(native_parsers):
29
+ attr = getattr(native_parsers, attr_name)
30
+ if isinstance(attr, BaseParser):
31
+ if first_native_parser_found is False:
32
+ first_native_parser_found = True
33
+ print(" * Native CLI arguments parsing...")
34
+ attr.execute(args[attr.get_arg_name()], org, padding=' ')
35
+
36
+ parser = argparse.ArgumentParser(description='TODO LATER')
37
+ parser.add_argument('--pce', type=str, required=False,
38
+ help='hostname of the PCE')
39
+ parser.add_argument('--debug', action='store_true',
40
+ help='Enables extra debugging output in Pylo framework')
41
+ parser.add_argument('--use-cache', action='store_true',
42
+ help='For developers only')
43
+
44
+ selected_command = None
45
+
46
+ if forced_command_name is None:
47
+ sub_parsers = parser.add_subparsers(dest='command', required=True)
48
+ for command in commands.available_commands.values():
49
+ sub_parser = sub_parsers.add_parser(command.name, help='')
50
+ command.fill_parser(sub_parser)
51
+ if command.native_parsers is not None:
52
+ add_native_parser_to_argparse(sub_parser, command.native_parsers)
53
+ else:
54
+ for command in commands.available_commands.values():
55
+ if forced_command_name is not None and command.name != forced_command_name:
56
+ continue
57
+ command.fill_parser(parser)
58
+ if command.native_parsers is not None:
59
+ add_native_parser_to_argparse(parser, command.native_parsers)
60
+ selected_command = command
61
+
62
+ args = vars(parser.parse_args())
63
+
64
+ if args['debug']:
65
+ pylo.log_set_debug()
66
+
67
+ credential_profile_name = args['pce']
68
+ settings_use_cache = args['use_cache']
69
+ org: Optional[pylo.Organization] = None
70
+
71
+ # We are getting the command object associated to the command name if it was not already set (via forced_command_name)
72
+ if selected_command is None:
73
+ selected_command = commands.available_commands[args['command']]
74
+ if selected_command is None:
75
+ raise pylo.PyloEx("Cannot find command named '{}'".format(args['command']))
76
+
77
+ connector: Optional[pylo.APIConnector] = None
78
+ config_data = None
79
+
80
+ if not selected_command.credentials_manager_mode:
81
+ # credential_profile_name is required for all commands except the credential manager
82
+ if credential_profile_name is None:
83
+ raise pylo.PyloEx("The --pce argument is required for this command")
84
+ if settings_use_cache:
85
+ print(" * Loading objects from cached PCE '{}' data... ".format(credential_profile_name), end="", flush=True)
86
+ org = pylo.Organization.get_from_cache_file(credential_profile_name)
87
+ print("OK!")
88
+ connector = pylo.APIConnector.create_from_credentials_in_file(credential_profile_name, request_if_missing=False)
89
+ if connector is not None:
90
+ org.connector = connector
91
+ else:
92
+ print(" * Looking for PCE/profile '{}' credentials... ".format(credential_profile_name), end="", flush=True)
93
+ connector = pylo.APIConnector.create_from_credentials_in_file(credential_profile_name, request_if_missing=True)
94
+ print("OK!")
95
+
96
+ print(" * Downloading PCE objects from API... ".format(credential_profile_name), end="", flush=True)
97
+ config_data = connector.get_pce_objects(list_of_objects_to_load=selected_command.load_specific_objects_only)
98
+ print("OK!")
99
+
100
+ org = pylo.Organization(1)
101
+ org.connector = connector
102
+
103
+ if not selected_command.skip_pce_config_loading:
104
+ print(" * Loading objects from PCE '{}' via API... ".format(credential_profile_name), end="", flush=True)
105
+ org.pce_version = connector.get_software_version()
106
+ org.load_from_json(config_data, list_of_objects_to_load=selected_command.load_specific_objects_only)
107
+ print("OK!")
108
+
109
+ print()
110
+ if not selected_command.skip_pce_config_loading:
111
+ print(" * PCE statistics: ")
112
+ print(org.stats_to_str(padding=' '))
113
+
114
+ print(flush=True)
115
+
116
+ print("**** {} UTILITY ****".format(selected_command.name.upper()), flush=True)
117
+ if selected_command.native_parsers is None:
118
+ native_parsers = None
119
+ else:
120
+ native_parsers = selected_command.native_parsers
121
+ execute_native_parsers(args, org, native_parsers)
122
+
123
+ if native_parsers is not None:
124
+ commands.available_commands[selected_command.name].main(args, org=org, config_data=config_data, connector=connector, native_parsers=native_parsers, pce_cache_was_used=settings_use_cache)
125
+ else:
126
+ commands.available_commands[selected_command.name].main(args, org=org, config_data=config_data, connector=connector, pce_cache_was_used=settings_use_cache)
127
+
128
+ print()
129
+ print("**** END OF {} UTILITY ****".format(selected_command.name.upper()))
130
+ print()
131
+
132
+
133
+ if __name__ == "__main__":
134
+ run()
@@ -0,0 +1,10 @@
1
+ import sys
2
+ import os
3
+
4
+ if __name__ == "__main__":
5
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))
6
+
7
+ from illumio_pylo.cli import run
8
+
9
+ if __name__ == "__main__":
10
+ run()
@@ -0,0 +1,32 @@
1
+ from typing import Dict, Optional, List
2
+
3
+
4
+ class Command:
5
+ def __init__(self, name: str, main_func, parser_func, load_specific_objects_only: Optional[List[str]] = None,
6
+ skip_pce_config_loading: bool = False,
7
+ native_parsers_as_class: Optional = None,
8
+ credentials_manager_mode: bool = False):
9
+ self.name: str = name
10
+ self.main = main_func
11
+ self.fill_parser = parser_func
12
+ self.load_specific_objects_only: Optional[List[str]] = load_specific_objects_only
13
+ self.skip_pce_config_loading = skip_pce_config_loading
14
+ self.native_parsers = native_parsers_as_class
15
+ self.credentials_manager_mode = credentials_manager_mode
16
+ available_commands[name] = self
17
+
18
+
19
+ available_commands: Dict[str, Command] = {}
20
+
21
+ from .ruleset_export import command_object
22
+ from .workload_used_in_rule_finder import command_object
23
+ from .workload_relabeler import command_object
24
+ from .ven_duplicate_remover import command_object
25
+ from .workload_export import command_object
26
+ from .iplist_import_from_file import command_object
27
+ from .update_pce_objects_cache import command_object
28
+ from .ven_upgrader import command_object
29
+ from .workload_import import command_object
30
+ from .ven_idle_to_visibility import command_object
31
+ from .workload_reset_names_to_null import command_object
32
+ from .credential_manager import command_object