From c36106056737afa8d90ffeea4169a402433596f3 Mon Sep 17 00:00:00 2001 From: Thomas Ryan Date: Mon, 27 May 2024 11:14:04 -0400 Subject: [PATCH 01/11] Releasing v24.5 --- docs/changelog/2024/may.rst | 59 ++++++++++ docs/changelog/index.rst | 1 + docs/changelog_plugins/2024/may.rst | 51 ++++++++ docs/changelog_plugins/index.rst | 1 + src/unicon/plugins/__init__.py | 2 +- .../iosxe/cat8k/service_implementation.py | 4 + .../iosxe/cat9k/service_implementation.py | 4 +- src/unicon/plugins/iosxe/cat9k/statements.py | 3 +- .../plugins/iosxe/connection_provider.py | 7 ++ .../iosxr/spitfire/service_implementation.py | 4 +- src/unicon/plugins/sros/patterns.py | 2 +- .../iosxe/iosxe_mock_data_cat9k_reload.yaml | 46 ++++++++ .../iosxe/iosxe_mock_data_sdwan.yaml | 111 +++++++++++++++++- .../tests/mock_data/sros/sros_mock_data.yaml | 10 +- .../plugins/tests/test_plugin_iosxe_cat9k.py | 30 +++++ .../plugins/tests/test_plugin_iosxe_sdwan.py | 26 +++- src/unicon/plugins/tests/test_plugin_sros.py | 6 + 17 files changed, 355 insertions(+), 12 deletions(-) create mode 100644 docs/changelog/2024/may.rst create mode 100644 docs/changelog_plugins/2024/may.rst diff --git a/docs/changelog/2024/may.rst b/docs/changelog/2024/may.rst new file mode 100644 index 00000000..1986ea03 --- /dev/null +++ b/docs/changelog/2024/may.rst @@ -0,0 +1,59 @@ +May 2024 +========== + +May 28 - Unicon v24.5 +------------------------ + + + +.. csv-table:: Module Versions + :header: "Modules", "Versions" + + ``unicon.plugins``, v24.5 + ``unicon``, v24.5 + +Install Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install unicon.plugins + bash$ pip install unicon + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install --upgrade unicon.plugins + bash$ pip install --upgrade unicon + +Features and Bug Fixes: +^^^^^^^^^^^^^^^^^^^^^^^ + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* playback + * mock_helper + * Added show version | include operating mode to list of recorded commands + + +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* iosxe + * cat9k + * Modified summary.py + * Added reload_confirm_iosxe to reload_to_rommon_statement_list + * Added post time + * Added POST_SWITCHOVER_WAIT before enable + + diff --git a/docs/changelog/index.rst b/docs/changelog/index.rst index 6267ffc7..24e1f86a 100644 --- a/docs/changelog/index.rst +++ b/docs/changelog/index.rst @@ -4,6 +4,7 @@ Changelog .. toctree:: :maxdepth: 2 + 2024/may 2024/april 2024/march 2024/february diff --git a/docs/changelog_plugins/2024/may.rst b/docs/changelog_plugins/2024/may.rst new file mode 100644 index 00000000..aaa05730 --- /dev/null +++ b/docs/changelog_plugins/2024/may.rst @@ -0,0 +1,51 @@ +May 2024 +========== + +May 28 - Unicon.Plugins v24.5 +------------------------ + + + +.. csv-table:: Module Versions + :header: "Modules", "Versions" + + ``unicon.plugins``, v24.5 + ``unicon``, v24.5 + +Install Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install unicon.plugins + bash$ pip install unicon + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install --upgrade unicon.plugins + bash$ pip install --upgrade unicon + +Features and Bug Fixes: +^^^^^^^^^^^^^^^^^^^^^^^ + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* sros + * Updated mdcli regex prompt to accommodate various output + +* iosxe + * CAT9K + * Updated regex in Rommon service + * Modified learn_tokens to go to enable mode before sending stop PnP disovery + + diff --git a/docs/changelog_plugins/index.rst b/docs/changelog_plugins/index.rst index 04171b38..5e79066b 100644 --- a/docs/changelog_plugins/index.rst +++ b/docs/changelog_plugins/index.rst @@ -4,6 +4,7 @@ Plugins Changelog .. toctree:: :maxdepth: 2 + 2024/may 2024/april 2024/march 2024/february diff --git a/src/unicon/plugins/__init__.py b/src/unicon/plugins/__init__.py index 3f8de17c..dc6b157f 100644 --- a/src/unicon/plugins/__init__.py +++ b/src/unicon/plugins/__init__.py @@ -1,4 +1,4 @@ -__version__ = '24.4' +__version__ = '24.5' supported_chassis = [ 'single_rp', diff --git a/src/unicon/plugins/iosxe/cat8k/service_implementation.py b/src/unicon/plugins/iosxe/cat8k/service_implementation.py index 5683ce8f..55f14090 100644 --- a/src/unicon/plugins/iosxe/cat8k/service_implementation.py +++ b/src/unicon/plugins/iosxe/cat8k/service_implementation.py @@ -115,6 +115,10 @@ def call_service(self, command=None, timeout=con.connection_timeout, context=self.context ) + + con.log.info(f'Waiting {con.settings.POST_SWITCHOVER_WAIT} seconds before going to enable mode') + sleep(con.settings.POST_SWITCHOVER_WAIT) + con.spawn.sendline() con.state_machine.go_to( 'enable', diff --git a/src/unicon/plugins/iosxe/cat9k/service_implementation.py b/src/unicon/plugins/iosxe/cat9k/service_implementation.py index 617a72e8..3b114338 100644 --- a/src/unicon/plugins/iosxe/cat9k/service_implementation.py +++ b/src/unicon/plugins/iosxe/cat9k/service_implementation.py @@ -125,10 +125,10 @@ def pre_service(self, *args, **kwargs): con.spawn, context=self.context) boot_info = con.execute('show boot') - m = re.search(r'Enable Break = (yes|no)|ENABLE_BREAK variable (= yes|does not exist)', boot_info) + m = re.search(r'Enable Break = (yes|no|0|1)|ENABLE_BREAK variable (= yes|does not exist)', boot_info) if m: break_enabled = m.group() - if 'yes' not in break_enabled: + if all(i not in break_enabled for i in ['yes', '1']): con.configure('boot enable-break') else: raise SubCommandFailure('Could not determine if break is enabled, cannot transition to rommon') diff --git a/src/unicon/plugins/iosxe/cat9k/statements.py b/src/unicon/plugins/iosxe/cat9k/statements.py index 9c327e02..affe2972 100644 --- a/src/unicon/plugins/iosxe/cat9k/statements.py +++ b/src/unicon/plugins/iosxe/cat9k/statements.py @@ -1,7 +1,7 @@ from unicon.eal.dialogs import Statement from unicon.plugins.generic.service_statements import ( - save_env, confirm_reset, reload_confirm, reload_confirm_ios) + save_env, confirm_reset, reload_confirm, reload_confirm_ios, reload_confirm_iosxe) from .patterns import IosXECat9kPatterns @@ -20,4 +20,5 @@ confirm_reset, reload_confirm, reload_confirm_ios, + reload_confirm_iosxe, boot_interrupt_stmt] diff --git a/src/unicon/plugins/iosxe/connection_provider.py b/src/unicon/plugins/iosxe/connection_provider.py index d9df63af..fd2afbf2 100644 --- a/src/unicon/plugins/iosxe/connection_provider.py +++ b/src/unicon/plugins/iosxe/connection_provider.py @@ -47,6 +47,13 @@ def learn_tokens(self): GenericPatterns().learn_os_prompt) con.state_machine.add_state(self.learn_tokens_state) + # Change to enable state before sending stop PnP disovery + con.state_machine.go_to('enable', + con.spawn, + context=con.context, + timeout=con.connection_timeout, + prompt_recovery=con.prompt_recovery) + # The first thing we need to is to send stop PnP discovery otherwise device will not execute any command. con.spawn.sendline('pnpa service discovery stop') # The device may reload after the command we get the dialog statements from reload service and try to handle that diff --git a/src/unicon/plugins/iosxr/spitfire/service_implementation.py b/src/unicon/plugins/iosxr/spitfire/service_implementation.py index 07b3bca0..5f195c5f 100644 --- a/src/unicon/plugins/iosxr/spitfire/service_implementation.py +++ b/src/unicon/plugins/iosxr/spitfire/service_implementation.py @@ -312,10 +312,10 @@ def call_service(self, line_type = line_type[1] if reload_creds: - context = self.context.copy() + context = con.active.context.copy() context.update(cred_list=reload_creds) else: - context = self.context + context = con.active.context if line_type != 'Console': raise Exception("Console is not used.") diff --git a/src/unicon/plugins/sros/patterns.py b/src/unicon/plugins/sros/patterns.py index e33a175e..72aad2ba 100644 --- a/src/unicon/plugins/sros/patterns.py +++ b/src/unicon/plugins/sros/patterns.py @@ -9,6 +9,6 @@ def __init__(self): super().__init__() self.continue_connect = r'Are you sure you want to continue connecting \(yes/no(/\[fingerprint\])?\)' self.permission_denied = r'^Permission denied, please try again\.\s?$' - self.mdcli_prompt = r'^(.*?)\[.*\][\r\n]+[AB]:.*@%N[#$]\s?$' + self.mdcli_prompt = r'^(.*?)(\[[^\]]*\])?[\r\n]+[AB]:.*@%N[#$]\s?$' self.classiccli_prompt = r'^(.*?)\*?[AB]:%N(>.*)?[#$]\s?$' self.discard_uncommitted = r'Discard uncommitted changes\? \[y,n\]' diff --git a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_cat9k_reload.yaml b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_cat9k_reload.yaml index ec1604ca..84c6fa26 100644 --- a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_cat9k_reload.yaml +++ b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_cat9k_reload.yaml @@ -87,6 +87,52 @@ cat9k_enable_reload_to_rommon_break2: "reload": new_state: cat9k_boot_to_rommon + +cat9k_enable_reload_to_rommon_break3: + prompt: "switch1#" + commands: + "show version | include operating mode": "" + "show boot": | + --------------------------- + Switch 1 + --------------------------- + Current Boot Variables: + BOOT variable does not exist + + Boot Variables on next reload: + BOOT variable does not exist + Manual Boot = yes + Enable Break = 1 + Boot Mode = DEVICE + iPXE Timeout = 0 + "config term": + new_state: cat9k_enable_reload_to_rommon_break_config + "reload": + new_state: cat9k_boot_to_rommon + + +cat9k_enable_reload_to_rommon_break4: + prompt: "switch1#" + commands: + "show version | include operating mode": "" + "show boot": | + --------------------------- + Switch 1 + --------------------------- + Current Boot Variables: + BOOT variable does not exist + + Boot Variables on next reload: + BOOT variable does not exist + Manual Boot = yes + Enable Break = 0 + Boot Mode = DEVICE + iPXE Timeout = 0 + "config term": + new_state: cat9k_enable_reload_to_rommon_break_config + "reload": + new_state: cat9k_boot_to_rommon + cat9k_enable_reload_to_rommon_break_config: prompt: "%N(config)#" commands: diff --git a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_sdwan.yaml b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_sdwan.yaml index e6ab4249..81930436 100644 --- a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_sdwan.yaml +++ b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_sdwan.yaml @@ -121,4 +121,113 @@ sdwan_config_commit_confirm: prompt: "Proceed? [yes,no]" commands: "yes": - new_state: sdwan_config2 \ No newline at end of file + new_state: sdwan_config2 + +sdwan_controller_mode: + prompt: "%N>" + commands: + "show version | include operating mode": "Router operating mode: Controller-Managed" + "enable": + new_state: sdwan_controller_mode_enable + +sdwan_controller_mode_enable: + prompt: "%N#" + commands: + <<: *sdwan_enable_cmds + "show version": | + Cisco IOS XE Software, Version BLD_V1715_THROTTLE_LATEST_20240501_033727_V17_15_0_32 + Cisco IOS Software [IOSXE], c8000aep Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Experimental Version 17.15.20240501:040851 [BLD_V1715_THROTTLE_LATEST_20240501_033727:/nobackup/mcpre/s2c-build-ws 102] + Copyright (c) 1986-2024 by Cisco Systems, Inc. + Compiled Tue 30-Apr-24 21:09 by mcpre + + + Cisco IOS-XE software, Copyright (c) 2005-2024 by cisco Systems, Inc. + All rights reserved. Certain components of Cisco IOS-XE software are + licensed under the GNU General Public License ("GPL") Version 2.0. The + software code licensed under GPL Version 2.0 is free software that comes + with ABSOLUTELY NO WARRANTY. You can redistribute and/or modify such + GPL code under the terms of GPL Version 2.0. For more details, see the + documentation or "License Notice" file accompanying the IOS-XE software, + or the applicable URL provided on the flyer accompanying the IOS-XE + software. + + + ROM: Encore_V14 + Encore uptime is 1 day, 14 hours, 52 minutes + Uptime for this control processor is 1 day, 14 hours, 53 minutes + System returned to ROM by Image Install + System image file is "bootflash:packages.conf" + Last reload reason: Image Install + + + + This product contains cryptographic features and is subject to United + States and local country laws governing import, export, transfer and + use. Delivery of Cisco cryptographic products does not imply + third-party authority to import, export, distribute or use encryption. + Importers, exporters, distributors and users are responsible for + compliance with U.S. and local country laws. By using this product you + agree to comply with applicable laws and regulations. If you are unable + to comply with U.S. and local laws, return this product immediately. + + A summary of U.S. laws governing Cisco cryptographic products may be found at: + http://www.cisco.com/wwl/export/crypto/tool/stqrg.html + + If you require further assistance please contact us by sending email to + export@cisco.com. + + License Mode: Controller-Managed + + Smart Licensing Status: Smart Licensing Using Policy + + cisco C8530-12X4QC (1EN) processor (revision 1EN) with 14594820K/6147K bytes of memory. + Processor board ID FLX273502YF + Router operating mode: Controller-Managed + 12 Ten Gigabit Ethernet interfaces + 3 Forty Gigabit Ethernet interfaces + 32768K bytes of non-volatile configuration memory. + 33554432K bytes of physical memory. + 464553984K bytes of NVMe SSD flash at bootflash:. + + Configuration register is 0x2102 + "show inventory": | + NAME: "Chassis", DESCR: "Cisco C8530-12X4QC Chassis" + PID: C8530-12X4QC , VID: V00 , SN: FLX273502YF + + NAME: "Fan Tray", DESCR: "Cisco C8500-FAN-1R Fan Tray" + PID: C8500-FAN-1R , VID: , SN: + + NAME: "module 0", DESCR: "Cisco C8530-12X4QC Modular Interface Processor" + PID: C8530-12X4QC , VID: , SN: + + NAME: "SPA subslot 0/0", DESCR: "8-port 10/1G SFP Ethernet Port Adapter" + PID: 8xSFP+ , VID: N/A , SN: JAE12345678 + + NAME: "subslot 0/0 transceiver 0", DESCR: "10GE SR" + PID: SFP-10G-SR-S , VID: V01 , SN: OPM25160UGU + + NAME: "subslot 0/0 transceiver 1", DESCR: "10GE SR" + PID: SFP-10G-SR , VID: V03 , SN: AGA15514DWD + + NAME: "subslot 0/0 transceiver 2", DESCR: "10GE SR" + PID: SFP-10G-SR-S , VID: V01 , SN: FNS26090JAL + + NAME: "subslot 0/0 transceiver 3", DESCR: "10GE SR" + PID: SFP-10G-SR-S , VID: V01 , SN: FNS26090L1M + + NAME: "subslot 0/0 transceiver 4", DESCR: "10GE SR" + PID: SFP-10G-SR-S , VID: V01 , SN: FNS26090JAW + + NAME: "SPA subslot 0/1", DESCR: "1-port 40/1-port 100/4-port 10 Gigabit QSFP Ethernet Port Adapter" + PID: 4xSFP+/1xQSFP , VID: N/A , SN: JAE12345678 + + NAME: "SPA subslot 0/2", DESCR: "3-port 40 / 1-port 100 Gigabit QSFP Ethernet Port Adapter" + PID: 3xQSFP , VID: N/A , SN: JAE12345678 + + NAME: "module R0", DESCR: "Cisco C8530-12X4QC Route Processor" + PID: C8530-12X4QC , VID: V00 , SN: JAE273709CU + + NAME: "module F0", DESCR: "Cisco C8530-12X4QC Embedded Services Processor" + PID: C8530-12X4QC , VID: , SN: + "uname -a": "" + "pnpa service discovery stop": "" \ No newline at end of file diff --git a/src/unicon/plugins/tests/mock_data/sros/sros_mock_data.yaml b/src/unicon/plugins/tests/mock_data/sros/sros_mock_data.yaml index 370035c8..853cbc95 100644 --- a/src/unicon/plugins/tests/mock_data/sros/sros_mock_data.yaml +++ b/src/unicon/plugins/tests/mock_data/sros/sros_mock_data.yaml @@ -42,6 +42,13 @@ mdcli_execute: new_state: mdcli_configure_global "environment console length 512": "" "environment console width 512": "" + "show port description": | + 1/1/c1 QSFP28 Connector + 1/1/c1/1 IMO1CRIP002:1/1/c22/1 C00235986 [I] + 1/1/c2 QSFP28 Connector + 1/1/c2/1 IMO1CRIP002:1/1/c23/1 C00235987 [I] + + 2024-03-18 17:25:17 WEST keys: 'ctrl-z': "" "//": @@ -189,4 +196,5 @@ classiccli_config_lag_access: new_state: classiccli_config_lag keys: "ctrl-z": - new_state: classiccli_execute \ No newline at end of file + new_state: classiccli_execute + diff --git a/src/unicon/plugins/tests/test_plugin_iosxe_cat9k.py b/src/unicon/plugins/tests/test_plugin_iosxe_cat9k.py index 90094279..cb17fe1c 100644 --- a/src/unicon/plugins/tests/test_plugin_iosxe_cat9k.py +++ b/src/unicon/plugins/tests/test_plugin_iosxe_cat9k.py @@ -445,6 +445,36 @@ def test_rommon_enable_break2(self): self.assertEqual(c.state_machine.current_state, 'rommon') c.disconnect() + def test_rommon_enable_break3(self): + c = Connection(hostname='switch', + start=['mock_device_cli --os iosxe --state cat9k_enable_reload_to_rommon_break3'], + os='iosxe', + platform='cat9k', + mit=True, + credentials=dict(default=dict(username='cisco', password='cisco'), + alt=dict(username='admin', password='lab')), + settings=dict(POST_DISCONNECT_WAIT_SEC=0, GRACEFUL_DISCONNECT_WAIT_SEC=0.2), + log_buffer=True) + c.connect() + c.rommon() + self.assertEqual(c.state_machine.current_state, 'rommon') + c.disconnect() + + def test_rommon_enable_break4(self): + c = Connection(hostname='switch', + start=['mock_device_cli --os iosxe --state cat9k_enable_reload_to_rommon_break4'], + os='iosxe', + platform='cat9k', + mit=True, + credentials=dict(default=dict(username='cisco', password='cisco'), + alt=dict(username='admin', password='lab')), + settings=dict(POST_DISCONNECT_WAIT_SEC=0, GRACEFUL_DISCONNECT_WAIT_SEC=0.2), + log_buffer=True) + c.connect() + c.rommon() + self.assertEqual(c.state_machine.current_state, 'rommon') + c.disconnect() + def test_reload_with_image(self): c = Connection(hostname='switch', start=['mock_device_cli --os iosxe --state cat9k_enable_reload_to_rommon'], diff --git a/src/unicon/plugins/tests/test_plugin_iosxe_sdwan.py b/src/unicon/plugins/tests/test_plugin_iosxe_sdwan.py index ae0c63a9..18f07bd9 100644 --- a/src/unicon/plugins/tests/test_plugin_iosxe_sdwan.py +++ b/src/unicon/plugins/tests/test_plugin_iosxe_sdwan.py @@ -76,9 +76,29 @@ def test_iosxe_sdwan_connect(self): finally: d.disconnect() - @classmethod - def tearDownClass(self): - self.md.stop() + def test_iosxe_sdwan_controller_mode_connect(self): + testbed = ''' + devices: + Router: + type: router + os: iosxe + platform: sdwan + credentials: + default: + username: cisco + password: cisco + connections: + defaults: + class: 'unicon.Unicon' + cli: + command: mock_device_cli --os iosxe --state sdwan_controller_mode + ''' + t = loader.load(testbed) + d = t.devices.Router + try: + d.connect() + finally: + d.disconnect() class TestIosXESDWANConfigure(unittest.TestCase): diff --git a/src/unicon/plugins/tests/test_plugin_sros.py b/src/unicon/plugins/tests/test_plugin_sros.py index 902c9b4c..a12343f4 100644 --- a/src/unicon/plugins/tests/test_plugin_sros.py +++ b/src/unicon/plugins/tests/test_plugin_sros.py @@ -29,6 +29,12 @@ def test_mdcli_execute(self): expect = self.md.mock_data['mdcli_execute']['commands'][cmd] self.assertEqual(self.joined(output), self.joined(expect)) + def test_mdcli_1_execute(self): + cmd = "show port description" + out = self.con.mdcli_execute(cmd) + expect = self.md.mock_data['mdcli_execute']['commands'][cmd] + self.assertEqual(self.joined(out), self.joined(expect)) + def test_mdcli_configure(self): cmd = 'router interface coreloop ipv4 primary address 1.1.1.1 prefix-length 32' output = self.con.mdcli_configure(cmd, mode='global') From adcce9080edbe8c1b733feb6490bf73c5d0def59 Mon Sep 17 00:00:00 2001 From: omid Date: Mon, 24 Jun 2024 14:44:10 -0400 Subject: [PATCH 02/11] Releasing v24.6 --- docs/changelog/2024/june.rst | 63 ++++ docs/changelog/index.rst | 1 + docs/changelog_plugins/2024/june.rst | 55 ++++ docs/changelog_plugins/index.rst | 1 + src/unicon/plugins/__init__.py | 2 +- src/unicon/plugins/generic/patterns.py | 2 +- src/unicon/plugins/iosxe/stack/exception.py | 10 + .../iosxe/stack/service_implementation.py | 89 +++--- .../plugins/iosxe/stack/service_patterns.py | 3 + .../plugins/iosxe/stack/service_statements.py | 64 ++++- src/unicon/plugins/iosxe/stack/utils.py | 90 +++++- src/unicon/plugins/iosxr/patterns.py | 2 + src/unicon/plugins/iosxr/statemachine.py | 4 + src/unicon/plugins/pid_tokens.csv | 272 +++++++++--------- .../mock_data/iosxe/iosxe_mock_data_c8kv.yaml | 5 + .../iosxe/iosxe_mock_data_sdwan.yaml | 234 ++++++++++++--- .../mock_data/iosxe/iosxe_mock_stack.yaml | 82 +++++- .../mock_data/iosxr/iosxr_mock_data.yaml | 34 ++- src/unicon/plugins/tests/test_plugin_iosxe.py | 9 + .../plugins/tests/test_plugin_iosxe_sdwan.py | 55 +++- .../plugins/tests/test_plugin_iosxe_stack.py | 20 ++ src/unicon/plugins/tests/test_plugin_iosxr.py | 10 + 22 files changed, 864 insertions(+), 243 deletions(-) create mode 100644 docs/changelog/2024/june.rst create mode 100644 docs/changelog_plugins/2024/june.rst create mode 100644 src/unicon/plugins/iosxe/stack/exception.py diff --git a/docs/changelog/2024/june.rst b/docs/changelog/2024/june.rst new file mode 100644 index 00000000..fe7ceafb --- /dev/null +++ b/docs/changelog/2024/june.rst @@ -0,0 +1,63 @@ +June 2024 +========== + + - Unicon v24.6 +------------------------ + + + +.. csv-table:: Module Versions + :header: "Modules", "Versions" + + ``unicon.plugins``, v24.6 + ``unicon``, v24.6 + +Install Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install unicon.plugins + bash$ pip install unicon + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install --upgrade unicon.plugins + bash$ pip install --upgrade unicon + +Features and Bug Fixes: +^^^^^^^^^^^^^^^^^^^^^^^ + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* stackswitchover + * Modified to wait for known switch state before continuing to check all stack members + +* stackreload + * Modified to always check all stack memebers after reload + * Modified to work for newer platforms + +* iosxe/stack + * Reload Service + * fix the logic for reloading stack devices to wait for all the members to be ready. + + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* iosxe.stack.utils + * Added new method wait_for_any_state + * wait for any known state to bypass possible timing issues + + diff --git a/docs/changelog/index.rst b/docs/changelog/index.rst index 24e1f86a..eaec7e87 100644 --- a/docs/changelog/index.rst +++ b/docs/changelog/index.rst @@ -4,6 +4,7 @@ Changelog .. toctree:: :maxdepth: 2 + 2024/june 2024/may 2024/april 2024/march diff --git a/docs/changelog_plugins/2024/june.rst b/docs/changelog_plugins/2024/june.rst new file mode 100644 index 00000000..cd7b898e --- /dev/null +++ b/docs/changelog_plugins/2024/june.rst @@ -0,0 +1,55 @@ +June 2024 +========== + + - Unicon.Plugins v24.6 +------------------------ + + + +.. csv-table:: Module Versions + :header: "Modules", "Versions" + + ``unicon.plugins``, v24.6 + ``unicon``, v24.6 + +Install Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install unicon.plugins + bash$ pip install unicon + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install --upgrade unicon.plugins + bash$ pip install --upgrade unicon + +Features and Bug Fixes: +^^^^^^^^^^^^^^^^^^^^^^^ + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* other + * Update os value to iosxe for model C1100 + * Updated os value to iosxe for ISR1100 submodel + + +-------------------------------------------------------------------------------- + Add +-------------------------------------------------------------------------------- + +* iosxr + * Added `admin_host` state support + + diff --git a/docs/changelog_plugins/index.rst b/docs/changelog_plugins/index.rst index 5e79066b..a4622231 100644 --- a/docs/changelog_plugins/index.rst +++ b/docs/changelog_plugins/index.rst @@ -4,6 +4,7 @@ Plugins Changelog .. toctree:: :maxdepth: 2 + 2024/june 2024/may 2024/april 2024/march diff --git a/src/unicon/plugins/__init__.py b/src/unicon/plugins/__init__.py index dc6b157f..840d1aac 100644 --- a/src/unicon/plugins/__init__.py +++ b/src/unicon/plugins/__init__.py @@ -1,4 +1,4 @@ -__version__ = '24.5' +__version__ = '24.6' supported_chassis = [ 'single_rp', diff --git a/src/unicon/plugins/generic/patterns.py b/src/unicon/plugins/generic/patterns.py index 3e358255..58618a3e 100644 --- a/src/unicon/plugins/generic/patterns.py +++ b/src/unicon/plugins/generic/patterns.py @@ -33,7 +33,7 @@ def __init__(self): # self.config_prompt = r'.*%N\(config.*\)#\s?$' self.config_prompt = r'^(.*)\(.*(con|cfg|ipsec-profile|ca-trustpoint|gkm-local-server)\S*\)#\s?$' - self.rommon_prompt = r'^(.*?)(rommon[\s\d]*>|switch:)\s?$' + self.rommon_prompt = r'^(.*?)(rommon[\s\d]*>|switch:|grub>)\s?$' # self.standby_enable_prompt = r'^(.*?)(RouterRP-standby|%N-standby|%N-sdby|%N\(standby\))#\s?$' # self.standby_disable_prompt = r'^(.*?)(RouterRP-standby|%N-standby|%N-sdby|%N\(standby\))>\s?$' self.standby_locked = r'^.*?([S|s]tandby console disabled|This \(D\)RP Node is not ready or active for login \/configuration.*)' diff --git a/src/unicon/plugins/iosxe/stack/exception.py b/src/unicon/plugins/iosxe/stack/exception.py new file mode 100644 index 00000000..6e305b93 --- /dev/null +++ b/src/unicon/plugins/iosxe/stack/exception.py @@ -0,0 +1,10 @@ +class StackException(Exception): + ''' base class ''' + pass + +class StackMemberReadyException(StackException): + """ + Exception for when all the member of stack device is configured + """ + pass + diff --git a/src/unicon/plugins/iosxe/stack/service_implementation.py b/src/unicon/plugins/iosxe/stack/service_implementation.py index 9b347d1f..70c717cb 100644 --- a/src/unicon/plugins/iosxe/stack/service_implementation.py +++ b/src/unicon/plugins/iosxe/stack/service_implementation.py @@ -4,9 +4,10 @@ from datetime import datetime, timedelta import re from unicon.eal.dialogs import Dialog -from unicon.core.errors import SubCommandFailure +from unicon.core.errors import SubCommandFailure, StateMachineError from unicon.bases.routers.services import BaseService +from .exception import StackMemberReadyException from .utils import StackUtils from unicon.plugins.generic.statements import custom_auth_statements, buffer_settled from unicon.plugins.generic.service_statements import standby_reset_rp_statement_list @@ -113,6 +114,8 @@ def call_service(self, command=None, connect_dialog = self.connection.connection_provider.get_connection_dialog() dialog += connect_dialog + start_time = datetime.now() + conn.log.info('Processing on active rp %s-%s' % (conn.hostname, conn.alias)) conn.sendline(switchover_cmd) try: @@ -141,10 +144,11 @@ def call_service(self, command=None, sleep(self.connection.settings.POST_SWITCHOVER_SLEEP) # check all members are ready - conn.state_machine.detect_state(conn.spawn, context=conn.context) + recheck_sleep_interval = self.connection.settings.SWITCHOVER_POSTCHECK_INTERVAL + recheck_max = timeout - (datetime.now() - start_time).seconds - interval = self.connection.settings.SWITCHOVER_POSTCHECK_INTERVAL - if utils.is_all_member_ready(conn, timeout=timeout, interval=interval): + self.connection.log.info('Wait for all members to be ready.') + if utils.is_all_member_ready(conn, timeout=recheck_max, interval=recheck_sleep_interval): self.connection.log.info('All members are ready.') else: self.connection.log.info('Timeout in %s secs. ' @@ -245,9 +249,10 @@ def call_service(self, reload_dialog += Dialog([switch_prompt]) + conn.context['post_reload_timeout'] = timedelta(seconds= self.post_reload_wait_time) + conn.log.info('Processing on active rp %s-%s' % (conn.hostname, conn.alias)) start_time = current_time = datetime.now() - timeout_time = timedelta(seconds=timeout) conn.sendline(reload_cmd) try: reload_cmd_output = reload_dialog.process(conn.spawn, @@ -256,6 +261,9 @@ def call_service(self, context=conn.context) self.result=reload_cmd_output.match_output self.get_service_result() + except StackMemberReadyException as e: + conn.log.debug('This is an expected exception for getting out of the dialog process') + pass except Exception as e: raise SubCommandFailure('Error during reload', e) from e @@ -273,59 +281,45 @@ def call_service(self, for subconn in self.connection.subconnections: self.connection.log.info('Processing on rp ' '%s-%s' % (conn.hostname, subconn.alias)) + subconn.context['post_reload_timeout'] = timedelta(seconds= self.post_reload_wait_time) utils.boot_process(subconn, timeout, self.prompt_recovery, reload_dialog) except Exception as e: self.connection.log.error(e) raise SubCommandFailure('Reload failed.', e) from e else: - conn.log.info('Waiting for boot messages to settle for {} seconds'.format( - self.post_reload_wait_time - )) - wait_time = timedelta(seconds=self.post_reload_wait_time) - settle_time = current_time = datetime.now() - while (current_time - settle_time) < wait_time: - if buffer_settled(conn.spawn, self.post_reload_wait_time): - conn.log.info('Buffer settled, accessing device..') - break - current_time = datetime.now() - if (current_time - start_time) > timeout_time: - conn.log.info('Time out, trying to acces device..') - break - try: - # bring device to enable mode - conn.state_machine.go_to('any', conn.spawn, timeout=timeout, - prompt_recovery=self.prompt_recovery, - context=conn.context) - conn.state_machine.go_to('enable', conn.spawn, timeout=timeout, - prompt_recovery=self.prompt_recovery, - context=conn.context) - except Exception as e: - raise SubCommandFailure('Failed to bring device to disable mode.', e) from e + self.connection.log.info('Processing autoboot on rp %s-%s' % (conn.hostname, conn.alias)) + + + self.connection.log.info('Sleeping for %s secs.' % \ + self.connection.settings.STACK_POST_RELOAD_SLEEP) + sleep(self.connection.settings.STACK_POST_RELOAD_SLEEP) + + # make sure detect_state is good to reduce the chance of timeout later + recheck_sleep_interval = self.connection.settings.RELOAD_POSTCHECK_INTERVAL + recheck_max = timeout - (datetime.now() - start_time).seconds + # check active and standby rp is ready self.connection.log.info('Wait for Standby RP to be ready.') - interval = self.connection.settings.RELOAD_POSTCHECK_INTERVAL - if utils.is_active_standby_ready(conn, timeout=timeout, interval=interval): + if utils.is_active_standby_ready(conn, timeout=recheck_max, interval=recheck_sleep_interval): self.connection.log.info('Active and Standby RPs are ready.') else: self.connection.log.info('Timeout in %s secs. ' 'Standby RP is not in Ready state. Reload failed' % timeout) self.result = False return + + self.connection.log.info('Start checking state of all members') + recheck_max = timeout - (datetime.now() - start_time).seconds + if utils.is_all_member_ready(conn, timeout=recheck_max, interval=recheck_sleep_interval): + self.connection.log.info('All Members are ready.') + else: + self.connection.log.info(f'Timeout in {recheck_max} secs. ' + f'Not all members are in Ready state. Reload failed') + self.result = False + return - if member: - if utils.is_all_member_ready(conn, timeout=timeout, interval=interval): - self.connection.log.info('All Members are ready.') - else: - self.connection.log.info(f'Timeout in {timeout} secs. ' - f'Member{member} is not in Ready state. Reload failed') - self.result = False - return - - self.connection.log.info('Sleeping for %s secs.' % \ - self.connection.settings.STACK_POST_RELOAD_SLEEP) - sleep(self.connection.settings.STACK_POST_RELOAD_SLEEP) self.connection.log.info('Disconnecting and reconnecting') self.connection.disconnect() @@ -578,10 +572,12 @@ def _check_invalid_mac(con): return True return False - from genie.utils.timeout import Timeout - exec_timeout = Timeout(timeout, 15) + chk_interval = con.settings.RELOAD_POSTCHECK_INTERVAL found_invalid_mac = False - while exec_timeout.iterate(): + start_time2 = time() + while (time() - start_time2) < timeout: + t_left = timeout - (time() - start_time2) + con.log.info('-- checking time left: %0.1f secs' % t_left) con.log.info('Make sure no invalid mac address 0000.0000.0000') if not _check_invalid_mac(con): con.log.info('Did not find invalid mac as 0000.0000.0000') @@ -590,7 +586,8 @@ def _check_invalid_mac(con): else: con.log.warning('Found 0000.0000.0000 mac address') found_invalid_mac = True - exec_timeout.sleep() + con.log.info(f'Sleep {chk_interval} secs') + sleep(chk_interval) continue else: if found_invalid_mac: diff --git a/src/unicon/plugins/iosxe/stack/service_patterns.py b/src/unicon/plugins/iosxe/stack/service_patterns.py index 551be85d..97769274 100644 --- a/src/unicon/plugins/iosxe/stack/service_patterns.py +++ b/src/unicon/plugins/iosxe/stack/service_patterns.py @@ -24,3 +24,6 @@ def __init__(self): super().__init__() self.reload_entire_shelf = r'^.*?Reload the entire shelf \[confirm\]' self.reload_fast = r'^.*Proceed with reload fast\? \[confirm\]' + self.apply_config = r'.*All switches in the stack have been discovered. Accelerating discovery.*' + self.bp_console = r'^.*sw\..*-bp>' + self.bp_console_enable = r'^.*sw\..*-bp#' diff --git a/src/unicon/plugins/iosxe/stack/service_statements.py b/src/unicon/plugins/iosxe/stack/service_statements.py index bfc241f5..fb69bebb 100644 --- a/src/unicon/plugins/iosxe/stack/service_statements.py +++ b/src/unicon/plugins/iosxe/stack/service_statements.py @@ -1,9 +1,14 @@ """ Generic IOS-XE Stack Service Statements """ -import time +from time import time, sleep +from datetime import datetime, timedelta from unicon.eal.dialogs import Statement + from unicon.plugins.generic.service_statements import reload_statement_list +from unicon.plugins.generic.statements import buffer_settled from unicon.plugins.iosxe.service_statements import factory_reset_confirm, are_you_sure_confirm from .service_patterns import StackIosXESwitchoverPatterns, StackIosXEReloadPatterns +from .exception import StackMemberReadyException + def update_curr_state(spawn, context, state): context['state'] = state @@ -21,10 +26,39 @@ def send_boot_cmd(spawn, context): if "image_to_boot" in context else "boot" spawn.sendline(cmd) -def stack_press_return(spawn, context): - spawn.log.info('Waiting for {} seconds'.format(spawn.timeout)) - time.sleep(spawn.timeout) - spawn.sendline() +def stack_press_return(spawn, context, session): + # for stack devices if we reload from a member console we will see 2 press return to continue. + # to make sure that we get out of the process dialog when all the members are ready we + # make sure first we match "All switches in the stack have been discovered. Accelerating discovery" in the + # buffer then we raise the StackMemberReadyException to end the process. + if session.get('apply_config_on_all_members') or session.get('bp_console'): + spawn.log.info('Waiting for buffer to settle') + timeout_time = context.get('post_reload_wait_time', 60) + if not isinstance(timeout_time, timedelta): + timeout_time = timedelta(seconds=timeout_time) + start_time = current_time = datetime.now() + while (current_time - start_time) < timeout_time: + if buffer_settled(spawn, wait_time=15): + spawn.log.info('Buffer settled, accessing device..') + break + current_time = datetime.now() + if (current_time - start_time) > timeout_time: + spawn.log.info('Time out, trying to access device..') + break + spawn.sendline() + raise StackMemberReadyException + +def apply_config_on_all_switch(spawn, session): + # we need to match theis pattern to make sure all the members are ready and we can access the device + """ Handles the number of apply configure message seen after install image """ + session["apply_config_on_all_members"] = True + +def bp_console_handler(spawn, session): + ''' strack_press_return will not wait for session["apply_config_on_all_members"] to be set + However, this pattern "All switches in the stack have been discovered. Accelerating discovery" + will never be seen for new stack design, which will cause the stack_press_return to wait forever. + Therefore, also checking bp-console prompt to make sure the reload process dialog will stop.''' + session["bp_console"] = True # switchover service statements @@ -85,10 +119,10 @@ def stack_press_return(spawn, context): loop_continue=False, continue_timer=False) -press_return = Statement(pattern=switchover_pat.press_return, +press_return_stack = Statement(pattern=switchover_pat.press_return, action=stack_press_return, args=None, - loop_continue=False, + loop_continue=True, continue_timer=False) found_return = Statement(pattern=switchover_pat.press_return, @@ -124,12 +158,26 @@ def stack_press_return(spawn, context): loop_continue=True, continue_timer=False) +apply_config = Statement(pattern=reload_pat.apply_config, + action=apply_config_on_all_switch, + loop_continue=True, + continue_timer=False) + + +bp_console = Statement(pattern=reload_pat.bp_console, + action=bp_console_handler, + loop_continue=True, + continue_timer=False) + stack_reload_stmt_list = list(reload_statement_list) stack_reload_stmt_list.extend([en_state, dis_state]) -stack_reload_stmt_list.insert(0, press_return) +stack_reload_stmt_list.insert(0, press_return_stack) stack_reload_stmt_list.insert(0, reload_shelf) stack_reload_stmt_list.insert(0, reload_fast) +stack_reload_stmt_list.insert(0, apply_config) +stack_reload_stmt_list.insert(0, bp_console) + stack_factory_reset_stmt_list = [factory_reset_confirm, are_you_sure_confirm] diff --git a/src/unicon/plugins/iosxe/stack/utils.py b/src/unicon/plugins/iosxe/stack/utils.py index 1392466f..313221f3 100644 --- a/src/unicon/plugins/iosxe/stack/utils.py +++ b/src/unicon/plugins/iosxe/stack/utils.py @@ -1,13 +1,18 @@ """ Stack utilities. """ import re +import logging from time import sleep, time from unicon.eal.dialogs import Dialog from unicon.utils import Utils, AttributeDict +from unicon.core.errors import StateMachineError +from .exception import StackMemberReadyException from .service_statements import send_boot +logger = logging.getLogger(__name__) + class StackUtils(Utils): @@ -83,9 +88,13 @@ def boot_process(self, connection, timeout, prompt_recovery, dialog=Dialog([])): None """ connection.spawn.sendline() - dialog.process(connection.spawn, timeout=timeout, - prompt_recovery=prompt_recovery, - context=connection.context) + try: + dialog.process(connection.spawn, timeout=timeout, + prompt_recovery=prompt_recovery, + context=connection.context) + except StackMemberReadyException as e: + logger.debug('This is an expected exception for getting out of the dialog proceess') + pass connection.state_machine.go_to('any', connection.spawn, timeout=timeout, prompt_recovery=prompt_recovery, context=connection.context) @@ -106,9 +115,23 @@ def is_active_standby_ready(self, connection, timeout=120, interval=30): """ active = standby = '' start_time = time() + end_time = start_time + timeout + + while (time() - start_time) < timeout: - details = self.get_redundancy_details(connection) + # double check the connection state + self.wait_for_any_state(connection, timeout=end_time - time(), interval=interval) + try: + # one connection reached a known state does not mean all connections are in the same state + # so cli execution can still fail + details = self.get_redundancy_details(connection) + except Exception as e: + connection.log.warning('Failed to get redundancy details. Stack might not be ready yet') + connection.log.info('Sleeping for %s secs.' % interval) + sleep(interval) + continue + for sw_num, info in details.items(): if info['role'] == 'Active': active = info.get('state') @@ -143,7 +166,7 @@ def is_active_ready(self, connection): return active == 'Ready' - def is_all_member_ready(self, connection, timeout=120, interval=30): + def is_all_member_ready(self, connection, timeout=270, interval=30): """ Check whether all rp are in ready state including active, standby and members @@ -157,9 +180,20 @@ def is_all_member_ready(self, connection, timeout=120, interval=30): """ ready = active = standby = False start_time = time() + end_time = start_time + timeout while (time() - start_time) < timeout: - details = self.get_redundancy_details(connection) + # double check the console state. + self.wait_for_any_state(connection, timeout=end_time - time(), interval=interval) + try: + # one connection reached a known state does not mean all connections are in the same state + # so cli execution can still fail + details = self.get_redundancy_details(connection) + except Exception as e: + connection.log.warning('Failed to get redundancy details. Stack might not be ready yet') + connection.log.info('Sleeping for %s secs.' % interval) + sleep(interval) + continue for sw_num, info in details.items(): state = info.get('state') if state != 'Ready': @@ -198,3 +232,47 @@ def get_standby_rp_sn(self, connection): standby = int(sw_num) return standby + + + def wait_for_any_state(self, connection, timeout=180, interval=15, auto_timeout_extend=True, auto_extend_secs=180): + ''' use this method to wait for any state or bypass possible timing issue which could cause state detection failure + use this where false failure is seen due to timing issue + Args: + connection (`obj`): connection object + timeout (`int`): timeout value, default is 180 secs + interval (`int`): check interval, default is 15 secs + auto_timeout_extend (`bool`): auto extend timeout if less than 0 + This is useful when the timeout is calculated based on an estimated total timeout + auto_extend_secs (`int`): Extend timeout to this vaule when auto_timeout_extend is True. Default is 180 secs + Returns: + None + raises StateMachineError if state detection fails and timeout is reached + + ''' + start_time = time() + good_state = False + if timeout <= 0 and auto_timeout_extend: + connection.log.warning(f'wait_for_any_state: given timeout is less than 0. Extend it to {auto_extend_secs} seconds') + timeout = auto_extend_secs + elif timeout <= 0: + connection.log.warning(f'wait_for_any_state: given timeout is less than 0. No auto extend. set timeout to 10 seconds') + timeout = 10 # set it to 10 seconds to check at least once + else: + connection.log.warning(f'wait_for_any_state: given timeout={timeout} seconds. No auto extend') + + connection.log.info(f'Looking for known state (detect_state) on {connection.alias} -- timeout={timeout} seconds') + while (time() - start_time) < timeout: + t_left = timeout - (time() - start_time) + connection.log.info('-- checking time left: %0.1f secs' % t_left) + try: + connection.state_machine.detect_state(connection.spawn, context=connection.context) + good_state = True + break + except Exception as e: + connection.log.warning(f'Fail to detect any state on {connection.alias}') + connection.log.info(f'Sleep {interval} secs') + sleep(interval) + if not good_state: + raise StateMachineError(f'wait_for_any_state: Timeout reached on {connection.alias}') + else: + connection.log.info(f'detect_state on {connection.alias} is successful') diff --git a/src/unicon/plugins/iosxr/patterns.py b/src/unicon/plugins/iosxr/patterns.py index 86bf7138..f866c199 100755 --- a/src/unicon/plugins/iosxr/patterns.py +++ b/src/unicon/plugins/iosxr/patterns.py @@ -31,6 +31,8 @@ def __init__(self): self.admin_prompt = r'^(.*?)(?:sysadmin-vm:0_(.*)\s?#\s?$|RP/\S+\(admin\)\s?#\s?)$' self.admin_conf_prompt = r'^(.*?)(?:sysadmin-vm:0_(.*)\(config.*\)\s?#\s?|RP/\S+\(admin-config(\S+)?\)\s?#\s?)$' self.admin_run_prompt = r'^(.*?)(?:\[sysadmin-vm:0_.*:([\s\S]+)?\]\s?\$\s?|[\r\n]+\s?#\s?)$' + # [host:0_RP0:~]$ + self.admin_host_prompt = r'^(.*?)(?:\[host:0_.*:([\s\S]+)?\]\s?\$\s?)$' self.unreachable_prompt = r'apples are green but oranges are red' self.configuration_failed_message = r'^.*Please issue \'show configuration failed \[inheritance\].*[\r\n]*' self.standby_prompt = r'^.*This \(D\)RP Node is not ready or active for login \/configuration.*' diff --git a/src/unicon/plugins/iosxr/statemachine.py b/src/unicon/plugins/iosxr/statemachine.py index 93fae1fc..45cc63e9 100755 --- a/src/unicon/plugins/iosxr/statemachine.py +++ b/src/unicon/plugins/iosxr/statemachine.py @@ -37,6 +37,7 @@ def create(self): admin = State('admin', patterns.admin_prompt) admin_conf = State('admin_conf', patterns.admin_conf_prompt) admin_run = State('admin_run', patterns.admin_run_prompt) + admin_host = State('admin_host', patterns.admin_host_prompt) self.add_state(enable) self.add_state(config) @@ -45,6 +46,7 @@ def create(self): self.add_state(admin) self.add_state(admin_conf) self.add_state(admin_run) + self.add_state(admin_host) config_dialog = Dialog([ [patterns.commit_changes_prompt, 'sendline(yes)', None, True, False], @@ -64,6 +66,7 @@ def create(self): run_to_enable = Path(run, enable, 'exit', None) config_to_enable = Path(config, enable, 'end', config_dialog) exclusive_to_enable = Path(exclusive, enable, 'end', config_dialog) + admin_host_to_admin_run = Path(admin_host, admin_run, 'exit', None) self.add_path(config_to_enable) self.add_path(enable_to_config) @@ -77,6 +80,7 @@ def create(self): self.add_path(admin_to_admin_run) self.add_path(admin_conf_to_admin) self.add_path(admin_run_to_admin) + self.add_path(admin_host_to_admin_run) self.add_default_statements(default_commands) diff --git a/src/unicon/plugins/pid_tokens.csv b/src/unicon/plugins/pid_tokens.csv index 92e4b817..97489ea6 100644 --- a/src/unicon/plugins/pid_tokens.csv +++ b/src/unicon/plugins/pid_tokens.csv @@ -62,134 +62,134 @@ C1000FE-24T-4G-L,iosxe,cat1k,c1000, C1000FE-48P-4G-L,iosxe,cat1k,c1000, C1000FE-48T-4G-L,iosxe,cat1k,c1000, C1100TG-1N32A,iosxe,isr,c1100, -C1101-4P,ios,c1k,c1100, -C1101-4PLTEP,ios,c1k,c1100, -C1101-4PLTEPWA,ios,c1k,c1100, -C1101-4PLTEPWB,ios,c1k,c1100, -C1101-4PLTEPWD,ios,c1k,c1100, -C1101-4PLTEPWE,ios,c1k,c1100, -C1101-4PLTEPWF,ios,c1k,c1100, -C1101-4PLTEPWH,ios,c1k,c1100, -C1101-4PLTEPWN,ios,c1k,c1100, -C1101-4PLTEPWQ,ios,c1k,c1100, -C1101-4PLTEPWR,ios,c1k,c1100, -C1101-4PLTEPWZ,ios,c1k,c1100, -C1109-2PLTEAU,ios,c1k,c1100, -C1109-2PLTEGB,ios,c1k,c1100, -C1109-2PLTEIN,ios,c1k,c1100, -C1109-2PLTEJN,ios,c1k,c1100, -C1109-2PLTEUS,ios,c1k,c1100, -C1109-2PLTEVZ,ios,c1k,c1100, -C1109-4PLTE2P,ios,c1k,c1100, -C1109-4PLTE2PWA,ios,c1k,c1100, -C1109-4PLTE2PWB,ios,c1k,c1100, -C1109-4PLTE2PWD,ios,c1k,c1100, -C1109-4PLTE2PWE,ios,c1k,c1100, -C1109-4PLTE2PWF,ios,c1k,c1100, -C1109-4PLTE2PWH,ios,c1k,c1100, -C1109-4PLTE2PWN,ios,c1k,c1100, -C1109-4PLTE2PWQ,ios,c1k,c1100, -C1109-4PLTE2PWR,ios,c1k,c1100, -C1109-4PLTE2PWZ,ios,c1k,c1100, -C1111-4P,ios,c1k,c1100, -C1111-4PLTEEA,ios,c1k,c1100, -C1111-4PLTELA,ios,c1k,c1100, -C1111-4PWA,ios,c1k,c1100, -C1111-4PWB,ios,c1k,c1100, -C1111-4PWD,ios,c1k,c1100, -C1111-4PWE,ios,c1k,c1100, -C1111-4PWF,ios,c1k,c1100, -C1111-4PWH,ios,c1k,c1100, -C1111-4PWN,ios,c1k,c1100, -C1111-4PWQ,ios,c1k,c1100, -C1111-4PWR,ios,c1k,c1100, -C1111-4PWZ,ios,c1k,c1100, -C1111-8P,ios,c1k,c1100, -C1111-8PLTEEA,ios,c1k,c1100, -C1111-8PLTEEAWA,ios,c1k,c1100, -C1111-8PLTEEAWB,ios,c1k,c1100, -C1111-8PLTEEAWE,ios,c1k,c1100, -C1111-8PLTEEAWR,ios,c1k,c1100, -C1111-8PLTELA,ios,c1k,c1100, -C1111-8PLTELAWD,ios,c1k,c1100, -C1111-8PLTELAWF,ios,c1k,c1100, -C1111-8PLTELAWH,ios,c1k,c1100, -C1111-8PLTELAWN,ios,c1k,c1100, -C1111-8PLTELAWQ,ios,c1k,c1100, -C1111-8PLTELAWS,ios,c1k,c1100, -C1111-8PLTELAWZ,ios,c1k,c1100, -C1111-8PWA,ios,c1k,c1100, -C1111-8PWB,ios,c1k,c1100, -C1111-8PWE,ios,c1k,c1100, -C1111-8PWF,ios,c1k,c1100, -C1111-8PWH,ios,c1k,c1100, -C1111-8PWN,ios,c1k,c1100, -C1111-8PWQ,ios,c1k,c1100, -C1111-8PWR,ios,c1k,c1100, -C1111-8PWS,ios,c1k,c1100, -C1111-8PWZ,ios,c1k,c1100, -C1111X-8P,ios,c1k,c1100, -C1112-8P,ios,c1k,c1100, -C1112-8PLTEEA,ios,c1k,c1100, -C1112-8PLTEEAWE,ios,c1k,c1100, -C1112-8PWE,ios,c1k,c1100, -C1113-8P,ios,c1k,c1100, -C1113-8PLTEEA,ios,c1k,c1100, -C1113-8PLTEEAWB,ios,c1k,c1100, -C1113-8PLTEEAWE,ios,c1k,c1100, -C1113-8PLTELA,ios,c1k,c1100, -C1113-8PLTELAWA,ios,c1k,c1100, -C1113-8PLTELAWZ,ios,c1k,c1100, -C1113-8PM,ios,c1k,c1100, -C1113-8PMLTEEA,ios,c1k,c1100, -C1113-8PMWE,ios,c1k,c1100, -C1113-8PWA,ios,c1k,c1100, -C1113-8PWB,ios,c1k,c1100, -C1113-8PWE,ios,c1k,c1100, -C1113-8PWZ,ios,c1k,c1100, -C1116-4P,ios,c1k,c1100, -C1116-4PLTEEA,ios,c1k,c1100, -C1116-4PLTEEAWE,ios,c1k,c1100, -C1116-4PWE,ios,c1k,c1100, -C1117-4P,ios,c1k,c1100, -C1117-4PLTEEA,ios,c1k,c1100, -C1117-4PLTEEAWA,ios,c1k,c1100, -C1117-4PLTEEAWE,ios,c1k,c1100, -C1117-4PLTELA,ios,c1k,c1100, -C1117-4PLTELAWZ,ios,c1k,c1100, -C1117-4PM,ios,c1k,c1100, -C1117-4PMLTEEA,ios,c1k,c1100, -C1117-4PMLTEEAWE,ios,c1k,c1100, -C1117-4PMWE,ios,c1k,c1100, -C1117-4PWA,ios,c1k,c1100, -C1117-4PWE,ios,c1k,c1100, -C1117-4PWZ,ios,c1k,c1100, -C1118-8P,ios,c1k,c1100, -C1121-4P,ios,c1k,c1100, -C1121-4PLTEP,ios,c1k,c1100, -C1121-8P,ios,c1k,c1100, -C1121-8PLTEP,ios,c1k,c1100, -C1121-8PLTEPWB,ios,c1k,c1100, -C1121-8PLTEPWE,ios,c1k,c1100, -C1121-8PLTEPWQ,ios,c1k,c1100, -C1121-8PLTEPWZ,ios,c1k,c1100, -C1121X-8P,ios,c1k,c1100, -C1121X-8PLTEP,ios,c1k,c1100, -C1121X-8PLTEPWA,ios,c1k,c1100, -C1121X-8PLTEPWB,ios,c1k,c1100, -C1121X-8PLTEPWE,ios,c1k,c1100, -C1121X-8PLTEPWZ,ios,c1k,c1100, -C1126-8PLTEP,ios,c1k,c1100, -C1126X-8PLTEP,ios,c1k,c1100, -C1127-8PLTEP,ios,c1k,c1100, -C1127-8PMLTEP,ios,c1k,c1100, -C1127X-8PLTEP,ios,c1k,c1100, -C1127X-8PMLTEP,ios,c1k,c1100, -C1128-8PLTEP,ios,c1k,c1100, -C1161-8P,ios,c1k,c1100, -C1161-8PLTEP,ios,c1k,c1100, -C1161X-8P,ios,c1k,c1100, -C1161X-8PLTEP,ios,c1k,c1100, +C1101-4P,iosxe,c1k,c1100, +C1101-4PLTEP,iosxe,c1k,c1100, +C1101-4PLTEPWA,iosxe,c1k,c1100, +C1101-4PLTEPWB,iosxe,c1k,c1100, +C1101-4PLTEPWD,iosxe,c1k,c1100, +C1101-4PLTEPWE,iosxe,c1k,c1100, +C1101-4PLTEPWF,iosxe,c1k,c1100, +C1101-4PLTEPWH,iosxe,c1k,c1100, +C1101-4PLTEPWN,iosxe,c1k,c1100, +C1101-4PLTEPWQ,iosxe,c1k,c1100, +C1101-4PLTEPWR,iosxe,c1k,c1100, +C1101-4PLTEPWZ,iosxe,c1k,c1100, +C1109-2PLTEAU,iosxe,c1k,c1100, +C1109-2PLTEGB,iosxe,c1k,c1100, +C1109-2PLTEIN,iosxe,c1k,c1100, +C1109-2PLTEJN,iosxe,c1k,c1100, +C1109-2PLTEUS,iosxe,c1k,c1100, +C1109-2PLTEVZ,iosxe,c1k,c1100, +C1109-4PLTE2P,iosxe,c1k,c1100, +C1109-4PLTE2PWA,iosxe,c1k,c1100, +C1109-4PLTE2PWB,iosxe,c1k,c1100, +C1109-4PLTE2PWD,iosxe,c1k,c1100, +C1109-4PLTE2PWE,iosxe,c1k,c1100, +C1109-4PLTE2PWF,iosxe,c1k,c1100, +C1109-4PLTE2PWH,iosxe,c1k,c1100, +C1109-4PLTE2PWN,iosxe,c1k,c1100, +C1109-4PLTE2PWQ,iosxe,c1k,c1100, +C1109-4PLTE2PWR,iosxe,c1k,c1100, +C1109-4PLTE2PWZ,iosxe,c1k,c1100, +C1111-4P,iosxe,c1k,c1100, +C1111-4PLTEEA,iosxe,c1k,c1100, +C1111-4PLTELA,iosxe,c1k,c1100, +C1111-4PWA,iosxe,c1k,c1100, +C1111-4PWB,iosxe,c1k,c1100, +C1111-4PWD,iosxe,c1k,c1100, +C1111-4PWE,iosxe,c1k,c1100, +C1111-4PWF,iosxe,c1k,c1100, +C1111-4PWH,iosxe,c1k,c1100, +C1111-4PWN,iosxe,c1k,c1100, +C1111-4PWQ,iosxe,c1k,c1100, +C1111-4PWR,iosxe,c1k,c1100, +C1111-4PWZ,iosxe,c1k,c1100, +C1111-8P,iosxe,c1k,c1100, +C1111-8PLTEEA,iosxe,c1k,c1100, +C1111-8PLTEEAWA,iosxe,c1k,c1100, +C1111-8PLTEEAWB,iosxe,c1k,c1100, +C1111-8PLTEEAWE,iosxe,c1k,c1100, +C1111-8PLTEEAWR,iosxe,c1k,c1100, +C1111-8PLTELA,iosxe,c1k,c1100, +C1111-8PLTELAWD,iosxe,c1k,c1100, +C1111-8PLTELAWF,iosxe,c1k,c1100, +C1111-8PLTELAWH,iosxe,c1k,c1100, +C1111-8PLTELAWN,iosxe,c1k,c1100, +C1111-8PLTELAWQ,iosxe,c1k,c1100, +C1111-8PLTELAWS,iosxe,c1k,c1100, +C1111-8PLTELAWZ,iosxe,c1k,c1100, +C1111-8PWA,iosxe,c1k,c1100, +C1111-8PWB,iosxe,c1k,c1100, +C1111-8PWE,iosxe,c1k,c1100, +C1111-8PWF,iosxe,c1k,c1100, +C1111-8PWH,iosxe,c1k,c1100, +C1111-8PWN,iosxe,c1k,c1100, +C1111-8PWQ,iosxe,c1k,c1100, +C1111-8PWR,iosxe,c1k,c1100, +C1111-8PWS,iosxe,c1k,c1100, +C1111-8PWZ,iosxe,c1k,c1100, +C1111X-8P,iosxe,c1k,c1100, +C1112-8P,iosxe,c1k,c1100, +C1112-8PLTEEA,iosxe,c1k,c1100, +C1112-8PLTEEAWE,iosxe,c1k,c1100, +C1112-8PWE,iosxe,c1k,c1100, +C1113-8P,iosxe,c1k,c1100, +C1113-8PLTEEA,iosxe,c1k,c1100, +C1113-8PLTEEAWB,iosxe,c1k,c1100, +C1113-8PLTEEAWE,iosxe,c1k,c1100, +C1113-8PLTELA,iosxe,c1k,c1100, +C1113-8PLTELAWA,iosxe,c1k,c1100, +C1113-8PLTELAWZ,iosxe,c1k,c1100, +C1113-8PM,iosxe,c1k,c1100, +C1113-8PMLTEEA,iosxe,c1k,c1100, +C1113-8PMWE,iosxe,c1k,c1100, +C1113-8PWA,iosxe,c1k,c1100, +C1113-8PWB,iosxe,c1k,c1100, +C1113-8PWE,iosxe,c1k,c1100, +C1113-8PWZ,iosxe,c1k,c1100, +C1116-4P,iosxe,c1k,c1100, +C1116-4PLTEEA,iosxe,c1k,c1100, +C1116-4PLTEEAWE,iosxe,c1k,c1100, +C1116-4PWE,iosxe,c1k,c1100, +C1117-4P,iosxe,c1k,c1100, +C1117-4PLTEEA,iosxe,c1k,c1100, +C1117-4PLTEEAWA,iosxe,c1k,c1100, +C1117-4PLTEEAWE,iosxe,c1k,c1100, +C1117-4PLTELA,iosxe,c1k,c1100, +C1117-4PLTELAWZ,iosxe,c1k,c1100, +C1117-4PM,iosxe,c1k,c1100, +C1117-4PMLTEEA,iosxe,c1k,c1100, +C1117-4PMLTEEAWE,iosxe,c1k,c1100, +C1117-4PMWE,iosxe,c1k,c1100, +C1117-4PWA,iosxe,c1k,c1100, +C1117-4PWE,iosxe,c1k,c1100, +C1117-4PWZ,iosxe,c1k,c1100, +C1118-8P,iosxe,c1k,c1100, +C1121-4P,iosxe,c1k,c1100, +C1121-4PLTEP,iosxe,c1k,c1100, +C1121-8P,iosxe,c1k,c1100, +C1121-8PLTEP,iosxe,c1k,c1100, +C1121-8PLTEPWB,iosxe,c1k,c1100, +C1121-8PLTEPWE,iosxe,c1k,c1100, +C1121-8PLTEPWQ,iosxe,c1k,c1100, +C1121-8PLTEPWZ,iosxe,c1k,c1100, +C1121X-8P,iosxe,c1k,c1100, +C1121X-8PLTEP,iosxe,c1k,c1100, +C1121X-8PLTEPWA,iosxe,c1k,c1100, +C1121X-8PLTEPWB,iosxe,c1k,c1100, +C1121X-8PLTEPWE,iosxe,c1k,c1100, +C1121X-8PLTEPWZ,iosxe,c1k,c1100, +C1126-8PLTEP,iosxe,c1k,c1100, +C1126X-8PLTEP,iosxe,c1k,c1100, +C1127-8PLTEP,iosxe,c1k,c1100, +C1127-8PMLTEP,iosxe,c1k,c1100, +C1127X-8PLTEP,iosxe,c1k,c1100, +C1127X-8PMLTEP,iosxe,c1k,c1100, +C1128-8PLTEP,iosxe,c1k,c1100, +C1161-8P,iosxe,c1k,c1100, +C1161-8PLTEP,iosxe,c1k,c1100, +C1161X-8P,iosxe,c1k,c1100, +C1161X-8PLTEP,iosxe,c1k,c1100, C1861-SRST-B/K9,ios,c1k,c1800, C1861-SRST-C-B/K9,ios,c1k,c1800, C1861-SRST-C-F/K9,ios,c1k,c1800, @@ -457,7 +457,7 @@ C9800-CL-K9,iosxe,cat9k,c9800,c9800cl C9800-L-C-K9,iosxe,cat9k,c9800,c9800l C9800-L-F-K9,iosxe,cat9k,c9800,c9800l CGR-2010/K9,ios,c2k,c2000, -CGR1120/K9,ios,c1k,c1100, +CGR1120/K9,iosxe,c1k,c1100, CGR1240/K9,ios,c1k,c1200, CHAS-7505,ios,c7k,c7500, CHAS-7505-DC,ios,c7k,c7500, @@ -658,13 +658,13 @@ IE-3400H-8FT-A,iosxe,ie3k,ie3400, IE-3400H-8FT-E,iosxe,ie3k,ie3400, IE-3400H-8T-A,iosxe,ie3k,ie3400, IE-3400H-8T-E,iosxe,ie3k,ie3400, -IR1101-K9,ios,c1k,c1100, -ISR1100-4G,ios,isr1k,isr1100, -ISR1100-4GLTEGB,ios,isr1k,isr1100, -ISR1100-4GLTENA,ios,isr1k,isr1100, -ISR1100-6G,ios,isr1k,isr1100, -ISR1100X-4G,ios,isr1k,isr1100, -ISR1100X-6G,ios,isr1k,isr1100, +IR1101-K9,iosxe,c1k,c1100, +ISR1100-4G,iosxe,isr1k,isr1100, +ISR1100-4GLTEGB,iosxe,isr1k,isr1100, +ISR1100-4GLTENA,iosxe,isr1k,isr1100, +ISR1100-6G,iosxe,isr1k,isr1100, +ISR1100X-4G,iosxe,isr1k,isr1100, +ISR1100X-6G,iosxe,isr1k,isr1100, ISR4221-B/K9,iosxe,isr4k,isr4200, ISR4221/K9,iosxe,isr4k,isr4200, ISR4221X/K9,iosxe,isr4k,isr4200, diff --git a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_c8kv.yaml b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_c8kv.yaml index 3fca391a..9232f26b 100644 --- a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_c8kv.yaml +++ b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_c8kv.yaml @@ -223,3 +223,8 @@ c8kv_exec: 'enable': new_state: 'c8kv_enable' +c8kv_rommon: + prompt: "grub>" + commands: + 'boot': + new_state: 'c8kv_enable' diff --git a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_sdwan.yaml b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_sdwan.yaml index 81930436..f8fd55c8 100644 --- a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_sdwan.yaml +++ b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_sdwan.yaml @@ -43,7 +43,45 @@ sdwan_enable: client count = 84 client_notification_TMR = 30000 milliseconds RF debug mask = 0x0 - + "show inventory": | + NAME: "Chassis", DESCR: "Cisco C8530-12X4QC Chassis" + PID: C8530-12X4QC , VID: V00 , SN: FLX273502YF + + NAME: "Fan Tray", DESCR: "Cisco C8500-FAN-1R Fan Tray" + PID: C8500-FAN-1R , VID: , SN: + + NAME: "module 0", DESCR: "Cisco C8530-12X4QC Modular Interface Processor" + PID: C8530-12X4QC , VID: , SN: + + NAME: "SPA subslot 0/0", DESCR: "8-port 10/1G SFP Ethernet Port Adapter" + PID: 8xSFP+ , VID: N/A , SN: JAE12345678 + + NAME: "subslot 0/0 transceiver 0", DESCR: "10GE SR" + PID: SFP-10G-SR-S , VID: V01 , SN: OPM25160UGU + + NAME: "subslot 0/0 transceiver 1", DESCR: "10GE SR" + PID: SFP-10G-SR , VID: V03 , SN: AGA15514DWD + + NAME: "subslot 0/0 transceiver 2", DESCR: "10GE SR" + PID: SFP-10G-SR-S , VID: V01 , SN: FNS26090JAL + + NAME: "subslot 0/0 transceiver 3", DESCR: "10GE SR" + PID: SFP-10G-SR-S , VID: V01 , SN: FNS26090L1M + + NAME: "subslot 0/0 transceiver 4", DESCR: "10GE SR" + PID: SFP-10G-SR-S , VID: V01 , SN: FNS26090JAW + + NAME: "SPA subslot 0/1", DESCR: "1-port 40/1-port 100/4-port 10 Gigabit QSFP Ethernet Port Adapter" + PID: 4xSFP+/1xQSFP , VID: N/A , SN: JAE12345678 + + NAME: "SPA subslot 0/2", DESCR: "3-port 40 / 1-port 100 Gigabit QSFP Ethernet Port Adapter" + PID: 3xQSFP , VID: N/A , SN: JAE12345678 + + NAME: "module R0", DESCR: "Cisco C8530-12X4QC Route Processor" + PID: C8530-12X4QC , VID: V00 , SN: JAE273709CU + + NAME: "module F0", DESCR: "Cisco C8530-12X4QC Embedded Services Processor" + PID: C8530-12X4QC , VID: , SN: "config-transaction": new_state: sdwan_config @@ -123,14 +161,14 @@ sdwan_config_commit_confirm: "yes": new_state: sdwan_config2 -sdwan_controller_mode: +sdwan_controller_mode_1: prompt: "%N>" commands: "show version | include operating mode": "Router operating mode: Controller-Managed" "enable": - new_state: sdwan_controller_mode_enable + new_state: sdwan_controller_mode_enable_1 -sdwan_controller_mode_enable: +sdwan_controller_mode_enable_1: prompt: "%N#" commands: <<: *sdwan_enable_cmds @@ -190,44 +228,176 @@ sdwan_controller_mode_enable: 464553984K bytes of NVMe SSD flash at bootflash:. Configuration register is 0x2102 - "show inventory": | - NAME: "Chassis", DESCR: "Cisco C8530-12X4QC Chassis" - PID: C8530-12X4QC , VID: V00 , SN: FLX273502YF + "uname -a": "" + "pnpa service discovery stop": "" - NAME: "Fan Tray", DESCR: "Cisco C8500-FAN-1R Fan Tray" - PID: C8500-FAN-1R , VID: , SN: +sdwan_controller_mode_2: + prompt: "%N>" + commands: + "show version | include operating mode": "Router operating mode: Controller-Managed" + "enable": + new_state: sdwan_controller_mode_enable_2 - NAME: "module 0", DESCR: "Cisco C8530-12X4QC Modular Interface Processor" - PID: C8530-12X4QC , VID: , SN: +sdwan_controller_mode_enable_2: + prompt: "%N#" + commands: + <<: *sdwan_enable_cmds + "show version": | + Cisco IOS XE Software, Version BLD_V179_THROTTLE_LATEST_20240404_152224 + Cisco IOS Software [Cupertino], isr1100be Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Experimental Version 17.9.20240404:174358 [BLD_V179_THROTTLE_LATEST_20240404_152224:/nobackup/mcpre/s2c-build-ws 101] + Copyright (c) 1986-2024 by Cisco Systems, Inc. + Compiled Thu 04-Apr-24 10:43 by mcpre - NAME: "SPA subslot 0/0", DESCR: "8-port 10/1G SFP Ethernet Port Adapter" - PID: 8xSFP+ , VID: N/A , SN: JAE12345678 - NAME: "subslot 0/0 transceiver 0", DESCR: "10GE SR" - PID: SFP-10G-SR-S , VID: V01 , SN: OPM25160UGU + Cisco IOS-XE software, Copyright (c) 2005-2024 by cisco Systems, Inc. + All rights reserved. Certain components of Cisco IOS-XE software are + licensed under the GNU General Public License ("GPL") Version 2.0. The + software code licensed under GPL Version 2.0 is free software that comes + with ABSOLUTELY NO WARRANTY. You can redistribute and/or modify such + GPL code under the terms of GPL Version 2.0. For more details, see the + documentation or "License Notice" file accompanying the IOS-XE software, + or the applicable URL provided on the flyer accompanying the IOS-XE + software. - NAME: "subslot 0/0 transceiver 1", DESCR: "10GE SR" - PID: SFP-10G-SR , VID: V03 , SN: AGA15514DWD - NAME: "subslot 0/0 transceiver 2", DESCR: "10GE SR" - PID: SFP-10G-SR-S , VID: V01 , SN: FNS26090JAL + ROM: 17.7(1r) - NAME: "subslot 0/0 transceiver 3", DESCR: "10GE SR" - PID: SFP-10G-SR-S , VID: V01 , SN: FNS26090L1M + ISR1100-6G-Type2-03 uptime is 6 weeks, 5 days, 13 hours, 22 minutes + Uptime for this control processor is 6 weeks, 5 days, 13 hours, 23 minutes + System returned to ROM by Image Install at 09:00:04 UTC Fri Jan 19 2024 + System image file is "bootflash:packages.conf" + Last reload reason: Image Install - NAME: "subslot 0/0 transceiver 4", DESCR: "10GE SR" - PID: SFP-10G-SR-S , VID: V01 , SN: FNS26090JAW - NAME: "SPA subslot 0/1", DESCR: "1-port 40/1-port 100/4-port 10 Gigabit QSFP Ethernet Port Adapter" - PID: 4xSFP+/1xQSFP , VID: N/A , SN: JAE12345678 - NAME: "SPA subslot 0/2", DESCR: "3-port 40 / 1-port 100 Gigabit QSFP Ethernet Port Adapter" - PID: 3xQSFP , VID: N/A , SN: JAE12345678 + This product contains cryptographic features and is subject to United + States and local country laws governing import, export, transfer and + use. Delivery of Cisco cryptographic products does not imply + third-party authority to import, export, distribute or use encryption. + Importers, exporters, distributors and users are responsible for + compliance with U.S. and local country laws. By using this product you + agree to comply with applicable laws and regulations. If you are unable + to comply with U.S. and local laws, return this product immediately. - NAME: "module R0", DESCR: "Cisco C8530-12X4QC Route Processor" - PID: C8530-12X4QC , VID: V00 , SN: JAE273709CU + A summary of U.S. laws governing Cisco cryptographic products may be found at: + http://www.cisco.com/wwl/export/crypto/tool/stqrg.html - NAME: "module F0", DESCR: "Cisco C8530-12X4QC Embedded Services Processor" - PID: C8530-12X4QC , VID: , SN: + If you require further assistance please contact us by sending email to + export@cisco.com. + + + Technology Package License Information: + Controller-managed + + The current throughput level is unthrottled + + + Smart Licensing Status: Smart Licensing Using Policy + + cisco ISR1100-6G (1RU) processor with 1325907K/6147K bytes of memory. + Processor board ID FGL2443LA48 + Router operating mode: Controller-Managed + 6 Gigabit Ethernet interfaces + 32768K bytes of non-volatile configuration memory. + 4194304K bytes of physical memory. + 5949439K bytes of flash memory at bootflash:. + + Configuration register is 0x1822 + "uname -a": "" + "pnpa service discovery stop": "" + +sdwan_controller_mode_3: + prompt: "%N>" + commands: + "show version | include operating mode": "Router operating mode: Controller-Managed" + "enable": + new_state: sdwan_controller_mode_enable_3 + +sdwan_controller_mode_enable_3: + prompt: "%N#" + commands: + <<: *sdwan_enable_cmds + "show version": | + Cisco IOS XE Software, Version BLD_V1711_THROTTLE_LATEST_20230402_072111 + Cisco IOS Software [Dublin], ISR Software (ARMV8EL_LINUX_IOSD-UNIVERSALK9-M), Experimental Version 17.11.20230402:074537 [BLD_V1711_THROTTLE_LATEST_20230402_072111:/nobackup/mcpre/s2c-build-ws 101] + Copyright (c) 1986-2023 by Cisco Systems, Inc. + Compiled Sun 02-Apr-23 00:45 by mcpre + + + Cisco IOS-XE software, Copyright (c) 2005-2023 by cisco Systems, Inc. + All rights reserved. Certain components of Cisco IOS-XE software are + licensed under the GNU General Public License ("GPL") Version 2.0. The + software code licensed under GPL Version 2.0 is free software that comes + with ABSOLUTELY NO WARRANTY. You can redistribute and/or modify such + GPL code under the terms of GPL Version 2.0. For more details, see the + documentation or "License Notice" file accompanying the IOS-XE software, + or the applicable URL provided on the flyer accompanying the IOS-XE + software. + + + ROM: 17.5(1r) + + BR1003-1-C1111-4P uptime is 6 days, 16 hours, 3 minutes + Uptime for this control processor is 6 days, 16 hours, 4 minutes + System returned to ROM by Image Install at 21:12:25 IST Wed Feb 14 2024 + System restarted at 17:53:56 IST Thu May 30 2024 + System image file is "bootflash:packages.conf" + Last reload reason: Image Install + + + + This product contains cryptographic features and is subject to United + States and local country laws governing import, export, transfer and + use. Delivery of Cisco cryptographic products does not imply + third-party authority to import, export, distribute or use encryption. + Importers, exporters, distributors and users are responsible for + compliance with U.S. and local country laws. By using this product you + agree to comply with applicable laws and regulations. If you are unable + to comply with U.S. and local laws, return this product immediately. + + A summary of U.S. laws governing Cisco cryptographic products may be found at: + http://www.cisco.com/wwl/export/crypto/tool/stqrg.html + + If you require further assistance please contact us by sending email to + export@cisco.com. + + + + Suite License Information for Module:'esg' + + -------------------------------------------------------------------------------- + Suite Suite Current Type Suite Next reboot + -------------------------------------------------------------------------------- + FoundationSuiteK9 None Smart License None + securityk9 + appxk9 + + + Technology Package License Information: + + ----------------------------------------------------------------- + Technology Technology-package Technology-package + Current Type Next reboot + ------------------------------------------------------------------ + appxk9 appxk9 Smart License appxk9 + uck9 uck9 Smart License uck9 + securityk9 securityk9 Smart License securityk9 + ipbase ipbasek9 Smart License ipbasek9 + + The current throughput level is unthrottled + + + Smart Licensing Status: Smart Licensing Using Policy + + cisco C1111-4P (1RU) processor with 1352820K/6147K bytes of memory. + Processor board ID FGL2402LKX6 + Router operating mode: Controller-Managed + 1 Virtual Ethernet interface + 8 Gigabit Ethernet interfaces + 32768K bytes of non-volatile configuration memory. + 4194304K bytes of physical memory. + 2863103K bytes of flash memory at bootflash:. + + Configuration register is 0x2102 "uname -a": "" - "pnpa service discovery stop": "" \ No newline at end of file + "pnpa service discovery stop": "" diff --git a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_stack.yaml b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_stack.yaml index e01c1aec..5761675a 100644 --- a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_stack.yaml +++ b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_stack.yaml @@ -336,7 +336,7 @@ reload_prompt2: boot - new_state: stack_rommon + new_state: stack_rommon_1 stack_rommon: prompt: "switch: " @@ -352,13 +352,81 @@ reload_prompt_1: commands: "": new_state: stack_exec + install_add_commit: preface: |2 - Copying image file: bootflash:asr1000rpx86-universalk9.BLD_V166_THROTTLE_LATEST_20171101_090919_2.SSA.bin to standby - rsync: write failed on "asr1000rpx86-universalk9.BLD_V166_THROTTLE_LATEST_20171101_090919_2.SSA.bin" (in bootflash): No space left on device (28) - rsync error: error in file IO (code 11) at ../rsync-3.1.2/receiver.c(393) [receiver=3.1.2] - rsync error: error in file IO (code 11) at ../rsync-3.1.2/io.c(1633) [generator=3.1.2] - rsync: read error: Connection reset by peer (104) - FAILED: install_add_activate_commit : Copy bootflash:asr1000rpx86-universalk9.BLD_V16 + Copying image file: bootflash:asr1000rpx86-universalk9.BLD_V166_THROTTLE_LATEST_20171101_090919_2.SSA.bin to standby + rsync: write failed on "asr1000rpx86-universalk9.BLD_V166_THROTTLE_LATEST_20171101_090919_2.SSA.bin" (in bootflash): No space left on device (28) + rsync error: error in file IO (code 11) at ../rsync-3.1.2/receiver.c(393) [receiver=3.1.2] + rsync error: error in file IO (code 11) at ../rsync-3.1.2/io.c(1633) [generator=3.1.2] + rsync: read error: Connection reset by peer (104) + FAILED: install_add_activate_commit : Copy bootflash:asr1000rpx86-universalk9.BLD_V16 new_state: stack_enable +stack_rommon_1: + prompt: "switch: " + commands: + "boot": + response: | + Booting...(use SKIP_POST)Up 1000 Mbps Full duplex (port 0) (SGMII) + + The system is not configured to boot automatically. The + following command will finish loading the operating system + software: + + boot + + + switch: boot + Reading full image into memory.............................................................................................................................................................................................................................................................................................................................................................................................................................................................................done + Bundle Image + -------------------------------------- + Kernel Address : 0x53778818 + Kernel Size : 0x438410/4424720 + Initramfs Address : 0x53bb0c28 + Initramfs Size : 0x1abc00f/28033039 + Compression Format: mzip + + Bootable image at @ ram:0x53778818 + Bootable image segment 0 address range [0x81100000, 0x81da5280] is in range [0x80180000, 0x90000000]. + @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + File "tftp://10.1.7.250/auto/nostgAuto/USERS/ranautiy/nirmagup/IOSXE/cat3k_caa-universalk9.BLD_V1612_THROTTLE_LATEST_20200403_053502_V16_12_3_6.SSA.bin" uncompressed and installed, entry point: 0x81895bf0 + Loading Linux kernel with entry point 0x81895bf0 ... + Bootloader: Done loading app on core_mask: 0xf + + ### Launching Linux Kernel (flags = 0x5) + + Linux version 4.9.187 (xelinux@sjc-xelinux2) (gcc version 5.3.0 (GCC) ) #1 SMP Wed Dec 11 09:25:00 PST 2019 + CVMSEG size: 2 cache lines (256 bytes) + Cavium Inc. SDK-5.1.0 + bootconsole [early0] enabled + CPU0 revision is: 000d900a (Cavium Octeon II) + Checking for the multiply/shift bug... no. + Checking for the daddiu bug... no. + %IOSXEBOOT-c34ad91569d0f862504bc287a15afe2e-new_cksum: (rp/0): 4 + %IOSXEBOOT-c34ad91569d0f862504bc287a15afe2e-saved_cksum: (rp/0): 4 + + Final tar file: mcu_ucode_bundle_6_2_0.tar + + Waiting for 120 seconds for other switches to boot + ##### + Switch number is 2 + All switches in the stack have been discovered. Accelerating discovery + timing: + - 0:,0,0.005 + new_state: stack_press_return + + + +stack_press_return: + prompt: "This software version supports only Smart Licensing as the software licensing mechanism." + commands: + "": + new_state: stack_press_return_1 + + +stack_press_return_1: + prompt: "Press RETURN to get started!" + commands: + "": + new_state: stack_exec \ No newline at end of file diff --git a/src/unicon/plugins/tests/mock_data/iosxr/iosxr_mock_data.yaml b/src/unicon/plugins/tests/mock_data/iosxr/iosxr_mock_data.yaml index 1596c7f2..3f497ed8 100644 --- a/src/unicon/plugins/tests/mock_data/iosxr/iosxr_mock_data.yaml +++ b/src/unicon/plugins/tests/mock_data/iosxr/iosxr_mock_data.yaml @@ -442,7 +442,6 @@ admin: 0/PM4/SP A9K-3KW-AC READY PWR,NSHUT,MON 0/PM5/SP A9K-3KW-AC FAILED PWR,NSHUT,MON - config: prompt: "RP/0/RP0/CPU0:%N(config)#" commands: &config_cmds @@ -1395,3 +1394,36 @@ bash_console5: prompt: "[xr-vm_nodeD0_CB0_CPU0:~]$" commands: <<: *bash_commands + +enable6: + prompt: "RP/0/RP0/CPU0:%N#" + commands: + "admin": + new_state: bash_console6 + +bash_console6: + preface: | + Tue Jun 6 07:50:51.753 UTC + Last login: Mon Jun 5 15:09:57 2023 from 192.0.0.4 + admin connected from 192.0.0.4 using ssh on sysadmin-vm:0_RP0 + prompt: sysadmin-vm:0_RP0# + commands: + "run": + new_state: admin_bash_console6 + "exit": + new_state: enable6 + +admin_bash_console6: + preface: "Tue Jun 6 07:50:55.337 UTC+00:00" + prompt: "[sysadmin-vm:0_RP0:~]$" + commands: + "ssh 10.0.2.16": + new_state: admin_host6 + "exit": + new_state: bash_console6 + +admin_host6: + prompt: "[host:0_RP0:~]$" + commands: + "exit": + new_state: admin_bash_console6 \ No newline at end of file diff --git a/src/unicon/plugins/tests/test_plugin_iosxe.py b/src/unicon/plugins/tests/test_plugin_iosxe.py index 47ff6948..640a7f08 100644 --- a/src/unicon/plugins/tests/test_plugin_iosxe.py +++ b/src/unicon/plugins/tests/test_plugin_iosxe.py @@ -568,6 +568,15 @@ def test_config_transaction_sdwan_iosxe_confirm(self): d.configure('no logging console') d.disconnect() +class TestIosXEC8KVPlugin(unittest.TestCase): + def test_connect(self): + d = Connection(hostname="switch", + start=["mock_device_cli --os iosxe --state c8kv_rommon --hostname switch"], + os="iosxe", + platform="cat8k", + log_buffer=True) + d.connect() + d.disconnect() class TestIosXEC8KvPluginReload(unittest.TestCase): @classmethod diff --git a/src/unicon/plugins/tests/test_plugin_iosxe_sdwan.py b/src/unicon/plugins/tests/test_plugin_iosxe_sdwan.py index 18f07bd9..6a1a9442 100644 --- a/src/unicon/plugins/tests/test_plugin_iosxe_sdwan.py +++ b/src/unicon/plugins/tests/test_plugin_iosxe_sdwan.py @@ -1,12 +1,9 @@ import unittest -from unittest.mock import patch from pyats.topology import loader import unicon from unicon import Connection -from unicon.eal.dialogs import Dialog, Statement -from unicon.core.errors import SubCommandFailure, StateMachineError, UniconAuthenticationError, ConnectionError as UniconConnectionError from unicon.plugins.tests.mock.mock_device_iosxe import MockDeviceTcpWrapperIOSXE unicon.settings.Settings.POST_DISCONNECT_WAIT_SEC = 0 @@ -76,7 +73,7 @@ def test_iosxe_sdwan_connect(self): finally: d.disconnect() - def test_iosxe_sdwan_controller_mode_connect(self): + def test_iosxe_sdwan_controller_mode_connect_1(self): testbed = ''' devices: Router: @@ -91,7 +88,55 @@ def test_iosxe_sdwan_controller_mode_connect(self): defaults: class: 'unicon.Unicon' cli: - command: mock_device_cli --os iosxe --state sdwan_controller_mode + command: mock_device_cli --os iosxe --state sdwan_controller_mode_1 + ''' + t = loader.load(testbed) + d = t.devices.Router + try: + d.connect() + finally: + d.disconnect() + + def test_iosxe_sdwan_controller_mode_connect_2(self): + testbed = ''' + devices: + Router: + type: router + os: iosxe + platform: sdwan + credentials: + default: + username: cisco + password: cisco + connections: + defaults: + class: 'unicon.Unicon' + cli: + command: mock_device_cli --os iosxe --state sdwan_controller_mode_2 + ''' + t = loader.load(testbed) + d = t.devices.Router + try: + d.connect() + finally: + d.disconnect() + + def test_iosxe_sdwan_controller_mode_connect_3(self): + testbed = ''' + devices: + Router: + type: router + os: iosxe + platform: sdwan + credentials: + default: + username: cisco + password: cisco + connections: + defaults: + class: 'unicon.Unicon' + cli: + command: mock_device_cli --os iosxe --state sdwan_controller_mode_3 ''' t = loader.load(testbed) d = t.devices.Router diff --git a/src/unicon/plugins/tests/test_plugin_iosxe_stack.py b/src/unicon/plugins/tests/test_plugin_iosxe_stack.py index 88b7a156..5d7ae27c 100644 --- a/src/unicon/plugins/tests/test_plugin_iosxe_stack.py +++ b/src/unicon/plugins/tests/test_plugin_iosxe_stack.py @@ -385,6 +385,26 @@ def test_get_redundancy_details(self): "state": "Ready" } }, rd) + + def test_wait_for_any_state(self): + '''Test wait_for_any_state with positive timeout''' + su = StackUtils() + su.wait_for_any_state(connection=self.c, timeout=2, interval=1) + + def test_wait_for_any_state2(self): + '''Test wait_for_any_state with negative timeout and auto_timeout_extend=True''' + su = StackUtils() + su.wait_for_any_state(connection=self.c, timeout=-10, interval=1, auto_timeout_extend=True, auto_extend_secs=2) + + def test_is_all_member_ready(self): + '''Test is_all_member_ready''' + su = StackUtils() + self.assertTrue(su.is_all_member_ready(connection=self.c, timeout=2, interval=1)) + + def test_is_active_standby_ready(self): + '''Test is_active_standby_ready''' + su = StackUtils() + self.assertTrue(su.is_active_standby_ready(connection=self.c, timeout=2, interval=1)) if __name__ == "__main__": diff --git a/src/unicon/plugins/tests/test_plugin_iosxr.py b/src/unicon/plugins/tests/test_plugin_iosxr.py index 2b404d22..68150550 100644 --- a/src/unicon/plugins/tests/test_plugin_iosxr.py +++ b/src/unicon/plugins/tests/test_plugin_iosxr.py @@ -225,6 +225,16 @@ def test_admin(self): self.assertIn('exit', ret) self.assertIn('Router#', ret) + def test_admin_host(self): + conn = Connection(hostname='Router', + start=['mock_device_cli --os iosxr --state enable6'], + os='iosxr', + enable_password='cisco', + mit=True) + + conn.connect() + with conn.admin_bash_console() as console: + console.execute('ssh 10.0.2.16', allow_state_change=True) class TestIosXrPluginBashService(unittest.TestCase): From 99a8cfd3d8ffb186dd92a74cb3f4cb40b2400c00 Mon Sep 17 00:00:00 2001 From: Lukeman Hakkim Sheik Alavudeen Date: Tue, 30 Jul 2024 12:33:24 -0700 Subject: [PATCH 03/11] Open branches for release_24.7 --- docs/changelog/2024/july.rst | 46 +++++++++++++++++++ docs/changelog/index.rst | 1 + docs/changelog_plugins/2024/july.rst | 46 +++++++++++++++++++ docs/changelog_plugins/index.rst | 1 + src/unicon/plugins/__init__.py | 2 +- .../plugins/generic/service_implementation.py | 4 ++ .../plugins/iosxe/cat9k/c9800cl/__init__.py | 3 +- .../plugins/iosxe/service_implementation.py | 22 +++++++++ .../tests/mock_data/ios/ios_mock_copy.yaml | 15 ++++++ .../tests/mock_data/ios/ios_mock_data.yaml | 2 + .../mock_data/iosxe/iosxe_mock_data.yaml | 4 ++ .../mock_data/iosxe/iosxe_mock_data_isr.yaml | 12 +++++ src/unicon/plugins/tests/test_copy_service.py | 11 +++++ src/unicon/plugins/tests/test_plugin_iosxe.py | 28 +++++++++++ 14 files changed, 195 insertions(+), 2 deletions(-) create mode 100644 docs/changelog/2024/july.rst create mode 100644 docs/changelog_plugins/2024/july.rst diff --git a/docs/changelog/2024/july.rst b/docs/changelog/2024/july.rst new file mode 100644 index 00000000..2b9608b1 --- /dev/null +++ b/docs/changelog/2024/july.rst @@ -0,0 +1,46 @@ +July 2024 +========== + +July 30 - Unicon v24.7 +------------------------ + + + +.. csv-table:: Module Versions + :header: "Modules", "Versions" + + ``unicon.plugins``, v24.7 + ``unicon``, v24.7 + +Install Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install unicon.plugins + bash$ pip install unicon + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install --upgrade unicon.plugins + bash$ pip install --upgrade unicon + +Features and Bug Fixes: +^^^^^^^^^^^^^^^^^^^^^^^ + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* generic + * Updated with `sleep_time` to handle the copy command + + diff --git a/docs/changelog/index.rst b/docs/changelog/index.rst index eaec7e87..3117ca67 100644 --- a/docs/changelog/index.rst +++ b/docs/changelog/index.rst @@ -4,6 +4,7 @@ Changelog .. toctree:: :maxdepth: 2 + 2024/july 2024/june 2024/may 2024/april diff --git a/docs/changelog_plugins/2024/july.rst b/docs/changelog_plugins/2024/july.rst new file mode 100644 index 00000000..73ef6427 --- /dev/null +++ b/docs/changelog_plugins/2024/july.rst @@ -0,0 +1,46 @@ +July 2024 +========== + +July 30 - Unicon.Plugins v24.7 +------------------------ + + + +.. csv-table:: Module Versions + :header: "Modules", "Versions" + + ``unicon.plugins``, v24.7 + ``unicon``, v24.7 + +Install Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install unicon.plugins + bash$ pip install unicon + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install --upgrade unicon.plugins + bash$ pip install --upgrade unicon + +Features and Bug Fixes: +^^^^^^^^^^^^^^^^^^^^^^^ + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* iosxe + * add "disable_selinux" parameter to bash_console service, to automatically + + diff --git a/docs/changelog_plugins/index.rst b/docs/changelog_plugins/index.rst index a4622231..699b6f68 100644 --- a/docs/changelog_plugins/index.rst +++ b/docs/changelog_plugins/index.rst @@ -4,6 +4,7 @@ Plugins Changelog .. toctree:: :maxdepth: 2 + 2024/july 2024/june 2024/may 2024/april diff --git a/src/unicon/plugins/__init__.py b/src/unicon/plugins/__init__.py index 840d1aac..26de5143 100644 --- a/src/unicon/plugins/__init__.py +++ b/src/unicon/plugins/__init__.py @@ -1,4 +1,4 @@ -__version__ = '24.6' +__version__ = '24.7' supported_chassis = [ 'single_rp', diff --git a/src/unicon/plugins/generic/service_implementation.py b/src/unicon/plugins/generic/service_implementation.py index bbf7a005..0c728f73 100644 --- a/src/unicon/plugins/generic/service_implementation.py +++ b/src/unicon/plugins/generic/service_implementation.py @@ -20,6 +20,7 @@ import collections import ipaddress from itertools import chain +import time import warnings from datetime import datetime, timedelta @@ -1666,6 +1667,9 @@ def call_service(self, reply=Dialog([]), *args, **kwargs): # noqa: C901 for retry_num in range(self.max_attempts): spawn.sendline(copy_string) try: + if (sleep_time := kwargs.get('sleep_time')): + con.log.info(f"sleep for {sleep_time} seconds") + time.sleep(sleep_time) self.result = dialog.process(spawn, context=copy_context, timeout=timeout) diff --git a/src/unicon/plugins/iosxe/cat9k/c9800cl/__init__.py b/src/unicon/plugins/iosxe/cat9k/c9800cl/__init__.py index c3c76477..a26df3e6 100644 --- a/src/unicon/plugins/iosxe/cat9k/c9800cl/__init__.py +++ b/src/unicon/plugins/iosxe/cat9k/c9800cl/__init__.py @@ -1,10 +1,11 @@ from unicon.plugins.iosxe.cat9k.c9800 import IosXEc9800ServiceList, IosXEc9800SingleRpConnection, IosXEc9800DualRPConnection - +from unicon.plugins.iosxe import service_implementation as svc class IosXEc9800CLServiceList(IosXEc9800ServiceList): def __init__(self): super().__init__() + self.rommon = svc.Rommon diff --git a/src/unicon/plugins/iosxe/service_implementation.py b/src/unicon/plugins/iosxe/service_implementation.py index 7cbcd3f8..79154677 100644 --- a/src/unicon/plugins/iosxe/service_implementation.py +++ b/src/unicon/plugins/iosxe/service_implementation.py @@ -165,6 +165,12 @@ def pre_service(self, *args, **kwargs): handle.context['_chassis'] = kwargs.get('chassis') else: handle.context.pop('_chassis', None) + if kwargs.get('disable_selinux') is not None: + handle.context['_disable_selinux'] = kwargs.get('disable_selinux') + elif hasattr(self, 'disable_selinux'): + handle.context['_disable_selinux'] = self.disable_selinux + else: + handle.context.pop('_disable_selinux', None) super().pre_service(*args, **kwargs) class ContextMgr(GenericBashService.ContextMgr): @@ -176,6 +182,12 @@ def __init__(self, connection, enable_bash=False, timeout=None, **kwargs): def __enter__(self): + if self.conn.context.get('_disable_selinux'): + try: + self.conn.execute('set platform software selinux permissive') + except SubCommandFailure: + pass + self.conn.log.debug('+++ attaching bash shell +++') # enter shell prompt self.conn.state_machine.go_to( @@ -190,6 +202,16 @@ def __enter__(self): return self + def __exit__(self, type, value, traceback): + res = super().__exit__(type, value, traceback) + + if self.conn.context.get('_disable_selinux'): + try: + self.conn.execute('set platform software selinux default') + except SubCommandFailure: + pass + + return res class ResetStandbyRP(GenericResetStandbyRP): """ Service to reset the standby rp. diff --git a/src/unicon/plugins/tests/mock_data/ios/ios_mock_copy.yaml b/src/unicon/plugins/tests/mock_data/ios/ios_mock_copy.yaml index de1ceb31..2220dd4f 100644 --- a/src/unicon/plugins/tests/mock_data/ios/ios_mock_copy.yaml +++ b/src/unicon/plugins/tests/mock_data/ios/ios_mock_copy.yaml @@ -70,3 +70,18 @@ wait_for_recovery: new_state: enable response: | sending keyboard interrupt + +copy_src_bootflash: + prompt: "Source filename []? " + commands: + "/c8000aep-universalk9.17.12.04.0.4708.SSA.bin": + new_state: dest_file_name + +dest_file_name: + prompt: "Destination filename [c8000aep-universalk9.17.12.04.0.4708.SSA.bin]? " + commands: + "test/c8000aep-universalk9.17.12.04.0.4708.SSA.bin": + new_state: enable + response: | + Copy in progress...CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC + 787557605 bytes copied in 71.982 secs (10941035 bytes/sec) \ No newline at end of file diff --git a/src/unicon/plugins/tests/mock_data/ios/ios_mock_data.yaml b/src/unicon/plugins/tests/mock_data/ios/ios_mock_data.yaml index fafc2e97..31ff66f5 100644 --- a/src/unicon/plugins/tests/mock_data/ios/ios_mock_data.yaml +++ b/src/unicon/plugins/tests/mock_data/ios/ios_mock_data.yaml @@ -341,6 +341,8 @@ enable: new_state: exec_standby "redundancy switch-activity force": new_state: confirm_switch_activity + "copy bootflash: usb:": + new_state: copy_src_bootflash "copy flash: flash-3:": new_state: copy_src "copy tftp: bootflash:": diff --git a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data.yaml b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data.yaml index 5358d3b8..4e76e8f5 100644 --- a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data.yaml +++ b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data.yaml @@ -300,6 +300,10 @@ general_enable: "copy somefile.bin flash:": new_state: confirm_abort_copy + "set platform software selinux permissive": "" + + "set platform software selinux default": "" + general_maintence_mode_confirm: prompt: "Template default will be applied. Do you want to continue?[confirm] " commands: diff --git a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_isr.yaml b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_isr.yaml index eb66b8b3..c7819282 100644 --- a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_isr.yaml +++ b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_data_isr.yaml @@ -168,6 +168,18 @@ enable_isr: "traceroute vrf MG501": new_state: traceroute_proto_isr + "set platform software selinux permissive": + response: + - |2 + ^ + % Invalid input detected at '^' marker." + + "set platform software selinux default": + response: + - |2 + ^ + % Invalid input detected at '^' marker." + "not a real command": response: - |2 diff --git a/src/unicon/plugins/tests/test_copy_service.py b/src/unicon/plugins/tests/test_copy_service.py index 69c5133e..eb401138 100644 --- a/src/unicon/plugins/tests/test_copy_service.py +++ b/src/unicon/plugins/tests/test_copy_service.py @@ -117,6 +117,17 @@ def test_copy_error_no_file(self): timeout=9) self.assertEqual(err.exception.args[0], 'Copy failed') + def test_copy_to_usb(self): + test_output = self.d.copy(source = 'bootflash:', dest = 'usb:', + source_file = '/c8000aep-universalk9.17.12.04.0.4708.SSA.bin', + dest_file = 'test/c8000aep-universalk9.17.12.04.0.4708.SSA.bin', + sleep_time = 10) + expected_output = self.md.mock_data['dest_file_name']['commands']\ + ['test/c8000aep-universalk9.17.12.04.0.4708.SSA.bin']['response'] + test_output = '\n'.join(test_output.splitlines()) + expected_output = '\n'.join(expected_output.splitlines()) + self.assertIn(expected_output, test_output) + @patch.object(unicon.settings.Settings, 'POST_DISCONNECT_WAIT_SEC', 0) @patch.object(unicon.settings.Settings, 'GRACEFUL_DISCONNECT_WAIT_SEC', 0.2) diff --git a/src/unicon/plugins/tests/test_plugin_iosxe.py b/src/unicon/plugins/tests/test_plugin_iosxe.py index 640a7f08..dd523512 100644 --- a/src/unicon/plugins/tests/test_plugin_iosxe.py +++ b/src/unicon/plugins/tests/test_plugin_iosxe.py @@ -529,6 +529,34 @@ def test_bash_chassis_standby(self): self.assertIn('WLC1#', c.spawn.match.match_output) c.disconnect() + def test_bash_disable_selinux(self): + c = Connection(hostname='Router', + start=['mock_device_cli --os iosxe --state general_enable --hostname Router'], + os='iosxe', + credentials=dict(default=dict(username='cisco', password='cisco')), + log_buffer=True + ) + with c.bash_console(disable_selinux=True) as console: + self.assertIn('[Router_RP_0:/]$', c.spawn.match.match_output) + console.execute('df /bootflash/') + self.assertIn('set platform software selinux default', c.spawn.match.match_output) + self.assertIn('Router#', c.spawn.match.match_output) + c.disconnect() + + def test_bash_disable_selinux_invalid_cmds(self): + c = Connection(hostname='Router', + start=['mock_device_cli --os iosxe --state enable_isr --hostname Router'], + os='iosxe', + credentials=dict(default=dict(username='cisco', password='cisco')), + log_buffer=True + ) + with c.bash_console(disable_selinux=True) as console: + self.assertIn('[Router:/]$', c.spawn.match.match_output) + console.execute('ls') + self.assertIn('set platform software selinux default', c.spawn.match.match_output) + self.assertIn('Router#', c.spawn.match.match_output) + c.disconnect() + class TestIosXESDWANConfigure(unittest.TestCase): def test_config_transaction(self): From d50be11de1a5bcc929fd2b7b81df08f912fc8d02 Mon Sep 17 00:00:00 2001 From: Lukeman Hakkim Sheik Alavudeen Date: Tue, 30 Jul 2024 12:45:45 -0700 Subject: [PATCH 04/11] Releasing v24.7 From 1adae75985a761126b59a9909a5d84aa95918e58 Mon Sep 17 00:00:00 2001 From: Lukeman Hakkim Sheik Alavudeen Date: Wed, 31 Jul 2024 10:30:54 -0700 Subject: [PATCH 05/11] Releasing v24.7 From 1e8929ead10298ebd46c92b0335bf18bac823679 Mon Sep 17 00:00:00 2001 From: domachad Date: Mon, 26 Aug 2024 14:00:58 -0400 Subject: [PATCH 06/11] Open branches for release_24.8 --- src/unicon/plugins/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unicon/plugins/__init__.py b/src/unicon/plugins/__init__.py index 26de5143..487371e7 100644 --- a/src/unicon/plugins/__init__.py +++ b/src/unicon/plugins/__init__.py @@ -1,4 +1,4 @@ -__version__ = '24.7' +__version__ = '24.8' supported_chassis = [ 'single_rp', From f896c8dfd66f90454266d0d871e92585dddae56d Mon Sep 17 00:00:00 2001 From: domachad Date: Tue, 3 Sep 2024 13:17:04 -0400 Subject: [PATCH 07/11] Releasing v24.8 --- docs/changelog/2024/august.rst | 92 +++++++++++ docs/changelog/2024/september.rst | 92 +++++++++++ docs/changelog/index.rst | 2 + docs/changelog_plugins/2024/august.rst | 67 ++++++++ docs/changelog_plugins/2024/september.rst | 67 ++++++++ docs/changelog_plugins/index.rst | 2 + docs/user_guide/services/iosxr.rst | 91 +++++++++- .../plugins/generic/service_implementation.py | 12 +- src/unicon/plugins/generic/statements.py | 3 +- .../plugins/iosxe/service_implementation.py | 3 +- .../iosxe/stack/service_implementation.py | 70 ++++---- .../plugins/iosxe/stack/service_patterns.py | 2 - .../plugins/iosxe/stack/service_statements.py | 16 +- src/unicon/plugins/iosxe/stack/utils.py | 74 +-------- src/unicon/plugins/iosxr/__init__.py | 3 +- src/unicon/plugins/iosxr/patterns.py | 14 ++ .../plugins/iosxr/service_implementation.py | 155 +++++++++++++++++- src/unicon/plugins/iosxr/settings.py | 3 + src/unicon/plugins/iosxr/statemachine.py | 4 + src/unicon/plugins/iosxr/statements.py | 44 +++-- src/unicon/plugins/pid_tokens.csv | 1 + .../mock_data/iosxe/iosxe_mock_data_c8kv.yaml | 14 ++ .../mock_data/iosxr/iosxr_mock_data.yaml | 65 +++++++- .../plugins/tests/test_plugin_generic.py | 41 ++++- src/unicon/plugins/tests/test_plugin_iosxe.py | 5 +- .../plugins/tests/test_plugin_iosxe_stack.py | 20 --- src/unicon/plugins/tests/test_plugin_iosxr.py | 95 ++++++++++- src/unicon/plugins/tests/test_plugin_linux.py | 4 +- src/unicon/plugins/tests/test_plugin_nd.py | 4 +- src/unicon/plugins/tests/test_plugin_sonic.py | 4 +- src/unicon/plugins/tests/test_utils.py | 132 +++++++++------ 31 files changed, 960 insertions(+), 241 deletions(-) create mode 100644 docs/changelog/2024/august.rst create mode 100644 docs/changelog/2024/september.rst create mode 100644 docs/changelog_plugins/2024/august.rst create mode 100644 docs/changelog_plugins/2024/september.rst diff --git a/docs/changelog/2024/august.rst b/docs/changelog/2024/august.rst new file mode 100644 index 00000000..6960f306 --- /dev/null +++ b/docs/changelog/2024/august.rst @@ -0,0 +1,92 @@ +August 2024 +========== + +August 27 - Unicon v24.8 +------------------------ + + + +.. csv-table:: Module Versions + :header: "Modules", "Versions" + + ``unicon.plugins``, v24.8 + ``unicon``, v24.8 + +Install Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install unicon.plugins + bash$ pip install unicon + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install --upgrade unicon.plugins + bash$ pip install --upgrade unicon + +Features and Bug Fixes: +^^^^^^^^^^^^^^^^^^^^^^^ + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* unicon.bases + * Added message argument to log_service_call + +* unicon.statemachine + * Modified Exception handling, propagate authentication failures + +* unicon + * topology + * Fixed logic for proxy connection. + * sshtunnel + * Added -o EnableEscapeCommandline=yes to ssh-options. + +* unicon.eal.backend + * Modified telnet backend + * improved option negotiation + * Added informational RTT log message + + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* unicon.adapter + * Modified topology adapter to support enxr + +* unicon.core.errors + * Add new exception LearnTokenError + +* unicon.bases + * Update exception handling to raise LearnTokenError without closing connection + + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* iosxe + * Modified Rommon service + * Allowing for a config-register parameter to the rommon service + + +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* unicon.plugins.generic + * Modified password_handler + * Have it check for tacacs_password first + + diff --git a/docs/changelog/2024/september.rst b/docs/changelog/2024/september.rst new file mode 100644 index 00000000..2c9ed20b --- /dev/null +++ b/docs/changelog/2024/september.rst @@ -0,0 +1,92 @@ +September 2024 +========== + +September 24 - Unicon v24.8 +------------------------ + + + +.. csv-table:: Module Versions + :header: "Modules", "Versions" + + ``unicon.plugins``, v24.8 + ``unicon``, v24.8 + +Install Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install unicon.plugins + bash$ pip install unicon + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install --upgrade unicon.plugins + bash$ pip install --upgrade unicon + +Features and Bug Fixes: +^^^^^^^^^^^^^^^^^^^^^^^ + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* unicon.bases + * Added message argument to log_service_call + +* unicon.statemachine + * Modified Exception handling, propagate authentication failures + +* unicon + * topology + * Fixed logic for proxy connection. + * sshtunnel + * Added -o EnableEscapeCommandline=yes to ssh-options. + +* unicon.eal.backend + * Modified telnet backend + * improved option negotiation + * Added informational RTT log message + + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* unicon.adapter + * Modified topology adapter to support enxr + +* unicon.core.errors + * Add new exception LearnTokenError + +* unicon.bases + * Update exception handling to raise LearnTokenError without closing connection + + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* iosxe + * Modified Rommon service + * Allowing for a config-register parameter to the rommon service + + +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* unicon.plugins.generic + * Modified password_handler + * Have it check for tacacs_password first + + diff --git a/docs/changelog/index.rst b/docs/changelog/index.rst index 3117ca67..2aa366b0 100644 --- a/docs/changelog/index.rst +++ b/docs/changelog/index.rst @@ -4,6 +4,8 @@ Changelog .. toctree:: :maxdepth: 2 + 2024/september + 2024/august 2024/july 2024/june 2024/may diff --git a/docs/changelog_plugins/2024/august.rst b/docs/changelog_plugins/2024/august.rst new file mode 100644 index 00000000..a32becbb --- /dev/null +++ b/docs/changelog_plugins/2024/august.rst @@ -0,0 +1,67 @@ +August 2024 +========== + +August 27 - Unicon.Plugins v24.8 +------------------------ + + + +.. csv-table:: Module Versions + :header: "Modules", "Versions" + + ``unicon.plugins``, v24.8 + ``unicon``, v24.8 + +Install Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install unicon.plugins + bash$ pip install unicon + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install --upgrade unicon.plugins + bash$ pip install --upgrade unicon + +Features and Bug Fixes: +^^^^^^^^^^^^^^^^^^^^^^^ + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Add +-------------------------------------------------------------------------------- + +* pid_tokens + * add pid entry for ir1800 device + + +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* generic + * Update execute() service log message to include device alias + * Update unittests to handle authentication exceptions + * Update unittests for token learning + +* iosxr + * Update more prompt handling to support (END) prompt + + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* iosxr + * New `monitor` service for IOS-XR with support for "monitor interface" command. + + diff --git a/docs/changelog_plugins/2024/september.rst b/docs/changelog_plugins/2024/september.rst new file mode 100644 index 00000000..746de0d6 --- /dev/null +++ b/docs/changelog_plugins/2024/september.rst @@ -0,0 +1,67 @@ +September 2024 +========== + +September 24 - Unicon.Plugins v24.8 +------------------------ + + + +.. csv-table:: Module Versions + :header: "Modules", "Versions" + + ``unicon.plugins``, v24.8 + ``unicon``, v24.8 + +Install Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install unicon.plugins + bash$ pip install unicon + +Upgrade Instructions +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + bash$ pip install --upgrade unicon.plugins + bash$ pip install --upgrade unicon + +Features and Bug Fixes: +^^^^^^^^^^^^^^^^^^^^^^^ + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Add +-------------------------------------------------------------------------------- + +* pid_tokens + * add pid entry for ir1800 device + + +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* generic + * Update execute() service log message to include device alias + * Update unittests to handle authentication exceptions + * Update unittests for token learning + +* iosxr + * Update more prompt handling to support (END) prompt + + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* iosxr + * New `monitor` service for IOS-XR with support for "monitor interface" command. + + diff --git a/docs/changelog_plugins/index.rst b/docs/changelog_plugins/index.rst index 699b6f68..85191282 100644 --- a/docs/changelog_plugins/index.rst +++ b/docs/changelog_plugins/index.rst @@ -4,6 +4,8 @@ Plugins Changelog .. toctree:: :maxdepth: 2 + 2024/september + 2024/august 2024/july 2024/june 2024/may diff --git a/docs/user_guide/services/iosxr.rst b/docs/user_guide/services/iosxr.rst index 18ee790a..606004a7 100644 --- a/docs/user_guide/services/iosxr.rst +++ b/docs/user_guide/services/iosxr.rst @@ -138,6 +138,87 @@ Has same arguments as generic configure service. output = device.configure_exclusive('logging console disable') +monitor +------- + +The monitor service can be used with the `monitor interface` command. You can +also pass `action` commands to execute while the monitor is running. For +example `clear` (lowercase) will send the key associated with the action as +shown in the output, i.e. Clear="c" will send "c" for action "clear". + +=============== ====================== ================================================== +Argument Type Description +=============== ====================== ================================================== +command str monitor command to execute ('monitor' is optional) + or action to send (e.g. 'clear') +reply Dialog additional dialog +timeout int (default 60 sec) timeout value for the overall interaction. +=============== ====================== ================================================== + +Example: + +.. code-block:: python + + rtr.monitor('monitor interface GigabitEthernet0/0/0/0') + + # execute `monitor interface` + rtr.monitor('interface') + + # tail the output for 10 seconds + rtr.monitor.tail(timeout=10) + + output = rtr.monitor.stop() + + # send an action to the device + rtr.monitor('clear') + rtr.monitor('bytes') + + +monitor.get_buffer +~~~~~~~~~~~~~~~~~~ + +To get the output that has been buffered by the monitor service, you can use the `monitor.get_buffer` +method. This will return all output from the start of the monitor command until the moment of execution +of this service. + +===================== ====================== =================================================== +Argument Type Description +===================== ====================== =================================================== +truncate bool (default: False) If true, will truncate the current buffer. +===================== ====================== =================================================== + +.. code-block:: python + + output = rtr.monitor.get_buffer() + + +monitor.tail +~~~~~~~~~~~~ + +The monitor.tail method can be used to monitor the output logging after the ``monitor`` service +has been used to start the monitor. + +===================== ====================== =================================================== +Argument Type Description +===================== ====================== =================================================== +timeout int (seconds) maximum time to wait before returning output. +===================== ====================== =================================================== + +.. code-block:: python + + output = rtr.monitor.tail(timeout=30) + + +monitor.stop +~~~~~~~~~~~~ + +Stop the monitor and return all output. + +.. code-block:: python + + output = rtr.monitor.stop() + + Sub-Plugins ----------- @@ -152,7 +233,7 @@ attach_console """""""""""""" Service to attach to line card console/Standby RP to execute commands in. Returns a -router-like object to execute commands on using python context managers.This service is +router-like object to execute commands on using python context managers.This service is supported in HA as well. ==================== ====================== ======================================== @@ -176,8 +257,8 @@ switchto """""""" Service to switch the router console to any state that user needs in order to perform -his tests. The api becomes a no-op if the console is already at the state user wants -to reach. This service is supported in HA as well. +his tests. The api becomes a no-op if the console is already at the state user wants +to reach. This service is supported in HA as well. The states available to switch to are : @@ -197,7 +278,7 @@ timeout int (default in None) timeout in sec for executing c ==================== ====================== ======================================== .. code-block:: python - + device.switchto("xr_env") .... some commands that need to be run in xr_env state .... - device.switchto("enable") + device.switchto("enable") diff --git a/src/unicon/plugins/generic/service_implementation.py b/src/unicon/plugins/generic/service_implementation.py index 0c728f73..e2431e0d 100644 --- a/src/unicon/plugins/generic/service_implementation.py +++ b/src/unicon/plugins/generic/service_implementation.py @@ -720,14 +720,10 @@ def call_service(self, command=[], # noqa: C901 command_output = {} for command in commands: - via = con.via - alias = con.alias if hasattr(con, 'alias') and con.alias != 'cli' else None - if alias and via: - con.log.info("+++ %s with via '%s' and alias '%s': executing command '%s' +++" % (con.hostname, via, alias, command)) - elif via: - con.log.info("+++ %s with via '%s': executing command '%s' +++" % (con.hostname, via, command)) - else: - con.log.info("+++ %s: executing command '%s' +++" % (con.hostname, command)) + + message = f"executing command '{command}'" + super().log_service_call(message) + con.sendline(command) try: dialog_match = dialog.process( diff --git a/src/unicon/plugins/generic/statements.py b/src/unicon/plugins/generic/statements.py index 36494018..56c22706 100644 --- a/src/unicon/plugins/generic/statements.py +++ b/src/unicon/plugins/generic/statements.py @@ -366,7 +366,8 @@ def password_handler(spawn, context, session): raise UniconAuthenticationError('Too many password retries') if context.get('username', '') == spawn.last_sent.rstrip() or ssh_tacacs_handler(spawn, context): - spawn.sendline(context['tacacs_password']) + if (tacacs_password := context.get('tacacs_password')): + spawn.sendline(tacacs_password) else: spawn.sendline(context['line_password']) diff --git a/src/unicon/plugins/iosxe/service_implementation.py b/src/unicon/plugins/iosxe/service_implementation.py index 79154677..8258ff4f 100644 --- a/src/unicon/plugins/iosxe/service_implementation.py +++ b/src/unicon/plugins/iosxe/service_implementation.py @@ -349,7 +349,8 @@ def pre_service(self, *args, **kwargs): sm.go_to('enable', con.spawn, context=self.context) - con.configure('config-register 0x0') + confreg = kwargs.get('config_register', "0x0") + con.configure('config-register {}'.format(confreg)) super().pre_service(*args, **kwargs) diff --git a/src/unicon/plugins/iosxe/stack/service_implementation.py b/src/unicon/plugins/iosxe/stack/service_implementation.py index 70c717cb..a6c5d08f 100644 --- a/src/unicon/plugins/iosxe/stack/service_implementation.py +++ b/src/unicon/plugins/iosxe/stack/service_implementation.py @@ -4,7 +4,7 @@ from datetime import datetime, timedelta import re from unicon.eal.dialogs import Dialog -from unicon.core.errors import SubCommandFailure, StateMachineError +from unicon.core.errors import SubCommandFailure from unicon.bases.routers.services import BaseService from .exception import StackMemberReadyException @@ -114,8 +114,6 @@ def call_service(self, command=None, connect_dialog = self.connection.connection_provider.get_connection_dialog() dialog += connect_dialog - start_time = datetime.now() - conn.log.info('Processing on active rp %s-%s' % (conn.hostname, conn.alias)) conn.sendline(switchover_cmd) try: @@ -144,11 +142,10 @@ def call_service(self, command=None, sleep(self.connection.settings.POST_SWITCHOVER_SLEEP) # check all members are ready - recheck_sleep_interval = self.connection.settings.SWITCHOVER_POSTCHECK_INTERVAL - recheck_max = timeout - (datetime.now() - start_time).seconds + conn.state_machine.detect_state(conn.spawn, context=conn.context) - self.connection.log.info('Wait for all members to be ready.') - if utils.is_all_member_ready(conn, timeout=recheck_max, interval=recheck_sleep_interval): + interval = self.connection.settings.SWITCHOVER_POSTCHECK_INTERVAL + if utils.is_all_member_ready(conn, timeout=timeout, interval=interval): self.connection.log.info('All members are ready.') else: self.connection.log.info('Timeout in %s secs. ' @@ -252,7 +249,6 @@ def call_service(self, conn.context['post_reload_timeout'] = timedelta(seconds= self.post_reload_wait_time) conn.log.info('Processing on active rp %s-%s' % (conn.hostname, conn.alias)) - start_time = current_time = datetime.now() conn.sendline(reload_cmd) try: reload_cmd_output = reload_dialog.process(conn.spawn, @@ -288,38 +284,39 @@ def call_service(self, self.connection.log.error(e) raise SubCommandFailure('Reload failed.', e) from e else: - self.connection.log.info('Processing autoboot on rp %s-%s' % (conn.hostname, conn.alias)) - - - self.connection.log.info('Sleeping for %s secs.' % \ - self.connection.settings.STACK_POST_RELOAD_SLEEP) - sleep(self.connection.settings.STACK_POST_RELOAD_SLEEP) - - # make sure detect_state is good to reduce the chance of timeout later - recheck_sleep_interval = self.connection.settings.RELOAD_POSTCHECK_INTERVAL - recheck_max = timeout - (datetime.now() - start_time).seconds - + try: + # bring device to enable mode + conn.state_machine.go_to('any', conn.spawn, timeout=timeout, + prompt_recovery=self.prompt_recovery, + context=conn.context) + conn.state_machine.go_to('enable', conn.spawn, timeout=timeout, + prompt_recovery=self.prompt_recovery, + context=conn.context) + except Exception as e: + raise SubCommandFailure('Failed to bring device to disable mode.', e) from e # check active and standby rp is ready self.connection.log.info('Wait for Standby RP to be ready.') - - if utils.is_active_standby_ready(conn, timeout=recheck_max, interval=recheck_sleep_interval): + interval = self.connection.settings.RELOAD_POSTCHECK_INTERVAL + if utils.is_active_standby_ready(conn, timeout=timeout, interval=interval): self.connection.log.info('Active and Standby RPs are ready.') else: self.connection.log.info('Timeout in %s secs. ' 'Standby RP is not in Ready state. Reload failed' % timeout) self.result = False return - - self.connection.log.info('Start checking state of all members') - recheck_max = timeout - (datetime.now() - start_time).seconds - if utils.is_all_member_ready(conn, timeout=recheck_max, interval=recheck_sleep_interval): - self.connection.log.info('All Members are ready.') - else: - self.connection.log.info(f'Timeout in {recheck_max} secs. ' - f'Not all members are in Ready state. Reload failed') - self.result = False - return + if member: + if utils.is_all_member_ready(conn, timeout=timeout, interval=interval): + self.connection.log.info('All Members are ready.') + else: + self.connection.log.info(f'Timeout in {timeout} secs. ' + f'Member{member} is not in Ready state. Reload failed') + self.result = False + return + + self.connection.log.info('Sleeping for %s secs.' % \ + self.connection.settings.STACK_POST_RELOAD_SLEEP) + sleep(self.connection.settings.STACK_POST_RELOAD_SLEEP) self.connection.log.info('Disconnecting and reconnecting') self.connection.disconnect() @@ -572,12 +569,10 @@ def _check_invalid_mac(con): return True return False - chk_interval = con.settings.RELOAD_POSTCHECK_INTERVAL + from genie.utils.timeout import Timeout + exec_timeout = Timeout(timeout, 15) found_invalid_mac = False - start_time2 = time() - while (time() - start_time2) < timeout: - t_left = timeout - (time() - start_time2) - con.log.info('-- checking time left: %0.1f secs' % t_left) + while exec_timeout.iterate(): con.log.info('Make sure no invalid mac address 0000.0000.0000') if not _check_invalid_mac(con): con.log.info('Did not find invalid mac as 0000.0000.0000') @@ -586,8 +581,7 @@ def _check_invalid_mac(con): else: con.log.warning('Found 0000.0000.0000 mac address') found_invalid_mac = True - con.log.info(f'Sleep {chk_interval} secs') - sleep(chk_interval) + exec_timeout.sleep() continue else: if found_invalid_mac: diff --git a/src/unicon/plugins/iosxe/stack/service_patterns.py b/src/unicon/plugins/iosxe/stack/service_patterns.py index 97769274..bae0caad 100644 --- a/src/unicon/plugins/iosxe/stack/service_patterns.py +++ b/src/unicon/plugins/iosxe/stack/service_patterns.py @@ -25,5 +25,3 @@ def __init__(self): self.reload_entire_shelf = r'^.*?Reload the entire shelf \[confirm\]' self.reload_fast = r'^.*Proceed with reload fast\? \[confirm\]' self.apply_config = r'.*All switches in the stack have been discovered. Accelerating discovery.*' - self.bp_console = r'^.*sw\..*-bp>' - self.bp_console_enable = r'^.*sw\..*-bp#' diff --git a/src/unicon/plugins/iosxe/stack/service_statements.py b/src/unicon/plugins/iosxe/stack/service_statements.py index fb69bebb..f3a6bb05 100644 --- a/src/unicon/plugins/iosxe/stack/service_statements.py +++ b/src/unicon/plugins/iosxe/stack/service_statements.py @@ -31,7 +31,7 @@ def stack_press_return(spawn, context, session): # to make sure that we get out of the process dialog when all the members are ready we # make sure first we match "All switches in the stack have been discovered. Accelerating discovery" in the # buffer then we raise the StackMemberReadyException to end the process. - if session.get('apply_config_on_all_members') or session.get('bp_console'): + if session.get('apply_config_on_all_members'): spawn.log.info('Waiting for buffer to settle') timeout_time = context.get('post_reload_wait_time', 60) if not isinstance(timeout_time, timedelta): @@ -43,7 +43,7 @@ def stack_press_return(spawn, context, session): break current_time = datetime.now() if (current_time - start_time) > timeout_time: - spawn.log.info('Time out, trying to access device..') + spawn.log.info('Time out, trying to acces device..') break spawn.sendline() raise StackMemberReadyException @@ -53,12 +53,6 @@ def apply_config_on_all_switch(spawn, session): """ Handles the number of apply configure message seen after install image """ session["apply_config_on_all_members"] = True -def bp_console_handler(spawn, session): - ''' strack_press_return will not wait for session["apply_config_on_all_members"] to be set - However, this pattern "All switches in the stack have been discovered. Accelerating discovery" - will never be seen for new stack design, which will cause the stack_press_return to wait forever. - Therefore, also checking bp-console prompt to make sure the reload process dialog will stop.''' - session["bp_console"] = True # switchover service statements @@ -164,11 +158,6 @@ def bp_console_handler(spawn, session): continue_timer=False) -bp_console = Statement(pattern=reload_pat.bp_console, - action=bp_console_handler, - loop_continue=True, - continue_timer=False) - stack_reload_stmt_list = list(reload_statement_list) stack_reload_stmt_list.extend([en_state, dis_state]) @@ -176,7 +165,6 @@ def bp_console_handler(spawn, session): stack_reload_stmt_list.insert(0, reload_shelf) stack_reload_stmt_list.insert(0, reload_fast) stack_reload_stmt_list.insert(0, apply_config) -stack_reload_stmt_list.insert(0, bp_console) stack_factory_reset_stmt_list = [factory_reset_confirm, are_you_sure_confirm] diff --git a/src/unicon/plugins/iosxe/stack/utils.py b/src/unicon/plugins/iosxe/stack/utils.py index 313221f3..7f656bb1 100644 --- a/src/unicon/plugins/iosxe/stack/utils.py +++ b/src/unicon/plugins/iosxe/stack/utils.py @@ -6,7 +6,6 @@ from unicon.eal.dialogs import Dialog from unicon.utils import Utils, AttributeDict -from unicon.core.errors import StateMachineError from .exception import StackMemberReadyException from .service_statements import send_boot @@ -115,23 +114,9 @@ def is_active_standby_ready(self, connection, timeout=120, interval=30): """ active = standby = '' start_time = time() - end_time = start_time + timeout - - while (time() - start_time) < timeout: - # double check the connection state - self.wait_for_any_state(connection, timeout=end_time - time(), interval=interval) - try: - # one connection reached a known state does not mean all connections are in the same state - # so cli execution can still fail - details = self.get_redundancy_details(connection) - except Exception as e: - connection.log.warning('Failed to get redundancy details. Stack might not be ready yet') - connection.log.info('Sleeping for %s secs.' % interval) - sleep(interval) - continue - + details = self.get_redundancy_details(connection) for sw_num, info in details.items(): if info['role'] == 'Active': active = info.get('state') @@ -180,20 +165,9 @@ def is_all_member_ready(self, connection, timeout=270, interval=30): """ ready = active = standby = False start_time = time() - end_time = start_time + timeout while (time() - start_time) < timeout: - # double check the console state. - self.wait_for_any_state(connection, timeout=end_time - time(), interval=interval) - try: - # one connection reached a known state does not mean all connections are in the same state - # so cli execution can still fail - details = self.get_redundancy_details(connection) - except Exception as e: - connection.log.warning('Failed to get redundancy details. Stack might not be ready yet') - connection.log.info('Sleeping for %s secs.' % interval) - sleep(interval) - continue + details = self.get_redundancy_details(connection) for sw_num, info in details.items(): state = info.get('state') if state != 'Ready': @@ -232,47 +206,3 @@ def get_standby_rp_sn(self, connection): standby = int(sw_num) return standby - - - def wait_for_any_state(self, connection, timeout=180, interval=15, auto_timeout_extend=True, auto_extend_secs=180): - ''' use this method to wait for any state or bypass possible timing issue which could cause state detection failure - use this where false failure is seen due to timing issue - Args: - connection (`obj`): connection object - timeout (`int`): timeout value, default is 180 secs - interval (`int`): check interval, default is 15 secs - auto_timeout_extend (`bool`): auto extend timeout if less than 0 - This is useful when the timeout is calculated based on an estimated total timeout - auto_extend_secs (`int`): Extend timeout to this vaule when auto_timeout_extend is True. Default is 180 secs - Returns: - None - raises StateMachineError if state detection fails and timeout is reached - - ''' - start_time = time() - good_state = False - if timeout <= 0 and auto_timeout_extend: - connection.log.warning(f'wait_for_any_state: given timeout is less than 0. Extend it to {auto_extend_secs} seconds') - timeout = auto_extend_secs - elif timeout <= 0: - connection.log.warning(f'wait_for_any_state: given timeout is less than 0. No auto extend. set timeout to 10 seconds') - timeout = 10 # set it to 10 seconds to check at least once - else: - connection.log.warning(f'wait_for_any_state: given timeout={timeout} seconds. No auto extend') - - connection.log.info(f'Looking for known state (detect_state) on {connection.alias} -- timeout={timeout} seconds') - while (time() - start_time) < timeout: - t_left = timeout - (time() - start_time) - connection.log.info('-- checking time left: %0.1f secs' % t_left) - try: - connection.state_machine.detect_state(connection.spawn, context=connection.context) - good_state = True - break - except Exception as e: - connection.log.warning(f'Fail to detect any state on {connection.alias}') - connection.log.info(f'Sleep {interval} secs') - sleep(interval) - if not good_state: - raise StateMachineError(f'wait_for_any_state: Timeout reached on {connection.alias}') - else: - connection.log.info(f'detect_state on {connection.alias} is successful') diff --git a/src/unicon/plugins/iosxr/__init__.py b/src/unicon/plugins/iosxr/__init__.py index 9053233a..4f0a273a 100755 --- a/src/unicon/plugins/iosxr/__init__.py +++ b/src/unicon/plugins/iosxr/__init__.py @@ -27,6 +27,7 @@ def __init__(self): self.admin_bash_console = svc.AdminBashService self.ping = IosXePing self.reload = svc.Reload + self.monitor = svc.Monitor class IOSXRHAServiceList(HAServiceList): @@ -45,7 +46,7 @@ def __init__(self): self.admin_attach_console = svc.AdminAttachModuleConsole self.admin_bash_console = svc.AdminBashService self.get_rp_state = svc.GetRPState - + self.monitor = svc.Monitor class IOSXRSingleRpConnection(BaseSingleRpConnection): os = 'iosxr' diff --git a/src/unicon/plugins/iosxr/patterns.py b/src/unicon/plugins/iosxr/patterns.py index f866c199..19f6f9d9 100755 --- a/src/unicon/plugins/iosxr/patterns.py +++ b/src/unicon/plugins/iosxr/patterns.py @@ -40,3 +40,17 @@ def __init__(self): self.confirm_y_prompt = r"\[confirm( with only 'y' or 'n')?\]\s*\[y/n\].*$" self.reload_module_prompt = r"^(.*)?Reload hardware module ? \[no,yes\].*$" self.proceed_config_mode = r'Would you like to proceed in configuration mode\? \[no\]:\s*$' + + # when changing more_prompt, please also change plugins/iosxr/settings.py MORE_REPLACE_PATTERN + # ESC[7m--More--ESC[27m + # ESC[7m(END)ESC[27m + self.more_prompt = r'^.*(--\s?[Mm]ore\s?--|\(END\)).*$' + + # Brief='b', Detail='d', Protocol(IPv4/IPv6)='r' + # Brief='b', Detail='d', Protocol(IPv4/IPv6)='r'\x1b[K\r\n\x1b[K\r\n + # (General='g', IPv4 Uni='4u', IPv4 Multi='4m', IPv6 Uni='6u', IPv6 Multi='6m') + self.monitor_prompt = r"^(.*?)(Brief='b', Detail='d', Protocol\(IPv4/IPv6\)='r'|\(General='g', IPv4 Uni='4u', IPv4 Multi='4m', IPv6 Uni='6u', IPv6 Multi='6m'\))(\x1b\S+[\r\n]+)*$" + # r1 Monitor Time: 00:00:06 SysUptime: 15:48:49 + self.monitor_time_regex = r'(?P\S+).*?Monitor Time: (?P