Subject: [netmod] Resolving schema node identifier

From: Michal Vaško <[email-masked]>
Date: Tue, 14 Dec 2021 10:22:59 +0100

Hello,

I would like to get some input for a use-case I came across, which to me does not seem to have any consistent rules that can be applied.

module mod_b {
    namespace "x:example:mod_b";
    prefix "mb";

    grouping mylist_wrapper {
        list mylist {
            key "name";
            unique "value";
            leaf name {
                type string;
            }
            leaf value {
                type uint32;
            }
        }
    }

    list mylist2 {
        key "a";
        leaf a {
            type string;
        }
        leaf b {
            type string;
        }
    }
}

module mod_a {
    namespace "x:example:mod_a";
    prefix "ma";

    import mod_b { prefix "mb"; }

    container root {
        uses mb:mylist_wrapper;
    }

    augment /mb:mylist2 {
        leaf c {
            type string;
        }
    }

    deviation /mb:mylist2 {
        deviate add {
            unique "mb:b c";
        }
    }
}

The focus is on the "unique" statements and how to resolve non-prefixed identifiers. RFC 7950 says that the argument is a "list of schema node identifiers"[1], which use "current module" for non-prefixed identifiers[2]. I have asked on this mailing list a few years back what current module means and the answer I got was the module where the statement is defined.

So let's get to the examples. As they are written, the unique in "mylist" should be wrong because the node "value" belongs to the module "mod_a" when the grouping is instantiated there, but unique is defined in the module "mod_b".

But even if we use the other understanding of current module and interpret is as the module of the context node of the statement (corresponds to the "current()" XPath function), then the other "unique" in the deviation cannot be resolved. It is referencing node "c", which belongs to the module "mod_a" (added by an augment) but the current module would then be "mod_b".

To summarize, if strictly following the specs, the "unique" in the "mylist" should probably reference "value" with a prefix, but that is not possible because "mod_a" is not even imported and it generally does not make sense. But then I cannot think of any consistent rule to successfully resolve both "unique" statements in this example. Can anyone help me with this, please?

Finally, I am asking because I am trying to implement this correctly in yanglint. I have also tried to test these examples with pyang, which, however, seems to not have any consistent rules applied because it loads these examples without warnings. No warnings are printed even if the "unique" in the deviation is changed to "b c", which is definitely wrong since node "b" belongs to "mod_b" and node "c" belongs to "mod_a".

Thanks,
Michal

[1] https://datatracker.ietf.org/doc/html/rfc7950#section-7.8.3
[2] https://datatracker.ietf.org/doc/html/rfc7950#section-6.5

---

From: Martin Björklund <[email-masked]>
Date: Tue, 14 Dec 2021 11:27:12 +0100 (CET)

Hi,

Michal Vaško <[email-masked]> wrote:
> Hello,
> 
> I would like to get some input for a use-case I came across, which to
> me does not seem to have any consistent rules that can be applied.
> 
> module mod_b {
> The focus is on the "unique" statements and how to resolve
> non-prefixed identifiers. RFC 7950 says that the argument is a "list
> of schema node identifiers"[1], which use "current module" for
> non-prefixed identifiers[2]. I have asked on this mailing list a few
> years back what current module means and the answer I got was the
> module where the statement is defined.
> 
> So let's get to the examples. As they are written, the unique in
> "mylist" should be wrong because the node "value" belongs to the
> module "mod_a" when the grouping is instantiated there, but unique is
> defined in the module "mod_b".
> 
> But even if we use the other understanding of current module and
> interpret is as the module of the context node of the statement
> (corresponds to the "current()" XPath function), then the other
> "unique" in the deviation cannot be resolved. It is referencing node
> "c", which belongs to the module "mod_a" (added by an augment) but the
> current module would then be "mod_b".
> 
> To summarize, if strictly following the specs, the "unique" in the
> "mylist" should probably reference "value" with a prefix, but that is
> not possible because "mod_a" is not even imported and it generally
> does not make sense. But then I cannot think of any consistent rule to
> successfully resolve both "unique" statements in this example. Can
> anyone help me with this, please?

Compare with this:

             must "value > 42";
             leaf name {
                 type string;
             }
             leaf value {
                 type uint32;
             }
         }
     }

I think the rules for the prefixes in "unique" should be the same as
for "must".  So I think that the correct syntax is to not use any
prefix in "unique".

And the deviation that adds a unique statement look correct.

/martin

> Finally, I am asking because I am trying to implement this correctly
> in yanglint. I have also tried to test these examples with pyang,
> which, however, seems to not have any consistent rules applied because
> it loads these examples without warnings. No warnings are printed even
> if the "unique" in the deviation is changed to "b c", which is
> definitely wrong since node "b" belongs to "mod_b" and node "c"
> belongs to "mod_a".
> 
> Thanks,
> Michal
> 
> _______________________________________________
> netmod mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/netmod

