Skip to content

Commit 4c29eee

Browse files
author
Thomas Ryan
committed
Releasing v25.6
1 parent ea87320 commit 4c29eee

27 files changed

+569
-62
lines changed

docs/changelog/2025/june.rst

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
June 2025
2+
==========
3+
4+
June 29 - Unicon v25.6
5+
------------------------
6+
7+
8+
9+
.. csv-table:: Module Versions
10+
:header: "Modules", "Versions"
11+
12+
``unicon.plugins``, v25.6
13+
``unicon``, v25.6
14+
15+
16+
17+
18+
Changelogs
19+
^^^^^^^^^^
20+
--------------------------------------------------------------------------------
21+
New
22+
--------------------------------------------------------------------------------
23+
24+
* bases/connection
25+
* Added logout() method
26+
* Added logout implementation for routers
27+
28+
29+
--------------------------------------------------------------------------------
30+
Fix
31+
--------------------------------------------------------------------------------
32+
33+
* unicon
34+
* Refactor plugin loading from pkg_resources.iter_entry_points to importlib.metadata.entry_points
35+
36+
37+
--------------------------------------------------------------------------------
38+
New
39+
--------------------------------------------------------------------------------
40+
41+
* iosxe
42+
* Added support for fast reload pattern
43+
44+

docs/changelog/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Changelog
44
.. toctree::
55
:maxdepth: 2
66

7+
2025/june
78
2025/may
89
2025/april
910
2025/march
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
June 2025
2+
==========
3+
4+
June 29 - Unicon.Plugins v25.6
5+
------------------------
6+
7+
8+
9+
.. csv-table:: Module Versions
10+
:header: "Modules", "Versions"
11+
12+
``unicon.plugins``, v25.6
13+
``unicon``, v25.6
14+
15+
16+
17+
18+
Changelogs
19+
^^^^^^^^^^
20+
--------------------------------------------------------------------------------
21+
Fix
22+
--------------------------------------------------------------------------------
23+
24+
* iosxr/spitfire
25+
* Update ZTP lock check
26+
27+
* unicon.plugins
28+
* IOSXE
29+
* Stack
30+
* Fixed `image_to_boot` parameter in reload service so that it is actually used in the reload process.
31+
32+
* generic
33+
* Update syslog pattern
34+
35+
36+
--------------------------------------------------------------------------------
37+
New
38+
--------------------------------------------------------------------------------
39+
40+
* iosxe
41+
* IosXEPatterns
42+
* Added the ca-trustpool regex to match prompt for adding a CA certificate to the trustpool
43+
* Added ACM rules state and transition support to the IOS-XE plugin.
44+
* Enhanced Configure and HAConfigure services to support ACM rules CLI via the rules argument, using context-driven state transitions.
45+
* Added post-service transitions to gracefully return to enable mode after configuration.
46+
47+
* nxos
48+
* Introducing a new service l2rib_pycl in NXOS plugin as a replacement for the existing service l2rib_dt
49+
* Deprecating the existing service l2rib_dt
50+
51+

docs/changelog_plugins/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Plugins Changelog
44
.. toctree::
55
:maxdepth: 2
66

7+
2025/june
78
2025/may
89
2025/april
910
2025/march

docs/user_guide/services/nxos.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,9 +580,39 @@ reconnect_sleep int (default 60 sec) sleep time interval before
580580
result, output = rtr.reload(return_output=True)
581581
582582
583+
l2rib_pycl
584+
----------
585+
586+
Layer 2 Routing Information Base (L2RIB) pyclient service.
587+
588+
With this service, the l2rib tool can be used to execute l2rib_pycl commands.
589+
The service is intended to be used as a context manager, see example below.
590+
591+
======================= ======================= ===============================================
592+
Argument Type Description
593+
======================= ======================= ===============================================
594+
client_id int or str (optional) Client identifier for l2rib_pycl tool.
595+
By default, a random ID will be used.
596+
======================= ======================= ===============================================
597+
598+
599+
.. code-block:: python
600+
601+
# default client ID (random)
602+
with rtr.l2rib_pycl() as l2rib_pycl:
603+
l2rib_pycl.execute('l2rib command')
604+
605+
# specific client ID
606+
with rtr.l2rib_pycl(client_id=1000) as l2rib_pycl:
607+
l2rib_pycl.execute('l2rib command')
608+
583609
l2rib_dt
584610
--------
585611

612+
This service is similar to the l2rib_pycl service.
613+
It will be deprecated in the future and users are encouraged to use the
614+
l2rib_pycl service instead.
615+
586616
Layer 2 Routing Information Base (L2RIB) developer tool service.
587617

588618
With this service, the l2rib tool can be used to execute commands. The service

src/unicon/plugins/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "25.5"
1+
__version__ = "25.6"
22

