Tracking XPaths on IOS XE
- #xpath
- #projects
- #tools
Tracking XPaths:
Working with YANG Models is extensive and a bit challenging, we created this guide to help any engineer navigating into the YANG repositories looking for any desired XPath. Visit this Link for more information about XPaths.
(This is a work in progress. We are still looking for a better/efficient way to get that information)
Prerequisites:
- A macOS or Linux computer with Internet access.
- Homebrew installed (for macOS users).
- Git installed.
pyenv
andpip
installed (if not already installed).- The
pyang
andfzf
tools were installed. - pyang-xpath XPath plugin.
Getting ready:
Homebrew is a popular package manager for MacOS. If you already have Homebrew installed, you can go to the 2nd step to install Git.
- Open terminal and paste the following command:
/bin/bash -c \
"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
- Install Git (if not already installed):
brew install git
- Git clone the YangModels repository to your computer.
git clone https://github.com/YangModels/yang.git
- Install
pyenv
(if not already installed)
brew install pyenv
- Install pyenv version 3.8:
pyenv install 3.8
- Create and activate a virtual environment with Python 3.8
- Get the version and path of Python installed:
pyenv versions
- Create the virtual environment
<fix your 3.8.x version>
~/.pyenv/versions/3.8.x/bin/python -m venv yang
- Change the directory and activate the virtual environment
- Run the following to work within the cloned “yang” repository:
cd yang
- Activate the virtual environment:
source bin/activate
- Install pip:
pip install --upgrade pip
- Install pyang:
pip install pyang
Pyang is an extensible YANG (RFC 6020/7950) validator. Provides a framework for plugins that can convert YANG modules to other formats.
- Clone the pyang-xpath plugin and record the downloaded path
- Run the following command to clone the
pyang-xpath
plugin:
git clone https://github.com/NSO-developer/pyang-xpath.git
This plugin prints the name of each YANG node on a separate line with its full XPath path. This is useful when looking for a particular element in a large YANG file, and looking for the exact path it (or they) are at.
- Run and copy the path of the pyang-xpath dir to be used in step 4 of “Track XPaths Using pyang and pyang-xpath” section:
find "$(pwd)" -type d -name "pyang-xpath" -print -quit
- Install command-line fuzzy finder fuzzy finder (fzf) and ripgrep (rg) command
- Run the following command to install fuzzy finder:
brew install fzf
It’s an interactive Unix filter for command-line that can be used with any list; files, command history, processes, hostnames, bookmarks, git commits, etc.
- Run the following command to install ripgrep:
brew install ripgrep
Ripgrep is a line-oriented search tool that recursively searches the current directory for a regex pattern.
Using fuzzy finder and ripgrep we will something like the grep command, but interactive!
Let’s see how everything works:
Let’s say that we are looking for a Xpath equivalent to a Cisco CLI command like: show lldp entry
in our case we are working with Cisco XE devices version 17.9.1.
- In your computer terminal, let’s go to the yang directory using:
cd yang/vendor/cisco/xe/1791
- Let’s start filtering looking for lldp (which is going to be our interesting keyword):
rg --vimgrep lldp | fzf -i
Your terminal should look like this:
As soon as you hit enter, you will get into an interactive shell with the greater than sign >
- We are looking for an equivalent of show lldp entry, so let’s try completing the command and see:
I highlighted one interesting line list lldp-entry
seems to be something related to our command, if you click on that line and hit enter, the terminal will print out that specific result like:
What did we get?
Searching inside the 1791 folder we got a module “Cisco-IOS-XE-lldp-oper.yang” that has some relationship with our lldp entry
command.
Now, let’s explore inside the module “Cisco-IOS-XE-lldp-oper.yang”
- We can see the complete tree of the module running:
pyang -f tree Cisco-IOS-XE-lldp-oper.yang
The output should look like:
darwin@darwins-Mac 1791 % pyang -f tree Cisco-IOS-XE-lldp-oper.yang
module: Cisco-IOS-XE-lldp-oper
+--ro lldp-entries
+--ro lldp-entry* [device-id local-interface connecting-interface]
| +--ro device-id string
| +--ro local-interface string
| +--ro connecting-interface string
| +--ro ttl? uint32
| +--ro capabilities
| | +--ro repeater? empty
| | +--ro bridge? empty
| | +--ro access-point? empty
| | +--ro router? empty
| | +--ro telephone? empty
| | +--ro docsis? empty
| | +--ro station? empty
| | +--ro other? empty
| +--ro port-vlan-id? uint32
| +--ro mau-type? uint32
| +--ro auto-neg
| | +--ro enabled? empty
| | +--ro supported? empty
| +--ro power
| +--ro is-drawing-power? empty
| +--ro power-details
| +--ro power-pair? lldp-ios-xe-oper:lldp-pwr-pair-type
| +--ro power-class? lldp-ios-xe-oper:lldp-pwr-class-type
| +--ro power-device-type? lldp-ios-xe-oper:lldp-pwr-device-type
| +--ro power-source? lldp-ios-xe-oper:lldp-pwr-source-type
| +--ro power-priority? lldp-ios-xe-oper:lldp-pwr-priority-type
| +--ro power-requested? uint32
| +--ro power-allocated? uint32
+--ro lldp-state-details!
| +--ro enabled? boolean
| +--ro hello-timer? uint64
| +--ro system-name? string
| +--ro system-desc? string
| +--ro chassis-id? string
| +--ro chassis-id-type? lldp-ios-xe-oper:chid-subtype
| +--ro frame-in? uint64
| +--ro frame-out? uint64
| +--ro frame-error-in? uint64
| +--ro frame-discard? uint64
| +--ro tlv-discard? uint64
| +--ro tlv-unknown? uint64
| +--ro entries-aged-out? uint64
| +--ro mem-failures? uint64
| +--ro encap-failures? uint64
| +--ro inqueue-overflow? uint64
| +--ro table-overflow? uint64
+--ro lldp-intf-details* [if-name]
+--ro if-name string
+--ro isenabled? boolean
+--ro lldp-neighbor-details* [identifier]
| +--ro identifier string
| +--ro chassis-id? string
| +--ro chassis-id-type? lldp-ios-xe-oper:chid-subtype
| +--ro port-id? string
| +--ro port-id-type? lldp-ios-xe-oper:poid-type
| +--ro port-desc? string
| +--ro system-name? string
| +--ro system-desc? string
| +--ro time-remaining? uint32
| +--ro age? uint32
| +--ro time-since-last-update? uint32
| +--ro mgmt-addrs* []
| | +--ro mgmt-addr? string
| | +--ro mgmt-addr-type? lldp-ios-xe-oper:mgmt-type
| +--ro system-capabilities
| | +--ro repeater? empty
| | +--ro bridge? empty
| | +--ro access-point? empty
| | +--ro router? empty
| | +--ro telephone? empty
| | +--ro docsis? empty
| | +--ro station? empty
| | +--ro other? empty
| +--ro enabled-capabilities
| | +--ro repeater? empty
| | +--ro bridge? empty
| | +--ro access-point? empty
| | +--ro router? empty
| | +--ro telephone? empty
| | +--ro docsis? empty
| | +--ro station? empty
| | +--ro other? empty
| +--ro media-caps? lldp-ios-xe-oper:phy-media-cap
| +--ro ttl? uint32
| +--ro orgtlv-detail* [platform-id]
| | +--ro platform-id string
| | +--ro system-cookie? string
| +--ro peer-src-mac? yang:mac-address
+--ro tx? lldp-ios-xe-oper:tx-state
+--ro rx? lldp-ios-xe-oper:rx-state
You can see the complete tree of the module “Cisco-IOS-XE-lldp-oper.yang” it’s still a lot information to digest, but now you have a hierarchical view of a yang module, but we are still looking for the Xpath though!
- The pyang Xpath filter will come into play, using the copied path from step 10
pyang --plugindir <path_to_your_plugin> -f xpath Cisco-IOS-XE-lldp-oper.yang
The output should look like:
darwin@darwins-Mac 1791 % pyang --plugindir <path_to_your_plugin> \
-f xpath Cisco-IOS-XE-lldp-oper.yang
>>> module: Cisco-IOS-XE-lldp-oper
/lldp-entries
/lldp-entries/lldp-entry
/lldp-entries/lldp-entry/device-id
/lldp-entries/lldp-entry/local-interface
/lldp-entries/lldp-entry/connecting-interface
/lldp-entries/lldp-entry/ttl
/lldp-entries/lldp-entry/capabilities
/lldp-entries/lldp-entry/capabilities/repeater
/lldp-entries/lldp-entry/capabilities/bridge
/lldp-entries/lldp-entry/capabilities/access-point
/lldp-entries/lldp-entry/capabilities/router
/lldp-entries/lldp-entry/capabilities/telephone
/lldp-entries/lldp-entry/capabilities/docsis
/lldp-entries/lldp-entry/capabilities/station
/lldp-entries/lldp-entry/capabilities/other
/lldp-entries/lldp-entry/port-vlan-id
/lldp-entries/lldp-entry/mau-type
/lldp-entries/lldp-entry/auto-neg
/lldp-entries/lldp-entry/auto-neg/enabled
/lldp-entries/lldp-entry/auto-neg/supported
/lldp-entries/lldp-entry/power
/lldp-entries/lldp-entry/power/is-drawing-power
/lldp-entries/lldp-entry/power/power-details
/lldp-entries/lldp-entry/power/power-details/power-pair
/lldp-entries/lldp-entry/power/power-details/power-class
/lldp-entries/lldp-entry/power/power-details/power-device-type
/lldp-entries/lldp-entry/power/power-details/power-source
/lldp-entries/lldp-entry/power/power-details/power-priority
/lldp-entries/lldp-entry/power/power-details/power-requested
/lldp-entries/lldp-entry/power/power-details/power-allocated
/lldp-entries/lldp-state-details
/lldp-entries/lldp-state-details/enabled
/lldp-entries/lldp-state-details/hello-timer
/lldp-entries/lldp-state-details/system-name
/lldp-entries/lldp-state-details/system-desc
/lldp-entries/lldp-state-details/chassis-id
/lldp-entries/lldp-state-details/chassis-id-type
/lldp-entries/lldp-state-details/frame-in
/lldp-entries/lldp-state-details/frame-out
/lldp-entries/lldp-state-details/frame-error-in
/lldp-entries/lldp-state-details/frame-discard
/lldp-entries/lldp-state-details/tlv-discard
/lldp-entries/lldp-state-details/tlv-unknown
/lldp-entries/lldp-state-details/entries-aged-out
/lldp-entries/lldp-state-details/mem-failures
/lldp-entries/lldp-state-details/encap-failures
/lldp-entries/lldp-state-details/inqueue-overflow
/lldp-entries/lldp-state-details/table-overflow
/lldp-entries/lldp-intf-details
/lldp-entries/lldp-intf-details/if-name
/lldp-entries/lldp-intf-details/isenabled
/lldp-entries/lldp-intf-details/lldp-neighbor-details
/lldp-entries/lldp-intf-details/lldp-neighbor-details/identifier
/lldp-entries/lldp-intf-details/lldp-neighbor-details/chassis-id
/lldp-entries/lldp-intf-details/lldp-neighbor-details/chassis-id-type
/lldp-entries/lldp-intf-details/lldp-neighbor-details/port-id
/lldp-entries/lldp-intf-details/lldp-neighbor-details/port-id-type
/lldp-entries/lldp-intf-details/lldp-neighbor-details/port-desc
/lldp-entries/lldp-intf-details/lldp-neighbor-details/system-name
/lldp-entries/lldp-intf-details/lldp-neighbor-details/system-desc
/lldp-entries/lldp-intf-details/lldp-neighbor-details/time-remaining
/lldp-entries/lldp-intf-details/lldp-neighbor-details/age
/lldp-entries/lldp-intf-details/lldp-neighbor-details/time-since-last-update
/lldp-entries/lldp-intf-details/lldp-neighbor-details/mgmt-addrs
/lldp-entries/lldp-intf-details/lldp-neighbor-details/mgmt-addrs/mgmt-addr
/lldp-entries/lldp-intf-details/lldp-neighbor-details/mgmt-addrs/mgmt-addr-type
/lldp-entries/lldp-intf-details/lldp-neighbor-details/system-capabilities
/lldp-entries/lldp-intf-details/lldp-neighbor-details/system-capabilities/repeater
/lldp-entries/lldp-intf-details/lldp-neighbor-details/system-capabilities/bridge
/lldp-entries/lldp-intf-details/lldp-neighbor-details/system-capabilities/access-point
/lldp-entries/lldp-intf-details/lldp-neighbor-details/system-capabilities/router
/lldp-entries/lldp-intf-details/lldp-neighbor-details/system-capabilities/telephone
/lldp-entries/lldp-intf-details/lldp-neighbor-details/system-capabilities/docsis
/lldp-entries/lldp-intf-details/lldp-neighbor-details/system-capabilities/station
/lldp-entries/lldp-intf-details/lldp-neighbor-details/system-capabilities/other
/lldp-entries/lldp-intf-details/lldp-neighbor-details/enabled-capabilities
/lldp-entries/lldp-intf-details/lldp-neighbor-details/enabled-capabilities/repeater
/lldp-entries/lldp-intf-details/lldp-neighbor-details/enabled-capabilities/bridge
/lldp-entries/lldp-intf-details/lldp-neighbor-details/enabled-capabilities/access-point
/lldp-entries/lldp-intf-details/lldp-neighbor-details/enabled-capabilities/router
/lldp-entries/lldp-intf-details/lldp-neighbor-details/enabled-capabilities/telephone
/lldp-entries/lldp-intf-details/lldp-neighbor-details/enabled-capabilities/docsis
/lldp-entries/lldp-intf-details/lldp-neighbor-details/enabled-capabilities/station
/lldp-entries/lldp-intf-details/lldp-neighbor-details/enabled-capabilities/other
/lldp-entries/lldp-intf-details/lldp-neighbor-details/media-caps
/lldp-entries/lldp-intf-details/lldp-neighbor-details/ttl
/lldp-entries/lldp-intf-details/lldp-neighbor-details/orgtlv-detail
/lldp-entries/lldp-intf-details/lldp-neighbor-details/orgtlv-detail/platform-id
/lldp-entries/lldp-intf-details/lldp-neighbor-details/orgtlv-detail/system-cookie
/lldp-entries/lldp-intf-details/lldp-neighbor-details/peer-src-mac
/lldp-entries/lldp-intf-details/tx
/lldp-entries/lldp-intf-details/rx
darwin@darwins-Mac 1791 %
We can see all the XPaths within our module “Cisco-IOS-XE-lldp-oper.yang”, because we are interested in show lldp entry
the following lines contain the Xpath for the CLI command:
>>> module: Cisco-IOS-XE-lldp-oper
/lldp-entries
/lldp-entries/lldp-entry
You can try using: | grep
statement at the end of the command to reduce the list:
pyang --plugindir <path_to_your_plugin> -f xpath \
Cisco-IOS-XE-lldp-oper.yang | grep entry
The following would be the reduced list of XPaths:
darwin@darwins-Mac 1791 % pyang --plugindir <path_to_your_plugin> \
-f xpath Cisco-IOS-XE-lldp-oper.yang | grep entry
>>> module: Cisco-IOS-XE-lldp-oper
/lldp-entries/lldp-entry
/lldp-entries/lldp-entry/device-id
/lldp-entries/lldp-entry/local-interface
/lldp-entries/lldp-entry/connecting-interface
/lldp-entries/lldp-entry/ttl
/lldp-entries/lldp-entry/capabilities
/lldp-entries/lldp-entry/capabilities/repeater
/lldp-entries/lldp-entry/capabilities/bridge
/lldp-entries/lldp-entry/capabilities/access-point
/lldp-entries/lldp-entry/capabilities/router
/lldp-entries/lldp-entry/capabilities/telephone
/lldp-entries/lldp-entry/capabilities/docsis
/lldp-entries/lldp-entry/capabilities/station
/lldp-entries/lldp-entry/capabilities/other
/lldp-entries/lldp-entry/port-vlan-id
/lldp-entries/lldp-entry/mau-type
/lldp-entries/lldp-entry/auto-neg
/lldp-entries/lldp-entry/auto-neg/enabled
/lldp-entries/lldp-entry/auto-neg/supported
/lldp-entries/lldp-entry/power
/lldp-entries/lldp-entry/power/is-drawing-power
/lldp-entries/lldp-entry/power/power-details
/lldp-entries/lldp-entry/power/power-details/power-pair
/lldp-entries/lldp-entry/power/power-details/power-class
/lldp-entries/lldp-entry/power/power-details/power-device-type
/lldp-entries/lldp-entry/power/power-details/power-source
/lldp-entries/lldp-entry/power/power-details/power-priority
/lldp-entries/lldp-entry/power/power-details/power-requested
/lldp-entries/lldp-entry/power/power-details/power-allocated
There is another way to get a more specific XPath line, for this we must match the exact keyword or combination to get any result, for example:
pyang --plugindir <path_to_your_plugin> \
-f xpath Cisco-IOS-XE-lldp-oper.yang --xpath-name=lldp-entry
pyang --plugindir <path_to_your_plugin> \
-f xpath Cisco-IOS-XE-lldp-oper.yang --xpath-name=lldp-entry
>>> module: Cisco-IOS-XE-lldp-oper
/lldp-entries/lldp-entry
Happy XPath tracking!