Blog Viewer

Scripting How-To: Create tables or views for complex use cases

By Erdem posted 08-05-2015 19:29

  

Create Tables or Views for Complex Use Cases

 
You can create Tables/Views for complex use cases, such as a multi-path route lookup. 

Let's say you need to find a routing path in your network, for example, do a route lookup. You need to find the route next-hop information, such as the next-hop IP address, outbound interface, and so on. In simple routing topologies, this is fairly trivial.
 
However, if you have complex MPLS environments with multi-path routing, this becomes more of a challenge. When you are troubleshooting or reporting routing paths in such an environment, how would you approach this task using the Junos PyEZ microframework?
 

Multi-path Route Lookup Example

 

Let's first take a look at  a route lookup for 10.207.64.0/24 as an example to illustrate this process.

 

Junos OS CLI

 

01 jeremy@mx> show route 10.207.64.0/24
02
03 inet.0: 54 destinations, 183 routes (46 active, 0 holddown, 8 hidden)
04 + = Active Route, - = Last Active, * = Both
05
06 10.207.64.0/24     *[BGP/170] 8w6d 11:24:41, localpref 100, from 10.160.252.208
07                       AS path: 99999 I
08                     > to 10.160.248.2 via xe-1/3/0.0, label-switched-path LSP-ABC-123
09                       to 10.160.248.6 via xe-1/2/0.0, label-switched-path LSP-ABC-123
10                       to 10.160.248.6 via xe-1/2/0.0, label-switched-path LSP-ABC-123
11                       to 10.160.248.2 via xe-1/3/0.0, label-switched-path LSP-ABC-123
12                     [BGP/170] 8w6d 11:24:41, localpref 100, from 10.160.252.240
13                       AS path: 99999 I
14                     > to 10.160.248.2 via xe-1/3/0.0, label-switched-path LSP-ABC-123
15                       to 10.160.248.6 via xe-1/2/0.0, label-switched-path LSP-ABC-123
16                       to 10.160.248.6 via xe-1/2/0.0, label-switched-path LSP-ABC-123
17                       to 10.160.248.2 via xe-1/3/0.0, label-switched-path LSP-ABC-123
18                     [BGP/170] 8w6d 11:24:41, localpref 100, from 10.160.252.208
19                       AS path: 99999 I
20                     > to 10.160.248.2 via xe-1/3/0.0, label-switched-path LSP-DEF-456
21                       to 10.160.248.6 via xe-1/2/0.0, label-switched-path LSP-DEF-456
22                       to 10.160.248.6 via xe-1/2/0.0, label-switched-path LSP-DEF-456
23                       to 10.160.248.2 via xe-1/3/0.0, label-switched-path LSP-DEF-456
24                     [BGP/170] 8w6d 11:24:41, localpref 100, from 10.160.252.240
25                       AS path: 99999 I
26                     > to 10.160.248.2 via xe-1/3/0.0, label-switched-path LSP-DEF-456
27                       to 10.160.248.6 via xe-1/2/0.0, label-switched-path LSP-DEF-456
28                       to 10.160.248.6 via xe-1/2/0.0, label-switched-path LSP-DEF-456
29                       to 10.160.248.2 via xe-1/3/0.0, label-switched-path LSP-DEF-456

 

Junos OS XML

 

Now let's examine the same data as XML output from the Junos OS API. As you can see, there are four route entries (<rt-entry>) for the destination. Within each of those route entries there are a number of "next-hop" (<nh>) items. Which one represents the one you want?

 

The answer is the first one, but this might not always be the case. Why is the first one the correct answer? You want the current active route, and this is designated by the <current-active> element, found on line 7. Now which of the four <nh> items do you want? You want the one that has the <selected-next-hop> element, found on line 16.

 

Ok, so now that we know what we want, how do we map this into the Junos PyEZ Table/View mechanisms?

 

