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
illumio_pylo/Rule.py ADDED
@@ -0,0 +1,671 @@
1
+ import typing
2
+ from typing import Optional, List, Union, Dict, Any, NewType
3
+
4
+ import illumio_pylo as pylo
5
+ from .API.JsonPayloadTypes import RuleServiceReferenceObjectJsonStructure, RuleDirectServiceReferenceObjectJsonStructure
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
8
+
9
+ RuleActorsAcceptableTypes = NewType('RuleActorsAcceptableTypes', Union[Workload, Label, LabelGroup, IPList, VirtualService])
10
+
11
+
12
+ class RuleApiUpdateStack:
13
+ def __init__(self):
14
+ self.json_payload = {}
15
+
16
+ def add_payload(self, data: Dict[str, Any]):
17
+ for prop_name, prop_value in data.items():
18
+ self.json_payload[prop_name] = prop_value
19
+
20
+ def get_payload_and_reset(self) -> Dict[str, Any]:
21
+ data = self.json_payload
22
+ self.json_payload = {}
23
+ return data
24
+
25
+ def count_payloads(self) -> int:
26
+ return len(self.json_payload)
27
+
28
+
29
+ class Rule:
30
+
31
+ def __init__(self, owner: 'Ruleset'):
32
+ self.owner: Ruleset = owner
33
+ self.description: Optional[str] = None
34
+ self.services: RuleServiceContainer = RuleServiceContainer(self)
35
+ self.providers: RuleHostContainer = RuleHostContainer(self, 'providers')
36
+ self.consumers: RuleHostContainer = RuleHostContainer(self, 'consumers')
37
+ self.consuming_principals: RuleSecurityPrincipalContainer = RuleSecurityPrincipalContainer(self)
38
+ self.href: Optional[str] = None
39
+ self.enabled: bool = True
40
+ self.secure_connect: bool = False
41
+ self.unscoped_consumers: bool = False
42
+ self.stateless: bool = False
43
+ self.machine_auth: bool = False
44
+
45
+ self.raw_json: Optional[Dict[str, Any]] = None
46
+ self.batch_update_stack: Optional[RuleApiUpdateStack] = None
47
+
48
+ def load_from_json(self, data):
49
+ self.raw_json = data
50
+
51
+ self.href = data['href']
52
+
53
+ self.description = data.get('description')
54
+
55
+ services = data.get('ingress_services')
56
+ if services is not None:
57
+ self.services.load_from_json(services)
58
+
59
+ enabled = data.get('enabled')
60
+ if enabled is not None:
61
+ self.enabled = enabled
62
+
63
+ stateless = data.get('stateless')
64
+ if stateless is not None:
65
+ self.stateless = stateless
66
+
67
+ machine_auth = data.get('machine_auth')
68
+ if machine_auth is not None:
69
+ self.machine_auth = machine_auth
70
+
71
+ secure_connect = data.get('sec_connect')
72
+ if secure_connect is not None:
73
+ self.secure_connect = secure_connect
74
+
75
+ unscoped_consumers = data.get('unscoped_consumers')
76
+ if unscoped_consumers is not None:
77
+ self.unscoped_consumers = unscoped_consumers
78
+
79
+ self.providers.load_from_json(data['providers'])
80
+ self.consumers.load_from_json(data['consumers'])
81
+ self.consuming_principals.load_from_json(data['consuming_security_principals'])
82
+
83
+ def is_extra_scope(self):
84
+ return self.unscoped_consumers
85
+
86
+ def is_intra_scope(self):
87
+ return not self.unscoped_consumers
88
+
89
+ def api_set_description(self, new_description: str):
90
+ data = {'description': new_description}
91
+ if self.batch_update_stack is None:
92
+ self.owner.owner.owner.connector.objects_rule_update(self.href, update_data=data)
93
+
94
+ self.raw_json.update(data)
95
+ self.description = new_description
96
+
97
+ def api_stacked_updates_start(self):
98
+ """
99
+ Turns on 'updates stacking' mode for this Rule which will not push changes to API as you make them but only
100
+ when you trigger 'api_push_stacked_updates()' function
101
+ """
102
+ self.batch_update_stack = RuleApiUpdateStack()
103
+
104
+ def api_stacked_updates_push(self):
105
+ """
106
+ Push all stacked changed to API and turns off 'updates stacking' mode
107
+ """
108
+ if self.batch_update_stack is None:
109
+ raise pylo.PyloEx("Workload was not in 'update stacking' mode")
110
+
111
+ connector = pylo.find_connector_or_die(self.owner)
112
+ connector.objects_rule_update(self.href, self.batch_update_stack.get_payload_and_reset())
113
+ self.batch_update_stack = None
114
+
115
+ def api_stacked_updates_count(self) -> int:
116
+ """
117
+ Counts the number of stacked changed for this Ruke
118
+ :return:
119
+ """
120
+ if self.batch_update_stack is None:
121
+ raise pylo.PyloEx("Workload was not in 'update stacking' mode")
122
+ return self.batch_update_stack.count_payloads()
123
+
124
+
125
+ class RuleSecurityPrincipalContainer(pylo.Referencer):
126
+ def __init__(self, owner: 'pylo.Rule'):
127
+ Referencer.__init__(self)
128
+ self.owner = owner
129
+ self._items: Dict[SecurityPrincipal, SecurityPrincipal] = {} # type:
130
+
131
+ def load_from_json(self, data):
132
+ ss_store = self.owner.owner.owner.owner.SecurityPrincipalStore # make it a local variable for fast lookups
133
+ for item_data in data:
134
+ wanted_href = item_data['href']
135
+ found_object = ss_store.find_by_href(wanted_href)
136
+ if found_object is None:
137
+ raise pylo.PyloEx(f"Could not find SecurityPrincipal with href '{wanted_href}' inside rule href '{self.owner.href}' and Ruleset named '{self.owner.owner.name}'")
138
+ found_object.add_reference(self)
139
+ self._items[found_object] = found_object
140
+
141
+
142
+ class DirectServiceInRule:
143
+ def __init__(self, proto: int, port: int = None, toport: int = None):
144
+ self.protocol = proto
145
+ self.port = port
146
+ self.to_port = toport
147
+
148
+ def is_tcp(self):
149
+ return self.protocol == 6
150
+
151
+ def is_udp(self):
152
+ return self.protocol == 17
153
+
154
+ def is_icmp(self):
155
+ return self.protocol == 1
156
+
157
+ def to_string_standard(self, protocol_first=True):
158
+ if self.protocol == 17:
159
+ if self.to_port is None:
160
+ if protocol_first:
161
+ return 'udp/' + str(self.port)
162
+
163
+ return str(self.port) + '/udp'
164
+ if protocol_first:
165
+ return 'udp/' + str(self.port) + '-' + str(self.to_port)
166
+
167
+ return str(self.port) + '-' + str(self.to_port) + '/udp'
168
+ elif self.protocol == 6:
169
+ if self.to_port is None:
170
+ if protocol_first:
171
+ return 'tcp/' + str(self.port)
172
+ return str(self.port) + '/tcp'
173
+
174
+ if protocol_first:
175
+ return 'tcp/' + str(self.port) + '-' + str(self.to_port)
176
+ return str(self.port) + '-' + str(self.to_port) + '/tcp'
177
+
178
+ if protocol_first:
179
+ return 'proto/' + str(self.protocol)
180
+
181
+ return str(self.protocol) + '/proto'
182
+
183
+ def get_api_json(self) -> Dict:
184
+ """
185
+ Generates json payload to be included in a rule's service update or creation
186
+ """
187
+ if self.protocol != 17 and self.protocol != 6:
188
+ return {'proto': self.protocol}
189
+
190
+ if self.to_port is None:
191
+ return {'proto': self.protocol, 'port': self.port}
192
+ return {'proto': self.protocol, 'port': self.port, 'to_port': self.to_port}
193
+
194
+ @staticmethod
195
+ def create_from_text(txt: str, seperator='/', protocol_first=True) -> 'DirectServiceInRule':
196
+ parts = txt.split(seperator)
197
+
198
+ if len(parts) != 2:
199
+ lower = txt.lower()
200
+ if lower == 'icmp':
201
+ return DirectServiceInRule(proto=1)
202
+ raise PyloEx("Invalid service syntax '{}'".format(txt))
203
+
204
+ if protocol_first:
205
+ proto = parts[0]
206
+ port_input = parts[1]
207
+ else:
208
+ proto = parts[1]
209
+ port_input = parts[0]
210
+
211
+ if not proto.isdigit():
212
+ proto_lower = proto.lower()
213
+ if proto_lower == 'tcp':
214
+ protocol_int = 6
215
+ elif proto_lower == 'udp':
216
+ protocol_int = 17
217
+ elif proto_lower == 'proto':
218
+ return DirectServiceInRule(proto=int(port_input))
219
+ else:
220
+ raise PyloEx("Invalid protocol provided: {}".format(proto))
221
+ else:
222
+ protocol_int = int(proto)
223
+
224
+ port_parts = port_input.split('-')
225
+ if len(port_parts) > 2:
226
+ raise PyloEx("Invalid port provided: '{}' in string '{}'".format(port_input, txt))
227
+
228
+ if len(port_parts) == 2:
229
+ if protocol_int != 17 and protocol_int != 6:
230
+ raise PyloEx("Only TCP and UDP support port ranges so this service in invalid: '{}'".format(txt))
231
+ from_port_input = port_parts[0]
232
+ to_port_input = port_parts[1]
233
+
234
+ if not from_port_input.isdigit():
235
+ raise PyloEx("Invalid port provided: '{}' in string '{}'".format(from_port_input, txt))
236
+ if not to_port_input.isdigit():
237
+ raise PyloEx("Invalid port provided: '{}' in string '{}'".format(to_port_input, txt))
238
+
239
+ return DirectServiceInRule(protocol_int, port=int(from_port_input), toport=int(to_port_input))
240
+
241
+ if not port_input.isdigit():
242
+ raise PyloEx("Invalid port provided: '{}' in string '{}'".format(port_input, txt))
243
+
244
+ return DirectServiceInRule(protocol_int, port=int(port_input))
245
+
246
+
247
+ class RuleServiceContainer(pylo.Referencer):
248
+ def __init__(self, owner: 'pylo.Rule'):
249
+ Referencer.__init__(self)
250
+ self.owner = owner
251
+ self._items: Dict[Service, Service] = {}
252
+ self._direct_services: List[DirectServiceInRule] = []
253
+
254
+ def load_from_json(self, data_list: List[RuleServiceReferenceObjectJsonStructure|RuleDirectServiceReferenceObjectJsonStructure]):
255
+ ss_store = self.owner.owner.owner.owner.ServiceStore # make it a local variable for fast lookups
256
+
257
+ for data in data_list:
258
+ # print(data)
259
+ href = data.get('href')
260
+ if href is None:
261
+ data = typing.cast(RuleDirectServiceReferenceObjectJsonStructure, data)
262
+ port = data.get('port')
263
+ if port is None:
264
+ raise PyloEx("unsupported service type in rule: {}".format(nice_json(data)))
265
+ protocol = data.get('proto')
266
+ if protocol is None:
267
+ raise PyloEx("Protocol not found in direct service use: {}".format(nice_json(data)))
268
+
269
+ to_port = data.get('to_port')
270
+ direct_port = DirectServiceInRule(protocol, port, to_port)
271
+ self._direct_services.append(direct_port)
272
+
273
+ continue
274
+
275
+ data = typing.cast(RuleServiceReferenceObjectJsonStructure, data)
276
+ find_service = ss_store.itemsByHRef.get(href)
277
+ if find_service is None:
278
+ raise Exception('Cannot find Service with HREF %s in Rule %s'.format(href, self.owner.href))
279
+
280
+ self._items[find_service] = find_service
281
+ find_service.add_reference(self)
282
+
283
+ def get_direct_services(self) -> List[DirectServiceInRule]:
284
+ """
285
+ Return a list of services directly included in the Rule
286
+ """
287
+ return self._direct_services.copy()
288
+
289
+ def get_services(self) -> List[pylo.Service]:
290
+ return list(self._items.values())
291
+
292
+ def remove_direct_service(self, service: DirectServiceInRule) -> bool:
293
+ """
294
+ Removes a direct service from the rule
295
+ :param service:
296
+ :return: True if the service was removed, False if it was not found
297
+ """
298
+ for i in range(0, len(self._direct_services)):
299
+ if self._direct_services[i] is service:
300
+ del(self._direct_services[i])
301
+ return True
302
+ return False
303
+
304
+ def add_direct_service(self, service: DirectServiceInRule) -> bool:
305
+ for member in self._direct_services:
306
+ if service is member:
307
+ return False
308
+ self._direct_services.append(service)
309
+ return True
310
+
311
+ def members_to_str(self, separator: str = ',') -> str:
312
+ text: str = ''
313
+
314
+ for service in self._items.values():
315
+ if len(text) > 0:
316
+ text += separator
317
+ text += service.name + ': ' + string_list_to_text(service.get_entries_str_list())
318
+
319
+ for direct in self._direct_services:
320
+ if len(text) > 0:
321
+ text += separator
322
+ text += direct.to_string_standard()
323
+
324
+ return text
325
+
326
+ def get_api_json_payload(self) -> List[Dict[str, Any]]:
327
+ """
328
+ Generate JSON payload for API update call
329
+ :return:
330
+ """
331
+ data = []
332
+ for service in self._direct_services:
333
+ data.append(service.get_api_json())
334
+
335
+ for service in self._items.values():
336
+ data.append({'href': service.href})
337
+
338
+ return data
339
+
340
+ def api_sync(self):
341
+ """
342
+ Synchronize a Rule's services after some changes were made
343
+ """
344
+ connector = find_connector_or_die(self)
345
+ data = self.get_api_json_payload()
346
+ data = {'ingress_services': data}
347
+
348
+ if self.owner.batch_update_stack is None:
349
+ connector.objects_rule_update(self.owner.href, update_data=data)
350
+ else:
351
+ self.owner.batch_update_stack.add_payload(data)
352
+
353
+ self.owner.raw_json.update(data)
354
+
355
+
356
+ class RuleHostContainer(pylo.Referencer):
357
+ def __init__(self, owner: 'pylo.Rule', name: str):
358
+ Referencer.__init__(self)
359
+ self.owner = owner
360
+ self._items: Dict[RuleActorsAcceptableTypes, RuleActorsAcceptableTypes] = {}
361
+ self.name = name
362
+ self._hasAllWorkloads = False
363
+
364
+ def load_from_json(self, data):
365
+ """
366
+ Parse from a JSON payload.
367
+ *For developers only*
368
+
369
+ :param data: JSON payload to parse
370
+ """
371
+ workload_store = self.owner.owner.owner.owner.WorkloadStore # make it a local variable for fast lookups
372
+ label_store = self.owner.owner.owner.owner.LabelStore # make it a local variable for fast lookups
373
+ virtual_service_store = self.owner.owner.owner.owner.VirtualServiceStore # make it a local variable for fast lookups
374
+ iplist_store = self.owner.owner.owner.owner.IPListStore # make it a local variable for fast lookups
375
+
376
+ for host_data in data:
377
+ find_object = None
378
+ if 'label' in host_data:
379
+ href = host_data['label'].get('href')
380
+ if href is None:
381
+ PyloEx('Cannot find object HREF ', host_data)
382
+ find_object = label_store.find_by_href(href)
383
+ if find_object is None:
384
+ raise Exception('Cannot find Label with HREF {} in Rule {}'.format(href, self.owner.href))
385
+ elif 'label_group' in host_data:
386
+ href = host_data['label_group'].get('href')
387
+ if href is None:
388
+ raise PyloEx('Cannot find object HREF ', host_data)
389
+ find_object = label_store.find_by_href(href)
390
+ if find_object is None:
391
+ raise Exception('Cannot find LabelGroup with HREF {} in Rule {}'.format(href, self.owner.href))
392
+ elif 'ip_list' in host_data:
393
+ href = host_data['ip_list'].get('href')
394
+ if href is None:
395
+ raise PyloEx('Cannot find object HREF ', host_data)
396
+ find_object = iplist_store.items_by_href.get(href)
397
+ if find_object is None:
398
+ raise Exception('Cannot find IPList with HREF {} in Rule {}'.format(href, self.owner.href))
399
+ elif 'workload' in host_data:
400
+ href = host_data['workload'].get('href')
401
+ if href is None:
402
+ raise PyloEx('Cannot find object HREF ', host_data)
403
+ # @TODO : better handling of temporary objects
404
+ find_object = workload_store.itemsByHRef.get(href)
405
+ if find_object is None:
406
+ # raise Exception("Cannot find Workload with HREF {} in Rule {}. JSON:\n {}".format(href, self.owner.href, nice_json(host_data)))
407
+ find_object = workload_store.find_by_href_or_create_tmp(href, 'tmp-deleted-wkl-'+href)
408
+ elif 'virtual_service' in host_data:
409
+ href = host_data['virtual_service'].get('href')
410
+ if href is None:
411
+ raise PyloEx('Cannot find object HREF ', host_data)
412
+ # @TODO : better handling of temporary objects
413
+ find_object = virtual_service_store.items_by_href.get(href)
414
+ if find_object is None:
415
+ # raise Exception("Cannot find VirtualService with HREF {} in Rule {}. JSON:\n {}".format(href, self.owner.href, nice_json(host_data)))
416
+ find_object = self.owner.owner.owner.owner.VirtualServiceStore.find_by_href_or_create_tmp(href, 'tmp-deleted-wkl-'+href)
417
+ elif 'virtual_server' in host_data:
418
+ pylo.log.warn('VirtualServer found in Rule {}. This is not supported yet by this library, beware of unexpected behaviors'.format(self.owner.href))
419
+ elif 'actors' in host_data:
420
+ actor_value = host_data['actors']
421
+ if actor_value is not None and actor_value == 'ams':
422
+ self._hasAllWorkloads = True
423
+ continue
424
+ # TODO implement actors
425
+ raise PyloEx("An actor that is not 'ams' was detected but this library doesn't support it yet", host_data)
426
+ else:
427
+ raise PyloEx("Unsupported reference type", host_data)
428
+
429
+ if find_object is not None:
430
+ self._items[find_object] = find_object
431
+ find_object.add_reference(self)
432
+
433
+ def has_workloads(self) -> bool:
434
+ """
435
+ Check if this container references at least one Workload
436
+ :return: True if contains at least one Workload
437
+ """
438
+ for item in self._items.values():
439
+ if isinstance(item, Workload):
440
+ return True
441
+ return False
442
+
443
+ def has_virtual_services(self) -> bool:
444
+ """
445
+ Check if this container references at least one Virtual Service
446
+ :return: True if contains at least one Virtual Service
447
+ """
448
+ for item in self._items.values():
449
+ if isinstance(item, VirtualService):
450
+ return True
451
+ return False
452
+
453
+ def has_labels(self) -> bool:
454
+ """
455
+ Check if this container references at least one Label or LabelGroup
456
+ :return: True if contains at least one Label or LabelGroup
457
+ """
458
+ for item in self._items.values():
459
+ if isinstance(item, Label) or isinstance(item, LabelGroup):
460
+ return True
461
+ return False
462
+
463
+ def get_labels(self) -> List[Union[pylo.Label, pylo.LabelGroup]]:
464
+ """
465
+ Get a list Labels and LabelGroups which are part of this container
466
+ :return:
467
+ """
468
+ result = []
469
+
470
+ for item in self._items.values():
471
+ if isinstance(item, Label) or isinstance(item, LabelGroup):
472
+ result.append(item)
473
+
474
+ return result
475
+
476
+ def get_role_labels(self) -> List[Union[pylo.Label, pylo.LabelGroup]]:
477
+ """
478
+ Get a list Role Labels and LabelGroups which are part of this container
479
+ :return:
480
+ """
481
+ result = []
482
+
483
+ for item in self._items.values():
484
+ if (isinstance(item, Label) or isinstance(item, LabelGroup)) and item.type_is_role():
485
+ result.append(item)
486
+
487
+ return result
488
+
489
+ def get_app_labels(self) -> List[Union[pylo.Label, pylo.LabelGroup]]:
490
+ """
491
+ Get a list App Labels and LabelGroups which are part of this container
492
+ :return:
493
+ """
494
+ result = []
495
+
496
+ for item in self._items.values():
497
+ if (isinstance(item, Label) or isinstance(item, LabelGroup)) and item.type_is_application():
498
+ result.append(item)
499
+
500
+ return result
501
+
502
+ def get_env_labels(self) -> List[Union[pylo.Label, pylo.LabelGroup]]:
503
+ """
504
+ Get a list Env Labels and LabelGroups which are part of this container
505
+ :return:
506
+ """
507
+ result = []
508
+
509
+ for item in self._items.values():
510
+ if (isinstance(item, Label) or isinstance(item, LabelGroup)) and item.type_is_environment():
511
+ result.append(item)
512
+
513
+ return result
514
+
515
+ def get_loc_labels(self) -> List[Union[pylo.Label, pylo.LabelGroup]]:
516
+ """
517
+ Get a list Loc Labels and LabelGroups which are part of this container
518
+ :return:
519
+ """
520
+ result = []
521
+
522
+ for item in self._items.values():
523
+ if (isinstance(item, Label) or isinstance(item, LabelGroup)) and item.type_is_location():
524
+ result.append(item)
525
+
526
+ return result
527
+
528
+ def members_to_str(self, separator=',', sort_alphabetically=True, sort_labels_by_type=True,
529
+ prefix_objects_with_type=False, object_types_as_section=False) -> str:
530
+ """
531
+ Conveniently creates a string with all members of this container, ordered by Label, IPList, Workload,
532
+ and Virtual Service
533
+
534
+ :param separator: string use to separate each member in the lit
535
+ :param sort_alphabetically: if True, the members will be sorted alphabetically
536
+ :param sort_labels_by_type: if True, the labels will be sorted by type (role, app, env, loc ...)
537
+ :param prefix_objects_with_type: if True, the objects will be prefixed with their type (Label, IPList, Workload, Virtual Service)
538
+ :param object_types_as_section: if True, the objects will be grouped by type and each group will be separated with a header
539
+ :return:
540
+ """
541
+ text = ''
542
+
543
+ if self._hasAllWorkloads:
544
+ text += "*All Workloads*"
545
+
546
+ labels = self.get_labels()
547
+ if len(labels) > 0:
548
+ if len(text) > 0:
549
+ text += separator
550
+ text += 'LABELS:'
551
+ if sort_alphabetically:
552
+ labels = sorted(labels, key=lambda x: x.name.lower())
553
+ if sort_labels_by_type:
554
+ labels = pylo.LabelStore.Utils.list_sort_by_type(labels, self.owner.owner.owner.owner.LabelStore.label_types)
555
+
556
+ for label in labels:
557
+ if prefix_objects_with_type:
558
+ if label.is_group():
559
+ prefix = 'lbg:'
560
+ else:
561
+ prefix = 'lbl:'
562
+ else:
563
+ prefix = ''
564
+ if len(text) > 0:
565
+ text += separator
566
+ text += prefix + label.name
567
+
568
+ iplists = self.get_iplists()
569
+ if len(iplists) > 0:
570
+ if len(text) > 0:
571
+ text += separator
572
+ text += 'IPLISTS:'
573
+ if sort_alphabetically:
574
+ iplists = sorted(iplists, key=lambda x: x.name.lower())
575
+ if prefix_objects_with_type:
576
+ prefix = 'ipl:'
577
+ else:
578
+ prefix = ''
579
+ for item in iplists:
580
+ if len(text) > 0:
581
+ text += separator
582
+ text += prefix + item.name
583
+
584
+ workloads = self.get_workloads()
585
+ if len(workloads) > 0:
586
+ if len(text) > 0:
587
+ text += separator
588
+ text += 'WORKLOADS:'
589
+ if sort_alphabetically:
590
+ workloads = sorted(workloads, key=lambda x: x.name.lower())
591
+ if prefix_objects_with_type:
592
+ prefix = 'wkl:'
593
+ else:
594
+ prefix = ''
595
+ for item in workloads:
596
+ if len(text) > 0:
597
+ text += separator
598
+ text += prefix + item.get_name()
599
+
600
+ virtual_services = self.get_virtual_services()
601
+ if len(virtual_services) > 0:
602
+ if len(text) > 0:
603
+ text += separator
604
+ text += 'VIRTUAL SERVICES:'
605
+ if sort_alphabetically:
606
+ virtual_services = sorted(virtual_services, key=lambda x: x.name.lower())
607
+ if prefix_objects_with_type:
608
+ prefix = 'vs:'
609
+ else:
610
+ prefix = ''
611
+ for item in virtual_services:
612
+ if len(text) > 0:
613
+ text += separator
614
+ text += prefix + item.name
615
+
616
+ return text
617
+
618
+ def contains_iplists(self) -> bool:
619
+ """
620
+ Returns True if at least 1 iplist is part of this container
621
+ """
622
+ for item in self._items.values():
623
+ if isinstance(item, IPList):
624
+ return True
625
+ return False
626
+
627
+ def get_iplists(self) -> List[IPList]:
628
+ """
629
+ Get a list of IPLists which are part of this container
630
+ :return:
631
+ """
632
+ result = []
633
+
634
+ for item in self._items.values():
635
+ if isinstance(item, IPList):
636
+ result.append(item)
637
+
638
+ return result
639
+
640
+ def get_workloads(self) -> List[Workload]:
641
+ """
642
+ Get a list of Workloads which are part of this container
643
+ :return:
644
+ """
645
+ result = []
646
+
647
+ for item in self._items.values():
648
+ if isinstance(item, Workload):
649
+ result.append(item)
650
+
651
+ return result
652
+
653
+ def get_virtual_services(self) -> List[pylo.VirtualService]:
654
+ """
655
+ Get a list of VirtualServices which are part of this container
656
+ :return:
657
+ """
658
+ result = []
659
+
660
+ for item in self._items.values():
661
+ if isinstance(item, VirtualService):
662
+ result.append(item)
663
+
664
+ return result
665
+
666
+ def contains_all_workloads(self) -> bool:
667
+ """
668
+ Check if this container references "All Workloads"
669
+ :return: True if "All Workloads" is referenced by this container
670
+ """
671
+ return self._hasAllWorkloads