catocli 3.0.14__py3-none-any.whl → 3.0.22__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.

Files changed (192) hide show
  1. catocli/Utils/clidriver.py +16 -8
  2. catocli/Utils/formatter_account_metrics.py +544 -0
  3. catocli/Utils/formatter_app_stats.py +184 -0
  4. catocli/Utils/formatter_app_stats_timeseries.py +377 -0
  5. catocli/Utils/formatter_events_timeseries.py +459 -0
  6. catocli/Utils/formatter_socket_port_metrics.py +189 -0
  7. catocli/Utils/formatter_socket_port_metrics_timeseries.py +339 -0
  8. catocli/Utils/formatter_utils.py +251 -0
  9. catocli/Utils/help_formatter.py +1 -1
  10. catocli/__init__.py +1 -1
  11. catocli/clisettings.json +37 -5
  12. catocli/parsers/custom/query_eventsFeed/README.md +94 -0
  13. catocli/parsers/custom/scim/README.md +346 -0
  14. catocli/parsers/custom/scim/scim_client.py +132 -26
  15. catocli/parsers/custom/scim/scim_commands.py +14 -56
  16. catocli/parsers/customParserApiClient.py +213 -65
  17. catocli/parsers/mutation_policy/__init__.py +405 -405
  18. catocli/parsers/mutation_site/__init__.py +15 -15
  19. catocli/parsers/mutation_sites/__init__.py +15 -15
  20. catocli/parsers/query_accountMetrics/README.md +99 -9
  21. catocli/parsers/query_accountMetrics/__init__.py +6 -0
  22. catocli/parsers/query_appStats/README.md +11 -11
  23. catocli/parsers/query_appStats/__init__.py +4 -2
  24. catocli/parsers/query_appStatsTimeSeries/README.md +10 -10
  25. catocli/parsers/query_appStatsTimeSeries/__init__.py +4 -2
  26. catocli/parsers/query_auditFeed/README.md +9 -9
  27. catocli/parsers/query_events/README.md +9 -9
  28. catocli/parsers/query_eventsTimeSeries/README.md +289 -9
  29. catocli/parsers/query_eventsTimeSeries/__init__.py +6 -0
  30. catocli/parsers/query_policy/__init__.py +42 -42
  31. catocli/parsers/query_socketPortMetrics/README.md +53 -9
  32. catocli/parsers/query_socketPortMetrics/__init__.py +6 -0
  33. catocli/parsers/query_socketPortMetricsTimeSeries/README.md +92 -9
  34. catocli/parsers/query_socketPortMetricsTimeSeries/__init__.py +4 -2
  35. {catocli-3.0.14.dist-info → catocli-3.0.22.dist-info}/METADATA +1 -1
  36. {catocli-3.0.14.dist-info → catocli-3.0.22.dist-info}/RECORD +187 -183
  37. {catocli-3.0.14.dist-info → catocli-3.0.22.dist-info}/top_level.txt +0 -1
  38. models/mutation.policy.antiMalwareFileHash.addRule.json +20 -0
  39. models/mutation.policy.antiMalwareFileHash.addSection.json +103 -0
  40. models/mutation.policy.antiMalwareFileHash.createPolicyRevision.json +123 -0
  41. models/mutation.policy.antiMalwareFileHash.discardPolicyRevision.json +123 -0
  42. models/mutation.policy.antiMalwareFileHash.moveRule.json +20 -0
  43. models/mutation.policy.antiMalwareFileHash.moveSection.json +103 -0
  44. models/mutation.policy.antiMalwareFileHash.publishPolicyRevision.json +123 -0
  45. models/mutation.policy.antiMalwareFileHash.removeRule.json +20 -0
  46. models/mutation.policy.antiMalwareFileHash.removeSection.json +103 -0
  47. models/mutation.policy.antiMalwareFileHash.updatePolicy.json +123 -0
  48. models/mutation.policy.antiMalwareFileHash.updateRule.json +20 -0
  49. models/mutation.policy.antiMalwareFileHash.updateSection.json +103 -0
  50. models/mutation.policy.appTenantRestriction.addRule.json +20 -0
  51. models/mutation.policy.appTenantRestriction.addSection.json +103 -0
  52. models/mutation.policy.appTenantRestriction.createPolicyRevision.json +123 -0
  53. models/mutation.policy.appTenantRestriction.discardPolicyRevision.json +123 -0
  54. models/mutation.policy.appTenantRestriction.moveRule.json +20 -0
  55. models/mutation.policy.appTenantRestriction.moveSection.json +103 -0
  56. models/mutation.policy.appTenantRestriction.publishPolicyRevision.json +123 -0
  57. models/mutation.policy.appTenantRestriction.removeRule.json +20 -0
  58. models/mutation.policy.appTenantRestriction.removeSection.json +103 -0
  59. models/mutation.policy.appTenantRestriction.updatePolicy.json +123 -0
  60. models/mutation.policy.appTenantRestriction.updateRule.json +20 -0
  61. models/mutation.policy.appTenantRestriction.updateSection.json +103 -0
  62. models/mutation.policy.applicationControl.addRule.json +20 -0
  63. models/mutation.policy.applicationControl.addSection.json +103 -0
  64. models/mutation.policy.applicationControl.createPolicyRevision.json +123 -0
  65. models/mutation.policy.applicationControl.discardPolicyRevision.json +123 -0
  66. models/mutation.policy.applicationControl.moveRule.json +20 -0
  67. models/mutation.policy.applicationControl.moveSection.json +103 -0
  68. models/mutation.policy.applicationControl.publishPolicyRevision.json +123 -0
  69. models/mutation.policy.applicationControl.removeRule.json +20 -0
  70. models/mutation.policy.applicationControl.removeSection.json +103 -0
  71. models/mutation.policy.applicationControl.updatePolicy.json +123 -0
  72. models/mutation.policy.applicationControl.updateRule.json +20 -0
  73. models/mutation.policy.applicationControl.updateSection.json +103 -0
  74. models/mutation.policy.dynamicIpAllocation.addRule.json +20 -0
  75. models/mutation.policy.dynamicIpAllocation.addSection.json +103 -0
  76. models/mutation.policy.dynamicIpAllocation.createPolicyRevision.json +123 -0
  77. models/mutation.policy.dynamicIpAllocation.discardPolicyRevision.json +123 -0
  78. models/mutation.policy.dynamicIpAllocation.moveRule.json +20 -0
  79. models/mutation.policy.dynamicIpAllocation.moveSection.json +103 -0
  80. models/mutation.policy.dynamicIpAllocation.publishPolicyRevision.json +123 -0
  81. models/mutation.policy.dynamicIpAllocation.removeRule.json +20 -0
  82. models/mutation.policy.dynamicIpAllocation.removeSection.json +103 -0
  83. models/mutation.policy.dynamicIpAllocation.updatePolicy.json +123 -0
  84. models/mutation.policy.dynamicIpAllocation.updateRule.json +20 -0
  85. models/mutation.policy.dynamicIpAllocation.updateSection.json +103 -0
  86. models/mutation.policy.internetFirewall.addRule.json +20 -0
  87. models/mutation.policy.internetFirewall.addSection.json +103 -0
  88. models/mutation.policy.internetFirewall.createPolicyRevision.json +123 -0
  89. models/mutation.policy.internetFirewall.discardPolicyRevision.json +123 -0
  90. models/mutation.policy.internetFirewall.moveRule.json +20 -0
  91. models/mutation.policy.internetFirewall.moveSection.json +103 -0
  92. models/mutation.policy.internetFirewall.publishPolicyRevision.json +123 -0
  93. models/mutation.policy.internetFirewall.removeRule.json +20 -0
  94. models/mutation.policy.internetFirewall.removeSection.json +103 -0
  95. models/mutation.policy.internetFirewall.updatePolicy.json +123 -0
  96. models/mutation.policy.internetFirewall.updateRule.json +20 -0
  97. models/mutation.policy.internetFirewall.updateSection.json +103 -0
  98. models/mutation.policy.remotePortFwd.addRule.json +20 -0
  99. models/mutation.policy.remotePortFwd.addSection.json +103 -0
  100. models/mutation.policy.remotePortFwd.createPolicyRevision.json +123 -0
  101. models/mutation.policy.remotePortFwd.discardPolicyRevision.json +123 -0
  102. models/mutation.policy.remotePortFwd.moveRule.json +20 -0
  103. models/mutation.policy.remotePortFwd.moveSection.json +103 -0
  104. models/mutation.policy.remotePortFwd.publishPolicyRevision.json +123 -0
  105. models/mutation.policy.remotePortFwd.removeRule.json +20 -0
  106. models/mutation.policy.remotePortFwd.removeSection.json +103 -0
  107. models/mutation.policy.remotePortFwd.updatePolicy.json +123 -0
  108. models/mutation.policy.remotePortFwd.updateRule.json +20 -0
  109. models/mutation.policy.remotePortFwd.updateSection.json +103 -0
  110. models/mutation.policy.socketLan.addRule.json +40 -0
  111. models/mutation.policy.socketLan.addSection.json +103 -0
  112. models/mutation.policy.socketLan.createPolicyRevision.json +143 -0
  113. models/mutation.policy.socketLan.discardPolicyRevision.json +143 -0
  114. models/mutation.policy.socketLan.moveRule.json +40 -0
  115. models/mutation.policy.socketLan.moveSection.json +103 -0
  116. models/mutation.policy.socketLan.publishPolicyRevision.json +143 -0
  117. models/mutation.policy.socketLan.removeRule.json +40 -0
  118. models/mutation.policy.socketLan.removeSection.json +103 -0
  119. models/mutation.policy.socketLan.updatePolicy.json +143 -0
  120. models/mutation.policy.socketLan.updateRule.json +40 -0
  121. models/mutation.policy.socketLan.updateSection.json +103 -0
  122. models/mutation.policy.terminalServer.addRule.json +20 -0
  123. models/mutation.policy.terminalServer.addSection.json +103 -0
  124. models/mutation.policy.terminalServer.createPolicyRevision.json +123 -0
  125. models/mutation.policy.terminalServer.discardPolicyRevision.json +123 -0
  126. models/mutation.policy.terminalServer.moveRule.json +20 -0
  127. models/mutation.policy.terminalServer.moveSection.json +103 -0
  128. models/mutation.policy.terminalServer.publishPolicyRevision.json +123 -0
  129. models/mutation.policy.terminalServer.removeRule.json +20 -0
  130. models/mutation.policy.terminalServer.removeSection.json +103 -0
  131. models/mutation.policy.terminalServer.updatePolicy.json +123 -0
  132. models/mutation.policy.terminalServer.updateRule.json +20 -0
  133. models/mutation.policy.terminalServer.updateSection.json +103 -0
  134. models/mutation.policy.tlsInspect.addRule.json +20 -0
  135. models/mutation.policy.tlsInspect.addSection.json +103 -0
  136. models/mutation.policy.tlsInspect.createPolicyRevision.json +123 -0
  137. models/mutation.policy.tlsInspect.discardPolicyRevision.json +123 -0
  138. models/mutation.policy.tlsInspect.moveRule.json +20 -0
  139. models/mutation.policy.tlsInspect.moveSection.json +103 -0
  140. models/mutation.policy.tlsInspect.publishPolicyRevision.json +123 -0
  141. models/mutation.policy.tlsInspect.removeRule.json +20 -0
  142. models/mutation.policy.tlsInspect.removeSection.json +103 -0
  143. models/mutation.policy.tlsInspect.updatePolicy.json +123 -0
  144. models/mutation.policy.tlsInspect.updateRule.json +20 -0
  145. models/mutation.policy.tlsInspect.updateSection.json +103 -0
  146. models/mutation.policy.wanFirewall.addRule.json +20 -0
  147. models/mutation.policy.wanFirewall.addSection.json +103 -0
  148. models/mutation.policy.wanFirewall.createPolicyRevision.json +123 -0
  149. models/mutation.policy.wanFirewall.discardPolicyRevision.json +123 -0
  150. models/mutation.policy.wanFirewall.moveRule.json +20 -0
  151. models/mutation.policy.wanFirewall.moveSection.json +103 -0
  152. models/mutation.policy.wanFirewall.publishPolicyRevision.json +123 -0
  153. models/mutation.policy.wanFirewall.removeRule.json +20 -0
  154. models/mutation.policy.wanFirewall.removeSection.json +103 -0
  155. models/mutation.policy.wanFirewall.updatePolicy.json +123 -0
  156. models/mutation.policy.wanFirewall.updateRule.json +20 -0
  157. models/mutation.policy.wanFirewall.updateSection.json +103 -0
  158. models/mutation.policy.wanNetwork.addRule.json +20 -0
  159. models/mutation.policy.wanNetwork.addSection.json +103 -0
  160. models/mutation.policy.wanNetwork.createPolicyRevision.json +123 -0
  161. models/mutation.policy.wanNetwork.discardPolicyRevision.json +123 -0
  162. models/mutation.policy.wanNetwork.moveRule.json +20 -0
  163. models/mutation.policy.wanNetwork.moveSection.json +103 -0
  164. models/mutation.policy.wanNetwork.publishPolicyRevision.json +123 -0
  165. models/mutation.policy.wanNetwork.removeRule.json +20 -0
  166. models/mutation.policy.wanNetwork.removeSection.json +103 -0
  167. models/mutation.policy.wanNetwork.updatePolicy.json +123 -0
  168. models/mutation.policy.wanNetwork.updateRule.json +20 -0
  169. models/mutation.policy.wanNetwork.updateSection.json +103 -0
  170. models/mutation.xdr.analystFeedback.json +822 -87
  171. models/query.policy.antiMalwareFileHash.policy.json +123 -0
  172. models/query.policy.appTenantRestriction.policy.json +123 -0
  173. models/query.policy.applicationControl.policy.json +123 -0
  174. models/query.policy.dynamicIpAllocation.policy.json +123 -0
  175. models/query.policy.internetFirewall.policy.json +123 -0
  176. models/query.policy.remotePortFwd.policy.json +123 -0
  177. models/query.policy.socketLan.policy.json +143 -0
  178. models/query.policy.terminalServer.policy.json +123 -0
  179. models/query.policy.tlsInspect.policy.json +123 -0
  180. models/query.policy.wanFirewall.policy.json +123 -0
  181. models/query.policy.wanNetwork.policy.json +123 -0
  182. models/query.xdr.stories.json +822 -87
  183. models/query.xdr.story.json +822 -87
  184. schema/catolib.py +34 -17
  185. catocli/Utils/csv_formatter.py +0 -663
  186. scripts/catolib.py +0 -62
  187. scripts/export_if_rules_to_json.py +0 -188
  188. scripts/export_wf_rules_to_json.py +0 -111
  189. scripts/import_wf_rules_to_tfstate.py +0 -331
  190. {catocli-3.0.14.dist-info → catocli-3.0.22.dist-info}/WHEEL +0 -0
  191. {catocli-3.0.14.dist-info → catocli-3.0.22.dist-info}/entry_points.txt +0 -0
  192. {catocli-3.0.14.dist-info → catocli-3.0.22.dist-info}/licenses/LICENSE +0 -0