001 <route-information>
002   <route-table>
003     <rtstyle="brief">
004       <rt-destination>10.207.64.0/24</rt-destination>
005       <rt-entry>
006         <active-tag>*</active-tag>
007         <current-active/>
008         <last-active/>
009         <protocol-name>BGP</protocol-name>
010         <preference>170</preference>
011         <ageseconds="5333608">8w5d 17:33:28</age>
012         <local-preference>100</local-preference>
013         <learned-from>10.160.252.208</learned-from>
014         <as-path>99999 I</as-path>
015         <nh>
016           <selected-next-hop/>
017           <to>10.160.248.2</to>
018           <via>xe-1/3/0.0</via>
019           <lsp-name>LSP-ABC-123</lsp-name>
020         </nh>
021         <nh>
022           <to>10.160.248.6</to>
023           <via>xe-1/2/0.0</via>
024           <lsp-name>LSP-ABC-123</lsp-name>
025         </nh>
026         <nh>
027           <to>10.160.248.6</to>
028           <via>xe-1/2/0.0</via>
029           <lsp-name>LSP-ABC-123</lsp-name>
030         </nh>
031         <nh>
032           <to>10.160.248.2</to>
033           <via>xe-1/3/0.0</via>
034           <lsp-name>LSP-ABC-123</lsp-name>
035         </nh>
036       </rt-entry>
037       <rt-entry>
038         <active-tag></active-tag>
039         <protocol-name>BGP</protocol-name>
040         <preference>170</preference>
041         <ageseconds="5333608">8w5d 17:33:28</age>
042         <local-preference>100</local-preference>
043         <learned-from>10.160.252.240</learned-from>
044         <as-path>99999 I</as-path>
045         <nh>
046           <selected-next-hop/>
047           <to>10.160.248.2</to>
048           <via>xe-1/3/0.0</via>
049           <lsp-name>LSP-ABC-123</lsp-name>
050         </nh>
051         <nh>
052           <to>10.160.248.6</to>
053           <via>xe-1/2/0.0</via>
054           <lsp-name>LSP-ABC-123</lsp-name>
055         </nh>
056         <nh>
057           <to>10.160.248.6</to>
058           <via>xe-1/2/0.0</via>
059           <lsp-name>LSP-ABC-123</lsp-name>
060         </nh>
061         <nh>
062           <to>10.160.248.2</to>
063           <via>xe-1/3/0.0</via>
064           <lsp-name>LSP-ABC-123</lsp-name>
065         </nh>
066       </rt-entry>
067       <rt-entry>
068         <active-tag></active-tag>
069         <protocol-name>BGP</protocol-name>
070         <preference>170</preference>
071         <ageseconds="5333608">8w5d 17:33:28</age>
072         <local-preference>100</local-preference>
073         <learned-from>10.160.252.208</learned-from>
074         <as-path>99999 I</as-path>
075         <nh>
076           <selected-next-hop/>
077           <to>10.160.248.2</to>
078           <via>xe-1/3/0.0</via>
079           <lsp-name>LSP-DEF-456</lsp-name>
080         </nh>
081         <nh>
082           <to>10.160.248.6</to>
083           <via>xe-1/2/0.0</via>
084           <lsp-name>LSP-DEF-456</lsp-name>
085         </nh>
086         <nh>
087           <to>10.160.248.6</to>
088           <via>xe-1/2/0.0</via>
089           <lsp-name>LSP-DEF-456</lsp-name>
090         </nh>
091         <nh>
092           <to>10.160.248.2</to>
093           <via>xe-1/3/0.0</via>
094           <lsp-name>LSP-DEF-456</lsp-name>
095         </nh>
096       </rt-entry>
097       <rt-entry>
098         <active-tag></active-tag>
099         <protocol-name>BGP</protocol-name>
100         <preference>170</preference>
101         <ageseconds="5333608">8w5d 17:33:28</age>
102         <local-preference>100</local-preference>
103         <learned-from>10.160.252.240</learned-from>
104         <as-path>99999 I</as-path>
105         <nh>
106           <selected-next-hop/>
107           <to>10.160.248.2</to>
108           <via>xe-1/3/0.0</via>
109           <lsp-name>LSP-DEF-456</lsp-name>
110         </nh>
111         <nh>
112           <to>10.160.248.6</to>
113           <via>xe-1/2/0.0</via>
114           <lsp-name>LSP-DEF-456</lsp-name>
115         </nh>
116         <nh>
117           <to>10.160.248.6</to>
118           <via>xe-1/2/0.0</via>
119           <lsp-name>LSP-DEF-456</lsp-name>
120         </nh>
121         <nh>
122           <to>10.160.248.2</to>
123           <via>xe-1/3/0.0</via>
124           <lsp-name>LSP-DEF-456</lsp-name>
125         </nh>
126       </rt-entry>
127     </rt>
128   </route-table>
129 </route-information>

 

