Annotate multiple augmented statements

I’m trying to clean the source yang of any “tailf:” statements.
The problem I’m facing is that the source has multiple augmentations on the same “root node” only differing at “when conditions”.

the source example:

	augment /if:interfaces/if:interface {
		when "derived-from(./if:type, 'avift:l1-ethernet')";

		.
		.
		.
		.
	}
	augment /if:interfaces/if:interface {
		when "derived-from(./if:type, 'avift:l2-ethernet')";
		.
		.
		.
		.
		.
	}

the annotation file example:

   tailf:annotate-statement "augment[target-node='/if:interfaces/if:interface']" {
   .
   .
   .
   }
   tailf:annotate-statement "augment[target-node='/if:interfaces/if:interface']" {
   .
   .
   .
   }

The confdc tells me that
error: No container statements with the given argument is found.
error: No leaf statements with the given argument is found.
error: No container statements with the given argument is found.
error: No container statements with the given argument is found.

These are all from the second annotation. If I comment out the first pair of source/annotation the yang builds successfully.
Putting both under the same annotate-statement does not help.

How do I solve this one please?
BR Jaka

Here’s an example:

module my-interfaces-ann {
  namespace "urn:dummy";
  prefix dummy;

  import ietf-interfaces {
    prefix if;
  }

  import tailf-common {
    prefix tailf;
  }

  tailf:annotate-module "my-interfaces" {
    tailf:annotate-statement augment[name='/if:interfaces/if:interface'] {
      tailf:annotate-statement leaf[name='my-leaf'] {
        tailf:info "test";
      }
    }
  }
}

@cohult, I believe @jaka already has that part covered (creative use of “target-node” instead of “name” btw:-) - the problem is that @jaka is trying to annotate two (or maybe even more…) different augment-statements, that have the same target-node argument. I.e. there is no way to differentiate between them via an “equality predicate” using the augment argument, and each tailf:annotate-statement at a given level is interpreted independent from the others, thus they will all match the first augment-statement.

@jaka, it seems from the confdc errors that you get that you are annotating schema nodes (container, leaf, etc), and then I would suggest that you use tailf:annotate instead of tailf:annotate-statement in this case, it is really the clearest/cleanest solution. However tailf:annotate can’t annotate statements that don’t define schema nodes, for that you need to use tailf:annotate-statement. The trick then is to be even more creative with the “XPath-like expression”, and guess that you can use a different predicate (even though it isn’t actually documented), in particular a “position predicate”. I.e. tailf:annotate-statement augment[1] identifies the first augment statement in the module being annotated, tailf:annotate-statement augment[2] the second one, and so on.

This is obviously pretty tedious to use, and error-prone with respect to changes in the annotated module (but hopefully the substatements will generate errors like the ones you got in case the augment statements are moved around or added/deleted) - which is why I recommend that you use tailf:annotate instead if at all possible.

1 Like

Thanks for catching my misunderstanding @per. Another attempt at examples of the two options described above.

Example YANG:

module my-interfaces {

  namespace "http://tail-f.com/ns/example/my-interfaces";
  prefix myif;

  import ietf-interfaces {
    prefix if;
  }

  leaf test { type int8; }
  
  augment "/if:interfaces/if:interface" {
    when "/myif:test = 0";
    leaf my-leaf1 { type int8; }
  }

  augment "/if:interfaces/if:interface" {
    when "/myif:test = 1";
    leaf my-leaf2 { type int8; }
  }
}

taif:annotate example:

module my-interfaces-ann {
  namespace "urn:dummy";
  prefix dummy;

  import ietf-interfaces {
    prefix if;
  }

  import my-interfaces {
    prefix myif;
  }

  import tailf-common {
    prefix tailf;
  }
  
  tailf:annotate "/if:interfaces/if:interface/myif:my-leaf1" {
    tailf:info "test";
  }

  tailf:annotate "/if:interfaces/if:interface/myif:my-leaf2" {
    tailf:info "test2";
  }
}

“position predicate” example:

module my-interfaces-ann {
  namespace "urn:dummy";
  prefix dummy;

  import ietf-interfaces {
    prefix if;
  }

  import tailf-common {
    prefix tailf;
  }

  tailf:annotate-module "my-interfaces" {
    tailf:annotate-statement augment[1] {
      tailf:annotate-statement leaf[name='my-leaf1'] {
        tailf:info "test";
      }
    }
  }
  
  tailf:annotate-module "my-interfaces" {
    tailf:annotate-statement augment[2] {
      tailf:annotate-statement leaf[name='my-leaf2'] {
        tailf:info "test2";
      }
    }
  }
}
1 Like

Thanks for writing the examples that I was too lazy to do:-) @cohult. I’ll make amends by showing more “compact” ways to write the annotations - whether they’re better I can’t say, a matter of taste perhaps.

taif:annotate example:

  tailf:annotate /if:interfaces/if:interface {
    tailf:annotate myif:my-leaf1 {
      tailf:info "test";
    }
    tailf:annotate myif:my-leaf2 {
      tailf:info "test2";
    }
  }

“position predicate” example:

  tailf:annotate-module my-interfaces {
    tailf:annotate-statement augment[1] {
      tailf:annotate-statement leaf[name='my-leaf1'] {
        tailf:info "test";
      }
    }
    tailf:annotate-statement augment[2] {
      tailf:annotate-statement leaf[name='my-leaf2'] {
        tailf:info "test2";
      }
    }
  }