232 lines
7.0 KiB
Python
232 lines
7.0 KiB
Python
"""CLI command generators for Cisco devices"""
|
|
from typing import List, Dict, Any, Optional
|
|
|
|
|
|
def generate_hostname_cli(hostname: str) -> List[str]:
|
|
"""Generate hostname configuration command"""
|
|
return [f"hostname {hostname}"]
|
|
|
|
|
|
def generate_vlan_cli(vlans: List[Dict[str, Any]]) -> List[str]:
|
|
"""
|
|
Generate VLAN configuration commands
|
|
|
|
Args:
|
|
vlans: List of dicts with keys:
|
|
- id (int)
|
|
- name (str)
|
|
|
|
Returns:
|
|
List of CLI commands
|
|
"""
|
|
commands = []
|
|
for vlan in vlans:
|
|
vlan_id = vlan.get("id")
|
|
vlan_name = vlan.get("name", f"VLAN{vlan_id}")
|
|
|
|
commands.append(f"vlan {vlan_id}")
|
|
commands.append(f" name {vlan_name}")
|
|
commands.append("!")
|
|
|
|
return commands
|
|
|
|
|
|
def generate_interface_cli(interfaces: List[Dict[str, Any]]) -> List[str]:
|
|
"""
|
|
Generate interface configuration commands
|
|
|
|
Args:
|
|
interfaces: List of dicts with keys:
|
|
- name (str): e.g., "GigabitEthernet0/1"
|
|
- description (str)
|
|
- type (str): "access" or "trunk"
|
|
- vlan (int): VLAN ID for access ports
|
|
- trunk_vlans (list): VLAN IDs for trunk
|
|
- ip_address (str): IP address (e.g., "10.0.0.1/24")
|
|
- enabled (bool)
|
|
|
|
Returns:
|
|
List of CLI commands
|
|
"""
|
|
commands = []
|
|
for iface in interfaces:
|
|
iface_name = iface.get("name")
|
|
description = iface.get("description")
|
|
iface_type = iface.get("type", "access")
|
|
enabled = iface.get("enabled", True)
|
|
|
|
commands.append(f"interface {iface_name}")
|
|
|
|
if description:
|
|
commands.append(f" description {description}")
|
|
|
|
# Switchport configuration
|
|
if iface_type == "access":
|
|
commands.append(" switchport mode access")
|
|
vlan = iface.get("vlan")
|
|
if vlan:
|
|
commands.append(f" switchport access vlan {vlan}")
|
|
elif iface_type == "trunk":
|
|
commands.append(" switchport mode trunk")
|
|
trunk_vlans = iface.get("trunk_vlans")
|
|
if trunk_vlans:
|
|
vlan_list = ",".join(map(str, trunk_vlans))
|
|
commands.append(f" switchport trunk allowed vlan {vlan_list}")
|
|
|
|
# IP configuration
|
|
ip_address = iface.get("ip_address")
|
|
if ip_address:
|
|
# Assume CIDR notation, convert to netmask
|
|
# e.g., "10.0.0.1/24" -> "10.0.0.1 255.255.255.0"
|
|
commands.append(f" ip address {ip_address.replace('/', ' ')}")
|
|
|
|
# Enable/disable
|
|
if not enabled:
|
|
commands.append(" shutdown")
|
|
else:
|
|
commands.append(" no shutdown")
|
|
|
|
commands.append("!")
|
|
|
|
return commands
|
|
|
|
|
|
def generate_routing_cli(routes: List[Dict[str, Any]]) -> List[str]:
|
|
"""
|
|
Generate static routing commands
|
|
|
|
Args:
|
|
routes: List of dicts with keys:
|
|
- destination (str): CIDR notation
|
|
- gateway (str): Next-hop IP
|
|
- metric (int): Optional metric/distance
|
|
|
|
Returns:
|
|
List of CLI commands
|
|
"""
|
|
commands = []
|
|
for route in routes:
|
|
destination = route.get("destination")
|
|
gateway = route.get("gateway")
|
|
metric = route.get("metric")
|
|
|
|
cmd = f"ip route {destination} {gateway}"
|
|
if metric:
|
|
cmd += f" {metric}"
|
|
|
|
commands.append(cmd)
|
|
|
|
return commands
|
|
|
|
|
|
def generate_nat_cli(nat_config: Dict[str, Any]) -> List[str]:
|
|
"""
|
|
Generate NAT (Network Address Translation) commands
|
|
|
|
Args:
|
|
nat_config: Dict with keys:
|
|
- inside_interface (str): Inside interface name
|
|
- outside_interface (str): Outside interface name
|
|
- inside_addresses (list): List of inside networks in CIDR
|
|
- outside_address (str): Single public IP for overload
|
|
|
|
Returns:
|
|
List of CLI commands
|
|
"""
|
|
commands = []
|
|
|
|
# Mark inside/outside interfaces
|
|
inside_iface = nat_config.get("inside_interface")
|
|
outside_iface = nat_config.get("outside_interface")
|
|
|
|
if inside_iface:
|
|
commands.append(f"interface {inside_iface}")
|
|
commands.append(" ip nat inside")
|
|
commands.append("!")
|
|
|
|
if outside_iface:
|
|
commands.append(f"interface {outside_iface}")
|
|
commands.append(" ip nat outside")
|
|
commands.append("!")
|
|
|
|
# NAT rules
|
|
inside_addresses = nat_config.get("inside_addresses", [])
|
|
outside_address = nat_config.get("outside_address")
|
|
|
|
for idx, inside_network in enumerate(inside_addresses, start=1):
|
|
acl_id = 100 + idx
|
|
commands.append(f"ip access-list standard NAT_INSIDE")
|
|
commands.append(f" {idx} permit {inside_network}")
|
|
commands.append("!")
|
|
|
|
if outside_address:
|
|
commands.append("ip nat inside source list 101 interface GigabitEthernet0/0 overload")
|
|
|
|
return commands
|
|
|
|
|
|
def generate_acl_cli(acls: List[Dict[str, Any]]) -> List[str]:
|
|
"""
|
|
Generate ACL (Access Control List) commands
|
|
|
|
Args:
|
|
acls: List of dicts with keys:
|
|
- name (str) or acl_id (int)
|
|
- type (str): "standard" or "extended"
|
|
- rules (list): List of dicts:
|
|
- action (str): "permit" or "deny"
|
|
- protocol (str): "ip", "tcp", "udp", etc.
|
|
- source (str): IP/CIDR or "any"
|
|
- destination (str): IP/CIDR (extended only)
|
|
- port (int): Port number (extended + protocol-specific)
|
|
|
|
Returns:
|
|
List of CLI commands
|
|
"""
|
|
commands = []
|
|
|
|
for acl in acls:
|
|
acl_type = acl.get("type", "standard")
|
|
acl_name = acl.get("name")
|
|
acl_id = acl.get("acl_id")
|
|
|
|
# ACL header
|
|
if acl_type == "standard":
|
|
if acl_id:
|
|
acl_header = f"access-list {acl_id}"
|
|
else:
|
|
acl_header = f"ip access-list standard {acl_name}"
|
|
else: # extended
|
|
if acl_id:
|
|
acl_header = f"access-list {acl_id}"
|
|
else:
|
|
acl_header = f"ip access-list extended {acl_name}"
|
|
|
|
# If named ACL, enter config mode
|
|
if acl_name:
|
|
commands.append(acl_header)
|
|
|
|
# ACL rules
|
|
for rule_idx, rule in enumerate(acl.get("rules", []), start=1):
|
|
action = rule.get("action", "permit")
|
|
protocol = rule.get("protocol", "ip")
|
|
source = rule.get("source", "any")
|
|
|
|
if acl_type == "standard":
|
|
cmd = f" {rule_idx} {action} {source}"
|
|
else: # extended
|
|
destination = rule.get("destination", "any")
|
|
cmd = f" {rule_idx} {action} {protocol} {source} {destination}"
|
|
|
|
# Add port if applicable
|
|
port = rule.get("port")
|
|
if port:
|
|
cmd += f" eq {port}"
|
|
|
|
commands.append(cmd)
|
|
|
|
if acl_name:
|
|
commands.append("!")
|
|
|
|
return commands
|