Tables and Views

 

You can store your Table and View definitions in a simple YAML file. The definitions of these files are explained on the Junos PyEZ project pages you can find here. Take a look at the YAML below. Line 11 defines the XPath expression to extract what you are looking for.

 

01 ---
02 RouteTable:
03   rpc: get-route-information
04   args_key: destination
05   item: route-table/rt
06   key: rt-destination
07   view: CurSelView
08  
09 CurSelView:
10   groups:
11     nh: 'rt-entry[current-active]/nh[selected-next-hop]'
12   fields_nh:
13     to: to
14     via: via
15     lsp: lsp-name

 

Let's examine that XPath expression in more detail. XPath is both powerful and difficult to master. So the whole point of the Junos PyEZ is that for one person to create the XPath magic, while everyone else simply uses the definitions to get what they want; in other words, they don't need to know XPath, Junos, and so on.

 

1 rt-entry[current-active]/nh[selected-next-hop]

 

First, why does it start with rt-entry? Because each table item is a <route-table/rt>, as defined in line 5 of the YAML file. So every field/group is relative to that XML element. The <rt-entry> element is a "child" of <route-table/rt>, so we simply begin with it.

 

Next, what is [current-active]? This is an XPath filter that means "only find <rt-entry> element that has a <current-active> element as a child element". The result of this filter would be the first <rt-entry> in the XML output, lines 5 through 36. The cool thing about XPath expressions is that you can continue to chain them together. So we need to continue to filter.

 

Next is the /nh[selected-next-hop] part of the XPath expression. This means "find the <nh> element that has a<selected-next-hop> child element".

 

The final result of the complete XPath expression is always the LAST element selected, which in this case is the <nh> element.

 

On the Python Shell

 

Finally, let's see how to use this YAML file in a Python shell (or your program), and see how the Junos PyEZ works in practice for someone who doesn't know Junos/XML/XPath. Assume that you've stored the above YAML in a file called "mydefs.yml", and you have an established Device instance (dev) to a remote Junos OS device.

 

01 ## At the Python shell.
02 ## import the 'loadyaml' utility and load the definitions into the Python
03 ## global namespace
04 ##
05 >>> fromjnpr.junos.factory importloadyaml
06 >>> globals().update( loadyaml('mydefs.yml') )
07 ##
08 ## examine our current namespace, see that we have a "RouteTable" class
09 ##
10 >>> dir()
11 ['CurSelView', 'RouteTable', 'loadyaml', 'dev', (...other stuff ommitted)]
12 ##
13 ## now define a table widget of RouteTable and bind it to a Device object
14 ##
15 >>> tbl =RouteTable(dev)
16 ##
17 ## You can then 'get' a specific route destination or pull in the entire table.
18 ## Let's just get the one for '10.207.64.0/24' - this will only extract this one
19 ## entry from the Junos device; which save considerably on processing.
20 ##
21 >>> tbl.get('10.207.64.0/24')
22 RouteTable:your_device_name: 1items
23 ##
24 ## since you only have one time in the table, you could get the item either
25 ## by using index 0, or again using the specific destination, since that
26 ## is the table item key. So let's do that
27 ##
28 >> find =tbl['10.207.64.0/24'] # or you could have done tbl[0]
29 ##
30 ## Now you could examine each of the fields in this table item
31 ##
32 >>> find.to
33 '10.160.248.2'
34 >>> find.via
35 'xe-1/3/0.0'
36 >>> find.lsp
37 'LSP-ABC-123'

 

Further Reading

 

If you are new to XML and XPath, I would recommend the W3schools website as a good primer. I would also very much recommend the XSLT 1.0 Pocket Guide.


#APIs
#Python
#example
#JunosOS
#How-To
#junospyez
#pyez

Permalink