33
supported_chassis = [
44
'single_rp',

src/unicon/plugins/generic/patterns.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,15 @@ def __init__(self):
6969
# %Error opening tftp://255.255.255.255/switch-confg (Timed out)
7070
# LC/0/2/CPU0:Sep 10 00:54:42.841
7171
# RP/0/0/CPU0:Oct 9 01:44:47.875
72-
self.syslog_message_pattern = r'^.*?(%\w+(-\S+)?-\d+-\w+|Guestshell destroyed successfully|%Error opening tftp:\/\/255\.255\.255\.255|Autoinstall trying|audit: kauditd hold queue overflow|(LC|RP)/\d+/\d+/CPU\d+:\w+\s+\d+\s+\d{2}:\d{2}:\d{2}).*\s*$'
73-
72+
# *May 28 09:01:05.136: yang-infra: Default hostkey created (NETCONF_SSH_RSA_KEY.server)
73+
# *May 28 09:01:11.975: PKI_SSL_IPC: SUDI certificate chain and key pair are invalid
74+
self.syslog_message_pattern = (
75+
r"^.*?(%\w+(-\S+)?-\d+-\w+|"
76+
r"yang-infra:|PKI_SSL_IPC:|Guestshell destroyed successfully|"
77+
r"%Error opening tftp:\/\/255\.255\.255\.255|Autoinstall trying|"
78+
r"audit: kauditd hold queue overflow|"
79+
r"(LC|RP)/\d+/\d+/CPU\d+:\w+\s+\d+\s+\d{2}:\d{2}:\d{2}).*\s*$"
80+
)
7481
self.config_locked = r'Configuration (mode )?(is )?locked|Config mode cannot be entered'
7582

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

src/unicon/plugins/iosxe/connection_provider.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def learn_tokens(self):
3232
con.spawn,
3333
context=con.context,
3434
prompt_recovery=con.prompt_recovery)
35-
if con.state_machine.current_state in ['acm', 'config']:
35+
if con.state_machine.current_state in ['acm', 'config','rules']:
3636
con.state_machine.go_to('enable',
3737
con.spawn,
3838
context=con.context,

src/unicon/plugins/iosxe/patterns.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def __init__(self):
2929
self.maintenance_mode_prompt = \
3030
r'^(.*?)(\(unlicensed\))?(WLC|Router|RouterRP|Switch|ios|switch|%N)([0-9])?(\(standby\))?(-stby)?(-standby)?(\(boot\))?\(maint-mode\)#[\s\x07]*$'
3131
self.press_enter = ReloadPatterns().press_enter
32-
self.config_prompt = r'^(.*)\((?!.*pki-hexmode).*(con|cfg|ipsec-profile|ca-trustpoint|ca-certificate-map|cs-server|ca-profile|gkm-local-server|cloud|host-list|config-gkm-group|gkm-sa-ipsec|gdoi-coop-ks-config|wsma|enforce-rule|DDNS)\S*\)#\s?$'
32+
self.config_prompt = r'^(.*)\((?!.*pki-hexmode).*(con|cfg|ipsec-profile|ca-trustpoint|ca-certificate-map|cs-server|ca-profile|gkm-local-server|cloud|host-list|config-gkm-group|gkm-sa-ipsec|gdoi-coop-ks-config|wsma|enforce-rule|DDNS|ca-trustpool)\S*\)#\s?$'
3333

3434

3535
self.config_pki_prompt = r'^(.*)\(config-pki-hexmode\)#\s?$'
@@ -42,6 +42,7 @@ def __init__(self):
4242
self.macro_prompt = r'^(.*?)(\{\.\.\}|then.else.fi)\s*>\s*$'
4343
self.unable_to_create = r'^(.*?)Unable to create.*$'
4444
self.acm_prompt = r'^(.*?)\(acm.*?\)#[\s\x07]*$'
45+
self.rules_prompt = r'^(.*?)\(rules.*?\)#[\s\x07]*$'
4546

4647

4748
class IosXEReloadPatterns(ReloadPatterns):

src/unicon/plugins/iosxe/service_implementation.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,30 @@ def truncate_trailing_prompt(self, con_state,
5656
self.utils = ConfigUtils()
5757

5858
def pre_service(self, *args, **kwargs):
59+
5960
self.acm_configlet = kwargs.pop('acm_configlet', None)
61+
self.rules = kwargs.pop('rules', False)
6062
self.prompt_recovery = kwargs.get('prompt_recovery', True)
6163

6264
if self.acm_configlet:
6365
self.connection.state_machine.go_to('acm', self.connection.spawn,context={'acm_configlet': self.acm_configlet})
6466
self.start_state = 'acm'
6567
self.end_state = 'acm'
68+
69+
elif self.rules:
70+
if self.connection.connected:
71+
self.connection.state_machine.go_to('rules', self.connection.spawn)
72+
self.start_state = 'rules'
73+
self.end_state = 'rules'
74+
6675
else:
6776
super().pre_service(*args, **kwargs)
6877

6978
def post_service(self, *args, **kwargs):
7079
if self.acm_configlet:
7180
self.connection.state_machine.go_to('enable', self.connection.spawn)
81+
elif self.rules:
82+
self.connection.state_machine.go_to('enable', self.connection.spawn)
7283
else:
7384
super().post_service(*args, **kwargs)
7485

@@ -115,18 +126,26 @@ def __init__(self, connection, context, **kwargs):
115126

116127
def pre_service(self, *args, **kwargs):
117128
self.acm_configlet = kwargs.pop('acm_configlet', None)
129+
self.rules = kwargs.pop('rules', False)
118130
self.prompt_recovery = kwargs.get('prompt_recovery', True)
119131

120132
if self.acm_configlet:
121133
self.connection.state_machine.go_to('acm', self.connection.spawn,context={'acm_configlet': self.acm_configlet})
122134
self.start_state = 'acm'
123135
self.end_state = 'acm'
136+
elif self.rules:
137+
if self.connection.connected:
138+
self.connection.state_machine.go_to('rules', self.connection.spawn)
139+
self.start_state = 'rules'
140+
self.end_state = 'rules'
124141
else:
125142
super().pre_service(*args, **kwargs)
126143

127144
def post_service(self, *args, **kwargs):
128145
if self.acm_configlet:
129146
self.connection.state_machine.go_to('enable', self.connection.spawn)
147+
elif self.rules:
148+
self.connection.state_machine.go_to('enable', self.connection.spawn)
130149
else:
131150
super().post_service(*args, **kwargs)
132151

0 commit comments

Comments
 (0)