Spaces:
Running
Running
| #!/usr/bin/env python3 | |
| """ | |
| Rebuild CCNA topology with REAL Cisco IOSvL2 switches | |
| Full IOS CLI, VLAN support, trunking - the complete CCNA experience! | |
| """ | |
| import requests | |
| import json | |
| import time | |
| import os | |
| GNS3_SERVER = os.getenv("GNS3_SERVER", "http://localhost:3080") | |
| GNS3_API = f"{GNS3_SERVER}/v2" | |
| PROJECT_NAME = os.getenv("GNS3_PROJECT_NAME", "overgrowth") | |
| IOSVL2_TEMPLATE_ID = "25dd7340-2e92-4e45-83de-f88077a24ceb" | |
| def get_project_id(name): | |
| resp = requests.get(f"{GNS3_API}/projects") | |
| projects = resp.json() | |
| project = next((p for p in projects if p['name'] == name), None) | |
| return project['project_id'] if project else None | |
| def delete_all_nodes(project_id): | |
| resp = requests.get(f"{GNS3_API}/projects/{project_id}/nodes") | |
| nodes = resp.json() | |
| print(f"Cleaning up {len(nodes)} existing nodes...") | |
| for node in nodes: | |
| requests.delete(f"{GNS3_API}/projects/{project_id}/nodes/{node['node_id']}") | |
| time.sleep(1) | |
| def create_iosvl2_switch(project_id, name, x, y): | |
| """Create a Cisco IOSvL2 switch""" | |
| data = { | |
| "name": name, | |
| "node_type": "qemu", | |
| "compute_id": "local", | |
| "template_id": IOSVL2_TEMPLATE_ID, | |
| "properties": { | |
| "qemu_path": "/usr/bin/qemu-system-x86_64", | |
| "platform": "x86_64", | |
| "adapters": 16, # CRITICAL: 16 Gigabit Ethernet ports! | |
| "ram": 1024, | |
| "hda_disk_image": "vios_l2-adventerprisek9-m.03.2017.qcow2" | |
| }, | |
| "x": x, | |
| "y": y | |
| } | |
| resp = requests.post(f"{GNS3_API}/projects/{project_id}/nodes", json=data) | |
| if resp.status_code in [200, 201]: | |
| return resp.json() | |
| else: | |
| print(f" Error creating {name}: {resp.status_code} - {resp.text}") | |
| return None | |
| def create_vpcs(project_id, name, x, y): | |
| """Create a VPCS (Virtual PC)""" | |
| data = { | |
| "name": name, | |
| "node_type": "vpcs", | |
| "compute_id": "local", | |
| "x": x, | |
| "y": y | |
| } | |
| resp = requests.post(f"{GNS3_API}/projects/{project_id}/nodes", json=data) | |
| return resp.json() if resp.status_code in [200, 201] else None | |
| def create_link(project_id, node1_id, adapter1, port1, node2_id, adapter2, port2, desc=""): | |
| data = { | |
| "nodes": [ | |
| {"node_id": node1_id, "adapter_number": adapter1, "port_number": port1}, | |
| {"node_id": node2_id, "adapter_number": adapter2, "port_number": port2} | |
| ] | |
| } | |
| resp = requests.post(f"{GNS3_API}/projects/{project_id}/links", json=data) | |
| if resp.status_code in [200, 201]: | |
| print(f" β {desc}") | |
| return True | |
| else: | |
| print(f" β {desc} - {resp.status_code}") | |
| return False | |
| def main(): | |
| project_id = get_project_id(PROJECT_NAME) | |
| if not project_id: | |
| print(f"Project '{PROJECT_NAME}' not found!") | |
| return | |
| print("="*70) | |
| print("REBUILDING CCNA TOPOLOGY WITH CISCO IOSvL2 SWITCHES") | |
| print("="*70) | |
| print() | |
| delete_all_nodes(project_id) | |
| print("Creating Cisco IOSvL2 Switches (this may take a moment)...") | |
| nodes = {} | |
| # Create 3 Cisco IOSvL2 switches | |
| nodes['SW1'] = create_iosvl2_switch(project_id, "SW1-Access", -300, 0) | |
| if nodes['SW1']: | |
| print(f" β SW1-Access (Cisco IOSvL2) - VLAN 10") | |
| time.sleep(2) | |
| nodes['SW2'] = create_iosvl2_switch(project_id, "SW2-Core", 0, 0) | |
| if nodes['SW2']: | |
| print(f" β SW2-Core (Cisco IOSvL2) - Trunk/Core") | |
| time.sleep(2) | |
| nodes['SW3'] = create_iosvl2_switch(project_id, "SW3-Access", 300, 0) | |
| if nodes['SW3']: | |
| print(f" β SW3-Access (Cisco IOSvL2) - VLAN 20") | |
| time.sleep(2) | |
| print("\nCreating Virtual PCs (VPCS)...") | |
| nodes['PC1'] = create_vpcs(project_id, "PC1-Sales", -400, -100) | |
| if nodes['PC1']: print(f" β PC1-Sales") | |
| time.sleep(0.3) | |
| nodes['PC2'] = create_vpcs(project_id, "PC2-Sales", -400, 100) | |
| if nodes['PC2']: print(f" β PC2-Sales") | |
| time.sleep(0.3) | |
| nodes['PC3'] = create_vpcs(project_id, "PC3-Engineering", -100, -100) | |
| if nodes['PC3']: print(f" β PC3-Engineering") | |
| time.sleep(0.3) | |
| nodes['PC4'] = create_vpcs(project_id, "PC4-Engineering", 100, -100) | |
| if nodes['PC4']: print(f" β PC4-Engineering") | |
| time.sleep(0.3) | |
| nodes['PC5'] = create_vpcs(project_id, "PC5-Guest", 400, -100) | |
| if nodes['PC5']: print(f" β PC5-Guest") | |
| time.sleep(0.3) | |
| nodes['PC6'] = create_vpcs(project_id, "PC6-Guest", 400, 100) | |
| if nodes['PC6']: print(f" β PC6-Guest") | |
| time.sleep(0.3) | |
| # Re-fetch all node IDs to ensure we have fresh data | |
| print("\nRefreshing node IDs...") | |
| resp = requests.get(f"{GNS3_API}/projects/{project_id}/nodes") | |
| all_nodes = resp.json() | |
| node_map = {n['name']: n for n in all_nodes} | |
| # Update nodes dict with refreshed IDs | |
| for name in nodes.keys(): | |
| if name in node_map: | |
| nodes[name] = node_map[name] | |
| print("\nCreating Network Links...") | |
| links = 0 | |
| # PC1 -> SW1 | |
| if nodes.get('PC1') and nodes.get('SW1'): | |
| if create_link(project_id, nodes['PC1']['node_id'], 0, 0, | |
| nodes['SW1']['node_id'], 0, 0, | |
| "PC1-Sales β SW1 Gi0/0"): | |
| links += 1 | |
| # PC2 -> SW1 | |
| if nodes.get('PC2') and nodes.get('SW1'): | |
| if create_link(project_id, nodes['PC2']['node_id'], 0, 0, | |
| nodes['SW1']['node_id'], 0, 1, | |
| "PC2-Sales β SW1 Gi0/1"): | |
| links += 1 | |
| # SW1 -> SW2 (Trunk) | |
| if nodes.get('SW1') and nodes.get('SW2'): | |
| if create_link(project_id, nodes['SW1']['node_id'], 1, 0, | |
| nodes['SW2']['node_id'], 1, 0, | |
| "SW1 Gi1/0 β SW2 Gi1/0 (TRUNK)"): | |
| links += 1 | |
| # PC3 -> SW2 | |
| if nodes.get('PC3') and nodes.get('SW2'): | |
| if create_link(project_id, nodes['PC3']['node_id'], 0, 0, | |
| nodes['SW2']['node_id'], 0, 1, | |
| "PC3-Engineering β SW2 Gi0/1"): | |
| links += 1 | |
| # PC4 -> SW2 | |
| if nodes.get('PC4') and nodes.get('SW2'): | |
| if create_link(project_id, nodes['PC4']['node_id'], 0, 0, | |
| nodes['SW2']['node_id'], 0, 2, | |
| "PC4-Engineering β SW2 Gi0/2"): | |
| links += 1 | |
| # SW2 -> SW3 (Trunk) | |
| if nodes.get('SW2') and nodes.get('SW3'): | |
| if create_link(project_id, nodes['SW2']['node_id'], 1, 1, | |
| nodes['SW3']['node_id'], 1, 0, | |
| "SW2 Gi1/1 β SW3 Gi1/0 (TRUNK)"): | |
| links += 1 | |
| # PC5 -> SW3 | |
| if nodes.get('PC5') and nodes.get('SW3'): | |
| if create_link(project_id, nodes['PC5']['node_id'], 0, 0, | |
| nodes['SW3']['node_id'], 0, 0, | |
| "PC5-Guest β SW3 Gi0/0"): | |
| links += 1 | |
| # PC6 -> SW3 | |
| if nodes.get('PC6') and nodes.get('SW3'): | |
| if create_link(project_id, nodes['PC6']['node_id'], 0, 0, | |
| nodes['SW3']['node_id'], 0, 1, | |
| "PC6-Guest β SW3 Gi0/1"): | |
| links += 1 | |
| print("\n" + "="*70) | |
| print("β CCNA TOPOLOGY CREATED WITH REAL CISCO SWITCHES!") | |
| print("="*70) | |
| print(f"\nDevices: {len([n for n in nodes.values() if n])}") | |
| print(f" - 3x Cisco IOSvL2 switches (full IOS CLI)") | |
| print(f" - 6x VPCS (virtual PCs)") | |
| print(f"Links: {links} connections") | |
| print("\n" + "="*70) | |
| print("π CCNA LAB CONFIGURATION GUIDE") | |
| print("="*70) | |
| print("\nπ Step 1: Start all devices in GNS3 GUI") | |
| print(" (Switches will take 1-2 minutes to boot)") | |
| print("\nπ Step 2: Configure VLANs on each switch") | |
| print("\nOn SW1-Access (console):") | |
| print("```") | |
| print("enable") | |
| print("configure terminal") | |
| print("vlan 10") | |
| print(" name Sales") | |
| print(" exit") | |
| print("interface range GigabitEthernet0/0 - 1") | |
| print(" switchport mode access") | |
| print(" switchport access vlan 10") | |
| print(" no shutdown") | |
| print(" exit") | |
| print("interface GigabitEthernet1/0") | |
| print(" switchport trunk encapsulation dot1q") | |
| print(" switchport mode trunk") | |
| print(" no shutdown") | |
| print(" exit") | |
| print("end") | |
| print("write memory") | |
| print("```") | |
| print("\nOn SW2-Core (console):") | |
| print("```") | |
| print("enable") | |
| print("configure terminal") | |
| print("vlan 10") | |
| print(" name Sales") | |
| print("vlan 20") | |
| print(" name Engineering") | |
| print(" exit") | |
| print("interface range GigabitEthernet0/1 - 2") | |
| print(" switchport mode access") | |
| print(" switchport access vlan 20") | |
| print(" no shutdown") | |
| print(" exit") | |
| print("interface range GigabitEthernet1/0 - 1") | |
| print(" switchport trunk encapsulation dot1q") | |
| print(" switchport mode trunk") | |
| print(" no shutdown") | |
| print(" exit") | |
| print("end") | |
| print("write memory") | |
| print("```") | |
| print("\nOn SW3-Access (console):") | |
| print("```") | |
| print("enable") | |
| print("configure terminal") | |
| print("vlan 20") | |
| print(" name Engineering") | |
| print(" exit") | |
| print("interface range GigabitEthernet0/0 - 1") | |
| print(" switchport mode access") | |
| print(" switchport access vlan 20") | |
| print(" no shutdown") | |
| print(" exit") | |
| print("interface GigabitEthernet1/0") | |
| print(" switchport trunk encapsulation dot1q") | |
| print(" switchport mode trunk") | |
| print(" no shutdown") | |
| print(" exit") | |
| print("end") | |
| print("write memory") | |
| print("```") | |
| print("\nπ Step 3: Configure PC IP addresses") | |
| print("\nPC1: ip 10.1.10.10/24 10.1.10.1") | |
| print("PC2: ip 10.1.10.11/24 10.1.10.1") | |
| print("PC3: ip 10.1.20.10/24 10.1.20.1") | |
| print("PC4: ip 10.1.20.11/24 10.1.20.1") | |
| print("PC5: ip 10.1.30.10/24 10.1.30.1") | |
| print("PC6: ip 10.1.30.11/24 10.1.30.1") | |
| print("\nπ Step 4: Verify VLAN configuration") | |
| print("\nOn any switch:") | |
| print(" show vlan brief") | |
| print(" show interfaces trunk") | |
| print(" show mac address-table") | |
| print("\nπ Step 5: Test connectivity") | |
| print(" PC1 ping PC2 (same VLAN - should work!)") | |
| print(" PC3 ping PC4 (same VLAN - should work!)") | |
| print(" PC1 ping PC3 (different VLANs - will fail without router)") | |
| print("\n⨠Now you have a REAL CCNA switching lab!") | |
| print(" Full IOS CLI, VLANs, trunking, and all CCNA features!") | |
| print("="*70) | |
| if __name__ == "__main__": | |
| main() | |