Skip to content

Commit

Permalink
A3 pre release (#124)
Browse files Browse the repository at this point in the history
* bump pins
* deprecate comms_ansi
* convert deprecation warning -> FutureWarning so users see it
* update docs, fix some links, redeploy docs
* handle annoying rare paramiko eof at tear down of integration tests
* first swag adding 3.10 testing
  * skip ssh2 on 3.10 for now
  * skip pyfakefs tests on 3.10 for now
* make tests not a package.... remove unnecessary sleep for iosxr
* fix system transport double timeout issue
* add logging and commandeer example
* remove unnecessary call to strip ansi in in channel auth
* remove comms_ansi arg from tests
* handle "parallel" privs correctly (i.e. configuration and configuration_exclusive)
* Logo (#121)
* change creds to just scrapli/scrapli in examples, functional test updates for lab environment
* remove unnecessary ansi strip in async channel telnet auth
  • Loading branch information
carlmontanari authored May 29, 2021
1 parent 2470e2a commit 062a5f4
Show file tree
Hide file tree
Showing 208 changed files with 2,132 additions and 2,399 deletions.
9 changes: 2 additions & 7 deletions .github/workflows/commit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ jobs:
build_posix:
runs-on: ${{ matrix.os }}
strategy:
max-parallel: 9
max-parallel: 12
matrix:
os: [ubuntu-latest, macos-latest]
version: [3.6, 3.7, 3.8, 3.9]
version: [3.6, 3.7, 3.8, 3.9, 3.10.0-beta.1]
steps:
- uses: actions/checkout@v2
- name: set up python ${{ matrix.version }}
Expand All @@ -67,11 +67,6 @@ jobs:
# version we are targeting with nox, while still having versions like 3.9.0a4
run: |
echo "FRIENDLY_PYTHON_VERSION=$(python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')")" >> $GITHUB_ENV
- name: install libxml2 and libxslt seems to only be needed for 3.9 image for some reason
if: matrix.os == 'ubuntu-latest' && matrix.version == '3.9'
run: |
sudo apt install libxml2-dev
sudo apt install libxslt-dev
- name: setup test env
run: |
python -m pip install --upgrade pip
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,9 @@ jobs:
run: |
python setup.py sdist bdist_wheel
python -m twine upload dist/*
- name: create release branch
uses: peterjgrainger/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
branch: ${{ github.event.release.tag_name }}
10 changes: 2 additions & 8 deletions .github/workflows/weekly.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ on:
- cron: '0 10 * * 0'
workflow_dispatch:

# in the future make this just call the commit workflow, but right now looks a little hacky to do in actions
jobs:
darglint:
runs-on: ${{ matrix.os }}
Expand All @@ -32,10 +31,10 @@ jobs:
build_posix:
runs-on: ${{ matrix.os }}
strategy:
max-parallel: 9
max-parallel: 12
matrix:
os: [ubuntu-latest, macos-latest]
version: [3.6, 3.7, 3.8, 3.9]
version: [3.6, 3.7, 3.8, 3.9, 3.10.0-beta.1]
steps:
- uses: actions/checkout@v2
- name: set up python ${{ matrix.version }}
Expand All @@ -47,11 +46,6 @@ jobs:
# version we are targeting with nox, while still having versions like 3.9.0a4
run: |
echo "FRIENDLY_PYTHON_VERSION=$(python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')")" >> $GITHUB_ENV
- name: install libxml2 and libxslt seems to only be needed for 3.9 image for some reason
if: matrix.os == 'ubuntu-latest' && matrix.version == '3.9'
run: |
sudo apt install libxml2-dev
sudo apt install libxslt-dev
- name: setup test env
run: |
python -m pip install --upgrade pip
Expand Down
21 changes: 6 additions & 15 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ cov:

test_unit:
python -m pytest \
--cov=scrapli \
--cov-report html \
--cov-report term \
tests/unit/

cov_unit:
Expand All @@ -35,9 +32,6 @@ cov_unit:

test_integration:
python -m pytest \
--cov=scrapli \
--cov-report html \
--cov-report term \
tests/integration/

cov_integration:
Expand All @@ -49,9 +43,6 @@ cov_integration:

test_functional:
python -m pytest \
--cov=scrapli \
--cov-report html \
--cov-report term \
tests/functional/

cov_functional:
Expand Down Expand Up @@ -110,19 +101,19 @@ stop_dev_env:
${DOCKER_COMPOSE} \

prepare_dev_env:
python tests/functional/prepare_devices.py cisco_iosxe,cisco_nxos,cisco_iosxr,arista_eos,juniper_junos
python tests/prepare_devices.py cisco_iosxe,cisco_nxos,cisco_iosxr,arista_eos,juniper_junos

prepare_dev_env_iosxe:
python tests/functional/prepare_devices.py cisco_iosxe
python tests/prepare_devices.py cisco_iosxe

prepare_dev_env_nxos:
python tests/functional/prepare_devices.py cisco_nxos
python tests/prepare_devices.py cisco_nxos

prepare_dev_env_iosxr:
python tests/functional/prepare_devices.py cisco_iosxr
python tests/prepare_devices.py cisco_iosxr

prepare_dev_env_eos:
python tests/functional/prepare_devices.py arista_eos
python tests/prepare_devices.py arista_eos

prepare_dev_env_junos:
python tests/functional/prepare_devices.py juniper_junos
python tests/prepare_devices.py juniper_junos
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<p align=center><a href=""><img src=scrapli.svg?sanitize=true/></a></p>

[![Supported Versions](https://img.shields.io/pypi/pyversions/scrapli.svg)](https://pypi.org/project/scrapli)
[![PyPI version](https://badge.fury.io/py/scrapli.svg)](https://badge.fury.io/py/scrapli)
[![Weekly Build](https://github.com/carlmontanari/scrapli/workflows/Weekly%20Build/badge.svg)](https://github.com/carlmontanari/scrapli/actions?query=workflow%3A%22Weekly+Build%22)
Expand Down Expand Up @@ -71,8 +73,8 @@ from scrapli import Scrapli

device = {
"host": "172.18.0.11",
"auth_username": "vrnetlab",
"auth_password": "VR-netlab9",
"auth_username": "scrapli",
"auth_password": "scrapli",
"auth_strict_key": False,
"platform": "cisco_iosxe"
}
Expand All @@ -81,3 +83,7 @@ conn = Scrapli(**device)
conn.open()
print(conn.get_prompt())
```

<small>* Bunny artwork by Caroline Montanari, inspired by [@egonelbre](https://github.com/egonelbre/gophers).
The bunny/rabbit is a nod to/inspired by the white rabbit in `Monty Python and the Holy Grail`, because there
are enough snake logos already!</small>
30 changes: 2 additions & 28 deletions docs/api_docs/channel/async_channel.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ class AsyncChannel(BaseChannel):
if self.channel_log:
self.channel_log.write(buf)

if self._base_channel_args.comms_ansi:
if b"\x1b" in buf.lower():
buf = self._strip_ansi(buf=buf)

return buf
Expand Down Expand Up @@ -282,14 +282,6 @@ class AsyncChannel(BaseChannel):
buf = await asyncio.wait_for(self.read(), timeout=1)
except asyncio.TimeoutError:
buf = b""

# if user sets comms_ansi *or* if we see an escape char, strip ansi... at least eos
# tends to have one escape char in the login output that will break things; other
# than this and telnet login, stripping ansi will only ever be governed by the users
# comms_ansi setting
if self._base_channel_args.comms_ansi or b"\x1b" in buf.lower():
buf = self._strip_ansi(buf=buf)

authenticate_buf += buf.lower()

if b"password" in authenticate_buf:
Expand Down Expand Up @@ -368,11 +360,6 @@ class AsyncChannel(BaseChannel):
while True:
buf = await self.read()

# telnet auth *probably* wont have ansi chars, but strip them if they do exist so
# we can at least get past auth
if self._base_channel_args.comms_ansi or b"\x1B" in buf:
buf = self._strip_ansi(buf=buf)

if not buf:
current_iteration_time = datetime.now().timestamp()
if (current_iteration_time - auth_start_time) > (
Expand Down Expand Up @@ -745,7 +732,7 @@ class AsyncChannel(BaseChannel):
if self.channel_log:
self.channel_log.write(buf)

if self._base_channel_args.comms_ansi:
if b"\x1b" in buf.lower():
buf = self._strip_ansi(buf=buf)

return buf
Expand Down Expand Up @@ -917,14 +904,6 @@ class AsyncChannel(BaseChannel):
buf = await asyncio.wait_for(self.read(), timeout=1)
except asyncio.TimeoutError:
buf = b""

# if user sets comms_ansi *or* if we see an escape char, strip ansi... at least eos
# tends to have one escape char in the login output that will break things; other
# than this and telnet login, stripping ansi will only ever be governed by the users
# comms_ansi setting
if self._base_channel_args.comms_ansi or b"\x1b" in buf.lower():
buf = self._strip_ansi(buf=buf)

authenticate_buf += buf.lower()

if b"password" in authenticate_buf:
Expand Down Expand Up @@ -1003,11 +982,6 @@ class AsyncChannel(BaseChannel):
while True:
buf = await self.read()

# telnet auth *probably* wont have ansi chars, but strip them if they do exist so
# we can at least get past auth
if self._base_channel_args.comms_ansi or b"\x1B" in buf:
buf = self._strip_ansi(buf=buf)

if not buf:
current_iteration_time = datetime.now().timestamp()
if (current_iteration_time - auth_start_time) > (
Expand Down
19 changes: 4 additions & 15 deletions docs/api_docs/channel/base_channel.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ from scrapli.exceptions import ScrapliAuthenticationFailed, ScrapliTypeError, Sc
from scrapli.logging import get_instance_logger
from scrapli.transport.base import AsyncTransport, Transport

ANSI_ESCAPE_PATTERN = re.compile(rb"\x1b(\[.*?[@-~]|\].*?(\x07|\x1b\\))")


@dataclass()
class BaseChannelArgs:
Expand All @@ -52,7 +54,6 @@ class BaseChannelArgs:
comms_prompt_search_depth: depth of the buffer to search in for searching for the prompt
in "read_until_prompt"; smaller number here will generally be faster, though may be less
reliable; default value is 1000
comms_ansi: comms_ansi to assign to the channel, see above
timeout_ops: timeout_ops to assign to the channel, see above
channel_log: log "channel" output -- this would be the output you would normally see on a
terminal. If `True` logs to `scrapli_channel.log`, if a string is provided, logs to
Expand All @@ -72,7 +73,6 @@ class BaseChannelArgs:
comms_prompt_pattern: str = r"^[a-z0-9.\-@()/:]{1,32}[#>$]$"
comms_return_char: str = "\n"
comms_prompt_search_depth: int = 1000
comms_ansi: bool = False
timeout_ops: float = 30.0
channel_log: Union[str, bool, BytesIO] = False
channel_log_mode: str = "write"
Expand Down Expand Up @@ -375,8 +375,7 @@ class BaseChannel:
N/A

"""
ansi_escape_pattern = re.compile(rb"\x1b(\[.*?[@-~]|\].*?(\x07|\x1b\\))")
buf = re.sub(pattern=ansi_escape_pattern, repl=b"", string=buf)
buf = re.sub(pattern=ANSI_ESCAPE_PATTERN, repl=b"", string=buf)
return buf

@staticmethod
Expand Down Expand Up @@ -716,8 +715,7 @@ class BaseChannel:
N/A

"""
ansi_escape_pattern = re.compile(rb"\x1b(\[.*?[@-~]|\].*?(\x07|\x1b\\))")
buf = re.sub(pattern=ansi_escape_pattern, repl=b"", string=buf)
buf = re.sub(pattern=ANSI_ESCAPE_PATTERN, repl=b"", string=buf)
return buf

@staticmethod
Expand Down Expand Up @@ -863,7 +861,6 @@ Args:
comms_prompt_search_depth: depth of the buffer to search in for searching for the prompt
in "read_until_prompt"; smaller number here will generally be faster, though may be less
reliable; default value is 1000
comms_ansi: comms_ansi to assign to the channel, see above
timeout_ops: timeout_ops to assign to the channel, see above
channel_log: log "channel" output -- this would be the output you would normally see on a
terminal. If `True` logs to `scrapli_channel.log`, if a string is provided, logs to
Expand Down Expand Up @@ -897,7 +894,6 @@ class BaseChannelArgs:
comms_prompt_search_depth: depth of the buffer to search in for searching for the prompt
in "read_until_prompt"; smaller number here will generally be faster, though may be less
reliable; default value is 1000
comms_ansi: comms_ansi to assign to the channel, see above
timeout_ops: timeout_ops to assign to the channel, see above
channel_log: log "channel" output -- this would be the output you would normally see on a
terminal. If `True` logs to `scrapli_channel.log`, if a string is provided, logs to
Expand All @@ -917,7 +913,6 @@ class BaseChannelArgs:
comms_prompt_pattern: str = r"^[a-z0-9.\-@()/:]{1,32}[#>$]$"
comms_return_char: str = "\n"
comms_prompt_search_depth: int = 1000
comms_ansi: bool = False
timeout_ops: float = 30.0
channel_log: Union[str, bool, BytesIO] = False
channel_log_mode: str = "write"
Expand Down Expand Up @@ -976,12 +971,6 @@ class BaseChannelArgs:



`comms_ansi: bool`





`comms_prompt_pattern: str`


Expand Down
30 changes: 2 additions & 28 deletions docs/api_docs/channel/sync_channel.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class Channel(BaseChannel):
if self.channel_log:
self.channel_log.write(buf)

if self._base_channel_args.comms_ansi:
if b"\x1b" in buf.lower():
buf = self._strip_ansi(buf=buf)

return buf
Expand Down Expand Up @@ -271,14 +271,6 @@ class Channel(BaseChannel):
with self._channel_lock():
while True:
buf = self.read()

# if user sets comms_ansi *or* if we see an escape char, strip ansi... at least eos
# tends to have one escape char in the login output that will break things; other
# than this and telnet login, stripping ansi will only ever be governed by the users
# comms_ansi setting
if self._base_channel_args.comms_ansi or b"\x1b" in buf.lower():
buf = self._strip_ansi(buf=buf)

authenticate_buf += buf.lower()

self._ssh_message_handler(output=authenticate_buf)
Expand Down Expand Up @@ -357,11 +349,6 @@ class Channel(BaseChannel):
while True:
buf = self.read()

# telnet auth *probably* wont have ansi chars, but strip them if they do exist so
# we can at least get past auth
if self._base_channel_args.comms_ansi or b"\x1B" in buf:
buf = self._strip_ansi(buf=buf)

if not buf:
current_iteration_time = datetime.now().timestamp()
if (current_iteration_time - auth_start_time) > (
Expand Down Expand Up @@ -734,7 +721,7 @@ class Channel(BaseChannel):
if self.channel_log:
self.channel_log.write(buf)

if self._base_channel_args.comms_ansi:
if b"\x1b" in buf.lower():
buf = self._strip_ansi(buf=buf)

return buf
Expand Down Expand Up @@ -901,14 +888,6 @@ class Channel(BaseChannel):
with self._channel_lock():
while True:
buf = self.read()

# if user sets comms_ansi *or* if we see an escape char, strip ansi... at least eos
# tends to have one escape char in the login output that will break things; other
# than this and telnet login, stripping ansi will only ever be governed by the users
# comms_ansi setting
if self._base_channel_args.comms_ansi or b"\x1b" in buf.lower():
buf = self._strip_ansi(buf=buf)

authenticate_buf += buf.lower()

self._ssh_message_handler(output=authenticate_buf)
Expand Down Expand Up @@ -987,11 +966,6 @@ class Channel(BaseChannel):
while True:
buf = self.read()

# telnet auth *probably* wont have ansi chars, but strip them if they do exist so
# we can at least get past auth
if self._base_channel_args.comms_ansi or b"\x1B" in buf:
buf = self._strip_ansi(buf=buf)

if not buf:
current_iteration_time = datetime.now().timestamp()
if (current_iteration_time - auth_start_time) > (
Expand Down
Loading

0 comments on commit 062a5f4

Please sign in to comment.