Automation
Automation

Define Operational Table

by Cordelia on ‎01-15-2014 05:09 AM - edited on ‎09-05-2017 09:02 PM by Administrator Administrator

Overview

Create the YAML definition for extracting operational data.

 

Description

Retrieving operational data allows you to extract useful running-state data from the device.  For example, you can configure an interface to be in OSPF.  The status of that interface neighbor relationship (for example, show ospf neighbors) is the operational data.

Rather than requiring you to code the specific Junos OS or XML commands and extract the various bits of data, you can define a simple YAML file that instructs the framework what to do. 

The following is an example that corresponds to the Junos OS CLI command to display the interface media data for all Ethernet interfaces (ae*, fe*, ge*, and xe*):

show interfaces media "[afgx]e*"

 

Example

 

1 ---
2 EthPortTable:
3   rpc: get-interface-information
4   args:
5     media: True
6     interface_name: '[afgx]e*'
7   args_key: interface_name
8   item: physical-interface
9   view: EthPortView

 

Discussion

Table Name

(REQUIRED)

You can choose to call your table definition anything you want.  The above example on line 2 defines the name as EthPortTable.  Your YAML file can contain multiple table definitions (as well as views).   The JunosPyEZ loader assumes that anything you define starting at the first column in the text file (like EthPortTable) will be a new widget definition (table, view, and so on).  Your YAML file can contain multiple widget definitions.

 

1 ---
2 EthPortTable:  rpc: get-interface-information
3   args:
4     media: True
5     interface_name: '[afgx]e*'
6   args_key: interface_name
7   item: physical-interface
8   view: EthPortView

 

RPC Command

(REQUIRED)

Every Junos command has a corresponding XML based Remote Procedure Call (RPC).  You can view this RPC definition directly on the Junos CLI using the "pipe display" filter, as illustrated:

 

01 jeremy@junos> show interfaces media "[afgx]e*" | display xml rpc
02 <rpc-reply xmlns:junos="http://xml.juniper.net/junos/12.1I0/junos">
03     <rpc>
04         <get-interface-information>                <media/>
05                 <interface-name>[afgx]e*</interface-name>
06         </get-interface-information>
07     </rpc>
08     <cli>
09         <banner></banner>
10     </cli>
11 </rpc-reply>

 

The XML tag immediately following the <rpc> element is the RPC command tag.  In this case the tag-name is <get-interface-information>.  You can see that this tag-name is used in the example YAML (highlighted) identified by rpc property. You simply provide the tag-name text without the angle brackets.

 

1 ---
2 EthPortTable:
3   rpc: get-interface-information  args:
4     media: True
5     interface_name: '[afgx]e*'
6   args_key: interface_name
7   item: physical-interface
8   view: EthPortView

 

RPC Default Arguments

(OPTIONAL)

In some cases, you will want to include default arguments to the command, such as values you do not want the user to have to specify.  In this example we always want to include the "media" flag and default the "interface-name" field to the set of values to retrieve the Ethernet ports.  You do this by including the optional args property in the YAML definition:

 

1 ---
2 EthPortTable:
3   rpc: get-interface-information
4   args:
5     media: True
6     interface_name: '[afgx]e*'
7   args_key: interface_name
8   item: physical-interface
9   view: EthPortView

 

Pay special attention to the fact that these defaults are indented under the args keyword.  If a default arg is a flag, like media, then simply set the value to True.  Otherwise set it to the value you want.  You can see that we replace dashes (-) with underscores (_) in hyphenated names like interface-name.

 

RPC Optional Argument Key

(OPTIONAL)

Some commands can take an optional first argument that does not require a specific keyword.  If you look at the Junos OS CLI show interfaces command, for example, you'll see an example where the first argument could be the interface name:

 

1 jeremy@junos> show interfaces ? 
2 Possible completions:
3   <[Enter]>            Execute this command
4   <interface-name>     Name of physical or logical interface
5   ge-0/0/0             management port
6   ge-0/0/0.0

 

