Linux SSH / OpenGear read_until_prompt fails to detect enable mode when prompt is only single character
See original GitHub issueSteps to reproduce:
- Initialise a connection with an OpenGear device, using the Linux SSH driver:
>>> from netmiko import ConnectHandler
>>> device = ConnectHandler(device_type="linux", host="some-opengear", username="root", password="pass", secret="pass", fast_cli=False)
- Attempt to enter in enable mode:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.9/site-packages/netmiko/linux/linux_ssh.py", line 150, in enable
raise ValueError(msg)
ValueError:
Netmiko failed to elevate privileges.
Please ensure you pass the sudo password into ConnectHandler
using the 'secret' argument and that the user has sudo
permissions.
The previous command does send the sudo -s
command as it should, the device returns a line containing the #
as expected, but it fails on check_enable_mode
.
After digging deeper, it seems like the issue is caused by the read_until_prompt
method that is misbehaving. To reproduce, use the device
defined previously:
>>> device.write_channel(device.RETURN)
>>> output = device.read_channel()
>>> results = re.split("(.*)", output, maxsplit=1, flags=re.I)
>>> output, match_str, buffer = results
>>> output
''
>>> match_str
''
>>> output + match_str
''
>>> buffer
'\n# \n# \n# '
>>>
Can notice that it sends the return, it reads the prompt correctly, but the regular expression split renders output + match_str
to be an empty string. As a result, check_enable_mode
will never find the #
prompt in the empty string, and therefore check_enable_mode
will always return False
in https://github.com/ktbyers/netmiko/blob/v4.1.1/netmiko/base_connection.py#L1861.
The above is a simplified version of https://github.com/ktbyers/netmiko/blob/v4.1.1/netmiko/base_connection.py#L614-L640 to reproduce it step-by-step. The pattern .*
comes from https://github.com/ktbyers/netmiko/blob/v4.1.1/netmiko/base_connection.py#L731-L733 as self.base_prompt
is empty string. So everything seems to be caused by the incorrectly detected prompt.
TL;DR: self.base_prompt
should be #
but it’s ''
.
If I change the line https://github.com/ktbyers/netmiko/blob/v4.1.1/netmiko/base_connection.py#L1289 to
self.base_prompt = prompt
Everything seems to work fine, but might break other things? If so, perhaps something like the following would be more appropriate?
if len(prompt.strip()) == 1:
self.base_prompt = prompt
else:
self.base_prompt = prompt[:-1]
In fact, I can’t think of a case where we need to strip the last character of a prompt, but perhaps there’s more background to this than I’m aware of.
Issue Analytics
- State:
- Created a year ago
- Comments:5 (5 by maintainers)
Top GitHub Comments
For self.base_prompt, I want something that is enduring (not likely to change).
For example, in the below:
I want to be able to go through the state changes and still have the netmiko read succeed. So I want the part of the prompt that is common to all of these cases i.e.
cisco3
. So that is what is meant by thebase
in self.base_prompt.Obviously, that doesn’t always work, but that is why the last character is dropped (to try to make Netmiko output reading more reliable).
Linux behavior can already be problematic here (relative to platforms that are very Cisco IOS like).
For example:
i.e. the prompt here is changing on more things than just the last character.
Should be fixed here:
https://github.com/ktbyers/netmiko/pull/2891