cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
1459
Views
0
Helpful
4
Replies

Is there a way to make webui-one display interfaces like ncs_cli?

ryan-hitch
Level 4
Level 4

Three questions

- Is there a way to make webui-one display interfaces like ncs_cli?

- switch-interface-description below displays descriptions for all interfaces 0/1 in the cdb, not 0/1 for the current switch. How can I fix this?

- Am I using tailf:dependency correctly in the model below?

Details

Using auto-completion with a question mark, ncs_cli displays interface id along with interface description (see cli display below). This is incredibly useful to users looking to select an interface not already in use (and thus with a certain description).

I have a few thoughts on how to accomplish this - though none are as elegant as is currently displayed in the cli and I would LOVE help/suggestions.
- Have a separate switch-interface-description leafref in the same switch-interface list as the interface id. (illustrated somewhat correctly below)
- Create a new leaf that is the union of two leafrefs (switch-interface-id and switch-interface-description) and then split this into two variables later on with python for template parsing.

- Modify webui-one code

cli display
admin@ncs% set mpls-vpn-environment CUST2 l2vpn TESTL2 vpn-state id-allocation site s00-rtr-1 switch s00-sw-2 switch-interface-types GigabitEthernet switch-interfaces-GigabitEthernet ?
Description: The switch interface identifier
Possible completions:
  <The switch interface identifier>
  0/1  - UNUSED
  0/2  - UNUSED
  0/3  - UNUSED
  0/4  - CUST5-DATA1-4020
  0/5  - CUST6-DATA2-4003
  0/6  - UNUSED
  0/7  - UNUSED
  0/8  - UNUSED


