cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
1320
Views
3
Helpful
10
Replies

pyATS Unicon connection to Arista switch times out

l00pback
Level 1
Level 1

Using EOS unicon plugin to connect to Arista switch.

During device.connect(), password is sent and unicon logs: %UNICON-INFO: +++ connection to spawn: ssh .... 
Then it times out with TimeoutError error.

One specific fact for this Arista switch is that when you login through SSH, once password is entered and user gets authenticated successfully, it will show a message: " Last login: #date# from IP address" before showing the hostname# prompt.

So I am assuming the login handler expects to see hostname in case of successful authentication or some error but not the "Last login" message through its predefined pattern matching logic.

How can that "last login" pattern be added for proper handling in this case?

10 Replies 10

You can do this by adding a custom statement to the connection dialog. Be something like (excuse the formatting on my phone!)

last_login_stmt = Statement( pattern=r'.*Last login:.*', action=None, loop_continue=True, continue_timer=True )

then .append(last_login_stmt) that to your device connection.

Please mark this as helpful or solution accepted to help others
Connect with me https://bigevilbeard.github.io

l00pback
Level 1
Level 1

Thanks for the reply. Trying to figure out how to append the Statement to my device connection.

Usually I use pyATS testbed to connect:

from pyats.topology import loader
testbed = loader.load(test_bed_file.yaml)
device = testbed.devices[device_name]
device.connect()

I get that I can define the new statement like this:

from unicon.eal.dialogs import Statement
last_login_stmt = Statement( pattern=r'.*Last login:.*', action=None, loop_continue=True, continue_timer=True )

But it seems I need to use native Python Unicon APIs to connect instead:

from unicon import Connection
dev = Connection(hostname=xxx, ....)
dev.connect()

How do I append the statement above? Am I on the right track?

You would not need to switch away from PyATS testbed and you can still use your testbed YAML and append the statement before connecting.

Please mark this as helpful or solution accepted to help others
Connect with me https://bigevilbeard.github.io

l00pback
Level 1
Level 1

Ok no idea how to do that. pyATS / Unicon are not open source so not able to look further.

Please test this, its been a minute since i did this. Try

from pyats.topology import loader
from unicon.eal.dialogs import Statement


testbed = loader.load('test_bed_file.yaml')
device = testbed.devices['device_name']

last_login_stmt = Statement(
    pattern=r'.*Last login:.*',
    action=None,
    loop_continue=True,
    continue_timer=True
)

device.connectionmgr.connections['default'].connection_provider.get_connection_dialog().append(last_login_stmt)

device.connect()

 

 

Please mark this as helpful or solution accepted to help others
Connect with me https://bigevilbeard.github.io

Thanks @bigevilbeard 

device.connectionmgr.connections['default'].connection_provider.get_connection_dialog().append(last_login_stmt)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[9], line 1
----> 1 device.connectionmgr.connections['default'].connection_provider.get_connection_dialog().append(last_login_stmt)

AttributeError: 'NoneType' object has no attribute 'connection_provider'

Where is this 'default' coming from? I guess that should be defined inside the testbed and I do not have it.

Thanks, told you was rusty! Soo...... i think if you update device.connect with these three lines.

 

device.instantiate()

device.connectionmgr.connections['default'].connection_provider.get_connection_dialog().append(last_login_stmt)

device.connect()

 

 

Please mark this as helpful or solution accepted to help others
Connect with me https://bigevilbeard.github.io

l00pback
Level 1
Level 1

Ok, so the first one works:

device1.instantiate()
2025-10-08 17:00:03,196: %UNICON-INFO: +++ device_name logfile device_name-cli-123423.log +++
2025-10-08 17:00:03,200: %UNICON-INFO: +++ Unicon plugin eos (unicon.plugins.eos) +++
Out[12]: <unicon.plugins.eos.EOSSingleRPConnection at 0x7f7e51953c20>

But the second errors out as before:

In [25]: device1.connectionmgr.connections['default'].connection_provider.get_connection_dialog().append(last_login_stmt)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[25], line 1
----> 1 device1.connectionmgr.connections['default'].connection_provider.get_connection_dialog().append(last_login_stmt)
AttributeError: 'NoneType' object has no attribute 'get_connection_dialog'

 

Seems get_connection_dialog() is not a method of device1.connectionmgr.connections['default'].connection_provider:

In [27]: dir(device1.connectionmgr.connections['default'].connection_provider)
Out[27]:
['__bool__',
'__class__',
'__delattr__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getstate__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__']

 

Hmm so the connection type is none. Try

device.instantiate()

device.connectionmgr.connections['default'].dialogs.append(last_login_stmt)

device.connect()

Please mark this as helpful or solution accepted to help others
Connect with me https://bigevilbeard.github.io

In [28]: device1.connectionmgr.connections['default'].dialogs.append(last_login_stmt)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[28], line 1
----> 1 device1.connectionmgr.connections['default'].dialogs.append(last_login_stmt)

AttributeError: 'EOSSingleRPConnection' object has no attribute 'dialogs'

In [29]: dir(device1.connectionmgr.connections['default'])
Out[29]:
['__class__',
'__delattr__',
'__device__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getstate__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lock__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'_connection_type',
'_get_learned_hostname',
'_hostname',
'_is_ha',
'_learned_hostname',
'_log_buffer',
'_logfile',
'_service_init',
'acquire',
'add_service',
'alias',
'attach',
'chassis_type',
'config',
'configure',
'configure_logging',
'connect',
'connect_reply',
'connected',
'connection_provider',
'connection_provider_class',
'connection_timeout',
'connection_type',
'context',
'copy',
'debug',
'device',
'disable',
'disconnect',
'enable',
'enable_password',
'execute',
'execute_proxy_commands',
'expect',
'expect_log',
'get_services',
'goto_enable',
'guestshell',
'hostname',
'init_config_commands',
'init_context',
'init_exec_commands',
'init_service',
'init_state_machine',
'is_connected',
'is_ha',
'learn_hostname',
'learn_os',
'learn_os_version',
'learn_tokens',
'learned_hostname',
'line_password',
'locked',
'log',
'log_buffer',
'log_file',
'log_propagate',
'log_stdout',
'log_user',
'logfile',
'logout',
'mit',
'mode',
'model',
'no_pyats_tasklog',
'operating_mode',
'os',
'os_flavor',
'overwrite_testbed_tokens',
'parent',
'parse_spawn_command',
'patch_service_attributes',
'ping',
'platform',
'playback_idx',
'playback_record',
'playback_replay',
'playback_speed',
'previous_hostname',
'prompt_recovery',
'proxy_connect',
'proxy_connections',
'receive',
'receive_buffer',
'reconnect',
'release',
'reload',
'role',
'rommon',
'send',
'sendline',
'service_attributes_patch',
'service_init',
'session',
'settings',
'setup_connection',
'shellexec',
'spawn',
'standby_goto_enable',
'start',
'state_machine',
'state_machine_class',
'subcommand_list',
'switchto',
'system_text',
'tacacs_password',
'traceroute',
'transmit',
'trim_line',
'username',
'via']

In [30]: