Using must condition under a leaf is causing internal error

  grouping sample_grouping_1 {
    description "sample";
    leaf sampleleaf_1 {
      type leafref {
        path "../../../h1/h2_list/h2_key";
      }
      mandatory true;
    }
  }

then under this other grouping

  grouping sample_grouping_2 {
    uses sample_grouping_1;
    leaf sample_leaf_2 {
      type int32 {
        range "1..9600";
      }
      must 'deref(current())../sampleleaf_1/one_attribute_under_h2key = "EXTERNAL"';
      default 30;
    }
  }

With this, I get internal error while I try to compile the yangs,
My question is , is the syntax I use legal in the first place, The deref comparison is being done across groupings, so should it involve additional syntax.

The path provided for the sample_leaf_1 is correct,so no issues there.

Thanks for the investment,
Arun kumar Bhattar

The XPath function deref() should be applied to a node that is either an instance-identifier or a leafref, I’m assuming you inteded to apply it to sampleleaf_1, but you applied it to current(). Moreover, I would say h2_key is the key leaf of your h2_list, hence the one_attribute_under_h2key is more likely a sibling of h2_key, not its child. So probably your must statement should look like

     must 'deref(../sampleleaf_1)/../one_attribute_under_h2key = "EXTERNAL"';

Note also that current() should not be needed in this context.

Hi @mvf,
Thank you for your pointing out my mistake.
I have made changes as mentioned above, and now I get this error:

error: The ‘must’ expression should have a tailf:dependency. If is doesn’t, it will be checked for every commit

I do not understand exactly what is causing this issue. Please recommend.
Thanks alot.

Have a look at the dependency extension and its description, either in tailf-common.yang or in tailf_yang_extensions man page in the documentation. Briefly, the message means that ConfD is not able to infer dependencies for the must statement and needs you to state them explicitly.

I was successfully able to fix the issue by adding a tailf:dependency. However, I would like to know if there is any way in which I could avoid importing the tailf-common.yang.

I am trying to look at possible ways to solving issue without importing the tailf-common.yang file

Sounds like you are looking for annotations - that’s the tool that lets you add tailf:... statements to a node without touching the original module. You write another YANG module (by convention it is named XXX-ann, i.e. if the main YANG file is my-module.yang, the annotation file is my-module-ann.yang - but it’s nothing more than a convention) that contains only statements tailf:annotate-module, tailf:annotate-statement, or tailf:annotate; usually the last one is more convenient, but since you are using groupings, maybe the first two are more handy. This file is then used when compiling my-module.yang with -a my-module-ann.yang - have a look at confdc man page.

There are some examples how those three statements should be used, read their description in tailf-common.yang or in the tailf_yang_extensions man page. Let me know if you can’t make them work.

I have added the tailf:dependency this way (in the annotation file)
tailf:annotate “/a:a1/b:vehicles/b:cars/b:car/b:engine” {
tailf:validate vp1
{
tailf:dependency ‘…/…/…/b:buses/b:bus/b:bus_engine’;
}
}

b:bus_engine is a leaf and the b:engine is a container
I am compiling the annotation file and the yang file together using --annotation file tag. However, I still get the “The ‘must’ expression should have a tailf:dependency. If is doesn’t, it will be checked for every commit” error

You need to annotate the must statement, so you have to use the combination of tailf:annotate-module and tailf:annotate-statement - the statement tailf:annotate can be used only to annotate data nodes, I believe. I did not notice this when writing the previous reply.

I have tried doing it the following way -->

tailf:annotate-module “module1”{
tailf:annotate-statement grouping [name = ‘grouping_inside_module1’]{
tailf:annotate-statement leaf[name=‘leaf_inside_the_above_grouping’] {
tailf:dependency ‘…/leaf_in_a_different_grouping_with_type_as_leafref’;
}
}
}

I see this error:

