summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorA. Wilcox <AWilcox@Wilcox-Tech.com>2020-09-15 16:56:18 -0500
committerA. Wilcox <AWilcox@Wilcox-Tech.com>2020-09-15 16:56:18 -0500
commit0c7c6b592df4c3d87be01f8f2cfc1d7ed669e403 (patch)
treea69bfe8b76305a96c582812603dd5ebb3fe9ae69
parentca203f339f392ec7590cd3fcf5ac7847ea3c1f28 (diff)
downloadnetconfapk-0c7c6b592df4c3d87be01f8f2cfc1d7ed669e403.tar.gz
netconfapk-0c7c6b592df4c3d87be01f8f2cfc1d7ed669e403.tar.bz2
netconfapk-0c7c6b592df4c3d87be01f8f2cfc1d7ed669e403.tar.xz
netconfapk-0c7c6b592df4c3d87be01f8f2cfc1d7ed669e403.zip
util: Add functions for handling leaf-list operations
-rw-r--r--ncserver/base/util.py97
1 files changed, 97 insertions, 0 deletions
diff --git a/ncserver/base/util.py b/ncserver/base/util.py
index f69c65b..5223d92 100644
--- a/ncserver/base/util.py
+++ b/ncserver/base/util.py
@@ -43,3 +43,100 @@ def node_operation(node, def_op='merge') -> str:
nc10 = '{urn:ietf:params:xml:ns:netconf:base:1.0}operation'
nc11 = '{urn:ietf:params:xml:ns:netconf:base:1.1}operation'
return node.attrib.get(nc11, node.attrib.get(nc10, def_op))
+
+
+def _index_for_list_op(the_list: list, operation: str, insert_value) -> int:
+ """Determine the index for a leaf-list insertion.
+
+ :param list the_list:
+ The Python list object that represents the leaf-list.
+
+ :param str operation:
+ The insertion mode: first, last, before, after.
+
+ :param insert_value:
+ The value to insert for modes before and after. MUST be specified.
+
+ :returns int:
+ The index in which to insert.
+ """
+ if operation == 'last':
+ return len(the_list)
+ if operation == 'first':
+ return 0
+ if operation == 'before':
+ return the_list.index(insert_value)
+ if operation == 'after':
+ return the_list.index(insert_value) + 1
+
+ return -1
+
+
+def handle_list_operation(rpc, the_list: list, node, operation: str) -> list:
+ """Perform a <edit-config/> operation on a leaf-list based on RFC 6020.
+
+ :param rpc:
+ The RPC <edit-config/> message.
+
+ :param list the_list:
+ The Python list object that represents the leaf-list.
+
+ :param node:
+ The XML node that represents the item being operated on.
+
+ :param str insert:
+ The insertion mode for non-deletion operation: first, last, before,
+ after. Defaults to 'last' if None.
+
+ :param insert_value:
+ The value to insert the new value before or after. Only used if
+ 'insert' is before or after.
+
+ :returns list:
+ The list with the value manipulated with the desired effect.
+ """
+ value = node.text
+
+ # RFC 6020 § 7.7.7
+ val_attr = '{urn:ietf:params:xml:ns:yang:1}value'
+ insert = node.attrib.get('{urn:ietf:params:xml:ns:yang:1}insert', 'last')
+ insert_value = node.attrib.get(val_attr, None)
+
+ if operation == 'create':
+ if value in the_list:
+ raise error.DataExistsAppError(rpc)
+ if insert is None:
+ insert = 'last'
+
+ if operation in ['merge', 'replace']:
+ # Need clarification about RFC § 7.7.7. This may be wrong.
+ # If so, change `return` to `insert = 'last'`, or move to function top.
+ if insert is None:
+ return the_list
+
+ # `insert` was specified, so we will move this item.
+ if value in the_list:
+ the_list.remove(value)
+
+ if operation in ['delete', 'remove']:
+ if value not in the_list:
+ if operation == 'delete':
+ raise error.DataMissingAppError(rpc)
+ return the_list # Job done.
+
+ the_list.remove(value)
+ return the_list
+
+ # Okay. We are performing an addition of some kind on this list.
+ if insert in ['before', 'after'] and (
+ insert_value is None or insert_value not in the_list):
+ raise error.BadAttributeAppError(rpc, node, val_attr)
+
+ index = _index_for_list_op(the_list, insert, insert_value)
+ if index == -1:
+ raise error.BadAttributeAppError(
+ rpc, node, '{urn:ietf:params:xml:ns:yang:1}insert'
+ )
+
+ the_list.insert(index, value)
+ return the_list