Spaces:
Running
Running
| #!/usr/bin/env python3 | |
| """ | |
| Create a CCNA-level topology in the overgrowth GNS3 project | |
| Classic topology: 2 routers + 2 switches + 2 PCs | |
| """ | |
| import requests | |
| import json | |
| import time | |
| import sys | |
| 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") | |
| def get_project_id(name): | |
| """Get project ID by 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): | |
| """Delete all existing nodes""" | |
| resp = requests.get(f"{GNS3_API}/projects/{project_id}/nodes") | |
| nodes = resp.json() | |
| print(f"Deleting {len(nodes)} existing nodes...") | |
| for node in nodes: | |
| requests.delete(f"{GNS3_API}/projects/{project_id}/nodes/{node['node_id']}") | |
| print(f" Deleted {node['name']}") | |
| time.sleep(1) | |
| def get_templates(): | |
| """Get available templates""" | |
| resp = requests.get(f"{GNS3_API}/templates") | |
| return resp.json() | |
| def find_template(templates, keywords): | |
| """Find template matching keywords""" | |
| for t in templates: | |
| name = t.get('name', '').lower() | |
| for kw in keywords: | |
| if kw.lower() in name: | |
| return t | |
| return None | |
| def create_node(project_id, name, x, y, template=None, node_type=None): | |
| """Create a node""" | |
| data = { | |
| "name": name, | |
| "compute_id": "local", | |
| "x": x, | |
| "y": y | |
| } | |
| if template: | |
| data["node_type"] = template.get('template_type', 'qemu') | |
| data["template_id"] = template['template_id'] | |
| elif node_type: | |
| data["node_type"] = node_type | |
| try: | |
| 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 | |
| except Exception as e: | |
| print(f" Error creating {name}: {e}") | |
| return None | |
| def create_link(project_id, node1_id, adapter1, port1, node2_id, adapter2, port2): | |
| """Create a link between two nodes""" | |
| data = { | |
| "nodes": [ | |
| { | |
| "node_id": node1_id, | |
| "adapter_number": adapter1, | |
| "port_number": port1 | |
| }, | |
| { | |
| "node_id": node2_id, | |
| "adapter_number": adapter2, | |
| "port_number": port2 | |
| } | |
| ] | |
| } | |
| try: | |
| resp = requests.post( | |
| f"{GNS3_API}/projects/{project_id}/links", | |
| json=data | |
| ) | |
| return resp.json() if resp.status_code in [200, 201] else None | |
| except Exception as e: | |
| print(f" Link error: {e}") | |
| return None | |
| def main(): | |
| # Get project | |
| project_id = get_project_id(PROJECT_NAME) | |
| if not project_id: | |
| print(f"Project '{PROJECT_NAME}' not found!") | |
| return | |
| print(f"Working with project: {PROJECT_NAME} ({project_id})") | |
| # Clean up existing nodes | |
| delete_all_nodes(project_id) | |
| # Get templates | |
| print("\nFetching templates...") | |
| templates = get_templates() | |
| # Look for IOSv router template | |
| router_template = find_template(templates, ['IOSv', 'cisco ios', 'c7200']) | |
| if router_template: | |
| print(f" Found router: {router_template['name']}") | |
| # Look for IOSvL2 switch template | |
| switch_template = find_template(templates, ['IOSvL2', 'iosvl2', 'l2-ios']) | |
| if switch_template: | |
| print(f" Found switch: {switch_template['name']}") | |
| # VPCS for PCs | |
| vpcs_template = find_template(templates, ['VPCS', 'vpcs']) | |
| if vpcs_template: | |
| print(f" Found PC: {vpcs_template['name']}") | |
| print("\n" + "="*60) | |
| print("Creating CCNA Topology") | |
| print("="*60) | |
| print(""" | |
| Topology Design: | |
| PC1 PC2 | |
| | | | |
| [Switch1]---[Router1]---[Router2]---[Switch2] | |
| | | | |
| PC3 PC4 | |
| - 2 Routers (R1, R2) connected via serial/ethernet | |
| - 2 Switches (SW1, SW2) one per router | |
| - 4 PCs (PC1-4) for testing connectivity | |
| """) | |
| print("="*60 + "\n") | |
| nodes = {} | |
| # Create Router 1 (left side) | |
| if router_template: | |
| print("Creating Router1...") | |
| nodes['R1'] = create_node(project_id, "R1", -200, -50, template=router_template) | |
| if nodes['R1']: | |
| print(f" β Created {nodes['R1']['name']}") | |
| time.sleep(1) | |
| # Create Router 2 (right side) | |
| if router_template: | |
| print("Creating Router2...") | |
| nodes['R2'] = create_node(project_id, "R2", 200, -50, template=router_template) | |
| if nodes['R2']: | |
| print(f" β Created {nodes['R2']['name']}") | |
| time.sleep(1) | |
| # Create Switch 1 (left) | |
| if switch_template: | |
| print("Creating Switch1...") | |
| nodes['SW1'] = create_node(project_id, "SW1", -200, 100, template=switch_template) | |
| if nodes['SW1']: | |
| print(f" β Created {nodes['SW1']['name']}") | |
| time.sleep(1) | |
| else: | |
| # Fallback to ethernet switch | |
| print("Creating Switch1 (ethernet switch)...") | |
| nodes['SW1'] = create_node(project_id, "SW1", -200, 100, node_type="ethernet_switch") | |
| if nodes['SW1']: | |
| print(f" β Created {nodes['SW1']['name']}") | |
| time.sleep(1) | |
| # Create Switch 2 (right) | |
| if switch_template: | |
| print("Creating Switch2...") | |
| nodes['SW2'] = create_node(project_id, "SW2", 200, 100, template=switch_template) | |
| if nodes['SW2']: | |
| print(f" β Created {nodes['SW2']['name']}") | |
| time.sleep(1) | |
| else: | |
| print("Creating Switch2 (ethernet switch)...") | |
| nodes['SW2'] = create_node(project_id, "SW2", 200, 100, node_type="ethernet_switch") | |
| if nodes['SW2']: | |
| print(f" β Created {nodes['SW2']['name']}") | |
| time.sleep(1) | |
| # Create PCs using VPCS | |
| if vpcs_template: | |
| print("Creating PC1...") | |
| nodes['PC1'] = create_node(project_id, "PC1", -300, 100, template=vpcs_template) | |
| if nodes['PC1']: | |
| print(f" β Created {nodes['PC1']['name']}") | |
| time.sleep(0.5) | |
| print("Creating PC2...") | |
| nodes['PC2'] = create_node(project_id, "PC2", 300, 100, template=vpcs_template) | |
| if nodes['PC2']: | |
| print(f" β Created {nodes['PC2']['name']}") | |
| time.sleep(0.5) | |
| print("Creating PC3...") | |
| nodes['PC3'] = create_node(project_id, "PC3", -300, 200, template=vpcs_template) | |
| if nodes['PC3']: | |
| print(f" β Created {nodes['PC3']['name']}") | |
| time.sleep(0.5) | |
| print("Creating PC4...") | |
| nodes['PC4'] = create_node(project_id, "PC4", 300, 200, template=vpcs_template) | |
| if nodes['PC4']: | |
| print(f" β Created {nodes['PC4']['name']}") | |
| time.sleep(0.5) | |
| # Create links | |
| print("\n" + "="*60) | |
| print("Creating Links") | |
| print("="*60 + "\n") | |
| links_created = 0 | |
| # R1 <-> R2 (core link) | |
| if nodes.get('R1') and nodes.get('R2'): | |
| print("Linking R1 <-> R2 (Gi0/0 <-> Gi0/0)...") | |
| link = create_link(project_id, | |
| nodes['R1']['node_id'], 0, 0, | |
| nodes['R2']['node_id'], 0, 0) | |
| if link: | |
| print(f" β Connected") | |
| links_created += 1 | |
| # R1 <-> SW1 | |
| if nodes.get('R1') and nodes.get('SW1'): | |
| print("Linking R1 <-> SW1 (Gi0/1 <-> port 0)...") | |
| link = create_link(project_id, | |
| nodes['R1']['node_id'], 1, 0, | |
| nodes['SW1']['node_id'], 0, 0) | |
| if link: | |
| print(f" β Connected") | |
| links_created += 1 | |
| # R2 <-> SW2 | |
| if nodes.get('R2') and nodes.get('SW2'): | |
| print("Linking R2 <-> SW2 (Gi0/1 <-> port 0)...") | |
| link = create_link(project_id, | |
| nodes['R2']['node_id'], 1, 0, | |
| nodes['SW2']['node_id'], 0, 0) | |
| if link: | |
| print(f" β Connected") | |
| links_created += 1 | |
| # PC1 <-> SW1 | |
| if nodes.get('PC1') and nodes.get('SW1'): | |
| print("Linking PC1 <-> SW1...") | |
| link = create_link(project_id, | |
| nodes['PC1']['node_id'], 0, 0, | |
| nodes['SW1']['node_id'], 1, 0) | |
| if link: | |
| print(f" β Connected") | |
| links_created += 1 | |
| # PC3 <-> SW1 | |
| if nodes.get('PC3') and nodes.get('SW1'): | |
| print("Linking PC3 <-> SW1...") | |
| link = create_link(project_id, | |
| nodes['PC3']['node_id'], 0, 0, | |
| nodes['SW1']['node_id'], 2, 0) | |
| if link: | |
| print(f" β Connected") | |
| links_created += 1 | |
| # PC2 <-> SW2 | |
| if nodes.get('PC2') and nodes.get('SW2'): | |
| print("Linking PC2 <-> SW2...") | |
| link = create_link(project_id, | |
| nodes['PC2']['node_id'], 0, 0, | |
| nodes['SW2']['node_id'], 1, 0) | |
| if link: | |
| print(f" β Connected") | |
| links_created += 1 | |
| # PC4 <-> SW2 | |
| if nodes.get('PC4') and nodes.get('SW2'): | |
| print("Linking PC4 <-> SW2...") | |
| link = create_link(project_id, | |
| nodes['PC4']['node_id'], 0, 0, | |
| nodes['SW2']['node_id'], 2, 0) | |
| if link: | |
| print(f" β Connected") | |
| links_created += 1 | |
| # Summary | |
| print("\n" + "="*60) | |
| print("Topology Created!") | |
| print("="*60) | |
| print(f"\nNodes created: {len([n for n in nodes.values() if n])}") | |
| print(f"Links created: {links_created}") | |
| print("\nCCNA Lab Scenarios Ready:") | |
| print(" β’ Static routing between R1 and R2") | |
| print(" β’ OSPF/EIGRP dynamic routing") | |
| print(" β’ Inter-VLAN routing on switches") | |
| print(" β’ Access lists and security") | |
| print(" β’ NAT/PAT configuration") | |
| print(" β’ Basic switch configuration (VLANs, trunking)") | |
| print("\nInitial IP Plan Suggestion:") | |
| print(" Network 1 (Left): 10.1.1.0/24") | |
| print(" - R1 Gi0/1: 10.1.1.1") | |
| print(" - PC1: 10.1.1.10") | |
| print(" - PC3: 10.1.1.11") | |
| print(" Network 2 (Right): 10.1.2.0/24") | |
| print(" - R2 Gi0/1: 10.1.2.1") | |
| print(" - PC2: 10.1.2.10") | |
| print(" - PC4: 10.1.2.11") | |
| print(" WAN Link: 10.1.100.0/30") | |
| print(" - R1 Gi0/0: 10.1.100.1") | |
| print(" - R2 Gi0/0: 10.1.100.2") | |
| print("\nβ Open project in GNS3 GUI to start devices and configure!") | |
| if __name__ == "__main__": | |
| main() | |