Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for NEC Univerge IX Routers #3408

Open
wants to merge 15 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions netmiko/nec/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from __future__ import unicode_literals
from netmiko.nec.nec_ix import NecIxSSH, NecIxTelnet

__all__ = ["NecIxSSH", "NecIxTelnet"]
170 changes: 170 additions & 0 deletions netmiko/nec/nec_ix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import time
import re
from netmiko._telnetlib.telnetlib import Telnet
from typing import Any, Optional

from netmiko.base_connection import BaseConnection


class NecIxBase(BaseConnection):
def session_preparation(self) -> None:
"""Prepare the session after the connection has been established."""
self.set_base_prompt()
self.enable()
time.sleep(0.3 * self.global_delay_factor)
self.config_mode()
time.sleep(0.3 * self.global_delay_factor)
self.clear_buffer()
self.disable_paging(command=self.RETURN + "terminal length 0")

def set_base_prompt(
self,
pri_prompt_terminator: str = "#",
alt_prompt_terminator: str = "",
delay_factor: float = 1.0,
pattern: Optional[str] = None,
) -> str:
"""
Cisco IOS/IOS-XE abbreviates the prompt at 20-chars in config mode.
Consequently, abbreviate the base_prompt
"""
base_prompt = super().set_base_prompt(
pri_prompt_terminator=pri_prompt_terminator,
alt_prompt_terminator=alt_prompt_terminator,
delay_factor=delay_factor,
pattern=pattern,
)
self.base_prompt = base_prompt[:16]
return self.base_prompt

def enable(
self,
cmd: str = "svintr-config",
pattern: str = "",
enable_pattern: Optional[str] = None,
check_state: bool = True,
re_flags: int = re.IGNORECASE,
) -> str:
"""
There are several commands to enter the enable mode,
NEC IX enable mode is the same as configuration mode.
svintr-config -- Enter configuration mode (supervisor interrupt)
enable-config -- Enter configuration mode
configure -- Enter configuration mode
"""
return super().enable(
cmd=cmd,
pattern=pattern,
enable_pattern=enable_pattern,
check_state=check_state,
re_flags=re_flags,
)

def check_enable_mode(self, check_string: str = ")#") -> bool:
return super().check_enable_mode(check_string=check_string)

def exit_enable_mode(self, exit_command: str = "exit") -> str:
"""Exits enable mode."""
output = ""
if self.check_enable_mode():
self.write_channel(self.normalize_cmd(exit_command))
time.sleep(1)
output = self.read_channel()
if ")#" in output:
self.write_channel("exit")
if self.base_prompt not in output:
output += self.read_until_prompt(read_entire_line=True)
if self.check_enable_mode():
raise ValueError("Failed to exit enable mode.")
return output

def config_mode(
self,
config_command: str = "configure",
pattern: str = "",
re_flags: int = re.IGNORECASE,
) -> str:
"""configure command is used to go to the top menu in configuration mode."""
return super().config_mode(
config_command=config_command, pattern=pattern, re_flags=re_flags
)

def check_config_mode(
self,
check_string: str = "(config)#",
pattern: str = "",
force_regex: bool = False,
) -> bool:
"""Checks if the device is in Configuration mode or not."""
return super().check_config_mode(check_string=check_string, pattern=pattern)

def exit_config_mode(
self, exit_config: str = "configure", pattern: str = ""
) -> str:
"""
When you exit configuration mode, the show commands available to you are limited.
Therefore, use the configure command to go to the top menu.
"""
output = ""
if self.check_config_mode():
self.write_channel(self.normalize_cmd(exit_config))
time.sleep(1)
if self.base_prompt not in output:
output += self.read_until_prompt(read_entire_line=True)
return output

def save_config(
self,
cmd: str = "write memory",
confirm: bool = False,
confirm_response: str = "",
) -> str:
"""Save Config."""
self.config_mode()
output = self._send_command_str(
command_string=cmd,
strip_prompt=False,
strip_command=False,
read_timeout=100.0,
)
return output


class NecIxSSH(NecIxBase):
"""NecIx SSH driver."""

pass


class NecIxTelnet(NecIxBase):
"""NecIx Telnet driver."""

def __init__(self, *args: Any, **kwargs: Any) -> None:
default_enter = kwargs.get("default_enter")
kwargs["default_enter"] = "\r" if default_enter is None else default_enter
super().__init__(*args, **kwargs)

def ignore_option_negotiation(self, sock: Any, cmd: Any, opt: Any) -> None:
pass

def telnet_login(
self,
pri_prompt_terminator: str = r"#\s*$",
alt_prompt_terminator: str = r">\s*$",
username_pattern: str = r"login",
pwd_pattern: str = r"assword",
delay_factor: float = 1.0,
max_loops: int = 20,
) -> str:
if isinstance(self.remote_conn, Telnet):
self.remote_conn.set_option_negotiation_callback(
self.ignore_option_negotiation
)
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,
)
6 changes: 6 additions & 0 deletions netmiko/ssh_autodetect.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,12 @@
"priority": 99,
"dispatch": "_autodetect_std",
},
"nec_ix": {
"cmd": "show hardware",
"search_patterns": [r"IX Series"],
"priority": 99,
"dispatch": "_autodetect_std",
},
}

# Sort SSH_MAPPER_DICT such that the most common commands are first
Expand Down
3 changes: 3 additions & 0 deletions netmiko/ssh_dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
NokiaSrlSSH,
)
from netmiko.netgear import NetgearProSafeSSH
from netmiko.nec import NecIxSSH, NecIxTelnet
from netmiko.oneaccess import OneaccessOneOSTelnet, OneaccessOneOSSSH
from netmiko.ovs import OvsLinuxSSH
from netmiko.paloalto import PaloAltoPanosSSH
Expand Down Expand Up @@ -259,6 +260,7 @@
"mellanox_mlnxos": MellanoxMlnxosSSH,
"mrv_lx": MrvLxSSH,
"mrv_optiswitch": MrvOptiswitchSSH,
"nec_ix": NecIxSSH,
"netapp_cdot": NetAppcDotSSH,
"netgear_prosafe": NetgearProSafeSSH,
"netscaler": NetscalerSSH,
Expand Down Expand Up @@ -356,6 +358,7 @@
CLASS_MAPPER["huawei_olt_telnet"] = HuaweiSmartAXSSH
CLASS_MAPPER["ipinfusion_ocnos_telnet"] = IpInfusionOcNOSTelnet
CLASS_MAPPER["juniper_junos_telnet"] = JuniperTelnet
CLASS_MAPPER["nec_ix_telnet"] = NecIxTelnet
CLASS_MAPPER["nokia_sros_telnet"] = NokiaSrosTelnet
CLASS_MAPPER["oneaccess_oneos_telnet"] = OneaccessOneOSTelnet
CLASS_MAPPER["paloalto_panos_telnet"] = PaloAltoPanosTelnet
Expand Down
Loading