Search code examples
ietf-netmod-yang

why pyang does not throw error in this scenario


the following when condition is referring to a non existing node. I wonder why pyang does not throw error ? It does, if I use a wrong prefix though.

can you review the when conditions (embedded in the module) please.

is it allowed (in when expression) to refer to schema out of the augment itself ?

module mod-w-1 {
  namespace "http://example.org/tests/mod-w-1";
  prefix m1;

  container m1 {
    leaf b1 {
      type string;
    }
  }
}

module when-tests {
  namespace "http://example.org/tests/when-tests";
  prefix wt;

  import mod-w-1 {
    prefix m1;
  }

  augment "/m1:m1" {
       // when "/m1:m1/b3 = 'abc'";
       // there is no b3, so, should be invalid.

       // when "/m1:m1/b1 = 'abc'";
       // a payload or data situation that has m1/b1 != 'abc' will cause the 
       // data that fits this augment content will be invalid/rejected.
       /* for ex; 
          <m1>
            <b1>fff</b1>
            <x>sfsf</x>
            <conditional>
              <foo>dddd</foo>
            </conditional>  
          </m1>
          is invalid, hence, the <x> and <conditional> parts will be 
          rejected.
      */   
       leaf x {
         type string;
       }
       container conditional {
          leaf foo {
              type string;
          }
       }
    } 
}

Solution

  • That is because pyang does not validate semantics of XPath expressions at all, only their syntax - and a couple of additional checks, such as function and prefix usage. You will need another YANG compiler to validate those properly.

    def v_xpath(ctx, stmt):
        try:
            toks = xpath.tokens(stmt.arg)
            for (tokname, s) in toks:
                if tokname == 'name' or tokname == 'prefix-match':
                    i = s.find(':')
                    if i != -1:
                        prefix = s[:i]
                        prefix_to_module(stmt.i_module, prefix, stmt.pos,
                                         ctx.errors)
                elif tokname == 'literal':
                    # kind of hack to detect qnames, and mark the prefixes
                    # as being used in order to avoid warnings.
                    if s[0] == s[-1] and s[0] in ("'", '"'):
                        s = s[1:-1]
                        i = s.find(':')
                        # make sure there is just one : present
                        if i != -1 and s[i+1:].find(':') == -1:
                            prefix = s[:i]
                            # we don't want to report an error; just mark the
                            # prefix as being used.
                            my_errors = []
                            prefix_to_module(stmt.i_module, prefix, stmt.pos,
                                             my_errors)
                            for (pos, code, arg) in my_errors:
                                if code == 'PREFIX_NOT_DEFINED':
                                    err_add(ctx.errors, pos,
                                            'WPREFIX_NOT_DEFINED', arg)
                elif ctx.lax_xpath_checks == True:
                    pass
                elif tokname == 'variable':
                    err_add(ctx.errors, stmt.pos, 'XPATH_VARIABLE', s)
                elif tokname == 'function':
                    if not (s in xpath.core_functions or
                            s in yang_xpath_functions or
                            (stmt.i_module.i_version != '1' and
                             s in yang_1_1_xpath_functions) or
                            s in extra_xpath_functions):
                        err_add(ctx.errors, stmt.pos, 'XPATH_FUNCTION', s)
        except SyntaxError as e:
            err_add(ctx.errors, stmt.pos, 'XPATH_SYNTAX_ERROR', e)
    

    Line 1993 of statements.py.

    Note that an XPath expression referring to a non-existent node is technically not invalid, not from XPath specification perspective. It just means that an empty node set will be selected by the location path (and that your condition will be false forever).

    Yes, you can refer to nodes that are "above" the augment's target node or are its siblings - in fact, you always should when when statement is in play (it should not refer to any node made conditional by it).

    Also, you should never attempt to break "module confinement" with a non-prefixed node test (such as b3 and b1). The XPath expression is only able to see names that are defined in imports of the defining module and the defining module itself. For example, even if b3 is later augmented by some unknown third module, your condition would still evaluate to false. It is best to assume that non-prefixed names belong to the defining module's namespace.