"""Custom Netmiko driver for the ALL-SG8316M (sw1) -- Telnet-only, IOS-like but non-standard CLI (no `terminal length`, `--More--` paging, `end` from config-vlan skips straight to the top level). No stock Netmiko/NAPALM driver matches this device. NOT YET WIRED IN: this module is imported nowhere yet. The `claudecode` Telnet account on sw1 is currently rejected ("Incorrect User Name!!", found 2026-07-16) so this driver is unverified against the real device. Once working credentials exist, activate it from nautobot_config.py: import importlib import allnet_sg8316m_driver # noqa: F401 (registers itself on import) and add to PLUGINS_CONFIG["nautobot_plugin_nornir"]["dispatcher_mapping"]: "allnet_sg8316m": "allnet_sg8316m_driver.GoldenConfigAllnetSg8316m" (dispatcher class still needs writing once the connection class below is confirmed to log in cleanly -- see project_nautobot_allnet_cudy_scope_20260716 memory for the full status and the two netmiko gotchas that cost the most time: device_type must contain the literal substring "_telnet" for Netmiko to pick the Telnet transport at all (BaseConnection.__init__ checks this by string, not by class hierarchy), and `netmiko.ssh_dispatcher` at package level is the dispatcher *function*, not the submodule -- reach CLASS_MAPPER via `importlib.import_module("netmiko.ssh_dispatcher")`. """ import importlib import time from netmiko.cisco_base_connection import CiscoBaseConnection _nm_dispatch = importlib.import_module("netmiko.ssh_dispatcher") class AllnetSg8316mTelnet(CiscoBaseConnection): def session_preparation(self): self._test_channel_read(pattern=r"[>#]") self.set_base_prompt() self.ansi_escape_codes = True def disable_paging(self, *args, **kwargs): # No config knob for this on this firmware; paging is handled # per-command in send_command_paged() below instead. return "" def telnet_login( self, pri_prompt_terminator=r"#\s*$", alt_prompt_terminator=r">\s*$", username_pattern=r"Username", pwd_pattern=r"Password", delay_factor=1, max_loops=20, ): return super().telnet_login( pri_prompt_terminator=pri_prompt_terminator, alt_prompt_terminator=alt_prompt_terminator, username_pattern=username_pattern, pwd_pattern=pwd_pattern, delay_factor=delay_factor, max_loops=max_loops, ) def send_command_paged(self, command_string, max_pages=200, delay=0.3): """sg8316m paginates with '--More--' and has no length-0 setting; page through by sending a space each time it appears.""" self.write_channel(command_string + self.RETURN) time.sleep(delay) output = "" for _ in range(max_pages): chunk = self.read_channel() output += chunk if "--More--" in chunk: self.write_channel(" ") time.sleep(delay) continue if any(p in chunk for p in ["sw1#", "sw1>"]) and "--More--" not in chunk: break if chunk == "": time.sleep(delay) return output.replace("--More--", "") # Registered under the "_telnet" suffix required by Netmiko's own transport # selection (see module docstring) -- registration is safe/inert on its own, # nothing calls ConnectHandler(device_type="allnet_sg8316m_telnet") yet. _nm_dispatch.CLASS_MAPPER["allnet_sg8316m_telnet"] = AllnetSg8316mTelnet _nm_dispatch.platforms = list(_nm_dispatch.CLASS_MAPPER.keys())