mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-08-27 12:30:13 +03:00
feat(copilot): add Netmiko device list generator and simplify Huawei driver
- Add script to generate Markdown documentation of all Netmiko supported
devices (SSH and Telnet), grouped by platform with source attribution
- Highlight custom GNS3-Copilot devices with "Custom ✨" marker
- Auto-generate device list to docs/gns3-copilot/netmiko_devices.md
- Simplify HuaweiTelnetCE driver: remove redundant aliases
(huawei_ce, huawei_telnet_ce_telnet), keep only huawei_telnet_ce
- Update tests to match simplified device registration
This commit is contained in:
parent
50fa4f6e2a
commit
effea3fb26
234
docs/gns3-copilot/netmiko_devices.md
Normal file
234
docs/gns3-copilot/netmiko_devices.md
Normal file
@ -0,0 +1,234 @@
|
||||
# Netmiko Supported Devices
|
||||
|
||||
**Netmiko Version:** 4.6.0
|
||||
**Generated:** 2026-03-12 23:00:41
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
- **Total Device Types:** 364
|
||||
- **SSH Devices:** 154
|
||||
- **Telnet Devices:** 53
|
||||
- **Custom Devices:** 1
|
||||
|
||||
## SSH Supported Devices
|
||||
|
||||
| Platform | Device Type | Source |
|
||||
|----------|-------------|--------|
|
||||
| A10 | `a10_ssh` | Netmiko |
|
||||
| Accedian | `accedian_ssh` | Netmiko |
|
||||
| Adtran | `adtran_os_ssh` | Netmiko |
|
||||
| Adva | `adva_fsp150f2_ssh` | Netmiko |
|
||||
| Adva | `adva_fsp150f3_ssh` | Netmiko |
|
||||
| Alaxala | `alaxala_ax26s_ssh` | Netmiko |
|
||||
| Alaxala | `alaxala_ax36s_ssh` | Netmiko |
|
||||
| Alcatel | `alcatel_aos_ssh` | Netmiko |
|
||||
| Alcatel | `alcatel_sros_ssh` | Netmiko |
|
||||
| Allied | `allied_telesis_awplus_ssh` | Netmiko |
|
||||
| Apresia | `apresia_aeos_ssh` | Netmiko |
|
||||
| Arista | `arista_eos_ssh` | Netmiko |
|
||||
| Arris | `arris_cer_ssh` | Netmiko |
|
||||
| Aruba | `aruba_aoscx_ssh` | Netmiko |
|
||||
| Aruba | `aruba_os_ssh` | Netmiko |
|
||||
| Aruba | `aruba_osswitch_ssh` | Netmiko |
|
||||
| Aruba | `aruba_procurve_ssh` | Netmiko |
|
||||
| Asterfusion | `asterfusion_asternos_ssh` | Netmiko |
|
||||
| Audiocode | `audiocode_66_ssh` | Netmiko |
|
||||
| Audiocode | `audiocode_72_ssh` | Netmiko |
|
||||
| Audiocode | `audiocode_shell_ssh` | Netmiko |
|
||||
| Avaya | `avaya_ers_ssh` | Netmiko |
|
||||
| Avaya | `avaya_vsp_ssh` | Netmiko |
|
||||
| Bintec | `bintec_boss_ssh` | Netmiko |
|
||||
| Broadcom | `broadcom_icos_ssh` | Netmiko |
|
||||
| Brocade | `brocade_fastiron_ssh` | Netmiko |
|
||||
| Brocade | `brocade_fos_ssh` | Netmiko |
|
||||
| Brocade | `brocade_netiron_ssh` | Netmiko |
|
||||
| Brocade | `brocade_nos_ssh` | Netmiko |
|
||||
| Brocade | `brocade_vdx_ssh` | Netmiko |
|
||||
| Brocade | `brocade_vyos_ssh` | Netmiko |
|
||||
| Calix | `calix_b6_ssh` | Netmiko |
|
||||
| Casa | `casa_cmts_ssh` | Netmiko |
|
||||
| Cdot | `cdot_cros_ssh` | Netmiko |
|
||||
| Centec | `centec_os_ssh` | Netmiko |
|
||||
| Check Point | `checkpoint_gaia_ssh` | Netmiko |
|
||||
| Ciena | `ciena_saos10_ssh` | Netmiko |
|
||||
| Ciena | `ciena_saos_ssh` | Netmiko |
|
||||
| Ciena | `ciena_waveserver_ssh` | Netmiko |
|
||||
| Cisco | `cisco_apic_ssh` | Netmiko |
|
||||
| Cisco | `cisco_asa_ssh` | Netmiko |
|
||||
| Cisco | `cisco_ftd_ssh` | Netmiko |
|
||||
| Cisco | `cisco_ios_ssh` | Netmiko |
|
||||
| Cisco | `cisco_nxos_ssh` | Netmiko |
|
||||
| Cisco | `cisco_s200_ssh` | Netmiko |
|
||||
| Cisco | `cisco_s300_ssh` | Netmiko |
|
||||
| Cisco | `cisco_tp_ssh` | Netmiko |
|
||||
| Cisco | `cisco_viptela_ssh` | Netmiko |
|
||||
| Cisco | `cisco_wlc_ssh` | Netmiko |
|
||||
| Cisco | `cisco_xe_ssh` | Netmiko |
|
||||
| Cisco | `cisco_xr_ssh` | Netmiko |
|
||||
| Cloudgenix | `cloudgenix_ion_ssh` | Netmiko |
|
||||
| Corelight | `corelight_linux_ssh` | Netmiko |
|
||||
| Coriant | `coriant_ssh` | Netmiko |
|
||||
| Cumulus | `cumulus_linux_ssh` | Netmiko |
|
||||
| Dell | `dell_dnos9_ssh` | Netmiko |
|
||||
| Dell | `dell_force10_ssh` | Netmiko |
|
||||
| Dell | `dell_isilon_ssh` | Netmiko |
|
||||
| Dell | `dell_os10_ssh` | Netmiko |
|
||||
| Dell | `dell_os6_ssh` | Netmiko |
|
||||
| Dell | `dell_os9_ssh` | Netmiko |
|
||||
| Dell | `dell_powerconnect_ssh` | Netmiko |
|
||||
| Dell | `dell_sonic_ssh` | Netmiko |
|
||||
| Digi | `digi_transport_ssh` | Netmiko |
|
||||
| Dlink | `dlink_ds_ssh` | Netmiko |
|
||||
| Edgecore | `edgecore_sonic_ssh` | Netmiko |
|
||||
| Ekinops | `ekinops_ek360_ssh` | Netmiko |
|
||||
| Eltex | `eltex_esr_ssh` | Netmiko |
|
||||
| Eltex | `eltex_ssh` | Netmiko |
|
||||
| Endace | `endace_ssh` | Netmiko |
|
||||
| Enterasys | `enterasys_ssh` | Netmiko |
|
||||
| Ericsson | `ericsson_ipos_ssh` | Netmiko |
|
||||
| Ericsson | `ericsson_mltn63_ssh` | Netmiko |
|
||||
| Ericsson | `ericsson_mltn66_ssh` | Netmiko |
|
||||
| Extreme | `extreme_ers_ssh` | Netmiko |
|
||||
| Extreme | `extreme_exos_ssh` | Netmiko |
|
||||
| Extreme | `extreme_netiron_ssh` | Netmiko |
|
||||
| Extreme | `extreme_nos_ssh` | Netmiko |
|
||||
| Extreme | `extreme_slx_ssh` | Netmiko |
|
||||
| Extreme | `extreme_ssh` | Netmiko |
|
||||
| Extreme | `extreme_tierra_ssh` | Netmiko |
|
||||
| Extreme | `extreme_vdx_ssh` | Netmiko |
|
||||
| Extreme | `extreme_vsp_ssh` | Netmiko |
|
||||
| Extreme | `extreme_wing_ssh` | Netmiko |
|
||||
| F5 | `f5_linux_ssh` | Netmiko |
|
||||
| F5 | `f5_ltm_ssh` | Netmiko |
|
||||
| F5 | `f5_tmsh_ssh` | Netmiko |
|
||||
| Fiberstore | `fiberstore_fsos_ssh` | Netmiko |
|
||||
| Fiberstore | `fiberstore_fsosv2_ssh` | Netmiko |
|
||||
| Fiberstore | `fiberstore_networkos_ssh` | Netmiko |
|
||||
| Flexvnf | `flexvnf_ssh` | Netmiko |
|
||||
| Fortinet | `fortinet_ssh` | Netmiko |
|
||||
| Garderos | `garderos_grs_ssh` | Netmiko |
|
||||
| Generic | `generic_ssh` | Netmiko |
|
||||
| Generic | `generic_termserver_ssh` | Netmiko |
|
||||
| H3C (华三) | `h3c_comware_ssh` | Netmiko |
|
||||
| HP | `hp_comware_ssh` | Netmiko |
|
||||
| HP | `hp_procurve_ssh` | Netmiko |
|
||||
| Hillstone | `hillstone_stoneos_ssh` | Netmiko |
|
||||
| Huawei | `huawei_olt_ssh` | Netmiko |
|
||||
| Huawei | `huawei_smartax_ssh` | Netmiko |
|
||||
| Huawei | `huawei_smartaxmmi_ssh` | Netmiko |
|
||||
| Huawei | `huawei_ssh` | Netmiko |
|
||||
| Huawei | `huawei_vrp_ssh` | Netmiko |
|
||||
| Huawei | `huawei_vrpv8_ssh` | Netmiko |
|
||||
| Infinera | `infinera_packet_ssh` | Netmiko |
|
||||
| Ipinfusion | `ipinfusion_ocnos_ssh` | Netmiko |
|
||||
| Juniper | `juniper_junos_ssh` | Netmiko |
|
||||
| Juniper | `juniper_screenos_ssh` | Netmiko |
|
||||
| Juniper | `juniper_ssh` | Netmiko |
|
||||
| Keymile | `keymile_nos_ssh` | Netmiko |
|
||||
| Keymile | `keymile_ssh` | Netmiko |
|
||||
| Lancom | `lancom_lcossx4_ssh` | Netmiko |
|
||||
| Linux | `linux_ssh` | Netmiko |
|
||||
| Maipu (迈普) | `maipu_ssh` | Netmiko |
|
||||
| Mellanox | `mellanox_mlnxos_ssh` | Netmiko |
|
||||
| Mellanox | `mellanox_ssh` | Netmiko |
|
||||
| Mikrotik | `mikrotik_routeros_ssh` | Netmiko |
|
||||
| Mikrotik | `mikrotik_switchos_ssh` | Netmiko |
|
||||
| Mrv | `mrv_lx_ssh` | Netmiko |
|
||||
| Mrv | `mrv_optiswitch_ssh` | Netmiko |
|
||||
| Nec | `nec_ix_ssh` | Netmiko |
|
||||
| Netapp | `netapp_cdot_ssh` | Netmiko |
|
||||
| Netgear | `netgear_prosafe_ssh` | Netmiko |
|
||||
| Netscaler | `netscaler_ssh` | Netmiko |
|
||||
| Nokia | `nokia_srl_ssh` | Netmiko |
|
||||
| Nokia | `nokia_sros_ssh` | Netmiko |
|
||||
| Oneaccess | `oneaccess_oneos_ssh` | Netmiko |
|
||||
| Ovs | `ovs_linux_ssh` | Netmiko |
|
||||
| Palo Alto | `paloalto_panos_ssh` | Netmiko |
|
||||
| Pluribus | `pluribus_ssh` | Netmiko |
|
||||
| Quanta | `quanta_mesh_ssh` | Netmiko |
|
||||
| Rad | `rad_etx_ssh` | Netmiko |
|
||||
| Raisecom | `raisecom_roap_ssh` | Netmiko |
|
||||
| Ruckus | `ruckus_fastiron_ssh` | Netmiko |
|
||||
| Ruijie (锐捷) | `ruijie_os_ssh` | Netmiko |
|
||||
| Silverpeak | `silverpeak_vxoa_ssh` | Netmiko |
|
||||
| Sixwind | `sixwind_os_ssh` | Netmiko |
|
||||
| Sophos | `sophos_sfos_ssh` | Netmiko |
|
||||
| Supermicro | `supermicro_smis_ssh` | Netmiko |
|
||||
| Telcosystems | `telcosystems_binos_ssh` | Netmiko |
|
||||
| Teldat | `teldat_cit_ssh` | Netmiko |
|
||||
| Tplink | `tplink_jetstream_ssh` | Netmiko |
|
||||
| Ubiquiti | `ubiquiti_edge_ssh` | Netmiko |
|
||||
| Ubiquiti | `ubiquiti_edgerouter_ssh` | Netmiko |
|
||||
| Ubiquiti | `ubiquiti_edgeswitch_ssh` | Netmiko |
|
||||
| Ubiquiti | `ubiquiti_unifiswitch_ssh` | Netmiko |
|
||||
| Vertiv | `vertiv_mph_ssh` | Netmiko |
|
||||
| Vyatta | `vyatta_vyos_ssh` | Netmiko |
|
||||
| Vyos | `vyos_ssh` | Netmiko |
|
||||
| Watchguard | `watchguard_fireware_ssh` | Netmiko |
|
||||
| Yamaha | `yamaha_ssh` | Netmiko |
|
||||
| ZTE (中兴) | `zte_zxros_ssh` | Netmiko |
|
||||
| Zyxel | `zyxel_os_ssh` | Netmiko |
|
||||
|
||||
## Telnet Supported Devices
|
||||
|
||||
| Platform | Device Type | Source |
|
||||
|----------|-------------|--------|
|
||||
| Adtran | `adtran_os_telnet` | Netmiko |
|
||||
| Apresia | `apresia_aeos_telnet` | Netmiko |
|
||||
| Arista | `arista_eos_telnet` | Netmiko |
|
||||
| Aruba | `aruba_procurve_telnet` | Netmiko |
|
||||
| Audiocode | `audiocode_66_telnet` | Netmiko |
|
||||
| Audiocode | `audiocode_72_telnet` | Netmiko |
|
||||
| Audiocode | `audiocode_shell_telnet` | Netmiko |
|
||||
| Bintec | `bintec_boss_telnet` | Netmiko |
|
||||
| Brocade | `brocade_fastiron_telnet` | Netmiko |
|
||||
| Brocade | `brocade_netiron_telnet` | Netmiko |
|
||||
| Calix | `calix_b6_telnet` | Netmiko |
|
||||
| Centec | `centec_os_telnet` | Netmiko |
|
||||
| Ciena | `ciena_saos_telnet` | Netmiko |
|
||||
| Cisco | `cisco_ios_telnet` | Netmiko |
|
||||
| Cisco | `cisco_nxos_telnet` | Netmiko |
|
||||
| Cisco | `cisco_s200_telnet` | Netmiko |
|
||||
| Cisco | `cisco_s300_telnet` | Netmiko |
|
||||
| Cisco | `cisco_xr_telnet` | Netmiko |
|
||||
| Dell | `dell_dnos6_telnet` | Netmiko |
|
||||
| Dell | `dell_powerconnect_telnet` | Netmiko |
|
||||
| Dlink | `dlink_ds_telnet` | Netmiko |
|
||||
| Extreme | `extreme_exos_telnet` | Netmiko |
|
||||
| Extreme | `extreme_netiron_telnet` | Netmiko |
|
||||
| Extreme | `extreme_telnet` | Netmiko |
|
||||
| Fiberstore | `fiberstore_fsosv2_telnet` | Netmiko |
|
||||
| Generic | `generic_telnet` | Netmiko |
|
||||
| Generic | `generic_termserver_telnet` | Netmiko |
|
||||
| Genexis | `genexis_solt33_telnet` | Netmiko |
|
||||
| HP | `hp_comware_telnet` | Netmiko |
|
||||
| HP | `hp_procurve_telnet` | Netmiko |
|
||||
| Huawei | `huawei_olt_telnet` | Netmiko |
|
||||
| Huawei | `huawei_telnet` | Netmiko |
|
||||
| Huawei | `huawei_telnet_ce` | Custom ✨ |
|
||||
| Infinera | `infinera_packet_telnet` | Netmiko |
|
||||
| Ipinfusion | `ipinfusion_ocnos_telnet` | Netmiko |
|
||||
| Juniper | `juniper_junos_telnet` | Netmiko |
|
||||
| Maipu (迈普) | `maipu_telnet` | Netmiko |
|
||||
| Nec | `nec_ix_telnet` | Netmiko |
|
||||
| Nokia | `nokia_sros_telnet` | Netmiko |
|
||||
| Oneaccess | `oneaccess_oneos_telnet` | Netmiko |
|
||||
| Optilink | `optilink_eolt11444_telnet` | Netmiko |
|
||||
| Optilink | `optilink_eolt9702_telnet` | Netmiko |
|
||||
| Palo Alto | `paloalto_panos_telnet` | Netmiko |
|
||||
| Rad | `rad_etx_telnet` | Netmiko |
|
||||
| Raisecom | `raisecom_telnet` | Netmiko |
|
||||
| Ruckus | `ruckus_fastiron_telnet` | Netmiko |
|
||||
| Ruijie (锐捷) | `ruijie_os_telnet` | Netmiko |
|
||||
| Supermicro | `supermicro_smis_telnet` | Netmiko |
|
||||
| Telcosystems | `telcosystems_binos_telnet` | Netmiko |
|
||||
| Teldat | `teldat_cit_telnet` | Netmiko |
|
||||
| Tplink | `tplink_jetstream_telnet` | Netmiko |
|
||||
| Yamaha | `yamaha_telnet` | Netmiko |
|
||||
| ZTE (中兴) | `zte_zxros_telnet` | Netmiko |
|
||||
|
||||
---
|
||||
|
||||
*This document was generated automatically by the Netmiko device list script.*
|
||||
@ -396,19 +396,12 @@ def register_custom_device_type() -> None:
|
||||
# not a function
|
||||
sd = importlib.import_module("netmiko.ssh_dispatcher")
|
||||
|
||||
# Add to both mappers
|
||||
# Register the device type in both mappers
|
||||
# CLASS_MAPPER_BASE is used for base class definitions
|
||||
sd.CLASS_MAPPER_BASE["huawei_telnet_ce"] = HuaweiTelnetCE
|
||||
sd.CLASS_MAPPER_BASE["huawei_ce"] = HuaweiTelnetCE
|
||||
|
||||
# CLASS_MAPPER is used by ConnectHandler for device type validation
|
||||
sd.CLASS_MAPPER["huawei_telnet_ce"] = HuaweiTelnetCE
|
||||
sd.CLASS_MAPPER["huawei_ce"] = HuaweiTelnetCE
|
||||
|
||||
# CRITICAL: Netmiko may also look for types with _telnet suffix
|
||||
# Add this variant to ensure compatibility
|
||||
sd.CLASS_MAPPER["huawei_telnet_ce_telnet"] = HuaweiTelnetCE
|
||||
sd.CLASS_MAPPER_BASE["huawei_telnet_ce_telnet"] = HuaweiTelnetCE
|
||||
|
||||
# CRITICAL: Update the static platforms lists
|
||||
# These lists are computed at module import time and won't
|
||||
|
||||
@ -0,0 +1,403 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# GNS3-Copilot - AI-powered Network Lab Assistant for GNS3
|
||||
#
|
||||
# Script to list all Netmiko supported devices (SSH and Telnet)
|
||||
#
|
||||
# This script queries the Netmiko library to extract all device types
|
||||
# that support SSH and Telnet connections, grouped by vendor/brand.
|
||||
# Includes custom device drivers from the GNS3-Copilot project.
|
||||
# Outputs a Markdown document with the complete device list.
|
||||
#
|
||||
# Usage: python list_netmiko_devices.py
|
||||
# Output: netmiko_devices.md (in current directory)
|
||||
#
|
||||
|
||||
"""
|
||||
Netmiko Device List Generator
|
||||
|
||||
This script extracts and displays all SSH and Telnet-supported device
|
||||
types from the Netmiko library, organized by vendor/brand.
|
||||
|
||||
Features:
|
||||
- Automatically detects Netmiko version
|
||||
- Loads custom GNS3-Copilot device drivers
|
||||
- Extracts all SSH and Telnet device types from CLASS_MAPPER
|
||||
- Groups devices by vendor/brand
|
||||
- Generates Markdown documentation
|
||||
- Provides statistics and summary
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from typing import Dict, List, Tuple
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def get_netmiko_version() -> str:
|
||||
"""Get Netmiko library version."""
|
||||
try:
|
||||
import netmiko
|
||||
return netmiko.__version__
|
||||
except Exception:
|
||||
return "Unknown"
|
||||
|
||||
|
||||
def register_custom_drivers() -> set:
|
||||
"""
|
||||
Register custom GNS3-Copilot device drivers.
|
||||
|
||||
This function imports and executes the registration functions for
|
||||
custom device drivers, adding them to Netmiko's CLASS_MAPPER.
|
||||
|
||||
Returns:
|
||||
Set of custom device type names that were registered
|
||||
"""
|
||||
# Get the directory where this script is located
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# Find the custom drivers directory
|
||||
custom_drivers_dir = os.path.dirname(script_dir)
|
||||
|
||||
# Add to sys.path if not already there
|
||||
if custom_drivers_dir not in sys.path:
|
||||
sys.path.insert(0, custom_drivers_dir)
|
||||
|
||||
custom_devices = set()
|
||||
|
||||
try:
|
||||
# Import and register Huawei CE driver
|
||||
from gns3server.agent.gns3_copilot.utils.custom_netmiko \
|
||||
import huawei_ce
|
||||
|
||||
# Store custom device types before registration
|
||||
custom_devices.add("huawei_telnet_ce")
|
||||
|
||||
# The driver auto-registers on import, but we can call it
|
||||
# explicitly
|
||||
if hasattr(huawei_ce, 'register_custom_device_type'):
|
||||
huawei_ce.register_custom_device_type()
|
||||
except ImportError:
|
||||
# Silently skip if custom drivers are not available
|
||||
pass
|
||||
except Exception as e:
|
||||
# Log but don't fail
|
||||
print(
|
||||
f"Warning: Failed to register custom drivers: {e}",
|
||||
file=sys.stderr
|
||||
)
|
||||
|
||||
return custom_devices
|
||||
|
||||
|
||||
def extract_brand_name(device_type: str) -> str:
|
||||
"""
|
||||
Extract brand name from device type.
|
||||
|
||||
Args:
|
||||
device_type: Device type string (e.g., 'cisco_ios_telnet')
|
||||
|
||||
Returns:
|
||||
Brand name in a standardized format
|
||||
"""
|
||||
# Remove common suffixes
|
||||
name = device_type.replace('_telnet', '').replace('_ssh', '')
|
||||
name = name.replace('_serial', '')
|
||||
|
||||
# Map to standard brand names
|
||||
brand_mapping = {
|
||||
'cisco': 'Cisco',
|
||||
'huawei': 'Huawei',
|
||||
'juniper': 'Juniper',
|
||||
'arista': 'Arista',
|
||||
'hp': 'HP',
|
||||
'aruba': 'Aruba',
|
||||
'dell': 'Dell',
|
||||
'brocade': 'Brocade',
|
||||
'extreme': 'Extreme',
|
||||
'ruckus': 'Ruckus',
|
||||
'ruijie': 'Ruijie (锐捷)',
|
||||
'zte': 'ZTE (中兴)',
|
||||
'maipu': 'Maipu (迈普)',
|
||||
'h3c': 'H3C (华三)',
|
||||
'nokia': 'Nokia',
|
||||
'paloalto': 'Palo Alto',
|
||||
'f5': 'F5',
|
||||
'checkpoint': 'Check Point',
|
||||
'generic': 'Generic',
|
||||
'huaweiyt': 'HuaweiYT',
|
||||
'vsz': 'Ruckus',
|
||||
}
|
||||
|
||||
# Check for exact matches first
|
||||
for key, value in brand_mapping.items():
|
||||
if name == key:
|
||||
return value
|
||||
|
||||
# Check for partial matches
|
||||
for key, value in brand_mapping.items():
|
||||
if key in name:
|
||||
return value
|
||||
|
||||
# Return capitalized version of the first part
|
||||
return name.split('_')[0].capitalize()
|
||||
|
||||
|
||||
def group_devices_by_brand(device_types: List[str]) -> Dict[str, List[str]]:
|
||||
"""
|
||||
Group device types by brand.
|
||||
|
||||
Args:
|
||||
device_types: List of device type strings
|
||||
|
||||
Returns:
|
||||
Dictionary mapping brand names to device type lists
|
||||
"""
|
||||
brands = {}
|
||||
|
||||
for device_type in device_types:
|
||||
brand = extract_brand_name(device_type)
|
||||
|
||||
if brand not in brands:
|
||||
brands[brand] = []
|
||||
|
||||
brands[brand].append(device_type)
|
||||
|
||||
return brands
|
||||
|
||||
|
||||
def get_devices_by_protocol() -> Tuple[List[str], List[str]]:
|
||||
"""
|
||||
Get all SSH and Telnet device types from Netmiko.
|
||||
|
||||
Returns:
|
||||
Tuple of (ssh_devices, telnet_devices) as sorted lists
|
||||
"""
|
||||
try:
|
||||
from netmiko.ssh_dispatcher import CLASS_MAPPER
|
||||
|
||||
ssh_devices = []
|
||||
telnet_devices = []
|
||||
both_protocols = []
|
||||
|
||||
for device_type in CLASS_MAPPER.keys():
|
||||
device_lower = device_type.lower()
|
||||
has_telnet = 'telnet' in device_lower
|
||||
has_ssh = 'ssh' in device_lower
|
||||
|
||||
if has_telnet and has_ssh:
|
||||
both_protocols.append(device_type)
|
||||
elif has_telnet:
|
||||
telnet_devices.append(device_type)
|
||||
elif has_ssh:
|
||||
ssh_devices.append(device_type)
|
||||
|
||||
# Devices with both protocols go to both lists
|
||||
ssh_devices.extend(both_protocols)
|
||||
telnet_devices.extend(both_protocols)
|
||||
|
||||
return sorted(ssh_devices), sorted(telnet_devices)
|
||||
|
||||
except ImportError as e:
|
||||
print(f"Error: Failed to import Netmiko: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def get_total_device_count() -> int:
|
||||
"""Get total number of device types in Netmiko."""
|
||||
try:
|
||||
from netmiko.ssh_dispatcher import CLASS_MAPPER
|
||||
return len(CLASS_MAPPER)
|
||||
except ImportError:
|
||||
return 0
|
||||
|
||||
|
||||
def generate_markdown(
|
||||
version: str,
|
||||
ssh_devices: List[str],
|
||||
telnet_devices: List[str],
|
||||
total_count: int,
|
||||
custom_devices: set
|
||||
) -> str:
|
||||
"""
|
||||
Generate Markdown documentation with table format.
|
||||
|
||||
Args:
|
||||
version: Netmiko version string
|
||||
ssh_devices: List of SSH device types
|
||||
telnet_devices: List of Telnet device types
|
||||
total_count: Total number of device types
|
||||
custom_devices: Set of custom device type names
|
||||
|
||||
Returns:
|
||||
Markdown formatted string
|
||||
"""
|
||||
md_lines = []
|
||||
|
||||
# Header
|
||||
md_lines.append("# Netmiko Supported Devices")
|
||||
md_lines.append("")
|
||||
md_lines.append(f"**Netmiko Version:** {version}")
|
||||
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
md_lines.append(f"**Generated:** {timestamp}")
|
||||
md_lines.append("")
|
||||
md_lines.append("---")
|
||||
md_lines.append("")
|
||||
|
||||
# Summary
|
||||
md_lines.append("## Summary")
|
||||
md_lines.append("")
|
||||
md_lines.append(f"- **Total Device Types:** {total_count}")
|
||||
md_lines.append(f"- **SSH Devices:** {len(ssh_devices)}")
|
||||
md_lines.append(f"- **Telnet Devices:** {len(telnet_devices)}")
|
||||
md_lines.append(f"- **Custom Devices:** {len(custom_devices)}")
|
||||
md_lines.append("")
|
||||
|
||||
# SSH Devices Section
|
||||
md_lines.append("## SSH Supported Devices")
|
||||
md_lines.append("")
|
||||
md_lines.append("| Platform | Device Type | Source |")
|
||||
md_lines.append("|----------|-------------|--------|")
|
||||
|
||||
ssh_brands = group_devices_by_brand(ssh_devices)
|
||||
for brand in sorted(ssh_brands.keys()):
|
||||
devices = sorted(ssh_brands[brand])
|
||||
for device in devices:
|
||||
if device in custom_devices:
|
||||
source = "Custom ✨"
|
||||
else:
|
||||
source = "Netmiko"
|
||||
md_lines.append(f"| {brand} | `{device}` | {source} |")
|
||||
md_lines.append("")
|
||||
|
||||
# Telnet Devices Section
|
||||
md_lines.append("## Telnet Supported Devices")
|
||||
md_lines.append("")
|
||||
md_lines.append("| Platform | Device Type | Source |")
|
||||
md_lines.append("|----------|-------------|--------|")
|
||||
|
||||
telnet_brands = group_devices_by_brand(telnet_devices)
|
||||
for brand in sorted(telnet_brands.keys()):
|
||||
devices = sorted(telnet_brands[brand])
|
||||
for device in devices:
|
||||
if device in custom_devices:
|
||||
source = "Custom ✨"
|
||||
else:
|
||||
source = "Netmiko"
|
||||
md_lines.append(f"| {brand} | `{device}` | {source} |")
|
||||
md_lines.append("")
|
||||
|
||||
# Footer
|
||||
md_lines.append("---")
|
||||
md_lines.append("")
|
||||
md_lines.append("*This document was generated automatically by the "
|
||||
"Netmiko device list script.*")
|
||||
|
||||
return "\n".join(md_lines)
|
||||
|
||||
|
||||
def save_markdown(content: str, filename: str = "netmiko_devices.md") -> None:
|
||||
"""
|
||||
Save Markdown content to file in docs/gns3-copilot directory.
|
||||
|
||||
Args:
|
||||
content: Markdown content to save
|
||||
filename: Output filename (default: netmiko_devices.md)
|
||||
"""
|
||||
# Get the project root directory
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
# Go up from: .../gns3server/agent/gns3_copilot/utils/
|
||||
# custom_netmiko/scripts to project root
|
||||
# That's 6 levels up
|
||||
project_root = os.path.dirname(os.path.dirname(
|
||||
os.path.dirname(os.path.dirname(
|
||||
os.path.dirname(os.path.dirname(script_dir))))
|
||||
)
|
||||
)
|
||||
|
||||
# Target directory: docs/gns3-copilot
|
||||
target_dir = os.path.join(project_root, "docs", "gns3-copilot")
|
||||
|
||||
# Create directory if it doesn't exist
|
||||
os.makedirs(target_dir, exist_ok=True)
|
||||
|
||||
# Full file path
|
||||
output_path = os.path.join(target_dir, filename)
|
||||
|
||||
try:
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
print(f"Markdown document saved to: {output_path}")
|
||||
except IOError as e:
|
||||
print(f"Error: Failed to save Markdown file: {e}",
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def print_summary(version: str, ssh_count: int, telnet_count: int,
|
||||
total_count: int, output_file: str) -> None:
|
||||
"""Print summary to console."""
|
||||
print("=" * 80)
|
||||
print("Netmiko Device List Generator")
|
||||
print(f"Netmiko Version: {version}")
|
||||
print("=" * 80)
|
||||
print()
|
||||
print(f"Total SSH devices: {ssh_count}")
|
||||
print(f"Total Telnet devices: {telnet_count}")
|
||||
print(f"Total device types: {total_count}")
|
||||
print()
|
||||
print(f"Output file: {output_file}")
|
||||
print("=" * 80)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
"""
|
||||
Main function to execute the script.
|
||||
|
||||
Returns:
|
||||
Exit code (0 for success, 1 for error)
|
||||
"""
|
||||
# Register custom GNS3-Copilot drivers
|
||||
custom_devices = register_custom_drivers()
|
||||
|
||||
# Get Netmiko version
|
||||
version = get_netmiko_version()
|
||||
|
||||
# Get SSH and Telnet devices
|
||||
ssh_devices, telnet_devices = get_devices_by_protocol()
|
||||
|
||||
if not ssh_devices and not telnet_devices:
|
||||
print("Error: No devices found!", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# Get total device count
|
||||
total_count = get_total_device_count()
|
||||
|
||||
# Generate Markdown
|
||||
markdown_content = generate_markdown(
|
||||
version=version,
|
||||
ssh_devices=ssh_devices,
|
||||
telnet_devices=telnet_devices,
|
||||
total_count=total_count,
|
||||
custom_devices=custom_devices
|
||||
)
|
||||
|
||||
# Save to file
|
||||
output_file = "netmiko_devices.md"
|
||||
save_markdown(markdown_content, output_file)
|
||||
|
||||
# Print summary
|
||||
print_summary(
|
||||
version=version,
|
||||
ssh_count=len(ssh_devices),
|
||||
telnet_count=len(telnet_devices),
|
||||
total_count=total_count,
|
||||
output_file=output_file
|
||||
)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@ -51,10 +51,8 @@ class TestHuaweiTelnetCEDriver(unittest.TestCase):
|
||||
|
||||
# Check CLASS_MAPPER_BASE
|
||||
self.assertIn("huawei_telnet_ce", CLASS_MAPPER_BASE)
|
||||
self.assertEqual(CLASS_MAPPER_BASE["huawei_telnet_ce"], self.HuaweiTelnetCE)
|
||||
|
||||
# Check alias
|
||||
self.assertIn("huawei_ce", CLASS_MAPPER)
|
||||
self.assertEqual(CLASS_MAPPER_BASE["huawei_telnet_ce"],
|
||||
self.HuaweiTelnetCE)
|
||||
|
||||
def test_inheritance_from_huawei_base(self):
|
||||
"""Test that HuaweiTelnetCE inherits from HuaweiBase."""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user