From f896c8dfd66f90454266d0d871e92585dddae56d Mon Sep 17 00:00:00 2001 From: domachad Date: Tue, 3 Sep 2024 13:17:04 -0400 Subject: [PATCH] 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