diff --git a/docs/changelog/2025/march.rst b/docs/changelog/2025/march.rst new file mode 100644 index 00000000..9eb04471 --- /dev/null +++ b/docs/changelog/2025/march.rst @@ -0,0 +1,51 @@ +March 2025 +========== + +March 25 - Unicon v25.3 +------------------------ + + + +.. csv-table:: Module Versions + :header: "Modules", "Versions" + + ``unicon.plugins``, v25.3 + ``unicon``, v25.3 + + + + +Changelogs +^^^^^^^^^^ +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* unicon.robot + * Modified Robot Library UniconRobot.py + * Address SyntaxWarning in UniconRobot.py showing up in python >= 3.12 + +* mock_device + * Updated mock device to handle ctrl-c for HA tests + + +-------------------------------------------------------------------------------- + New +-------------------------------------------------------------------------------- + +* connection_provider + * Modified execute_init_commands + * Updated logic to config init commands only on first connnection + + +-------------------------------------------------------------------------------- + Fix +-------------------------------------------------------------------------------- + +* generic + * Added fallback credentials to login_handler statement + +* iosxe + * Added grub statement in the list 'boot_from_rommon_statement_list' for + + diff --git a/docs/changelog/index.rst b/docs/changelog/index.rst index f8818805..e4cf4407 100644 --- a/docs/changelog/index.rst +++ b/docs/changelog/index.rst @@ -4,6 +4,7 @@ Changelog .. toctree:: :maxdepth: 2 + 2025/march 2025/february 2025/january 2024/november diff --git a/docs/changelog_plugins/2025/march.rst b/docs/changelog_plugins/2025/march.rst new file mode 100644 index 00000000..107b4d42 --- /dev/null +++ b/docs/changelog_plugins/2025/march.rst @@ -0,0 +1,19 @@ +March 2025 +========== + +March 25 - Unicon.Plugins v25.3 +------------------------ + + + +.. csv-table:: Module Versions + :header: "Modules", "Versions" + + ``unicon.plugins``, v25.3 + ``unicon``, v25.3 + + + + +Changelogs +^^^^^^^^^^ diff --git a/docs/changelog_plugins/index.rst b/docs/changelog_plugins/index.rst index 30cf5fe5..13b36dc0 100644 --- a/docs/changelog_plugins/index.rst +++ b/docs/changelog_plugins/index.rst @@ -4,6 +4,7 @@ Plugins Changelog .. toctree:: :maxdepth: 2 + 2025/march 2025/february 2025/january 2024/november diff --git a/src/unicon/plugins/__init__.py b/src/unicon/plugins/__init__.py index 83f3d5d2..fde86553 100644 --- a/src/unicon/plugins/__init__.py +++ b/src/unicon/plugins/__init__.py @@ -1,4 +1,4 @@ -__version__ = '25.2' +__version__ = '25.3' supported_chassis = [ 'single_rp', diff --git a/src/unicon/plugins/generic/service_statements.py b/src/unicon/plugins/generic/service_statements.py index 631be71b..bb417e8d 100644 --- a/src/unicon/plugins/generic/service_statements.py +++ b/src/unicon/plugins/generic/service_statements.py @@ -53,6 +53,8 @@ def login_handler(spawn, context, session): """ credential = get_current_credential(context=context, session=session) if credential: + if credential != 'default': + spawn.log.info(f'Using {credential} credential set for login into device') common_cred_username_handler( spawn=spawn, context=context, credential=credential) else: diff --git a/src/unicon/plugins/generic/statements.py b/src/unicon/plugins/generic/statements.py index b61354f8..928af1ba 100644 --- a/src/unicon/plugins/generic/statements.py +++ b/src/unicon/plugins/generic/statements.py @@ -216,6 +216,8 @@ def login_handler(spawn, context, session): """ credential = get_current_credential(context=context, session=session) if credential: + if credential != 'default': + spawn.log.info(f'Using {credential} credential set for login into device') common_cred_username_handler( spawn=spawn, context=context, credential=credential) else: diff --git a/src/unicon/plugins/iosxe/statements.py b/src/unicon/plugins/iosxe/statements.py index fa4d0569..b264af1a 100644 --- a/src/unicon/plugins/iosxe/statements.py +++ b/src/unicon/plugins/iosxe/statements.py @@ -217,7 +217,7 @@ def boot_image(spawn, context, session): boot_from_rommon_statement_list = [ please_reset_stmt, admin_password_stmt, setup_dialog_stmt, auto_install_stmt, - boot_timeout_stmt + boot_timeout_stmt, grub_prompt_stmt ] @@ -245,4 +245,4 @@ def wrapper(spawn, session, context, **kwargs): boot_from_rommon_statement_list += connection_statement_list.copy() for stmt in boot_from_rommon_statement_list: if stmt.pattern in [reload_patterns.press_return] or stmt.loop_continue is False: - stmt.action = boot_finished_deco(stmt.action) + stmt.action = boot_finished_deco(stmt.action) \ No newline at end of file diff --git a/src/unicon/plugins/iosxr/spitfire/statements.py b/src/unicon/plugins/iosxr/spitfire/statements.py index 6566dc30..877cfb8e 100644 --- a/src/unicon/plugins/iosxr/spitfire/statements.py +++ b/src/unicon/plugins/iosxr/spitfire/statements.py @@ -46,6 +46,8 @@ def xr_login_handler(spawn, context, session): """ credential = get_current_credential(context=context, session=session) if credential: + if credential != 'default': + spawn.log.info(f'Using {credential} credential set to login into device') common_cred_username_handler(spawn=spawn, context=context, credential=credential) else: spawn.sendline(context['username']) diff --git a/src/unicon/plugins/linux/statements.py b/src/unicon/plugins/linux/statements.py index 605685e4..93283432 100644 --- a/src/unicon/plugins/linux/statements.py +++ b/src/unicon/plugins/linux/statements.py @@ -16,6 +16,8 @@ def username_handler(spawn, context, session): credential = get_current_credential(context=context, session=session) if credential: + if credential != 'default': + spawn.log.info(f'Using {credential} credential set for login into device') common_cred_username_handler(spawn=spawn, context=context, credential=credential) else: diff --git a/src/unicon/plugins/nxos/service_statements.py b/src/unicon/plugins/nxos/service_statements.py index 6984528a..ac96db63 100644 --- a/src/unicon/plugins/nxos/service_statements.py +++ b/src/unicon/plugins/nxos/service_statements.py @@ -41,6 +41,8 @@ def admin_password_handler(spawn, context, session): """ credential = get_current_credential(context=context, session=session) if credential: + if credential != 'default': + spawn.log.info(f'Using {credential} credential set for login into devices') common_cred_password_handler( spawn=spawn, context=context, credential=credential, session=session, reuse_current_credential=True) diff --git a/src/unicon/plugins/sros/statements.py b/src/unicon/plugins/sros/statements.py index 4c02ca3b..60d19a46 100644 --- a/src/unicon/plugins/sros/statements.py +++ b/src/unicon/plugins/sros/statements.py @@ -15,6 +15,8 @@ def username_handler(spawn, context, session): credential = get_current_credential(context=context, session=session) if credential: + if credential != 'default': + spawn.log.info(f'Using {credential} credential set for login into device') common_cred_username_handler(spawn=spawn, context=context, credential=credential) else: diff --git a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_cat9k.yaml b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_cat9k.yaml index 5cf1bd62..4499b0af 100644 --- a/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_cat9k.yaml +++ b/src/unicon/plugins/tests/mock_data/iosxe/iosxe_mock_cat9k.yaml @@ -628,6 +628,18 @@ c9k_login5: "admin": new_state: c9k_password5 +c9k_login6: + prompt: "Username: " + commands: + "admin": + new_state: c9k_password6 + +c9k_password6: + prompt: "Password: " + commands: + "cisco": + new_state: c9k_login4 + c9k_password5: prompt: "Password: " commands: diff --git a/src/unicon/plugins/tests/test_plugin_generic.py b/src/unicon/plugins/tests/test_plugin_generic.py index 836df53c..b3b3e576 100644 --- a/src/unicon/plugins/tests/test_plugin_generic.py +++ b/src/unicon/plugins/tests/test_plugin_generic.py @@ -160,6 +160,7 @@ def mock_sendline(*args, **kwargs): print("Sendline called with: %s %s" % (args, kwargs)) self.spawn = MockSpawn() + self.spawn.log = Mock() self.spawn.spawn_command = 'ssh -l cisco@router' self.spawn.last_sent = 'ssh -l cisco@router' self.spawn.sendline = Mock(side_effect=mock_sendline) diff --git a/src/unicon/plugins/tests/test_plugin_iosxe_cat9k.py b/src/unicon/plugins/tests/test_plugin_iosxe_cat9k.py index 851fb18c..49172128 100644 --- a/src/unicon/plugins/tests/test_plugin_iosxe_cat9k.py +++ b/src/unicon/plugins/tests/test_plugin_iosxe_cat9k.py @@ -105,7 +105,42 @@ def test_connect_fallback(self): connections: defaults: class: unicon.Unicon - debug: True + fallback_credentials: + - set1 + a: + protocol: telnet + ip: 127.0.0.1 + port: {} + """.format(md.ports[0]) + + tb = loader.load(testbed) + device = tb.devices.R1 + try: + device.connect() + self.assertEqual(device.state_machine.current_state, 'enable') + finally: + device.disconnect() + md.stop() + + def test_connect_fallback_login_handler(self): + md = MockDeviceTcpWrapperIOSXE(port=0, state='c9k_login6', hostname='switch') + md.start() + + testbed = """ + devices: + R1: + os: iosxe + type: cat9k + credentials: + default: + username: admin + password: cisco + set1: + username: cisco + password: cisco + connections: + defaults: + class: unicon.Unicon fallback_credentials: - set1 a: diff --git a/src/unicon/plugins/utils.py b/src/unicon/plugins/utils.py index 6535b125..70fedcaa 100644 --- a/src/unicon/plugins/utils.py +++ b/src/unicon/plugins/utils.py @@ -31,8 +31,12 @@ def _fallback_cred(context): - return [context['default_cred_name']] \ + creds = [context['default_cred_name']] \ if 'default_cred_name' in context else [] + if context.get('fallback_creds'): + creds.extend(context['fallback_creds']) + return creds + def _get_creds_to_try(context): """ Get list of credentials to try. """