cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
2675
Views
6
Helpful
3
Replies

How to use must() and XPATH to filter items in leafref()

Andrew Horrigan
Cisco Employee
Cisco Employee

I have a leafref() that is generating a list of devices based on the devices currently managed by NSO.

    leaf csp-device {

      type leafref {

        path "/ncs:devices/ncs:device/ncs:name";

      }

      mandatory true;

    }

I would like to filter that list based on whether or not the device name contains the string "csp".  I know I need to use a must() statement but I am confused whether or not I need to use current() or a deref.  I am also confused whether or not I need to use contains().


I have tried a number of things, but my YANG never compiles.  This is my latest iteration:


    leaf csp-device {

      type leafref {

        path "/ncs:devices/ncs:device/ncs:name";

      }

      mandatory true;

      must "current() = (current()[contains(name,'csp')]";

    }

I am trying to do something similar in a number of places, so it would be great to get some help.  Thanks!

1 Accepted Solution

Accepted Solutions

1) I noticed that the YANG would not compile unless I used ' ' for the whole must() statement and " " for the string.  I thought those were interchangeable in YANG ... is that not the case?

No, they are not completely interchangeable. Single quotes make everything in the string exactly as is, while double quotes treat some escape characters as special, such as \n \t \" etc. For strings that represent code or regex expressions, I prefer single quotes for fewer surprises. Double quotes are good for descriptions and other plain text.

2) I am now attempting to do something similar with another leafref for interfaces.  However, with this must statement, I need to a) verify the interface is up and b) ensure the interface is not being used for management.  I am trying to employ your example above:

In general, that's perfectly doable.

The current() function just returns the current node, and since you are treating it as a string, it will simply evaluate to the name of the pnic interface, which in most cases would not be relevant to compare to "up".

In order to get to the object the name refers to, you need to use deref(). Since this leafref points to the name, you'll need to back up a level to navigate to the adminstatus. Since you are also interested to compare to the entire value, not just find a substring, you can use simple equality. So I think the must expression would be something like this:

     must 'deref(current())/../pnic:adminstatus = "up" ' { error-message "..."; }

Keep reading however.

You didn't supply the pnic YANG module, or any information about it, so I can only guess what you are using. I did a random search on my laptop and found a pnic.yang dated 2015-04-30. Not sure if this is relevant to your use case. Here's the adminstatus leaf definition from the module I found:

module pnic {

...

  revision 2015-04-30 {

...

      leaf adminstatus {

        // for now making this unconfigurable

        tailf:cdb-oper {

          tailf:persistent true;

        }

        type enumeration {

          enum up;

          enum down;

        }

        must "(../passthrough != 'pcie') and (../passthrough != 'sriov')" {

            tailf:dependency "../passthrough";

            error-message "not allow to shutdown PCIE or SRIOV interface";

        }

        default up;

        description "Admin configured status for a physical interface";

        tailf:info "Admin configured status for a physical interface";

      }

So if you are using the same version as I found, I'm not sure the expression I gave is going to work, since the adminstatus is marked as operational data, and not configuration. In the YANG world, it's never ok that the validity of one configuration leaf (vnic1-pnic) depends on a non-configuration value (adminstatus). Perhaps you'll want to say "but, adminstatus *is* a configuration item". Well, it should be. But it's not how it's been modeled above. The comment near the top "// for now making this unconfigurable" suggests that the modeler realized this was not a perfect way of modeling, but chose to do so anyway for untold reasons. Maybe you have an improved version. So try this out with the pnic.yang you have to see if this works for you.

For the second-half of 2), is it possible to combine must statements?

Yes. You can either just use "and" as in

     must '(some expr) and (some other expr)';

or you can use two must expressions after each other. Both must hold true:

     must 'some expr';
     must 'some other expr';

Hope this helps,
/jan

View solution in original post

3 Replies 3

Jan Lindblad
Cisco Employee
Cisco Employee

Try this:

must 'contains(current(), "csp")' { error-message "blah, ..."; }

(or maybe starts-with(current(), "csp") so you don't get false positives like "asr-acspool5"?

You could also construct your must expression so that instead of going by the name, it could verify that the device in question has some csp specific configuration.

Awesome! Thanks that worked =)

2 things:

1) I noticed that the YANG would not compile unless I used ' ' for the whole must() statement and " " for the string.  I thought those were interchangeable in YANG ... is that not the case?

