Conditional assignment of default values in yang - ietf-netmod-yang

I have two properties in a model:
leaf protocol,
leaf port.
I want to specify that:
if protocol = 'ssh' then default port value is 22,
if protocol = 'http' then default port value is 80,
etc.
How do I express this in yang ?

There are no conditional default values in YANG - you need two default statements for two defaults with different values, and a single leaf may only have one default substatement. You can work around this, however. Perhaps by using a presence container instead of your protocol leaf:
module conditional-default {
namespace "http://example.com/conditional-default";
prefix "excd";
grouping common {
leaf port {
type int32;
}
}
container config {
container ssh {
presence "If this container is present, ssh is configured.";
uses common {
refine port {
default 22;
}
}
}
container http {
presence "If this container is present, http is configured.";
uses common {
refine port {
default 80;
}
}
}
}
}
From RFC6020, 7.5.5.:
The "presence" statement assigns a meaning to the presence of a
container in the data tree. It takes as an argument a string that
contains a textual description of what the node's presence means.

Related

Is it possible to use two When statements in a Yang model

Trying to use one Yang leaf with two different if-types depending on the value given.
Currently have:
leaf interface_number {
when "boolean(string(/payload/interface_type) != 'ae')";
type isyt:interface_number_value;
when "boolean(string(/payload/interface_type) == 'ae')";
type isyt:interface_lag_value;
description
"Interface Number. Example value: 1/1/1 or 11 for LAG";
mandatory "true";
}
I have also tried:
leaf interface_number {
when "boolean(string(/payload/interface_type) != 'ae')" {
type isyt:interface_number_value;
}
when "boolean(string(/payload/interface_type) == 'ae')" {
type isyt:interface_lag_value;
}
description
"Interface Number. Example value: 1/1/1 or 11 for LAG";
mandatory "true";
}
Yang seems to accept the first when they errors on the second when statements' boolean.
Is this even possible? or is there a better method to use for this.
That's not how the YANG syntax works; the type statement cannot be conditional upon the when. The when affects the whole enclosing node, so if it evaluates to false, your interface_number would not be valid at all.
What you can do here is to create a choice whose case statements are when-conditional depending on the type of the ../interface_type leaf. This will need a different name for each of the leaf that you define within these case statements.

alternative way to use boolean container

