Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| Automatically configure GNS3 network topology for SSH access. | |
| This script: | |
| 1. Links switches to the HQ-Building cloud (which has access to Docker bridge) | |
| 2. Configures management IPs on the Docker bridge network (172.18.0.x) | |
| 3. Enables SSH access | |
| 4. Tests connectivity from host | |
| """ | |
| import sys | |
| import json | |
| import telnetlib | |
| import time | |
| import requests | |
| from pathlib import Path | |
| GNS3_SERVER = "http://lab.grahampaasch.com:3080" | |
| PROJECT_ID = "1f712057-b33d-433f-90bb-2b9b3804a95e" | |
| # Docker bridge network on host: 172.18.0.1/16 | |
| # We'll use 172.18.0.10, 172.18.0.20, 172.18.0.30 for switches | |
| SWITCH_CONFIGS = { | |
| 'SW-HQ-Core': { | |
| 'node_id': 'f947ef67-b787-434f-a16d-262780849bbb', | |
| 'console_port': 5046, | |
| 'mgmt_ip': '172.18.0.10', | |
| 'interface': 'GigabitEthernet0/0' # Use Gi0/0 for management | |
| }, | |
| 'SW-West': { | |
| 'node_id': 'b8526171-91a3-4892-b38b-1785506a4875', | |
| 'console_port': 5059, | |
| 'mgmt_ip': '172.18.0.20', | |
| 'interface': 'GigabitEthernet0/0' | |
| }, | |
| 'SW-East': { | |
| 'node_id': '53f10866-e6c4-496f-994e-0fe535df3f23', | |
| 'console_port': 5069, | |
| 'mgmt_ip': '172.18.0.30', | |
| 'interface': 'GigabitEthernet0/0' | |
| }, | |
| } | |
| CLOUD_NODE_ID = "72f75f2b-90cb-4ddb-a345-c250e63dd77f" # HQ-Building cloud | |
| def create_link(switch_node_id, switch_adapter, switch_port, cloud_port=0): | |
| """Create link between switch and cloud connector""" | |
| url = f"{GNS3_SERVER}/v2/projects/{PROJECT_ID}/links" | |
| payload = { | |
| "nodes": [ | |
| { | |
| "node_id": switch_node_id, | |
| "adapter_number": switch_adapter, | |
| "port_number": switch_port | |
| }, | |
| { | |
| "node_id": CLOUD_NODE_ID, | |
| "adapter_number": 0, | |
| "port_number": cloud_port # br-3ef6718405de port | |
| } | |
| ] | |
| } | |
| response = requests.post(url, json=payload) | |
| if response.status_code in [200, 201]: | |
| print(f" ✓ Link created") | |
| return True | |
| elif response.status_code == 409: | |
| print(f" ℹ Link already exists") | |
| return True | |
| else: | |
| print(f" ✗ Failed: {response.text}") | |
| return False | |
| def configure_management_ip(device_name, config): | |
| """Configure management IP via console""" | |
| console_port = config['console_port'] | |
| mgmt_ip = config['mgmt_ip'] | |
| interface = config['interface'] | |
| print(f"\nConfiguring {device_name} ({mgmt_ip})...") | |
| commands = f""" | |
| enable | |
| configure terminal | |
| ! | |
| ! Configure management interface | |
| interface {interface} | |
| description Management - Docker Bridge | |
| no switchport | |
| ip address {mgmt_ip} 255.255.0.0 | |
| no shutdown | |
| ! | |
| ! Add route to host | |
| ip route 0.0.0.0 0.0.0.0 172.18.0.1 | |
| ! | |
| ! Enable SSH | |
| ip domain-name lab.grahampaasch.com | |
| username admin privilege 15 secret cisco | |
| enable secret cisco | |
| ! | |
| line vty 0 4 | |
| login local | |
| transport input ssh | |
| ! | |
| crypto key generate rsa modulus 2048 | |
| ! | |
| end | |
| write memory | |
| """ | |
| try: | |
| tn = telnetlib.Telnet('localhost', console_port, timeout=10) | |
| # Wake up | |
| tn.write(b"\r\n\r\n") | |
| time.sleep(1) | |
| # Send config | |
| for line in commands.strip().split('\n'): | |
| if line.strip() and not line.strip().startswith('!'): | |
| tn.write(line.encode('ascii') + b"\r\n") | |
| time.sleep(0.2) | |
| tn.write(b"\r\n") | |
| time.sleep(2) | |
| output = tn.read_very_eager().decode('ascii', errors='ignore') | |
| tn.close() | |
| print(f" ✓ Management IP configured") | |
| return True | |
| except Exception as e: | |
| print(f" ✗ Error: {e}") | |
| return False | |
| def test_connectivity(ip): | |
| """Test ping to device""" | |
| import subprocess | |
| print(f"\nTesting connectivity to {ip}...") | |
| try: | |
| result = subprocess.run( | |
| ['ping', '-c', '2', '-W', '2', ip], | |
| capture_output=True, | |
| timeout=5 | |
| ) | |
| if result.returncode == 0: | |
| print(f" ✓ Ping successful!") | |
| return True | |
| else: | |
| print(f" ⚠ Ping failed (may need a moment to come up)") | |
| return False | |
| except Exception as e: | |
| print(f" ⚠ Error: {e}") | |
| return False | |
| def test_ssh(ip, username='admin', password='cisco'): | |
| """Test SSH connectivity""" | |
| print(f"\nTesting SSH to {ip}...") | |
| sys.path.insert(0, str(Path(__file__).parent.parent)) | |
| from agent.device_driver import DeviceDriver, DeviceCredentials, DeviceType | |
| driver = DeviceDriver(use_napalm=True) | |
| creds = DeviceCredentials( | |
| hostname=ip, | |
| username=username, | |
| password=password, | |
| device_type=DeviceType.CISCO_IOS, | |
| timeout=10 | |
| ) | |
| conn = driver.connect(creds) | |
| if conn.status.value == 'connected': | |
| print(f" ✅ SSH working! Stage 6 ready!") | |
| driver.disconnect(ip) | |
| return True | |
| else: | |
| print(f" ⚠ SSH not ready: {conn.last_error}") | |
| return False | |
| def main(): | |
| """Main entry point""" | |
| print("\n" + "="*70) | |
| print("Automatic GNS3 Network Configuration for SSH Access") | |
| print("="*70) | |
| print("\nThis will automatically:") | |
| print(" 1. Link switches to Docker bridge (172.18.0.1/16)") | |
| print(" 2. Configure management IPs (172.18.0.10/20/30)") | |
| print(" 3. Enable SSH access") | |
| print(" 4. Test connectivity") | |
| print("\nNo manual configuration required!") | |
| response = input("\nProceed? (yes/no): ") | |
| if response.lower() != 'yes': | |
| print("Aborted.") | |
| return 1 | |
| print("\n" + "="*70) | |
| print("Step 1: Creating Network Links") | |
| print("="*70) | |
| # Create links to cloud connector (Docker bridge) | |
| for name, config in SWITCH_CONFIGS.items(): | |
| print(f"\n{name}:") | |
| # Adapter 0, Port 0 (Gi0/0) connects to cloud port 0 (br-3ef6718405de) | |
| create_link(config['node_id'], 0, 0, cloud_port=0) | |
| print("\n" + "="*70) | |
| print("Step 2: Configuring Management IPs") | |
| print("="*70) | |
| # Configure management IPs | |
| success_count = 0 | |
| for name, config in SWITCH_CONFIGS.items(): | |
| if configure_management_ip(name, config): | |
| success_count += 1 | |
| print(f"\n✓ Configured {success_count}/{len(SWITCH_CONFIGS)} devices") | |
| print("\n" + "="*70) | |
| print("Step 3: Waiting for Interfaces to Come Up") | |
| print("="*70) | |
| print("\n⏳ Waiting 15 seconds for network to stabilize...") | |
| time.sleep(15) | |
| print("\n" + "="*70) | |
| print("Step 4: Testing Connectivity") | |
| print("="*70) | |
| # Test connectivity | |
| reachable = [] | |
| for name, config in SWITCH_CONFIGS.items(): | |
| if test_connectivity(config['mgmt_ip']): | |
| reachable.append(name) | |
| print(f"\n✓ {len(reachable)}/{len(SWITCH_CONFIGS)} devices reachable") | |
| if reachable: | |
| print("\n⏳ Waiting 10 more seconds for SSH to start...") | |
| time.sleep(10) | |
| print("\n" + "="*70) | |
| print("Step 5: Testing SSH Access") | |
| print("="*70) | |
| ssh_ready = [] | |
| for name, config in SWITCH_CONFIGS.items(): | |
| if test_ssh(config['mgmt_ip']): | |
| ssh_ready.append(name) | |
| print("\n" + "="*70) | |
| print("Configuration Complete!") | |
| print("="*70) | |
| if ssh_ready: | |
| print(f"\n🎉 SUCCESS! {len(ssh_ready)}/{len(SWITCH_CONFIGS)} devices ready for SSH deployment!") | |
| print("\nManagement IPs:") | |
| for name, config in SWITCH_CONFIGS.items(): | |
| status = "✅" if name in ssh_ready else "⏳" | |
| print(f" {status} {name:15s}: {config['mgmt_ip']}") | |
| print("\n" + "="*70) | |
| print("Next Steps:") | |
| print("="*70) | |
| print("\n1. Update examples/deploy_to_gns3_lab.py with these IPs:") | |
| print("\nGNS3_DEVICES = [") | |
| for name, config in SWITCH_CONFIGS.items(): | |
| print(f" {{'name': '{name}', 'hostname': '{config['mgmt_ip']}', ...}},") | |
| print("]") | |
| print("\n2. Test deployment:") | |
| print(" python examples/deploy_to_gns3_lab.py --device SW-HQ-Core --dry-run") | |
| print("\n3. Deploy to all:") | |
| print(" python examples/deploy_to_gns3_lab.py --all --production") | |
| return 0 | |
| else: | |
| print("\n⚠ SSH not ready yet. Give it a few more minutes and try:") | |
| print(" ssh admin@172.18.0.10 (password: cisco)") | |
| return 1 | |
| else: | |
| print("\n⚠ Devices not reachable. Check:") | |
| print(" 1. GNS3 project is open") | |
| print(" 2. Devices are started") | |
| print(" 3. Docker bridge network (172.18.0.1/16) is accessible") | |
| return 1 | |
| if __name__ == '__main__': | |
| try: | |
| sys.exit(main()) | |
| except KeyboardInterrupt: | |
| print("\n\nAborted by user") | |
| sys.exit(1) | |
| except Exception as e: | |
| print(f"\n❌ Error: {e}") | |
| import traceback | |
| traceback.print_exc() | |
| sys.exit(1) | |