Skip to content

Commit

Permalink
Banner Configuration Changes require cmd_verify to be disable (#2558)
Browse files Browse the repository at this point in the history
* Banner fix and add global_cmd_verify to send_config_set

* Improving testability
  • Loading branch information
ktbyers authored Nov 2, 2021
1 parent ad04b53 commit bc8fc44
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 1 deletion.
23 changes: 22 additions & 1 deletion netmiko/base_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -1965,7 +1965,8 @@ def send_config_from_file(
:param kwargs: params to be sent to send_config_set method
"""
with io.open(config_file, "rt", encoding="utf-8") as cfg_file:
return self.send_config_set(cfg_file, **kwargs)
commands = cfg_file.readlines()
return self.send_config_set(commands, **kwargs)

def send_config_set(
self,
Expand All @@ -1982,6 +1983,7 @@ def send_config_set(
enter_config_mode: bool = True,
error_pattern: str = "",
terminator: str = r"#",
bypass_commands: Optional[str] = None,
) -> str:
"""
Send configuration commands down the SSH channel.
Expand Down Expand Up @@ -2016,8 +2018,14 @@ def send_config_set(
:param terminator: Regular expression pattern to use as an alternate terminator in certain
situations.
:param bypass_commands: Regular expression pattern indicating configuration commands
where cmd_verify is automatically disabled.
"""

if self.global_cmd_verify is not None:
cmd_verify = self.global_cmd_verify

if delay_factor is not None or max_loops is not None:
warnings.warn(DELAY_FACTOR_DEPR_SIMPLE_MSG, DeprecationWarning)

Expand Down Expand Up @@ -2052,6 +2060,19 @@ def send_config_set(
if not hasattr(config_commands, "__iter__"):
raise ValueError("Invalid argument passed into send_config_set")

if bypass_commands is None:
# Commands where cmd_verify is automatically disabled reg-ex logical-or
bypass_commands = r"^banner .*$"

# Set bypass_commands="" to force no-bypass (usually for testing)
bypass_detected = False
if bypass_commands:
bypass_detected = any(
[True for cmd in config_commands if re.search(bypass_commands, cmd)]
)
if bypass_detected:
cmd_verify = False

# Send config commands
output = ""
if enter_config_mode:
Expand Down
2 changes: 2 additions & 0 deletions netmiko/hp/hp_comware.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def send_config_set(
enter_config_mode: bool = True,
error_pattern: str = "",
terminator: str = r"\]",
bypass_commands: Optional[str] = None,
) -> str:
return super().send_config_set(
config_commands=config_commands,
Expand All @@ -68,6 +69,7 @@ def send_config_set(
enter_config_mode=enter_config_mode,
error_pattern=error_pattern,
terminator=terminator,
bypass_commands=bypass_commands,
)

def set_base_prompt(
Expand Down
64 changes: 64 additions & 0 deletions tests/test_netmiko_config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python
import pytest
from netmiko import ConfigInvalidException
from netmiko import ReadTimeout


def test_ssh_connect(net_connect, commands, expected_responses):
Expand Down Expand Up @@ -148,6 +149,69 @@ def test_config_error_pattern(net_connect, commands, expected_responses):
print("Skipping test: no error_pattern supplied.")


def test_global_cmd_verify(net_connect, commands, expected_responses):
"""
Banner configuration has a special exclusing where cmd_verify is dynamically
disabled so make sure it works.
"""

# Make sure banner comes in as separate lines
banner = commands.get("banner").splitlines()
if banner is None:
pytest.skip("No banner defined.")
config_base = commands.get("config")
config_list = config_base + banner

# Remove any existing banner
net_connect.send_config_set("no banner login")

# bypass_commands="" should fail as cmd_verify will be True
with pytest.raises(ReadTimeout) as e: # noqa
net_connect.send_config_set(config_commands=config_list, bypass_commands="")

# Recover from send_config_set failure. The "%" is to finish the failed banner.
net_connect.write_channel("%\n")
net_connect.exit_config_mode()

net_connect.global_cmd_verify = False
# Should work now as global_cmd_verify is False
net_connect.send_config_set(config_commands=config_list, bypass_commands="")
show_run = net_connect.send_command("show run | inc banner log")
assert "banner login" in show_run

net_connect.send_config_set("no banner login")


def test_banner(net_connect, commands, expected_responses):
"""
Banner configuration has a special exclusing where cmd_verify is dynamically
disabled so make sure it works.
"""
# Make sure banner comes in as separate lines
banner = commands.get("banner").splitlines()
if banner is None:
pytest.skip("No banner defined.")
config_base = commands.get("config")
config_list = config_base + banner

# Remove any existing banner
net_connect.send_config_set("no banner login")

# bypass_commands="" should fail as cmd_verify will be True
with pytest.raises(ReadTimeout) as e: # noqa
net_connect.send_config_set(config_commands=config_list, bypass_commands="")

# Recover from send_config_set failure. The "%" is to finish the failed banner.
net_connect.write_channel("%\n")
net_connect.exit_config_mode()

net_connect.send_config_set(config_commands=config_list)
show_run = net_connect.send_command("show run | inc banner log")
assert "banner login" in show_run

net_connect.send_config_set("no banner login")


def test_disconnect(net_connect, commands, expected_responses):
"""
Terminate the SSH session
Expand Down

0 comments on commit bc8fc44

Please sign in to comment.