Skip to content

Commit

Permalink
Merge pull request #101 from CiscoTestAutomation/release_24.6
Browse files Browse the repository at this point in the history
Releasing v24.6
  • Loading branch information
omehrabi authored Jun 26, 2024
2 parents 4835c2e + adcce90 commit 46cdcc1
Show file tree
Hide file tree
Showing 22 changed files with 864 additions and 243 deletions.
63 changes: 63 additions & 0 deletions docs/changelog/2024/june.rst
Original file line number Diff line number Diff line change
@@ -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


1 change: 1 addition & 0 deletions docs/changelog/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Changelog
.. toctree::
:maxdepth: 2

2024/june
2024/may
2024/april
2024/march
Expand Down
55 changes: 55 additions & 0 deletions docs/changelog_plugins/2024/june.rst
Original file line number Diff line number Diff line change
@@ -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


1 change: 1 addition & 0 deletions docs/changelog_plugins/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Plugins Changelog
.. toctree::
:maxdepth: 2

2024/june
2024/may
2024/april
2024/march
Expand Down
2 changes: 1 addition & 1 deletion src/unicon/plugins/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = '24.5'
__version__ = '24.6'

supported_chassis = [
'single_rp',
Expand Down
2 changes: 1 addition & 1 deletion src/unicon/plugins/generic/patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.*)'
Expand Down
10 changes: 10 additions & 0 deletions src/unicon/plugins/iosxe/stack/exception.py
Original file line number Diff line number Diff line change
@@ -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

89 changes: 43 additions & 46 deletions src/unicon/plugins/iosxe/stack/service_implementation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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. '
Expand Down Expand Up @@ -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,
Expand All @@ -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

Expand All @@ -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()
Expand Down Expand Up @@ -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')
Expand All @@ -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:
Expand Down
3 changes: 3 additions & 0 deletions src/unicon/plugins/iosxe/stack/service_patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -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#'
Loading

0 comments on commit 46cdcc1

Please sign in to comment.