""" Integrated network operations - combines local GNS3/device management with external network change simulation """ from typing import List, Dict, Tuple, Optional import os import logging from .local_mcp import get_mcp_client from . import mcp_client # Keep existing NCS simulator client from .topology_diagram import ( generate_ascii_diagram, generate_mermaid_diagram, generate_topology_summary ) logger = logging.getLogger(__name__) def get_lab_topology(project_name: str = "overgrowth") -> Dict: """ Get actual lab topology from local GNS3 server Returns topology with nodes, links, device status, and diagrams """ client = get_mcp_client() try: logger.info(f"Fetching topology for project: {project_name}") topology = client.get_topology(project_name) # Add diagrams topology['ascii_diagram'] = generate_ascii_diagram(topology) topology['mermaid_diagram'] = generate_mermaid_diagram(topology) topology['summary'] = generate_topology_summary(topology) logger.info(f"Successfully fetched topology with {len(topology.get('nodes', []))} nodes") return topology except Exception as e: logger.error(f"Failed to get topology: {str(e)}") # Graceful fallback return { "error": str(e), "project": project_name, "nodes": [], "links": [], "ascii_diagram": f"Error: {str(e)}", "mermaid_diagram": "graph TD\n A[Error Loading Topology]", "summary": f"**Error:** {str(e)}" } def get_lab_projects() -> List[Dict]: """Get list of all GNS3 projects""" client = get_mcp_client() try: return client.get_projects() except Exception as e: return [{"error": str(e)}] def manage_device(action: str, project_name: str, device_name: str) -> Dict: """ Start or stop a network device Args: action: "start" or "stop" project_name: GNS3 project name device_name: Device name in project Returns: Status dict with success/error info """ client = get_mcp_client() try: if action == "start": success = client.start_device(project_name, device_name) elif action == "stop": success = client.stop_device(project_name, device_name) else: return {"success": False, "error": f"Unknown action: {action}"} return { "success": success, "action": action, "device": device_name, "project": project_name } except Exception as e: return { "success": False, "error": str(e), "action": action, "device": device_name } def get_device_configuration(host: str, username: str = "admin") -> Dict: """ Get running configuration from a device Args: host: Device IP/hostname username: SSH username Returns: Dict with config text or error """ client = get_mcp_client() try: config = client.get_device_config(host, username) return { "success": True, "host": host, "config": config } except Exception as e: return { "success": False, "host": host, "error": str(e) } def configure_device(host: str, commands: List[str], username: str = "admin") -> Dict: """ Send configuration commands to a device Args: host: Device IP/hostname commands: List of config commands username: SSH username Returns: Dict with output or error """ client = get_mcp_client() try: output = client.configure_device(host, commands, username) return { "success": True, "host": host, "commands": commands, "output": output } except Exception as e: return { "success": False, "host": host, "error": str(e) } def backup_device_config(host: str, device_name: str, username: str = "admin") -> Dict: """ Backup device configuration to timestamped file Args: host: Device IP or hostname device_name: Name for the backup username: SSH username Returns: Dict with success status and backup info """ client = get_mcp_client() try: result = client.call_tool( "backup_device_config", { "host": host, "device_name": device_name, "username": username } ) return result except Exception as e: # Some deployments still expose the older name; try it as a fallback. try: result = client.call_tool( "backup_config", { "host": host, "device_name": device_name, "username": username } ) return result except Exception: return {"success": False, "error": str(e)} def build_network_from_description(description: str, project_name: str = "overgrowth", auto_configure: bool = True) -> Dict: """ Build a complete network from natural language description This calls the MCP tool that: 1. Creates GNS3 topology based on description 2. Auto-configures all devices (if auto_configure=True) 3. Returns complete network info Args: description: Natural language description of network needs project_name: GNS3 project name (default: overgrowth) auto_configure: Whether to auto-configure devices (default: True) Returns: Dict with success status, topology info, and configuration results """ client = get_mcp_client() try: result = client.call_tool( "build_network_from_description", { "description": description, "project_name": project_name, "auto_configure": auto_configure } ) return result except Exception as e: return {"success": False, "error": str(e)} def simulate_change(steps: List[Dict]) -> Tuple[List[Dict], List[Dict]]: """ Wrapper for backward compatibility """ return simulate_network_change_with_ncs(steps) # Keep existing NCS simulator integration def simulate_network_change_with_ncs(steps: List[Dict]) -> Tuple[List[Dict], List[Dict]]: """ Use external Network Change Simulator for risk analysis This keeps the hackathon demo functionality working """ return mcp_client.simulate_steps_with_mcp(steps)