def node_get_ii(node: InstanceNode) -> InstanceRoute: m = node ii_gen = InstanceRoute() try: while m: m_sn = m.schema_node m_sn_dp = m_sn.data_parent() if isinstance(m_sn, ListNode): if isinstance(m.value, ArrayValue): mn = MemberName( m_sn.qual_name[0], None if m_sn_dp and m_sn.ns == m_sn_dp.ns else m_sn.qual_name[1]) ii_gen.append(mn) else: kv = {} for qk in m_sn.keys: k = qk[0] k_ns = None if m_sn_dp and m_sn.ns == m_sn_dp.ns else qk[ 1] kv[(k, k_ns)] = m.value.get(k) ek = EntryKeys(kv) ii_gen.append(ek) elif isinstance(m_sn, ContainerNode): mn = MemberName( m_sn.qual_name[0], None if m_sn_dp and m_sn.ns == m_sn_dp.ns else m_sn.qual_name[1]) ii_gen.append(mn) m = m.up() except NonexistentInstance: pass ii_gen.reverse() return ii_gen
def create_node_rpc(self, root: InstanceNode, rpc: RpcInfo, value: Any) -> Tuple[InstanceNode, bool]: ii = self.parse_ii(rpc.path, rpc.path_format) # Get target member name input_member_keys = tuple(value.keys()) if len(input_member_keys) != 1: raise ValueError( "Received json object must contain exactly one member") input_member_name_fq = input_member_keys[0] try: input_member_ns, input_member_name = input_member_name_fq.split( ":", maxsplit=1) except ValueError: raise ValueError( "Input object name must me in fully-qualified format") input_member_value = value[input_member_name_fq] # Deny any changes of NACM data for non-privileged users nacm_changed = False if (len(ii) > 0) and (isinstance(ii[0], MemberName)): # Not getting root ns_first = ii[0].namespace if ns_first == "ietf-netconf-acm": nacm_changed = True if rpc.username not in CONFIG_NACM["ALLOWED_USERS"]: raise NacmForbiddenError( rpc.username + " not allowed to modify NACM data") else: # Editing root node if input_member_ns == "ietf-netconf-acm": nacm_changed = True if rpc.username not in CONFIG_NACM["ALLOWED_USERS"]: raise NacmForbiddenError( rpc.username + " not allowed to modify NACM data") # Evaluate NACM if self.nacm and not rpc.skip_nacm_check: nrpc = self.nacm.get_user_rules(rpc.username) if nrpc.check_data_node_permission( root, ii, Permission.NACM_ACCESS_CREATE) == Action.DENY: raise NacmForbiddenError() n = root.goto(ii) # Get target schema node sn = n.schema_node # type: InternalNode member_sn = sn.get_child(input_member_name, input_member_ns) if member_sn is None: raise ValueError("Received json object contains unknown member") # Check if target member already exists if sn.ns == member_sn.ns: try: existing_member = n[input_member_name] except NonexistentInstance: existing_member = None else: try: existing_member = n[input_member_name_fq] except NonexistentInstance: existing_member = None # Get query parameters insert = rpc.qs.get("insert", [None])[0] point = rpc.qs.get("point", [None])[0] if isinstance(member_sn, ListNode): # Append received node to list # Create list if necessary if existing_member is None: new_member_name = input_member_name if n.namespace == input_member_ns else input_member_name_fq existing_member = n.put_member(new_member_name, ArrayValue([])) # Get ListNode key names list_node_keys = member_sn.keys # Key names in the form [(key, ns), ] if insert == "first": # Optimization if len(existing_member.value) > 0: list_entry_first = existing_member[0] # type: ArrayEntry new_member = list_entry_first.insert_before( input_member_value, raw=True).up() else: new_member = existing_member.update([input_member_value], raw=True) elif (insert == "last") or (insert is None): # Optimization if len(existing_member.value) > 0: list_entry_last = existing_member[-1] # type: ArrayEntry new_member = list_entry_last.insert_after( input_member_value, raw=True).up() else: new_member = existing_member.update([input_member_value], raw=True) elif (insert == "before") and (point is not None): point_keys_val = point.split( "," ) # List key values passed in the "point" query argument if len(list_node_keys) != len(point_keys_val): raise ValueError( "Invalid number of keys passed in 'point' query: {} ({} expected)" .format(len(point_keys_val), len(list_node_keys))) entry_keys = dict( map(lambda i: (list_node_keys[i], point_keys_val[i]), range(len(list_node_keys)))) entry_sel = EntryKeys(entry_keys) point_list_entry = entry_sel.goto_step( existing_member) # type: ArrayEntry new_member = point_list_entry.insert_before(input_member_value, raw=True).up() elif (insert == "after") and (point is not None): point_keys_val = point.split( "," ) # List key values passed in the "point" query argument if len(list_node_keys) != len(point_keys_val): raise ValueError( "Invalid number of keys passed in 'point' query: {} ({} expected)" .format(len(point_keys_val), len(list_node_keys))) entry_keys = dict( map(lambda i: (list_node_keys[i], point_keys_val[i]), range(len(list_node_keys)))) entry_sel = EntryKeys(entry_keys) point_list_entry = entry_sel.goto_step( existing_member) # type: ArrayEntry new_member = point_list_entry.insert_after(input_member_value, raw=True).up() else: raise ValueError("Invalid 'insert'/'point' query values") elif isinstance(member_sn, LeafListNode): # Append received node to leaf list # Create leaf list if necessary if existing_member is None: new_member_name = input_member_name if n.namespace == input_member_ns else input_member_name_fq existing_member = n.put_member(new_member_name, ArrayValue([])) # Convert input data from List/Dict to ArrayValue/ObjectValue new_value_item = member_sn.entry_from_raw(input_member_value) if insert == "first": new_member = existing_member.update( ArrayValue([new_value_item] + existing_member.value)) elif (insert == "last") or (insert is None): new_member = existing_member.update( ArrayValue(existing_member.value + [new_value_item])) else: raise ValueError("Invalid 'insert' query value") else: # Create new container member if existing_member is None: # Create new node (object member) new_member_name = input_member_name if n.namespace == input_member_ns else input_member_name_fq new_member = n.put_member(new_member_name, input_member_value, raw=True) else: # Data node already exists raise InstanceAlreadyPresent( "Member \"{}\" already present in \"{}\"".format( input_member_name, ii)) return new_member.top(), nacm_changed