cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
552
Views
10
Helpful
8
Replies

Concatenate in YANG definition

Hi,

 

Does anybody know if it's possible to concatenate the output of one leaf with a substring in another leafref. In my specific use-case I have a device-group that makes up an area, in that 'area' device-group I have a child device-group that contains all access-switches;

 

        leaf area-id {
          tailf:info "Area assignment";
          mandatory true;
          type leafref {
            path "/ncs:devices/ncs:device-group/ncs:name";
          }
        }
        container access-port {
          leaf access-sw {
            type leafref {
              path "/ncs:devices/ncs:device-group[ncs:name=concat(current()/../../area-id,'-SW')]/ncs:member"; 
          }
          leaf port {
            type leafref {
              path "deref(../access-sw)/../ncs:config/ios:interface/ios:GigabitEthernet/ios:name";
            }
          }
        }

Is this possible?

 

-J

1 Accepted Solution

Accepted Solutions

vleijon
Cisco Employee
Cisco Employee
ou have a bit of a weird example in the first post, so there are a few things I want to clear up before I get to how to do it.

First, you reference member which is operational data from config, which isn't generally allowed. In YANG 1.1 you can use require-instance false to be allowed.

Second, you reference device config from a service model. This means that if the config is deleted from the device, a sync-from will fail. Say that an interface card is replaced for instance.

Third, you reference a device group and its member but it seems like the only valid device is named exactly {area}-SW, so it is unclear to me why you need the device-group instead of just an area-list and the device tree.

Anyhow, assuming those requirements, this is my yang model:
        leaf area-id {
            tailf:info "Area assignment";
            mandatory false;
            type leafref {
                path "/ncs:devices/ncs:device-group/ncs:name";
            }
        }
        container access-port {
            leaf access-sw {
                type leafref {
                    path "/ncs:devices/ncs:device-group/ncs:member";
                    require-instance false;
                }
                must ". = concat(current()/../../area-id, '-SW')";
            }
            leaf port {
                type leafref {
                    path "/ncs:devices/ncs:device[ncs:name=current()/../access-sw]/ncs:config/ios:interface/ios:GigabitEthernet/ios:name";
                }
            }
        }
Which works in NSO and gives the tab-expand I expect:
admin@ncs# show devices device-group member
NAME   MEMBER
-----------------------------
area1  [ area1-R area1-SW ]
area2  [ area2-R area2-SW ]

admin@ncs# conf
Entering configuration mode terminal
admin@ncs(config)# myservice example area-id area
Possible completions:
  area1  area2
admin@ncs(config)# myservice example area-id area1
admin@ncs(config-myservice-example)# access-port access-sw area1-SW
admin@ncs(config-myservice-example)# port
                                     ^
% Invalid input detected at '^' marker.
admin@ncs(config-myservice-example)# access-port port 0/
Possible completions:
  1   Hi
  2   Hi
admin@ncs(config-myservice-example)# access-port port 0/1
admin@ncs(config-myservice-example)# val
Validation complete

View solution in original post

8 Replies 8

vleijon
Cisco Employee
Cisco Employee
This is not possible, the path statement is a small subset of true XPath (https://datatracker.ietf.org/doc/html/rfc7950#section-9.9.2),

You can try doing an unconstrained path and adding a must-expression with the stricter requirement. The NSO CLI is pretty smart about tab expansion in these situation so it may still work nicely. Of course it may be problematic if the number of device-groups/devices is large.

Thanks for your reply, Viktor.

 

Can you provide an example on how to do that?

 

I tried to do this, but I the access-sw leafref returned a list of device-group names instead of the members (and the port leafref failed as well);

 

leaf area-id {
  tailf:info "Area assignment";
  mandatory true;
  type leafref {
    path "/ncs:devices/ncs:device-group/ncs:name";
  }
}
list access-port {
  tailf:info "Access ports to assign vlan to";
  key "access-sw port";
  leaf access-sw {
    type leafref {
      path "/ncs:devices/ncs:device-group/ncs:name";
    }
    must "contains(deref(current())/../ncs:name,deref(current())/../../area-id) and contains(deref(current())/../ncs:name,'-SW')" {
      tailf:dependency "/ncs:devices/ncs:device-group/ncs:name";              
    }
  }
  leaf port {
    type leafref {
      path "/ncs:devices/ncs:device[name=current()/../access-sw]/ncs:config/ios:interface/ios:GigabitEthernet/ios:name";
    }
  }
}

 

vleijon
Cisco Employee
Cisco Employee
ou have a bit of a weird example in the first post, so there are a few things I want to clear up before I get to how to do it.

First, you reference member which is operational data from config, which isn't generally allowed. In YANG 1.1 you can use require-instance false to be allowed.

Second, you reference device config from a service model. This means that if the config is deleted from the device, a sync-from will fail. Say that an interface card is replaced for instance.

Third, you reference a device group and its member but it seems like the only valid device is named exactly {area}-SW, so it is unclear to me why you need the device-group instead of just an area-list and the device tree.

Anyhow, assuming those requirements, this is my yang model:
        leaf area-id {
            tailf:info "Area assignment";
            mandatory false;
            type leafref {
                path "/ncs:devices/ncs:device-group/ncs:name";
            }
        }
        container access-port {
            leaf access-sw {
                type leafref {
                    path "/ncs:devices/ncs:device-group/ncs:member";
                    require-instance false;
                }
                must ". = concat(current()/../../area-id, '-SW')";
            }
            leaf port {
                type leafref {
                    path "/ncs:devices/ncs:device[ncs:name=current()/../access-sw]/ncs:config/ios:interface/ios:GigabitEthernet/ios:name";
                }
            }
        }
Which works in NSO and gives the tab-expand I expect:
admin@ncs# show devices device-group member
NAME   MEMBER
-----------------------------
area1  [ area1-R area1-SW ]
area2  [ area2-R area2-SW ]

admin@ncs# conf
Entering configuration mode terminal
admin@ncs(config)# myservice example area-id area
Possible completions:
  area1  area2
admin@ncs(config)# myservice example area-id area1
admin@ncs(config-myservice-example)# access-port access-sw area1-SW
admin@ncs(config-myservice-example)# port
                                     ^
% Invalid input detected at '^' marker.
admin@ncs(config-myservice-example)# access-port port 0/
Possible completions:
  1   Hi
  2   Hi
admin@ncs(config-myservice-example)# access-port port 0/1
admin@ncs(config-myservice-example)# val
Validation complete

I could imagine that the level of details I've provided makes it a bit weird  

 

Image that you have a "distribution-block" consisting of a range of routers and range of access switches. All access switches are grouped in a device group "AREA01-SW" and all routers in that area are in "AREA01-RTR" device-group. As a parent device group, we have "AREA01" which has the two device-groups as child device-groups.

 

So basically, when constructing the service I want to reference only the top-level device-group AREA01, then for the access-port element (which is actually a list, and not a container) I want the YANG model to figure out to only allow (or display in the UI) all devices in the AREA01-SW device-group.

 

Further down, for the access-port selection I want to allow or display the ports on the particular device selected from the AREA01-SW device-group.

 

I know that this goes against the idea being abstracted from the underlying hardware/vendor etc. But in this case, the major purpose is to develop a user-friendly UI in a strict environment that doesn't require very deep network configuration skills to be able to deploy a service.

Right, I figured there was more outside of the example. Anyhow, the must-method I show above generalizes.

Ok thanks, I think that I've found an approach then. I do have another issue about the 'port' element. Then name in the path is in the /devices/device tree, while the element-name is derived from /devices/device-group. This doesn't seem to work..

 

Is there a way to just use the 'device-name' element as a string in the /ncs:devices/ncs:device[ncs:name=...] ?

 

That was what I did in my example above, you don’t need to deref it, the leafref is naturally a string.

Thanks a lot Viktor! It seem to be working for me now

Getting Started

Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the NSO Developer community:

Recognize Your Peers