Yang Model recursive search for must condition - ietf-netmod-yang

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.

Related

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.

How to write to an Element in a Set?

With arrays you can use a subscript to access Array Elements directly. You can read or write to them. With Sets I am not sure of a way to write its Elements.
For example, if I access a set element matching a condition I'm only able to read the element. It is passed by copy and I can't therefore write to the original.
For example:
columns.first(
where: {
$0.header.last == Character(String(i))
}
)?.cells.append(value: addValue)
// ERROR: Cannot use mutating member on immutable value: function call returns immutable value
You can't just change things inside a set, because of how a (hash) set works. Changing them would possibly change their hash value, making the set into an invalid state.
Therefore, you would have to take the thing you want to change out of the set, change it, then put it back.
if var thing = columns.first(
where: {
$0.header.last == Character(String(i))
}) {
columns.remove(thing)
thing.cells.append(value: addValue)
columns.insert(thing)
}
If the == operator on Column doesn't care about cells (i.e. adding cells to a column doesn't suddenly make two originally equal columns unequal and vice versa), then you could use update instead:
if var thing = columns.first(
where: {
$0.header.last == Character(String(i))
}) {
thing.cells.append(value: addValue)
columns.update(thing)
}
As you can see, it's quite a lot of work, so maybe sets aren't a suitable data structure to use in this situation. Have you considered using an array instead? :)
private var _columns: [Column]
public var columns : [Column] {
get { _columns }
set { _columns = Array(Set(newValue)) }
// or any other way to remove duplicate as described here: https://stackoverflow.com/questions/25738817/removing-duplicate-elements-from-an-array-in-swift
}
You are getting the error because columns might be a set of struct. So columns.first will give you an immutable value. If you were to use a class, you will get a mutable result from columns.first and your code will work as expected.
Otherwise, you will have to do as explained by #Sweeper in his answer.

openscad drill into group created by for

I know that when I use for it creates a group of the generated children.
I created a module called grid like so:
module grid(x0,y0,dx,dy,nx,ny) {
for (x=[0:1:nx-1]) {
for(y=[0:1:ny-1]) {
i=x*nx+y;
echo(i);
translate([x0+x*dx,y0+y*dy,0]) children(i);
}
}
}
which when used like this:
grid(-50,-50,25,25,5,5) {
cube([10,10,10],center=true);
cube([10,10,10],center=true);
cube([10,10,10],center=true);
cube([10,10,10],center=true);
//.. continue to create 25 cubes total
}
arranges the cubes in a nice grid.
however my original hope and intention was to use it like this:
grid(-50,-50,25,25,5,5) {
for(i=[0:1:24]) {
cube([10,10,10],center=true);
}
}
Which fails because the for operator returns a group and not a set of children.
Why does the for add a group to begin with? (also leading to the need for intersection_for)
And is there a way for my Grid operator module to handle the children of the group?
I personally hope for the grouping/union for elements within a for() to become optional at some time.
If you don't mind compiling OpenSCAD from source, you could try it already today.
There is an ongoing issue Lazy union (aka. no implicit union)
and a patch here Make for() UNION optional
Just updated my knowledge of OpenSCAD, there is a better solution:
module nice_cube()
{
translate([0,0,$height/2]) cube([9,9,$height], center = true);
}
module nice_cylinder()
{
translate([0,0,$height/2]) cylinder(d=10,h=$height, center = true);
}
module nice_text()
{
linear_extrude(height=$height, center=false) text(str($height), size=5);
}
module nice_grid()
{
for(i=[0:9], j=[0:9])
{
$height=(i+1)*(j+1);
x=10*i;
y=10*j;
translate([x,y,0]) children();
/* let($height=(i+1)*(j+1)) {children();} */
}
}
nice_grid() nice_cube();
translate([0,-110,0]) nice_grid() nice_text();
translate([-110,0,0]) nice_grid() nice_cylinder();
The trick here is to control the shape produced by module by special variables (starting with $) those can be used like in example, commented line using let() requires development version of openscad.
I guess You want this:
for(x=[...], y=[...]) {
translate([x,y,0]) children();
}
Note, that you need only one for statement to loop through both x and y values.
What I have understood from your comment is, that you want your objects in the nodes of the grids to be parametric, and parameter depends on index. This requirement was not mentioned in the original question. In this case, solution depends on your problem context, I guess. The two possibilities I see are:
module grid_of_parametric_modules(other_param)
{
for(i=[0:24])
{
x=_x(i);
y=_y(i);
translate([x,y,0]) parametric_module(i_param(i), other_param);
}
}
However this may not be suitable, especially if You are going to add new shapes to your grid in future. Then you can probably do it like:
function grid_pos(i) = [_x(i), _y(i), 0];
....
for(i=[0:24])
translate(grid_pos(i)) parametric_module(i);

Are there any side effects of exiting a loop with return rather than break in Swift?

I need to match items in two different arrays (one with imported items and another with local items that share some properties with the imported items) to sync two databases that are quite different. I need to use several criteria to do the matching to increase the robustness of finding the right local item and match it with the imported item. I could check each criterium in the same loop, but that is too expensive, because the criteria are checked by the likelihood of success in descending order. Thus, in my first implementation I used a boolean flag called found to flag that the checking of other criteria should be ignored.
Using pseudo code:
// calling code for the matching
for item in importedItems {
item.match() }
In the imported item class:
match()
{
var found = false
for localItem in localItems
{
if (self.property == localItem.property)
{
// update the local item here
found = true
break
}
}
// match with less likely 2nd property
if (!found)
{
for localItem in localItems
{
if (self.property2 == localItem.property2)
{
// update the local item here
found = true
break
}
}
}
The if !found {...} pattern is repeated two additional times with even less likely criteria.
After reviewing this code, it is clear that this can be optimized by returning instead of breaking when there is a match.
So, my question is "are there any known side-effects of leaving a loop early by using return instead of break in Swift?" I could not find any definitive answer here in SO or in the Swift documentation or in blogs that discuss Swift flow control.
No, there are no side effects, quite the opposite it's more efficient.
It's like Short-circuit evaluation in a boolean expression.
But your code is a bad example because found cannot be used outside the function.
This is a more practical example returning a boolean value
func match() -> Bool
{
for localItem in localItems
{
if (self.property == localItem.property)
{
// update the local item here
return true
}
}
....
return false
}
If you know for sure that you can return because nothing else have to be done after the loop then there are no side effects of using return