---

From: Michal Vaško <[email-masked]>
Date: Tue, 14 Dec 2021 11:32:55 +0100

> > > I would like to get some input for a use-case I came across, which to> me does not seem to have any consistent rules that can be applied.
> > > module mod_b {
> > module "mod_a" when the grouping is instantiated there, but unique is> defined in the module "mod_b".
> > "mylist" should probably reference "value" with a prefix, but that is> not possible because "mod_a" is not even imported and it generally

Thanks for the reply but I do not think you have answered my question. Please formulate a formal rule how to assign modules to non-prefixed identifiers, whether they be in "unique", "must", or any other statement with identifiers. That is what I need to implement it properly and I am simply not able to come up with any that would be consistent and compliant with the specification.

---

From: Martin Björklund <[email-masked]>
Date: Tue, 14 Dec 2021 11:39:45 +0100 (CET)

Michal Vaško <[email-masked]> wrote:
> > > > I would like to get some input for a use-case I came across, which to>
> > > "mylist" should probably reference "value" with a prefix, but that is>
> Thanks for the reply but I do not think you have answered my
> question. Please formulate a formal rule how to assign modules to
> non-prefixed identifiers, whether they be in "unique", "must", or any
> other statement with identifiers. That is what I need to implement it
> properly and I am simply not able to come up with any that would be
> consistent and compliant with the specification.

Interpret the unique argument the same way as an XPath expression, and
apply (from 6.4.1):

   o  Names without a namespace prefix belong to the same namespace as
      the identifier of the current node.  Inside a grouping, that
      namespace is affected by where the grouping is used

So "value" in the unique statement will refer to "value" in "mod_a"
when the grouping is used in "mod_a".

/martin

---

From: Michal Vaško <[email-masked]>
Date: Tue, 14 Dec 2021 11:58:32 +0100

> > > > years back what current module means and the answer I got was the> > > module where the statement is defined.
> > non-prefixed identifiers, whether they be in "unique", "must", or any> other statement with identifiers. That is what I need to implement it> properly and I am simply not able to come up with any that would be

I see. Okay, this should be possible to implement, thanks.

> > > > in yanglint. I have also tried to test these examples with pyang,> > > which, however, seems to not have any consistent rules applied because
> > > > > [1] https://datatracker.ietf.org/doc/html/rfc7950#section-7.8.3> > > [2] https://datatracker.ietf.org/doc/html/rfc7950#section-6.5

---

From: Michal Vaško <[email-masked]>
Date: Tue, 14 Dec 2021 12:03:09 +0100

> I see. Okay, this should be possible to implement, thanks.

I was too hasty with the reply, this is not working because of the "unique" in the deviation I have in the example. What is the "current node" in that case? I suppose that can only be "mylist2", so the namespace will be that of "mod_b". But this is wrong, the "c" node belongs to "mod_a", so the "unique" in the deviation would be wrong.

---

From: Ladislav Lhotka <[email-masked]>
Date: Tue, 14 Dec 2021 12:42:39 +0100

> I was too hasty with the reply, this is not working because of the "unique" in the deviation I have in the example. What is the "current node" in that case? I suppose that can only be "mylist2", so…

Yes, this is unclear. I guess the only chance is to define the current 
node to be the (anonymous) root of the module "mod_a". A similar 
situation can happen inside a refine statement.

Lada

-- 
Ladislav Lhotka
Head, CZ.NIC Labs
PGP Key ID: 0xB8F92B08A9F76C67

---

From: Martin Björklund <[email-masked]>
Date: Tue, 14 Dec 2021 13:01:13 +0100 (CET)

Michal Vaško <[email-masked]> wrote:
> > > > > > years back what current module means and the answer I got was the> >
> > > > > > module "mod_a" when the grouping is instantiated there, but unique
> > > > > > is>
> > > > non-prefixed identifiers, whether they be in "unique", "must", or any>
> > > > other statement with identifiers. That is what I need to implement it>
> I was too hasty with the reply, this is not working because of the
> "unique" in the deviation I have in the example. What is the "current
> node" in that case? I suppose that can only be "mylist2", so the
> namespace will be that of "mod_b". But this is wrong, the "c" node
> belongs to "mod_a", so the "unique" in the deviation would be wrong.

Right; I was thinking that since "c" didn't have a prefix, it would
belong to "mod_a", and thus work as expected.

I think it is ok to solve this by requiring a prefix in this case.

/martin

> > > > > > in yanglint. I have also tried to test these examples with pyang,> >
> > > > > > > [1] https://datatracker.ietf.org/doc/html/rfc7950#section-7.8.3> >

---

From: Michal Vaško <[email-masked]>
Date: Tue, 14 Dec 2021 13:23:29 +0100

> > "unique" in the deviation I have in the example. What is the "current> node" in that case? I suppose that can only be "mylist2", so the

What you are saying is that you would be fine with the deviation not working with no prefix in the example and stick to the rule of using the current (context) node to get modules for non-prefixed identifiers?

@Lada You seem to suggest some special handling of paths in deviations (or what exactly)?

Neither really seem like a proper solution and, more importantly, interpreting "unique" paths (non-prefixed identifiers) according to XPath contradicts what I was told those few years back (I will try to find the mailing list communication if necessary), which is that for "schema node identifiers" the current module is the module where the statements are "physically" written, not that of the current node.

We keep hitting these problems because the use-cases vary greatly and the most complex ones were probably not anticipated when writing the specs. Still, the code must handle all the use-cases somehow and we have huge problems with that.

I would appreciate any exact rules that we can agree on.

Michal

---

From: Ladislav Lhotka <[email-masked]>
Date: Tue, 14 Dec 2021 14:04:42 +0100

> @Lada You seem to suggest some special handling of paths in deviations (or what exactly)?

Not really. If we wanted to extend the rule from sec. 6.4.1 that Martin cited to deviations, the only candidate for the "current node" is the root node.

On the other hand, sec. 6.4.1 is about XPath context, and the argument of "unique" contains schema node identifiers, i.e. NOT XPath.

> I would appreciate any exact rules that we can agree on.

The existing rules in RFC 7950 seem unclear/contradictory.

This is in sec. 7.12 on "grouping":

   Identifiers appearing inside the grouping are resolved relative to
   the scope in which the grouping is defined, not where it is used.
   Prefix mappings, type names, grouping names, and extension usage
   are evaluated in the hierarchy where the "grouping" statement
   appears.

And this is then in sec. 7.13 on "uses":

   The identifiers defined in the grouping are not bound to a namespace
   until the contents of the grouping are added to the schema tree via a
   "uses" statement that does not appear inside a "grouping" statement,
   at which point they are bound to the namespace of the current module.

Lada

---

From: Michal Vaško <[email-masked]>
Date: Tue, 14 Dec 2021 14:49:35 +0100

>    at which point they are bound to the namespace of the current module.

I always understood this in the way that all the explicitly mentioned statements (prefix mappings, type names, grouping names, and extension usage) are evaluated in the context of the grouping whereas anything else in the context of where the grouping is used. But it is definitely left for interpretation what includes "prefix mappings", I assumed the "schema node identifiers" that we have talked about, which are the arguments for "unique", "deviation", "augment" and so on. I also assumed it does not include XPath expressions since they have their own rules (arguments of statements "path" in leafref, "must", and "when").

But these section are definitely also relevant to the original problem.

Michal

---

From: Robert Varga <[email-masked]>
Date: Wed, 15 Dec 2021 17:25:06 +0100

>>>>>>>> Michal Vaško <[email-masked]> wrote:

[snip]

>>>>>>>>>>      import mod_b { prefix "mb"; }

[snip]

>     at which point they are bound to the namespace of the current module.

Just my .02EUR, in OpenDaylight we deal with this particular case in two 
steps:

1. the argument to unique is interpreted in scope of mod_a, hence "mb:b 
c" interprets the same as "mb:b ma:c", just as it would in any other 
declaration site

2. in the particular case of "deviate add", the statement is then copied 
verbatim to deviation target site

i.e. this works similar to how an augment would work -- and hence the 
quoted example works as one would expect from just a cursory glance at 
the model without giving it a second thought :)

Regards,
Robert

---

From: Michal Vaško <[email-masked]>
Date: Thu, 16 Dec 2021 12:27:26 +0100

> the model without giving it a second thought :)

Thanks, we will have to come up with our own solution as well. If I understood properly, you are technically adding the prefix when it is missing. That should be fine for "unique" but generally impossible to do for "must", for example. We have tried similar solutions but were not reliable enough and it seems there is no reliable solution even in theory based on this discussion, unfortunately.

Regards,
Michal

---

From: Robert Varga <[email-masked]>
Date: Thu, 16 Dec 2021 14:30:14 +0100

[snip]

> Thanks, we will have to come up with our own solution as well. If I understood properly, you are technically adding the prefix when it is missing. That should be fine for "unique" but generally imp…

That's true, but then 'must' takes an XPath, and the rules for handling 
that are unambiguous (as per section 6.4.1). In this particular case:

- unprefixed names would propagate to the deviated list unprefixed would 
be bound to the list's namespace
- prefixed names would be bound at the declaration site, i.e. under 
deviate, and would be propagated as-is to the deviated list

Regards,
Robert