catocli 1.0.21__py3-none-any.whl → 2.0.0__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 +112 -25
- catocli/Utils/profile_manager.py +188 -0
- catocli/Utils/version_checker.py +192 -0
- catocli/__init__.py +1 -1
- catocli/parsers/configure/__init__.py +115 -0
- catocli/parsers/configure/configure.py +307 -0
- catocli/parsers/custom/__init__.py +8 -0
- catocli/parsers/custom/export_rules/__init__.py +36 -0
- catocli/parsers/custom/export_rules/export_rules.py +361 -0
- catocli/parsers/custom/import_rules_to_tf/__init__.py +58 -0
- catocli/parsers/custom/import_rules_to_tf/import_rules_to_tf.py +577 -0
- catocli/parsers/mutation_admin_addAdmin/README.md +1 -1
- catocli/parsers/mutation_hardware/README.md +7 -0
- catocli/parsers/mutation_hardware/__init__.py +23 -0
- catocli/parsers/mutation_hardware_updateHardwareShipping/README.md +17 -0
- catocli/parsers/mutation_site_addBgpPeer/README.md +1 -1
- catocli/parsers/mutation_site_addNetworkRange/README.md +1 -1
- catocli/parsers/mutation_site_updateBgpPeer/README.md +1 -1
- catocli/parsers/mutation_site_updateNetworkRange/README.md +1 -1
- catocli/parsers/mutation_sites_addBgpPeer/README.md +1 -1
- catocli/parsers/mutation_sites_addNetworkRange/README.md +1 -1
- catocli/parsers/mutation_sites_updateBgpPeer/README.md +1 -1
- catocli/parsers/mutation_sites_updateNetworkRange/README.md +1 -1
- catocli/parsers/query_auditFeed/README.md +1 -1
- catocli/parsers/query_catalogs/README.md +19 -0
- catocli/parsers/query_catalogs/__init__.py +17 -0
- catocli/parsers/query_devices/README.md +19 -0
- catocli/parsers/query_devices/__init__.py +17 -0
- catocli/parsers/query_eventsFeed/README.md +1 -1
- catocli/parsers/query_hardware/README.md +17 -0
- catocli/parsers/query_hardware/__init__.py +17 -0
- catocli/parsers/query_sandbox/README.md +1 -1
- {catocli-1.0.21.dist-info → catocli-2.0.0.dist-info}/METADATA +1 -1
- {catocli-1.0.21.dist-info → catocli-2.0.0.dist-info}/RECORD +139 -114
- {catocli-1.0.21.dist-info → catocli-2.0.0.dist-info}/top_level.txt +1 -0
- graphql_client/api/call_api.py +4 -0
- graphql_client/api_client_types.py +4 -3
- graphql_client/configuration.py +2 -0
- models/mutation.admin.addAdmin.json +130 -0
- models/mutation.hardware.updateHardwareShipping.json +2506 -0
- models/mutation.policy.appTenantRestriction.addRule.json +11 -11
- models/mutation.policy.appTenantRestriction.createPolicyRevision.json +11 -11
- models/mutation.policy.appTenantRestriction.discardPolicyRevision.json +11 -11
- models/mutation.policy.appTenantRestriction.moveRule.json +11 -11
- models/mutation.policy.appTenantRestriction.publishPolicyRevision.json +11 -11
- models/mutation.policy.appTenantRestriction.removeRule.json +11 -11
- models/mutation.policy.appTenantRestriction.updatePolicy.json +11 -11
- models/mutation.policy.appTenantRestriction.updateRule.json +11 -11
- models/mutation.policy.dynamicIpAllocation.addRule.json +4 -4
- models/mutation.policy.dynamicIpAllocation.createPolicyRevision.json +4 -4
- models/mutation.policy.dynamicIpAllocation.discardPolicyRevision.json +4 -4
- models/mutation.policy.dynamicIpAllocation.moveRule.json +4 -4
- models/mutation.policy.dynamicIpAllocation.publishPolicyRevision.json +4 -4
- models/mutation.policy.dynamicIpAllocation.removeRule.json +4 -4
- models/mutation.policy.dynamicIpAllocation.updatePolicy.json +4 -4
- models/mutation.policy.dynamicIpAllocation.updateRule.json +4 -4
- models/mutation.policy.internetFirewall.addRule.json +63 -63
- models/mutation.policy.internetFirewall.createPolicyRevision.json +45 -45
- models/mutation.policy.internetFirewall.discardPolicyRevision.json +45 -45
- models/mutation.policy.internetFirewall.moveRule.json +45 -45
- models/mutation.policy.internetFirewall.publishPolicyRevision.json +45 -45
- models/mutation.policy.internetFirewall.removeRule.json +45 -45
- models/mutation.policy.internetFirewall.updatePolicy.json +45 -45
- models/mutation.policy.internetFirewall.updateRule.json +63 -63
- models/mutation.policy.remotePortFwd.addRule.json +5 -5
- models/mutation.policy.remotePortFwd.createPolicyRevision.json +5 -5
- models/mutation.policy.remotePortFwd.discardPolicyRevision.json +5 -5
- models/mutation.policy.remotePortFwd.moveRule.json +5 -5
- models/mutation.policy.remotePortFwd.publishPolicyRevision.json +5 -5
- models/mutation.policy.remotePortFwd.removeRule.json +5 -5
- models/mutation.policy.remotePortFwd.updatePolicy.json +5 -5
- models/mutation.policy.remotePortFwd.updateRule.json +5 -5
- models/mutation.policy.socketLan.addRule.json +3580 -125
- models/mutation.policy.socketLan.createPolicyRevision.json +3580 -125
- models/mutation.policy.socketLan.discardPolicyRevision.json +3580 -125
- models/mutation.policy.socketLan.moveRule.json +3580 -125
- models/mutation.policy.socketLan.publishPolicyRevision.json +3580 -125
- models/mutation.policy.socketLan.removeRule.json +3580 -125
- models/mutation.policy.socketLan.updatePolicy.json +3580 -125
- models/mutation.policy.socketLan.updateRule.json +3580 -125
- models/mutation.policy.wanFirewall.addRule.json +77 -77
- models/mutation.policy.wanFirewall.createPolicyRevision.json +59 -59
- models/mutation.policy.wanFirewall.discardPolicyRevision.json +59 -59
- models/mutation.policy.wanFirewall.moveRule.json +59 -59
- models/mutation.policy.wanFirewall.publishPolicyRevision.json +59 -59
- models/mutation.policy.wanFirewall.removeRule.json +59 -59
- models/mutation.policy.wanFirewall.updatePolicy.json +59 -59
- models/mutation.policy.wanFirewall.updateRule.json +77 -77
- models/mutation.policy.wanNetwork.addRule.json +49 -49
- models/mutation.policy.wanNetwork.createPolicyRevision.json +49 -49
- models/mutation.policy.wanNetwork.discardPolicyRevision.json +49 -49
- models/mutation.policy.wanNetwork.moveRule.json +49 -49
- models/mutation.policy.wanNetwork.publishPolicyRevision.json +49 -49
- models/mutation.policy.wanNetwork.removeRule.json +49 -49
- models/mutation.policy.wanNetwork.updatePolicy.json +49 -49
- models/mutation.policy.wanNetwork.updateRule.json +49 -49
- models/mutation.site.addBgpPeer.json +2812 -217
- models/mutation.site.addNetworkRange.json +114 -0
- models/mutation.site.addSocketSite.json +18 -0
- models/mutation.site.removeBgpPeer.json +667 -1
- models/mutation.site.updateBgpPeer.json +3152 -559
- models/mutation.site.updateNetworkRange.json +114 -0
- models/mutation.sites.addBgpPeer.json +2812 -217
- models/mutation.sites.addNetworkRange.json +114 -0
- models/mutation.sites.addSocketSite.json +18 -0
- models/mutation.sites.removeBgpPeer.json +667 -1
- models/mutation.sites.updateBgpPeer.json +3152 -559
- models/mutation.sites.updateNetworkRange.json +114 -0
- models/mutation.xdr.addStoryComment.json +2 -2
- models/mutation.xdr.analystFeedback.json +182 -42
- models/mutation.xdr.deleteStoryComment.json +2 -2
- models/query.accountMetrics.json +112 -0
- models/query.accountSnapshot.json +62 -0
- models/query.admin.json +46 -0
- models/query.admins.json +46 -0
- models/query.appStats.json +528 -0
- models/query.appStatsTimeSeries.json +396 -0
- models/query.auditFeed.json +273 -3336
- models/query.catalogs.json +9840 -0
- models/query.devices.json +15469 -0
- models/query.events.json +4606 -4318
- models/query.eventsFeed.json +1167 -1095
- models/query.eventsTimeSeries.json +3459 -3243
- models/query.hardware.json +5730 -0
- models/query.hardwareManagement.json +8 -2
- models/query.licensing.json +3 -3
- models/query.policy.json +3743 -298
- models/query.sandbox.json +6 -4
- models/query.site.json +1329 -4
- models/query.xdr.stories.json +182 -42
- models/query.xdr.story.json +182 -42
- schema/catolib.py +105 -28
- scripts/catolib.py +62 -0
- scripts/export_if_rules_to_json.py +188 -0
- scripts/export_wf_rules_to_json.py +111 -0
- scripts/import_wf_rules_to_tfstate.py +331 -0
- {catocli-1.0.21.dist-info → catocli-2.0.0.dist-info}/LICENSE +0 -0
- {catocli-1.0.21.dist-info → catocli-2.0.0.dist-info}/WHEEL +0 -0
- {catocli-1.0.21.dist-info → catocli-2.0.0.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Direct Terraform Import Script using Python
|
|
4
|
+
Imports firewall rules and sections directly using subprocess calls to terraform import
|
|
5
|
+
Reads from JSON structure exported from Cato API
|
|
6
|
+
Adapted from scripts/import_if_rules_to_tfstate.py for CLI usage
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import subprocess
|
|
11
|
+
import sys
|
|
12
|
+
import re
|
|
13
|
+
import time
|
|
14
|
+
import glob
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def load_json_data(json_file):
|
|
19
|
+
"""Load firewall data from JSON file"""
|
|
20
|
+
try:
|
|
21
|
+
with open(json_file, 'r') as f:
|
|
22
|
+
data = json.load(f)
|
|
23
|
+
return data['data']['policy']['internetFirewall']['policy']
|
|
24
|
+
except FileNotFoundError:
|
|
25
|
+
print(f"Error: JSON file '{json_file}' not found")
|
|
26
|
+
sys.exit(1)
|
|
27
|
+
except json.JSONDecodeError as e:
|
|
28
|
+
print(f"Error: Invalid JSON in '{json_file}': {e}")
|
|
29
|
+
sys.exit(1)
|
|
30
|
+
except KeyError as e:
|
|
31
|
+
print(f"Error: Expected JSON structure not found in '{json_file}': {e}")
|
|
32
|
+
sys.exit(1)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def sanitize_name_for_terraform(name):
|
|
36
|
+
"""Sanitize rule/section name to create valid Terraform resource key"""
|
|
37
|
+
# Replace spaces and special characters with underscores
|
|
38
|
+
sanitized = re.sub(r'[^a-zA-Z0-9_-]', '_', name)
|
|
39
|
+
# Remove multiple consecutive underscores
|
|
40
|
+
sanitized = re.sub(r'_+', '_', sanitized)
|
|
41
|
+
# Remove leading/trailing underscores
|
|
42
|
+
sanitized = sanitized.strip('_')
|
|
43
|
+
return sanitized
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def extract_rules_and_sections(policy_data):
|
|
47
|
+
"""Extract rules and sections from the policy data"""
|
|
48
|
+
rules = []
|
|
49
|
+
sections = []
|
|
50
|
+
|
|
51
|
+
# Extract rules
|
|
52
|
+
for rule_entry in policy_data.get('rules', []):
|
|
53
|
+
rule = rule_entry.get('rule', {})
|
|
54
|
+
if rule.get('id') and rule.get('name'):
|
|
55
|
+
rules.append({
|
|
56
|
+
'id': rule['id'],
|
|
57
|
+
'name': rule['name'],
|
|
58
|
+
'index': rule.get('index', 0),
|
|
59
|
+
'section_name': rule.get('section', {}).get('name', 'Default')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
# Extract sections
|
|
63
|
+
section_ids = policy_data.get('section_ids', {})
|
|
64
|
+
for section in policy_data.get('sections', []):
|
|
65
|
+
if section.get('section_name'):
|
|
66
|
+
sections.append({
|
|
67
|
+
'section_name': section['section_name'],
|
|
68
|
+
'section_index': section.get('section_index', 0),
|
|
69
|
+
'section_id': section_ids.get(section['section_name'], '')
|
|
70
|
+
})
|
|
71
|
+
return rules, sections
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def run_terraform_import(resource_address, resource_id, timeout=60, verbose=False):
|
|
75
|
+
"""
|
|
76
|
+
Run a single terraform import command
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
resource_address: The terraform resource address
|
|
80
|
+
resource_id: The actual resource ID to import
|
|
81
|
+
timeout: Command timeout in seconds
|
|
82
|
+
verbose: Whether to show verbose output
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
tuple: (success: bool, output: str, error: str)
|
|
86
|
+
"""
|
|
87
|
+
cmd = ['terraform', 'import', resource_address, resource_id]
|
|
88
|
+
if verbose:
|
|
89
|
+
print(f"Command: {' '.join(cmd)}")
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
print(f"Importing: {resource_address} <- {resource_id}")
|
|
93
|
+
|
|
94
|
+
result = subprocess.run(
|
|
95
|
+
cmd,
|
|
96
|
+
capture_output=True,
|
|
97
|
+
text=True,
|
|
98
|
+
timeout=timeout,
|
|
99
|
+
cwd=Path.cwd()
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
if result.returncode == 0:
|
|
103
|
+
print(f"Success: {resource_address}")
|
|
104
|
+
return True, result.stdout, result.stderr
|
|
105
|
+
else:
|
|
106
|
+
print(f"Failed: {resource_address}")
|
|
107
|
+
print(f"Error: {result.stderr}")
|
|
108
|
+
return False, result.stdout, result.stderr
|
|
109
|
+
|
|
110
|
+
except subprocess.TimeoutExpired:
|
|
111
|
+
print(f"Timeout: {resource_address} (exceeded {timeout}s)")
|
|
112
|
+
return False, "", f"Command timed out after {timeout} seconds"
|
|
113
|
+
except Exception as e:
|
|
114
|
+
print(f"Unexpected error for {resource_address}: {e}")
|
|
115
|
+
return False, "", str(e)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def find_rule_index(rules, rule_name):
|
|
119
|
+
"""Find rule index by name."""
|
|
120
|
+
for index, rule in enumerate(rules):
|
|
121
|
+
if rule['name'] == rule_name:
|
|
122
|
+
return index
|
|
123
|
+
return None
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def import_sections(sections, module_name, verbose=False,
|
|
127
|
+
resource_type="cato_if_section", resource_name="sections"):
|
|
128
|
+
"""Import all sections"""
|
|
129
|
+
print("\nStarting section imports...")
|
|
130
|
+
total_sections = len(sections)
|
|
131
|
+
successful_imports = 0
|
|
132
|
+
failed_imports = 0
|
|
133
|
+
|
|
134
|
+
for i, section in enumerate(sections):
|
|
135
|
+
section_id = section['section_id']
|
|
136
|
+
section_name = section['section_name']
|
|
137
|
+
section_index = section['section_index']
|
|
138
|
+
resource_address = f'{module_name}.{resource_type}.{resource_name}["{str(section_index)}"]'
|
|
139
|
+
print(f"\n[{i+1}/{total_sections}] Section: {section_name} (index: {section_index})")
|
|
140
|
+
|
|
141
|
+
# For sections, we use the section name as the ID since that's how Cato identifies them
|
|
142
|
+
success, stdout, stderr = run_terraform_import(resource_address, section_id, verbose=verbose)
|
|
143
|
+
|
|
144
|
+
if success:
|
|
145
|
+
successful_imports += 1
|
|
146
|
+
else:
|
|
147
|
+
failed_imports += 1
|
|
148
|
+
|
|
149
|
+
print(f"\nSection Import Summary: {successful_imports} successful, {failed_imports} failed")
|
|
150
|
+
return successful_imports, failed_imports
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def import_rules(rules, module_name, verbose=False,
|
|
154
|
+
resource_type="cato_if_rule", resource_name="rules",
|
|
155
|
+
batch_size=10, delay_between_batches=2, auto_approve=False):
|
|
156
|
+
"""Import all rules in batches"""
|
|
157
|
+
print("\nStarting rule imports...")
|
|
158
|
+
successful_imports = 0
|
|
159
|
+
failed_imports = 0
|
|
160
|
+
total_rules = len(rules)
|
|
161
|
+
|
|
162
|
+
for i, rule in enumerate(rules):
|
|
163
|
+
rule_id = rule['id']
|
|
164
|
+
rule_name = rule['name']
|
|
165
|
+
rule_index = find_rule_index(rules, rule_name)
|
|
166
|
+
terraform_key = sanitize_name_for_terraform(rule_name)
|
|
167
|
+
|
|
168
|
+
# Use array index syntax instead of rule ID
|
|
169
|
+
resource_address = f'{module_name}.{resource_type}.{resource_name}["{str(rule_index)}"]'
|
|
170
|
+
print(f"\n[{i+1}/{total_rules}] Rule: {rule_name} (index: {rule_index})")
|
|
171
|
+
|
|
172
|
+
success, stdout, stderr = run_terraform_import(resource_address, rule_id, verbose=verbose)
|
|
173
|
+
|
|
174
|
+
if success:
|
|
175
|
+
successful_imports += 1
|
|
176
|
+
else:
|
|
177
|
+
failed_imports += 1
|
|
178
|
+
|
|
179
|
+
# Ask user if they want to continue on failure (unless auto-approved)
|
|
180
|
+
if failed_imports <= 3 and not auto_approve: # Only prompt for first few failures
|
|
181
|
+
response = input(f"\nContinue with remaining imports? (y/n): ").lower()
|
|
182
|
+
if response == 'n':
|
|
183
|
+
print("Import process stopped by user.")
|
|
184
|
+
break
|
|
185
|
+
|
|
186
|
+
# Delay between batches
|
|
187
|
+
if (i + 1) % batch_size == 0 and i < total_rules - 1:
|
|
188
|
+
print(f"\n Batch complete. Waiting {delay_between_batches}s before next batch...")
|
|
189
|
+
time.sleep(delay_between_batches)
|
|
190
|
+
|
|
191
|
+
print(f"\n Rule Import Summary: {successful_imports} successful, {failed_imports} failed")
|
|
192
|
+
return successful_imports, failed_imports
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def check_terraform_binary():
|
|
196
|
+
"""Check if terraform binary is available"""
|
|
197
|
+
try:
|
|
198
|
+
result = subprocess.run(['terraform', '--version'], capture_output=True, text=True)
|
|
199
|
+
if result.returncode == 0:
|
|
200
|
+
return True, result.stdout.strip().split('\n')[0]
|
|
201
|
+
else:
|
|
202
|
+
return False, "Terraform binary not found or not working"
|
|
203
|
+
except FileNotFoundError:
|
|
204
|
+
return False, "Terraform binary not found in PATH"
|
|
205
|
+
except Exception as e:
|
|
206
|
+
return False, f"Error checking terraform binary: {e}"
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def check_terraform_config_files():
|
|
210
|
+
"""Check if Terraform configuration files exist in current directory"""
|
|
211
|
+
tf_files = glob.glob('*.tf') + glob.glob('*.tf.json')
|
|
212
|
+
if tf_files:
|
|
213
|
+
return True, tf_files
|
|
214
|
+
else:
|
|
215
|
+
return False, []
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def check_terraform_init():
|
|
219
|
+
"""Check if Terraform has been initialized"""
|
|
220
|
+
terraform_dir = Path('.terraform')
|
|
221
|
+
if terraform_dir.exists() and terraform_dir.is_dir():
|
|
222
|
+
# Check for providers
|
|
223
|
+
providers_dir = terraform_dir / 'providers'
|
|
224
|
+
if providers_dir.exists():
|
|
225
|
+
return True, "Terraform is initialized"
|
|
226
|
+
else:
|
|
227
|
+
return False, "Terraform directory exists but no providers found"
|
|
228
|
+
else:
|
|
229
|
+
return False, "Terraform not initialized (.terraform directory not found)"
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def check_module_exists(module_name):
|
|
233
|
+
"""Check if the specified module exists in Terraform configuration"""
|
|
234
|
+
try:
|
|
235
|
+
# Remove 'module.' prefix if present
|
|
236
|
+
clean_module_name = module_name.replace('module.', '')
|
|
237
|
+
|
|
238
|
+
# Method 1: Check .tf files directly for module definitions
|
|
239
|
+
tf_files = glob.glob('*.tf') + glob.glob('*.tf.json')
|
|
240
|
+
for tf_file in tf_files:
|
|
241
|
+
try:
|
|
242
|
+
with open(tf_file, 'r') as f:
|
|
243
|
+
content = f.read()
|
|
244
|
+
# Look for module "module_name" blocks
|
|
245
|
+
if f'module "{clean_module_name}"' in content or f"module '{clean_module_name}'" in content:
|
|
246
|
+
return True, f"Module '{clean_module_name}' found in {tf_file}"
|
|
247
|
+
except Exception as e:
|
|
248
|
+
print(f"Warning: Could not read {tf_file}: {e}")
|
|
249
|
+
continue
|
|
250
|
+
|
|
251
|
+
# Method 2: Try terraform show -json as fallback
|
|
252
|
+
try:
|
|
253
|
+
result = subprocess.run(
|
|
254
|
+
['terraform', 'show', '-json'],
|
|
255
|
+
capture_output=True,
|
|
256
|
+
text=True,
|
|
257
|
+
cwd=Path.cwd()
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
if result.returncode == 0:
|
|
261
|
+
state_data = json.loads(result.stdout)
|
|
262
|
+
|
|
263
|
+
# Check if module exists in configuration
|
|
264
|
+
if 'configuration' in state_data and state_data['configuration']:
|
|
265
|
+
modules = state_data.get('configuration', {}).get('root_module', {}).get('module_calls', {})
|
|
266
|
+
if clean_module_name in modules:
|
|
267
|
+
return True, f"Module '{clean_module_name}' found in Terraform state"
|
|
268
|
+
|
|
269
|
+
# Also check in planned_values for modules
|
|
270
|
+
if 'planned_values' in state_data and state_data['planned_values']:
|
|
271
|
+
modules = state_data.get('planned_values', {}).get('root_module', {}).get('child_modules', [])
|
|
272
|
+
for module in modules:
|
|
273
|
+
module_addr = module.get('address', '')
|
|
274
|
+
if clean_module_name in module_addr:
|
|
275
|
+
return True, f"Module '{clean_module_name}' found in planned values"
|
|
276
|
+
except (subprocess.SubprocessError, json.JSONDecodeError) as e:
|
|
277
|
+
print(f"Warning: Could not check terraform state: {e}")
|
|
278
|
+
|
|
279
|
+
return False, f"Module '{clean_module_name}' not found in Terraform configuration files"
|
|
280
|
+
|
|
281
|
+
except Exception as e:
|
|
282
|
+
return False, f"Error checking module existence: {e}"
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def validate_terraform_environment(module_name, verbose=False):
|
|
286
|
+
"""Validate the complete Terraform environment"""
|
|
287
|
+
print("\n Validating Terraform environment...")
|
|
288
|
+
|
|
289
|
+
# 1. Check terraform binary
|
|
290
|
+
print("\n Checking Terraform binary...")
|
|
291
|
+
has_terraform, terraform_msg = check_terraform_binary()
|
|
292
|
+
if not has_terraform:
|
|
293
|
+
raise Exception(f" Terraform not available: {terraform_msg}")
|
|
294
|
+
if verbose:
|
|
295
|
+
print(f" {terraform_msg}")
|
|
296
|
+
else:
|
|
297
|
+
print(" Terraform binary found")
|
|
298
|
+
|
|
299
|
+
# 2. Check for configuration files
|
|
300
|
+
print("\n Checking Terraform configuration files...")
|
|
301
|
+
has_config, config_files = check_terraform_config_files()
|
|
302
|
+
if not has_config:
|
|
303
|
+
raise Exception(" No Terraform configuration files (.tf or .tf.json) found in current directory")
|
|
304
|
+
if verbose:
|
|
305
|
+
print(f" Found {len(config_files)} configuration files: {', '.join(config_files)}")
|
|
306
|
+
else:
|
|
307
|
+
print(f" Found {len(config_files)} Terraform configuration files")
|
|
308
|
+
|
|
309
|
+
# 3. Check if terraform is initialized
|
|
310
|
+
print("\n Checking Terraform initialization...")
|
|
311
|
+
is_initialized, init_msg = check_terraform_init()
|
|
312
|
+
if not is_initialized:
|
|
313
|
+
raise Exception(f" {init_msg}. Run 'terraform init' first.")
|
|
314
|
+
if verbose:
|
|
315
|
+
print(f" {init_msg}")
|
|
316
|
+
else:
|
|
317
|
+
print(" Terraform is initialized")
|
|
318
|
+
|
|
319
|
+
# 4. Check if the specified module exists
|
|
320
|
+
print(f"\n Checking if module '{module_name}' exists...")
|
|
321
|
+
module_exists, module_msg = check_module_exists(module_name)
|
|
322
|
+
if not module_exists:
|
|
323
|
+
raise Exception(f" {module_msg}. Please add the module to your Terraform configuration first.")
|
|
324
|
+
if verbose:
|
|
325
|
+
print(f" {module_msg}")
|
|
326
|
+
else:
|
|
327
|
+
print(f" Module '{module_name}' found")
|
|
328
|
+
|
|
329
|
+
print("\n All Terraform environment checks passed!")
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def import_if_rules_to_tf(args, configuration):
|
|
333
|
+
"""Main function to orchestrate the import process"""
|
|
334
|
+
try:
|
|
335
|
+
print(" Terraform Import Tool - Cato IFW Rules & Sections")
|
|
336
|
+
print("=" * 60)
|
|
337
|
+
|
|
338
|
+
# Load data
|
|
339
|
+
print(f" Loading data from {args.json_file}...")
|
|
340
|
+
policy_data = load_json_data(args.json_file)
|
|
341
|
+
|
|
342
|
+
# Extract rules and sections
|
|
343
|
+
rules, sections = extract_rules_and_sections(policy_data)
|
|
344
|
+
|
|
345
|
+
if hasattr(args, 'verbose') and args.verbose:
|
|
346
|
+
print(f"section_ids: {json.dumps(policy_data.get('section_ids', {}), indent=2)}")
|
|
347
|
+
|
|
348
|
+
print(f" Found {len(rules)} rules")
|
|
349
|
+
print(f" Found {len(sections)} sections")
|
|
350
|
+
|
|
351
|
+
if not rules and not sections:
|
|
352
|
+
print(" No rules or sections found. Exiting.")
|
|
353
|
+
return [{"success": False, "error": "No rules or sections found"}]
|
|
354
|
+
|
|
355
|
+
# Validate Terraform environment before proceeding
|
|
356
|
+
validate_terraform_environment(args.module_name, verbose=args.verbose)
|
|
357
|
+
|
|
358
|
+
# Ask for confirmation (unless auto-approved)
|
|
359
|
+
if not args.rules_only and not args.sections_only:
|
|
360
|
+
print(f"\n Ready to import {len(sections)} sections and {len(rules)} rules.")
|
|
361
|
+
elif args.rules_only:
|
|
362
|
+
print(f"\n Ready to import {len(rules)} rules only.")
|
|
363
|
+
elif args.sections_only:
|
|
364
|
+
print(f"\n Ready to import {len(sections)} sections only.")
|
|
365
|
+
|
|
366
|
+
if hasattr(args, 'auto_approve') and args.auto_approve:
|
|
367
|
+
print("\nAuto-approve enabled, proceeding with import...")
|
|
368
|
+
else:
|
|
369
|
+
confirm = input(f"\nProceed with import? (y/n): ").lower()
|
|
370
|
+
if confirm != 'y':
|
|
371
|
+
print("Import cancelled.")
|
|
372
|
+
return [{"success": False, "error": "Import cancelled by user"}]
|
|
373
|
+
|
|
374
|
+
total_successful = 0
|
|
375
|
+
total_failed = 0
|
|
376
|
+
|
|
377
|
+
# Import sections first (if not skipped)
|
|
378
|
+
if not args.rules_only and sections:
|
|
379
|
+
successful, failed = import_sections(sections, module_name=args.module_name, verbose=args.verbose)
|
|
380
|
+
total_successful += successful
|
|
381
|
+
total_failed += failed
|
|
382
|
+
|
|
383
|
+
# Import rules (if not skipped)
|
|
384
|
+
if not args.sections_only and rules:
|
|
385
|
+
successful, failed = import_rules(rules, module_name=args.module_name,
|
|
386
|
+
verbose=args.verbose, batch_size=args.batch_size,
|
|
387
|
+
delay_between_batches=args.delay,
|
|
388
|
+
auto_approve=getattr(args, 'auto_approve', False))
|
|
389
|
+
total_successful += successful
|
|
390
|
+
total_failed += failed
|
|
391
|
+
|
|
392
|
+
# Final summary
|
|
393
|
+
print("\n" + "=" * 60)
|
|
394
|
+
print(" FINAL IMPORT SUMMARY")
|
|
395
|
+
print("=" * 60)
|
|
396
|
+
print(f" Total successful imports: {total_successful}")
|
|
397
|
+
print(f" Total failed imports: {total_failed}")
|
|
398
|
+
print(f" Overall success rate: {(total_successful / (total_successful + total_failed) * 100):.1f}%" if (total_successful + total_failed) > 0 else "N/A")
|
|
399
|
+
print("\n Import process completed!")
|
|
400
|
+
|
|
401
|
+
return [{
|
|
402
|
+
"success": True,
|
|
403
|
+
"total_successful": total_successful,
|
|
404
|
+
"total_failed": total_failed,
|
|
405
|
+
"module_name": args.module_name
|
|
406
|
+
}]
|
|
407
|
+
|
|
408
|
+
except Exception as e:
|
|
409
|
+
print(f"ERROR: {str(e)}")
|
|
410
|
+
return [{"success": False, "error": str(e)}]
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def load_wf_json_data(json_file):
|
|
414
|
+
"""Load WAN Firewall data from JSON file"""
|
|
415
|
+
try:
|
|
416
|
+
with open(json_file, 'r') as f:
|
|
417
|
+
data = json.load(f)
|
|
418
|
+
return data['data']['policy']['wanFirewall']['policy']
|
|
419
|
+
except FileNotFoundError:
|
|
420
|
+
print(f"Error: JSON file '{json_file}' not found")
|
|
421
|
+
sys.exit(1)
|
|
422
|
+
except json.JSONDecodeError as e:
|
|
423
|
+
print(f"Error: Invalid JSON in '{json_file}': {e}")
|
|
424
|
+
sys.exit(1)
|
|
425
|
+
except KeyError as e:
|
|
426
|
+
print(f"Error: Expected JSON structure not found in '{json_file}': {e}")
|
|
427
|
+
sys.exit(1)
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def import_wf_sections(sections, module_name, verbose=False,
|
|
431
|
+
resource_type="cato_wf_section", resource_name="sections"):
|
|
432
|
+
"""Import all WAN Firewall sections"""
|
|
433
|
+
print("\nStarting WAN Firewall section imports...")
|
|
434
|
+
total_sections = len(sections)
|
|
435
|
+
successful_imports = 0
|
|
436
|
+
failed_imports = 0
|
|
437
|
+
|
|
438
|
+
for i, section in enumerate(sections):
|
|
439
|
+
section_id = section['section_id']
|
|
440
|
+
section_name = section['section_name']
|
|
441
|
+
section_index = section['section_index']
|
|
442
|
+
resource_address = f'{module_name}.{resource_type}.{resource_name}["{str(section_index)}"]'
|
|
443
|
+
print(f"\n[{i+1}/{total_sections}] Section: {section_name} (index: {section_index})")
|
|
444
|
+
|
|
445
|
+
# For sections, we use the section name as the ID since that's how Cato identifies them
|
|
446
|
+
success, stdout, stderr = run_terraform_import(resource_address, section_id, verbose=verbose)
|
|
447
|
+
|
|
448
|
+
if success:
|
|
449
|
+
successful_imports += 1
|
|
450
|
+
else:
|
|
451
|
+
failed_imports += 1
|
|
452
|
+
|
|
453
|
+
print(f"\nWAN Firewall Section Import Summary: {successful_imports} successful, {failed_imports} failed")
|
|
454
|
+
return successful_imports, failed_imports
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
def import_wf_rules(rules, module_name, verbose=False,
|
|
458
|
+
resource_type="cato_wf_rule", resource_name="rules",
|
|
459
|
+
batch_size=10, delay_between_batches=2, auto_approve=False):
|
|
460
|
+
"""Import all WAN Firewall rules in batches"""
|
|
461
|
+
print("\nStarting WAN Firewall rule imports...")
|
|
462
|
+
successful_imports = 0
|
|
463
|
+
failed_imports = 0
|
|
464
|
+
total_rules = len(rules)
|
|
465
|
+
|
|
466
|
+
for i, rule in enumerate(rules):
|
|
467
|
+
rule_id = rule['id']
|
|
468
|
+
rule_name = rule['name']
|
|
469
|
+
rule_index = find_rule_index(rules, rule_name)
|
|
470
|
+
terraform_key = sanitize_name_for_terraform(rule_name)
|
|
471
|
+
|
|
472
|
+
# Use array index syntax instead of rule ID
|
|
473
|
+
resource_address = f'{module_name}.{resource_type}.{resource_name}["{str(rule_index)}"]'
|
|
474
|
+
print(f"\n[{i+1}/{total_rules}] Rule: {rule_name} (index: {rule_index})")
|
|
475
|
+
|
|
476
|
+
success, stdout, stderr = run_terraform_import(resource_address, rule_id, verbose=verbose)
|
|
477
|
+
|
|
478
|
+
if success:
|
|
479
|
+
successful_imports += 1
|
|
480
|
+
else:
|
|
481
|
+
failed_imports += 1
|
|
482
|
+
|
|
483
|
+
# Ask user if they want to continue on failure (unless auto-approved)
|
|
484
|
+
if failed_imports <= 3 and not auto_approve: # Only prompt for first few failures
|
|
485
|
+
response = input(f"\nContinue with remaining imports? (y/n): ").lower()
|
|
486
|
+
if response == 'n':
|
|
487
|
+
print("Import process stopped by user.")
|
|
488
|
+
break
|
|
489
|
+
|
|
490
|
+
# Delay between batches
|
|
491
|
+
if (i + 1) % batch_size == 0 and i < total_rules - 1:
|
|
492
|
+
print(f"\n Batch complete. Waiting {delay_between_batches}s before next batch...")
|
|
493
|
+
time.sleep(delay_between_batches)
|
|
494
|
+
|
|
495
|
+
print(f"\nWAN Firewall Rule Import Summary: {successful_imports} successful, {failed_imports} failed")
|
|
496
|
+
return successful_imports, failed_imports
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
def import_wf_rules_to_tf(args, configuration):
|
|
500
|
+
"""Main function to orchestrate the WAN Firewall import process"""
|
|
501
|
+
try:
|
|
502
|
+
print(" Terraform Import Tool - Cato WF Rules & Sections")
|
|
503
|
+
print("=" * 60)
|
|
504
|
+
|
|
505
|
+
# Load data
|
|
506
|
+
print(f" Loading data from {args.json_file}...")
|
|
507
|
+
policy_data = load_wf_json_data(args.json_file)
|
|
508
|
+
|
|
509
|
+
# Extract rules and sections
|
|
510
|
+
rules, sections = extract_rules_and_sections(policy_data)
|
|
511
|
+
|
|
512
|
+
if hasattr(args, 'verbose') and args.verbose:
|
|
513
|
+
print(f"section_ids: {json.dumps(policy_data.get('section_ids', {}), indent=2)}")
|
|
514
|
+
|
|
515
|
+
print(f" Found {len(rules)} rules")
|
|
516
|
+
print(f" Found {len(sections)} sections")
|
|
517
|
+
|
|
518
|
+
if not rules and not sections:
|
|
519
|
+
print(" No rules or sections found. Exiting.")
|
|
520
|
+
return [{"success": False, "error": "No rules or sections found"}]
|
|
521
|
+
|
|
522
|
+
# Validate Terraform environment before proceeding
|
|
523
|
+
validate_terraform_environment(args.module_name, verbose=args.verbose)
|
|
524
|
+
|
|
525
|
+
# Ask for confirmation (unless auto-approved)
|
|
526
|
+
if not args.rules_only and not args.sections_only:
|
|
527
|
+
print(f"\n Ready to import {len(sections)} sections and {len(rules)} rules.")
|
|
528
|
+
elif args.rules_only:
|
|
529
|
+
print(f"\n Ready to import {len(rules)} rules only.")
|
|
530
|
+
elif args.sections_only:
|
|
531
|
+
print(f"\n Ready to import {len(sections)} sections only.")
|
|
532
|
+
|
|
533
|
+
if hasattr(args, 'auto_approve') and args.auto_approve:
|
|
534
|
+
print("\nAuto-approve enabled, proceeding with import...")
|
|
535
|
+
else:
|
|
536
|
+
confirm = input(f"\nProceed with import? (y/n): ").lower()
|
|
537
|
+
if confirm != 'y':
|
|
538
|
+
print("Import cancelled.")
|
|
539
|
+
return [{"success": False, "error": "Import cancelled by user"}]
|
|
540
|
+
|
|
541
|
+
total_successful = 0
|
|
542
|
+
total_failed = 0
|
|
543
|
+
|
|
544
|
+
# Import sections first (if not skipped)
|
|
545
|
+
if not args.rules_only and sections:
|
|
546
|
+
successful, failed = import_wf_sections(sections, module_name=args.module_name, verbose=args.verbose)
|
|
547
|
+
total_successful += successful
|
|
548
|
+
total_failed += failed
|
|
549
|
+
|
|
550
|
+
# Import rules (if not skipped)
|
|
551
|
+
if not args.sections_only and rules:
|
|
552
|
+
successful, failed = import_wf_rules(rules, module_name=args.module_name,
|
|
553
|
+
verbose=args.verbose, batch_size=args.batch_size,
|
|
554
|
+
delay_between_batches=args.delay,
|
|
555
|
+
auto_approve=getattr(args, 'auto_approve', False))
|
|
556
|
+
total_successful += successful
|
|
557
|
+
total_failed += failed
|
|
558
|
+
|
|
559
|
+
# Final summary
|
|
560
|
+
print("\n" + "=" * 60)
|
|
561
|
+
print(" FINAL IMPORT SUMMARY")
|
|
562
|
+
print("=" * 60)
|
|
563
|
+
print(f" Total successful imports: {total_successful}")
|
|
564
|
+
print(f" Total failed imports: {total_failed}")
|
|
565
|
+
print(f" Overall success rate: {(total_successful / (total_successful + total_failed) * 100):.1f}%" if (total_successful + total_failed) > 0 else "N/A")
|
|
566
|
+
print("\n Import process completed!")
|
|
567
|
+
|
|
568
|
+
return [{
|
|
569
|
+
"success": True,
|
|
570
|
+
"total_successful": total_successful,
|
|
571
|
+
"total_failed": total_failed,
|
|
572
|
+
"module_name": args.module_name
|
|
573
|
+
}]
|
|
574
|
+
|
|
575
|
+
except Exception as e:
|
|
576
|
+
print(f"ERROR: {str(e)}")
|
|
577
|
+
return [{"success": False, "error": str(e)}]
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
`catocli mutation admin addAdmin "$(cat < addAdmin.json)"`
|
|
12
12
|
|
|
13
|
-
`catocli mutation admin addAdmin '{"addAdminInput": {"email": {"email": "String"}, "firstName": {"firstName": "String"}, "lastName": {"lastName": "String"}, "passwordNeverExpires": {"passwordNeverExpires": "Boolean"}, "updateAdminRoleInput": {"allowedAccounts": {"allowedAccounts": ["ID"]}, "allowedEntities": {"id": {"id": "ID"}, "name": {"name": "String"}, "type": {"type": "enum(EntityType)"}}, "role": {"id": {"id": "ID"}, "name": {"name": "String"}}}}}'`
|
|
13
|
+
`catocli mutation admin addAdmin '{"addAdminInput": {"adminType": {"adminType": "enum(AdminType)"}, "email": {"email": "String"}, "firstName": {"firstName": "String"}, "lastName": {"lastName": "String"}, "passwordNeverExpires": {"passwordNeverExpires": "Boolean"}, "updateAdminRoleInput": {"allowedAccounts": {"allowedAccounts": ["ID"]}, "allowedEntities": {"id": {"id": "ID"}, "name": {"name": "String"}, "type": {"type": "enum(EntityType)"}}, "role": {"id": {"id": "ID"}, "name": {"name": "String"}}}}}'`
|
|
14
14
|
|
|
15
15
|
#### Operation Arguments for mutation.admin.addAdmin ####
|
|
16
16
|
`accountId` [ID] - (required) N/A
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
from ..parserApiClient import createRequest, get_help
|
|
3
|
+
|
|
4
|
+
def mutation_hardware_parse(mutation_subparsers):
|
|
5
|
+
mutation_hardware_parser = mutation_subparsers.add_parser('hardware',
|
|
6
|
+
help='hardware() mutation operation',
|
|
7
|
+
usage=get_help("mutation_hardware"))
|
|
8
|
+
|
|
9
|
+
mutation_hardware_subparsers = mutation_hardware_parser.add_subparsers()
|
|
10
|
+
|
|
11
|
+
mutation_hardware_updateHardwareShipping_parser = mutation_hardware_subparsers.add_parser('updateHardwareShipping',
|
|
12
|
+
help='updateHardwareShipping() hardware operation',
|
|
13
|
+
usage=get_help("mutation_hardware_updateHardwareShipping"))
|
|
14
|
+
|
|
15
|
+
mutation_hardware_updateHardwareShipping_parser.add_argument('json', help='Variables in JSON format.')
|
|
16
|
+
mutation_hardware_updateHardwareShipping_parser.add_argument('-accountID', help='Override the CATO_ACCOUNT_ID environment variable with this value.')
|
|
17
|
+
mutation_hardware_updateHardwareShipping_parser.add_argument('-t', const=True, default=False, nargs='?',
|
|
18
|
+
help='Print test request preview without sending api call')
|
|
19
|
+
mutation_hardware_updateHardwareShipping_parser.add_argument('-v', const=True, default=False, nargs='?',
|
|
20
|
+
help='Verbose output')
|
|
21
|
+
mutation_hardware_updateHardwareShipping_parser.add_argument('-p', const=True, default=False, nargs='?',
|
|
22
|
+
help='Pretty print')
|
|
23
|
+
mutation_hardware_updateHardwareShipping_parser.set_defaults(func=createRequest,operation_name='mutation.hardware.updateHardwareShipping')
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
## CATO-CLI - mutation.hardware.updateHardwareShipping:
|
|
3
|
+
[Click here](https://api.catonetworks.com/documentation/#mutation-updateHardwareShipping) for documentation on this operation.
|
|
4
|
+
|
|
5
|
+
### Usage for mutation.hardware.updateHardwareShipping:
|
|
6
|
+
|
|
7
|
+
`catocli mutation hardware updateHardwareShipping -h`
|
|
8
|
+
|
|
9
|
+
`catocli mutation hardware updateHardwareShipping <json>`
|
|
10
|
+
|
|
11
|
+
`catocli mutation hardware updateHardwareShipping "$(cat < updateHardwareShipping.json)"`
|
|
12
|
+
|
|
13
|
+
`catocli mutation hardware updateHardwareShipping '{"updateHardwareShippingInput": {"hardwareShippingDetailsInput": {"details": {"address": {"cityName": {"cityName": "String"}, "companyName": {"companyName": "String"}, "countryName": {"countryName": "String"}, "stateName": {"stateName": "String"}, "street": {"street": "String"}, "zipCode": {"zipCode": "String"}}, "comment": {"comment": "String"}, "contact": {"email": {"email": "Email"}, "name": {"name": "String"}, "phone": {"phone": "Phone"}}, "incoterms": {"incoterms": "String"}, "instruction": {"instruction": "String"}, "vatId": {"vatId": "String"}}, "powerCable": {"powerCable": "String"}}, "ids": {"ids": ["ID"]}}}'`
|
|
14
|
+
|
|
15
|
+
#### Operation Arguments for mutation.hardware.updateHardwareShipping ####
|
|
16
|
+
`accountId` [ID] - (required) N/A
|
|
17
|
+
`updateHardwareShippingInput` [UpdateHardwareShippingInput] - (required) N/A
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
`catocli mutation site addBgpPeer "$(cat < addBgpPeer.json)"`
|
|
12
12
|
|
|
13
|
-
`catocli mutation site addBgpPeer '{"addBgpPeerInput": {"advertiseAllRoutes": {"advertiseAllRoutes": "Boolean"}, "advertiseDefaultRoute": {"advertiseDefaultRoute": "Boolean"}, "advertiseSummaryRoutes": {"advertiseSummaryRoutes": "Boolean"}, "bfdEnabled": {"bfdEnabled": "Boolean"}, "bfdSettingsInput": {"multiplier": {"multiplier": "Int"}, "receiveInterval": {"receiveInterval": "Int"}, "transmitInterval": {"transmitInterval": "Int"}}, "bgpSummaryRouteInput": {"community": {"from": {"from": "Asn16"}, "to": {"to": "Asn16"}}, "route": {"route": "NetworkSubnet"}}, "bgpTrackingInput": {"alertFrequency": {"alertFrequency": "enum(PolicyRuleTrackingFrequencyEnum)"}, "enabled": {"enabled": "Boolean"}, "subscriptionId": {"subscriptionId": "ID"}}, "catoAsn": {"catoAsn": "Asn16"}, "defaultAction": {"defaultAction": "enum(BgpDefaultAction)"}, "holdTime": {"holdTime": "Int"}, "keepaliveInterval": {"keepaliveInterval": "Int"}, "md5AuthKey": {"md5AuthKey": "String"}, "metric": {"metric": "Int"}, "name": {"name": "String"}, "peerAsn": {"peerAsn": "Asn32"}, "peerIp": {"peerIp": "IPAddress"}, "performNat": {"performNat": "Boolean"}, "siteRefInput": {"by": {"by": "enum(ObjectRefBy)"}, "input": {"input": "String"}}}}'`
|
|
13
|
+
`catocli mutation site addBgpPeer '{"addBgpPeerInput": {"advertiseAllRoutes": {"advertiseAllRoutes": "Boolean"}, "advertiseDefaultRoute": {"advertiseDefaultRoute": "Boolean"}, "advertiseSummaryRoutes": {"advertiseSummaryRoutes": "Boolean"}, "bfdEnabled": {"bfdEnabled": "Boolean"}, "bfdSettingsInput": {"multiplier": {"multiplier": "Int"}, "receiveInterval": {"receiveInterval": "Int"}, "transmitInterval": {"transmitInterval": "Int"}}, "bgpFilterRuleInput": {"bgpRouteExactAndInclusiveFilterRule": {"ge": {"ge": "Int"}, "globalIpRange": {"by": {"by": "enum(ObjectRefBy)"}, "input": {"input": "String"}}, "globalIpRangeException": {"by": {"by": "enum(ObjectRefBy)"}, "input": {"input": "String"}}, "le": {"le": "Int"}, "networkSubnet": {"networkSubnet": ["NetworkSubnet"]}, "networkSubnetException": {"networkSubnetException": ["NetworkSubnet"]}}, "bgpRouteExactFilterRule": {"globalIpRange": {"by": {"by": "enum(ObjectRefBy)"}, "input": {"input": "String"}}, "networkSubnet": {"networkSubnet": ["NetworkSubnet"]}}, "communityFilterRule": {"community": {"from": {"from": "Asn16"}, "to": {"to": "Asn16"}}, "predicate": {"predicate": "enum(BgpCommunityFilterPredicate)"}}}, "bgpSummaryRouteInput": {"community": {"from": {"from": "Asn16"}, "to": {"to": "Asn16"}}, "route": {"route": "NetworkSubnet"}}, "bgpTrackingInput": {"alertFrequency": {"alertFrequency": "enum(PolicyRuleTrackingFrequencyEnum)"}, "enabled": {"enabled": "Boolean"}, "subscriptionId": {"subscriptionId": "ID"}}, "catoAsn": {"catoAsn": "Asn16"}, "defaultAction": {"defaultAction": "enum(BgpDefaultAction)"}, "holdTime": {"holdTime": "Int"}, "keepaliveInterval": {"keepaliveInterval": "Int"}, "md5AuthKey": {"md5AuthKey": "String"}, "metric": {"metric": "Int"}, "name": {"name": "String"}, "peerAsn": {"peerAsn": "Asn32"}, "peerIp": {"peerIp": "IPAddress"}, "performNat": {"performNat": "Boolean"}, "siteRefInput": {"by": {"by": "enum(ObjectRefBy)"}, "input": {"input": "String"}}}}'`
|
|
14
14
|
|
|
15
15
|
#### Operation Arguments for mutation.site.addBgpPeer ####
|
|
16
16
|
`accountId` [ID] - (required) N/A
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
`catocli mutation site addNetworkRange "$(cat < addNetworkRange.json)"`
|
|
12
12
|
|
|
13
|
-
`catocli mutation site addNetworkRange '{"addNetworkRangeInput": {"azureFloatingIp": {"azureFloatingIp": "IPAddress"}, "gateway": {"gateway": "IPAddress"}, "localIp": {"localIp": "IPAddress"}, "mdnsReflector": {"mdnsReflector": "Boolean"}, "name": {"name": "String"}, "networkDhcpSettingsInput": {"dhcpType": {"dhcpType": "enum(DhcpType)"}, "ipRange": {"ipRange": "IPRange"}, "relayGroupId": {"relayGroupId": "ID"}}, "rangeType": {"rangeType": "enum(SubnetType)"}, "subnet": {"subnet": "IPSubnet"}, "translatedSubnet": {"translatedSubnet": "IPSubnet"}, "vlan": {"vlan": "Int"}}, "lanSocketInterfaceId": "ID"}'`
|
|
13
|
+
`catocli mutation site addNetworkRange '{"addNetworkRangeInput": {"azureFloatingIp": {"azureFloatingIp": "IPAddress"}, "gateway": {"gateway": "IPAddress"}, "internetOnly": {"internetOnly": "Boolean"}, "localIp": {"localIp": "IPAddress"}, "mdnsReflector": {"mdnsReflector": "Boolean"}, "name": {"name": "String"}, "networkDhcpSettingsInput": {"dhcpMicrosegmentation": {"dhcpMicrosegmentation": "Boolean"}, "dhcpType": {"dhcpType": "enum(DhcpType)"}, "ipRange": {"ipRange": "IPRange"}, "relayGroupId": {"relayGroupId": "ID"}}, "rangeType": {"rangeType": "enum(SubnetType)"}, "subnet": {"subnet": "IPSubnet"}, "translatedSubnet": {"translatedSubnet": "IPSubnet"}, "vlan": {"vlan": "Int"}}, "lanSocketInterfaceId": "ID"}'`
|
|
14
14
|
|
|
15
15
|
#### Operation Arguments for mutation.site.addNetworkRange ####
|
|
16
16
|
`accountId` [ID] - (required) N/A
|