illumio-pylo 0.3.4__py3-none-any.whl → 0.3.6__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 +19 -13
- illumio_pylo/API/CredentialsManager.py +61 -42
- illumio_pylo/AgentStore.py +3 -0
- illumio_pylo/IPList.py +1 -7
- illumio_pylo/IPMap.py +3 -0
- illumio_pylo/LabelCommon.py +2 -0
- illumio_pylo/LabelGroup.py +2 -0
- illumio_pylo/LabelStore.py +2 -0
- illumio_pylo/LabeledObject.py +2 -0
- illumio_pylo/Organization.py +4 -1
- illumio_pylo/Rule.py +15 -0
- illumio_pylo/Ruleset.py +6 -0
- illumio_pylo/RulesetStore.py +2 -0
- illumio_pylo/SecurityPrincipal.py +3 -0
- illumio_pylo/Service.py +8 -0
- illumio_pylo/SoftwareVersion.py +1 -3
- illumio_pylo/VirtualService.py +3 -0
- illumio_pylo/VirtualServiceStore.py +2 -0
- illumio_pylo/Workload.py +3 -0
- illumio_pylo/WorkloadStore.py +2 -0
- illumio_pylo/WorkloadStoreSubClasses.py +1 -0
- illumio_pylo/__init__.py +2 -5
- illumio_pylo/cli/commands/credential_manager.py +13 -14
- illumio_pylo/tmp.py +27 -8
- {illumio_pylo-0.3.4.dist-info → illumio_pylo-0.3.6.dist-info}/METADATA +1 -1
- {illumio_pylo-0.3.4.dist-info → illumio_pylo-0.3.6.dist-info}/RECORD +29 -29
- {illumio_pylo-0.3.4.dist-info → illumio_pylo-0.3.6.dist-info}/LICENSE +0 -0
- {illumio_pylo-0.3.4.dist-info → illumio_pylo-0.3.6.dist-info}/WHEEL +0 -0
- {illumio_pylo-0.3.4.dist-info → illumio_pylo-0.3.6.dist-info}/top_level.txt +0 -0
illumio_pylo/API/APIConnector.py
CHANGED
|
@@ -625,12 +625,14 @@ class APIConnector:
|
|
|
625
625
|
return None
|
|
626
626
|
|
|
627
627
|
def objects_ven_get(self,
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
628
|
+
include_deleted=False,
|
|
629
|
+
filter_by_ip: str = None,
|
|
630
|
+
filter_by_label: Optional[WorkloadsGetQueryLabelFilterJsonStructure] = None,
|
|
631
|
+
filter_by_name: str = None,
|
|
632
|
+
max_results: int = None,
|
|
633
|
+
async_mode=True,
|
|
634
|
+
representation: Optional[Literal['ven_labels']] = None
|
|
635
|
+
) -> List[VenObjectJsonStructure]:
|
|
634
636
|
path = '/vens'
|
|
635
637
|
data = {}
|
|
636
638
|
|
|
@@ -647,12 +649,14 @@ class APIConnector:
|
|
|
647
649
|
if filter_by_name is not None:
|
|
648
650
|
data['name'] = filter_by_name
|
|
649
651
|
|
|
652
|
+
if representation is not None:
|
|
653
|
+
data['representation'] = representation
|
|
654
|
+
|
|
650
655
|
if max_results is not None:
|
|
651
656
|
data['max_results'] = max_results
|
|
652
657
|
|
|
653
658
|
return self.do_get_call(path=path, async_call=async_mode, params=data)
|
|
654
659
|
|
|
655
|
-
|
|
656
660
|
def objects_workload_get(self,
|
|
657
661
|
include_deleted=False,
|
|
658
662
|
filter_by_ip: str = None,
|
|
@@ -935,18 +939,20 @@ class APIConnector:
|
|
|
935
939
|
|
|
936
940
|
return self.do_get_call(path=path, async_call=False, include_org_id=False )
|
|
937
941
|
|
|
938
|
-
def object_network_device_endpoint_create(self, network_device_href: str, name: str,
|
|
942
|
+
def object_network_device_endpoint_create(self, network_device_href: str, name: str,
|
|
943
|
+
endpoint_type: Literal['switch_port'], workloads_href: List[str]) \
|
|
944
|
+
-> List[NetworkDeviceEndpointObjectJsonStructure]:
|
|
945
|
+
|
|
939
946
|
path = '{}/network_endpoints'.format(network_device_href)
|
|
940
947
|
|
|
941
|
-
|
|
948
|
+
workloads_href_objects = []
|
|
942
949
|
for workload_href in workloads_href:
|
|
943
|
-
|
|
950
|
+
workloads_href_objects.append({'href': workload_href})
|
|
944
951
|
|
|
945
|
-
data = {
|
|
952
|
+
data = {'config': {'name': name, 'endpoint_type': endpoint_type}, 'workloads': workloads_href_objects}
|
|
946
953
|
|
|
947
954
|
return self.do_post_call(path=path, async_call=False, include_org_id=False, json_arguments=data, json_output_expected=True)
|
|
948
955
|
|
|
949
|
-
|
|
950
956
|
def objects_ruleset_get(self, max_results: int = None, async_mode=True) -> List[RulesetObjectJsonStructure]:
|
|
951
957
|
path = '/sec_policy/draft/rule_sets'
|
|
952
958
|
data = {}
|
|
@@ -1069,7 +1075,7 @@ class APIConnector:
|
|
|
1069
1075
|
'ingress_services': services_json
|
|
1070
1076
|
}
|
|
1071
1077
|
|
|
1072
|
-
path = ruleset_href+'/sec_rules'
|
|
1078
|
+
path = ruleset_href + '/sec_rules'
|
|
1073
1079
|
|
|
1074
1080
|
return self.do_post_call(path, json_arguments=data, json_output_expected=True, include_org_id=False)
|
|
1075
1081
|
|
|
@@ -4,6 +4,7 @@ from typing import Dict, TypedDict, Union, List, Optional
|
|
|
4
4
|
import json
|
|
5
5
|
import os
|
|
6
6
|
from cryptography.fernet import Fernet
|
|
7
|
+
from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305
|
|
7
8
|
from ..Exception import PyloEx
|
|
8
9
|
from .. import log
|
|
9
10
|
|
|
@@ -122,7 +123,7 @@ def get_credentials_from_file(fqdn_or_profile_name: str = None,
|
|
|
122
123
|
|
|
123
124
|
if fail_with_an_exception:
|
|
124
125
|
raise PyloEx("No profile found in credential file '{}' with fqdn: {}".
|
|
125
|
-
|
|
126
|
+
format(credential_file, fqdn_or_profile_name))
|
|
126
127
|
|
|
127
128
|
return None
|
|
128
129
|
|
|
@@ -133,8 +134,8 @@ def list_potential_credential_files() -> List[str]:
|
|
|
133
134
|
:return:
|
|
134
135
|
"""
|
|
135
136
|
potential_credential_files = []
|
|
136
|
-
if os.environ.get('
|
|
137
|
-
potential_credential_files.append(os.environ.get('
|
|
137
|
+
if os.environ.get('PYLO_CREDENTIAL_FILE', None) is not None:
|
|
138
|
+
potential_credential_files.append(os.environ.get('PYLO_CREDENTIAL_FILE'))
|
|
138
139
|
potential_credential_files.append(os.path.expanduser("~/.pylo/credentials.json"))
|
|
139
140
|
potential_credential_files.append(os.path.join(os.getcwd(), "credentials.json"))
|
|
140
141
|
|
|
@@ -153,7 +154,7 @@ def get_all_credentials() -> List[CredentialProfile]:
|
|
|
153
154
|
return credentials
|
|
154
155
|
|
|
155
156
|
|
|
156
|
-
def create_credential_in_file(file_full_path: str, data: CredentialFileEntry, overwrite_existing_profile
|
|
157
|
+
def create_credential_in_file(file_full_path: str, data: CredentialFileEntry, overwrite_existing_profile=False) -> str:
|
|
157
158
|
"""
|
|
158
159
|
Create a credential in a file and return the full path to the file
|
|
159
160
|
:param file_full_path:
|
|
@@ -173,7 +174,10 @@ def create_credential_in_file(file_full_path: str, data: CredentialFileEntry, ov
|
|
|
173
174
|
for profile in credentials:
|
|
174
175
|
if profile['name'].lower() == data['name'].lower():
|
|
175
176
|
if overwrite_existing_profile:
|
|
176
|
-
profile
|
|
177
|
+
# profile is a dict, remove of all its entries
|
|
178
|
+
for key in list(profile.keys()):
|
|
179
|
+
del profile[key]
|
|
180
|
+
profile.update(data)
|
|
177
181
|
break
|
|
178
182
|
else:
|
|
179
183
|
raise PyloEx("Profile with name {} already exists in file {}".format(data['name'], file_full_path))
|
|
@@ -187,7 +191,7 @@ def create_credential_in_file(file_full_path: str, data: CredentialFileEntry, ov
|
|
|
187
191
|
else:
|
|
188
192
|
credentials = [credentials, data]
|
|
189
193
|
else:
|
|
190
|
-
|
|
194
|
+
credentials = [data]
|
|
191
195
|
|
|
192
196
|
# write to the file
|
|
193
197
|
with open(file_full_path, 'w') as f:
|
|
@@ -195,6 +199,7 @@ def create_credential_in_file(file_full_path: str, data: CredentialFileEntry, ov
|
|
|
195
199
|
|
|
196
200
|
return file_full_path
|
|
197
201
|
|
|
202
|
+
|
|
198
203
|
def create_credential_in_default_file(data: CredentialFileEntry) -> str:
|
|
199
204
|
"""
|
|
200
205
|
Create a credential in the default credential file and return the full path to the file
|
|
@@ -206,32 +211,20 @@ def create_credential_in_default_file(data: CredentialFileEntry) -> str:
|
|
|
206
211
|
return file_path
|
|
207
212
|
|
|
208
213
|
|
|
209
|
-
def
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
:param raw:
|
|
214
|
-
:param key:
|
|
215
|
-
:return: base64 encoded encrypted string
|
|
216
|
-
"""
|
|
217
|
-
f = Fernet(base64.urlsafe_b64encode(key))
|
|
218
|
-
token = f.encrypt(bytes(raw, 'utf-8'))
|
|
219
|
-
return token
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
# generate a random 128bit key
|
|
223
|
-
session_key_to_sign = os.urandom(32)
|
|
214
|
+
def encrypt_api_key_with_paramiko_ssh_key_chacha20poly1305(ssh_key: paramiko.AgentKey, api_key: str) -> str:
|
|
215
|
+
seed_key_to_be_signed = os.urandom(32)
|
|
216
|
+
signed_seed_key = ssh_key.sign_ssh_data(seed_key_to_be_signed)
|
|
217
|
+
encryption_key = sha256(signed_seed_key).digest()
|
|
224
218
|
|
|
225
|
-
|
|
219
|
+
nonce = seed_key_to_be_signed[:12]
|
|
220
|
+
chacha20_object = ChaCha20Poly1305(encryption_key)
|
|
226
221
|
|
|
227
|
-
|
|
228
|
-
encryption_key = sha256(signed_message).digest()
|
|
229
|
-
#print("Encryption key: {}".format(encryption_key.hex()))
|
|
230
|
-
encrypted_text = encrypt(api_key, encryption_key)
|
|
222
|
+
encrypted_text = chacha20_object.encrypt(nonce, bytes(api_key, 'utf-8'), ssh_key.get_fingerprint())
|
|
231
223
|
|
|
232
|
-
api_key = "$encrypted$:ssh-
|
|
233
|
-
|
|
234
|
-
|
|
224
|
+
api_key = "$encrypted$:ssh-ChaCha20Poly1305:{}:{}:{}".format(
|
|
225
|
+
base64.urlsafe_b64encode(ssh_key.get_fingerprint()).decode('utf-8'),
|
|
226
|
+
base64.urlsafe_b64encode(seed_key_to_be_signed).decode('utf-8'),
|
|
227
|
+
base64.urlsafe_b64encode(encrypted_text).decode('utf-8'))
|
|
235
228
|
|
|
236
229
|
return api_key
|
|
237
230
|
|
|
@@ -251,36 +244,62 @@ def decrypt_api_key_with_paramiko_ssh_key_fernet(encrypted_api_key_payload: str)
|
|
|
251
244
|
session_key = base64.urlsafe_b64decode(api_key_parts[3])
|
|
252
245
|
encrypted_api_key = api_key_parts[4]
|
|
253
246
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
found_key = None
|
|
257
|
-
for key in keys:
|
|
258
|
-
if key.get_fingerprint() == fingerprint:
|
|
259
|
-
found_key = key
|
|
260
|
-
break
|
|
261
|
-
|
|
262
|
-
if found_key is None:
|
|
247
|
+
ssh_key = find_ssh_key_from_fingerprint(fingerprint)
|
|
248
|
+
if ssh_key is None:
|
|
263
249
|
raise PyloEx("No key found in the agent with fingerprint {}".format(fingerprint.hex()))
|
|
264
250
|
|
|
265
251
|
# sign the session key
|
|
266
|
-
signed_session_key =
|
|
252
|
+
signed_session_key = ssh_key.sign_ssh_data(session_key)
|
|
267
253
|
encryption_key = sha256(signed_session_key).digest()
|
|
268
|
-
#print("Encryption key: {}".format(encryption_key.hex()))
|
|
269
|
-
#print("Encrypted from KEY fingerprint: {}".format(fingerprint.hex()))
|
|
254
|
+
# print("Encryption key: {}".format(encryption_key.hex()))
|
|
255
|
+
# print("Encrypted from KEY fingerprint: {}".format(fingerprint.hex()))
|
|
270
256
|
|
|
271
257
|
return decrypt(token_b64_encoded=encrypted_api_key,
|
|
272
258
|
key=encryption_key
|
|
273
259
|
)
|
|
274
260
|
|
|
261
|
+
|
|
262
|
+
def decrypt_api_key_with_paramiko_ssh_key_chacha20poly1305(encrypted_api_key_payload: str) -> str:
|
|
263
|
+
api_key_parts = encrypted_api_key_payload.split(":")
|
|
264
|
+
if len(api_key_parts) != 5:
|
|
265
|
+
raise PyloEx("Invalid encrypted API key format")
|
|
266
|
+
|
|
267
|
+
fingerprint = base64.urlsafe_b64decode(api_key_parts[2])
|
|
268
|
+
seed_key_to_be_signed = base64.urlsafe_b64decode(api_key_parts[3])
|
|
269
|
+
encrypted_api_key = base64.urlsafe_b64decode(api_key_parts[4])
|
|
270
|
+
|
|
271
|
+
ssh_key = find_ssh_key_from_fingerprint(fingerprint)
|
|
272
|
+
if ssh_key is None:
|
|
273
|
+
raise PyloEx("No key found in the agent with fingerprint {}".format(fingerprint.hex()))
|
|
274
|
+
|
|
275
|
+
signed_session_key = ssh_key.sign_ssh_data(seed_key_to_be_signed)
|
|
276
|
+
encryption_key = sha256(signed_session_key).digest()
|
|
277
|
+
|
|
278
|
+
chacha20_object = ChaCha20Poly1305(encryption_key)
|
|
279
|
+
nonce = seed_key_to_be_signed[:12]
|
|
280
|
+
|
|
281
|
+
return chacha20_object.decrypt(nonce, encrypted_api_key, ssh_key.get_fingerprint()).decode('utf-8')
|
|
282
|
+
|
|
283
|
+
|
|
275
284
|
def decrypt_api_key(encrypted_api_key_payload: str) -> str:
|
|
276
285
|
# detect the encryption method
|
|
277
286
|
if not encrypted_api_key_payload.startswith("$encrypted$:"):
|
|
278
287
|
raise PyloEx("Invalid encrypted API key format")
|
|
279
288
|
if encrypted_api_key_payload.startswith("$encrypted$:ssh-Fernet:"):
|
|
280
289
|
return decrypt_api_key_with_paramiko_ssh_key_fernet(encrypted_api_key_payload)
|
|
290
|
+
elif encrypted_api_key_payload.startswith("$encrypted$:ssh-ChaCha20Poly1305:"):
|
|
291
|
+
return decrypt_api_key_with_paramiko_ssh_key_chacha20poly1305(encrypted_api_key_payload)
|
|
281
292
|
|
|
282
293
|
raise PyloEx("Unsupported encryption method: {}".format(encrypted_api_key_payload.split(":")[1]))
|
|
283
294
|
|
|
284
295
|
|
|
285
296
|
def is_api_key_encrypted(encrypted_api_key_payload: str) -> bool:
|
|
286
|
-
return encrypted_api_key_payload.startswith("$encrypted$:")
|
|
297
|
+
return encrypted_api_key_payload.startswith("$encrypted$:")
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def find_ssh_key_from_fingerprint(fingerprint: bytes) -> Optional[paramiko.AgentKey]:
|
|
301
|
+
keys = paramiko.Agent().get_keys()
|
|
302
|
+
for key in keys:
|
|
303
|
+
if key.get_fingerprint() == fingerprint:
|
|
304
|
+
return key
|
|
305
|
+
return None
|
illumio_pylo/AgentStore.py
CHANGED
|
@@ -12,6 +12,9 @@ from typing import *
|
|
|
12
12
|
|
|
13
13
|
class VENAgent(pylo.ReferenceTracker):
|
|
14
14
|
|
|
15
|
+
__slots__ = ['href', 'owner', 'workload', 'software_version', '_last_heartbeat', '_status_security_policy_sync_state',
|
|
16
|
+
'_status_security_policy_applied_at', '_status_rule_count', 'mode', 'raw_json']
|
|
17
|
+
|
|
15
18
|
def __init__(self, href: str, owner: 'pylo.AgentStore', workload: 'pylo.Workload' = None):
|
|
16
19
|
pylo.ReferenceTracker.__init__(self)
|
|
17
20
|
self.href: str = href
|
illumio_pylo/IPList.py
CHANGED
|
@@ -8,13 +8,7 @@ from .Helpers import *
|
|
|
8
8
|
|
|
9
9
|
class IPList(pylo.ReferenceTracker):
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
:type owner: IPListStore
|
|
13
|
-
:type description: str|None
|
|
14
|
-
:type raw_entries: dict[str,str]
|
|
15
|
-
"""
|
|
16
|
-
name: str
|
|
17
|
-
href: str
|
|
11
|
+
__slots__ = ['owner', 'name', 'href', 'description', 'raw_json', 'raw_entries']
|
|
18
12
|
|
|
19
13
|
def __init__(self, name: str, href: str, owner: 'pylo.IPListStore', description=None):
|
|
20
14
|
"""
|
illumio_pylo/IPMap.py
CHANGED
illumio_pylo/LabelCommon.py
CHANGED
|
@@ -5,6 +5,8 @@ from .LabelStore import label_type_role, label_type_env, label_type_loc, label_t
|
|
|
5
5
|
|
|
6
6
|
class LabelCommon:
|
|
7
7
|
|
|
8
|
+
__slots__ = ['owner', 'name', 'href', 'type']
|
|
9
|
+
|
|
8
10
|
def __init__(self, name: str, href: str, label_type: str, owner: LabelStore):
|
|
9
11
|
self.owner: LabelStore = owner
|
|
10
12
|
self.name: str = name
|
illumio_pylo/LabelGroup.py
CHANGED
|
@@ -8,6 +8,8 @@ from .API.JsonPayloadTypes import LabelGroupObjectJsonStructure
|
|
|
8
8
|
|
|
9
9
|
class LabelGroup(pylo.ReferenceTracker, pylo.LabelCommon):
|
|
10
10
|
|
|
11
|
+
__slots__ = ['_members_by_href', 'raw_json']
|
|
12
|
+
|
|
11
13
|
def __init__(self, name: str, href: str, label_type: str, owner):
|
|
12
14
|
pylo.ReferenceTracker.__init__(self)
|
|
13
15
|
pylo.LabelCommon.__init__(self, name, href, label_type, owner)
|
illumio_pylo/LabelStore.py
CHANGED
|
@@ -47,6 +47,8 @@ class LabelStore:
|
|
|
47
47
|
result.append(label)
|
|
48
48
|
return result
|
|
49
49
|
|
|
50
|
+
__slots__ = ['owner', '_items_by_href', 'label_types', 'label_types_as_set', 'label_resolution_cache']
|
|
51
|
+
|
|
50
52
|
def __init__(self, owner: 'pylo.Organization'):
|
|
51
53
|
self.owner: "pylo.Organization" = owner
|
|
52
54
|
self._items_by_href: Dict[str, Union[pylo.Label, pylo.LabelGroup]] = {}
|
illumio_pylo/LabeledObject.py
CHANGED
illumio_pylo/Organization.py
CHANGED
|
@@ -9,6 +9,9 @@ from .API.CredentialsManager import get_credentials_from_file
|
|
|
9
9
|
|
|
10
10
|
class Organization:
|
|
11
11
|
|
|
12
|
+
__slots__ = ['id', 'connector', 'LabelStore', 'IPListStore', 'WorkloadStore', 'VirtualServiceStore', 'AgentStore',
|
|
13
|
+
'ServiceStore', 'RulesetStore', 'SecurityPrincipalStore', 'pce_version']
|
|
14
|
+
|
|
12
15
|
def __init__(self, org_id):
|
|
13
16
|
self.id: int = org_id
|
|
14
17
|
self.connector: Optional['pylo.APIConnector'] = None
|
|
@@ -58,7 +61,7 @@ class Organization:
|
|
|
58
61
|
"""
|
|
59
62
|
Credentials files will be looked for in the following order:
|
|
60
63
|
1. The path provided in the credential_file argument
|
|
61
|
-
2. The path provided in the
|
|
64
|
+
2. The path provided in the PYLO_CREDENTIAL_FILE environment variable
|
|
62
65
|
3. The path ~/.pylo/credentials.json
|
|
63
66
|
4. Current working directory credentials.json
|
|
64
67
|
:param fqdn_or_profile_name:
|
illumio_pylo/Rule.py
CHANGED
|
@@ -28,6 +28,9 @@ class RuleApiUpdateStack:
|
|
|
28
28
|
|
|
29
29
|
class Rule:
|
|
30
30
|
|
|
31
|
+
__slots__ = ['owner', 'description', 'services', 'providers', 'consumers', 'consuming_principals', 'href', 'enabled',
|
|
32
|
+
'secure_connect', 'unscoped_consumers', 'stateless', 'machine_auth', 'raw_json', 'batch_update_stack']
|
|
33
|
+
|
|
31
34
|
def __init__(self, owner: 'Ruleset'):
|
|
32
35
|
self.owner: Ruleset = owner
|
|
33
36
|
self.description: Optional[str] = None
|
|
@@ -123,6 +126,9 @@ class Rule:
|
|
|
123
126
|
|
|
124
127
|
|
|
125
128
|
class RuleSecurityPrincipalContainer(pylo.Referencer):
|
|
129
|
+
|
|
130
|
+
__slots__ = ['owner', '_items']
|
|
131
|
+
|
|
126
132
|
def __init__(self, owner: 'pylo.Rule'):
|
|
127
133
|
Referencer.__init__(self)
|
|
128
134
|
self.owner = owner
|
|
@@ -140,6 +146,9 @@ class RuleSecurityPrincipalContainer(pylo.Referencer):
|
|
|
140
146
|
|
|
141
147
|
|
|
142
148
|
class DirectServiceInRule:
|
|
149
|
+
|
|
150
|
+
__slots__ = ['protocol', 'port', 'to_port']
|
|
151
|
+
|
|
143
152
|
def __init__(self, proto: int, port: int = None, toport: int = None):
|
|
144
153
|
self.protocol = proto
|
|
145
154
|
self.port = port
|
|
@@ -245,6 +254,9 @@ class DirectServiceInRule:
|
|
|
245
254
|
|
|
246
255
|
|
|
247
256
|
class RuleServiceContainer(pylo.Referencer):
|
|
257
|
+
|
|
258
|
+
__slots__ = ['owner', '_items', '_direct_services', '_cached_port_map']
|
|
259
|
+
|
|
248
260
|
def __init__(self, owner: 'pylo.Rule'):
|
|
249
261
|
Referencer.__init__(self)
|
|
250
262
|
self.owner = owner
|
|
@@ -380,6 +392,9 @@ class RuleServiceContainer(pylo.Referencer):
|
|
|
380
392
|
|
|
381
393
|
|
|
382
394
|
class RuleHostContainer(pylo.Referencer):
|
|
395
|
+
|
|
396
|
+
__slots__ = ['owner', '_items', 'name', '_hasAllWorkloads']
|
|
397
|
+
|
|
383
398
|
def __init__(self, owner: 'pylo.Rule', name: str):
|
|
384
399
|
Referencer.__init__(self)
|
|
385
400
|
self.owner = owner
|
illumio_pylo/Ruleset.py
CHANGED
|
@@ -10,6 +10,8 @@ ruleset_id_extraction_regex = re.compile(r"^/orgs/([0-9]+)/sec_policy/([0-9]+)?(
|
|
|
10
10
|
|
|
11
11
|
class RulesetScope:
|
|
12
12
|
|
|
13
|
+
__slots__ = ['owner', 'scope_entries']
|
|
14
|
+
|
|
13
15
|
def __init__(self, owner: 'pylo.Ruleset'):
|
|
14
16
|
self.owner: 'pylo.Ruleset' = owner
|
|
15
17
|
self.scope_entries: Dict['pylo.RulesetScopeEntry', 'pylo.RulesetScopeEntry'] = {}
|
|
@@ -39,6 +41,8 @@ class RulesetScope:
|
|
|
39
41
|
|
|
40
42
|
class RulesetScopeEntry:
|
|
41
43
|
|
|
44
|
+
__slots__ = ['owner', '_labels']
|
|
45
|
+
|
|
42
46
|
def __init__(self, owner: 'pylo.RulesetScope'):
|
|
43
47
|
self.owner: pylo.RulesetScope = owner
|
|
44
48
|
self._labels: Dict[str, Union['pylo.Label', 'pylo.LabelGroup']] = {}
|
|
@@ -144,6 +148,8 @@ class RulesetScopeEntry:
|
|
|
144
148
|
|
|
145
149
|
class Ruleset:
|
|
146
150
|
|
|
151
|
+
__slots__ = ['owner', 'href', 'name', 'description', 'scopes', '_rules_by_href', '_rules', 'disabled']
|
|
152
|
+
|
|
147
153
|
def __init__(self, owner: 'pylo.RulesetStore'):
|
|
148
154
|
self.owner: 'pylo.RulesetStore' = owner
|
|
149
155
|
self.href: Optional[str] = None
|
illumio_pylo/RulesetStore.py
CHANGED
|
@@ -5,6 +5,9 @@ from illumio_pylo import log
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class SecurityPrincipal(pylo.ReferenceTracker):
|
|
8
|
+
|
|
9
|
+
__slots__ = ['owner', 'name', 'href', 'sid', 'deleted', 'raw_json']
|
|
10
|
+
|
|
8
11
|
def __init__(self, name: str, href: str, owner: 'pylo.SecurityPrincipalStore'):
|
|
9
12
|
pylo.ReferenceTracker.__init__(self)
|
|
10
13
|
self.owner: 'pylo.SecurityPrincipalStore' = owner
|
illumio_pylo/Service.py
CHANGED
|
@@ -6,6 +6,9 @@ from typing import *
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class PortMap:
|
|
9
|
+
|
|
10
|
+
__slots__ = ['_tcp_map', '_udp_map', '_protocol_map']
|
|
11
|
+
|
|
9
12
|
def __init__(self):
|
|
10
13
|
self._tcp_map: List[List[2]] = [] # [start, end]
|
|
11
14
|
self._udp_map: List[List[2]] = [] # [start, end]
|
|
@@ -99,6 +102,9 @@ class PortMap:
|
|
|
99
102
|
|
|
100
103
|
|
|
101
104
|
class ServiceEntry:
|
|
105
|
+
|
|
106
|
+
__slots__ = ['protocol', 'port', 'to_port', 'icmp_code', 'icmp_type']
|
|
107
|
+
|
|
102
108
|
def __init__(self, protocol: int, port: int = None, to_port: Optional[int] = None, icmp_code: Optional[int] = None,
|
|
103
109
|
icmp_type: Optional[int] = None):
|
|
104
110
|
self.protocol = protocol
|
|
@@ -160,6 +166,8 @@ class ServiceEntry:
|
|
|
160
166
|
|
|
161
167
|
class Service(pylo.ReferenceTracker):
|
|
162
168
|
|
|
169
|
+
__slots__ = ['name', 'href', 'owner', 'entries', 'description', 'processName', 'deleted', 'raw_json']
|
|
170
|
+
|
|
163
171
|
def __init__(self, name: str, href: str, owner: 'pylo.ServiceStore'):
|
|
164
172
|
pylo.ReferenceTracker.__init__(self)
|
|
165
173
|
|
illumio_pylo/SoftwareVersion.py
CHANGED
|
@@ -6,9 +6,7 @@ version_regex = re.compile(r"^(?P<major>[0-9]+)\.(?P<middle>[0-9]+)\.(?P<minor>[
|
|
|
6
6
|
|
|
7
7
|
class SoftwareVersion:
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
:type version_string: str
|
|
11
|
-
"""
|
|
9
|
+
__slots__ = ['version_string', 'is_unknown', 'major', 'middle', 'minor', 'build']
|
|
12
10
|
|
|
13
11
|
def __init__(self, version_string: str):
|
|
14
12
|
self.version_string = version_string
|
illumio_pylo/VirtualService.py
CHANGED
|
@@ -4,6 +4,9 @@ import illumio_pylo as pylo
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class VirtualService(pylo.ReferenceTracker):
|
|
7
|
+
|
|
8
|
+
__slots__ = ['owner', 'name', 'href', 'raw_json']
|
|
9
|
+
|
|
7
10
|
def __init__(self, name: str, href: str, owner: 'pylo.VirtualServiceStore'):
|
|
8
11
|
pylo.ReferenceTracker.__init__(self)
|
|
9
12
|
self.owner = owner
|
|
@@ -6,6 +6,8 @@ from .API.JsonPayloadTypes import VirtualServiceObjectJsonStructure
|
|
|
6
6
|
|
|
7
7
|
class VirtualServiceStore:
|
|
8
8
|
|
|
9
|
+
__slots__ = ['owner', 'items_by_href', 'itemsByName']
|
|
10
|
+
|
|
9
11
|
def __init__(self, owner: 'pylo.Organization'):
|
|
10
12
|
self.owner: 'pylo.Organization' = owner
|
|
11
13
|
self.items_by_href: Dict[str, 'pylo.VirtualService'] = {}
|
illumio_pylo/Workload.py
CHANGED
|
@@ -47,6 +47,9 @@ class WorkloadApiUpdateStack:
|
|
|
47
47
|
|
|
48
48
|
class Workload(pylo.ReferenceTracker, pylo.Referencer, LabeledObject):
|
|
49
49
|
|
|
50
|
+
__slots__ = ['owner', 'name', 'href', 'forced_name', 'hostname', 'description', 'interfaces', 'online', 'os_id',
|
|
51
|
+
'os_detail', 'ven_agent', 'unmanaged', 'temporary', 'deleted', 'raw_json', '_batch_update_stack']
|
|
52
|
+
|
|
50
53
|
def __init__(self, name: str, href: str, owner: 'pylo.WorkloadStore'):
|
|
51
54
|
ReferenceTracker.__init__(self)
|
|
52
55
|
Referencer.__init__(self)
|
illumio_pylo/WorkloadStore.py
CHANGED
|
@@ -10,6 +10,8 @@ from .WorkloadStoreSubClasses import UnmanagedWorkloadDraft, UnmanagedWorkloadDr
|
|
|
10
10
|
|
|
11
11
|
class WorkloadStore:
|
|
12
12
|
|
|
13
|
+
__slots__ = ['owner', 'itemsByHRef']
|
|
14
|
+
|
|
13
15
|
def __init__(self, owner: 'Organization'):
|
|
14
16
|
self.owner: Organization = owner
|
|
15
17
|
self.itemsByHRef: Dict[str, Workload] = {}
|
illumio_pylo/__init__.py
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
__version__ = "0.3.
|
|
1
|
+
__version__ = "0.3.6"
|
|
2
2
|
|
|
3
|
-
import os
|
|
4
|
-
import sys
|
|
5
3
|
from typing import Callable
|
|
6
4
|
|
|
7
5
|
from .tmp import *
|
|
@@ -60,7 +58,7 @@ def get_organization_using_credential_file(fqdn_or_profile_name: str = None,
|
|
|
60
58
|
"""
|
|
61
59
|
Credentials files will be looked for in the following order:
|
|
62
60
|
1. The path provided in the credential_file argument
|
|
63
|
-
2. The path provided in the
|
|
61
|
+
2. The path provided in the PYLO_CREDENTIAL_FILE environment variable
|
|
64
62
|
3. The path ~/.pylo/credentials.json
|
|
65
63
|
4. Current working directory credentials.json
|
|
66
64
|
:param fqdn_or_profile_name:
|
|
@@ -77,7 +75,6 @@ def get_organization_using_credential_file(fqdn_or_profile_name: str = None,
|
|
|
77
75
|
callback_api_objects_downloaded=callback_api_objects_downloaded)
|
|
78
76
|
|
|
79
77
|
|
|
80
|
-
|
|
81
78
|
ignoreWorkloadsWithSameName = True
|
|
82
79
|
|
|
83
80
|
objectNotFound = object()
|
|
@@ -9,8 +9,9 @@ import paramiko
|
|
|
9
9
|
import illumio_pylo as pylo
|
|
10
10
|
import click
|
|
11
11
|
from illumio_pylo.API.CredentialsManager import get_all_credentials, create_credential_in_file, CredentialFileEntry, \
|
|
12
|
-
create_credential_in_default_file,
|
|
13
|
-
get_credentials_from_file
|
|
12
|
+
create_credential_in_default_file, \
|
|
13
|
+
get_credentials_from_file, encrypt_api_key_with_paramiko_ssh_key_chacha20poly1305, \
|
|
14
|
+
decrypt_api_key_with_paramiko_ssh_key_chacha20poly1305, decrypt_api_key_with_paramiko_ssh_key_fernet
|
|
14
15
|
|
|
15
16
|
from illumio_pylo import log
|
|
16
17
|
from . import Command
|
|
@@ -28,7 +29,6 @@ def fill_parser(parser: argparse.ArgumentParser):
|
|
|
28
29
|
test_parser.add_argument('--name', required=False, type=str, default=None,
|
|
29
30
|
help='Name of the credential profile to test')
|
|
30
31
|
|
|
31
|
-
|
|
32
32
|
create_parser = sub_parser.add_parser('create', help='Create a new credential')
|
|
33
33
|
create_parser.add_argument('--name', required=False, type=str, default=None,
|
|
34
34
|
help='Name of the credential')
|
|
@@ -46,20 +46,18 @@ def fill_parser(parser: argparse.ArgumentParser):
|
|
|
46
46
|
|
|
47
47
|
def __main(args, **kwargs):
|
|
48
48
|
if args['sub_command'] == 'list':
|
|
49
|
+
table = PrettyTable(field_names=["Name", "URL", "API User", "Originating File"])
|
|
50
|
+
# all should be left justified
|
|
51
|
+
table.align = "l"
|
|
52
|
+
|
|
49
53
|
credentials = get_all_credentials()
|
|
50
54
|
# sort credentials by name
|
|
51
55
|
credentials.sort(key=lambda x: x.name)
|
|
52
56
|
|
|
53
|
-
# print credentials in a nice table
|
|
54
|
-
table_template = " {:<19} {:<40} {:<22} {:<25}"
|
|
55
|
-
print(table_template.format("Name", "URL", "API User", "Originating File"))
|
|
56
|
-
|
|
57
57
|
for credential in credentials:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
credential.originating_file)
|
|
62
|
-
)
|
|
58
|
+
table.add_row([credential.name, credential.fqdn, credential.api_user, credential.originating_file])
|
|
59
|
+
|
|
60
|
+
print(table)
|
|
63
61
|
|
|
64
62
|
elif args['sub_command'] == 'create':
|
|
65
63
|
|
|
@@ -136,10 +134,11 @@ def __main(args, **kwargs):
|
|
|
136
134
|
selected_ssh_key.get_fingerprint().hex(),
|
|
137
135
|
selected_ssh_key.comment))
|
|
138
136
|
print(" * encrypting API key with selected key (you may be prompted by your SSH agent for confirmation or PIN code) ...", flush=True, end="")
|
|
139
|
-
encrypted_api_key = encrypt_api_key_with_paramiko_ssh_key_fernet(ssh_key=selected_ssh_key, api_key=api_key)
|
|
137
|
+
# encrypted_api_key = encrypt_api_key_with_paramiko_ssh_key_fernet(ssh_key=selected_ssh_key, api_key=api_key)
|
|
138
|
+
encrypted_api_key = encrypt_api_key_with_paramiko_ssh_key_chacha20poly1305(ssh_key=selected_ssh_key, api_key=api_key)
|
|
140
139
|
print("OK!")
|
|
141
140
|
print(" * trying to decrypt the encrypted API key...", flush=True, end="")
|
|
142
|
-
decrypted_api_key =
|
|
141
|
+
decrypted_api_key = decrypt_api_key_with_paramiko_ssh_key_chacha20poly1305(encrypted_api_key_payload=encrypted_api_key)
|
|
143
142
|
if decrypted_api_key != api_key:
|
|
144
143
|
raise pylo.PyloEx("Decrypted API key does not match original API key")
|
|
145
144
|
print("OK!")
|
illumio_pylo/tmp.py
CHANGED
|
@@ -37,14 +37,33 @@ def find_connector_or_die(obj) -> 'pylo.APIConnector':
|
|
|
37
37
|
:param obj:
|
|
38
38
|
:return:
|
|
39
39
|
"""
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
|
|
41
|
+
connector = None
|
|
42
|
+
|
|
43
|
+
# check if object has a __dict__ attribute
|
|
44
|
+
if not hasattr(obj, '__dict__'):
|
|
45
|
+
# check if it's in __slots__
|
|
46
|
+
if hasattr(obj, '__slots__'):
|
|
47
|
+
if 'connector' in obj.__slots__:
|
|
48
|
+
connector = obj.__getattribute__('connector')
|
|
49
|
+
if connector is not None:
|
|
50
|
+
return connector
|
|
51
|
+
raise Exception("Could not find a Connector object")
|
|
52
|
+
if 'owner' in obj.__slots__:
|
|
53
|
+
owner = obj.__getattribute__('owner')
|
|
54
|
+
if owner is None:
|
|
55
|
+
raise Exception("Could not find a Connector object")
|
|
56
|
+
return find_connector_or_die(owner)
|
|
57
|
+
raise Exception("Could not find a Connector object")
|
|
58
|
+
else:
|
|
59
|
+
connector = obj.__dict__.get('connector') # type: pylo.APIConnector
|
|
60
|
+
if connector is None:
|
|
61
|
+
owner = obj.__dict__.get('owner')
|
|
62
|
+
if owner is None:
|
|
63
|
+
raise Exception("Could not find a Connector object")
|
|
64
|
+
return find_connector_or_die(owner)
|
|
65
|
+
|
|
66
|
+
return connector
|
|
48
67
|
|
|
49
68
|
|
|
50
69
|
class IDTranslationTable:
|
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
illumio_pylo/AgentStore.py,sha256=
|
|
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=XvvE__qMISOrfHxM18tuLCv_fVWe_d3eb1eck3cEFvQ,4443
|
|
4
|
+
illumio_pylo/IPMap.py,sha256=x8t4eeX0DDYRAoofjL7eeA9hkmQ6v7H0h7iRFHSye-w,10263
|
|
5
5
|
illumio_pylo/Label.py,sha256=sn6qNFo8Etdl0lUYRoSp_VC0mJymuFJpQ99x9vAwKSY,835
|
|
6
|
-
illumio_pylo/LabelCommon.py,sha256=
|
|
7
|
-
illumio_pylo/LabelGroup.py,sha256=
|
|
8
|
-
illumio_pylo/LabelStore.py,sha256=
|
|
9
|
-
illumio_pylo/LabeledObject.py,sha256=
|
|
10
|
-
illumio_pylo/Organization.py,sha256=
|
|
6
|
+
illumio_pylo/LabelCommon.py,sha256=MKdhxKKz6CTrAzI9f9YjtU_gf8G2QVprInNR_vCQ7OA,1551
|
|
7
|
+
illumio_pylo/LabelGroup.py,sha256=ZPC3xBLJUEhStyBTMB3fTTcEi8Z4CDjHUwnq_T-8p5Y,2674
|
|
8
|
+
illumio_pylo/LabelStore.py,sha256=bZjfCs4EZkY4SE5yI37_kshn24-DVhh2tn4YqS965OE,19917
|
|
9
|
+
illumio_pylo/LabeledObject.py,sha256=MsXoe3olAntxIvwAzXaPeOrnJQ_lHXIXAFNsB0lNBAk,2020
|
|
10
|
+
illumio_pylo/Organization.py,sha256=4IvTgJ27kFndBvwsWhcfZxuJ0PZvHH7pFGH4CMP83lE,12591
|
|
11
11
|
illumio_pylo/Query.py,sha256=lgLjst41ma3HMVkngvTjL7zSLjh80RoXYL5vS3PWO7Q,13330
|
|
12
12
|
illumio_pylo/ReferenceTracker.py,sha256=HyY0NwZwOdAzSXJrs6i6dhB_kgn1tidZL5LFLLkPuSM,1070
|
|
13
|
-
illumio_pylo/Rule.py,sha256=
|
|
14
|
-
illumio_pylo/Ruleset.py,sha256=
|
|
15
|
-
illumio_pylo/RulesetStore.py,sha256=
|
|
16
|
-
illumio_pylo/SecurityPrincipal.py,sha256=
|
|
17
|
-
illumio_pylo/Service.py,sha256=
|
|
18
|
-
illumio_pylo/SoftwareVersion.py,sha256=
|
|
19
|
-
illumio_pylo/VirtualService.py,sha256=
|
|
20
|
-
illumio_pylo/VirtualServiceStore.py,sha256=
|
|
21
|
-
illumio_pylo/Workload.py,sha256=
|
|
22
|
-
illumio_pylo/WorkloadStore.py,sha256=
|
|
23
|
-
illumio_pylo/WorkloadStoreSubClasses.py,sha256=
|
|
24
|
-
illumio_pylo/__init__.py,sha256=
|
|
25
|
-
illumio_pylo/tmp.py,sha256=
|
|
26
|
-
illumio_pylo/API/APIConnector.py,sha256=
|
|
13
|
+
illumio_pylo/Rule.py,sha256=LUMNyHtbOWF207DSuD1Dy_X4Oo6eD_VQ1uQA3jqEMmE,26827
|
|
14
|
+
illumio_pylo/Ruleset.py,sha256=c3mPoibfYroEtV4njBRux3R33772l2z8SDJnZcA_Jhc,11901
|
|
15
|
+
illumio_pylo/RulesetStore.py,sha256=KgTjE-TXIbvzjxusadijpMKY2ySX3DZAwOk3e4GChmk,3424
|
|
16
|
+
illumio_pylo/SecurityPrincipal.py,sha256=gASMxmNFDjfbfqJp0igmLeRpi03XLzGjbL-Ric_RGW4,2354
|
|
17
|
+
illumio_pylo/Service.py,sha256=qyUWvYFtTpJzZMVkppvxnBFFbeQf9bow_K3OBFiEdZ4,8523
|
|
18
|
+
illumio_pylo/SoftwareVersion.py,sha256=H_5WM42ObUkVtuxVWak30KMbEuar567k33E6pb83Zbo,4388
|
|
19
|
+
illumio_pylo/VirtualService.py,sha256=K1GT8pzkMOYkD4ZEwDkdriLOAUFAr0oCYNErJAMy9Ck,617
|
|
20
|
+
illumio_pylo/VirtualServiceStore.py,sha256=MNTwo1cvteUuID6JniWUk5oRHQHGY4OwrWvFaRXDuuk,3116
|
|
21
|
+
illumio_pylo/Workload.py,sha256=9kZHawayQQ_L-OBzyuuDcViWSa7HzDKEfPtcSHMsInw,19910
|
|
22
|
+
illumio_pylo/WorkloadStore.py,sha256=3C6SMU0wRlet6C6UVbjkYNsTY7vkyK_ZwqM1dlCBpsQ,10989
|
|
23
|
+
illumio_pylo/WorkloadStoreSubClasses.py,sha256=4GBb5sXan38Y5OE7O6aAR-IZrZJar0mYE44FbCSb3_k,6093
|
|
24
|
+
illumio_pylo/__init__.py,sha256=sMq1_pXxrK7ELnh7MG1KYAdqdcz4F-zq6b9GH5Y4rOA,4172
|
|
25
|
+
illumio_pylo/tmp.py,sha256=DYlm07YEP6Nm5qScByfTloGi7TGaN9WtklSqeVROPik,3913
|
|
26
|
+
illumio_pylo/API/APIConnector.py,sha256=pxHuaRvUU_sX_DWgE_TVMR5ktRURVMOVGhkBbuV--Sc,60725
|
|
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
|
|
29
|
+
illumio_pylo/API/CredentialsManager.py,sha256=-7c9_2VBJ_7zttBd6aa9K8YZ1iZmuQGAURVAy2jPopQ,12166
|
|
30
30
|
illumio_pylo/API/Explorer.py,sha256=fFAIF-67_uuKgJOP0eZPPJrOGuYmFl33GK75AyMjgJU,47590
|
|
31
31
|
illumio_pylo/API/JsonPayloadTypes.py,sha256=9gql3-tn3cu1qmpOD_JcPCX5b594eOKDgVhTqHu6CsQ,7984
|
|
32
32
|
illumio_pylo/API/RuleSearchQuery.py,sha256=O0-MsUXhwmywoO0G-GXnLq6kkVC9LgmxMZwqVKc_oJE,5325
|
|
@@ -38,7 +38,7 @@ illumio_pylo/cli/NativeParsers.py,sha256=nzDL54EV0J-Iz0P9EkeiPl6DWQBSbCu-MpEPRad
|
|
|
38
38
|
illumio_pylo/cli/__init__.py,sha256=UuZ2KamgIpvfYE1FXilm_THHAvXimdUcvGb3Jrbjfhc,7737
|
|
39
39
|
illumio_pylo/cli/__main__.py,sha256=ll1gK8k1YL_kPsImI7WVlw2sCyNyhocnuCqko6mGaYI,223
|
|
40
40
|
illumio_pylo/cli/commands/__init__.py,sha256=yoVkXy-qBGiAAziWiayJdjcclx1WTayShXSPqHelcWA,1489
|
|
41
|
-
illumio_pylo/cli/commands/credential_manager.py,sha256=
|
|
41
|
+
illumio_pylo/cli/commands/credential_manager.py,sha256=YHu8xb2ejOwt6FVkz6kfeP7mhhL85Vc4yU818iyE_3A,9638
|
|
42
42
|
illumio_pylo/cli/commands/iplist_analyzer.py,sha256=vOl6fNd0HrUKnKXtY1sj7jeyx2GtuDZENV7mF79O7yU,3714
|
|
43
43
|
illumio_pylo/cli/commands/iplist_import_from_file.py,sha256=XvC-GlJyjA4dDPzfvGoBFtwelI9g_rQqGzgKgqMYcsI,8284
|
|
44
44
|
illumio_pylo/cli/commands/ruleset_export.py,sha256=E64oYgGKI1Ry382DqV1gT4IlsLdd55QTqdInXlL9EPU,5896
|
|
@@ -65,8 +65,8 @@ illumio_pylo/utilities/resources/iplists-import-example.xlsx,sha256=VW-7CRr8NA2V
|
|
|
65
65
|
illumio_pylo/utilities/resources/workload-exporter-filter-example.csv,sha256=cn5IA8AGEPjvS-EsPXA_GJ-LFsdF9t_44rSzFTCmAzE,36
|
|
66
66
|
illumio_pylo/utilities/resources/workloads-import-example.csv,sha256=DEOGVikFjxQpMFFI0l0jb3hrxEEeZCpTGkmWkz6GUcY,91
|
|
67
67
|
illumio_pylo/utilities/resources/workloads-import-example.xlsx,sha256=U8Ac2BZidA6NlvBFAVPHqeY5zmg3rjmIAXp5b3b1P5w,17101
|
|
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.
|
|
68
|
+
illumio_pylo-0.3.6.dist-info/LICENSE,sha256=WYmcYJG1QFgu1hfo7qrEkZ3Jhcz8NUWe6XUraZvlIFs,10172
|
|
69
|
+
illumio_pylo-0.3.6.dist-info/METADATA,sha256=zvRaxKi6Y-1PCfsnM8H8xyd6oBeXw9cJKXG_ienAjTU,12224
|
|
70
|
+
illumio_pylo-0.3.6.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
71
|
+
illumio_pylo-0.3.6.dist-info/top_level.txt,sha256=c5cu_ZMuSuxjq48ih58Kc0Tr8-JdQtV8GrKJicvWNFE,13
|
|
72
|
+
illumio_pylo-0.3.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|