Example #1
0
    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
Example #2
0
    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