Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 24.1 #94

Merged
merged 2 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions docs/changelog/2024/january.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
January 2024
==========

30 - Unicon v24.1
------------------------



.. csv-table:: Module Versions
:header: "Modules", "Versions"

``unicon.plugins``, v24.1
``unicon``, v24.1

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
--------------------------------------------------------------------------------

* pty_backend
* Modified error handling logic to allow dialog to process statements on subprocess exit

* utils
* Update ansi pattern to allow imports

* statemachine
* Update hostname logic to handle hostnames with special characters

* unicon
* Add CLI option to enable debug logs


--------------------------------------------------------------------------------
Fix
--------------------------------------------------------------------------------

* service_implementation
* Modified Reload service
* Removed sendline after reload

* iosxr
* Modified moonshine UTs
* Updated wrong import statements in standalone_ping_test.py and config_test.py UTs.


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/january
2023/november
2023/october
2023/september
Expand Down
66 changes: 66 additions & 0 deletions docs/changelog_plugins/2024/january.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
January 2024
==========

30 - Unicon.Plugins v24.1
------------------------



.. csv-table:: Module Versions
:header: "Modules", "Versions"

``unicon.plugins``, v24.1
``unicon``, v24.1

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
--------------------------------------------------------------------------------

* generic
* Added more prompt support in connection statement list


--------------------------------------------------------------------------------
Fix
--------------------------------------------------------------------------------

* iosxe
* Added unittests to test hostnames with special characters\
* Update settings for reload API, change SYSLOG_WAIT to 10 seconds
* cat9k
* Update image_to_boot for HA device. (active and standby rp)

* generic, iosxe
* Update config transition logic, increase wait time for prompt

* generic
* Update response to setup dialog to "no" instead of "n"

* linux
* Update linux hostname learning pattern to handle ANSI characters in prompt


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/january
2023/november
2023/october
2023/september
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__ = '23.11'
__version__ = '24.1'

