ktbyers / netmiko

Multi-vendor library to simplify Paramiko SSH connections to network devices
MIT License
3.62k stars 1.31k forks source link

Arista driver with SCP driver and bash >= 5.1 encounters new ANSI escape code #3482

Closed jniec-js closed 2 months ago

jniec-js commented 3 months ago

Description of Issue/Question

Beginning with bash 5.1, bracketed-paste-mode is enabled by default: https://forum.endeavouros.com/t/bash-5-1-bracketed-paste-now-on-by-default/10258

This causes issues when trying to scp a file to a remote unix system using bash 5.1, as the first line is now escape characters instead of the expected header line as the source code indicates here: https://github.com/ktbyers/netmiko/blob/f0041bb1a8526f054292af2174c3412931ee565e/netmiko/scp_handler.py#L177

The actual output Netmiko sees is:

[0m[?2004l
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/mmcblk0p1   7409788 3047916   4345488  42% /mnt/flash

Setup

Netmiko version

In [2]: netmiko.__version__
Out[2]: '4.3.0'

Netmiko device_type (if relevant to the issue)

(Paste device_type between quotes below)

arista_eos

Note: Starting in 4.32 train, Arista has upgraded the version of bash to 5.1 on their devices, so this requires a device running EOS 4.32 or higher.

 bash --version
GNU bash, version 5.1.8(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Steps to Reproduce the Issue

Error Traceback

(Paste the complete traceback of the exception between quotes below)

Traceback (most recent call last):
  File "/...snip.../tmp/netmiko-debugging/./repro.py", line 25, in <module>
    netmiko.file_transfer(cur, source_file="test.txt", dest_file="test.txt", file_system="/mnt/flash")
  File "/...snip.../lib/python3.10/site-packages/netmiko/scp_functions.py", line 149, in file_transfer
    verifyspace_and_transferfile(scp_transfer)
  File "/...snip.../lib/python3.10/site-packages/netmiko/scp_functions.py", line 48, in verifyspace_and_transferfile
    if not scp_transfer.verify_space_available():
  File "/...snip.../lib/python3.10/site-packages/netmiko/scp_handler.py", line 213, in verify_space_available
    space_avail = self.remote_space_available(search_pattern=search_pattern)
  File "/...snip.../lib/python3.10/site-packages/netmiko/arista/arista.py", line 139, in remote_space_available
    return self._remote_space_available_unix(search_pattern=search_pattern)
  File "/...snip.../lib/python3.10/site-packages/netmiko/scp_handler.py", line 184, in _remote_space_available_unix
    raise ValueError(msg)
ValueError: Parsing error, unexpected output from /bin/df -k /mnt/flash:

Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/mmcblk0p1   7409788 5473932   1919472  75% /mnt/flash

Note, the escape characters are not printable by default, this is the actual output:

[0m[?2004l
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/mmcblk0p1   7409788 3047916   4345488  42% /mnt/flash

Relevant Python code

Run the below against an Arista device that is running 4.32 or higher version of code, you will get a parse failure.

import netmiko

import os
import getpass
import sys
import pathlib
import re

device = sys.argv[1]

connection = {
    "device_type": "arista_eos",
    "username": getpass.getuser(),
    "password": getpass.getpass(),
    "host": device,
    "session_log": "session.log",
}

pathlib.Path("test.txt").touch()

with netmiko.ConnectHandler(**connection) as cur:
    netmiko.file_transfer(cur, source_file="test.txt", dest_file="test.txt", file_system="/mnt/flash")
jniec-js commented 3 months ago

I think one way to solve this is to remove the escaped characters from the output: In https://github.com/ktbyers/netmiko/blob/f0041bb1a8526f054292af2174c3412931ee565e/netmiko/scp_handler.py#L173C9-L173C46

We can do something like remote_output = remote_output.strip().replace(u"\x1b[?2004l\r", u"").replace(u"\x1b[?2004h", u"")

Another option is to send bind 'set enable-bracketed-paste off' to the file system before sending any unix commands.

HOWEVER,

This probably affects other interactions with bash/unix to remote systems, so probably best to make whatever solution generalizable to apply to all unix interactions with devices and not just this specific issue.

ktbyers commented 3 months ago

We should add the:

[0m[?2004l

https://github.com/ktbyers/netmiko/blob/develop/netmiko/base_connection.py#L2340

To the ANSI escape code sequences and then enable ANSI escape code stripping for the Arista driver, basically set:

self.ansi_escape_codes = True

In the Arista driver.

jniec-js commented 3 months ago

Thanks, I will work on a PR