Skip to content

Commit 26a94a6

Browse files
avazquezrdrjarry
authored andcommitted
changes: optionally include values in ChangeDeleted
Allows the user to choose whether to retrieve the values of nodes deleted in ChangeDeleted when generating the subscription (by default, False). This now also includes List and Container nodes. Signed-off-by: Adrián Vázquez <[email protected]>
1 parent 99e4f3f commit 26a94a6

File tree

4 files changed

+105
-5
lines changed

4 files changed

+105
-5
lines changed

sysrepo/change.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ def parse(
3131
prev_list: str,
3232
prev_dflt: bool,
3333
include_implicit_defaults: bool = True,
34+
include_deleted_values: bool = False,
3435
) -> "Change":
3536
"""
3637
Parse an operation code and values from libsysrepo.so and return a Change
@@ -64,6 +65,8 @@ def parse(
6465
Previous value default flag, depends on the operation.
6566
:arg include_implicit_defaults:
6667
Include implicit default values into the data dictionaries.
68+
:arg include_deleted_values:
69+
Include deleted nodes values.
6770
"""
6871
if operation == lib.SR_OP_CREATED:
6972
if not node.should_print(
@@ -83,8 +86,8 @@ def parse(
8386
prev_dflt=prev_dflt,
8487
)
8588
if operation == lib.SR_OP_DELETED:
86-
if isinstance(node, (libyang.DLeaf, libyang.DLeafList)):
87-
value = node.value()
89+
if include_deleted_values:
90+
value = _node_value(node, include_implicit_defaults)
8891
else:
8992
value = None
9093
return ChangeDeleted(node.path(), value)

sysrepo/session.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ def subscribe_module_change(
293293
private_data: Any = None,
294294
asyncio_register: bool = False,
295295
include_implicit_defaults: bool = True,
296+
include_deleted_values: bool = False,
296297
extra_info: bool = False,
297298
) -> None:
298299
"""
@@ -329,6 +330,8 @@ def subscribe_module_change(
329330
monitored read file descriptors. Implies `no_thread=True`.
330331
:arg include_implicit_defaults:
331332
Include implicit default nodes in changes.
333+
:arg include_deleted_values:
334+
Include deleted nodes values in changes.
332335
:arg extra_info:
333336
When True, the given callback is called with extra keyword arguments
334337
containing extra information of the sysrepo session that gave origin to the
@@ -343,6 +346,7 @@ def subscribe_module_change(
343346
private_data,
344347
asyncio_register=asyncio_register,
345348
include_implicit_defaults=include_implicit_defaults,
349+
include_deleted_values=include_deleted_values,
346350
extra_info=extra_info,
347351
)
348352
sub_p = ffi.new("sr_subscription_ctx_t **")
@@ -732,7 +736,10 @@ def subscribe_notification(
732736

733737
# begin: changes
734738
def get_changes(
735-
self, xpath: str, include_implicit_defaults: bool = True
739+
self,
740+
xpath: str,
741+
include_implicit_defaults: bool = True,
742+
include_deleted_values: bool = False,
736743
) -> Iterator[Change]:
737744
"""
738745
Return an iterator that will yield all pending changes in the current session.
@@ -743,6 +750,8 @@ def get_changes(
743750
appended to the XPath.
744751
:arg include_implicit_defaults:
745752
Include implicit default nodes.
753+
:arg include_deleted_values:
754+
Include deleted node values into the returned Change objects.
746755
747756
:returns:
748757
An iterator that will yield `sysrepo.Change` objects.
@@ -778,6 +787,7 @@ def get_changes(
778787
prev_list=c2str(prev_list_p[0]),
779788
prev_dflt=bool(prev_dflt_p[0]),
780789
include_implicit_defaults=include_implicit_defaults,
790+
include_deleted_values=include_deleted_values,
781791
)
782792
except Change.Skip:
783793
pass

sysrepo/subscription.py

+7
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def __init__(
3333
asyncio_register: bool = False,
3434
strict: bool = False,
3535
include_implicit_defaults: bool = True,
36+
include_deleted_values: bool = False,
3637
extra_info: bool = False,
3738
):
3839
"""
@@ -50,6 +51,9 @@ def __init__(
5051
:arg include_implicit_defaults:
5152
If True, include implicit default nodes into Change objects passed to module
5253
change callbacks and into input parameters passed to RPC/action callbacks.
54+
:arg include_deleted_values:
55+
If True, include the complete deleted node values into Change objects passed
56+
to module change callbacks.
5357
:arg extra_info:
5458
When True, the given callback is called with extra keyword arguments
5559
containing extra information of the sysrepo session that gave origin to the
@@ -64,6 +68,7 @@ def __init__(
6468
self.asyncio_register = asyncio_register
6569
self.strict = strict
6670
self.include_implicit_defaults = include_implicit_defaults
71+
self.include_deleted_values = include_deleted_values
6772
self.extra_info = extra_info
6873
if asyncio_register:
6974
self.loop = asyncio.get_event_loop()
@@ -242,6 +247,7 @@ def module_change_callback(session, sub_id, module, xpath, event, req_id, priv):
242247
session.get_changes(
243248
root_xpath + "//.",
244249
include_implicit_defaults=subscription.include_implicit_defaults,
250+
include_deleted_values=subscription.include_deleted_values,
245251
)
246252
)
247253
task = subscription.loop.create_task(
@@ -270,6 +276,7 @@ def module_change_callback(session, sub_id, module, xpath, event, req_id, priv):
270276
session.get_changes(
271277
root_xpath + "//.",
272278
include_implicit_defaults=subscription.include_implicit_defaults,
279+
include_deleted_values=subscription.include_deleted_values,
273280
)
274281
)
275282
callback(event_name, req_id, changes, private_data, **extra_info)

tests/test_subs_module_change.py

+82-2
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,11 @@ def module_change_cb(event, req_id, changes, private_data):
111111
),
112112
sysrepo.ChangeDeleted(
113113
"/sysrepo-example:conf/network/interface[name='eth0']/name",
114-
"eth0",
114+
None,
115115
),
116116
sysrepo.ChangeDeleted(
117117
"/sysrepo-example:conf/network/interface[name='eth0']/up",
118-
True,
118+
None,
119119
),
120120
sysrepo.ChangeCreated(
121121
"/sysrepo-example:conf/network/interface[name='eth2']",
@@ -195,6 +195,86 @@ def module_change_cb(event, req_id, changes, private_data):
195195
ch_sess.replace_config(sent_config, "sysrepo-example", strict=True)
196196
self.assertEqual(current_config, sent_config)
197197

198+
def test_module_change_sub_with_deleted_values(self):
199+
priv = object()
200+
current_config = {}
201+
expected_changes = []
202+
203+
def module_change_cb(event, req_id, changes, private_data):
204+
self.assertIn(event, ("change", "done", "abort"))
205+
self.assertIs(private_data, priv)
206+
if event in ("change", "done"):
207+
self.assertEqual(changes, expected_changes)
208+
if event == "done":
209+
sysrepo.update_config_cache(current_config, changes)
210+
211+
self.sess.subscribe_module_change(
212+
"sysrepo-example",
213+
"/sysrepo-example:conf",
214+
module_change_cb,
215+
private_data=priv,
216+
include_deleted_values=True,
217+
)
218+
219+
with self.conn.start_session("running") as ch_sess:
220+
# 1.
221+
sent_config = {
222+
"conf": {
223+
"system": {"hostname": "bar"},
224+
"network": {"interface": [{"name": "eth0", "up": True}]},
225+
}
226+
}
227+
expected_changes = [
228+
sysrepo.ChangeCreated("/sysrepo-example:conf/system/hostname", "bar"),
229+
sysrepo.ChangeCreated(
230+
"/sysrepo-example:conf/network/interface[name='eth0']",
231+
{"name": "eth0", "up": True},
232+
after="",
233+
),
234+
sysrepo.ChangeCreated(
235+
"/sysrepo-example:conf/network/interface[name='eth0']/name", "eth0"
236+
),
237+
sysrepo.ChangeCreated(
238+
"/sysrepo-example:conf/network/interface[name='eth0']/up", True
239+
),
240+
]
241+
ch_sess.replace_config(sent_config, "sysrepo-example", strict=True)
242+
self.assertEqual(current_config, sent_config)
243+
# 2.
244+
sent_config = {
245+
"conf": {
246+
"system": {"hostname": "bar"},
247+
"network": {"interface": [{"name": "eth2", "up": False}]},
248+
}
249+
}
250+
expected_changes = [
251+
sysrepo.ChangeDeleted(
252+
"/sysrepo-example:conf/network/interface[name='eth0']",
253+
{"name": "eth0", "up": True},
254+
),
255+
sysrepo.ChangeDeleted(
256+
"/sysrepo-example:conf/network/interface[name='eth0']/name",
257+
"eth0",
258+
),
259+
sysrepo.ChangeDeleted(
260+
"/sysrepo-example:conf/network/interface[name='eth0']/up",
261+
True,
262+
),
263+
sysrepo.ChangeCreated(
264+
"/sysrepo-example:conf/network/interface[name='eth2']",
265+
{"name": "eth2", "up": False},
266+
after="",
267+
),
268+
sysrepo.ChangeCreated(
269+
"/sysrepo-example:conf/network/interface[name='eth2']/name", "eth2"
270+
),
271+
sysrepo.ChangeCreated(
272+
"/sysrepo-example:conf/network/interface[name='eth2']/up", False
273+
),
274+
]
275+
ch_sess.replace_config(sent_config, "sysrepo-example", strict=True)
276+
self.assertEqual(current_config, sent_config)
277+
198278
def test_module_change_sub_with_extra_info(self):
199279
priv = object()
200280
calls = []

0 commit comments

Comments
 (0)