module1-ann.yang:86:34: error: unterminated statement for keyword “annotate-module”
module1-ann.yang:86:34: error: unterminated statement for keyword “annotate-module”
module1.yang:707: error: The ‘must’ expression should have a tailf:dependency. If is doesn’t, it will be checked for every commit.
module1.yang:707: error: The ‘must’ expression should have a tailf:dependency. If is doesn’t, it will be checked for every commit.
Generating .fxs file “module1-aug-npt.fxs”
module1.yang:707: error: The ‘must’ expression should have a tailf:dependency. If is doesn’t, it will be checked for every commit.
module1.yang:707: error: The ‘must’ expression should have a tailf:dependency. If is doesn’t, it will be checked for every commit.
module1-ann.yang:86:34: error: unterminated statement for keyword “annotate-module”
module1-ann.yang:86:34: error: unterminated statement for keyword “annotate-module”

Please help

I guess it should look something like this:

  tailf:annotate-module "module1" {
    tailf:annotate-statement grouping [name = 'grouping_inside_module1']{
      tailf:annotate-statement leaf[name='leaf_inside_the_above_grouping'] {
        tailf:annotate-statement must {
          tailf:dependency '../leaf_in_a_different_grouping_with_type_as_leafref';
        }
      }
    }
  }

Note one more annotate-statement for the must statement itself.

Also watch the whitespace - there mustn’t be any space between the statement name and the predicate, nor around the ‘=’ in the predicate, and you have both in your ‘grouping’ annotation - this is the reason for your “unterminated statement” errors. I.e. it should be

  tailf:annotate-module "module1" {
    tailf:annotate-statement grouping[name='grouping_inside_module1'] {
      tailf:annotate-statement leaf[name='leaf_inside_the_above_grouping'] {
        tailf:annotate-statement must {
          tailf:dependency '../leaf_in_a_different_grouping_with_type_as_leafref';
        }
      }
    }
  }