Current model

    list switch {
      tailf:info "The list of switches for the site";
      key switch-name;

      leaf switch-name {
        tailf:info "The name of the switch";
        type leafref {
          path "/net-topo:net-topo/net-topo:switch/net-topo:switch-name";
          // net-topo:switch-name is a leafref to "/ncs:devices/ncs:device/ncs:name"
        }
        must "current()=deref(current()/../../router-name)/../net-topo:switch/net-topo:switch-name"{
          tailf:dependency "/net-topo:jior-topology/net-topo:switch/net-topo:switch-name";
        }
      }


        list switch-interfaces-GigabitEthernet {
          key switch-interface-id;
          when "../switch-interface-type = 'GigabitEthernet'";
          uses switch-interface-grouping;

          leaf switch-interface-id {
            tailf:info "The switch interface identifier";
            type leafref {
              path "/ncs:devices/ncs:device/ncs:config/ios:interface/ios:GigabitEthernet/ios:name";
            }
            must "current()=deref(deref(current()/../../../switch-name))/../ncs:config/ios:interface/ios:GigabitEthernet/ios:name"{
              tailf:dependency "/ncs:devices/ncs:device/ncs:config/ios:interface/ios:GigabitEthernet/ios:name";
            }
          }


          leaf switch-interface-description {
            tailf:info "The switch interface description";
            type leafref {
              path "/ncs:devices/ncs:device/ncs:config/ios:interface/ios:GigabitEthernet/ios:description";
            }
            must "current()=deref(current()/../switch-interface-id)/../ios:description"; //displays descriptions for all interfaces 0/1 in the cdb, not 0/1 for the current switch
          }
        }

1 Accepted Solution

Accepted Solutions

Michael Maddern
Cisco Employee
Cisco Employee

Hi Ryan,

I’ve answered your questions below and made some other suggestions you could look into.

- Is there a way to make webui-one display interfaces like ncs_cli?

The CLI displays leafref completion by outputting the leaf value plus any other leafs from the list configured by the tailf:cli-instance-info-leafs CLI extension. By default, this is the value of a leaf called description: From the tailf-yang-cli-exntensions man page:

This statement is used to specifiy how list entries are displayed when doing completion in the CLI. By default, a list entry is displayed by listing its key values, and the value of a leaf called 'description', if such a leaf exists in the list entry.

The Web UI doesn't have the same completion, it’s populating the possible leafref values directly in the dropdown list

You could open a second tab to look at the list of interfaces. What’s nice in the Web UI is that lists are displayed as tables with each leaf as a column, so you’ll see more information than the completion in the CLI shows.

- switch-interface-description below displays descriptions for all interfaces 0/1 in the cdb, not 0/1 for the current switch. How can I fix this?

I think the reason you're seeing all 0/1 descriptions is because the switch-interface-id leafref path includes all devices.

A better approach here would be to add the description leaf as operational data and link it to the description leaf under the device interface using tailf:link (check out the man page for tailf_yang_extensions for more info):

    leaf switch-interface-description {

      config false;

      type string;

      tailf:link "/ncs:devices/ncs:device[ncs:name=current()/../../switch-name]/ncs:config/ios:interface/ios:GigabitEthernet[ios:name=current()/../switch-interface-id]/ios:description";

      tailf:info "The switch interface description";

    }

(I haven't tested the XPath, you may have to tweak it for your model)

The only problem with this solution is that you wouldn’t see the description until after the interface was selected.

- Am I using tailf:dependency correctly in the model below?

No, the interface name is the key of the list, so it would never change. The dependency should be an XPath to a node that would trigger the must statement to be re-evaluated when that node is modified. So in this case, you might put the switch-name as the dependency.

Other ideas

Your idea to restrict the switch-interface leaf to only allow the UNUSED ones could work. Whatever criteria you enter in the must statement must always hold true, even after the service has been created. You should be able to construct a must statement which also allows the description value after it has been updated. Do you have access to the VLAN ID and VPN Name in the yang model? If not (i.e you are allocating them), it can be nice to add them to your model as operational data anyway. Then you should be able to use something like:

  must "deref(current())/../ios:description = ‘UNUSED’ or deref(current())/../ios:description = concat(current()/../path/to/vpn-name, ' - ' ,current()/../path/to/vlan-id)" {

    tailf:dependency "/ncs:devices/ncs:device/ncs:config/ios:interface/ios:GigabitEthernet/ios:description";

  }

Have you considered allocating the interface automatically instead? If you’re using python, it would only be a few lines of code to loop through each interface and check for the first UNUSED one. You can then create template variables for the switch-name and switch-interface and use those in your template instead of having leafs in your service model.

If you really want to see a drop down list with both the interface name and description in the list in the existing web UI, then one option you could explore are YANG transformations. They can be tricky though, and probably not worth the hassle for just one leaf. They are generally used when you have a complex low level model that you want to abstract to a high level model. You define a mapping which can convert between the two. They are written in Erlang. If you’re interested take a look at the NSO-developer github at genet and ec_map_example.

There’s probably a few different ways to do it, but one option is to augment the device interface list with a HL leaf i.e. name-w-desc, and create the mapping so this is automatically derived from the name and description leafs. Assuming you’d augmented the GigabitEthernet list with int-desc:name-w-desc, you would add a mapping something like the following in the ec_server code:

        [['http://cisco.com/ns/genet/examples/int-desc'|'name-w-desc’],{Interface},GigabitEthernet,['urn:ios'|interface],config,{Device},device,['http://tail-f.com/ns/ncs'|devices]] ->

            LLPath=[{Interface},’GigabitEthernet',['urn:ios'|'interface'],config,{Device},device,?LLROOT],

            #mappings{path=[name|LLPath],

                      fupval=fun(Tctx,_,Val,_) ->

                                    Description=ec_genet:get_elem(Tctx, [description|LLPath], none),

                                    case Description of

                                        none -> Val;

                                        _ -> <<Val/binary, " - ", Description/binary>>

                                    end

                              end};

To add this to your service model, you should do it through a second transformation, since you don’t want to store the value with the description. You can create a HL leaf in your service of type leafref with a path to the name-w-desc leaf so the dropdown list will display correctly, but map it to your original switch-interface leaf (which you could hide if you wanted).

One other thing you could consider is creating a custom UI instead. Again, if it’s just for this one leaf, it’s probably too much hassle, but if you have other data you want to display in different ways it could be worth looking into. You can’t update the webui-one code directly, but it’s easy to add new applications to the Application Hub. It’s configuration data in the CDB (try show running-config webui applications). You can use any web frameworks you like, but even with basic HTML and Javascript, you can create a new page quite easily and then use the JSON-RPC API to read and write transactions.

View solution in original post

4 Replies 4

ryan-hitch
Level 4
Level 4

Another way that I am trying to accomplish this is to create a leafref of only interfaces which have a certain description (such as "UNUSED"). This *sort of* works as the following leafref builds the initial list of unused interfaces, but then I have a problem when I go to commit because my model changes the interface description to "{vpn-name}-{VLAN number}" when the interface is assigned to a VPN and VLAN which invalidates the must constraint. Is there a way to work around this somehow?

leaf switch-interface-id {

  tailf:info "The switch interface identifier";

  type leafref {

  path "/ncs:devices/ncs:device[ncs:name=current()/../../switch-name]/ncs:config/ios:interface/ios:GigabitEthernet/ios:name";

  }

  must "deref(current())/../ios:description = 'UNUSED'";

}

I tried changing the must constraint to the following, but it does not appear to constrain switch-interface-id at all in either the cli or webui-one.

tailf:display-when "deref(current())/../ios:description = 'UNUSED'"

Michael Maddern
Cisco Employee
Cisco Employee

Hi Ryan,

I’ve answered your questions below and made some other suggestions you could look into.

- Is there a way to make webui-one display interfaces like ncs_cli?

The CLI displays leafref completion by outputting the leaf value plus any other leafs from the list configured by the tailf:cli-instance-info-leafs CLI extension. By default, this is the value of a leaf called description: From the tailf-yang-cli-exntensions man page:

This statement is used to specifiy how list entries are displayed when doing completion in the CLI. By default, a list entry is displayed by listing its key values, and the value of a leaf called 'description', if such a leaf exists in the list entry.

The Web UI doesn't have the same completion, it’s populating the possible leafref values directly in the dropdown list

You could open a second tab to look at the list of interfaces. What’s nice in the Web UI is that lists are displayed as tables with each leaf as a column, so you’ll see more information than the completion in the CLI shows.

- switch-interface-description below displays descriptions for all interfaces 0/1 in the cdb, not 0/1 for the current switch. How can I fix this?

I think the reason you're seeing all 0/1 descriptions is because the switch-interface-id leafref path includes all devices.

A better approach here would be to add the description leaf as operational data and link it to the description leaf under the device interface using tailf:link (check out the man page for tailf_yang_extensions for more info):

    leaf switch-interface-description {

      config false;

      type string;

      tailf:link "/ncs:devices/ncs:device[ncs:name=current()/../../switch-name]/ncs:config/ios:interface/ios:GigabitEthernet[ios:name=current()/../switch-interface-id]/ios:description";

      tailf:info "The switch interface description";

    }

(I haven't tested the XPath, you may have to tweak it for your model)

The only problem with this solution is that you wouldn’t see the description until after the interface was selected.

- Am I using tailf:dependency correctly in the model below?

No, the interface name is the key of the list, so it would never change. The dependency should be an XPath to a node that would trigger the must statement to be re-evaluated when that node is modified. So in this case, you might put the switch-name as the dependency.

Other ideas

Your idea to restrict the switch-interface leaf to only allow the UNUSED ones could work. Whatever criteria you enter in the must statement must always hold true, even after the service has been created. You should be able to construct a must statement which also allows the description value after it has been updated. Do you have access to the VLAN ID and VPN Name in the yang model? If not (i.e you are allocating them), it can be nice to add them to your model as operational data anyway. Then you should be able to use something like:

  must "deref(current())/../ios:description = ‘UNUSED’ or deref(current())/../ios:description = concat(current()/../path/to/vpn-name, ' - ' ,current()/../path/to/vlan-id)" {

    tailf:dependency "/ncs:devices/ncs:device/ncs:config/ios:interface/ios:GigabitEthernet/ios:description";

  }

Have you considered allocating the interface automatically instead? If you’re using python, it would only be a few lines of code to loop through each interface and check for the first UNUSED one. You can then create template variables for the switch-name and switch-interface and use those in your template instead of having leafs in your service model.

If you really want to see a drop down list with both the interface name and description in the list in the existing web UI, then one option you could explore are YANG transformations. They can be tricky though, and probably not worth the hassle for just one leaf. They are generally used when you have a complex low level model that you want to abstract to a high level model. You define a mapping which can convert between the two. They are written in Erlang. If you’re interested take a look at the NSO-developer github at genet and ec_map_example.

There’s probably a few different ways to do it, but one option is to augment the device interface list with a HL leaf i.e. name-w-desc, and create the mapping so this is automatically derived from the name and description leafs. Assuming you’d augmented the GigabitEthernet list with int-desc:name-w-desc, you would add a mapping something like the following in the ec_server code:

        [['http://cisco.com/ns/genet/examples/int-desc'|'name-w-desc’],{Interface},GigabitEthernet,['urn:ios'|interface],config,{Device},device,['http://tail-f.com/ns/ncs'|devices]] ->

            LLPath=[{Interface},’GigabitEthernet',['urn:ios'|'interface'],config,{Device},device,?LLROOT],

            #mappings{path=[name|LLPath],

                      fupval=fun(Tctx,_,Val,_) ->

                                    Description=ec_genet:get_elem(Tctx, [description|LLPath], none),

                                    case Description of

                                        none -> Val;

                                        _ -> <<Val/binary, " - ", Description/binary>>

                                    end

                              end};

To add this to your service model, you should do it through a second transformation, since you don’t want to store the value with the description. You can create a HL leaf in your service of type leafref with a path to the name-w-desc leaf so the dropdown list will display correctly, but map it to your original switch-interface leaf (which you could hide if you wanted).

One other thing you could consider is creating a custom UI instead. Again, if it’s just for this one leaf, it’s probably too much hassle, but if you have other data you want to display in different ways it could be worth looking into. You can’t update the webui-one code directly, but it’s easy to add new applications to the Application Hub. It’s configuration data in the CDB (try show running-config webui applications). You can use any web frameworks you like, but even with basic HTML and Javascript, you can create a new page quite easily and then use the JSON-RPC API to read and write transactions.

Thanks for your detailed response. Much appreciated. We are going to take the simple approach of using python to auto-assign a free interface in the short term and are moving toward a custom web UI for the long term.