@@ -1,331 +0,0 @@
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
- """
7
-
8
- import json
9
- import subprocess
10
- import sys
11
- import re
12
- import time
13
- import argparse
14
- import os
15
- import glob
16
- from pathlib import Path
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']['wanFirewall']['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
- def check_terraform_initialized(dest_dir):
35
- """Check if Terraform is initialized in the destination directory"""
36
- terraform_dir = os.path.join(dest_dir, '.terraform')
37
- if not os.path.exists(terraform_dir):
38
- return False, "Terraform directory '.terraform' not found"
39
-
40
- # Check for terraform.tfstate or .terraform.lock.hcl
41
- state_file = os.path.join(dest_dir, 'terraform.tfstate')
42
- lock_file = os.path.join(dest_dir, '.terraform.lock.hcl')
43
-
44
- if not os.path.exists(state_file) and not os.path.exists(lock_file):
45
- return False, "No terraform state or lock file found"
46
-
47
- return True, "Terraform appears to be initialized"
48
-
49
- def validate_module_in_tf_files(dest_dir, module_name):
50
- """Validate that the specified module name exists in .tf files"""
51
- tf_files = glob.glob(os.path.join(dest_dir, '*.tf'))
52
-
53
- if not tf_files:
54
- return False, "No .tf files found in destination directory"
55
-
56
- module_found = False
57
- files_checked = []
58
-
59
- for tf_file in tf_files:
60
- files_checked.append(os.path.basename(tf_file))
61
- try:
62
- with open(tf_file, 'r') as f:
63
- content = f.read()
64
- # Look for the module name in various forms
65
- patterns = [
66
- rf'module\s+"{module_name.split(".")[-1]}"', # module "if_rules"
67
- rf'module\s+{module_name.split(".")[-1]}\s+{{', # module if_rules {
68
- rf'{re.escape(module_name)}', # exact match module.if_rules
69
- ]
70
-
71
- for pattern in patterns:
72
- if re.search(pattern, content, re.MULTILINE):
73
- module_found = True
74
- break
75
-
76
- if module_found:
77
- break
78
- except Exception as e:
79
- print(f"Warning: Could not read {tf_file}: {e}")
80
-
81
- if module_found:
82
- return True, f"Module '{module_name}' found in Terraform files"
83
- else:
84
- return False, f"Module '{module_name}' not found in files: {', '.join(files_checked)}"
85
-
86
- def sanitize_name_for_terraform(name):
87
- """Sanitize rule/section name to create valid Terraform resource key"""
88
- # Replace spaces and special characters with underscores
89
- sanitized = re.sub(r'[^a-zA-Z0-9_-]', '_', name)
90
- # Remove multiple consecutive underscores
91
- sanitized = re.sub(r'_+', '_', sanitized)
92
- # Remove leading/trailing underscores
93
- sanitized = sanitized.strip('_')
94
- return sanitized
95
-
96
- def extract_rules_and_sections(policy_data):
97
- """Extract rules and sections from the policy data"""
98
- rules = []
99
- sections = []
100
-
101
- # Extract rules
102
- for rule_entry in policy_data.get('rules', []):
103
- rule = rule_entry.get('rule', {})
104
- if rule.get('id') and rule.get('name'):
105
- rules.append({
106
- 'id': rule['id'],
107
- 'name': rule['name'],
108
- 'index': rule.get('index', 0),
109
- 'section_name': rule.get('section', {}).get('name', 'Default')
110
- })
111
-
112
- # Extract sections
113
- section_ids = policy_data.get('section_ids', {})
114
- print("section_ids",json.dumps(section_ids, indent=2))
115
- for section in policy_data.get('sections', []):
116
- if section.get('section_name'):
117
- sections.append({
118
- 'section_name': section['section_name'],
119
- 'section_index': section.get('section_index', 0),
120
- 'section_id': section_ids.get(section['section_name'], '')
121
- })
122
- return rules, sections
123
-
124
- def run_terraform_import(resource_address, resource_id, dest_dir=None, timeout=60):
125
- """
126
- Run a single terraform import command
127
-
128
- Args:
129
- resource_address: The terraform resource address
130
- resource_id: The actual resource ID to import
131
- timeout: Command timeout in seconds
132
-
133
- Returns:
134
- tuple: (success: bool, output: str, error: str)
135
- """
136
- cmd = ['terraform', 'import', resource_address, resource_id]
137
- print(f"🔧 Command: {' '.join(cmd)}")
138
-
139
- try:
140
- print(f"Importing: {resource_address} <- {resource_id}")
141
-
142
- result = subprocess.run(
143
- cmd,
144
- capture_output=True,
145
- text=True,
146
- timeout=timeout,
147
- cwd=dest_dir if dest_dir else Path.cwd()
148
- )
149
-
150
- if result.returncode == 0:
151
- print(f"✅ Success: {resource_address}")
152
- return True, result.stdout, result.stderr
153
- else:
154
- print(f"❌ Failed: {resource_address}")
155
- print(f"Error: {result.stderr}")
156
- return False, result.stdout, result.stderr
157
-
158
- except subprocess.TimeoutExpired:
159
- print(f"⏰ Timeout: {resource_address} (exceeded {timeout}s)")
160
- return False, "", f"Command timed out after {timeout} seconds"
161
- except Exception as e:
162
- print(f"❌ Unexpected error for {resource_address}: {e}")
163
- return False, "", str(e)
164
-
165
- def find_rule_index(rules, rule_name):
166
- """Find rule index by name."""
167
- for index, rule in enumerate(rules):
168
- if rule['name'] == rule_name:
169
- return index
170
- return None
171
-
172
- def import_sections(sections, dest_dir, module_name="module.wf_rules",
173
- resource_type="cato_wf_section", resource_name="sections"):
174
- """Import all sections"""
175
- print("\n🗂️ Starting section imports...")
176
- total_sections = len(sections)
177
- successful_imports = 0
178
- failed_imports = 0
179
-
180
- for i, section in enumerate(sections):
181
- section_id = section['section_id']
182
- section_name = section['section_name']
183
- section_index = section['section_index']
184
- resource_address = f'{module_name}.{resource_type}.{resource_name}["{str(section_index)}"]'
185
- print(f"\n[{i+1}/{total_sections}] Section: {section_name} (index: {section_index})")
186
-
187
- # For sections, we use the section name as the ID since that's how Cato identifies them
188
- success, stdout, stderr = run_terraform_import(resource_address, section_id, dest_dir)
189
-
190
- if success:
191
- successful_imports += 1
192
- else:
193
- failed_imports += 1
194
-
195
- print(f"\n📊 Section Import Summary: {successful_imports} successful, {failed_imports} failed")
196
- return successful_imports, failed_imports
197
-
198
- def import_rules(rules, dest_dir, module_name="module.wf_rules",
199
- resource_type="cato_wf_rule", resource_name="rules",
200
- batch_size=10, delay_between_batches=2):
201
- """Import all rules in batches"""
202
- print("\n📋 Starting rule imports...")
203
- successful_imports = 0
204
- failed_imports = 0
205
- total_rules = len(rules)
206
-
207
- for i, rule in enumerate(rules):
208
- rule_id = rule['id']
209
- rule_name = rule['name']
210
- rule_index = find_rule_index(rules, rule_name)
211
- terraform_key = sanitize_name_for_terraform(rule_name)
212
-
213
- # Use array index syntax instead of rule ID
214
- resource_address = f'{module_name}.{resource_type}.{resource_name}["{str(rule_index)}"]'
215
- print(f"\n[{i+1}/{total_rules}] Rule: {rule_name} (index: {rule_index})")
216
-
217
- success, stdout, stderr = run_terraform_import(resource_address, rule_id, dest_dir)
218
-
219
- if success:
220
- successful_imports += 1
221
- else:
222
- failed_imports += 1
223
-
224
- # Ask user if they want to continue on failure
225
- if failed_imports <= 3: # Only prompt for first few failures
226
- response = input(f"\nContinue with remaining imports? (y/n): ").lower()
227
- if response == 'n':
228
- print("Import process stopped by user.")
229
- break
230
-
231
- # Delay between batches
232
- if (i + 1) % batch_size == 0 and i < total_rules - 1:
233
- print(f"\n⏸️ Batch complete. Waiting {delay_between_batches}s before next batch...")
234
- time.sleep(delay_between_batches)
235
-
236
- print(f"\n📊 Rule Import Summary: {successful_imports} successful, {failed_imports} failed")
237
- return successful_imports, failed_imports
238
-
239
- def main():
240
- """Main function to orchestrate the import process"""
241
- parser = argparse.ArgumentParser(description='Import Cato WF rules and sections to Terraform state')
242
- parser.add_argument('json_file', help='Path to the JSON file containing WF rules and sections')
243
- parser.add_argument('--module-name', required=True, default='module.wf_rules',
244
- help='Terraform module name to import resources into (default: module.wf_rules)')
245
- parser.add_argument('--batch-size', type=int, default=10, help='Number of imports per batch (default: 10)')
246
- parser.add_argument('--dest-dir', required=True, help='Destination directory for Terraform state')
247
- parser.add_argument('--delay', type=int, default=2, help='Delay between batches in seconds (default: 2)')
248
- parser.add_argument('--rules-only', action='store_true', help='Import only rules, skip sections')
249
- parser.add_argument('--sections-only', action='store_true', help='Import only sections, skip rules')
250
-
251
- args = parser.parse_args()
252
-
253
- print("🔧 Terraform Import Tool - Cato WF Rules & Sections")
254
- print("=" * 60)
255
-
256
- # Verify destination directory
257
- if not os.path.isdir(args.dest_dir):
258
- print(f"Error: Destination directory '{args.dest_dir}' does not exist.")
259
- sys.exit(1)
260
-
261
- # Check if Terraform is initialized in the destination directory
262
- print(f"🔍 Checking Terraform initialization in {args.dest_dir}...")
263
- tf_initialized, tf_message = check_terraform_initialized(args.dest_dir)
264
- if not tf_initialized:
265
- print(f"❌ Error: {tf_message}")
266
- print("Please run 'terraform init' in the destination directory first.")
267
- sys.exit(1)
268
- print(f"✅ {tf_message}")
269
-
270
- # Validate module name exists in .tf files
271
- print(f"🔍 Validating module '{args.module_name}' exists in Terraform files...")
272
- module_valid, module_message = validate_module_in_tf_files(args.dest_dir, args.module_name)
273
- if not module_valid:
274
- print(f"❌ Error: {module_message}")
275
- print(f"Please ensure the module '{args.module_name}' is defined in your .tf files.")
276
- sys.exit(1)
277
- print(f"✅ {module_message}")
278
-
279
- # Load data
280
- print(f"📂 Loading data from {args.json_file}...")
281
- policy_data = load_json_data(args.json_file)
282
-
283
- # Extract rules and sections
284
- rules, sections = extract_rules_and_sections(policy_data)
285
-
286
- print(f"📄 Found {len(rules)} rules")
287
- print(f"🗂️ Found {len(sections)} sections")
288
-
289
- if not rules and not sections:
290
- print("❌ No rules or sections found. Exiting.")
291
- sys.exit(1)
292
-
293
- # Ask for confirmation
294
- if not args.rules_only and not args.sections_only:
295
- print(f"\n🎯 Ready to import {len(sections)} sections and {len(rules)} rules.")
296
- elif args.rules_only:
297
- print(f"\n🎯 Ready to import {len(rules)} rules only.")
298
- elif args.sections_only:
299
- print(f"\n🎯 Ready to import {len(sections)} sections only.")
300
-
301
- confirm = input(f"\nProceed with import? (y/n): ").lower()
302
- if confirm != 'y':
303
- print("Import cancelled.")
304
- sys.exit(0)
305
-
306
- total_successful = 0
307
- total_failed = 0
308
-
309
- # Import sections first (if not skipped)
310
- if not args.rules_only and sections:
311
- successful, failed = import_sections(sections, args.dest_dir, module_name=args.module_name)
312
- total_successful += successful
313
- total_failed += failed
314
-
315
- # Import rules (if not skipped)
316
- if not args.sections_only and rules:
317
- successful, failed = import_rules(rules, args.dest_dir, module_name=args.module_name, batch_size=args.batch_size, delay_between_batches=args.delay)
318
- total_successful += successful
319
- total_failed += failed
320
-
321
- # Final summary
322
- print("\n" + "=" * 60)
323
- print("📊 FINAL IMPORT SUMMARY")
324
- print("=" * 60)
325
- print(f"✅ Total successful imports: {total_successful}")
326
- print(f"❌ Total failed imports: {total_failed}")
327
- print(f"📈 Overall success rate: {(total_successful / (total_successful + total_failed) * 100):.1f}%" if (total_successful + total_failed) > 0 else "N/A")
328
- print("\n🎉 Import process completed!")
329
-
330
- if __name__ == "__main__":
331
- main()