ConfD User Community

Possible to do a 'reverse augment'?


#1

Hi All.

Say I have a container called foods, which contains a list (food-id) with a key, a ‘food-type’ enum {fruit,veg}

and seperate module files fruit.yang and veg.yang, how can i import {fruit|veg}/properties into /food, based on the value of ‘food-type’

Currently i have to have a seperate container for each option

container veg-props{
  when "../food-type='veg'";
  uses veg:veg;
}

container fruit-props{
  when "../food-type='fruit'";
  uses fruit:fruit;
}

where each food module has a container (called props)

So i actually end up with food/fruit-props/props or /foods/veg-props/props

I just want food/props, and to ‘augment’ the food with the props from the given module, but I want to do it this way around (not from within fruit.yang or veg.yang) because if i use augment in those files then i have to absolutely specify what i’m augmenting, but food can appear anywhere in the tree

I hope this makes some sort of sense, obviously I’ve hidden details of my real implementation behind fruit and vegetables but hopefully someone will get the idea

Thanks
James


#2

For context, I tried to do

container properties {
  uses fruit:fruit{
    when "../food-type='fruit'";
  }
  uses veg:veg{
    when "../food-type='veg'";
  }
}

but both the fuit and the veg types have key leafs in them, so i can’t use that as the RFC specifically bans it.


#3

Have you considered using a choice statement? See https://tools.ietf.org/html/rfc7950#section-7.9.6. Example:

container food {
   choice food-type {
     case veg {
      uses veg:veg; 
     }
     case fruit {
       uses fruit:fruit;
     }
   }
 }

#4

We did, but the problem is that then items within the container can’t be common across both cases, so from 4.2.7 of rfc750, the example is


     container food {
       choice snack {
         case sports-arena {
           leaf pretzel {
             type empty;
           }
           leaf beer {
             type empty;
           }
         }
         case late-night {
           leaf chocolate {
             type enumeration {
               enum dark;
               enum milk;
               enum first-available;
             }
           }
         }
       }
     }

However, it is illegal to have a pretzel late-night because all the ‘possible’ nodes of every choice have to be unique, but some properties of fruit and veg are common across both submodules (they both have might have a ‘color’ option, for example, which would now have to become veg-color and fruit-color, which means it’s more complicated to reference them elsewhere.)

Not all cases would have a color option, for example i might have a ‘meat’ case, which we might assume is red and therefore not have a meat-color property


#5

It is only the top-level nodes of each case that need to be unique across the choice (because naming one of those top-level nodes when setting a value is how you actually “make” the choice - the choice and case are not “data nodes”, i.e. they are not visible in NB interfaces). If you make each case in your example a container with the same name as the case, there are no requirements on either uniqueness or equivalence of the contents between the containers. You actually just need to change case to container for this, since the compiler effectively “synthesizes” a case per the “shorthand” logic described in https://tools.ietf.org/html/rfc7950#section-7.9.2 .


#6

Thank you for your reply. Unfortunately this doesn’t meet our requirement because each container would have to be uniquely named just like the cases would, which means we’d end up with fruit-props and veg-props instead of just props

We think we’ve found a solution which we are trialling now, which is to have a container called props in each of the veg.yang anf fruit.yang files, and using conditional uses statements like so:

uses veg:veg{
    when "./food-type='veg'";
}
uses fruit:fruit{
    when "./food-type='fruit';
}

This was actually our first solution, but the editor complained that we couldn't make an element with a key conditional, but the 'outer' element in `fruit.yang|veg.yang` have a container as the root element in the grouping so we think the editor was interpreting it wrong - the pyang library seems to think it's OK.

#7

It’s a bit difficult to comment since you keep changing the contents of your model and adding requirements, but going back to the fruit vs veg case, while keeping the requirement from your previous comment that some but not all properties may be common, you seem to want to achieve that paths like /food{fruit}/props/color and /food{veg}/props/color would refer to different schema leafs - this is simply not possible, whether you use when or choice.

This can’t work - the toplevel nodes of the groupings must be unique across all the uses, regardless of the when expressions. I.e. if your groupings all have a toplevel container called props, you obviously violate this requirement (you will get a “schema node ‘props’ already defined” error from confdc), and if you instead wrap all the uses statements with a single props container and only have the property leafs in the groupings, you will get the same violation/error for the leafs that have the same name (like color in my example above).

The latter variant will work if you drop the requirement that some properties may be common across the types, but otherwise you would have to have only type-specific properties in the “type” groupings, and have common properties in separate groupings - one grouping for each combination of types that have the properties in the grouping in common. You obviously don’t want this.

Taking a step back, I believe the problem here originates in your desire to have a “flat” model - i.e. the properties are at the “same level” as the “type selector”, i.e. the list key. If you instead make use of the hierarchical nature of YANG, you could have the “type selector” be a parent of the properties, and the choice variant with appropriately named containers would be a perfect fit:

  list food {
    key name;
    leaf name { type string; }
    choice type {
      container veg {
        uses veg:veg;
      }
      container fruit {
        uses fruit:fruit;
      }
    }
  }

Thus the groupings are completely independent, and e.g. the paths /food{key}/veg/props/color and /food{key}/fruit/props/color would of course refer to different schema leafs. An added benefit is that (at least in the ConfD implementation) with a large number of “types”, a choice is much more efficient than lots of when-conditional nodes.