If you want your YAML definition to make use of this so that the caller of the table can retrieve operational data without specifying the keyword explicit (to mimic the CLI behavior), then you can define the args_key property in your YAML:

 

1 ---
2 EthPortTable:
3   rpc: get-interface-information
4   args:
5     media: True
6     interface_name: '[afgx]e*'
7   args_key: interface_name
8   item: physical-interface
9   view: EthPortView

 

Table Item

(REQUIRED)

Each table item represents a "record" of data.  You need to define the XML XPath that identifies the record container, in other words, the thing that contains the fields of data you want to extract.  For the case of the "show interfaces" command, we want to identify each interface as the unique record. 

 

To identify the XML XPath, you can examine the Junos OS command results in XML using the pipe display, as illustrated.  The following output has been edited for brevity.  You know you want the physical information information, so this XML item is highlighted below:

 

01 jeremy@junos> show interfaces media "[afgx]e*" | display xml  
02 <rpc-reply xmlns:junos="http://xml.juniper.net/junos/12.1I0/junos">
03     <interface-information xmlns="http://xml.juniper.net/junos/12.1I0/junos-interface"junos:style="normal">
04         <physical-interface>            <name>ge-0/0/0</name>
05             <admin-status junos:format="Enabled">up</admin-status>
06             <oper-status>up</oper-status>
07             ##<snip>##        </physical-interface>
08         <physical-interface>            <name>ge-0/0/1</name>
09             <admin-status junos:format="Enabled">up</admin-status>
10             <oper-status>up</oper-status>
11             ##<snip>##           
12         <physical-interface>            <name>ge-0/0/2</name>
13             <admin-status junos:format="Enabled">up</admin-status>
14             <oper-status>up</oper-status>
15             <local-index>135</local-index>
16             ##<snip>##      
17         </physical-interface>
18     </interface-information>           
19     <cli>
20         <banner></banner>
21     </cli>
22 </rpc-reply>

 

When Junos PyEz extracts the data from the table, the XPath expression is relative to the top-level element immediately following the <rpc-reply> tag.  In this case the XPath is relative from <interface-information>.  From that point of reference, the XPath expression to select each physical interface is simply: physical-interface.  You identify the table-item XPath in the YAML definition using the itemproperty:

 

1 ---
2 EthPortTable:
3   rpc: get-interface-information
4   args:
5     media: True
6     interface_name: '[afgx]e*'
7   args_key: interface_name
8   item: physical-interface 
9   view: EthPortView

 

Table Item Key

(OPTIONAL)

Each table item needs a unique identifier so that the user of the table can select the record by name.  Junos OS conventionally uses the XML element-tag <name> for this purpose, but in many instances a different element tag is used.  If table-item uses this <name> tag, then you do not need to define a specific key, name is the default.  If you need to identify a different item-key tag, you can use the key property. 

 

For example, consider the show route command.  If we wanted to create a table of route entries, the associated YAML would look like the following:

 

1 ---
2 RouteTable:
3   rpc: get-route-information
4   args_key: destination
5   item: route-table/rt
6   key: rt-destination 
7   view: RouteTableView

 

I will leave it as an exercise for the reader to examine the specific Junos OS XML command and response output.

 

Some tables also take multiple key values. When this is the case, the key property must be defined as a list.  Here is a snippet of the YAML for extracting LACP status.  You can find the complete example in the Junos PyEZ library (op/lacp.yaml):

 

01 # -----------------------------------------------------------------------------
02 # Each LACP port maintains a "state" table that ha a composite key of the
03 # interface name and it's role (Actor/Partner).  name with the "_" so this
04 # item does not get exported to the global namespace
05 # -----------------------------------------------------------------------------
06  
07 _LacpPortStateTable:
08   item: lag-lacp-state
09   key:   
10     - name   
11     - lacp-role 
12   view: _LacpPortStateView

 

