illumio-pylo 0.3.10__py3-none-any.whl → 0.3.12__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.
- illumio_pylo/API/APIConnector.py +145 -103
- illumio_pylo/API/CredentialsManager.py +38 -0
- illumio_pylo/API/Explorer.py +44 -0
- illumio_pylo/API/JsonPayloadTypes.py +39 -0
- illumio_pylo/Helpers/exports.py +1 -1
- illumio_pylo/IPList.py +15 -8
- illumio_pylo/IPMap.py +9 -0
- illumio_pylo/__init__.py +1 -1
- illumio_pylo/cli/commands/__init__.py +1 -0
- illumio_pylo/cli/commands/credential_manager.py +379 -4
- illumio_pylo/cli/commands/label_delete_unused.py +79 -0
- illumio_pylo/cli/commands/ui/credential_manager_ui/app.js +449 -0
- illumio_pylo/cli/commands/ui/credential_manager_ui/index.html +168 -0
- illumio_pylo/cli/commands/ui/credential_manager_ui/styles.css +430 -0
- illumio_pylo/cli/commands/ven_duplicate_remover.py +145 -93
- illumio_pylo/utilities/cli.py +4 -1
- illumio_pylo/utilities/health_monitoring.py +5 -1
- {illumio_pylo-0.3.10.dist-info → illumio_pylo-0.3.12.dist-info}/METADATA +18 -11
- {illumio_pylo-0.3.10.dist-info → illumio_pylo-0.3.12.dist-info}/RECORD +22 -18
- {illumio_pylo-0.3.10.dist-info → illumio_pylo-0.3.12.dist-info}/WHEEL +1 -1
- {illumio_pylo-0.3.10.dist-info → illumio_pylo-0.3.12.dist-info/licenses}/LICENSE +0 -0
- {illumio_pylo-0.3.10.dist-info → illumio_pylo-0.3.12.dist-info}/top_level.txt +0 -0
|
@@ -2,6 +2,7 @@ from typing import Dict, List, Literal, Optional
|
|
|
2
2
|
import datetime
|
|
3
3
|
import click
|
|
4
4
|
import argparse
|
|
5
|
+
import os
|
|
5
6
|
|
|
6
7
|
import illumio_pylo as pylo
|
|
7
8
|
from illumio_pylo import ExcelHeader
|
|
@@ -10,7 +11,7 @@ from .utils.misc import make_filename_with_timestamp
|
|
|
10
11
|
from . import Command
|
|
11
12
|
|
|
12
13
|
command_name = 'ven-duplicate-remover'
|
|
13
|
-
objects_load_filter = ['labels']
|
|
14
|
+
objects_load_filter = ['labels', 'workloads']
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
def fill_parser(parser: argparse.ArgumentParser):
|
|
@@ -37,8 +38,18 @@ def fill_parser(parser: argparse.ArgumentParser):
|
|
|
37
38
|
parser.add_argument('--limit-number-of-deleted-workloads', '-l', type=int, default=None,
|
|
38
39
|
help='Limit the number of workloads to be deleted, for a limited test run for example.')
|
|
39
40
|
|
|
41
|
+
# New option: don't delete if labels mismatch across duplicates
|
|
42
|
+
parser.add_argument('--do-not-delete-if-labels-mismatch', action='store_true',
|
|
43
|
+
help='Do not delete workloads for a duplicated hostname if the workloads do not all have the same set of labels')
|
|
44
|
+
|
|
45
|
+
# New option: ignore PCE online status and allow online workloads to be considered for deletion
|
|
46
|
+
parser.add_argument('--ignore-pce-online-status', action='store_true',
|
|
47
|
+
help='Bypass the logic that keeps online workloads; when set online workloads will be treated like offline ones for deletion decisions')
|
|
48
|
+
|
|
40
49
|
parser.add_argument('--output-dir', '-o', type=str, required=False, default="output",
|
|
41
50
|
help='Directory where to write the report file(s)')
|
|
51
|
+
parser.add_argument('--output-filename', type=str, default=None,
|
|
52
|
+
help='Write report to the specified file (or basename) instead of using the default timestamped filename. If multiple formats are requested, the provided path\'s extension will be replaced/added per format.')
|
|
42
53
|
|
|
43
54
|
|
|
44
55
|
def __main(args, org: pylo.Organization, pce_cache_was_used: bool, **kwargs):
|
|
@@ -55,11 +66,16 @@ def __main(args, org: pylo.Organization, pce_cache_was_used: bool, **kwargs):
|
|
|
55
66
|
arg_do_not_delete_if_last_heartbeat_is_more_recent_than = args['do_not_delete_if_last_heartbeat_is_more_recent_than']
|
|
56
67
|
arg_override_pce_offline_timer_to = args['override_pce_offline_timer_to']
|
|
57
68
|
arg_limit_number_of_deleted_workloads = args['limit_number_of_deleted_workloads']
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
69
|
+
arg_ignore_pce_online_status = args['ignore_pce_online_status'] is True
|
|
70
|
+
arg_do_not_delete_if_labels_mismatch = args['do_not_delete_if_labels_mismatch'] is True
|
|
71
|
+
arg_report_output_dir: str = args['output_dir']
|
|
72
|
+
|
|
73
|
+
# Determine output filename behavior: user provided filename/basename or use timestamped prefix
|
|
74
|
+
arg_output_filename: Optional[str] = args.get('output_filename')
|
|
75
|
+
if arg_output_filename is None:
|
|
76
|
+
output_file_prefix = make_filename_with_timestamp('ven-duplicate-removal_', arg_report_output_dir)
|
|
77
|
+
else:
|
|
78
|
+
output_file_prefix = None
|
|
63
79
|
|
|
64
80
|
csv_report_headers = pylo.ExcelHeaderSet([
|
|
65
81
|
ExcelHeader(name='name', max_width=40),
|
|
@@ -88,54 +104,18 @@ def __main(args, org: pylo.Organization, pce_cache_was_used: bool, **kwargs):
|
|
|
88
104
|
raise pylo.PyloEx("Cannot find label '{}' in the PCE".format(label_name))
|
|
89
105
|
filter_labels.append(label)
|
|
90
106
|
|
|
91
|
-
#
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
else:
|
|
97
|
-
filter_labels_list_of_list: List[List[pylo.Label]] = []
|
|
98
|
-
# convert filter_labels dict to an array of arrays
|
|
99
|
-
for label_type, label_list in org.LabelStore.Utils.list_to_dict_by_type(filter_labels).items():
|
|
100
|
-
filter_labels_list_of_list.append(label_list)
|
|
101
|
-
|
|
102
|
-
# convert filter_labels_list_of_list to a matrix of all possibilities
|
|
103
|
-
# example: [[a,b],[c,d]] becomes [[a,c],[a,d],[b,c],[b,d]]
|
|
104
|
-
filter_labels_matrix = [[]]
|
|
105
|
-
for label_list in filter_labels_list_of_list:
|
|
106
|
-
new_matrix = []
|
|
107
|
-
for label in label_list:
|
|
108
|
-
for row in filter_labels_matrix:
|
|
109
|
-
new_row = row.copy()
|
|
110
|
-
new_row.append(label.href)
|
|
111
|
-
new_matrix.append(new_row)
|
|
112
|
-
filter_labels_matrix = new_matrix
|
|
113
|
-
|
|
114
|
-
workloads_json = org.connector.objects_workload_get(async_mode=False, max_results=1000000, filter_by_label=filter_labels_matrix)
|
|
115
|
-
|
|
116
|
-
org.WorkloadStore.load_workloads_from_json(workloads_json)
|
|
117
|
-
|
|
118
|
-
print("OK! {} workloads loaded".format(org.WorkloadStore.count_workloads()))
|
|
119
|
-
# </editor-fold>
|
|
120
|
-
|
|
121
|
-
all_workloads: List[pylo.Workload] # the list of all workloads to be processed
|
|
122
|
-
|
|
123
|
-
if pce_cache_was_used:
|
|
124
|
-
# if some filters were used, let's apply them now
|
|
125
|
-
print("* Filtering workloads loaded from cache based on their labels... ", end='', flush=True)
|
|
126
|
-
# if some label filters were used, we will apply them at later stage
|
|
127
|
-
all_workloads: List[pylo.Workload] = list((org.WorkloadStore.find_workloads_matching_all_labels(filter_labels)).values())
|
|
128
|
-
print("OK! {} workloads left after filtering".format(len(all_workloads)))
|
|
129
|
-
else:
|
|
130
|
-
# filter was already applied during the download from the PCE
|
|
131
|
-
all_workloads = org.WorkloadStore.workloads
|
|
107
|
+
# if some filters were used, let's apply them now
|
|
108
|
+
print("* Filtering workloads loaded based on their labels... ", end='', flush=True)
|
|
109
|
+
# if some label filters were used, we will apply them at later stage
|
|
110
|
+
all_workloads: List[pylo.Workload] = list((org.WorkloadStore.find_workloads_matching_all_labels(filter_labels)).values())
|
|
111
|
+
print("OK! {} workloads left after filtering".format(len(all_workloads)))
|
|
132
112
|
|
|
133
113
|
def add_workload_to_report(workload: pylo.Workload, action: str):
|
|
134
114
|
url_link_to_pce = workload.get_pce_ui_url()
|
|
135
115
|
new_row = {
|
|
136
116
|
'hostname': workload.hostname,
|
|
137
|
-
'online': workload.online,
|
|
138
|
-
'last_heartbeat': workload.ven_agent.get_last_heartbeat_date().strftime('%Y-%m-%d %H:%M'),
|
|
117
|
+
'online': workload.online if not workload.unmanaged else 'UNMANAGED',
|
|
118
|
+
'last_heartbeat': workload.ven_agent.get_last_heartbeat_date().strftime('%Y-%m-%d %H:%M') if not workload.unmanaged else 'UNMANAGED',
|
|
139
119
|
'created_at': workload.created_at_datetime().strftime('%Y-%m-%d %H:%M'),
|
|
140
120
|
'href': workload.href,
|
|
141
121
|
'link_to_pce': url_link_to_pce,
|
|
@@ -147,9 +127,8 @@ def __main(args, org: pylo.Organization, pce_cache_was_used: bool, **kwargs):
|
|
|
147
127
|
|
|
148
128
|
sheet.add_line_from_object(new_row)
|
|
149
129
|
|
|
150
|
-
duplicated_hostnames = DuplicateRecordManager(arg_override_pce_offline_timer_to)
|
|
151
|
-
|
|
152
130
|
print(" * Looking for VEN with duplicated hostname(s)")
|
|
131
|
+
duplicated_hostnames = DuplicateRecordManager(arg_override_pce_offline_timer_to)
|
|
153
132
|
|
|
154
133
|
for workload in all_workloads:
|
|
155
134
|
if workload.deleted:
|
|
@@ -161,10 +140,12 @@ def __main(args, org: pylo.Organization, pce_cache_was_used: bool, **kwargs):
|
|
|
161
140
|
|
|
162
141
|
print(" * Found {} duplicated hostnames".format(duplicated_hostnames.count_duplicates()))
|
|
163
142
|
|
|
164
|
-
delete_tracker = org.connector.new_tracker_workload_multi_delete()
|
|
143
|
+
delete_tracker = org.connector.new_tracker_workload_multi_delete() # tracker to handle deletions, it will be executed later
|
|
165
144
|
|
|
145
|
+
# Process each duplicated hostname record
|
|
166
146
|
for dup_hostname, dup_record in duplicated_hostnames._records.items():
|
|
167
|
-
|
|
147
|
+
|
|
148
|
+
if not dup_record.has_duplicates(): # no duplicates, skip
|
|
168
149
|
continue
|
|
169
150
|
|
|
170
151
|
print(" - hostname '{}' has duplicates. ({} online, {} offline, {} unmanaged)".format(dup_hostname,
|
|
@@ -172,48 +153,88 @@ def __main(args, org: pylo.Organization, pce_cache_was_used: bool, **kwargs):
|
|
|
172
153
|
len(dup_record.offline),
|
|
173
154
|
len(dup_record.unmanaged)))
|
|
174
155
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
156
|
+
# If the new flag was passed, ensure all workloads under this duplicate record have identical labels
|
|
157
|
+
if arg_do_not_delete_if_labels_mismatch:
|
|
158
|
+
label_strings = set()
|
|
159
|
+
for wkl in dup_record.all:
|
|
160
|
+
# Use workload.get_labels_str() to produce a stable representation across label types
|
|
161
|
+
lbl_str = wkl.get_labels_str()
|
|
162
|
+
label_strings.add(lbl_str)
|
|
163
|
+
|
|
164
|
+
if len(label_strings) > 1:
|
|
165
|
+
print(" - IGNORED: workloads for hostname '{}' have mismatching labels".format(dup_hostname))
|
|
166
|
+
for wkl in dup_record.all:
|
|
167
|
+
add_workload_to_report(wkl, "ignored (labels mismatch)")
|
|
168
|
+
continue
|
|
169
|
+
|
|
170
|
+
if not dup_record.has_no_managed_workloads():
|
|
171
|
+
latest_created_workload = dup_record.find_latest_managed_created_at()
|
|
172
|
+
latest_heartbeat_workload = dup_record.find_latest_heartbeat()
|
|
173
|
+
|
|
174
|
+
print(" - Latest created at {} and latest heartbeat at {}".format(latest_created_workload.created_at, latest_heartbeat_workload.ven_agent.get_last_heartbeat_date()))
|
|
175
|
+
|
|
176
|
+
if not arg_ignore_pce_online_status and dup_record.count_online() == 0:
|
|
177
|
+
print(" - IGNORED: there is no VEN online")
|
|
178
|
+
for wkl in dup_record.offline:
|
|
179
|
+
add_workload_to_report(wkl, "ignored (no VEN online)")
|
|
180
|
+
continue
|
|
181
|
+
|
|
182
|
+
if dup_record.count_online() > 1:
|
|
183
|
+
print(" - WARNING: there are more than 1 VEN online")
|
|
184
|
+
|
|
185
|
+
# Don't delete online workloads but still show them in the report
|
|
186
|
+
if not arg_ignore_pce_online_status:
|
|
187
|
+
for wkl in dup_record.online:
|
|
188
|
+
add_workload_to_report(wkl, "ignored (VEN is online)")
|
|
189
|
+
|
|
190
|
+
# Build the list of candidate workloads to consider for deletion. If --ignore-pce-online-status
|
|
191
|
+
# is passed, include online workloads among the candidates.
|
|
192
|
+
if arg_ignore_pce_online_status:
|
|
193
|
+
deletion_candidates = list(dup_record.offline) + list(dup_record.online)
|
|
202
194
|
else:
|
|
195
|
+
deletion_candidates = list(dup_record.offline)
|
|
196
|
+
|
|
197
|
+
for wkl in deletion_candidates:
|
|
198
|
+
if arg_do_not_delete_the_most_recent_workload and wkl is latest_created_workload:
|
|
199
|
+
print(" - IGNORED: wkl {}/{} is the most recent".format(wkl.get_name_stripped_fqdn(), wkl.href))
|
|
200
|
+
add_workload_to_report(wkl, "ignored (it is the most recently created)")
|
|
201
|
+
elif arg_do_not_delete_the_most_recently_heartbeating_workload and wkl is latest_heartbeat_workload:
|
|
202
|
+
print(" - IGNORED: wkl {}/{} is the most recently heartbeating".format(wkl.get_name_stripped_fqdn(), wkl.href))
|
|
203
|
+
add_workload_to_report(wkl, "ignored (it is the most recently heartbeating)")
|
|
204
|
+
elif arg_do_not_delete_if_last_heartbeat_is_more_recent_than is not None and wkl.ven_agent.get_last_heartbeat_date() > datetime.datetime.now() - datetime.timedelta(days=arg_do_not_delete_if_last_heartbeat_is_more_recent_than):
|
|
205
|
+
print(" - IGNORED: wkl {}/{} has a last heartbeat more recent than {} days".format(wkl.get_name_stripped_fqdn(), wkl.href, arg_do_not_delete_if_last_heartbeat_is_more_recent_than))
|
|
206
|
+
add_workload_to_report(wkl, "ignored (last heartbeat is more recent than {} days)".format(arg_do_not_delete_if_last_heartbeat_is_more_recent_than))
|
|
207
|
+
else:
|
|
208
|
+
if arg_limit_number_of_deleted_workloads is not None and delete_tracker.count_entries() >= arg_limit_number_of_deleted_workloads:
|
|
209
|
+
print(" - IGNORED: wkl {}/{} because the limit of {} workloads to be deleted was reached".format(wkl.get_name_stripped_fqdn(), wkl.href, arg_limit_number_of_deleted_workloads))
|
|
210
|
+
add_workload_to_report(wkl, "ignored (limit of {} workloads to be deleted was reached)".format(arg_limit_number_of_deleted_workloads))
|
|
211
|
+
else:
|
|
212
|
+
delete_tracker.add_workload(wkl)
|
|
213
|
+
print(" - added wkl {}/{} to the delete list".format(wkl.get_name_stripped_fqdn(), wkl.href))
|
|
214
|
+
|
|
215
|
+
for wkl in dup_record.unmanaged:
|
|
203
216
|
if arg_limit_number_of_deleted_workloads is not None and delete_tracker.count_entries() >= arg_limit_number_of_deleted_workloads:
|
|
204
217
|
print(" - IGNORED: wkl {}/{} because the limit of {} workloads to be deleted was reached".format(wkl.get_name_stripped_fqdn(), wkl.href, arg_limit_number_of_deleted_workloads))
|
|
205
218
|
add_workload_to_report(wkl, "ignored (limit of {} workloads to be deleted was reached)".format(arg_limit_number_of_deleted_workloads))
|
|
206
219
|
else:
|
|
207
220
|
delete_tracker.add_workload(wkl)
|
|
208
|
-
print(" - added
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
if
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
221
|
+
print(" - added unmanaged wkl {}/{} to the delete list".format(wkl.get_name_stripped_fqdn(), wkl.href))
|
|
222
|
+
else:
|
|
223
|
+
latest_created_workload = dup_record.find_latest_unmanaged_created_at()
|
|
224
|
+
if latest_created_workload is None:
|
|
225
|
+
raise pylo.PyloEx("Internal error: cannot find the latest created unmanaged workload for hostname '{}'".format(dup_hostname))
|
|
226
|
+
print(" - All workloads are unmanaged. Latest created at {} will be kept".format(latest_created_workload.created_at))
|
|
227
|
+
for wkl in dup_record.unmanaged:
|
|
228
|
+
if wkl is latest_created_workload:
|
|
229
|
+
print(" - IGNORED: wkl {}/{} is the most recent".format(wkl.get_name_stripped_fqdn(), wkl.href))
|
|
230
|
+
add_workload_to_report(wkl, "ignored (it is the most recently created)")
|
|
231
|
+
else:
|
|
232
|
+
if arg_limit_number_of_deleted_workloads is not None and delete_tracker.count_entries() >= arg_limit_number_of_deleted_workloads:
|
|
233
|
+
print(" - IGNORED: wkl {}/{} because the limit of {} workloads to be deleted was reached".format(wkl.get_name_stripped_fqdn(), wkl.href, arg_limit_number_of_deleted_workloads))
|
|
234
|
+
add_workload_to_report(wkl, "ignored (limit of {} workloads to be deleted was reached)".format(arg_limit_number_of_deleted_workloads))
|
|
235
|
+
else:
|
|
236
|
+
delete_tracker.add_workload(wkl)
|
|
237
|
+
print(" - added unmanaged wkl {}/{} to the delete list".format(wkl.get_name_stripped_fqdn(), wkl.href))
|
|
217
238
|
|
|
218
239
|
print()
|
|
219
240
|
|
|
@@ -239,7 +260,8 @@ def __main(args, org: pylo.Organization, pce_cache_was_used: bool, **kwargs):
|
|
|
239
260
|
for wkl in delete_tracker.workloads:
|
|
240
261
|
add_workload_to_report(wkl, "TO BE DELETED (aborted by user)")
|
|
241
262
|
else:
|
|
242
|
-
|
|
263
|
+
# execute deletions
|
|
264
|
+
print(" * Executing deletion requests ... ", end='', flush=True)
|
|
243
265
|
delete_tracker.execute(unpair_agents=True)
|
|
244
266
|
print("DONE")
|
|
245
267
|
|
|
@@ -259,13 +281,29 @@ def __main(args, org: pylo.Organization, pce_cache_was_used: bool, **kwargs):
|
|
|
259
281
|
for wkl in delete_tracker.workloads:
|
|
260
282
|
add_workload_to_report(wkl, "TO BE DELETED (no confirm option used)")
|
|
261
283
|
|
|
284
|
+
# if report is not empty, write it to disk
|
|
262
285
|
if sheet.lines_count() >= 1:
|
|
263
286
|
if len(report_wanted_format) < 1:
|
|
264
287
|
print(" * No report format was specified, no report will be generated")
|
|
265
288
|
else:
|
|
266
289
|
sheet.reorder_lines(['hostname']) # sort by hostname for better readability
|
|
267
290
|
for report_format in report_wanted_format:
|
|
268
|
-
|
|
291
|
+
# Choose output filename depending on whether user provided --output-filename
|
|
292
|
+
if arg_output_filename is None:
|
|
293
|
+
output_filename = output_file_prefix + '.' + report_format
|
|
294
|
+
else:
|
|
295
|
+
# If only one format requested, use the provided filename as-is
|
|
296
|
+
if len(report_wanted_format) == 1:
|
|
297
|
+
output_filename = arg_output_filename
|
|
298
|
+
else:
|
|
299
|
+
base = os.path.splitext(arg_output_filename)[0]
|
|
300
|
+
output_filename = base + '.' + report_format
|
|
301
|
+
|
|
302
|
+
# Ensure parent directory exists
|
|
303
|
+
output_directory = os.path.dirname(output_filename)
|
|
304
|
+
if output_directory:
|
|
305
|
+
os.makedirs(output_directory, exist_ok=True)
|
|
306
|
+
|
|
269
307
|
print(" * Writing report file '{}' ... ".format(output_filename), end='', flush=True)
|
|
270
308
|
if report_format == 'csv':
|
|
271
309
|
sheet.write_to_csv(output_filename)
|
|
@@ -324,7 +362,12 @@ class DuplicateRecordManager:
|
|
|
324
362
|
return True
|
|
325
363
|
return False
|
|
326
364
|
|
|
327
|
-
def
|
|
365
|
+
def has_no_managed_workloads(self):
|
|
366
|
+
if len(self.offline) + len(self.online) == 0:
|
|
367
|
+
return True
|
|
368
|
+
return False
|
|
369
|
+
|
|
370
|
+
def find_latest_managed_created_at(self) -> Optional['pylo.Workload']:
|
|
328
371
|
latest: Optional[pylo.Workload] = None
|
|
329
372
|
for wkl in self.all:
|
|
330
373
|
if wkl.unmanaged:
|
|
@@ -333,7 +376,16 @@ class DuplicateRecordManager:
|
|
|
333
376
|
latest = wkl
|
|
334
377
|
return latest
|
|
335
378
|
|
|
336
|
-
def
|
|
379
|
+
def find_latest_unmanaged_created_at(self) -> Optional['pylo.Workload']:
|
|
380
|
+
latest: Optional[pylo.Workload] = None
|
|
381
|
+
for wkl in self.all:
|
|
382
|
+
if not wkl.unmanaged:
|
|
383
|
+
continue
|
|
384
|
+
if latest is None or wkl.created_at > latest.created_at:
|
|
385
|
+
latest = wkl
|
|
386
|
+
return latest
|
|
387
|
+
|
|
388
|
+
def find_latest_heartbeat(self) -> Optional['pylo.Workload']:
|
|
337
389
|
latest: Optional[pylo.Workload] = None
|
|
338
390
|
for wkl in self.all:
|
|
339
391
|
if wkl.unmanaged:
|
illumio_pylo/utilities/cli.py
CHANGED
|
@@ -4,7 +4,10 @@ import os
|
|
|
4
4
|
import sys
|
|
5
5
|
|
|
6
6
|
# in case user wants to run this utility while having a version of pylo already installed
|
|
7
|
-
|
|
7
|
+
if __name__ == "__main__":
|
|
8
|
+
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))
|
|
9
|
+
pass
|
|
10
|
+
|
|
8
11
|
import illumio_pylo.cli
|
|
9
12
|
|
|
10
13
|
illumio_pylo.cli.run()
|
|
@@ -4,7 +4,11 @@ import argparse
|
|
|
4
4
|
import math
|
|
5
5
|
from datetime import datetime
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
# in case user wants to run this utility while having a version of pylo already installed
|
|
8
|
+
if __name__ == "__main__":
|
|
9
|
+
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))
|
|
10
|
+
pass
|
|
11
|
+
|
|
8
12
|
import illumio_pylo as pylo
|
|
9
13
|
|
|
10
14
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: illumio_pylo
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.12
|
|
4
4
|
Summary: A set of tools and library for working with Illumio PCE
|
|
5
5
|
Home-page: https://github.com/cpainchaud/pylo
|
|
6
6
|
Author: Christophe Painchaud
|
|
7
7
|
Author-email: shellescape@gmail.com
|
|
8
|
-
License:
|
|
8
|
+
License: Apache License
|
|
9
9
|
Version 2.0, January 2004
|
|
10
10
|
http://www.apache.org/licenses/
|
|
11
11
|
|
|
@@ -185,13 +185,20 @@ Project-URL: Homepage, https://github.com/cpainchaud/pylo
|
|
|
185
185
|
Project-URL: Issues, https://github.com/cpainchaud/pylo/issues
|
|
186
186
|
Requires-Python: >=3.11
|
|
187
187
|
License-File: LICENSE
|
|
188
|
-
Requires-Dist: click
|
|
189
|
-
Requires-Dist: colorama
|
|
190
|
-
Requires-Dist: cryptography
|
|
191
|
-
Requires-Dist: openpyxl
|
|
192
|
-
Requires-Dist: paramiko
|
|
193
|
-
Requires-Dist: prettytable
|
|
194
|
-
Requires-Dist: requests
|
|
195
|
-
Requires-Dist: xlsxwriter
|
|
188
|
+
Requires-Dist: click==8.1.7
|
|
189
|
+
Requires-Dist: colorama~=0.4.4
|
|
190
|
+
Requires-Dist: cryptography==44.0.1
|
|
191
|
+
Requires-Dist: openpyxl~=3.1.3
|
|
192
|
+
Requires-Dist: paramiko~=3.4.0
|
|
193
|
+
Requires-Dist: prettytable~=3.10.0
|
|
194
|
+
Requires-Dist: requests~=2.32.0
|
|
195
|
+
Requires-Dist: xlsxwriter~=3.2.0
|
|
196
|
+
Requires-Dist: flask~=2.2.0
|
|
197
|
+
Dynamic: author
|
|
198
|
+
Dynamic: author-email
|
|
199
|
+
Dynamic: description
|
|
200
|
+
Dynamic: home-page
|
|
201
|
+
Dynamic: license-file
|
|
202
|
+
Dynamic: requires-python
|
|
196
203
|
|
|
197
204
|
README.md
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
illumio_pylo/AgentStore.py,sha256=7xWpjGJHK5Xp69M-WzqcDeC1WMLCeMii1D_hh6xVqb4,5312
|
|
2
2
|
illumio_pylo/Exception.py,sha256=3lxS-ANBaEvHAKhDb8UzNLj5IpQBmRHNs4YkHONmQjs,1033
|
|
3
|
-
illumio_pylo/IPList.py,sha256=
|
|
4
|
-
illumio_pylo/IPMap.py,sha256=
|
|
3
|
+
illumio_pylo/IPList.py,sha256=0fPsX6TYUQmmyWMQpl-QsMll9JwpvEiGN6lmbUtBwDU,4614
|
|
4
|
+
illumio_pylo/IPMap.py,sha256=XrC-qvnTUWCVq38NCRDebDnXWQYCAyTRtdVX6fk9DiE,10575
|
|
5
5
|
illumio_pylo/Label.py,sha256=hGeU3zQW8GIfRekSVcRAiTQbezbjYTF1nGHoH9DxvyY,834
|
|
6
6
|
illumio_pylo/LabelCommon.py,sha256=fgmzE8tztufAXXzLgmOqo74z66e8uAyJYnM917e8wRE,1486
|
|
7
7
|
illumio_pylo/LabelGroup.py,sha256=ZPC3xBLJUEhStyBTMB3fTTcEi8Z4CDjHUwnq_T-8p5Y,2674
|
|
@@ -21,30 +21,31 @@ illumio_pylo/VirtualServiceStore.py,sha256=MNTwo1cvteUuID6JniWUk5oRHQHGY4OwrWvFa
|
|
|
21
21
|
illumio_pylo/Workload.py,sha256=k6s420rExq_Nb453f9UYjsLyNfxcCGuhgX6sPDBx9kU,19813
|
|
22
22
|
illumio_pylo/WorkloadStore.py,sha256=3C6SMU0wRlet6C6UVbjkYNsTY7vkyK_ZwqM1dlCBpsQ,10989
|
|
23
23
|
illumio_pylo/WorkloadStoreSubClasses.py,sha256=P9dUqT4Hb_tTCW14RmfJU3kVp5Zx9ZcfzeuD2VdsPDs,6101
|
|
24
|
-
illumio_pylo/__init__.py,sha256=
|
|
24
|
+
illumio_pylo/__init__.py,sha256=V0HyPA1VXx4jie4Vb4dNQIa74v9betxHervNCy05B5o,4173
|
|
25
25
|
illumio_pylo/tmp.py,sha256=8WSnsdgnLgVS2m4lxc6qCpCfefADV77B8MqiwdqFkos,3914
|
|
26
|
-
illumio_pylo/API/APIConnector.py,sha256=
|
|
26
|
+
illumio_pylo/API/APIConnector.py,sha256=Uf_uYwl7qtCI8qXm6r-S5itXta0X7aLFXmwy6S05uPo,64281
|
|
27
27
|
illumio_pylo/API/AuditLog.py,sha256=p0mfjrE5S8qoJgA5LIP_XGFBP3iL86Nl6BQEmhMVrPA,1533
|
|
28
28
|
illumio_pylo/API/ClusterHealth.py,sha256=GdMpVQrHUW4zLM-409GcPHM8H8b3LAppO37ZcUZyT_Q,5122
|
|
29
|
-
illumio_pylo/API/CredentialsManager.py,sha256=
|
|
30
|
-
illumio_pylo/API/Explorer.py,sha256=
|
|
31
|
-
illumio_pylo/API/JsonPayloadTypes.py,sha256=
|
|
29
|
+
illumio_pylo/API/CredentialsManager.py,sha256=noIs8IuOIjh0Obt4KZ2I0O05YoBv-2_wqkxwdGTpKNU,14263
|
|
30
|
+
illumio_pylo/API/Explorer.py,sha256=fZQDkjbbJTYYOAuVqsbb7STJDNKFVj2U5LsF4yQN6TE,49201
|
|
31
|
+
illumio_pylo/API/JsonPayloadTypes.py,sha256=wrKMW3xSTM-PQk6ABUI4lNu-HAQMtnfaZ6FjGA1yypw,8963
|
|
32
32
|
illumio_pylo/API/RuleSearchQuery.py,sha256=O0-MsUXhwmywoO0G-GXnLq6kkVC9LgmxMZwqVKc_oJE,5325
|
|
33
33
|
illumio_pylo/API/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
34
|
illumio_pylo/Helpers/__init__.py,sha256=6E2eTZe-4qfPKGjRRQNtYsPrBhJSAjbdvv_DpniV_rY,49
|
|
35
|
-
illumio_pylo/Helpers/exports.py,sha256=
|
|
35
|
+
illumio_pylo/Helpers/exports.py,sha256=3lme5g1UZYSlEkvfT3gU5dj86ndX0NIGQVFsAw2nZWQ,21896
|
|
36
36
|
illumio_pylo/Helpers/functions.py,sha256=WmLCJjAHPLqJH6WM7bKSz4ZbP2zDAFJ73FCoJZRTIJE,4635
|
|
37
37
|
illumio_pylo/cli/NativeParsers.py,sha256=nzDL54EV0J-Iz0P9EkeiPl6DWQBSbCu-MpEPRad3j6c,4055
|
|
38
38
|
illumio_pylo/cli/__init__.py,sha256=hgp7KG4FZujnRnId3A1tAoaYpUDFkE_Fv2wXyF02GNM,7737
|
|
39
39
|
illumio_pylo/cli/__main__.py,sha256=ll1gK8k1YL_kPsImI7WVlw2sCyNyhocnuCqko6mGaYI,223
|
|
40
|
-
illumio_pylo/cli/commands/__init__.py,sha256=
|
|
41
|
-
illumio_pylo/cli/commands/credential_manager.py,sha256=
|
|
40
|
+
illumio_pylo/cli/commands/__init__.py,sha256=_M2qTOOfCN3FVnL_0j6CgfwYmatvobzwierJDtlVtz0,1537
|
|
41
|
+
illumio_pylo/cli/commands/credential_manager.py,sha256=v7Jjbf7iFiUndN7ScKz1Wz1UBMDasqM0myjiV5LpYP4,27209
|
|
42
42
|
illumio_pylo/cli/commands/iplist_analyzer.py,sha256=OJB8hSDzLhICCkFF5NaRC3a0uCUSfaEDuJb2CLUJgu4,3709
|
|
43
43
|
illumio_pylo/cli/commands/iplist_import_from_file.py,sha256=yqB6VvDT72VxC8tIyu2wRixorwzarhWF6t8J-MvLGlM,9836
|
|
44
|
+
illumio_pylo/cli/commands/label_delete_unused.py,sha256=KRJDppSQFonKVet9kjrPOaHUiIhahfjHMs92KAE9mYQ,3434
|
|
44
45
|
illumio_pylo/cli/commands/ruleset_export.py,sha256=MsT-jd0BzA_cpZcvbKtkD1Dvwqt6_9F5Q1vp8-qfEo0,6080
|
|
45
46
|
illumio_pylo/cli/commands/update_pce_objects_cache.py,sha256=vSVSA9K9mXQhfiQPLoH7uEcSz5j1JddQW6UGGYvydKQ,1255
|
|
46
47
|
illumio_pylo/cli/commands/ven_compatibility_report_export.py,sha256=Hp58Z0cj-hX8tpcD9IyT0c2c36CutT9rrfhTfgx9sbI,8070
|
|
47
|
-
illumio_pylo/cli/commands/ven_duplicate_remover.py,sha256=
|
|
48
|
+
illumio_pylo/cli/commands/ven_duplicate_remover.py,sha256=zPLbuZ3m2sFP6IbeZeUGM3R63K-ih8Db3C6H-JSqPNo,23397
|
|
48
49
|
illumio_pylo/cli/commands/ven_idle_to_visibility.py,sha256=ez8NbryK_I7motzkhLWHOdKl0Uh-zCkO4ASD1exsOkY,13352
|
|
49
50
|
illumio_pylo/cli/commands/ven_upgrader.py,sha256=h0XCcI-kMzq9GC-ovIph7r0-BObo_4GHdyuMnVfRYZA,7158
|
|
50
51
|
illumio_pylo/cli/commands/workload_export.py,sha256=EcQR8AacJVe7rOqYH-HFxyTchwHHQ9ZTc-ALSMt9gDY,11421
|
|
@@ -52,21 +53,24 @@ illumio_pylo/cli/commands/workload_import.py,sha256=mpcHISn5qxM13eSYCWusQRvkkNuZ
|
|
|
52
53
|
illumio_pylo/cli/commands/workload_reset_names_to_null.py,sha256=j87jbnDxT3kABlqCHlqVd1_U1mfV7y0mgFwEEdFmt0Q,3331
|
|
53
54
|
illumio_pylo/cli/commands/workload_update.py,sha256=nPlSCOAx0wmshVWy4WNp-15wwg-IWcPPQy66AWEDTic,28659
|
|
54
55
|
illumio_pylo/cli/commands/workload_used_in_rule_finder.py,sha256=35t_HpAw_gk9SjmNoyPI3eyZT6doPhqcFF6XkuzbNII,3340
|
|
56
|
+
illumio_pylo/cli/commands/ui/credential_manager_ui/app.js,sha256=FROWIE-nIGv1X47hDgpL18t6lhgmc2kMNA8gIVbqdwQ,17221
|
|
57
|
+
illumio_pylo/cli/commands/ui/credential_manager_ui/index.html,sha256=MOfSDkGvq8zpGdWfU9d-aPfMfdYt3BfQ2yaQ-MF8q9Q,7501
|
|
58
|
+
illumio_pylo/cli/commands/ui/credential_manager_ui/styles.css,sha256=A8t4r1-rW5iEMyHT0ligUVWXwFgemR_5ONmsTPvBdB4,6765
|
|
55
59
|
illumio_pylo/cli/commands/utils/LabelCreation.py,sha256=cO_MWJrAIgeZGZrm0Dix50isrGzhckZ_kLnjy1VWWRI,4885
|
|
56
60
|
illumio_pylo/cli/commands/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
57
61
|
illumio_pylo/cli/commands/utils/misc.py,sha256=dsFHrmCaQ1OrRGms8dHaHtE_rTJ0j4-Q3JXcFCKNC_I,775
|
|
58
62
|
illumio_pylo/docs/Doxygen,sha256=AVvSIRYLHFWJ15YLGahhzhsW0ZUUFO5lVxd2-F3iWz8,74257
|
|
59
63
|
illumio_pylo/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
60
|
-
illumio_pylo/utilities/cli.py,sha256=
|
|
64
|
+
illumio_pylo/utilities/cli.py,sha256=AJl9NaMzAfKbEHwVy96bvXAZMV_jdcwvpUodWEEgoDQ,361
|
|
61
65
|
illumio_pylo/utilities/credentials.example.json,sha256=CZcp3aAbdVljfyQzFbgxIZCU9Ln2eWZKfWcmN9VAeVc,439
|
|
62
|
-
illumio_pylo/utilities/health_monitoring.py,sha256=
|
|
66
|
+
illumio_pylo/utilities/health_monitoring.py,sha256=_8IsDvOGxoqMvZhN8GQwHqrRb5qkh_x4ccENuECe19E,3831
|
|
63
67
|
illumio_pylo/utilities/resources/iplists-import-example.csv,sha256=beM9OBWJQNiYXlGh1KYiHxCN8LpZk4uPpoiO14-CgOE,200
|
|
64
68
|
illumio_pylo/utilities/resources/iplists-import-example.xlsx,sha256=VW-7CRr8NA2Vultv9jLGd8-_jzVp5ZtL3KgswjOUHeQ,16893
|
|
65
69
|
illumio_pylo/utilities/resources/workload-exporter-filter-example.csv,sha256=cn5IA8AGEPjvS-EsPXA_GJ-LFsdF9t_44rSzFTCmAzE,36
|
|
66
70
|
illumio_pylo/utilities/resources/workloads-import-example.csv,sha256=HBZj5e1TFnJTzNrcgO3ZVzqAwqBoyGABJtd9Y8W8j7g,115
|
|
67
71
|
illumio_pylo/utilities/resources/workloads-import-example.xlsx,sha256=B5LRCFjqkZ0xbGel7qlmLepmhAysoq1Cu9eVFUiZLq0,17191
|
|
68
|
-
illumio_pylo-0.3.
|
|
69
|
-
illumio_pylo-0.3.
|
|
70
|
-
illumio_pylo-0.3.
|
|
71
|
-
illumio_pylo-0.3.
|
|
72
|
-
illumio_pylo-0.3.
|
|
72
|
+
illumio_pylo-0.3.12.dist-info/licenses/LICENSE,sha256=WYmcYJG1QFgu1hfo7qrEkZ3Jhcz8NUWe6XUraZvlIFs,10172
|
|
73
|
+
illumio_pylo-0.3.12.dist-info/METADATA,sha256=QnZMdnCzrIt0_B_2qoO0w8uyqU2hvDWeOWrhGuece7M,12403
|
|
74
|
+
illumio_pylo-0.3.12.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
75
|
+
illumio_pylo-0.3.12.dist-info/top_level.txt,sha256=c5cu_ZMuSuxjq48ih58Kc0Tr8-JdQtV8GrKJicvWNFE,13
|
|
76
|
+
illumio_pylo-0.3.12.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|