diff options
author | A. Wilcox <AWilcox@Wilcox-Tech.com> | 2020-09-15 16:56:18 -0500 |
---|---|---|
committer | A. Wilcox <AWilcox@Wilcox-Tech.com> | 2020-09-15 16:56:18 -0500 |
commit | 0c7c6b592df4c3d87be01f8f2cfc1d7ed669e403 (patch) | |
tree | a69bfe8b76305a96c582812603dd5ebb3fe9ae69 /ncserver | |
parent | ca203f339f392ec7590cd3fcf5ac7847ea3c1f28 (diff) | |
download | netconfapk-0c7c6b592df4c3d87be01f8f2cfc1d7ed669e403.tar.gz netconfapk-0c7c6b592df4c3d87be01f8f2cfc1d7ed669e403.tar.bz2 netconfapk-0c7c6b592df4c3d87be01f8f2cfc1d7ed669e403.tar.xz netconfapk-0c7c6b592df4c3d87be01f8f2cfc1d7ed669e403.zip |
util: Add functions for handling leaf-list operations
Diffstat (limited to 'ncserver')
-rw-r--r-- | ncserver/base/util.py | 97 |
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 |