(A space before ‘{’ isn’t required, but improves readability IMHO.)

Edit: I guess it would be a good idea if you showed the relevant part of the module being annotated - for starters, it is “unusual” that you have to use tailf:dependency with a must expression, perhaps you have some unintentional problem with the syntax of it.

This is the module in the yang file →
grouping grouping_inside_module1 {
uses different_grouping;

            leaf leaf_inside_the_above_grouping {
                    type int32 {
            range "1..3600";
                    }
             must 'deref(../leaf_in_a_different_grouping_with_type_as_leafref)/../leaf_needed_to_be_compared = "EXTERNAL"'{
            //tailf:dependency '../leaf_in_a_different_grouping_with_type_as_leafref';

}

When I un-comment the tailf dependency, I get the desired behavior. I am trying to achieve the same behavior by annotating that particular leaf in the corresponding annotation file.

With the above comments, I to write the annotation file, but I get an internal error.

tailf:annotate-module “module1”{
tailf:annotate-statement grouping[name=‘grouping_inside_module1’]{
tailf:annotate-statement leaf[name=‘leaf_inside_the_above_grouping’] {
tailf:annotate-statement must {
tailf:dependency ‘…/leaf_in_a_different_grouping_with_type_as_leafref’;
}
}
}
}

OK, it seems the compiler can’t calculate the dependencies when deref() is used - i.e. you do
need a tailf:dependency statement.

Looks OK, except for the three leading dots in …/leaf_in_a_different_grouping_with_type_as_leafref, should of course be two - do you actually have three? When I try that, I get the expected “bad argument value” from the compiler, but with two dots it’s fine, no errors or warnings.

Exactly how do you run the compiler? And what version of ConfD are you using?

It is a correction, I have made a mistake while typing it here, it is actually two dots itself

I need a a tailf:dependency statement, otherwise I will see the error --> error: The ‘must’ expression should have a tailf:dependency. If is doesn’t, it will be checked for every commit.
I am using confdversion=6.4.

And I perform confd compilation by this way -->

confdc -c --annotate module1-ann.yang -o module1.fxs --verbose --fail-on-warnings -F module1.yang

I have tried doing this way -->

tailf:annotate-module “module1”{
tailf:annotate-statement grouping[name=‘grouping_inside_module1’]{
tailf:annotate-statement leaf[name=‘leaf_inside_the_above_grouping’] {
tailf:annotate-statement must"(…/leaf_in_a_different_grouping_with_type_as_leafref[key_under_different_grouping=current()]/…/leaf_needed_to_be_compared=‘EXTERNAL’)" {
tailf:dependency ‘…/leaf_in_a_different_grouping_with_type_as_leafref’;
}
}
}
}

I see this error -->

bad argument value “must”(…/leaf_in_a_different_grouping_with_type_as_leafref[key_under_different_grouping=current()]/…/leaf_needed_to_be_compared=‘EXTERNAL’)"": bad predicate

Agreed.

That can’t possibly work, since module1.yang is taken as an argument to -F. When I try it in ConfD-6.4:

$ confdc -c --annotate module1-ann.yang -o module1.fxs --verbose --fail-on-warnings -F module1.yang
confdc: --compile needs a file to compile
        Try 'confdc -h' for help and more information

If I remove the -F option, it works fine. If you want to tell the compiler that no features should be supported, you need to follow the instruction in the confdc man page:

   -Ffeatures, --feature features
       Indicates that support for the YANG features should be present in
       the fxs file.  features is a string on the form
       modulename:[feature(,feature)*]

I.e. to specify that none of the features in module1 should be supported, you need to use

confdc -c --annotate module1-ann.yang -o module1.fxs --verbose --fail-on-warnings -F module1: module1.yang

which also works fine for me with ConfD-6.4.

Don’t do that. In principle it is possible to give a predicate for the must annotation, but it has the same syntax as all the other predicates, no ‘"’ or ‘(’ but:

tailf:annotate-statement must[name='...the argument to must in the model...'] {

but getting the quoting right for '...the argument to must in the model...' is at best really hard, and often impossible due to limitations of XPath. There is absolutely no reason to try unless you have multiple must statements at the same “level” in the annotated module, and even then there is a simpler way to identify which of them you want to annotate.

Also, since what you had in that last tailf:annotate-statement must is nothing like what you showed for the actual must statement in the annotated module (more like what you had before the first correction that @mvf posted), it seems you keep changing things around and it is very difficult to understand what you actually have in your modules - and thus very difficult to help you.

I’ll post here what I actually have in the modules that compile fine for me in 6.4 - each module is preceded and followed by three “back-ticks” on a line of its own, to indicate pre-formatted text and thereby make the contents easy to read or copy, and I don’t type any of the contents, just copy and paste exactly what is in the modules, to avoid mistakes. It is mostly based on your original post, with the corrections from @mvf applied. Perhaps you can do the same - or compare these modules with what you have.

module1.yang:

module module1 {
  namespace urn:module1;
  prefix m;

  grouping sample_grouping_1 {
    description "sample";
    leaf sample_leaf_1 {
      type leafref {
        path "../../../h1/h2_list/h2_key";
      }
      mandatory true;
    }
  }

  grouping sample_grouping_2 {
    uses sample_grouping_1;
    leaf sample_leaf_2 {
      type int32 {
        range "1..9600";
      }
      must 'deref(../sample_leaf_1)/../one_attribute_under_h2key = "EXTERNAL"';
      default 30;
    }
  }

  container h1 {
    list h2_list {
      key h2_key;
      leaf h2_key {
        type string;
      }
      leaf one_attribute_under_h2key {
        type string;
      }
    }
  }
  container h2 {
    container h3 {
      uses sample_grouping_2;
    }
  }
}

module1-ann.yang:

module module1-ann {
  namespace urn:module1-ann;
  prefix ma;

  import tailf-common {
    prefix tailf;
  }

  tailf:annotate-module "module1" {
    tailf:annotate-statement grouping[name='sample_grouping_2'] {
      tailf:annotate-statement leaf[name='sample_leaf_2'] {
        tailf:annotate-statement must {
          tailf:dependency '../sample_leaf_1';
          tailf:dependency '../../../h1/h2_list/one_attribute_under_h2key';
        }
      }
    }
  }
}

(I added another dependency in module1-ann - while the compiler will be happy with any dependency, it is vitally important that the dependencies that you specify when the compiler can’t calculate them are correct and complete, and I don’t think that’s the case with the single dependency that you are trying to annotate.)