catocli 2.0.1__py3-none-any.whl → 2.0.3__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.
Potentially problematic release.
This version of catocli might be problematic. Click here for more details.
- catocli/Utils/clidriver.py +41 -6
- catocli/__init__.py +1 -1
- catocli/parsers/custom/__init__.py +7 -5
- catocli/parsers/custom/customLib.py +490 -1
- catocli/parsers/custom/export_rules/__init__.py +5 -1
- catocli/parsers/custom/export_rules/export_rules.py +32 -183
- catocli/parsers/custom/export_sites/__init__.py +20 -0
- catocli/parsers/custom/export_sites/export_sites.py +365 -0
- catocli/parsers/custom/import_rules_to_tf/__init__.py +3 -3
- catocli/parsers/custom/import_rules_to_tf/import_rules_to_tf.py +20 -146
- catocli/parsers/custom/import_sites_to_tf/__init__.py +45 -0
- catocli/parsers/custom/import_sites_to_tf/import_sites_to_tf.py +891 -0
- catocli/parsers/mutation_accountManagement/__init__.py +18 -21
- catocli/parsers/mutation_admin/__init__.py +18 -21
- catocli/parsers/mutation_container/__init__.py +6 -7
- catocli/parsers/mutation_hardware/__init__.py +6 -7
- catocli/parsers/mutation_policy/__init__.py +666 -588
- catocli/parsers/mutation_policy_terminalServer/README.md +7 -0
- catocli/parsers/mutation_policy_terminalServer_addRule/README.md +18 -0
- catocli/parsers/mutation_policy_terminalServer_addSection/README.md +18 -0
- catocli/parsers/mutation_policy_terminalServer_createPolicyRevision/README.md +18 -0
- catocli/parsers/mutation_policy_terminalServer_discardPolicyRevision/README.md +18 -0
- catocli/parsers/mutation_policy_terminalServer_moveRule/README.md +18 -0
- catocli/parsers/mutation_policy_terminalServer_moveSection/README.md +18 -0
- catocli/parsers/mutation_policy_terminalServer_publishPolicyRevision/README.md +18 -0
- catocli/parsers/mutation_policy_terminalServer_removeRule/README.md +18 -0
- catocli/parsers/mutation_policy_terminalServer_removeSection/README.md +18 -0
- catocli/parsers/mutation_policy_terminalServer_updatePolicy/README.md +18 -0
- catocli/parsers/mutation_policy_terminalServer_updateRule/README.md +18 -0
- catocli/parsers/mutation_policy_terminalServer_updateSection/README.md +18 -0
- catocli/parsers/mutation_sandbox/__init__.py +12 -14
- catocli/parsers/mutation_site/__init__.py +189 -175
- catocli/parsers/mutation_site_addSocketAddOnCard/README.md +17 -0
- catocli/parsers/mutation_site_removeSocketAddOnCard/README.md +17 -0
- catocli/parsers/mutation_site_startSiteUpgrade/README.md +17 -0
- catocli/parsers/mutation_sites/__init__.py +189 -175
- catocli/parsers/mutation_sites_addSocketAddOnCard/README.md +17 -0
- catocli/parsers/mutation_sites_removeSocketAddOnCard/README.md +17 -0
- catocli/parsers/mutation_sites_startSiteUpgrade/README.md +17 -0
- catocli/parsers/mutation_xdr/__init__.py +18 -21
- catocli/parsers/parserApiClient.py +36 -11
- catocli/parsers/query_accountBySubdomain/__init__.py +6 -7
- catocli/parsers/query_accountManagement/__init__.py +6 -7
- catocli/parsers/query_accountMetrics/__init__.py +6 -7
- catocli/parsers/query_accountRoles/__init__.py +6 -7
- catocli/parsers/query_accountSnapshot/__init__.py +6 -7
- catocli/parsers/query_admin/__init__.py +6 -7
- catocli/parsers/query_admins/__init__.py +6 -7
- catocli/parsers/query_appStats/__init__.py +6 -7
- catocli/parsers/query_appStatsTimeSeries/__init__.py +6 -7
- catocli/parsers/query_auditFeed/__init__.py +6 -7
- catocli/parsers/query_catalogs/__init__.py +6 -7
- catocli/parsers/query_container/__init__.py +6 -7
- catocli/parsers/query_devices/README.md +2 -1
- catocli/parsers/query_devices/__init__.py +6 -7
- catocli/parsers/query_entityLookup/__init__.py +6 -7
- catocli/parsers/query_events/__init__.py +6 -7
- catocli/parsers/query_eventsFeed/README.md +1 -1
- catocli/parsers/query_eventsFeed/__init__.py +6 -7
- catocli/parsers/query_eventsTimeSeries/__init__.py +6 -7
- catocli/parsers/query_hardware/__init__.py +6 -7
- catocli/parsers/query_hardwareManagement/__init__.py +6 -7
- catocli/parsers/query_licensing/__init__.py +6 -7
- catocli/parsers/query_policy/README.md +2 -1
- catocli/parsers/query_policy/__init__.py +6 -7
- catocli/parsers/query_sandbox/__init__.py +6 -7
- catocli/parsers/query_site/README.md +2 -1
- catocli/parsers/query_site/__init__.py +6 -7
- catocli/parsers/query_siteLocation/__init__.py +4 -8
- catocli/parsers/query_subDomains/__init__.py +6 -7
- catocli/parsers/query_xdr/__init__.py +12 -14
- catocli/parsers/raw/README.md +4 -0
- catocli/parsers/raw/__init__.py +5 -2
- {catocli-2.0.1.dist-info → catocli-2.0.3.dist-info}/METADATA +1 -1
- {catocli-2.0.1.dist-info → catocli-2.0.3.dist-info}/RECORD +108 -67
- graphql_client/api/call_api.py +12 -6
- models/mutation.policy.remotePortFwd.updateRule.json +6 -6
- models/mutation.policy.terminalServer.addRule.json +2403 -0
- models/mutation.policy.terminalServer.addSection.json +1358 -0
- models/mutation.policy.terminalServer.createPolicyRevision.json +1873 -0
- models/mutation.policy.terminalServer.discardPolicyRevision.json +1807 -0
- models/mutation.policy.terminalServer.moveRule.json +1605 -0
- models/mutation.policy.terminalServer.moveSection.json +1259 -0
- models/mutation.policy.terminalServer.publishPolicyRevision.json +1864 -0
- models/mutation.policy.terminalServer.removeRule.json +1253 -0
- models/mutation.policy.terminalServer.removeSection.json +958 -0
- models/mutation.policy.terminalServer.updatePolicy.json +1883 -0
- models/mutation.policy.terminalServer.updateRule.json +2096 -0
- models/mutation.policy.terminalServer.updateSection.json +1111 -0
- models/mutation.site.addSocketAddOnCard.json +1050 -0
- models/mutation.site.removeSocketAddOnCard.json +786 -0
- models/mutation.site.startSiteUpgrade.json +802 -0
- models/mutation.sites.addSocketAddOnCard.json +1050 -0
- models/mutation.sites.removeSocketAddOnCard.json +786 -0
- models/mutation.sites.startSiteUpgrade.json +802 -0
- models/query.devices.json +311 -2
- models/query.events.json +48 -0
- models/query.eventsFeed.json +12 -0
- models/query.eventsTimeSeries.json +36 -0
- models/query.licensing.json +21815 -10093
- models/query.policy.json +1898 -305
- models/query.site.json +225 -0
- models/query.siteLocation.json +97190 -295396
- schema/catolib.py +63 -30
- {catocli-2.0.1.dist-info → catocli-2.0.3.dist-info}/LICENSE +0 -0
- {catocli-2.0.1.dist-info → catocli-2.0.3.dist-info}/WHEEL +0 -0
- {catocli-2.0.1.dist-info → catocli-2.0.3.dist-info}/entry_points.txt +0 -0
- {catocli-2.0.1.dist-info → catocli-2.0.3.dist-info}/top_level.txt +0 -0
|
@@ -3,7 +3,7 @@ import json
|
|
|
3
3
|
import sys
|
|
4
4
|
from graphql_client.api.call_api import ApiClient, CallApi
|
|
5
5
|
from graphql_client.api_client import ApiException
|
|
6
|
-
|
|
6
|
+
from ..customLib import writeDataToFile, makeCall, getAccountID
|
|
7
7
|
|
|
8
8
|
def strip_ids_recursive(data):
|
|
9
9
|
"""Recursively strip id attributes from data structure, but only from objects that contain only 'id' and 'name' keys"""
|
|
@@ -37,40 +37,7 @@ def export_if_rules_to_json(args, configuration):
|
|
|
37
37
|
Adapted from scripts/export_if_rules_to_json.py
|
|
38
38
|
"""
|
|
39
39
|
try:
|
|
40
|
-
|
|
41
|
-
account_id = None
|
|
42
|
-
if hasattr(args, 'accountID') and args.accountID:
|
|
43
|
-
account_id = args.accountID
|
|
44
|
-
elif hasattr(configuration, 'accountID') and configuration.accountID:
|
|
45
|
-
account_id = configuration.accountID
|
|
46
|
-
else:
|
|
47
|
-
account_id = os.getenv('CATO_ACCOUNT_ID')
|
|
48
|
-
|
|
49
|
-
if not account_id:
|
|
50
|
-
raise ValueError("Account ID is required. Provide it using the -accountID flag or set CATO_ACCOUNT_ID environment variable.")
|
|
51
|
-
|
|
52
|
-
# Set up output file path
|
|
53
|
-
if hasattr(args, 'output_file_path') and args.output_file_path:
|
|
54
|
-
# Use output file path if provided
|
|
55
|
-
output_file = args.output_file_path
|
|
56
|
-
destination_dir = os.path.dirname(output_file)
|
|
57
|
-
if hasattr(args, 'verbose') and args.verbose:
|
|
58
|
-
print(f"Using output file path: {output_file}")
|
|
59
|
-
else:
|
|
60
|
-
# Use default path and filename
|
|
61
|
-
destination_dir = 'config_data'
|
|
62
|
-
json_output_file = f"all_ifw_rules_and_sections_{account_id}.json"
|
|
63
|
-
output_file = os.path.join(destination_dir, json_output_file)
|
|
64
|
-
if hasattr(args, 'verbose') and args.verbose:
|
|
65
|
-
print(f"Using default path: {output_file}")
|
|
66
|
-
|
|
67
|
-
# Create destination directory if it doesn't exist
|
|
68
|
-
if destination_dir and not os.path.exists(destination_dir):
|
|
69
|
-
if hasattr(args, 'verbose') and args.verbose:
|
|
70
|
-
print(f"Creating directory: {destination_dir}")
|
|
71
|
-
os.makedirs(destination_dir)
|
|
72
|
-
|
|
73
|
-
# Define the GraphQL query
|
|
40
|
+
account_id = getAccountID(args, configuration)
|
|
74
41
|
policy_query = {
|
|
75
42
|
"query": "query policy ( $accountId:ID! ) { policy ( accountId:$accountId ) { internetFirewall { policy { enabled rules { audit { updatedTime updatedBy } rule { id name description index section { id name } enabled source { ip host { id name } site { id name } subnet ipRange { from to } globalIpRange { id name } networkInterface { id name } siteNetworkSubnet { id name } floatingSubnet { id name } user { id name } usersGroup { id name } group { id name } systemGroup { id name } } connectionOrigin country { id name } device { id name } deviceOS deviceAttributes { category type model manufacturer os osVersion } destination { application { id name } customApp { id name } appCategory { id name } customCategory { id name } sanctionedAppsCategory { id name } country { id name } domain fqdn ip subnet ipRange { from to } globalIpRange { id name } remoteAsn containers { fqdnContainer { id name } ipAddressRangeContainer { id name } } } service { standard { id name } custom { port portRange { from to } protocol } } action tracking { event { enabled } alert { enabled frequency subscriptionGroup { id name } webhook { id name } mailingList { id name } } } schedule { activeOn customTimeframePolicySchedule: customTimeframe { from to } customRecurringPolicySchedule: customRecurring { from to days } } exceptions { name source { ip host { id name } site { id name } subnet ipRange { from to } globalIpRange { id name } networkInterface { id name } siteNetworkSubnet { id name } floatingSubnet { id name } user { id name } usersGroup { id name } group { id name } systemGroup { id name } } deviceOS country { id name } device { id name } deviceAttributes { category type model manufacturer os osVersion } destination { application { id name } customApp { id name } appCategory { id name } customCategory { id name } sanctionedAppsCategory { id name } country { id name } domain fqdn ip subnet ipRange { from to } globalIpRange { id name } remoteAsn containers { fqdnContainer { id name } ipAddressRangeContainer { id name } } } service { standard { id name } custom { port portRangeCustomService: portRange { from to } protocol } } connectionOrigin } } properties } sections { audit { updatedTime updatedBy } section { id name } properties } audit { publishedTime publishedBy } revision { id name description changes createdTime updatedTime } } } } }",
|
|
76
43
|
"variables": {
|
|
@@ -78,56 +45,7 @@ def export_if_rules_to_json(args, configuration):
|
|
|
78
45
|
},
|
|
79
46
|
"operationName": "policy"
|
|
80
47
|
}
|
|
81
|
-
|
|
82
|
-
# Create API client instance with params
|
|
83
|
-
instance = CallApi(ApiClient(configuration))
|
|
84
|
-
params = {
|
|
85
|
-
'v': hasattr(args, 'verbose') and args.verbose, # verbose mode
|
|
86
|
-
'f': 'json', # format
|
|
87
|
-
'p': False, # pretty print
|
|
88
|
-
't': False # test mode
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
try:
|
|
92
|
-
# Call the API directly
|
|
93
|
-
# NOTE: The API client (graphql_client/api_client_types.py lines 106-108)
|
|
94
|
-
# automatically prints error responses and exits on GraphQL errors.
|
|
95
|
-
# This means our custom error handling below may not be reached if there are GraphQL errors.
|
|
96
|
-
response = instance.call_api(policy_query, params)
|
|
97
|
-
all_ifw_rules = response[0] if response else {}
|
|
98
|
-
|
|
99
|
-
# Show raw API response in verbose mode
|
|
100
|
-
if hasattr(args, 'verbose') and args.verbose:
|
|
101
|
-
print("\n" + "=" * 80)
|
|
102
|
-
print("RAW API RESPONSE:")
|
|
103
|
-
print("=" * 80)
|
|
104
|
-
print(json.dumps(all_ifw_rules, indent=2))
|
|
105
|
-
print("=" * 80 + "\n")
|
|
106
|
-
|
|
107
|
-
# Check for GraphQL errors first (may not be reached due to API client behavior)
|
|
108
|
-
if 'errors' in all_ifw_rules:
|
|
109
|
-
error_messages = [error.get('message', 'Unknown error') for error in all_ifw_rules['errors']]
|
|
110
|
-
raise Exception(f"API returned errors: {', '.join(error_messages)}")
|
|
111
|
-
|
|
112
|
-
if not all_ifw_rules or 'data' not in all_ifw_rules:
|
|
113
|
-
raise ValueError("Failed to retrieve data from API")
|
|
114
|
-
|
|
115
|
-
except ApiException as e:
|
|
116
|
-
raise Exception(f"API call failed - {e}")
|
|
117
|
-
except Exception as e:
|
|
118
|
-
raise Exception(f"Unexpected error during API call - {e}")
|
|
119
|
-
|
|
120
|
-
# IMPORTANT: Preserve section IDs BEFORE stripping them
|
|
121
|
-
section_id_map = {}
|
|
122
|
-
section_to_start_after_id = None
|
|
123
|
-
sections_with_ids = all_ifw_rules['data']['policy']['internetFirewall']['policy']['sections']
|
|
124
|
-
for index, section_data in enumerate(sections_with_ids):
|
|
125
|
-
section_name = section_data['section']['name']
|
|
126
|
-
section_id = section_data['section']['id']
|
|
127
|
-
if index == 0:
|
|
128
|
-
section_to_start_after_id = section_id
|
|
129
|
-
else:
|
|
130
|
-
section_id_map[section_name] = section_id
|
|
48
|
+
all_ifw_rules = makeCall(args, configuration, policy_query)
|
|
131
49
|
|
|
132
50
|
# Processing data to strip id attributes
|
|
133
51
|
processed_data = strip_ids_recursive(all_ifw_rules)
|
|
@@ -173,26 +91,28 @@ def export_if_rules_to_json(args, configuration):
|
|
|
173
91
|
|
|
174
92
|
# Reformat sections array to have index, section_id and section_name structure
|
|
175
93
|
# Exclude the first section from export
|
|
94
|
+
sections_with_ids = all_ifw_rules['data']['policy']['internetFirewall']['policy']['sections']
|
|
176
95
|
processed_sections = []
|
|
177
|
-
for index, section_data in enumerate(
|
|
96
|
+
for index, section_data in enumerate(sections_with_ids):
|
|
97
|
+
# print("sections_with_ids",json.dumps(section_data, indent=2))
|
|
178
98
|
if index > 0: # Skip the first section (index 0)
|
|
179
99
|
processed_sections.append({
|
|
180
100
|
"section_index": index,
|
|
181
|
-
"section_name": section_data['section']['name']
|
|
101
|
+
"section_name": section_data['section']['name'],
|
|
102
|
+
"section_id": section_data['section']['id']
|
|
182
103
|
})
|
|
183
|
-
|
|
184
|
-
# Add preserved section IDs and section_to_start_after_id
|
|
185
|
-
processed_data['data']['policy']['internetFirewall']['policy']['section_ids'] = section_id_map
|
|
186
|
-
if section_to_start_after_id:
|
|
187
|
-
processed_data['data']['policy']['internetFirewall']['policy']['section_to_start_after_id'] = section_to_start_after_id
|
|
188
104
|
|
|
189
105
|
# Replace the original sections array with the reformatted one
|
|
190
106
|
processed_data['data']['policy']['internetFirewall']['policy']['sections'] = processed_sections
|
|
191
107
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
108
|
+
output_file = writeDataToFile(
|
|
109
|
+
data=processed_data,
|
|
110
|
+
args=args,
|
|
111
|
+
account_id=account_id,
|
|
112
|
+
default_filename_template="all_ifw_rules_and_sections_{account_id}.json",
|
|
113
|
+
default_directory="config_data"
|
|
114
|
+
)
|
|
115
|
+
|
|
196
116
|
return [{"success": True, "output_file": output_file, "account_id": account_id}]
|
|
197
117
|
|
|
198
118
|
except Exception as e:
|
|
@@ -206,40 +126,8 @@ def export_wf_rules_to_json(args, configuration):
|
|
|
206
126
|
Adapted from scripts/export_wf_rules_to_json.py
|
|
207
127
|
"""
|
|
208
128
|
try:
|
|
209
|
-
|
|
210
|
-
account_id = None
|
|
211
|
-
if hasattr(args, 'accountID') and args.accountID:
|
|
212
|
-
account_id = args.accountID
|
|
213
|
-
elif hasattr(configuration, 'accountID') and configuration.accountID:
|
|
214
|
-
account_id = configuration.accountID
|
|
215
|
-
else:
|
|
216
|
-
account_id = os.getenv('CATO_ACCOUNT_ID')
|
|
217
|
-
|
|
218
|
-
if not account_id:
|
|
219
|
-
raise ValueError("Account ID is required. Provide it using the -accountID flag or set CATO_ACCOUNT_ID environment variable.")
|
|
129
|
+
account_id = getAccountID(args, configuration)
|
|
220
130
|
|
|
221
|
-
# Set up output file path
|
|
222
|
-
if hasattr(args, 'output_file_path') and args.output_file_path:
|
|
223
|
-
# Use output file path if provided
|
|
224
|
-
output_file = args.output_file_path
|
|
225
|
-
destination_dir = os.path.dirname(output_file)
|
|
226
|
-
if hasattr(args, 'verbose') and args.verbose:
|
|
227
|
-
print(f"Using output file path: {output_file}")
|
|
228
|
-
else:
|
|
229
|
-
# Use default path and filename
|
|
230
|
-
destination_dir = 'config_data'
|
|
231
|
-
json_output_file = f"all_wf_rules_and_sections_{account_id}.json"
|
|
232
|
-
output_file = os.path.join(destination_dir, json_output_file)
|
|
233
|
-
if hasattr(args, 'verbose') and args.verbose:
|
|
234
|
-
print(f"Using default path: {output_file}")
|
|
235
|
-
|
|
236
|
-
# Create destination directory if it doesn't exist
|
|
237
|
-
if destination_dir and not os.path.exists(destination_dir):
|
|
238
|
-
if hasattr(args, 'verbose') and args.verbose:
|
|
239
|
-
print(f"Creating directory: {destination_dir}")
|
|
240
|
-
os.makedirs(destination_dir)
|
|
241
|
-
|
|
242
|
-
# Define the GraphQL query for WAN Firewall
|
|
243
131
|
policy_query = {
|
|
244
132
|
"query": "query policy ( $accountId:ID! ) { policy ( accountId:$accountId ) { wanFirewall { policy { enabled rules { audit { updatedTime updatedBy } rule { id name description index section { id name } enabled source { host { id name } site { id name } subnet ip ipRange { from to } globalIpRange { id name } networkInterface { id name } siteNetworkSubnet { id name } floatingSubnet { id name } user { id name } usersGroup { id name } group { id name } systemGroup { id name } } connectionOrigin country { id name } device { id name } deviceOS deviceAttributes { category type model manufacturer os osVersion } destination { host { id name } site { id name } subnet ip ipRange { from to } globalIpRange { id name } networkInterface { id name } siteNetworkSubnet { id name } floatingSubnet { id name } user { id name } usersGroup { id name } group { id name } systemGroup { id name } } application { application { id name } appCategory { id name } customApp { id name } customCategory { id name } sanctionedAppsCategory { id name } domain fqdn ip subnet ipRange { from to } globalIpRange { id name } } service { standard { id name } custom { port portRange { from to } protocol } } action tracking { event { enabled } alert { enabled frequency subscriptionGroup { id name } webhook { id name } mailingList { id name } } } schedule { activeOn customTimeframePolicySchedule: customTimeframe { from to } customRecurringPolicySchedule: customRecurring { from to days } } direction exceptions { name source { host { id name } site { id name } subnet ip ipRange { from to } globalIpRange { id name } networkInterface { id name } siteNetworkSubnet { id name } floatingSubnet { id name } user { id name } usersGroup { id name } group { id name } systemGroup { id name } } deviceOS destination { host { id name } site { id name } subnet ip ipRange { from to } globalIpRange { id name } networkInterface { id name } siteNetworkSubnet { id name } floatingSubnet { id name } user { id name } usersGroup { id name } group { id name } systemGroup { id name } } country { id name } device { id name } deviceAttributes { category type model manufacturer os osVersion } application { application { id name } appCategory { id name } customApp { id name } customCategory { id name } sanctionedAppsCategory { id name } domain fqdn ip subnet ipRange { from to } globalIpRange { id name } } service { standard { id name } custom { port portRangeCustomService: portRange { from to } protocol } } connectionOrigin direction } } properties } sections { audit { updatedTime updatedBy } section { id name } properties } audit { publishedTime publishedBy } revision { id name description changes createdTime updatedTime } } } } }",
|
|
245
133
|
"variables": {
|
|
@@ -247,51 +135,11 @@ def export_wf_rules_to_json(args, configuration):
|
|
|
247
135
|
},
|
|
248
136
|
"operationName": "policy"
|
|
249
137
|
}
|
|
250
|
-
|
|
251
|
-
# Create API client instance with params
|
|
252
|
-
instance = CallApi(ApiClient(configuration))
|
|
253
|
-
params = {
|
|
254
|
-
'v': hasattr(args, 'verbose') and args.verbose, # verbose mode
|
|
255
|
-
'f': 'json', # format
|
|
256
|
-
'p': False, # pretty print
|
|
257
|
-
't': False # test mode
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
try:
|
|
261
|
-
# Call the API directly
|
|
262
|
-
response = instance.call_api(policy_query, params)
|
|
263
|
-
all_wf_rules = response[0] if response else {}
|
|
264
|
-
|
|
265
|
-
# Show raw API response in verbose mode
|
|
266
|
-
if hasattr(args, 'verbose') and args.verbose:
|
|
267
|
-
print("\n" + "=" * 80)
|
|
268
|
-
print("RAW API RESPONSE:")
|
|
269
|
-
print("=" * 80)
|
|
270
|
-
print(json.dumps(all_wf_rules, indent=2))
|
|
271
|
-
print("=" * 80 + "\n")
|
|
272
|
-
|
|
273
|
-
# Check for GraphQL errors first
|
|
274
|
-
if 'errors' in all_wf_rules:
|
|
275
|
-
error_messages = [error.get('message', 'Unknown error') for error in all_wf_rules['errors']]
|
|
276
|
-
raise Exception(f"API returned errors: {', '.join(error_messages)}")
|
|
277
|
-
|
|
278
|
-
if not all_wf_rules or 'data' not in all_wf_rules:
|
|
279
|
-
raise ValueError("Failed to retrieve data from API")
|
|
138
|
+
all_wf_rules = makeCall(args, configuration, policy_query)
|
|
280
139
|
|
|
281
|
-
|
|
282
|
-
raise
|
|
283
|
-
except Exception as e:
|
|
284
|
-
raise Exception(f"Unexpected error during API call - {e}")
|
|
140
|
+
if not all_wf_rules or 'data' not in all_wf_rules:
|
|
141
|
+
raise ValueError("Failed to retrieve data from API")
|
|
285
142
|
|
|
286
|
-
# IMPORTANT: Preserve section IDs BEFORE stripping them
|
|
287
|
-
section_id_map = {}
|
|
288
|
-
section_to_start_after_id = None
|
|
289
|
-
sections_with_ids = all_wf_rules['data']['policy']['wanFirewall']['policy']['sections']
|
|
290
|
-
for index, section_data in enumerate(sections_with_ids):
|
|
291
|
-
section_name = section_data['section']['name']
|
|
292
|
-
section_id = section_data['section']['id']
|
|
293
|
-
section_id_map[section_name] = section_id
|
|
294
|
-
|
|
295
143
|
# Processing data to strip id attributes
|
|
296
144
|
processed_data = strip_ids_recursive(all_wf_rules)
|
|
297
145
|
|
|
@@ -335,24 +183,25 @@ def export_wf_rules_to_json(args, configuration):
|
|
|
335
183
|
|
|
336
184
|
# Reformat sections array to have index, section_id and section_name structure
|
|
337
185
|
# Exclude the first section from export
|
|
186
|
+
sections_with_ids = all_wf_rules['data']['policy']['wanFirewall']['policy']['sections']
|
|
338
187
|
processed_sections = []
|
|
339
|
-
for index, section_data in enumerate(
|
|
188
|
+
for index, section_data in enumerate(sections_with_ids):
|
|
340
189
|
processed_sections.append({
|
|
341
|
-
"section_index": index,
|
|
342
|
-
"section_name": section_data['section']['name']
|
|
190
|
+
"section_index": index+1,
|
|
191
|
+
"section_name": section_data['section']['name'],
|
|
192
|
+
"section_id": section_data['section']['id']
|
|
343
193
|
})
|
|
344
|
-
|
|
345
|
-
# Add preserved section IDs and section_to_start_after_id
|
|
346
|
-
processed_data['data']['policy']['wanFirewall']['policy']['section_ids'] = section_id_map
|
|
347
|
-
if section_to_start_after_id:
|
|
348
|
-
processed_data['data']['policy']['wanFirewall']['policy']['section_to_start_after_id'] = section_to_start_after_id
|
|
349
194
|
|
|
350
195
|
# Replace the original sections array with the reformatted one
|
|
351
196
|
processed_data['data']['policy']['wanFirewall']['policy']['sections'] = processed_sections
|
|
352
197
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
198
|
+
output_file = writeDataToFile(
|
|
199
|
+
data=processed_data,
|
|
200
|
+
args=args,
|
|
201
|
+
account_id=account_id,
|
|
202
|
+
default_filename_template="all_wf_rules_and_sections_{account_id}.json",
|
|
203
|
+
default_directory="config_data"
|
|
204
|
+
)
|
|
356
205
|
|
|
357
206
|
return [{"success": True, "output_file": output_file, "account_id": account_id}]
|
|
358
207
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import catocli.parsers.custom.export_sites.export_sites as export_sites
|
|
2
|
+
|
|
3
|
+
def export_sites_parse(subparsers):
|
|
4
|
+
"""Create export_sites command parsers"""
|
|
5
|
+
|
|
6
|
+
# Create the socket_sites parser (direct command, no subparsers)
|
|
7
|
+
socket_sites_parser = subparsers.add_parser(
|
|
8
|
+
'socket_sites',
|
|
9
|
+
help='Export consolidated site and socket data to JSON format',
|
|
10
|
+
usage='catocli export socket_sites [-accountID <account_id>] [options]'
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
socket_sites_parser.add_argument('-accountID', help='Account ID to export data from (uses CATO_ACCOUNT_ID environment variable if not specified)', required=False)
|
|
14
|
+
socket_sites_parser.add_argument('-siteIDs', help='Comma-separated list of site IDs to export (e.g., "132606,132964,133511")', required=False)
|
|
15
|
+
socket_sites_parser.add_argument('--output-file-path', help='Full path including filename and extension for output file. If not specified, uses default: config_data/socket_site_data_{account_id}.json')
|
|
16
|
+
socket_sites_parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
|
|
17
|
+
|
|
18
|
+
socket_sites_parser.set_defaults(func=export_sites.export_socket_site_to_json)
|
|
19
|
+
|
|
20
|
+
return socket_sites_parser
|