2) I am now attempting to do something similar with another leafref for interfaces.  However, with this must statement, I need to a) verify the interface is up and b) ensure the interface is not being used for management.  I am trying to employ your example above:

      leaf vnic1-pnic {

        type leafref {

          path "deref(../../csp-device)/../ncs:config/pnic:pnics/pnic:pnic/pnic:name";

        }

        must 'contains((current()/pnic:adminstatus), "up")';

        tailf:info "SR-IOV Interface";

      }

I have also tried:

        must 'contains((current()/../pnic:adminstatus), "up")';

But I am getting an error during the make similar to this:


warning: The 'must' expression will fail: the node 'adminstatus' from module 'pnic' (in node 'vnic1-pnic' in module 'cspOnboard' from 'cspOnboard') is not found


Edit: Just thought this might be useful, but here is the XPATH for what I am trying to access:


admin@ncs# show running-config devices device sae-csp2 config pnic enp1s0f0 adminstatus | display xpath

/devices/device[name='sae-csp2']/config/pnic:pnics/pnic[name='enp1s0f0']/adminstatus up

For the second-half of 2), is it possible to combine must statements?

1) I noticed that the YANG would not compile unless I used ' ' for the whole must() statement and " " for the string.  I thought those were interchangeable in YANG ... is that not the case?

No, they are not completely interchangeable. Single quotes make everything in the string exactly as is, while double quotes treat some escape characters as special, such as \n \t \" etc. For strings that represent code or regex expressions, I prefer single quotes for fewer surprises. Double quotes are good for descriptions and other plain text.

2) I am now attempting to do something similar with another leafref for interfaces.  However, with this must statement, I need to a) verify the interface is up and b) ensure the interface is not being used for management.  I am trying to employ your example above:

In general, that's perfectly doable.

The current() function just returns the current node, and since you are treating it as a string, it will simply evaluate to the name of the pnic interface, which in most cases would not be relevant to compare to "up".

In order to get to the object the name refers to, you need to use deref(). Since this leafref points to the name, you'll need to back up a level to navigate to the adminstatus. Since you are also interested to compare to the entire value, not just find a substring, you can use simple equality. So I think the must expression would be something like this:

     must 'deref(current())/../pnic:adminstatus = "up" ' { error-message "..."; }

Keep reading however.

You didn't supply the pnic YANG module, or any information about it, so I can only guess what you are using. I did a random search on my laptop and found a pnic.yang dated 2015-04-30. Not sure if this is relevant to your use case. Here's the adminstatus leaf definition from the module I found:

module pnic {

...

  revision 2015-04-30 {

...

      leaf adminstatus {

        // for now making this unconfigurable

        tailf:cdb-oper {

          tailf:persistent true;

        }

        type enumeration {

          enum up;

          enum down;

        }

        must "(../passthrough != 'pcie') and (../passthrough != 'sriov')" {

            tailf:dependency "../passthrough";

            error-message "not allow to shutdown PCIE or SRIOV interface";

        }

        default up;

        description "Admin configured status for a physical interface";

        tailf:info "Admin configured status for a physical interface";

      }

So if you are using the same version as I found, I'm not sure the expression I gave is going to work, since the adminstatus is marked as operational data, and not configuration. In the YANG world, it's never ok that the validity of one configuration leaf (vnic1-pnic) depends on a non-configuration value (adminstatus). Perhaps you'll want to say "but, adminstatus *is* a configuration item". Well, it should be. But it's not how it's been modeled above. The comment near the top "// for now making this unconfigurable" suggests that the modeler realized this was not a perfect way of modeling, but chose to do so anyway for untold reasons. Maybe you have an improved version. So try this out with the pnic.yang you have to see if this works for you.

For the second-half of 2), is it possible to combine must statements?

Yes. You can either just use "and" as in

     must '(some expr) and (some other expr)';

or you can use two must expressions after each other. Both must hold true:

     must 'some expr';
     must 'some other expr';

Hope this helps,
/jan