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,115 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Configure command parser for Cato CLI
|
|
4
|
+
Handles profile creation, listing, and switching
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
from .configure import (
|
|
9
|
+
configure_profile,
|
|
10
|
+
list_profiles,
|
|
11
|
+
set_profile,
|
|
12
|
+
delete_profile,
|
|
13
|
+
show_profile
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def configure_parse(subparsers):
|
|
18
|
+
"""Create configure command parsers"""
|
|
19
|
+
|
|
20
|
+
# Create the main configure parser
|
|
21
|
+
configure_parser = subparsers.add_parser(
|
|
22
|
+
'configure',
|
|
23
|
+
help='Configure Cato CLI credentials and profiles',
|
|
24
|
+
usage='catocli configure <subcommand> [options]'
|
|
25
|
+
)
|
|
26
|
+
configure_subparsers = configure_parser.add_subparsers(
|
|
27
|
+
description='Configure operations',
|
|
28
|
+
help='Profile management operations'
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Configure profile command
|
|
32
|
+
config_parser = configure_subparsers.add_parser(
|
|
33
|
+
'set',
|
|
34
|
+
help='Configure a profile with credentials',
|
|
35
|
+
usage='catocli configure set [--profile PROFILE] [options]'
|
|
36
|
+
)
|
|
37
|
+
config_parser.add_argument(
|
|
38
|
+
'--profile',
|
|
39
|
+
default='default',
|
|
40
|
+
help='Profile name to configure (default: default)'
|
|
41
|
+
)
|
|
42
|
+
config_parser.add_argument(
|
|
43
|
+
'--endpoint',
|
|
44
|
+
help='Cato API endpoint URL (default: https://api.catonetworks.com/api/v1/graphql2)'
|
|
45
|
+
)
|
|
46
|
+
config_parser.add_argument(
|
|
47
|
+
'--cato-token',
|
|
48
|
+
help='Cato API token'
|
|
49
|
+
)
|
|
50
|
+
config_parser.add_argument(
|
|
51
|
+
'--account-id',
|
|
52
|
+
help='Cato account ID'
|
|
53
|
+
)
|
|
54
|
+
config_parser.add_argument(
|
|
55
|
+
'--interactive',
|
|
56
|
+
action='store_true',
|
|
57
|
+
help='Interactive configuration mode'
|
|
58
|
+
)
|
|
59
|
+
config_parser.add_argument(
|
|
60
|
+
'--skip-validation',
|
|
61
|
+
action='store_true',
|
|
62
|
+
help='Skip credential validation (save without testing)'
|
|
63
|
+
)
|
|
64
|
+
config_parser.set_defaults(func=configure_profile)
|
|
65
|
+
|
|
66
|
+
# List profiles command
|
|
67
|
+
list_parser = configure_subparsers.add_parser(
|
|
68
|
+
'list',
|
|
69
|
+
help='List all configured profiles',
|
|
70
|
+
usage='catocli configure list'
|
|
71
|
+
)
|
|
72
|
+
list_parser.set_defaults(func=list_profiles)
|
|
73
|
+
|
|
74
|
+
# Use/switch profile command
|
|
75
|
+
use_parser = configure_subparsers.add_parser(
|
|
76
|
+
'use',
|
|
77
|
+
help='Set the active profile',
|
|
78
|
+
usage='catocli configure use <profile>'
|
|
79
|
+
)
|
|
80
|
+
use_parser.add_argument(
|
|
81
|
+
'profile',
|
|
82
|
+
help='Profile name to activate'
|
|
83
|
+
)
|
|
84
|
+
use_parser.set_defaults(func=set_profile)
|
|
85
|
+
|
|
86
|
+
# Show current profile command
|
|
87
|
+
show_parser = configure_subparsers.add_parser(
|
|
88
|
+
'show',
|
|
89
|
+
help='Show current profile configuration',
|
|
90
|
+
usage='catocli configure show [--profile PROFILE]'
|
|
91
|
+
)
|
|
92
|
+
show_parser.add_argument(
|
|
93
|
+
'--profile',
|
|
94
|
+
help='Profile name to show (default: current active profile)'
|
|
95
|
+
)
|
|
96
|
+
show_parser.set_defaults(func=show_profile)
|
|
97
|
+
|
|
98
|
+
# Delete profile command
|
|
99
|
+
delete_parser = configure_subparsers.add_parser(
|
|
100
|
+
'delete',
|
|
101
|
+
help='Delete a profile',
|
|
102
|
+
usage='catocli configure delete <profile>'
|
|
103
|
+
)
|
|
104
|
+
delete_parser.add_argument(
|
|
105
|
+
'profile',
|
|
106
|
+
help='Profile name to delete'
|
|
107
|
+
)
|
|
108
|
+
delete_parser.add_argument(
|
|
109
|
+
'--force',
|
|
110
|
+
action='store_true',
|
|
111
|
+
help='Force deletion without confirmation'
|
|
112
|
+
)
|
|
113
|
+
delete_parser.set_defaults(func=delete_profile)
|
|
114
|
+
|
|
115
|
+
return configure_parser
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Configure command implementation for Cato CLI
|
|
4
|
+
Implements profile creation, listing, switching, and management
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import getpass
|
|
8
|
+
import sys
|
|
9
|
+
import json
|
|
10
|
+
from graphql_client import Configuration
|
|
11
|
+
from graphql_client.api_client import ApiException
|
|
12
|
+
from graphql_client.api.call_api import ApiClient, CallApi
|
|
13
|
+
from ...Utils.profile_manager import get_profile_manager
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_credentials(endpoint, cato_token, account_id):
|
|
17
|
+
"""Test credentials by making an entityLookup API call"""
|
|
18
|
+
try:
|
|
19
|
+
print("Testing credentials...")
|
|
20
|
+
|
|
21
|
+
# Create a temporary configuration
|
|
22
|
+
test_config = Configuration()
|
|
23
|
+
test_config.verify_ssl = False
|
|
24
|
+
test_config.debug = False
|
|
25
|
+
test_config.version = "1.0.0" # Required for API client
|
|
26
|
+
test_config.api_key["x-api-key"] = cato_token
|
|
27
|
+
test_config.host = endpoint
|
|
28
|
+
test_config.accountID = account_id
|
|
29
|
+
|
|
30
|
+
# Make a simple entityLookup call to test credentials
|
|
31
|
+
instance = CallApi(ApiClient(test_config))
|
|
32
|
+
response = instance.call_api({
|
|
33
|
+
"query": "query entityLookup($accountID: ID!, $type: EntityType!) { entityLookup(accountID: $accountID, type: $type) { items { entity { id name } } } }",
|
|
34
|
+
"variables": {"accountID": account_id, "type": "country"}
|
|
35
|
+
}, {})
|
|
36
|
+
result = response[0] if response else None
|
|
37
|
+
|
|
38
|
+
# Check if the call was successful
|
|
39
|
+
if result and result.get('data') is not None:
|
|
40
|
+
print("✓ Credentials validated successfully")
|
|
41
|
+
return True, "Credentials are valid"
|
|
42
|
+
elif result and result.get('errors'):
|
|
43
|
+
error_msg = result['errors'][0].get('message', 'Unknown API error')
|
|
44
|
+
return False, f"API error: {error_msg}"
|
|
45
|
+
elif result is None:
|
|
46
|
+
return False, "No response from API"
|
|
47
|
+
else:
|
|
48
|
+
return False, f"Invalid API response: {result}"
|
|
49
|
+
|
|
50
|
+
except ApiException as e:
|
|
51
|
+
if e.status == 401:
|
|
52
|
+
return False, "Invalid API token"
|
|
53
|
+
elif e.status == 403:
|
|
54
|
+
return False, "Access denied - check account ID and permissions"
|
|
55
|
+
else:
|
|
56
|
+
return False, f"API error (status {e.status}): {str(e)}"
|
|
57
|
+
except Exception as e:
|
|
58
|
+
return False, f"Connection error: {str(e)}"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def configure_profile(args, configuration=None):
|
|
62
|
+
"""Configure a profile with credentials"""
|
|
63
|
+
pm = get_profile_manager()
|
|
64
|
+
profile_name = args.profile
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
# Interactive mode
|
|
68
|
+
if args.interactive or (not args.cato_token and not args.account_id and not args.endpoint):
|
|
69
|
+
print(f"Configuring profile '{profile_name}'")
|
|
70
|
+
print("Leave blank to keep existing values (if any)")
|
|
71
|
+
print()
|
|
72
|
+
|
|
73
|
+
# Get current values if profile exists
|
|
74
|
+
current_config = pm.get_profile_config(profile_name) or {}
|
|
75
|
+
|
|
76
|
+
# Get endpoint
|
|
77
|
+
current_endpoint = current_config.get('endpoint', pm.default_endpoint)
|
|
78
|
+
endpoint_input = input(f"Cato API Endpoint [{current_endpoint}]: ").strip()
|
|
79
|
+
endpoint = endpoint_input if endpoint_input else current_endpoint
|
|
80
|
+
|
|
81
|
+
# Get token
|
|
82
|
+
current_token = current_config.get('cato_token', '')
|
|
83
|
+
if current_token:
|
|
84
|
+
token_prompt = f"Cato API Token [****{current_token[-4:]}]: "
|
|
85
|
+
else:
|
|
86
|
+
token_prompt = "Cato API Token: "
|
|
87
|
+
token_input = getpass.getpass(token_prompt).strip()
|
|
88
|
+
cato_token = token_input if token_input else current_token
|
|
89
|
+
|
|
90
|
+
# Get account ID
|
|
91
|
+
current_account = current_config.get('account_id', '')
|
|
92
|
+
account_input = input(f"Account ID [{current_account}]: ").strip()
|
|
93
|
+
account_id = account_input if account_input else current_account
|
|
94
|
+
|
|
95
|
+
else:
|
|
96
|
+
# Non-interactive mode
|
|
97
|
+
endpoint = args.endpoint
|
|
98
|
+
cato_token = getattr(args, 'cato_token', None)
|
|
99
|
+
account_id = getattr(args, 'account_id', None)
|
|
100
|
+
|
|
101
|
+
# Validate required fields
|
|
102
|
+
if not cato_token or not account_id:
|
|
103
|
+
current_config = pm.get_profile_config(profile_name) or {}
|
|
104
|
+
if not cato_token:
|
|
105
|
+
cato_token = current_config.get('cato_token')
|
|
106
|
+
if not account_id:
|
|
107
|
+
account_id = current_config.get('account_id')
|
|
108
|
+
|
|
109
|
+
if not cato_token:
|
|
110
|
+
print("ERROR: Cato API token is required")
|
|
111
|
+
return [{"success": False, "error": "Missing cato_token"}]
|
|
112
|
+
|
|
113
|
+
if not account_id:
|
|
114
|
+
print("ERROR: Account ID is required")
|
|
115
|
+
return [{"success": False, "error": "Missing account_id"}]
|
|
116
|
+
|
|
117
|
+
# Set default endpoint if not provided
|
|
118
|
+
if not endpoint:
|
|
119
|
+
endpoint = pm.default_endpoint
|
|
120
|
+
|
|
121
|
+
# Test credentials before saving (unless validation is skipped)
|
|
122
|
+
if hasattr(args, 'skip_validation') and args.skip_validation:
|
|
123
|
+
print("⚠️ Skipping credential validation")
|
|
124
|
+
else:
|
|
125
|
+
is_valid, error_message = test_credentials(endpoint, cato_token, account_id)
|
|
126
|
+
if not is_valid:
|
|
127
|
+
print(f"ERROR: {error_message}")
|
|
128
|
+
print("Profile not saved. Please check your credentials and try again.")
|
|
129
|
+
print("(Use --skip-validation to save without testing)")
|
|
130
|
+
return [{"success": False, "error": f"Credential validation failed: {error_message}"}]
|
|
131
|
+
|
|
132
|
+
# Create the profile
|
|
133
|
+
success = pm.create_profile(
|
|
134
|
+
profile_name=profile_name,
|
|
135
|
+
endpoint=endpoint,
|
|
136
|
+
cato_token=cato_token,
|
|
137
|
+
account_id=account_id
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
if success:
|
|
141
|
+
print(f"Profile '{profile_name}' configured successfully!")
|
|
142
|
+
if profile_name == 'default' or len(pm.list_profiles()) == 1:
|
|
143
|
+
pm.set_current_profile(profile_name)
|
|
144
|
+
print(f"Set '{profile_name}' as the active profile")
|
|
145
|
+
else:
|
|
146
|
+
print(f"Failed to configure profile '{profile_name}'")
|
|
147
|
+
return [{"success": False, "error": "Failed to create profile"}]
|
|
148
|
+
|
|
149
|
+
return [{"success": True, "profile": profile_name}]
|
|
150
|
+
|
|
151
|
+
except KeyboardInterrupt:
|
|
152
|
+
print("\nOperation cancelled")
|
|
153
|
+
return [{"success": False, "error": "Operation cancelled by user"}]
|
|
154
|
+
except Exception as e:
|
|
155
|
+
print(f"ERROR: {e}")
|
|
156
|
+
return [{"success": False, "error": str(e)}]
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def list_profiles(args, configuration=None):
|
|
160
|
+
"""List all configured profiles"""
|
|
161
|
+
pm = get_profile_manager()
|
|
162
|
+
|
|
163
|
+
try:
|
|
164
|
+
profiles = pm.list_profiles()
|
|
165
|
+
current_profile = pm.get_current_profile()
|
|
166
|
+
|
|
167
|
+
if not profiles:
|
|
168
|
+
print("No profiles configured.")
|
|
169
|
+
print("Run 'catocli configure set' to create your first profile.")
|
|
170
|
+
return [{"success": True, "profiles": []}]
|
|
171
|
+
|
|
172
|
+
print("Available profiles:")
|
|
173
|
+
print()
|
|
174
|
+
|
|
175
|
+
for profile in profiles:
|
|
176
|
+
is_current = profile == current_profile
|
|
177
|
+
status = " (current)" if is_current else ""
|
|
178
|
+
|
|
179
|
+
config = pm.get_profile_config(profile)
|
|
180
|
+
endpoint = config.get('endpoint', 'N/A')
|
|
181
|
+
account_id = config.get('account_id', 'N/A')
|
|
182
|
+
|
|
183
|
+
print(f" {profile}{status}")
|
|
184
|
+
print(f" Endpoint: {endpoint}")
|
|
185
|
+
print(f" Account ID: {account_id}")
|
|
186
|
+
print()
|
|
187
|
+
|
|
188
|
+
return [{"success": True, "profiles": profiles, "current": current_profile}]
|
|
189
|
+
|
|
190
|
+
except Exception as e:
|
|
191
|
+
print(f"ERROR: {e}")
|
|
192
|
+
return [{"success": False, "error": str(e)}]
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def set_profile(args, configuration=None):
|
|
196
|
+
"""Set the active profile"""
|
|
197
|
+
pm = get_profile_manager()
|
|
198
|
+
profile_name = args.profile
|
|
199
|
+
|
|
200
|
+
try:
|
|
201
|
+
# Check if profile exists
|
|
202
|
+
if profile_name not in pm.list_profiles():
|
|
203
|
+
print(f"ERROR: Profile '{profile_name}' does not exist.")
|
|
204
|
+
print("Available profiles:")
|
|
205
|
+
for p in pm.list_profiles():
|
|
206
|
+
print(f" {p}")
|
|
207
|
+
return [{"success": False, "error": "Profile not found"}]
|
|
208
|
+
|
|
209
|
+
# Validate profile has required credentials
|
|
210
|
+
is_valid, message = pm.validate_profile(profile_name)
|
|
211
|
+
if not is_valid:
|
|
212
|
+
print(f"ERROR: {message}")
|
|
213
|
+
print(f"Run 'catocli configure set --profile {profile_name}' to update the profile.")
|
|
214
|
+
return [{"success": False, "error": message}]
|
|
215
|
+
|
|
216
|
+
# Set as current profile
|
|
217
|
+
pm.set_current_profile(profile_name)
|
|
218
|
+
print(f"Switched to profile '{profile_name}'")
|
|
219
|
+
|
|
220
|
+
return [{"success": True, "profile": profile_name}]
|
|
221
|
+
|
|
222
|
+
except Exception as e:
|
|
223
|
+
print(f"ERROR: {e}")
|
|
224
|
+
return [{"success": False, "error": str(e)}]
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def show_profile(args, configuration=None):
|
|
228
|
+
"""Show current profile configuration"""
|
|
229
|
+
pm = get_profile_manager()
|
|
230
|
+
|
|
231
|
+
try:
|
|
232
|
+
profile_name = args.profile if hasattr(args, 'profile') and args.profile else pm.get_current_profile()
|
|
233
|
+
|
|
234
|
+
# Check if profile exists
|
|
235
|
+
config = pm.get_profile_config(profile_name)
|
|
236
|
+
if not config:
|
|
237
|
+
print(f"Profile '{profile_name}' not found.")
|
|
238
|
+
return [{"success": False, "error": "Profile not found"}]
|
|
239
|
+
|
|
240
|
+
print(f"Profile: {profile_name}")
|
|
241
|
+
print(f"Endpoint: {config.get('endpoint', 'N/A')}")
|
|
242
|
+
print(f"Account ID: {config.get('account_id', 'N/A')}")
|
|
243
|
+
|
|
244
|
+
# Show token status without revealing it
|
|
245
|
+
token = config.get('cato_token', '')
|
|
246
|
+
if token:
|
|
247
|
+
print(f"Token: ****{token[-4:]} (configured)")
|
|
248
|
+
else:
|
|
249
|
+
print("Token: (not configured)")
|
|
250
|
+
|
|
251
|
+
# Show if this is the current profile
|
|
252
|
+
current_profile = pm.get_current_profile()
|
|
253
|
+
if profile_name == current_profile:
|
|
254
|
+
print("Status: Current active profile")
|
|
255
|
+
else:
|
|
256
|
+
print(f"Status: Available (current: {current_profile})")
|
|
257
|
+
|
|
258
|
+
# Create masked config for JSON output
|
|
259
|
+
masked_config = config.copy()
|
|
260
|
+
if masked_config.get('cato_token'):
|
|
261
|
+
masked_config['cato_token'] = f"****{masked_config['cato_token'][-4:]}"
|
|
262
|
+
|
|
263
|
+
return [{"success": True, "profile": profile_name, "config": masked_config}]
|
|
264
|
+
|
|
265
|
+
except Exception as e:
|
|
266
|
+
print(f"ERROR: {e}")
|
|
267
|
+
return [{"success": False, "error": str(e)}]
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def delete_profile(args, configuration=None):
|
|
271
|
+
"""Delete a profile"""
|
|
272
|
+
pm = get_profile_manager()
|
|
273
|
+
profile_name = args.profile
|
|
274
|
+
|
|
275
|
+
try:
|
|
276
|
+
# Check if profile exists
|
|
277
|
+
if profile_name not in pm.list_profiles():
|
|
278
|
+
print(f"Profile '{profile_name}' does not exist.")
|
|
279
|
+
return [{"success": False, "error": "Profile not found"}]
|
|
280
|
+
|
|
281
|
+
# Check if it's the current profile
|
|
282
|
+
current_profile = pm.get_current_profile()
|
|
283
|
+
if profile_name == current_profile:
|
|
284
|
+
print(f"Cannot delete the current active profile '{profile_name}'.")
|
|
285
|
+
print("Switch to another profile first using 'catocli configure use <profile>'")
|
|
286
|
+
return [{"success": False, "error": "Cannot delete active profile"}]
|
|
287
|
+
|
|
288
|
+
# Confirm deletion unless forced
|
|
289
|
+
if not args.force:
|
|
290
|
+
response = input(f"Are you sure you want to delete profile '{profile_name}'? (y/N): ").strip().lower()
|
|
291
|
+
if response != 'y':
|
|
292
|
+
print("Deletion cancelled.")
|
|
293
|
+
return [{"success": False, "error": "Deletion cancelled by user"}]
|
|
294
|
+
|
|
295
|
+
# Delete the profile
|
|
296
|
+
success = pm.delete_profile(profile_name)
|
|
297
|
+
if success:
|
|
298
|
+
print(f"Profile '{profile_name}' deleted successfully.")
|
|
299
|
+
else:
|
|
300
|
+
print(f"Failed to delete profile '{profile_name}'.")
|
|
301
|
+
return [{"success": False, "error": "Failed to delete profile"}]
|
|
302
|
+
|
|
303
|
+
return [{"success": True, "deleted_profile": profile_name}]
|
|
304
|
+
|
|
305
|
+
except Exception as e:
|
|
306
|
+
print(f"ERROR: {e}")
|
|
307
|
+
return [{"success": False, "error": str(e)}]
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
import catocli.parsers.custom.customLib as customLib
|
|
3
|
+
from catocli.parsers.custom.export_rules import export_parse
|
|
4
|
+
from catocli.parsers.custom.import_rules_to_tf import import_parse
|
|
5
|
+
from catocli.parsers.configure import configure_parse
|
|
3
6
|
|
|
4
7
|
def custom_parse(subparsers):
|
|
5
8
|
entityTypes = ["account","admin","allocatedIP","any","availablePooledUsage","availableSiteUsage","dhcpRelayGroup","groupSubscription","host","lanFirewall","localRouting","location","mailingListSubscription","networkInterface","portProtocol","simpleService","site","siteRange","timezone","vpnUser","webhookSubscription"]
|
|
@@ -27,6 +30,11 @@ def custom_parse(subparsers):
|
|
|
27
30
|
|
|
28
31
|
item_list_parser.set_defaults(func=customLib.entityTypeList,operation_name=entity)
|
|
29
32
|
|
|
33
|
+
# Add additional custom parsers here
|
|
34
|
+
export_parse(subparsers)
|
|
35
|
+
import_parse(subparsers)
|
|
36
|
+
configure_parse(subparsers)
|
|
37
|
+
|
|
30
38
|
def get_help_custom(path):
|
|
31
39
|
matchCmd = "catocli "+path.replace("_"," ")
|
|
32
40
|
import os
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import catocli.parsers.custom.export_rules.export_rules as export_rules
|
|
2
|
+
|
|
3
|
+
def export_parse(subparsers):
|
|
4
|
+
"""Create export command parsers"""
|
|
5
|
+
|
|
6
|
+
# Create the main export parser
|
|
7
|
+
export_parser = subparsers.add_parser('export', help='Export data to various formats', usage='catocli export <operation> [options]')
|
|
8
|
+
export_subparsers = export_parser.add_subparsers(description='valid export operations', help='additional help')
|
|
9
|
+
|
|
10
|
+
# Add if_rules command
|
|
11
|
+
if_rules_parser = export_subparsers.add_parser(
|
|
12
|
+
'if_rules',
|
|
13
|
+
help='Export Internet Firewall rules to JSON format',
|
|
14
|
+
usage='catocli export if_rules [-accountID <account_id>] [options]'
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
if_rules_parser.add_argument('-accountID', help='Account ID to export rules from (uses CATO_ACCOUNT_ID environment variable if not specified)', required=False)
|
|
18
|
+
if_rules_parser.add_argument('--output-file-path', help='Full path including filename and extension for output file. If not specified, uses default: config_data/all_ifw_rules_and_sections_{account_id}.json')
|
|
19
|
+
if_rules_parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
|
|
20
|
+
|
|
21
|
+
if_rules_parser.set_defaults(func=export_rules.export_if_rules_to_json)
|
|
22
|
+
|
|
23
|
+
# Add wf_rules command
|
|
24
|
+
wf_rules_parser = export_subparsers.add_parser(
|
|
25
|
+
'wf_rules',
|
|
26
|
+
help='Export WAN Firewall rules to JSON format',
|
|
27
|
+
usage='catocli export wf_rules [-accountID <account_id>] [options]'
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
wf_rules_parser.add_argument('-accountID', help='Account ID to export rules from (uses CATO_ACCOUNT_ID environment variable if not specified)', required=False)
|
|
31
|
+
wf_rules_parser.add_argument('--output-file-path', help='Full path including filename and extension for output file. If not specified, uses default: config_data/all_wf_rules_and_sections_{account_id}.json')
|
|
32
|
+
wf_rules_parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
|
|
33
|
+
|
|
34
|
+
wf_rules_parser.set_defaults(func=export_rules.export_wf_rules_to_json)
|
|
35
|
+
|
|
36
|
+
return export_parser
|