Skip to content

Commit 3f647bc

Browse files
ktbyersdysby
andcommitted
Teldata CIT Driver (ktbyers#3168)
Co-authored-by: disbymixtape <> Co-authored-by: dysby <helder-j-dias@telecom.pt>
1 parent e770055 commit 3f647bc

File tree

3 files changed

+196
-0
lines changed

3 files changed

+196
-0
lines changed

netmiko/ssh_dispatcher.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
from netmiko.ruijie import RuijieOSSSH, RuijieOSTelnet
111111
from netmiko.sixwind import SixwindOSSSH
112112
from netmiko.sophos import SophosSfosSSH
113+
from netmiko.teldat import TeldatCITSSH, TeldatCITTelnet
113114
from netmiko.terminal_server import TerminalServerSSH
114115
from netmiko.terminal_server import TerminalServerTelnet
115116
from netmiko.tplink import TPLinkJetStreamSSH, TPLinkJetStreamTelnet
@@ -249,6 +250,7 @@
249250
"sixwind_os": SixwindOSSSH,
250251
"sophos_sfos": SophosSfosSSH,
251252
"supermicro_smis": SmciSwitchSmisSSH,
253+
"teldat_cit": TeldatCITSSH,
252254
"tplink_jetstream": TPLinkJetStreamSSH,
253255
"ubiquiti_edge": UbiquitiEdgeSSH,
254256
"ubiquiti_edgerouter": UbiquitiEdgeRouterSSH,
@@ -332,6 +334,7 @@
332334
CLASS_MAPPER["ruckus_fastiron_telnet"] = RuckusFastironTelnet
333335
CLASS_MAPPER["ruijie_os_telnet"] = RuijieOSTelnet
334336
CLASS_MAPPER["supermicro_smis_telnet"] = SmciSwitchSmisTelnet
337+
CLASS_MAPPER["teldat_cit_telnet"] = TeldatCITTelnet
335338
CLASS_MAPPER["tplink_jetstream_telnet"] = TPLinkJetStreamTelnet
336339
CLASS_MAPPER["yamaha_telnet"] = YamahaTelnet
337340
CLASS_MAPPER["zte_zxros_telnet"] = ZteZxrosTelnet

netmiko/teldat/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from netmiko.teldat.teldat_cit import TeldatCITSSH, TeldatCITTelnet
2+
3+
__all__ = ["TeldatCITSSH", "TeldatCITTelnet"]

netmiko/teldat/teldat_cit.py

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
from typing import Optional, Any, Union, Sequence, Iterator, TextIO
2+
from netmiko.base_connection import BaseConnection
3+
from netmiko.no_enable import NoEnable
4+
import time
5+
import re
6+
from netmiko import log
7+
8+
9+
class TeldatCITBase(NoEnable, BaseConnection):
10+
def session_preparation(self) -> None:
11+
# Prompt is "*"
12+
self._test_channel_read(pattern=r"\*")
13+
self.set_base_prompt()
14+
# Clear the read buffer
15+
time.sleep(0.3 * self.global_delay_factor)
16+
self.clear_buffer()
17+
18+
def disable_paging(
19+
self,
20+
command: str = "",
21+
delay_factor: Optional[float] = None,
22+
cmd_verify: bool = True,
23+
pattern: Optional[str] = None,
24+
) -> str:
25+
"""Teldat doesn't have pagging"""
26+
return ""
27+
28+
def set_base_prompt(
29+
self,
30+
pri_prompt_terminator: str = "*",
31+
alt_prompt_terminator: str = "*",
32+
delay_factor: float = 1.0,
33+
pattern: Optional[str] = None,
34+
) -> str:
35+
"""
36+
Teldat base prompt is "hostname *"
37+
"""
38+
return super().set_base_prompt(
39+
pri_prompt_terminator=pri_prompt_terminator,
40+
alt_prompt_terminator=alt_prompt_terminator,
41+
delay_factor=delay_factor,
42+
pattern=pattern,
43+
)
44+
45+
def cleanup(self, command: str = "logout") -> None:
46+
"""Gracefully exit the SSH session."""
47+
self._base_mode()
48+
49+
if self.session_log:
50+
self.session_log.fin = True
51+
52+
# Always try to send final 'logout'
53+
self.write_channel(command + self.RETURN)
54+
output = ""
55+
for _ in range(30):
56+
time.sleep(0.1)
57+
output += self.read_channel()
58+
if "Do you wish to end" in output:
59+
self.write_channel("yes" + self.RETURN)
60+
break
61+
62+
def _check_monitor_mode(self, check_string: str = "+", pattern: str = "") -> bool:
63+
return super().check_config_mode(check_string=check_string, pattern=pattern)
64+
65+
def check_config_mode(
66+
self, check_string: str = ">", pattern: str = "", force_regex: bool = False
67+
) -> bool:
68+
return super().check_config_mode(
69+
check_string=check_string, pattern=pattern, force_regex=force_regex
70+
)
71+
72+
def _check_running_config_mode(
73+
self, check_string: str = "$", pattern: str = ""
74+
) -> bool:
75+
return super().check_config_mode(check_string=check_string, pattern=pattern)
76+
77+
def _monitor_mode(
78+
self, monitor_command: str = "p 3", pattern: str = r"\+", re_flags: int = 0
79+
) -> str:
80+
"""
81+
Enter into monitor_mode.
82+
On Teldat devices always go to base mode before entering other modes
83+
Cannot reuse super.config_mode() because config mode check is called only with
84+
defaults in BaseConnection
85+
"""
86+
self._base_mode() # Teldat does not allow mode switching, go to base mode first
87+
88+
output = ""
89+
self.write_channel(self.normalize_cmd(monitor_command))
90+
# Make sure you read until you detect the command echo (avoid getting out of sync)
91+
if self.global_cmd_verify is not False:
92+
output += self.read_until_pattern(
93+
pattern=re.escape(monitor_command.strip())
94+
)
95+
if not re.search(pattern, output, flags=re_flags):
96+
output += self.read_until_pattern(pattern=pattern, re_flags=re_flags)
97+
if not self._check_monitor_mode():
98+
raise ValueError("Failed to enter monitor mode.")
99+
return output
100+
101+
def config_mode(
102+
self, config_command: str = "p 4", pattern: str = "onfig>", re_flags: int = 0
103+
) -> str:
104+
self._base_mode()
105+
return super().config_mode(
106+
config_command=config_command, pattern=pattern, re_flags=re_flags
107+
)
108+
109+
def _running_config_mode(
110+
self, config_command: str = "p 5", pattern: str = r"onfig\$", re_flags: int = 0
111+
) -> str:
112+
"""Enter running config mode."""
113+
self._base_mode()
114+
115+
output = ""
116+
self.write_channel(self.normalize_cmd(config_command))
117+
# Make sure you read until you detect the command echo (avoid getting out of sync)
118+
if self.global_cmd_verify is not False:
119+
output += self.read_until_pattern(pattern=re.escape(config_command.strip()))
120+
if not re.search(pattern, output, flags=re_flags):
121+
output += self.read_until_pattern(pattern=pattern, re_flags=re_flags)
122+
if not self._check_running_config_mode():
123+
raise ValueError("Failed to enter running config mode.")
124+
return output
125+
126+
def send_config_set(
127+
self,
128+
config_commands: Union[str, Sequence[str], Iterator[str], TextIO, None] = None,
129+
*,
130+
exit_config_mode: bool = False,
131+
**kwargs: Any,
132+
) -> str:
133+
"""
134+
For Teldat devices always enter config mode
135+
"""
136+
return super().send_config_set(
137+
config_commands=config_commands,
138+
exit_config_mode=exit_config_mode,
139+
**kwargs,
140+
)
141+
142+
def save_config(
143+
self, cmd: str = "save yes", confirm: bool = False, confirm_response: str = ""
144+
) -> str:
145+
if not self.check_config_mode() or not self._check_running_config_mode():
146+
raise ValueError("Cannot save if not in config or running config mode")
147+
# Some devices are slow so match on trailing-prompt if you can
148+
output = self._send_command_str(
149+
command_string=cmd, strip_prompt=False, strip_command=False
150+
)
151+
return output
152+
153+
def exit_config_mode(self, exit_config: str = "", pattern: str = "") -> str:
154+
return self._base_mode()
155+
156+
def _base_mode(self, exit_cmd: str = "\x10", pattern: str = r"\*") -> str:
157+
"""
158+
Exit from other modes (monitor, config, running config).
159+
Send CTRL+P to the device
160+
"""
161+
output = ""
162+
self.write_channel(self.normalize_cmd(exit_cmd))
163+
# Teldat - exit_cmd not printable
164+
output += self.read_until_pattern(pattern=pattern)
165+
log.debug(f"_base_mode: {output}")
166+
return output
167+
168+
169+
class TeldatCITSSH(TeldatCITBase):
170+
pass
171+
172+
173+
class TeldatCITTelnet(TeldatCITBase):
174+
def telnet_login(
175+
self,
176+
pri_prompt_terminator: str = r"\*",
177+
alt_prompt_terminator: str = r"\*",
178+
username_pattern: str = "Username:",
179+
pwd_pattern: str = "Password:",
180+
delay_factor: float = 1.0,
181+
max_loops: int = 60,
182+
) -> str:
183+
return super().telnet_login(
184+
pri_prompt_terminator=pri_prompt_terminator,
185+
alt_prompt_terminator=alt_prompt_terminator,
186+
username_pattern=username_pattern,
187+
pwd_pattern=pwd_pattern,
188+
delay_factor=delay_factor,
189+
max_loops=max_loops,
190+
)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy