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.
- illumio_pylo/API/APIConnector.py +1308 -0
- illumio_pylo/API/AuditLog.py +42 -0
- illumio_pylo/API/ClusterHealth.py +136 -0
- illumio_pylo/API/CredentialsManager.py +286 -0
- illumio_pylo/API/Explorer.py +1077 -0
- illumio_pylo/API/JsonPayloadTypes.py +240 -0
- illumio_pylo/API/RuleSearchQuery.py +128 -0
- illumio_pylo/API/__init__.py +0 -0
- illumio_pylo/AgentStore.py +139 -0
- illumio_pylo/Exception.py +44 -0
- illumio_pylo/Helpers/__init__.py +3 -0
- illumio_pylo/Helpers/exports.py +508 -0
- illumio_pylo/Helpers/functions.py +166 -0
- illumio_pylo/IPList.py +135 -0
- illumio_pylo/IPMap.py +285 -0
- illumio_pylo/Label.py +25 -0
- illumio_pylo/LabelCommon.py +48 -0
- illumio_pylo/LabelGroup.py +68 -0
- illumio_pylo/LabelStore.py +403 -0
- illumio_pylo/LabeledObject.py +25 -0
- illumio_pylo/Organization.py +258 -0
- illumio_pylo/Query.py +331 -0
- illumio_pylo/ReferenceTracker.py +41 -0
- illumio_pylo/Rule.py +671 -0
- illumio_pylo/Ruleset.py +306 -0
- illumio_pylo/RulesetStore.py +101 -0
- illumio_pylo/SecurityPrincipal.py +62 -0
- illumio_pylo/Service.py +256 -0
- illumio_pylo/SoftwareVersion.py +125 -0
- illumio_pylo/VirtualService.py +17 -0
- illumio_pylo/VirtualServiceStore.py +75 -0
- illumio_pylo/Workload.py +506 -0
- illumio_pylo/WorkloadStore.py +289 -0
- illumio_pylo/__init__.py +82 -0
- illumio_pylo/cli/NativeParsers.py +96 -0
- illumio_pylo/cli/__init__.py +134 -0
- illumio_pylo/cli/__main__.py +10 -0
- illumio_pylo/cli/commands/__init__.py +32 -0
- illumio_pylo/cli/commands/credential_manager.py +168 -0
- illumio_pylo/cli/commands/iplist_import_from_file.py +185 -0
- illumio_pylo/cli/commands/misc.py +7 -0
- illumio_pylo/cli/commands/ruleset_export.py +129 -0
- illumio_pylo/cli/commands/update_pce_objects_cache.py +44 -0
- illumio_pylo/cli/commands/ven_duplicate_remover.py +366 -0
- illumio_pylo/cli/commands/ven_idle_to_visibility.py +287 -0
- illumio_pylo/cli/commands/ven_upgrader.py +226 -0
- illumio_pylo/cli/commands/workload_export.py +251 -0
- illumio_pylo/cli/commands/workload_import.py +423 -0
- illumio_pylo/cli/commands/workload_relabeler.py +510 -0
- illumio_pylo/cli/commands/workload_reset_names_to_null.py +83 -0
- illumio_pylo/cli/commands/workload_used_in_rule_finder.py +80 -0
- illumio_pylo/docs/Doxygen +1757 -0
- illumio_pylo/tmp.py +104 -0
- illumio_pylo/utilities/__init__.py +0 -0
- illumio_pylo/utilities/cli.py +10 -0
- illumio_pylo/utilities/credentials.example.json +20 -0
- illumio_pylo/utilities/explorer_report_exporter.py +86 -0
- illumio_pylo/utilities/health_monitoring.py +102 -0
- illumio_pylo/utilities/iplist_analyzer.py +148 -0
- illumio_pylo/utilities/iplists_stats_duplicates_unused_finder.py +75 -0
- illumio_pylo/utilities/resources/iplists-import-example.csv +3 -0
- illumio_pylo/utilities/resources/iplists-import-example.xlsx +0 -0
- illumio_pylo/utilities/resources/workload-exporter-filter-example.csv +3 -0
- illumio_pylo/utilities/resources/workloads-import-example.csv +2 -0
- illumio_pylo/utilities/resources/workloads-import-example.xlsx +0 -0
- illumio_pylo/utilities/ven_compatibility_report_export.py +240 -0
- illumio_pylo/utilities/ven_idle_to_illumination.py +344 -0
- illumio_pylo/utilities/ven_reassign_pce.py +183 -0
- illumio_pylo-0.2.5.dist-info/LICENSE +176 -0
- illumio_pylo-0.2.5.dist-info/METADATA +197 -0
- illumio_pylo-0.2.5.dist-info/RECORD +73 -0
- illumio_pylo-0.2.5.dist-info/WHEEL +5 -0
- 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
|