supported_chassis = [
'single_rp',
Expand Down
5 changes: 1 addition & 4 deletions src/unicon/plugins/generic/patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,12 @@ def __init__(self):
""" initialises all generic patterns
"""
super().__init__()
# self.enable_prompt = r'.*%N#\s?$'
self.default_hostname_pattern = r'WLC|RouterRP|Router|[Ss]witch|Controller|ios'

self.enable_prompt = r'^(.*?)(Router|Router-stby|Router-sdby|RouterRP|RouterRP-standby|%N-standby|%N\(standby\)|%N-sdby|%N-stby|(S|s)witch|(S|s)witch\(standby\)|Controller|ios|-Slot[0-9]+|%N)(\(boot\))*#\s?$'

# self.disable_prompt = r'.*%N>\s?$'
self.disable_prompt = r'^(.*?)(Router|Router-stby|Router-sdby|RouterRP|RouterRP-standby|%N-standby|%N-sdby|%N-stby|(S|s)witch|s(S|s)witch\(standby\)|Controller|ios|-Slot[0-9]+|%N)(\(boot\))*>\s?$'

# 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.standby_enable_prompt = r'^(.*?)(RouterRP-standby|%N-standby|%N-sdby|%N\(standby\))#\s?$'
Expand Down Expand Up @@ -71,7 +68,7 @@ def __init__(self):

self.config_locked = r'Configuration (mode )?(is )?locked|Config mode cannot be entered'

self.config_start = r'Enter configuration commands, one per line\.\s+End with CNTL/Z\.\s*$'
self.config_start = r'\nEnter configuration commands, one per line\.\s+End with CNTL/Z\.\s*$'

self.enable_secret = r'^.*?(Enter|Confirm) enable secret:\s*$'

Expand Down
14 changes: 12 additions & 2 deletions src/unicon/plugins/generic/service_implementation.py
Original file line number Diff line number Diff line change
Expand Up @@ -1094,10 +1094,12 @@ def call_service(self,
post_reload_wait_time = None,
*args, **kwargs):


con = self.connection
timeout = timeout or self.timeout

syslog_wait = con.settings.SYSLOG_WAIT
con.settings.SYSLOG_WAIT = con.settings.RELOAD_SYSLOG_WAIT

if error_pattern is None:
self.error_pattern = con.settings.ERROR_PATTERN
else:
Expand Down Expand Up @@ -1200,7 +1202,13 @@ def call_service(self,
if (current_time - start_time) > timeout_time:
con.log.info('Time out, trying to acces device..')
break
con.sendline()

# ! This line was added to resolve an issue with HA devices, but was
# ! found to cause further issues with other devices on reload
# TODO Need to find a better way to implement a fix for HA devices
# TODO that does not cause issues with other devices. Likely need to
# TODO modify the state machine and/or dialog processing.
# con.sendline()
try:
con.context = context
con.connection_provider.connect()
Expand All @@ -1212,6 +1220,8 @@ def call_service(self,
con.log.exception('Connection to {} failed'.format(con.hostname))
self.result = False

con.settings.SYSLOG_WAIT = syslog_wait

self.log_buffer.seek(0)
reload_output = self.log_buffer.read()
# clear buffer
Expand Down
2 changes: 1 addition & 1 deletion src/unicon/plugins/generic/service_statements.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ def config_session_locked_handler(context):
continue_timer=False)

setup_dialog = Statement(pattern=reload_patterns.setup_dialog,
action=send_response, args={'response': 'n'},
action=send_response, args={'response': 'no'},
loop_continue=True,
continue_timer=False)

Expand Down
9 changes: 4 additions & 5 deletions src/unicon/plugins/generic/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,8 @@ def __init__(self):
self.BOOT_FILESYSTEM = 'bootflash:'
self.BOOT_FILE_REGEX = r'(\S+\.bin)'

# Wait for the config prompt to appear
# before checking for the config prompt.
# This may need to be adjusted if the RTT between
# the execution host and lab device is high.
self.CONFIG_TRANSITION_WAIT = 0.2
# Time to wait for the config prompt to appear
self.CONFIG_TRANSITION_WAIT = 15

# If learn_hostname is requested but no hostname was actually learned,
# substitute this default hostname when occurances of HOSTNAME_SUBST_PAT
Expand All @@ -100,6 +97,8 @@ def __init__(self):

# syslog message handling timers
self.SYSLOG_WAIT = 1
# syslog wait time for reload service
self.RELOAD_SYSLOG_WAIT = 10

# pattern to replace "more" string
# command to continue for more_prompt_stmt
Expand Down
7 changes: 4 additions & 3 deletions src/unicon/plugins/generic/statemachine.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,17 @@ def config_service_prompt_handler(spawn, config_pattern):
""" Check if we need to send the sevice config prompt command.
"""
if hasattr(spawn.settings, 'SERVICE_PROMPT_CONFIG_CMD') and spawn.settings.SERVICE_PROMPT_CONFIG_CMD:
spawn.log.debug('Waiting for config prompt')
# if the config prompt is seen, return
if re.search(config_pattern, spawn.buffer):
return
else:
# if no buffer changes for a few seconds, check again
if buffer_settled(spawn, spawn.settings.CONFIG_PROMPT_WAIT):
# if no buffer changes for (config timout) seconds, check again
if buffer_settled(spawn, spawn.settings.CONFIG_TRANSITION_WAIT):
if re.search(config_pattern, spawn.buffer):
return
else:
spawn.log.debug('Config prompt not seen, enabling service prompt config')
spawn.sendline(spawn.settings.SERVICE_PROMPT_CONFIG_CMD)


Expand All @@ -66,7 +68,6 @@ def config_transition(statemachine, spawn, context):

for attempt in range(max_attempts + 1):
spawn.sendline(statemachine.config_command)
buffer_wait(spawn, spawn.settings.CONFIG_TRANSITION_WAIT)
dialog.process(spawn, timeout=spawn.settings.CONFIG_TIMEOUT, context=context)

statemachine.detect_state(spawn)
Expand Down
10 changes: 6 additions & 4 deletions src/unicon/plugins/generic/statements.py
Original file line number Diff line number Diff line change
Expand Up @@ -806,13 +806,15 @@ def __init__(self):
generic_statements.enter_your_selection_stmt
]

connection_statement_list = \
authentication_statement_list + \
initial_statement_list + \
pre_connection_statement_list

############################################################
# Default pattern Statement
#############################################################

default_statement_list = [generic_statements.more_prompt_stmt]

connection_statement_list = \
default_statement_list + \
authentication_statement_list + \
initial_statement_list + \
pre_connection_statement_list
14 changes: 12 additions & 2 deletions src/unicon/plugins/iosxe/cat9k/service_implementation.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,22 @@ def pre_service(self, *args, **kwargs):
if 'image_to_boot' in self.context:
self.context['orig_image_to_boot'] = self.context['image_to_boot']
self.context["image_to_boot"] = kwargs["image_to_boot"]
self.connection.active.context = self.context
self.connection.standby.context = self.context
self.connection.active.context.update({
"image_to_boot": self.context["image_to_boot"]
})
self.connection.standby.context.update({
"image_to_boot": self.context["image_to_boot"]
})
self.connection.log.info("'image_to_boot' specified with reload, transitioning to 'rommon' state")
else:
if 'image' in kwargs:
self.context['image_to_boot'] = kwargs.get('image')
self.connection.active.context.update({
"image_to_boot": self.context["image_to_boot"]
})
self.connection.standby.context.update({
"image_to_boot": self.context["image_to_boot"]
})
self.start_state = 'enable'

super().pre_service(*args, **kwargs)
Expand Down
19 changes: 2 additions & 17 deletions src/unicon/plugins/iosxe/statemachine.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

import re
from datetime import datetime
from unicon.plugins.generic.statemachine import GenericSingleRpStateMachine, config_transition
from unicon.plugins.generic.statemachine import (GenericSingleRpStateMachine, config_transition,
config_service_prompt_handler)
from unicon.plugins.generic.statements import (connection_statement_list,
default_statement_list, wait_and_enter)
from unicon.plugins.generic.service_statements import reload_statement_list
Expand Down Expand Up @@ -47,22 +48,6 @@ def send_break(statemachine, spawn, context):
spawn.send('\x03')


def config_service_prompt_handler(spawn, config_pattern):
""" Check if we need to send the sevice config prompt command.
"""
if hasattr(spawn.settings, 'SERVICE_PROMPT_CONFIG_CMD') and spawn.settings.SERVICE_PROMPT_CONFIG_CMD:
# if the config prompt is seen, return
if re.search(config_pattern, spawn.buffer):
return
else:
# if no buffer changes for a few seconds, check again
if buffer_settled(spawn, spawn.settings.CONFIG_PROMPT_WAIT):
if re.search(config_pattern, spawn.buffer):
return
else:
spawn.sendline(spawn.settings.SERVICE_PROMPT_CONFIG_CMD)


def enable_to_maintenance_transition(statemachine, spawn, context):

dialog = Dialog([
Expand Down
2 changes: 1 addition & 1 deletion src/unicon/plugins/iosxr/moonshine/tests/config_test.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python3

from pyats import aetest
from pyats.kleenex import BringUp
from pyats.bringup import BringUp
import re, logging

# NOTE: uut1 device must be Moonshine for this test to work.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python3

from pyats import aetest
from pyats.kleenex import BringUp
from pyats.bringup import BringUp

class common_setup(aetest.CommonSetup):
@aetest.subsection
Expand Down
5 changes: 3 additions & 2 deletions src/unicon/plugins/linux/patterns.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

from unicon.utils import ANSI_REGEX
from unicon.plugins.generic.patterns import GenericPatterns


class LinuxPatterns(GenericPatterns):
def __init__(self):
super().__init__()
Expand All @@ -11,7 +12,7 @@ def __init__(self):
# The reason for using the learn_hostname pattern instead of the shell_prompt pattern
# to learn the hostname, is that the regex in the router implementation matches \S
# which is not exact enough for the known linux prompts.
self.learn_hostname = r'^.*?(?P<hostname>[-\w]+)\s?([-\w\]/~:\.\d ]+)?([>\$~%#\]])\s*(\x1b\S+)?$'
self.learn_hostname = r'^.*?({a})?(?P<hostname>[-\w]+)\s?([-\w\]/~:\.\d ]+)?([>\$~%#\]])\s*(\x1b\S+)?$'.format(a=ANSI_REGEX)

# shell_prompt pattern will be used by the 'shell' state after lean_hostname matches
# a known hostname pattern this pattern is set for the shell state at transition
Expand Down
Loading
Loading