From 9951e786caf5687eb912fdb2ce2ff50b4631761c Mon Sep 17 00:00:00 2001 From: Lukeman Hakkim Sheik Alavudeen Date: Mon, 25 Nov 2024 09:46:49 -0800 Subject: [PATCH] Releasing v24.11 --- Makefile | 4 +- docs/changelog/2024/november.rst | 29 ++++ docs/changelog/index.rst | 1 + docs/changelog_plugins/2024/november.rst | 50 ++++++ docs/changelog_plugins/index.rst | 1 + src/unicon/plugins/__init__.py | 2 +- src/unicon/plugins/generic/patterns.py | 2 +- src/unicon/plugins/generic/statements.py | 2 + src/unicon/plugins/hvrp/patterns.py | 8 +- .../plugins/hvrp/service_implementation.py | 20 ++- src/unicon/plugins/iosxe/quad/statemachine.py | 3 - src/unicon/plugins/iosxe/settings.py | 2 + src/unicon/plugins/iosxr/spitfire/settings.py | 1 + src/unicon/plugins/nxos/setting.py | 4 +- .../tests/mock_data/hvrp/hvrp_mock_data.yaml | 11 ++ .../iosxe/cat9k_vwlc_reload_logs.txt | 118 ++++++++++++++ .../mock_data/iosxe/iosxe_mock_data_vwlc.yaml | 139 ++++++++++++++++ .../mock_data/iosxe/iosxe_mock_quad.yaml | 22 ++- src/unicon/plugins/tests/test_plugin_hvrp.py | 151 ++++++++++++------ .../tests/test_plugin_iosxe_cat9k_vwlc.py | 37 +++++ .../plugins/tests/test_plugin_iosxe_quad.py | 16 ++ 21 files changed, 558 insertions(+), 65 deletions(-) create mode 100644 docs/changelog/2024/november.rst create mode 100644 docs/changelog_plugins/2024/november.rst create mode 100644 src/unicon/plugins/tests/mock_data/iosxe/cat9k_vwlc_reload_logs.txt create mode 100644 src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_vwlc.yaml create mode 100644 src/unicon/plugins/tests/test_plugin_iosxe_cat9k_vwlc.py diff --git a/Makefile b/Makefile index 697c724c..39efbd0d 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ develop: @echo "" @pip uninstall -y $(PKG_NAME) @pip install $(DEPENDENCIES) - @$(PYTHON) setup.py develop --no-deps + @pip install -e . --no-deps @echo "" @echo "Completed building and installing: $@" @echo "" @@ -97,7 +97,7 @@ undevelop: @echo "Uninstalling $(PKG_NAME) development distributable: $@" @echo "" - @$(PYTHON) setup.py develop --no-deps -q --uninstall + @pip uninstall $(PKG_NAME) -y @echo "" @echo "Completed uninstalling: $@" diff --git a/docs/changelog/2024/november.rst b/docs/changelog/2024/november.rst new file mode 100644 index 00000000..dc60d032 --- /dev/null +++ b/docs/changelog/2024/november.rst @@ -0,0 +1,29 @@ +November 2024 +========== + +November 26 - Unicon v24.11 +------------------------ + + + +.. csv-table:: Module Versions + :header: "Modules", "Versions" + + ``unicon.plugins``, v24.11 + ``unicon``, v24.11 + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* unicon/bases + * Router/connection_provider + * Updated designate_handles to not change state of standby if it is locked. + * Added quad device specific unlock_standby method to execute configs only on Active console + + diff --git a/docs/changelog/index.rst b/docs/changelog/index.rst index 67187602..64691bd6 100644 --- a/docs/changelog/index.rst +++ b/docs/changelog/index.rst @@ -4,6 +4,7 @@ Changelog .. toctree:: :maxdepth: 2 + 2024/november 2024/october 2024/September 2024/august diff --git a/docs/changelog_plugins/2024/november.rst b/docs/changelog_plugins/2024/november.rst new file mode 100644 index 00000000..d72930e1 --- /dev/null +++ b/docs/changelog_plugins/2024/november.rst @@ -0,0 +1,50 @@ +November 2024 +========== + +November 26 - Unicon.Plugins v24.11 +------------------------ + + + +.. csv-table:: Module Versions + :header: "Modules", "Versions" + + ``unicon.plugins``, v24.11 + ``unicon``, v24.11 + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* iosxe + * Added UT for Quad device to test scenario when standby console is disabled + +* iosxr + * SPITFIRE plugin + * Added UNICON_BACKEND_DECODE_ERROR_LIMIT with a default value of 10, to handle scenarios when the device is slow + +* hvrp + * Update config pattern + * Update configure service to handle immediate vs two-stage config mode + +* nxos + * modify regex to handle new error pattern for NXOS + +* generic + * Modified enable_secret regex pattern to accommodate various outputs + * Updated password_handler to pass password if password key in context dict + + +-------------------------------------------------------------------------------- + Add +-------------------------------------------------------------------------------- + +* iosxe + * Update prompt recovery command + + diff --git a/docs/changelog_plugins/index.rst b/docs/changelog_plugins/index.rst index d4aea656..b0b7b047 100644 --- a/docs/changelog_plugins/index.rst +++ b/docs/changelog_plugins/index.rst @@ -4,6 +4,7 @@ Plugins Changelog .. toctree:: :maxdepth: 2 + 2024/november 2024/october 2024/September 2024/august diff --git a/src/unicon/plugins/__init__.py b/src/unicon/plugins/__init__.py index cd70af54..53f9d7d7 100644 --- a/src/unicon/plugins/__init__.py +++ b/src/unicon/plugins/__init__.py @@ -1,4 +1,4 @@ -__version__ = '24.10' +__version__ = '24.11' supported_chassis = [ 'single_rp', diff --git a/src/unicon/plugins/generic/patterns.py b/src/unicon/plugins/generic/patterns.py index 58618a3e..471ef4b0 100644 --- a/src/unicon/plugins/generic/patterns.py +++ b/src/unicon/plugins/generic/patterns.py @@ -73,7 +73,7 @@ def __init__(self): self.config_start = r'Enter configuration commands, one per line\.\s+End with CNTL/Z\.\s*$' - self.enable_secret = r'^.*?(Enter|Confirm) enable secret:\s*$' + self.enable_secret = r'^.*?(Enter|Confirm) enable secret( \[\])?:\s*$' self.enable_password = r'^.*?enable[\r\n]*.*?[Pp]assword( for )?(\S+)?: ?$' self.enter_your_selection_2 = r'^.*?Enter your selection( \[2])?:\s*$' diff --git a/src/unicon/plugins/generic/statements.py b/src/unicon/plugins/generic/statements.py index 56c22706..ee3f4d74 100644 --- a/src/unicon/plugins/generic/statements.py +++ b/src/unicon/plugins/generic/statements.py @@ -368,6 +368,8 @@ def password_handler(spawn, context, session): if context.get('username', '') == spawn.last_sent.rstrip() or ssh_tacacs_handler(spawn, context): if (tacacs_password := context.get('tacacs_password')): spawn.sendline(tacacs_password) + elif context.get('password'): + spawn.sendline(context['password']) else: spawn.sendline(context['line_password']) diff --git a/src/unicon/plugins/hvrp/patterns.py b/src/unicon/plugins/hvrp/patterns.py index 685c8324..76ddc28d 100644 --- a/src/unicon/plugins/hvrp/patterns.py +++ b/src/unicon/plugins/hvrp/patterns.py @@ -21,12 +21,12 @@ def __init__(self): self.username = r'^.*[Ll]ogin:' self.password = r'^.*[Pp]assword:' - # | # + # self.enable_prompt = r'^(.*)\<%N.*\>$' - - # [~HOSTNAME] | # # breaks on [\y\n] # Warning: All the configuration will be saved to the next startup configuration. Continue? [y/n]: - self.config_prompt = r'^.*\[(~|\*)%N.*\]' + # [~HOSTNAME] # two-stage config mode + # [HOSTNAME] # immediate config mode + self.config_prompt = r'^.*\[(?P~|\*)?%N.*\]' # Exit with uncommitted changes? [yes,no] (yes) self.commit_changes_prompt = r'Exit with uncommitted changes? [yes,no] (yes)\s*' diff --git a/src/unicon/plugins/hvrp/service_implementation.py b/src/unicon/plugins/hvrp/service_implementation.py index 94758949..4d262a0e 100644 --- a/src/unicon/plugins/hvrp/service_implementation.py +++ b/src/unicon/plugins/hvrp/service_implementation.py @@ -22,4 +22,22 @@ def __init__(self, connection, context, **kwargs): self.start_state = 'config' self.end_state = 'enable' self.service_name = 'config' - self.commit_cmd = 'commit' \ No newline at end of file + + def pre_service(self, *args, **kwargs): + super().pre_service(*args, **kwargs) + + # Check if device is operating in two-stage configuration mode. + # ============================================================= + spawn = self.get_spawn() + two_stage = spawn.match.last_match.groupdict().get('two_stage') + + # In the two-stage mode, if the user has modified configurations but has + # not submit the modification, the system prompt ~ is changed to *, + # prompting the user that the configurations are not submitted. After + # the user runs the commit command to submit the configurations, the + # system prompt * is restored to ~. + + if two_stage: + self.commit_cmd = 'commit' + else: + self.commit_cmd = '' diff --git a/src/unicon/plugins/iosxe/quad/statemachine.py b/src/unicon/plugins/iosxe/quad/statemachine.py index bc98b0cf..cf69361a 100644 --- a/src/unicon/plugins/iosxe/quad/statemachine.py +++ b/src/unicon/plugins/iosxe/quad/statemachine.py @@ -11,9 +11,6 @@ class IosXEQuadStateMachine(IosXEDualRpStateMachine): def create(self): super().create() - # Remove standby_locked state - self.remove_state('standby_locked') - # Add RPR state rpr = State('rpr', patterns.rpr_state) self.add_state(rpr) diff --git a/src/unicon/plugins/iosxe/settings.py b/src/unicon/plugins/iosxe/settings.py index 96b22206..82552f97 100644 --- a/src/unicon/plugins/iosxe/settings.py +++ b/src/unicon/plugins/iosxe/settings.py @@ -12,6 +12,8 @@ def __init__(self): # A single cycle of retries wasn't enough to recover an iosxe device # just rebooted after a "write erase". self.PROMPT_RECOVERY_RETRIES = 2 + self.PROMPT_RECOVERY_COMMANDS = ['\r', '\x1e', '\x03'] + self.ERROR_PATTERN = [ r'^%\s*[Ii]nvalid (command|input)', r'^%\s*[Ii]ncomplete (command|input)', diff --git a/src/unicon/plugins/iosxr/spitfire/settings.py b/src/unicon/plugins/iosxr/spitfire/settings.py index fa16f04a..eb63aaf4 100644 --- a/src/unicon/plugins/iosxr/spitfire/settings.py +++ b/src/unicon/plugins/iosxr/spitfire/settings.py @@ -27,6 +27,7 @@ def __init__(self): 'session-timeout 0' ] self.CONFIG_TIMEOUT = 600 + self.UNICON_BACKEND_DECODE_ERROR_LIMIT = 10 self.STANDBY_STATE_REGEX = r'Standby node .* is (.*)' # Default commands: Enter key , Ctrl-C, Enter Key diff --git a/src/unicon/plugins/nxos/setting.py b/src/unicon/plugins/nxos/setting.py index a15be84d..36d1757a 100644 --- a/src/unicon/plugins/nxos/setting.py +++ b/src/unicon/plugins/nxos/setting.py @@ -42,8 +42,8 @@ def __init__(self): r'^%\s*[Nn]ot supported.*', r'^%\s*[Ff]ail.*', r'^%\s*[Aa]bort.*' - r'^%\s*[Ee](RROR|rror).*', - r'^%\s*Ambiguous command' + r'^%?\s*[Ee](RROR|rror).*', + r'^%\s*Ambiguous command', ] self.GUESTSHELL_CONFIG_CMDS = [] diff --git a/src/unicon/plugins/tests/mock_data/hvrp/hvrp_mock_data.yaml b/src/unicon/plugins/tests/mock_data/hvrp/hvrp_mock_data.yaml index d3c0fc3a..5b89849f 100644 --- a/src/unicon/plugins/tests/mock_data/hvrp/hvrp_mock_data.yaml +++ b/src/unicon/plugins/tests/mock_data/hvrp/hvrp_mock_data.yaml @@ -81,4 +81,15 @@ bgp_config_uncommitted_change: - "0:,0,2,0" new_state: bgp_config +exec2: + prompt: <%N> + commands: + "system-view": + new_state: config2 +config2: + prompt: "[%N]" + commands: + "bgp 65000": "" + "return": + new_state: exec2 diff --git a/src/unicon/plugins/tests/mock_data/iosxe/cat9k_vwlc_reload_logs.txt b/src/unicon/plugins/tests/mock_data/iosxe/cat9k_vwlc_reload_logs.txt new file mode 100644 index 00000000..b86e90d4 --- /dev/null +++ b/src/unicon/plugins/tests/mock_data/iosxe/cat9k_vwlc_reload_logs.txt @@ -0,0 +1,118 @@ + + + Cisco Systems, Inc. + + 170 West Tasman Drive + + San Jose, California 95134-1706 + + + + +Cisco IOS Software [IOSXE], C9800-CL Software (C9800-CL-K9_IOSXE), Experimental Version 17.17.20240919:014147 [BLD_POLARIS_DEV_LATEST_20240919_003342:/nobackup/mcpre/s2c-build-ws 101] + +Copyright (c) 1986-2024 by Cisco Systems, Inc. + +Compiled Wed 18-Sep-24 18:42 by mcpre + + + +This software version supports only Smart Licensing as the software licensing mechanism. + + + +Please read the following carefully before proceeding. By downloading, + +installing, and/or using any Cisco software product, application, feature, + +license, or license key (collectively, the "Software"), you accept and + +agree to the following terms. If you do not agree, do not proceed and do not + +use this Software. + + +This Software and its use are governed by Cisco's General Terms and any + +relevant supplemental terms found at + +https://www.cisco.com/site/us/en/about/legal/contract-experience/index.html. + +If you have a negotiated agreement with Cisco that includes this Software, the + +terms of that agreement apply as well. In the event of a conflict, the order + +of precedence stated in your negotiated agreement controls. + + +Cisco Software is licensed on a term and/or subscription-basis. The license to + +the Software is valid only for the duration of the specified term, or in the + +case of a subscription-based license, only so long as all required subscription + +payments are current and fully paid-up. While Cisco may provide you + +licensing-related alerts, it is your sole responsibility to monitor your usage. + +Using Cisco Software without a valid license is not permitted and may result in + +fees charged to your account. Cisco reserves the right to terminate access to, + +or restrict the functionality of, any Cisco Software, or any features thereof, + +that are being used without a valid license. + + + +% Failed to initialize nvram + + +Database already initialized + +FIPS: Flash Key Check : Key Not Found, FIPS Mode Not Enabled + +platform initcisco C9800-CL (VXE) processor (revision VXE) with 4016588K/3075K bytes of memory. + +Processor board ID 9U9NBR9CPLO + +Router operating mode: Autonomous + +1 Virtual Ethernet interface + +3 Gigabit Ethernet interfaces + +32768K bytes of non-volatile configuration memory. + +8084084K bytes of physical memory. + +6201343K bytes of virtual hard disk at bootflash:. + +0K bytes of Cloud S3 Storage at cloudfs:. + +Installation mode is BUNDLE + + + +No startup-config, starting autoinstall/pnp/ztp... + + +Autoinstall will terminate if any input is detected on console + + +Autoinstall trying DHCPv4 on Vlan1 + + +-------------------------------------------------- + + System is booted with ASCII based startup configuration + + due to missing binary configuration or previous condition. + + Please perform "write mem" to generate binary + + configuration. System uses binary-config internally to + + reduce overall bootime significantly. + +-------------------------------------------------- \ No newline at end of file diff --git a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_vwlc.yaml b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_vwlc.yaml new file mode 100644 index 00000000..7bba0ae7 --- /dev/null +++ b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_vwlc.yaml @@ -0,0 +1,139 @@ +c9k_vwlc_login: + prompt: "Username: " + commands: + "admin": + new_state: c9k_vwlc_password + +c9k_vwlc_password: + prompt: "Password: " + commands: + "cisco": + new_state: c9k_vwlc_enable + +c9k_vwlc_enable: + prompt: "%N#" + commands: + "show version | include operating mode": "" + "reload": + new_state: c9k_vwlc_system_config_change + +c9k_vwlc_system_config_change: + prompt: "\nSystem configuration has been modified. Save? [yes/no]:" + commands: + "n": + new_state: c9k_vwlc_reload_proceed + "no": + new_state: c9k_vwlc_reload_proceed + +c9k_vwlc_reload_proceed: + prompt: "\nProceed with reload? [confirm]" + commands: + "": + response: file|mock_data/iosxe/cat9k_vwlc_reload_logs.txt + timing: + - 0:,0,0.005 + new_state: c9k_vwlc_config_dialog + +c9k_vwlc_config_dialog: + preface: + timing: + - 0:,0,0.01 + response: |2 + --- System Configuration Dialog --- + prompt: "\nWould you like to enter the initial configuration dialog? [yes/no]: " + commands: + "no": + new_state: c9k_vwlc_enter_enable_config_secret + response: |2 + + The enable secret is a password used to protect + access to privileged EXEC and configuration modes. + This password, after entered, becomes encrypted in + the configuration. + ------------------------------------------------- + secret should be of minimum 10 characters with + at least 1 upper case, 1 lower case, 1 digit and + should not contain [cisco] + ------------------------------------------------- + + +c9k_vwlc_enter_enable_config_secret: + prompt: "\n Enter enable secret: " + commands: + "Secret12345": + new_state: c9k_vwlc_confirm_enable_config_secret + +c9k_vwlc_confirm_enable_config_secret: + prompt: " Confirm enable secret: " + commands: + "Secret12345": + new_state: c9k_vwlc_enter_enable_secret_selection + response: |2 + + The following configuration command script was created: + enable secret 9 $9$gCGcm2IWBJOT5U$p6jqb1plxOJpr3yYwa/3fUSfpQjM.RgfcunyUXhqfRA + ! + end + + [0] Go to the IOS command prompt without saving this config. + [1] Return back to the setup without saving this config. + [2] Save this configuration to nvram and exit. + +c9k_vwlc_enter_enable_secret_selection: + prompt: "\nEnter your selection: " + commands: + "2": + new_state: c9k_vwlc_enter_encryption_config_selection + response: | + + Building configuration... + [OK] + Use the enabled mode 'configure' command to modify this configuration. + + -----System Security Configuration Dialog----- + +c9k_vwlc_enter_encryption_config_selection: + prompt: "\nWould you like to enter the initial configuration dialog? [yes/no]: " + commands: + "no": + new_state: c9k_vwlc_enter_enable_config_current_secret + response: |2 + + The enable secret is a password used to protect + access to privileged EXEC and configuration modes. + This password, after entered, becomes encrypted in + the configuration. + ------------------------------------------------- + secret should be of minimum 10 characters with + at least 1 upper case, 1 lower case, 1 digit and + should not contain [cisco] + ------------------------------------------------- + +c9k_vwlc_enter_enable_config_current_secret: + prompt: "\nEnter enable secret []: " + commands: + "Secret12345": + new_state: c9k_vwlc_enter_enable_config_current_secret_again + +c9k_vwlc_enter_enable_config_current_secret_again: + prompt: "\nConfirm enable secret []: " + commands: + "Secret12345": + new_state: c9k_vwlc_enter_current_secret_selection + response: |2 + + The following configuration command script was created: + + enable secret 9 $9$gCGcm2IWBJOT5U$p6jqb1plxOJpr3yYwa/3fUSfpQjM.RgfcunyUXhqfRA + ! + end + + [0] Go to the IOS command prompt without saving this config. + [1] Return back to the setup without saving this config. + [2] Save this configuration to nvram and exit. + +c9k_vwlc_enter_current_secret_selection: + prompt: "\nEnter your selection: " + commands: + "2": + new_state: press_return diff --git a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_quad.yaml b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_quad.yaml index 2f0df7ec..654eebec 100644 --- a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_quad.yaml +++ b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_quad.yaml @@ -803,4 +803,24 @@ quad_install_add_commit: rsync: read error: Connection reset by peer (104) FAILED: install_add_activate_commit : Copy bootflash:asr1000rpx86-universalk9.BLD_V16 - new_state: quad_enable \ No newline at end of file + new_state: quad_enable + +quad_stby_locked_login: + prompt: "Username: " + commands: + "cisco": + new_state: quad_stby_locked_password + +quad_stby_locked_password: + prompt: "Password: " + commands: + "cisco": + new_state: quad_stby_locked_exec + +quad_stby_locked_exec: + prompt: "%N-stby>" + preface: | + Standby console disabled + commands: + "enable": + new_state: quad_stby_enable_pwd diff --git a/src/unicon/plugins/tests/test_plugin_hvrp.py b/src/unicon/plugins/tests/test_plugin_hvrp.py index 89d4fbda..fc356d4c 100644 --- a/src/unicon/plugins/tests/test_plugin_hvrp.py +++ b/src/unicon/plugins/tests/test_plugin_hvrp.py @@ -2,96 +2,147 @@ import yaml import unittest +import unicon from unicon import Connection from unicon.eal.dialogs import Dialog from unicon.mock.mock_device import mockdata_path -from unicon.core.errors import SubCommandFailure,UniconAuthenticationError -with open(os.path.join(mockdata_path, 'hvrp/hvrp_mock_data.yaml'), 'rb') as datafile: +from unicon.core.errors import SubCommandFailure + +with open(os.path.join(mockdata_path, "hvrp/hvrp_mock_data.yaml"), "rb") as datafile: mock_data = yaml.safe_load(datafile.read()) +unicon.settings.Settings.POST_DISCONNECT_WAIT_SEC = 0 +unicon.settings.Settings.GRACEFUL_DISCONNECT_WAIT_SEC = 0.2 + + class TestHuaweiVrpPluginConnect(unittest.TestCase): def test_login_connect(self): - c = Connection(hostname='ooo-gg-9999zz-99', - start=['mock_device_cli --os hvrp --state exec'], - os='hvrp', - credentials={'default': {'username': 'nielsvanhooy', 'password': 'kpn'}}) + c = Connection( + hostname="ooo-gg-9999zz-99", + start=["mock_device_cli --os hvrp --state exec"], + os="hvrp", + credentials={"default": {"username": "nielsvanhooy", "password": "kpn"}}, + ) c.connect() - self.assertIn('', c.spawn.match.match_output) + self.assertIn("", c.spawn.match.match_output) c.disconnect() def test_login_connect_ssh(self): - c = Connection(hostname='ooo-gg-9999zz-99', - start=['mock_device_cli --os hvrp --state connect_ssh'], - os='hvrp', - credentials={'default': {'username': 'nielsvanhooy', 'password': 'kpn'}}) + c = Connection( + hostname="ooo-gg-9999zz-99", + start=["mock_device_cli --os hvrp --state connect_ssh"], + os="hvrp", + credentials={"default": {"username": "nielsvanhooy", "password": "kpn"}}, + ) c.connect() - self.assertIn('', c.spawn.match.match_output) + self.assertIn("", c.spawn.match.match_output) c.disconnect() def test_login_connect_connectReply(self): - c = Connection(hostname='ooo-gg-9999zz-99', - start=['mock_device_cli --os hvrp --state exec'], - os='hvrp', - credentials={'default': {'username': 'nielsvanhooy', 'password': 'kpn'}}, - connect_reply = Dialog([[r'^(.*?)Password:']])) + c = Connection( + hostname="ooo-gg-9999zz-99", + start=["mock_device_cli --os hvrp --state exec"], + os="hvrp", + credentials={"default": {"username": "nielsvanhooy", "password": "kpn"}}, + connect_reply=Dialog([[r"^(.*?)Password:"]]), + ) c.connect() - self.assertIn("^(.*?)Password:", str(c.connection_provider.get_connection_dialog())) + self.assertIn( + "^(.*?)Password:", str(c.connection_provider.get_connection_dialog()) + ) c.disconnect() + class TestHuaweiVrpPluginExecute(unittest.TestCase): def test_execute_show_feature(self): - c = Connection(hostname='ooo-gg-9999zz-99', - start=['mock_device_cli --os hvrp --state exec'], - os='hvrp', - credentials={'default': {'username': 'nielsvanhooy', 'password': 'kpn'}}, - init_exec_commands=[], - init_config_commands=[] - ) + c = Connection( + hostname="ooo-gg-9999zz-99", + start=["mock_device_cli --os hvrp --state exec"], + os="hvrp", + credentials={"default": {"username": "nielsvanhooy", "password": "kpn"}}, + init_exec_commands=[], + init_config_commands=[], + ) c.connect() - cmd = 'display version' - expected_response = mock_data['exec']['commands'][cmd].strip() - ret = c.execute(cmd).replace('\r', '') + cmd = "display version" + expected_response = mock_data["exec"]["commands"][cmd].strip() + ret = c.execute(cmd).replace("\r", "") self.assertIn(expected_response, ret) c.disconnect() def test_execute_unsupported(self): - c = Connection(hostname='ooo-gg-9999zz-99', - start=['mock_device_cli --os hvrp --state exec'], - os='hvrp', - credentials={'default': {'username': 'nielsvanhooy', 'password': 'kpn'}}, - init_exec_commands=[], - init_config_commands=[] - ) + c = Connection( + hostname="ooo-gg-9999zz-99", + start=["mock_device_cli --os hvrp --state exec"], + os="hvrp", + credentials={"default": {"username": "nielsvanhooy", "password": "kpn"}}, + init_exec_commands=[], + init_config_commands=[], + ) c.connect() - self.assertRaises(SubCommandFailure,c.execute,"display vresion") + self.assertRaises(SubCommandFailure, c.execute, "display vresion") c.disconnect() + class TestHuaweiVrpPluginConfigure(unittest.TestCase): def test_config(self): - c = Connection(hostname='ooo-gg-9999zz-99', - start=['mock_device_cli --os hvrp --state exec'], - os='hvrp', - credentials={'default': {'username': 'nielsvanhooy', 'password': 'kpn'}}, - init_config_commands=[] - ) + c = Connection( + hostname="ooo-gg-9999zz-99", + start=["mock_device_cli --os hvrp --state exec"], + os="hvrp", + credentials={"default": {"username": "nielsvanhooy", "password": "kpn"}}, + init_config_commands=[], + ) c.connect() - c.configure(["bgp 65000","peer 1.1.1.1 as-number 64666"]) + c.configure(["bgp 65000", "peer 1.1.1.1 as-number 64666"]) c.disconnect() def test_unsupported_config(self): - c = Connection(hostname='ooo-gg-9999zz-99', - start=['mock_device_cli --os hvrp --state exec'], - os='hvrp', - credentials={'default': {'username': 'nielsvanhooy', 'password': 'kpn'}}, - init_config_commands=[] - ) + c = Connection( + hostname="ooo-gg-9999zz-99", + start=["mock_device_cli --os hvrp --state exec"], + os="hvrp", + credentials={"default": {"username": "nielsvanhooy", "password": "kpn"}}, + init_config_commands=[], + ) c.connect() - self.assertRaises(SubCommandFailure,c.configure,"bpg 65000") + self.assertRaises(SubCommandFailure, c.configure, "bpg 65000") c.disconnect() + def test_learn_hostname_configure_immediate(self): + c = Connection( + hostname="N09990", + start=["mock_device_cli --os hvrp --state exec2 --hostname N09990"], + os="hvrp", + learn_hostname=True, + init_exec_commands=[], + init_config_commands=[], + ) + try: + c.connect() + c.configure('bgp 65000') + finally: + c.disconnect() + + def test_learn_hostname_configure_two_stage(self): + c = Connection( + hostname="ooo-gg-9999zz-99", + start=["mock_device_cli --os hvrp --state exec --hostname ooo-gg-9999zz-99"], + os="hvrp", + learn_hostname=True, + init_exec_commands=[], + init_config_commands=[], + ) + try: + c.connect() + c.configure('bgp 65000') + finally: + c.disconnect() + + if __name__ == "__main__": unittest.main() diff --git a/src/unicon/plugins/tests/test_plugin_iosxe_cat9k_vwlc.py b/src/unicon/plugins/tests/test_plugin_iosxe_cat9k_vwlc.py new file mode 100644 index 00000000..f1bc4968 --- /dev/null +++ b/src/unicon/plugins/tests/test_plugin_iosxe_cat9k_vwlc.py @@ -0,0 +1,37 @@ +""" +Unittests for iosxe/cat9k plugin +""" + +import unittest + + +import unicon +from unicon import Connection + +unicon.settings.Settings.POST_DISCONNECT_WAIT_SEC = 0 +unicon.settings.Settings.GRACEFUL_DISCONNECT_WAIT_SEC = 0.2 + + +class TestIosXECat9kPluginReload(unittest.TestCase): + + def test_reload(self): + c = Connection(hostname='Router', + start=['mock_device_cli --os iosxe --state c9k_vwlc_login --hostname WLC'], + os='iosxe', + platform='cat9k', + type='vWLC', + credentials=dict(default=dict(username='admin', password='cisco'), + enable=dict(password='Secret12345')), + learn_hostname=True, + log_buffer=True, + init_exec_commands=[], + init_config_commands=[], + debug=False) + try: + c.connect() + c.settings.POST_RELOAD_WAIT = 1 + c.settings.PASSWORD_ATTEMPTS = 5 + c.reload() + self.assertEqual(c.state_machine.current_state, 'enable') + finally: + c.disconnect() diff --git a/src/unicon/plugins/tests/test_plugin_iosxe_quad.py b/src/unicon/plugins/tests/test_plugin_iosxe_quad.py index c748b122..9013931d 100644 --- a/src/unicon/plugins/tests/test_plugin_iosxe_quad.py +++ b/src/unicon/plugins/tests/test_plugin_iosxe_quad.py @@ -108,6 +108,22 @@ def test_quad_connect3(self): d.disconnect() md.stop() + def test_quad_connect4(self): + d = Connection(hostname='Router', + start=['mock_device_cli --os iosxe --state quad_login --hostname Router', + 'mock_device_cli --os iosxe --state quad_ics_login --hostname Router', + 'mock_device_cli --os iosxe --state quad_stby_locked_login --hostname Router', + 'mock_device_cli --os iosxe --state quad_ics_login --hostname Router'], + os='iosxe', + chassis_type='quad', + username='cisco', + tacacs_password='cisco', + enable_password='cisco') + d.connect() + d.execute('term width 0') + self.assertEqual(d.spawn.match.match_output, 'term width 0\r\nRouter#') + d.disconnect() + class TestIosXEQuadDisableEnable(unittest.TestCase):