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,168 @@
|
|
|
1
|
+
from prettytable import PrettyTable
|
|
2
|
+
import argparse
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
import paramiko
|
|
6
|
+
|
|
7
|
+
import illumio_pylo as pylo
|
|
8
|
+
import click
|
|
9
|
+
from illumio_pylo.API.CredentialsManager import get_all_credentials, create_credential_in_file, CredentialFileEntry, \
|
|
10
|
+
create_credential_in_default_file, encrypt_api_key_with_paramiko_key, decrypt_api_key_with_paramiko_key
|
|
11
|
+
|
|
12
|
+
from illumio_pylo import log
|
|
13
|
+
from . import Command
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
command_name = "cred-manager"
|
|
17
|
+
objects_load_filter = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def fill_parser(parser: argparse.ArgumentParser):
|
|
21
|
+
sub_parser = parser.add_subparsers(dest='sub_command', required=True)
|
|
22
|
+
list_parser = sub_parser.add_parser('list', help='List all credentials')
|
|
23
|
+
create_parser = sub_parser.add_parser('create', help='Create a new credential')
|
|
24
|
+
|
|
25
|
+
create_parser.add_argument('--name', required=True, type=str,
|
|
26
|
+
help='Name of the credential')
|
|
27
|
+
create_parser.add_argument('--fqdn', required=True, type=str,
|
|
28
|
+
help='FQDN of the PCE')
|
|
29
|
+
create_parser.add_argument('--port', required=True, type=int,
|
|
30
|
+
help='Port of the PCE')
|
|
31
|
+
create_parser.add_argument('--org', required=True, type=int,
|
|
32
|
+
help='Organization ID')
|
|
33
|
+
create_parser.add_argument('--api-user', required=True, type=str,
|
|
34
|
+
help='API user')
|
|
35
|
+
create_parser.add_argument('--verify-ssl', required=True, type=bool,
|
|
36
|
+
help='Verify SSL')
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def __main(args, **kwargs):
|
|
40
|
+
if args['sub_command'] == 'list':
|
|
41
|
+
credentials = get_all_credentials()
|
|
42
|
+
# sort credentials by name
|
|
43
|
+
credentials.sort(key=lambda x: x.name)
|
|
44
|
+
|
|
45
|
+
# print credentials in a nice table
|
|
46
|
+
table_template = " {:<19} {:<40} {:<22} {:<25}"
|
|
47
|
+
print(table_template.format("Name", "URL", "API User", "Originating File"))
|
|
48
|
+
|
|
49
|
+
for credential in credentials:
|
|
50
|
+
print(table_template.format(credential.name,
|
|
51
|
+
credential.fqdn + ':' + str(credential.port),
|
|
52
|
+
credential.api_user,
|
|
53
|
+
credential.originating_file)
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
elif args['sub_command'] == 'create':
|
|
57
|
+
print("Recap:")
|
|
58
|
+
print("Name: {}".format(args['name']))
|
|
59
|
+
print("FQDN: {}".format(args['fqdn']))
|
|
60
|
+
print("Port: {}".format(args['port']))
|
|
61
|
+
print("Org ID: {}".format(args['org']))
|
|
62
|
+
print("API User: {}".format(args['api_user']))
|
|
63
|
+
print("Verify SSL: {}".format(args['verify_ssl']))
|
|
64
|
+
print()
|
|
65
|
+
|
|
66
|
+
print("* Checking if a credential with the same name already exists...", flush=True, end="")
|
|
67
|
+
credentials = get_all_credentials()
|
|
68
|
+
for credential in credentials:
|
|
69
|
+
if credential.name == args['name']:
|
|
70
|
+
raise pylo.PyloEx("A credential named '{}' already exists".format(args['name']))
|
|
71
|
+
print("OK!")
|
|
72
|
+
|
|
73
|
+
# prompt of API key from user input, single line, hidden
|
|
74
|
+
api_key = click.prompt('> API Key', hide_input=True)
|
|
75
|
+
|
|
76
|
+
credentials_data: CredentialFileEntry = {
|
|
77
|
+
"name": args['name'],
|
|
78
|
+
"fqdn": args['fqdn'],
|
|
79
|
+
"port": args['port'],
|
|
80
|
+
"org_id": args['org'],
|
|
81
|
+
"api_user": args['api_user'],
|
|
82
|
+
"verify_ssl": args['verify_ssl'],
|
|
83
|
+
"api_key": api_key
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
encrypt_api_key = click.prompt('> Encrypt API? Y/N', type=bool)
|
|
87
|
+
if encrypt_api_key:
|
|
88
|
+
print("Available keys (ECDSA NISTPXXX keys and a few others are not supported and will be filtered out):")
|
|
89
|
+
ssh_keys = paramiko.Agent().get_keys()
|
|
90
|
+
# filter out ECDSA NISTPXXX and sk-ssh-ed25519@openssh.com
|
|
91
|
+
ssh_keys = get_supported_keys_from_ssh_agent()
|
|
92
|
+
|
|
93
|
+
# display a table of keys
|
|
94
|
+
print_keys(keys=ssh_keys, display_index=True)
|
|
95
|
+
print()
|
|
96
|
+
|
|
97
|
+
index_of_selected_key = click.prompt('> Select key by ID#', type=click.IntRange(0, len(ssh_keys)-1))
|
|
98
|
+
selected_ssh_key = ssh_keys[index_of_selected_key]
|
|
99
|
+
print("Selected key: {} | {} | {}".format(selected_ssh_key.get_name(),
|
|
100
|
+
selected_ssh_key.get_fingerprint().hex(),
|
|
101
|
+
selected_ssh_key.comment))
|
|
102
|
+
print(" * encrypting API key with selected key (you may be prompted by your SSH agent for confirmation or PIN code) ...", flush=True, end="")
|
|
103
|
+
encrypted_api_key = encrypt_api_key_with_paramiko_key(ssh_key=selected_ssh_key, api_key=api_key)
|
|
104
|
+
print("OK!")
|
|
105
|
+
print(" * trying to decrypt the encrypted API key...", flush=True, end="")
|
|
106
|
+
decrypted_api_key = decrypt_api_key_with_paramiko_key(encrypted_api_key_payload=encrypted_api_key)
|
|
107
|
+
if decrypted_api_key != api_key:
|
|
108
|
+
raise pylo.PyloEx("Decrypted API key does not match original API key")
|
|
109
|
+
print("OK!")
|
|
110
|
+
credentials_data["api_key"] = encrypted_api_key
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
cwd = os.getcwd()
|
|
114
|
+
create_in_current_workdir = click.prompt('> Create in current workdir ({})? If not then user homedir will be used. Y/N '.format(cwd), type=bool)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
print("* Creating credential...", flush=True, end="")
|
|
118
|
+
if create_in_current_workdir:
|
|
119
|
+
file_path = create_credential_in_file(file_full_path=cwd, data=credentials_data)
|
|
120
|
+
else:
|
|
121
|
+
file_path = create_credential_in_default_file(data=credentials_data)
|
|
122
|
+
|
|
123
|
+
print("OK! ({})".format(file_path))
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
command_object = Command(command_name, __main, fill_parser, credentials_manager_mode=True)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def get_supported_keys_from_ssh_agent() -> list[paramiko.AgentKey]:
|
|
130
|
+
keys = paramiko.Agent().get_keys()
|
|
131
|
+
# filter out ECDSA NISTPXXX and sk-ssh-ed25519
|
|
132
|
+
# RSA and ED25519 keys are reported to be working
|
|
133
|
+
return [key for key in keys if not (key.get_name().startswith("ecdsa-sha2-nistp") or
|
|
134
|
+
key.get_name().startswith("sk-ssh-ed25519"))]
|
|
135
|
+
|
|
136
|
+
def print_keys(keys: list[paramiko.AgentKey], display_index = True) -> None:
|
|
137
|
+
|
|
138
|
+
args_for_print = []
|
|
139
|
+
|
|
140
|
+
column_properties = [ # (name, width)
|
|
141
|
+
("ID#", 4),
|
|
142
|
+
("Type", 20),
|
|
143
|
+
("Fingerprint", 40),
|
|
144
|
+
("Comment", 48)
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
if not display_index:
|
|
148
|
+
# remove tuple with name "ID#"
|
|
149
|
+
column_properties = [item for item in column_properties if item[0] != "ID#"]
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
table = PrettyTable()
|
|
153
|
+
table.field_names = [item[0] for item in column_properties]
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
for i, key in enumerate(keys):
|
|
157
|
+
display_values = []
|
|
158
|
+
if display_index:
|
|
159
|
+
display_values.append(i)
|
|
160
|
+
display_values.append(key.get_name())
|
|
161
|
+
display_values.append(key.get_fingerprint().hex())
|
|
162
|
+
display_values.append(key.comment)
|
|
163
|
+
|
|
164
|
+
table.add_row(display_values)
|
|
165
|
+
|
|
166
|
+
print(table)
|
|
167
|
+
|
|
168
|
+
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import illumio_pylo as pylo
|
|
2
|
+
import argparse
|
|
3
|
+
import sys
|
|
4
|
+
from .misc import make_filename_with_timestamp
|
|
5
|
+
from . import Command
|
|
6
|
+
|
|
7
|
+
command_name = 'iplist-import'
|
|
8
|
+
objects_load_filter = ['iplists']
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def fill_parser(parser: argparse.ArgumentParser):
|
|
12
|
+
parser.add_argument('--input-file', '-i', type=str, required=True,
|
|
13
|
+
help='CSV or Excel input filename')
|
|
14
|
+
parser.add_argument('--input-file-delimiter', type=str, required=False, default=',',
|
|
15
|
+
help='CSV field delimiter')
|
|
16
|
+
|
|
17
|
+
parser.add_argument('--ignore-if-iplist-exists', action='store_true',
|
|
18
|
+
help='If an IPList with same same exists, ignore CSV entry')
|
|
19
|
+
|
|
20
|
+
parser.add_argument('--network-delimiter', type=str, required=False, default=',', nargs='?', const=True,
|
|
21
|
+
help='If an IPList with same same exists, ignore CSV entry')
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def __main(args, org: pylo.Organization, **kwargs):
|
|
25
|
+
input_file = args['input_file']
|
|
26
|
+
input_file_delimiter = args['input_file_delimiter']
|
|
27
|
+
ignore_if_iplist_exists = args['ignore_if_iplist_exists']
|
|
28
|
+
network_delimiter = args['network_delimiter']
|
|
29
|
+
|
|
30
|
+
output_file_prefix = make_filename_with_timestamp('import-iplists-results_')
|
|
31
|
+
output_file_csv = output_file_prefix + '.csv'
|
|
32
|
+
output_file_excel = output_file_prefix + '.xlsx'
|
|
33
|
+
|
|
34
|
+
csv_expected_fields = [
|
|
35
|
+
{'name': 'name', 'optional': False},
|
|
36
|
+
{'name': 'description', 'optional': True},
|
|
37
|
+
{'name': 'networks', 'optional': False, 'type': 'array_of_strings'}
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
csv_created_fields = csv_expected_fields.copy()
|
|
41
|
+
csv_created_fields.append({'name': 'href'})
|
|
42
|
+
csv_created_fields.append({'name': '**not_created_reason**'})
|
|
43
|
+
|
|
44
|
+
pylo.file_clean(output_file_csv)
|
|
45
|
+
pylo.file_clean(output_file_excel)
|
|
46
|
+
|
|
47
|
+
print(" * Loading CSV input file '{}'...".format(input_file), flush=True, end='')
|
|
48
|
+
csv_data = pylo.CsvExcelToObject(input_file, expected_headers=csv_expected_fields, csv_delimiter=input_file_delimiter)
|
|
49
|
+
print('OK')
|
|
50
|
+
print(" - CSV has {} columns and {} lines (headers don't count)".format(csv_data.count_columns(), csv_data.count_lines()))
|
|
51
|
+
# print(pylo.nice_json(csv_data._objects))
|
|
52
|
+
|
|
53
|
+
print(" * Checking for iplist name collisions:", flush=True)
|
|
54
|
+
name_cache = {}
|
|
55
|
+
for iplist in org.IPListStore.items_by_href.values():
|
|
56
|
+
if iplist.name is not None and len(iplist.name) > 0:
|
|
57
|
+
lower_name = iplist.name.lower()
|
|
58
|
+
if lower_name not in name_cache:
|
|
59
|
+
name_cache[lower_name] = {'pce': True}
|
|
60
|
+
else:
|
|
61
|
+
print(" - Warning duplicate found in the PCE for IPList name: {}".format(iplist.name))
|
|
62
|
+
|
|
63
|
+
for csv_object in csv_data.objects():
|
|
64
|
+
if csv_object['name'] is not None and len(csv_object['name']) > 0:
|
|
65
|
+
lower_name = csv_object['name'].lower()
|
|
66
|
+
if lower_name not in name_cache:
|
|
67
|
+
name_cache[lower_name] = {'csv': True}
|
|
68
|
+
else:
|
|
69
|
+
if 'csv' in name_cache[lower_name]:
|
|
70
|
+
pylo.log.error('CSV contains iplists with duplicates name: {}'.format(lower_name))
|
|
71
|
+
sys.exit(1)
|
|
72
|
+
else:
|
|
73
|
+
csv_object['**not_created_reason**'] = 'Found duplicated name in PCE'
|
|
74
|
+
if not ignore_if_iplist_exists:
|
|
75
|
+
pylo.log.error("PCE contains iplists with duplicates name from CSV: '{}' at line #{}. Please fix CSV or look for --options to ignore it".format(lower_name, csv_object['*line*']))
|
|
76
|
+
sys.exit(1)
|
|
77
|
+
print(" - WARNING: CSV has an entry for iplist name '{}' at line #{} but it exists already in the PCE. It will be ignored.".format(lower_name, csv_object['*line*']))
|
|
78
|
+
|
|
79
|
+
del name_cache
|
|
80
|
+
print(" * DONE", flush=True)
|
|
81
|
+
|
|
82
|
+
# Listing objects to be created (filtering out inconsistent ones)
|
|
83
|
+
csv_objects_to_create = []
|
|
84
|
+
ignored_objects_count = 0
|
|
85
|
+
for csv_object in csv_data.objects():
|
|
86
|
+
if '**not_created_reason**' not in csv_object:
|
|
87
|
+
csv_objects_to_create.append(csv_object)
|
|
88
|
+
else:
|
|
89
|
+
ignored_objects_count += 1
|
|
90
|
+
|
|
91
|
+
print(' * Preparing Iplist JSON data...')
|
|
92
|
+
iplists_json_data = []
|
|
93
|
+
for data in csv_objects_to_create:
|
|
94
|
+
new_iplist = {}
|
|
95
|
+
iplists_json_data.append(new_iplist)
|
|
96
|
+
|
|
97
|
+
if len(data['name']) < 1:
|
|
98
|
+
raise pylo.PyloEx('Iplist at line #{} is missing a name in CSV'.format(data['*line*']))
|
|
99
|
+
else:
|
|
100
|
+
new_iplist['name'] = data['name']
|
|
101
|
+
|
|
102
|
+
if len(data['description']) > 0:
|
|
103
|
+
new_iplist['description'] = data['description']
|
|
104
|
+
|
|
105
|
+
if len(data['networks']) < 1:
|
|
106
|
+
print('Iplist at line #{} has empty networks list'.format(data['*line*']))
|
|
107
|
+
sys.exit(1)
|
|
108
|
+
|
|
109
|
+
network_delimiter = network_delimiter.replace("\\n", "\n")
|
|
110
|
+
ip_ranges = []
|
|
111
|
+
new_iplist['ip_ranges'] = ip_ranges
|
|
112
|
+
|
|
113
|
+
for network_string in data['networks'].rsplit(network_delimiter):
|
|
114
|
+
network_string = network_string.strip(" \r\n") # cleanup trailing characters
|
|
115
|
+
|
|
116
|
+
exclusion = False
|
|
117
|
+
if network_string.find('!') == 0:
|
|
118
|
+
exclusion = True
|
|
119
|
+
network_string = network_string[1:]
|
|
120
|
+
|
|
121
|
+
split_dash = network_string.split('-')
|
|
122
|
+
if len(split_dash) > 2:
|
|
123
|
+
pylo.log.error('Iplist at line #{} has invalid network entry: {}'.format(data['*line*'], network_string))
|
|
124
|
+
sys.exit(1)
|
|
125
|
+
if len(split_dash) == 2:
|
|
126
|
+
ip_ranges.append({'from_ip': split_dash[0], 'to_ip': split_dash[1], 'exclusion': exclusion})
|
|
127
|
+
continue
|
|
128
|
+
|
|
129
|
+
split_slash = network_string.split('/')
|
|
130
|
+
if len(split_slash) > 2:
|
|
131
|
+
pylo.log.error('Iplist at line #{} has invalid network entry: {}'.format(data['*line*'], network_string))
|
|
132
|
+
sys.exit(1)
|
|
133
|
+
if len(split_slash) == 2:
|
|
134
|
+
if len(split_slash[1]) > 2:
|
|
135
|
+
pylo.log.error('Iplist at line #{} has invalid network mask in CIDR {}'.format(data['*line*'], network_string))
|
|
136
|
+
sys.exit(1)
|
|
137
|
+
ip_ranges.append({'from_ip': split_slash[0]+'/'+split_slash[1], 'exclusion': exclusion})
|
|
138
|
+
continue
|
|
139
|
+
else:
|
|
140
|
+
is_ip4 = pylo.is_valid_ipv4(network_string)
|
|
141
|
+
is_ip6 = pylo.is_valid_ipv6(network_string)
|
|
142
|
+
|
|
143
|
+
if not is_ip4 and not is_ip6:
|
|
144
|
+
pylo.log.error('Iplist at line #{} has invalid address format: {}'.format(data['*line*'], network_string))
|
|
145
|
+
sys.exit(1)
|
|
146
|
+
ip_ranges.append({'from_ip': network_string, 'exclusion': exclusion})
|
|
147
|
+
continue
|
|
148
|
+
|
|
149
|
+
if len(ip_ranges) == 0:
|
|
150
|
+
pylo.log.error('Iplist at line #{} has no network entry'.format(data['*line*']))
|
|
151
|
+
sys.exit(1)
|
|
152
|
+
|
|
153
|
+
print(" - iplist '{}' extracted with {} with networks".format(new_iplist['name'], len(new_iplist['ip_ranges'])))
|
|
154
|
+
# print(new_iplist)
|
|
155
|
+
|
|
156
|
+
print(" * DONE")
|
|
157
|
+
|
|
158
|
+
print(" * Creating {} IPLists".format(len(iplists_json_data)))
|
|
159
|
+
total_created_count = 0
|
|
160
|
+
total_failed_count = 0
|
|
161
|
+
|
|
162
|
+
for index in range(0, len(iplists_json_data)):
|
|
163
|
+
json_blob = iplists_json_data[index]
|
|
164
|
+
print(" - Pushing new iplist '{}' to PCE (#{} of {})... ".format(json_blob['name'], index+1, len(iplists_json_data)), end='', flush=True)
|
|
165
|
+
result = org.connector.objects_iplist_create(json_blob)
|
|
166
|
+
print("OK")
|
|
167
|
+
|
|
168
|
+
href = result.get('href')
|
|
169
|
+
if href is None:
|
|
170
|
+
raise pylo.PyloEx('API returned unexpected response which is missing a HREF:', result)
|
|
171
|
+
|
|
172
|
+
total_created_count += 1
|
|
173
|
+
csv_objects_to_create[index]['href'] = href
|
|
174
|
+
|
|
175
|
+
csv_data.save_to_csv(output_file_csv, csv_created_fields)
|
|
176
|
+
csv_data.save_to_excel(output_file_excel, csv_created_fields)
|
|
177
|
+
|
|
178
|
+
csv_data.save_to_csv(output_file_csv, csv_created_fields)
|
|
179
|
+
csv_data.save_to_excel(output_file_excel, csv_created_fields)
|
|
180
|
+
|
|
181
|
+
print(" * DONE - {} created with success, {} failures and {} ignored. A report was created in {} and {}".format(total_created_count, total_failed_count, ignored_objects_count, output_file_csv, output_file_excel))
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
command_object = Command(command_name, __main, fill_parser, load_specific_objects_only=objects_load_filter)
|
|
185
|
+
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import os
|
|
3
|
+
from typing import Dict, List
|
|
4
|
+
|
|
5
|
+
import illumio_pylo as pylo
|
|
6
|
+
from .misc import make_filename_with_timestamp
|
|
7
|
+
from . import Command
|
|
8
|
+
|
|
9
|
+
command_name = 'rule-export'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def fill_parser(parser: argparse.ArgumentParser):
|
|
13
|
+
parser.add_argument('--format', '-f', required=False, default='excel',choices=['csv', 'excel'], help='Output file format')
|
|
14
|
+
parser.add_argument('--output', '-o', required=False, default='.', help='Directory where to save the output file')
|
|
15
|
+
parser.add_argument('--prefix-objects-with-type', nargs='?', const=True, default=False,
|
|
16
|
+
help='Prefix objects with their type (e.g. "label:mylabel")')
|
|
17
|
+
parser.add_argument('--object-types-as-section', action='store_true', default=False,
|
|
18
|
+
help="Consumer and providers will show objects types section headers, example:" + os.linesep +
|
|
19
|
+
"LABELS: " + os.linesep +
|
|
20
|
+
"R-WEB" + os.linesep +
|
|
21
|
+
"A-FUSION" + os.linesep +
|
|
22
|
+
"IPLISTS: " + os.linesep +
|
|
23
|
+
"Private_Networks" + os.linesep +
|
|
24
|
+
"Public_NATed")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def __main(options: Dict, org: pylo.Organization, **kwargs):
|
|
29
|
+
csv_report_headers: List[pylo.ExcelHeader] = \
|
|
30
|
+
[{'name': 'ruleset', 'max_width': 40},
|
|
31
|
+
{'name': 'scope', 'max_width': 50},
|
|
32
|
+
{'name': 'type', 'max_width': 10},
|
|
33
|
+
{'name': 'consumers', 'max_width': 80},
|
|
34
|
+
{'name': 'providers', 'max_width': 80},
|
|
35
|
+
{'name': 'services', 'max_width': 30},
|
|
36
|
+
{'name': 'options', 'max_width': 40},
|
|
37
|
+
{'name': 'ruleset_url', 'max_width': 40, 'wrap_text': False},
|
|
38
|
+
{'name': 'ruleset_href', 'max_width': 30, 'wrap_text': False}
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
setting_prefix_objects_with_type: bool|str = options['prefix_objects_with_type']
|
|
42
|
+
if setting_prefix_objects_with_type is False:
|
|
43
|
+
print(" * Prefix for object types are disabled")
|
|
44
|
+
else:
|
|
45
|
+
print(" * Prefix for object types are enabled")
|
|
46
|
+
|
|
47
|
+
setting_object_types_as_section: bool = options['prefix_objects_with_type']
|
|
48
|
+
if setting_object_types_as_section is False:
|
|
49
|
+
print(" * Object types as section are disabled")
|
|
50
|
+
else:
|
|
51
|
+
print(" * Object types as section are enabled")
|
|
52
|
+
|
|
53
|
+
output_file_format = options.get('format')
|
|
54
|
+
if output_file_format == "excel":
|
|
55
|
+
output_file_extension = ".xlsx"
|
|
56
|
+
elif output_file_format == "csv":
|
|
57
|
+
output_file_extension = ".csv"
|
|
58
|
+
else:
|
|
59
|
+
raise Exception("Unknown output file format: %s" % output_file_format)
|
|
60
|
+
|
|
61
|
+
output_file_name = options.get('output') + os.sep + make_filename_with_timestamp('rule_export_') + output_file_extension
|
|
62
|
+
output_file_name = os.path.abspath(output_file_name)
|
|
63
|
+
|
|
64
|
+
csv_report = pylo.ArraysToExcel()
|
|
65
|
+
sheet = csv_report.create_sheet('rulesets', csv_report_headers, force_all_wrap_text=True, multivalues_cell_delimiter=',')
|
|
66
|
+
|
|
67
|
+
for ruleset in org.RulesetStore.rulesets:
|
|
68
|
+
for rule in ruleset.rules_ordered_by_type:
|
|
69
|
+
rule_options = []
|
|
70
|
+
if not rule.enabled:
|
|
71
|
+
rule_options.append('disabled')
|
|
72
|
+
if rule.secure_connect:
|
|
73
|
+
rule_options.append('secure-connect')
|
|
74
|
+
if rule.stateless:
|
|
75
|
+
rule_options.append('stateless')
|
|
76
|
+
if rule.machine_auth:
|
|
77
|
+
rule_options.append('machine_auth')
|
|
78
|
+
|
|
79
|
+
scope_str = ''
|
|
80
|
+
for scope in ruleset.scopes.scope_entries.values():
|
|
81
|
+
if len(scope_str) > 0:
|
|
82
|
+
scope_str += "\n"
|
|
83
|
+
if scope.is_all_all_all():
|
|
84
|
+
scope_str += "*ALL LABELS*"
|
|
85
|
+
continue
|
|
86
|
+
for label in scope.labels_sorted_by_type:
|
|
87
|
+
scope_str += f"{label.name}\n"
|
|
88
|
+
# remove last \n from scope
|
|
89
|
+
if scope_str[-1] == "\n":
|
|
90
|
+
scope_str = scope_str[:-1]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
consumers_str = rule.consumers.members_to_str("\n", prefix_objects_with_type=setting_prefix_objects_with_type,
|
|
94
|
+
object_types_as_section=setting_object_types_as_section)
|
|
95
|
+
providers_str = rule.providers.members_to_str("\n", prefix_objects_with_type=setting_prefix_objects_with_type,
|
|
96
|
+
object_types_as_section=setting_object_types_as_section)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
data = {'ruleset': ruleset.name, 'scope': scope_str,
|
|
100
|
+
'consumers': consumers_str,
|
|
101
|
+
'providers': providers_str,
|
|
102
|
+
'services': rule.services.members_to_str("\n"),
|
|
103
|
+
'options': pylo.string_list_to_text(rule_options, "\n"),
|
|
104
|
+
'ruleset_href': ruleset.href,
|
|
105
|
+
'ruleset_url': ruleset.get_ruleset_url()}
|
|
106
|
+
if rule.is_extra_scope():
|
|
107
|
+
data['type'] = 'extra'
|
|
108
|
+
else:
|
|
109
|
+
data['type'] = 'intra'
|
|
110
|
+
sheet.add_line_from_object(data)
|
|
111
|
+
|
|
112
|
+
if output_file_format == "csv":
|
|
113
|
+
print(" * Writing export file '{}' ... ".format(output_file_name), end='', flush=True)
|
|
114
|
+
sheet.write_to_csv(output_file_name)
|
|
115
|
+
print("DONE")
|
|
116
|
+
elif output_file_format == "excel":
|
|
117
|
+
print(" * Writing export file '{}' ... ".format(output_file_name), end='', flush=True)
|
|
118
|
+
csv_report.write_to_excel(output_file_name)
|
|
119
|
+
print("DONE")
|
|
120
|
+
else:
|
|
121
|
+
raise pylo.PyloEx("Unknown format: '{}'".format(options['format']))
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
command_object = Command(command_name, __main, fill_parser)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import argparse
|
|
3
|
+
import illumio_pylo as pylo
|
|
4
|
+
import os
|
|
5
|
+
import datetime
|
|
6
|
+
import json
|
|
7
|
+
|
|
8
|
+
from illumio_pylo import log
|
|
9
|
+
from . import Command
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
command_name = "pce-objects-cache-updater"
|
|
13
|
+
objects_load_filter = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def fill_parser(parser: argparse.ArgumentParser):
|
|
17
|
+
parser.add_argument('--include-deleted-workloads', action='store_true',
|
|
18
|
+
help='should deleted workloads be downloaded as well')
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def __main(args, org: pylo.Organization = None, connector: pylo.APIConnector = None, config_data=None, **kwargs):
|
|
22
|
+
|
|
23
|
+
# filename should be like 'cache_xxx.yyy.zzz.json'
|
|
24
|
+
filename = 'cache_' + connector.name + '.json'
|
|
25
|
+
|
|
26
|
+
timestamp = datetime.datetime.now(datetime.timezone.utc)
|
|
27
|
+
|
|
28
|
+
json_content = {'generation_date': timestamp.isoformat(),
|
|
29
|
+
'pce_version': connector.get_software_version_string(),
|
|
30
|
+
'data': config_data,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
with open(filename, 'w') as outfile:
|
|
34
|
+
json.dump(json_content, outfile)
|
|
35
|
+
|
|
36
|
+
size = os.path.getsize(filename)
|
|
37
|
+
|
|
38
|
+
print("\nPCE objects and settings were saved to file '%s' with a size of %iKB" % (filename, int(size/1024)))
|
|
39
|
+
|
|
40
|
+
print()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
command_object = Command(command_name, __main, fill_parser, skip_pce_config_loading=True)
|
|
44
|
+
|