Table View

(REQUIRED, sort of)

The table view property identifies the View widget that maps your field-name definitions to the XML or XPath in each record.  The topic of creating a View widget is discussed in a separate reference article (TBD).

 

1 ---
2 EthPortTable:
3   rpc: get-interface-information
4   args:
5     media: True
6     interface_name: '[afgx]e*'
7   args_key: interface_name
8   item: physical-interface
9   view: EthPortView

 

Generally speaking, you will always associate a view to a table, since that's really the way to make accessing data easy.  If you do not specify a view, then when the caller selects a table item, they will be given the XML data (lxml).  They would then have to extract fiel -data manually using a standard lxml programming technique.

 

Property Summary

The following table summarizes the operational table property definitions:

 

Property

Required / Optional

Description

rpc

Required Identifies the RPC command.

args

Optional

Default RPC command arguments so the called doesn't have to always specify these.

args_key

Optional

Identifies the command argument without requiring a specific keyword.
item Required XPath expression to select table items from command response.  These records become the reference to the view.
key Optional XPath expression that uniquely identifies the item.  By default this is the <name> tag.
view Required Identifies the view widget that is used to extract table-item field data.
'
Comments
Jan 16, 2014
Cordelia
 
Can you define multiple args_key items? For instance, I want to modify the default "RouteTable" to allow the user to specify a particular table. The "show route destination <network>" command will show results from all tables. When trying to grab a specific route using the framework in it's current state, it will only get the first route that is returned, which may not be the one desired.

I assume the other way is to define table using the route table name as the key and chain them down but I was curious if you can allow multiple user defined arguments.
Posted 13:32, 16 Jan 2014
Jan 17, 2014
Cordelia
 
Hi Brad,

The args_key is meant to define the default parameter to the command. In the case of "show route" the default argument is the [destination] field. Perhaps I should change "args_key" to "args_default" (thoughts?)

You can pass any parameter that the command supports when you make the call to the Table get() function. So if you want to pass the name of the routing table, you would do the following, for example:

mytable.get("192.168.10.1", table="inet.0")

The first parameter does not require the "destination" key since destination is defined as the "args_key". If it was not, then you would have to explicitly do something like:

mytable.get(destination="192.168.10.1", table="inet.0")

You can pass as many parameters to the get() as the Junos command allows. Metaprogramming is cool. :-)

Hope this helps!
-- Jeremy
Posted 04:02, 17 Jan 2014
Aug 3, 2015
Cordelia
Hi ,
Can I use Tables and views to get subscribers table?
I try create two file as "testsubscriber.py" and "testsubscriber.yml" in "/usr/local/lib/python2.7/dist-packages/jnpr/junos/op".
The testsubscriber.py content as:
"""
Python for Subscriber Table/View
"""
from jnpr.junos.factory import loadyaml
from os.path import splitext
_YAML_ = splitext(__file__)[0] + '.yml'
globals().update(loadyaml(_YAML_))

The testsubscriber.yml content as:
---
Show_subscriber:
rpc: get-subscribers
item: .//subscriber
view: SubscriberView

SubscriberView:
fields:
interface: interface
username: user-name

I try it in python shell as:
from jnpr.junos import Device
from jnpr.junos.op.testsubscriber import *
dev = Device(host = "x.x.x.x",user = "lab",password = "lab123")
I can get dev.facts success
but I try :
>>> dir()
['Show_subscriber', 'SubscriberView', '__builtins__', '__doc__', '__name__', '__package__', 'dev', 'loadyaml', 'login', 'splitext']
>>> Show_subscriber(dev)
Show_subscriber:x.x.x.x - Table empty
>>> subscribers = Show_subscriber(dev)
>>> subscribers.get()
Show_subscriber:x.x.x.x: 0 items

why I get subscibers with 0 items, in facts there a 126 subscribers. Thank you!
Posted 08:15, 3 Aug 2015