container first{
container second{
type boolean;
}
}
how can i do something like this.(My error:i can't boolean a container/error: unexpected keyword "type") I don't want to use leaf. Is there an alternative ?
As per RFC 6020. For storing single data we have to use leaf. Using containers to store boolean data, I don't think would be possible.
As per RFC6020 section 7.5.1, Containers are used to organize the hierarchy of data nodes, and those whose presence in the configuration has an explicit meaning.It means we can't use container to store the data.
If you don't want to use boolean then you can try to use "enum" like this:
leaf myenum {
type enumeration {
enum zero {
value 0;
}
enum one {
value 1;
}
}
}
.

How to augment list from one module to another and add leafs YANG

Suppose I have two modules, I would like to extend one list with new leafs.
module A {
list deviceList {
key name;
leaf name{
}
leaf hostname{
}
}
}
and I would like to augment it to another leaf
module B {
list generalInfo{
key customerName;
leaf customerName{
type string;
}
augment moduleA:deviceList {
leaf ipAddress{
}
}
}
I have done it using grouping and container and list inside but this completely changes our existing structure, I would like to ommit container and grouping if thats possible.
It seems that you want to reuse a part of the schema definition, put it in another place in the schema tree and add a node to it.
You cannot do it the way you tried because the augment statement can appear only on the root level or in the uses statement.
You can do that only with a grouping but you can omit the container. Refactor A: define a grouping that's a list. Refer to it in B and augment it.
module A {
grouping devices {
list deviceList {
key name;
leaf name{
}
leaf hostname{
}
}
}
uses devices;
}
module B {
list generalInfo{
key customerName;
leaf customerName{
type string;
}
uses moduleA:devices {
augment "deviceList" {
leaf ipAddress{
}
}
}
}
}
Note that if you use the augment statement in the module B then it means that any device implementing module B has to also implement module A and its root-level list deviceList. See RFC 7950 4.2.8:
When a server implements a module containing an "augment" statement,
that implies that the server's implementation of the augmented module
contains the additional nodes.
I am not sure if this is what you want. If not, then move the grouping definition to a module that contains only grouping definitions (without any "data definition statements") and import it from both A and B.

Yang Model recursive search for must condition

I have a problem with a restriction on my CLI. I've been investigating yang RFC7950 (https://www.rfc-editor.org/rfc/rfc7950) but I've found nothing.
Here is an example.
grouping httpGroup {
list http-list{
key "value";
leaf value {
status current { yexte:preliminary; }
description "value to match";
must "(not(../protocol)) and (not(../network-port)))" {
error-message "Not compatible with protocol or non-TCP ports";
}
type string { length "1..255"; }
}
}
}
This group will be included in several groups with the following structure:
list and {
leaf-list protocol { ..... }
uses A;
list or {
leaf-list protocol { ..... }
uses A;
}
}
grouping A {
status{}
leaf-list protocol { ..... }
leaf-list X { ..... }
uses httpGroup;
}
I need this must condition included in httpGroup to verify that protocol value has not been configured in any level of the hierarchy.
I've made this be adding more relatives paths to search for this node:
// same level
not(../protocol)
// next level
not(../and/protocol)
not(../or/protocol)
// previous level
not(../../protocol)
not(../../protocol)
//recursively down previous level
not(../../and/protocol)
not(../../or/protocol)
// third level
not(../and/or/protocol)
not(../and/and/protocol)
As you can see, this is not a clean solution at all.
Is there any way it can be done for a whole hierarchy like:
if protocol node exists and http-list exists then error.
Thank you in advance.
Groupings are meant to be reusable. It is a bad practice to attempt to create a grouping that may only be used in specific contexts. This is exactly what happens if you define an XPath expression within a grouping and this expression references nodes that are "outside" this grouping (a not yet known ancestor data node, for example, or even worse - an ancestor with a specific name).
The proper way for you to handle this situation would be to use a refine statement in each different context where this grouping is used. You target the value leaf with it, then refine it by adding a must statement, the expression of which of course depends on usage context. You do not define a must statement within grouping http-list.
Within grouping A:
grouping A {
status{}
leaf-list protocol { ..... }
leaf-list X { ..... }
uses httpGroup {refine "http-list/value" {must "not(../../protocol)";}}
}
As you can see, grouping A is now completely self-sufficient and may be used within any context - the must will not have any problems with it.

how is this yang notification valid?

yang 1.1 spec has this example,
The following example defines a notification in a data node:
module example-interface-module {
yang-version 1.1;
namespace "urn:example:interface-module";
prefix "if";
container interfaces {
list interface {
key "name";
leaf name {
type string;
}
notification interface-enabled {
leaf by-user {
type string;
}
}
}
}
}
A corresponding XML instance example of the complete notification:
<notification
xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
<eventTime>2008-07-08T00:01:00Z</eventTime>
<interfaces xmlns="urn:example:interface-module">
<interface>
<name>eth1</name>
<interface-enabled>
<by-user>fred</by-user>
</interface-enabled>
</interface>
</interfaces>
</notification>
My question is, when I raise a notification from server, I thought the notification content would be this :
<notification
xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
<eventTime>2008-07-08T00:01:00Z</eventTime>
<interface-enabled xmlns="urn:example:interface-module">
<by-user>fred</by-user>
</interface-enabled>
</notification>
But, such a notification will be useless without identifying the data node for which the notification is relevant.
I guess my question is, what rule/text in the spec tells me how to form the payload correctly
https://www.rfc-editor.org/rfc/rfc7950#section-7.16.2
When a notification node is defined as a child to a data node, the
element defined in [RFC5277] contains a hierarchy of
nodes that identifies the node in the datastore. It MUST contain all
containers and list nodes from the top level down to the list or
container containing the notification.
The notification payload must include all ancestor container/lists up to the module root. Only then it is always possible to identify the exact node to which the notification is referring.