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
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"""This module contains the JSON payload types for the PCE API."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Optional, TypedDict, NotRequired, Union, Literal
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class HrefReference(TypedDict):
|
|
7
|
+
href: str
|
|
8
|
+
|
|
9
|
+
class HrefReferenceWithName(TypedDict):
|
|
10
|
+
href: str
|
|
11
|
+
name: str
|
|
12
|
+
|
|
13
|
+
class LabelHrefRef(TypedDict):
|
|
14
|
+
label: HrefReference
|
|
15
|
+
|
|
16
|
+
class WorkloadHrefRef(TypedDict):
|
|
17
|
+
workload: HrefReference
|
|
18
|
+
|
|
19
|
+
class IPListHrefRef(TypedDict):
|
|
20
|
+
ip_list: HrefReference
|
|
21
|
+
|
|
22
|
+
class ServiceHrefRef(TypedDict):
|
|
23
|
+
service: HrefReference
|
|
24
|
+
|
|
25
|
+
class VirtualServiceHrefRef(TypedDict):
|
|
26
|
+
virtual_service: HrefReference
|
|
27
|
+
|
|
28
|
+
class LabelObjectJsonStructure(TypedDict):
|
|
29
|
+
created_at: str
|
|
30
|
+
created_by: Optional[HrefReferenceWithName]
|
|
31
|
+
deleted: bool
|
|
32
|
+
href: str
|
|
33
|
+
key: str
|
|
34
|
+
updated_at: str
|
|
35
|
+
updated_by: Optional[HrefReferenceWithName]
|
|
36
|
+
value: str
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class LabelObjectCreationJsonStructure(TypedDict):
|
|
40
|
+
value: str
|
|
41
|
+
key: str
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class LabelObjectUpdateJsonStructure(TypedDict):
|
|
45
|
+
value: str
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class LabelGroupObjectJsonStructure(TypedDict):
|
|
49
|
+
created_at: str
|
|
50
|
+
created_by: Optional[HrefReferenceWithName]
|
|
51
|
+
deleted: bool
|
|
52
|
+
href: str
|
|
53
|
+
key: str
|
|
54
|
+
labels: List[HrefReference]
|
|
55
|
+
name: str
|
|
56
|
+
updated_at: str
|
|
57
|
+
updated_by: Optional[HrefReferenceWithName]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class LabelGroupObjectUpdateJsonStructure(TypedDict):
|
|
61
|
+
labels: NotRequired[List[HrefReference]]
|
|
62
|
+
name: NotRequired[str]
|
|
63
|
+
|
|
64
|
+
class IPListObjectJsonStructure(TypedDict):
|
|
65
|
+
created_at: str
|
|
66
|
+
created_by: Optional[HrefReferenceWithName]
|
|
67
|
+
description: str
|
|
68
|
+
href: str
|
|
69
|
+
ip_ranges: List[TypedDict('record', {'from_ip': str, 'to_ip': str, 'exclusion': bool})]
|
|
70
|
+
name: str
|
|
71
|
+
updated_at: str
|
|
72
|
+
updated_by: Optional[HrefReferenceWithName]
|
|
73
|
+
|
|
74
|
+
class IPListObjectCreationJsonStructure(TypedDict):
|
|
75
|
+
description: str
|
|
76
|
+
ip_ranges: List[TypedDict('record', {'from_ip': str, 'to_ip': str, 'exclusion': bool})]
|
|
77
|
+
name: str
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class WorkloadInterfaceObjectJsonStructure(TypedDict):
|
|
81
|
+
name: str
|
|
82
|
+
address: str
|
|
83
|
+
|
|
84
|
+
class WorkloadObjectJsonStructure(TypedDict):
|
|
85
|
+
created_at: str
|
|
86
|
+
created_by: Optional[HrefReferenceWithName]
|
|
87
|
+
description: Optional[str]
|
|
88
|
+
hostname: Optional[str]
|
|
89
|
+
href: str
|
|
90
|
+
interfaces: List[WorkloadInterfaceObjectJsonStructure]
|
|
91
|
+
labels: List[HrefReference]
|
|
92
|
+
name: Optional[str]
|
|
93
|
+
public_ip: Optional[str]
|
|
94
|
+
managed: bool
|
|
95
|
+
updated_at: str
|
|
96
|
+
updated_by: Optional[HrefReferenceWithName]
|
|
97
|
+
|
|
98
|
+
class WorkloadObjectCreateJsonStructure(TypedDict):
|
|
99
|
+
description: Optional[str]
|
|
100
|
+
hostname: Optional[str]
|
|
101
|
+
interfaces: NotRequired[List[WorkloadInterfaceObjectJsonStructure]]
|
|
102
|
+
labels: NotRequired[List[HrefReference]]
|
|
103
|
+
name: Optional[str]
|
|
104
|
+
public_ip: NotRequired[Optional[str]]
|
|
105
|
+
|
|
106
|
+
class RuleServiceReferenceObjectJsonStructure(TypedDict):
|
|
107
|
+
href: str
|
|
108
|
+
name: str
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class RuleDirectServiceReferenceObjectJsonStructure(TypedDict):
|
|
112
|
+
port: int
|
|
113
|
+
proto: int
|
|
114
|
+
to_port: NotRequired[int]
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class RuleObjectJsonStructure(TypedDict):
|
|
118
|
+
created_at: str
|
|
119
|
+
created_by: Optional[HrefReferenceWithName]
|
|
120
|
+
href: str
|
|
121
|
+
ingress_services: List[RuleDirectServiceReferenceObjectJsonStructure|RuleServiceReferenceObjectJsonStructure]
|
|
122
|
+
updated_at: str
|
|
123
|
+
updated_by: Optional[HrefReferenceWithName]
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class RulesetScopeEntryLineJsonStructure(TypedDict):
|
|
127
|
+
label: NotRequired[HrefReference]
|
|
128
|
+
label_group: NotRequired[HrefReference]
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class RulesetObjectJsonStructure(TypedDict):
|
|
132
|
+
created_at: str
|
|
133
|
+
created_by: Optional[HrefReferenceWithName]
|
|
134
|
+
description: str
|
|
135
|
+
href: str
|
|
136
|
+
name: str
|
|
137
|
+
rules: List[RuleObjectJsonStructure]
|
|
138
|
+
scopes: List[List[RulesetScopeEntryLineJsonStructure]]
|
|
139
|
+
updated_at: str
|
|
140
|
+
updated_by: Optional[HrefReferenceWithName]
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class RulesetObjectUpdateStructure(TypedDict):
|
|
144
|
+
name: NotRequired[str]
|
|
145
|
+
description: NotRequired[str]
|
|
146
|
+
scopes: NotRequired[List[List[RulesetScopeEntryLineJsonStructure]]]
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class ServiceObjectJsonStructure(TypedDict):
|
|
150
|
+
created_at: str
|
|
151
|
+
href: str
|
|
152
|
+
name: str
|
|
153
|
+
updated_at: str
|
|
154
|
+
updated_by: Optional[HrefReferenceWithName]
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class VirtualServiceObjectJsonStructure(TypedDict):
|
|
158
|
+
created_at: str
|
|
159
|
+
created_by: Optional[HrefReferenceWithName]
|
|
160
|
+
href: str
|
|
161
|
+
name: str
|
|
162
|
+
updated_at: str
|
|
163
|
+
updated_by: Optional[HrefReferenceWithName]
|
|
164
|
+
|
|
165
|
+
class NetworkDeviceConfigObjectJsonStructure(TypedDict):
|
|
166
|
+
device_type: Literal['switch']
|
|
167
|
+
name: str
|
|
168
|
+
|
|
169
|
+
class NetworkDeviceObjectJsonStructure(TypedDict):
|
|
170
|
+
href: str
|
|
171
|
+
config: NetworkDeviceConfigObjectJsonStructure
|
|
172
|
+
supported_endpoint_type: Literal['switch_port']
|
|
173
|
+
|
|
174
|
+
class NetworkDeviceEndpointConfigObjectJsonStructure(TypedDict):
|
|
175
|
+
type: Literal['switch_port']
|
|
176
|
+
name: str
|
|
177
|
+
workload_discovery: bool
|
|
178
|
+
|
|
179
|
+
class NetworkDeviceEndpointObjectJsonStructure(TypedDict):
|
|
180
|
+
href: str
|
|
181
|
+
config: NetworkDeviceEndpointConfigObjectJsonStructure
|
|
182
|
+
status: Literal['unmonitored', 'monitored']
|
|
183
|
+
workloads: List[HrefReference]
|
|
184
|
+
|
|
185
|
+
class SecurityPrincipalObjectJsonStructure(TypedDict):
|
|
186
|
+
created_at: str
|
|
187
|
+
created_by: Optional[HrefReferenceWithName]
|
|
188
|
+
href: str
|
|
189
|
+
name: str
|
|
190
|
+
updated_at: str
|
|
191
|
+
updated_by: Optional[HrefReferenceWithName]
|
|
192
|
+
|
|
193
|
+
class LabelDimensionObjectStructure(TypedDict):
|
|
194
|
+
created_at: str
|
|
195
|
+
created_by: Optional[HrefReferenceWithName]
|
|
196
|
+
display_name: str
|
|
197
|
+
href: str
|
|
198
|
+
key: str
|
|
199
|
+
updated_at: str
|
|
200
|
+
updated_by: Optional[HrefReferenceWithName]
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class PCEObjectsJsonStructure(TypedDict):
|
|
204
|
+
iplists: List[IPListObjectJsonStructure]
|
|
205
|
+
labelgroups: List[LabelGroupObjectJsonStructure]
|
|
206
|
+
labels: List[LabelObjectJsonStructure]
|
|
207
|
+
rulesets: List[RulesetObjectJsonStructure]
|
|
208
|
+
security_principals: List[SecurityPrincipalObjectJsonStructure]
|
|
209
|
+
services: List[ServiceObjectJsonStructure]
|
|
210
|
+
virtual_services: List[VirtualServiceObjectJsonStructure]
|
|
211
|
+
workloads: List[WorkloadObjectJsonStructure]
|
|
212
|
+
label_dimensions: List[LabelDimensionObjectStructure]
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class PCECacheFileJsonStructure(TypedDict):
|
|
216
|
+
data: PCEObjectsJsonStructure
|
|
217
|
+
pce_version: str
|
|
218
|
+
generation_date: str
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
class RuleCoverageQueryEntryJsonStructure(TypedDict):
|
|
222
|
+
source: Union[IPListHrefRef, WorkloadHrefRef]
|
|
223
|
+
destination: Union[IPListHrefRef, WorkloadHrefRef]
|
|
224
|
+
services: List
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
WorkloadsGetQueryLabelFilterJsonStructure = List[List[str]]
|
|
228
|
+
|
|
229
|
+
AuditLogApiEventType = Literal['agent.clone_detected', 'workloads.update', 'workload.update', 'workload_interfaces.update']
|
|
230
|
+
|
|
231
|
+
class AuditLogEntryJsonStructure(TypedDict):
|
|
232
|
+
event_type: AuditLogApiEventType
|
|
233
|
+
timestamp: str
|
|
234
|
+
|
|
235
|
+
class AuditLogApiRequestPayloadStructure(TypedDict):
|
|
236
|
+
pass
|
|
237
|
+
|
|
238
|
+
class AuditLogApiReplyEventJsonStructure(TypedDict):
|
|
239
|
+
pass
|
|
240
|
+
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
from typing import List, Union, Dict, Optional
|
|
2
|
+
import illumio_pylo as pylo
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class RuleSearchQueryResolvedResultSet:
|
|
6
|
+
rules: Dict[str, 'pylo.Rule']
|
|
7
|
+
rules_per_ruleset: Dict['pylo.Ruleset', Dict[str, 'pylo.Rule']]
|
|
8
|
+
|
|
9
|
+
def count_results(self):
|
|
10
|
+
return len(self.rules)
|
|
11
|
+
|
|
12
|
+
def __init__(self, raw_json_data, organization: 'pylo.Organization'):
|
|
13
|
+
self._raw_json = raw_json_data
|
|
14
|
+
self.rules = {}
|
|
15
|
+
self.rules_per_ruleset = {}
|
|
16
|
+
|
|
17
|
+
for rule_data in raw_json_data:
|
|
18
|
+
rule_href = rule_data.get('href')
|
|
19
|
+
if rule_href is None:
|
|
20
|
+
raise pylo.PyloEx('Cannot find rule HREF in RuleSearchQuery response', rule_data)
|
|
21
|
+
rule_found = organization.RulesetStore.find_rule_by_href(rule_href)
|
|
22
|
+
if rule_found is None:
|
|
23
|
+
raise pylo.PyloEx("Cannot find rule with HREF '{}' in Organization".format(rule_href), rule_data)
|
|
24
|
+
|
|
25
|
+
self.rules[rule_found.href] = rule_found
|
|
26
|
+
ruleset_found = self.rules_per_ruleset.get(rule_found.owner)
|
|
27
|
+
if ruleset_found is None:
|
|
28
|
+
# print("new ruleset")
|
|
29
|
+
self.rules_per_ruleset[rule_found.owner] = {rule_found.href: rule_found}
|
|
30
|
+
else:
|
|
31
|
+
# print("existing rs")
|
|
32
|
+
self.rules_per_ruleset[rule_found.owner][rule_found.href] = rule_found
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class RuleSearchQuery:
|
|
36
|
+
_advanced_mode_consumer_labels: Dict[str, Union['pylo.Label', 'pylo.LabelGroup']] = {}
|
|
37
|
+
_advanced_mode_provider_labels: Dict[str, Union['pylo.Label', 'pylo.LabelGroup']] = {}
|
|
38
|
+
_basic_mode_labels: Dict[str, 'pylo.Label']
|
|
39
|
+
connector: 'pylo.APIConnector'
|
|
40
|
+
max_results: int = 10000
|
|
41
|
+
|
|
42
|
+
def __init__(self, connector: 'pylo.APIConnector'):
|
|
43
|
+
self.connector = connector
|
|
44
|
+
self.mode_is_basic = True
|
|
45
|
+
self._basic_mode_labels = {}
|
|
46
|
+
self._advanced_mode_provider_labels = {}
|
|
47
|
+
self._advanced_mode_consumer_labels = {}
|
|
48
|
+
self._exact_matches = True
|
|
49
|
+
self._mode_is_draft = True
|
|
50
|
+
|
|
51
|
+
def set_basic_mode(self):
|
|
52
|
+
self.mode_is_basic = True
|
|
53
|
+
self._advanced_mode_provider_labels = {}
|
|
54
|
+
self._advanced_mode_consumer_labels = {}
|
|
55
|
+
|
|
56
|
+
def set_advanced_mode(self):
|
|
57
|
+
self.mode_is_basic = False
|
|
58
|
+
self._basic_mode_labels = {}
|
|
59
|
+
|
|
60
|
+
def set_draft_mode(self):
|
|
61
|
+
self._mode_is_draft = True
|
|
62
|
+
|
|
63
|
+
def set_active_mode(self):
|
|
64
|
+
self._mode_is_draft = False
|
|
65
|
+
|
|
66
|
+
def set_max_results(self, max_results: int):
|
|
67
|
+
if max_results < 1:
|
|
68
|
+
raise pylo.PyloEx("max_results must be greater than 0")
|
|
69
|
+
self.max_results = max_results
|
|
70
|
+
|
|
71
|
+
def add_label(self, label: 'pylo.Label'):
|
|
72
|
+
if not self.mode_is_basic:
|
|
73
|
+
raise pylo.PyloEx('You can add labels to RuleSearchQuery only in Basic mode. Use consumer/provider counterparts with Advanced mode')
|
|
74
|
+
self._basic_mode_labels[label.href] = label
|
|
75
|
+
|
|
76
|
+
def add_consumer_label(self, label: 'pylo.Label'):
|
|
77
|
+
if self.mode_is_basic:
|
|
78
|
+
raise pylo.PyloEx('You can add labels to RuleSearchQuery consumers only in Advanced mode')
|
|
79
|
+
self._advanced_mode_consumer_labels[label.href] = label
|
|
80
|
+
|
|
81
|
+
def add_provider_label(self, label: 'pylo.Label'):
|
|
82
|
+
if self.mode_is_basic:
|
|
83
|
+
raise pylo.PyloEx('You can add labels to RuleSearchQuery providers only in Advanced mode')
|
|
84
|
+
self._advanced_mode_provider_labels[label.href] = label
|
|
85
|
+
|
|
86
|
+
def use_exact_matches(self):
|
|
87
|
+
self._exact_matches = True
|
|
88
|
+
|
|
89
|
+
def use_resolved_matches(self):
|
|
90
|
+
self._exact_matches = False
|
|
91
|
+
|
|
92
|
+
def execute(self):
|
|
93
|
+
data = {'max_results': self.max_results}
|
|
94
|
+
if not self._exact_matches:
|
|
95
|
+
data['resolve_actors'] = True
|
|
96
|
+
|
|
97
|
+
uri = '/sec_policy/draft/rule_search'
|
|
98
|
+
if not self._mode_is_draft:
|
|
99
|
+
uri = '/sec_policy/active/rule_search'
|
|
100
|
+
|
|
101
|
+
if self.mode_is_basic:
|
|
102
|
+
if len(self._basic_mode_labels) > 0:
|
|
103
|
+
data['providers_or_consumers'] = []
|
|
104
|
+
for label_href, label in self._basic_mode_labels.items():
|
|
105
|
+
if label.is_label():
|
|
106
|
+
data['providers_or_consumers'].append({'label': {'href': label_href}})
|
|
107
|
+
else:
|
|
108
|
+
data['providers_or_consumers'].append({'label_group': {'href': label_href}})
|
|
109
|
+
else:
|
|
110
|
+
if len(self._advanced_mode_provider_labels) > 0:
|
|
111
|
+
data['providers'] = []
|
|
112
|
+
for label_href, label in self._advanced_mode_provider_labels.items():
|
|
113
|
+
if label.is_label():
|
|
114
|
+
data['providers'].append({'label': {'href': label_href}})
|
|
115
|
+
else:
|
|
116
|
+
data['providers'].append({'label_group': {'href': label_href}})
|
|
117
|
+
if len(self._advanced_mode_consumer_labels) > 0:
|
|
118
|
+
data['consumers'] = []
|
|
119
|
+
for label_href, label in self._advanced_mode_consumer_labels.items():
|
|
120
|
+
if label.is_label():
|
|
121
|
+
data['consumers'].append({'label': {'href': label_href}})
|
|
122
|
+
else:
|
|
123
|
+
data['consumers'].append({'label_group': {'href': label_href}})
|
|
124
|
+
|
|
125
|
+
return self.connector.do_post_call(uri, data)
|
|
126
|
+
|
|
127
|
+
def execute_and_resolve(self, organization: 'pylo.Organization'):
|
|
128
|
+
return RuleSearchQueryResolvedResultSet(self.execute(), organization)
|
|
File without changes
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
import illumio_pylo as pylo
|
|
4
|
+
from illumio_pylo import log, SoftwareVersion
|
|
5
|
+
from .Helpers import *
|
|
6
|
+
import re
|
|
7
|
+
import datetime
|
|
8
|
+
from typing import *
|
|
9
|
+
|
|
10
|
+
# version_regex = re.compile(r"^(?P<major>[0-9]+)\.(?P<middle>[0-9]+)\.(?P<minor>[0-9]+)-(?P<build>[0-9]+)(u[0-9]+)?$")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class VENAgent(pylo.ReferenceTracker):
|
|
14
|
+
|
|
15
|
+
def __init__(self, href: str, owner: 'pylo.AgentStore', workload: 'pylo.Workload' = None):
|
|
16
|
+
pylo.ReferenceTracker.__init__(self)
|
|
17
|
+
self.href: str = href
|
|
18
|
+
self.owner: 'pylo.AgentStore' = owner
|
|
19
|
+
self.workload: Optional['pylo.Workload'] = workload
|
|
20
|
+
|
|
21
|
+
self.software_version: Optional['pylo.SoftwareVersion'] = None
|
|
22
|
+
self._last_heartbeat: Optional[datetime.datetime] = None
|
|
23
|
+
|
|
24
|
+
self._status_security_policy_sync_state: Optional[str] = None
|
|
25
|
+
self._status_security_policy_applied_at: Optional[str] = None
|
|
26
|
+
self._status_rule_count: Optional[int] = None
|
|
27
|
+
|
|
28
|
+
self.mode = None
|
|
29
|
+
|
|
30
|
+
self.raw_json = None
|
|
31
|
+
|
|
32
|
+
def _get_date_from_json(self, prop_name_in_json: str) -> Optional[datetime.datetime]:
|
|
33
|
+
status_json = self.raw_json.get('status')
|
|
34
|
+
if status_json is None:
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
prop_value = status_json.get(prop_name_in_json)
|
|
38
|
+
if prop_value is None:
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
if '.' in prop_value:
|
|
42
|
+
time_found = datetime.datetime.strptime(prop_value, "%Y-%m-%dT%H:%M:%S.%fZ")
|
|
43
|
+
else:
|
|
44
|
+
time_found = datetime.datetime.strptime(prop_value, "%Y-%m-%dT%H:%M:%SZ")
|
|
45
|
+
|
|
46
|
+
return time_found
|
|
47
|
+
|
|
48
|
+
def load_from_json(self, data):
|
|
49
|
+
self.raw_json = data
|
|
50
|
+
|
|
51
|
+
status_json = data.get('status')
|
|
52
|
+
if status_json is None:
|
|
53
|
+
raise pylo.PyloEx("Cannot find VENAgent status in JSON from '{}'".format(self.href))
|
|
54
|
+
|
|
55
|
+
version_string = status_json.get('agent_version')
|
|
56
|
+
if version_string is None:
|
|
57
|
+
raise pylo.PyloEx("Cannot find VENAgent version from '{}'".format(self.href))
|
|
58
|
+
self.software_version = pylo.SoftwareVersion(version_string)
|
|
59
|
+
if self.software_version.is_unknown:
|
|
60
|
+
pylo.log.warn("Agent {} from Workload {}/{} has unknown software version: {}".format(
|
|
61
|
+
self.href,
|
|
62
|
+
self.workload.get_name(),
|
|
63
|
+
self.workload.href,
|
|
64
|
+
self.software_version.version_string))
|
|
65
|
+
|
|
66
|
+
self._status_security_policy_sync_state = status_json.get('security_policy_sync_state')
|
|
67
|
+
|
|
68
|
+
self._status_rule_count = status_json.get('firewall_rule_count')
|
|
69
|
+
# if self._status_rule_count is None:
|
|
70
|
+
# raise pylo.PyloEx("Cannot find firewall_rule_count VENAgent '{}' rule count ".format(self.href), status_json)
|
|
71
|
+
|
|
72
|
+
config_json = data.get('config')
|
|
73
|
+
if config_json is None:
|
|
74
|
+
raise pylo.PyloEx("Cannot find Agent's config in JSON", data)
|
|
75
|
+
|
|
76
|
+
self.mode = config_json.get('mode')
|
|
77
|
+
if self.mode is None:
|
|
78
|
+
raise pylo.PyloEx("Cannot find Agent's mode in config JSON", config_json)
|
|
79
|
+
|
|
80
|
+
if self.mode == 'illuminated':
|
|
81
|
+
log_traffic = config_json.get('log_traffic')
|
|
82
|
+
if log_traffic:
|
|
83
|
+
self.mode = "test"
|
|
84
|
+
else:
|
|
85
|
+
self.mode = "build"
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def status(self) -> Literal['stopped','active','suspended','uninstalled']:
|
|
89
|
+
return self.raw_json['status']['status']
|
|
90
|
+
|
|
91
|
+
def get_last_heartbeat_date(self) -> Optional[datetime.datetime]:
|
|
92
|
+
if self._last_heartbeat is None:
|
|
93
|
+
self._last_heartbeat = self._get_date_from_json('last_heartbeat_on')
|
|
94
|
+
return self._last_heartbeat
|
|
95
|
+
|
|
96
|
+
def get_status_security_policy_applied_at(self):
|
|
97
|
+
if self._status_security_policy_applied_at is None:
|
|
98
|
+
self._status_security_policy_applied_at = self._get_date_from_json('security_policy_applied_at')
|
|
99
|
+
return self._status_security_policy_applied_at
|
|
100
|
+
|
|
101
|
+
def get_status_security_policy_sync_state(self):
|
|
102
|
+
return self._status_security_policy_sync_state
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class AgentStore:
|
|
106
|
+
|
|
107
|
+
def __init__(self, owner: 'pylo.Organization'):
|
|
108
|
+
self.owner = owner
|
|
109
|
+
self.items_by_href: Dict[str, pylo.VENAgent] = {}
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def agents(self) -> List['pylo.VENAgent']:
|
|
113
|
+
"""
|
|
114
|
+
Returns a copy of the list of all agents in the store
|
|
115
|
+
:return:
|
|
116
|
+
"""
|
|
117
|
+
return list(self.items_by_href.values())
|
|
118
|
+
|
|
119
|
+
def find_by_href(self, href: str) -> VENAgent:
|
|
120
|
+
return self.items_by_href.get(href)
|
|
121
|
+
|
|
122
|
+
def create_ven_agent_from_workload_record(self, workload: 'pylo.Workload', json_data) -> 'pylo.VENAgent':
|
|
123
|
+
# For developer use only. This is called by the WorkloadStore when it creates a new workload as the Agent records are read from there
|
|
124
|
+
href = json_data.get('href')
|
|
125
|
+
if href is None:
|
|
126
|
+
raise pylo.PyloEx("Cannot extract Agent href from workload '{}'".format(workload.href))
|
|
127
|
+
|
|
128
|
+
agent = pylo.VENAgent(href, self, workload)
|
|
129
|
+
agent.load_from_json(json_data)
|
|
130
|
+
|
|
131
|
+
self.items_by_href[href] = agent
|
|
132
|
+
|
|
133
|
+
return agent
|
|
134
|
+
|
|
135
|
+
def count_agents(self) -> int:
|
|
136
|
+
return len(self.items_by_href)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from .Helpers import nice_json
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class PyloEx(Exception):
|
|
5
|
+
"""
|
|
6
|
+
Base class for all Pylo exceptions
|
|
7
|
+
"""
|
|
8
|
+
def __init__(self, arg, json_object=None):
|
|
9
|
+
if json_object is None:
|
|
10
|
+
Exception.__init__(self, arg)
|
|
11
|
+
return
|
|
12
|
+
|
|
13
|
+
text = "{}\nJSON output:\n{}".format(arg, nice_json(json_object))
|
|
14
|
+
super().__init__(self, text)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class PyloObjectNotFound(PyloEx):
|
|
18
|
+
def __init__(self, arg, json_object=None):
|
|
19
|
+
PyloEx(arg, json_object)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class PyloApiEx(PyloEx):
|
|
23
|
+
"""
|
|
24
|
+
Base class for all Pylo API exceptions
|
|
25
|
+
"""
|
|
26
|
+
def __init__(self, arg, json_object=None):
|
|
27
|
+
PyloEx(arg, json_object)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class PyloApiTooManyRequestsEx(PyloApiEx):
|
|
31
|
+
def __init__(self, arg, json_object=None):
|
|
32
|
+
PyloApiEx(arg, json_object)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class PyloApiUnexpectedSyntax(PyloApiEx):
|
|
36
|
+
def __init__(self, arg, json_object=None):
|
|
37
|
+
PyloApiEx(arg, json_object)
|
|
38
|
+
|
|
39
|
+
class PyloApiRequestForbiddenEx(PyloApiEx):
|
|
40
|
+
def __init__(self, arg, json_object=None):
|
|
41
|
+
PyloApiEx(arg, json_object)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|